cancel
Showing results for 
Search instead for 
Did you mean: 

TIM1 and TIM8 preload behavior

Posted on November 04, 2015 at 13:25

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-enable
9 REPLIES 9
Posted on November 04, 2015 at 14:46

> 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?

JW

Posted on November 04, 2015 at 15:31

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.

Posted on November 04, 2015 at 15:59

>> 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.

JW

mikael239955_stm1_st
Associate III
Posted on November 04, 2015 at 18:25

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).

Posted on November 04, 2015 at 20:59

>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.

/Richard

Posted on November 04, 2015 at 21:28

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.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on November 04, 2015 at 22:18

>>>> 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

JW

Posted on November 05, 2015 at 13:43

>>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

/Richard

Posted on November 05, 2015 at 14:09

> The moment I answered so definitive I knew I had it coming.

:D