2015-11-04 04:25 AM
Hello,
We're using STM32F207Zx and have a strange problem when using TIM1/8 for PWM. when code include line TIM_OCxPreloadConfig(Tim,TIM_OCPreload_Enable); where x can be any number from 1-4 for TIM1, new duty values are loaded much later than expected. Delay time is drifting and change between 10-350ms in a predictive repetitive sequence. I know that these timers are a bit special and supposed to be used for motor control. We have this line to change timer behavior to normal PWM if(Tim==TIM1) TIM_CtrlPWMOutputs(Tim,ENABLE); Is there a bit to be set or cleared to solve this problem? We use 10 other timers with preload enabled and don't see same behavior with them. Regards, Richard #tim1-preload-enable2015-11-04 05:46 AM
> when code include line
> TIM_OCxPreloadConfig(Tim,TIM_OCPreload_Enable);
> where x can be any number from 1-4 for TIM1, new duty values are loaded much later than expected. Delay time is drifting and change between 10-350ms in a predictive repetitive sequence. How do you know that? What is the expected behaviour and how does the observed behaviour depart from that? Can you construct a minimal but complete example exhibiting the problem? JW2015-11-04 06:31 AM
How do you know that?
We toggle another pin when duty is changed and look at that pin and output from i.e. TIM1 on a scope. When we not use preload the two outputs are aligned.2015-11-04 06:59 AM
>> How do you know that?
> We toggle another pin when duty is changed
What does that mean? A write to TIMx_CCRy? When preload is enabled, the ''real'' CCRy is updated upon the UE (update event), which is roughly speaking when TIMx_CNT overflows. That can be disabled (using TIMx_CR1.UDIS), or, when TIMx_RCR is non-zero, does happen only when repetition count gets to zero. Do you do any of these in your program? I repeat, try to construct a minimal but complete compilable example exhibiting the problem. JW2015-11-04 09:25 AM
From ref manual:
The TIMx_CCRx register can be updated at any time by software to control the outputwaveform, provided that the preload register is not enabled (OCxPE=’0’, else TIMx_CCRx
shadow register is updated only at the next update event UEV).
2015-11-04 11:59 AM
>What does that mean? A write to TIMx_CCRy?
No,we use low level code to get minimum delay for the reference output. GPIOC->BSRRL=GPIO_Pin_7; // pin high GPIOC->BSRRH=GPIO_Pin_7; // pin low A small delay <1ms is expected for the 16 PWM outputs we're testing when setting a new duty. 5 of those PWM outputs use TIM1/8, the other PWM outputs work flawless with preload enabled. The observed delay of 10-375ms with sequential drifting is only appearant for the output channels using TIM1/8. The delay disappear if we comment the line where preload is enabled. I.e. TIM_OC4PreloadConfig(Tim,TIM_OCPreload_Enable); >When preload is enabled, the ''real'' CCRy is updated upon the UE (update event), which is roughly speaking when >TIMx_CNT overflows. That can be disabled (using TIMx_CR1.UDIS), or, when TIMx_RCR is non-zero, does happen only >when repetition count gets to zero. Do you do any of these in your program? No. >I repeat, try to construct a minimal but complete compilable example exhibiting the problem. The code is rather complex, it would take hours of work to minimize to a compilable program. Was hoping that we've missed something that was needed for TIM1/8 to work as the other timers, similar to /* This is needed for TIM1 since PWM OC not it's primary use. */ if(Tim==TIM1) TIM_CtrlPWMOutputs(Tim,ENABLE); Now when I know that the buggy behavior is related to enabling preload I've used the code below to test all 16 channels in sequence. The reference output pin is aligned with all 16 channels when looking at the scope if preload is disabled for TIM1/8. When preload is enabled again the strange delay can be seen only for channels using TIM1/8. for(i=0; i<16; i++) PwmDcCfg(i,500,0,0,1000,1); OutConfig(4); // configure pin as non-PWM Output SetOutPin(4,Stop); // pin now at 0v while(1) { for(i=0; i<16; i++) { PwmSetDuty(i,1000); Delay_ms(1000); PwmSetDuty(i,0); Delay_ms(2000); } } We toggle the reference pin at the bottom of PwmSetDuty() function. >From ref manual: >The TIMx_CCRx register can be updated at any time by software to control the output >waveform, provided that the preload register is not enabled (OCxPE=’0’, else TIMx_CCRx >shadow register is updated only at the next update event UEV). We want to update CCRx regster on next UEV, not ''at any time''. While testing we've set period to 500Hz, which would lead to worst case of 2ms before next UEV occur. The text cited from ref manual is the same for TIM1/8 and other timers. Which implies that preload should be doable also for TIM1 and TIM8. /Richard2015-11-04 12:28 PM
2us I hope, but 500 KHz is probably a bit high for interrupting.
/* This is needed for TIM1 since PWM OC not it's primary use. */
if(Tim==TIM1) TIM_CtrlPWMOutputs(Tim,ENABLE);
This is needed for TIM1 and TIM8, along with a *complete* initialization of the Time Base and Channel structures, failure to do this will result in random junk determining what happens.The code is rather complex, it would take hours of work to minimize to a compilable program. Was hoping that we've missed something that was needed for TIM1/8 to work as the other timers...Yeah, well you've probably already wasted hours, and you want us to *guess* what you're screwing up by providing next to nothing to look at and cross check. I'm not looking to do keyhole debugging, or code a demo to prove you right/wrong.Create a small app that configures the timers, channels, and interrupts, and demos the effect you're complaining about. It should be a 30 min task at best.2015-11-04 01:18 PM
>>>> How do you know that?
>>> We toggle another pin when duty is changed >> What does that mean? A write to TIMx_CCRy? >No,we use low level code to get minimum delay for the reference output. > >GPIOC->BSRRL=GPIO_Pin_7; // pin high >GPIOC->BSRRH=GPIO_Pin_7; // pin low Oh, I was not asking ''what does 'We toggle another pin' mean'', I meant to ask ''what does 'duty is changed' mean''... I thought ''A write to TIMx_CCRy?'' explains what was the question... > [Clive, looking into his extraordinarily clean crystal ball]: This is needed for TIM1 and TIM8, along with a *complete* initialization of the Time Base and Channel structures, failure to do this will result in random junk determining what happens. There is a function in SPL for that initialization for every peripheral including timers, and SPL's documentation requires to either fill in the whole structure OR to call that function. I would recommend the latter, except that I recommend against using SPL at all... :) Which leads us to: >>When preload is enabled, the ''real'' CCRy is updated upon the UE (update event), which is roughly speaking when >>TIMx_CNT overflows. That can be disabled (using TIMx_CR1.UDIS), or, when TIMx_RCR is non-zero, does happen only >>when repetition count gets to zero. Do you do any of these in your program? > >No. What Clive hints to above is, that not filling in the whole init struct, you probably DO set TIMx_RCR to non-zero. Please, check by reading the register in debugger, and come back with the result. > Create a small app that configures the timers, channels, and interrupts, and demos the effect > you're complaining about. It should be a 30 min task at best. +1 JW2015-11-05 04:43 AM
>>When preload is enabled, the ''real'' CCRy is updated upon the UE (update event), which is roughly speaking when
>>TIMx_CNT overflows. That can be disabled (using TIMx_CR1.UDIS), or, when TIMx_RCR is non-zero, does happen only >>when repetition count gets to zero. Do you do any of these in your program? > >No. The moment I answered so definitive I knew I had it coming. Looking closer into library function TIM_TimeBaseInit() I noticed it reloaded RCR value to TIM1/8. Adding line TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000; solved our problem. Thanks for the hints /Richard2015-11-05 05:09 AM
> The moment I answered so definitive I knew I had it coming.
:D