cancel
Showing results for 
Search instead for 
Did you mean: 

Timer1 reset on trigger

klaasdc
Associate II
Posted on July 07, 2012 at 20:24

I found something very funny/weird when using TIM1 to measure the frequency of a signal:

Set TIM2 and TIM1 to use the same prescaler (e.g. 8). TIM2 is configured to generate PWM with period 10000, in this case resulting in 2Mhz/(8*10000)=25Hz signal.

Then, TIM1 is configured in Input CapCom mode, and its trigger controller resets the timer on every rising edge on input channel1.

Now connect pins TIM2_Chan1 with TIM1_Chan1. In theory, the values obtained in CapCompareReg1 of TIM1 should equal the period of TIM2 perfectly.

In this example, the CCR1 contains 8880 instead of 9999. The values deviate even more worse when taking smaller prescalers for TIM1.

 

-------------------

 

Main code

:

    TIM1_DeInit();

    /* Set TIM1 Frequency to 1 Mhz (=2Mhz/2), thus 1 unit = 1us */

  TIM1_TimeBaseInit(8, TIM1_COUNTERMODE_UP, 60000, 0);//Max 60000 steps before overflow

    

  /* TIM1 channel 1 is used (PC1) with rising edge and no divider (1) nor filter (0) */

  TIM1_ICInit(TIM1_CHANNEL_1, TIM1_ICPOLARITY_RISING, TIM1_ICSELECTION_DIRECTTI,  TIM1_ICPSC_DIV1, 0x00);    

  /* the trigger input (TRGI) to used to synchronize the counter */

    TIM1_SelectInputTrigger(TIM1_TS_TI1FP1);

  /* Reset mode - Rising edge of the selected trigger signal (TI1FP1 in this case) re-initializes the counter and

     generates an update of the registers. */

  TIM1_SelectSlaveMode(TIM1_SLAVEMODE_RESET);

  /* Overflow interrupt ; Capture1 interrupt enabled */

  TIM1_ITConfig(TIM1_IT_UPDATE | TIM1_IT_CC1, ENABLE);

  /* Generate an update event */

  TIM1_GenerateEvent(TIM1_EVENTSOURCE_UPDATE);

  /* Clear CC1 and update Flag */

  TIM1_ClearFlag(TIM1_FLAG_CC1 | TIM1_FLAG_UPDATE);

    //Update URS bit van TIM_CR1 so only over/underflow generates interrupt.

    TIM1_UpdateRequestConfig(TIM1_UPDATESOURCE_REGULAR);

    /* Enable TIM1 */

  TIM1_Cmd(ENABLE);

    TIM1_GenerateEvent(TIM1_EVENTSOURCE_UPDATE);

    //---------------------------

    TIM2_TimeBaseInit(TIM2_PRESCALER_8, 9999);

    /* PWM1 Mode configuration: Channel1 */

    TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, 4000, TIM2_OCPOLARITY_HIGH);

    TIM2_OC1PreloadConfig(ENABLE);

    TIM2_ARRPreloadConfig(ENABLE);

    /* TIM2 enable counter */

    TIM2_Cmd(ENABLE);

    //---------------------------

  /* Enable general interrupts */

  enableInterrupts();

-----------------------------------

 

Interrupt handler for TIM1 CapCom:

void TIM1_CAP_COM_IRQHandler(void) interrupt 12

{

    measuredTime = (TIM1_GetCapture1());

    TIM1_ClearFlag(TIM1_FLAG_CC1);//Clear capture-compare flag

}

So, the timer must lose ''counts'' somewhere. Ironically, it is more accurate to do the whole thing with EXTI interrupts and start/stop the counter in software.

I would love to believe that my code is wrong, but it dawns on me that the while timer synchronisation implementation could be a piece of crap.

#broken-timer-stm8s
4 REPLIES 4
fggnrc2
Associate II
Posted on July 08, 2012 at 08:53

Hello Klaas.

Section 17.4.5 ''Trigger synchronization'' of RM0016 Reference Manual of STM8S microcontroller family explains why your code doesn't work as you think.

Your code makes TIM1 work in ''trigger reset mode'', so what Figure 47 shows applies to your example too.

Even if Figure 47 isn't correct, because TIM1_CNTR is cleared before the trigger edge, it shows a delay between the trigger edge and the update event.

The resynchronization circuit on TI1 input adds this delay which depends on prescaler and counter values.

I don't know why STM8 designers added this feature.

I think that TIM1 may be a powerful timer but it's a rather complex timer to use because there are many ways to accomplish a task but only one really works.

Regards

EtaPhi

klaasdc
Associate II
Posted on July 08, 2012 at 09:45

Hi EtaPhi,

Thanks for your reply! You are right about the delay, I must have missed that part.

But I would expect that the delay only 'shifts' the time of reset, and therefore does not alter the value of the counter itself.

And if it does alter it, it would make sense that the value in the counter becomes too high but in the example case the time value ends up too low (8880 instead of 10000).

Also, in my example, the timer is running at 250kHz, but magically loses 4.4ms worth of counts (error of 12%). That is kind of extreme, but can get worse: running the timer at 1Mhz, the difference is 3.3 ms, or an error of about 30% on the counter value.

I will try some other things to try to measure frequencies but losing confidence in using this uC. Like you say, it might be possible to do it with Timer1, but it's just too complex and the documentation does not really help much.

fggnrc2
Associate II
Posted on July 08, 2012 at 11:54

Klass,

STM8 TIM1 is the same timer that you can find in a STM32 device.

You are therefore losing confidence in STM32 microcontrollers too...

I don't like this complex timer, because I've been acquainted with ST7Lite Auto Reload Timer which is simpler and better documented, albeit it's less flexible than TIM1.

Some great documentation from ST would help and it's strongly needed, but I don't want to miss the opportunity of an easy and painless transition to ARM microcontroller from ST.

Ciao

EtaPhi

klaasdc
Associate II
Posted on July 09, 2012 at 10:45

I found the problem. Very stupid mistake of course...:

 /* Set TIM1 Frequency to 250kHz (=2Mhz/8) */

  TIM1_TimeBaseInit(8, TIM1_COUNTERMODE_UP, 60000, 0);//Max 60000 steps before overflow

The Prescaler is off-by-one! It should be 7 to divide by 8.

Knowing this, everything works as it should and measurements are quite accurate now.