cancel
Showing results for 
Search instead for 
Did you mean: 

TIM5 accuracy and overflow: configuration

SylvainFluent
Associate II

I am trying to configure the TIM5 to get timestamp in milliseconds for a long period (over 40 seconds).

Here is the current configuration of TIM5:

// This function inits and start the timers used
void timer_init(void) {
__HAL_RCC_TIM5_CLK_ENABLE();
TIM5->PSC = (HAL_RCC_GetPCLK1Freq() / 1000000) - 1;
TIM5->CR1 |= TIM_CR1_CEN;
}

We did observed an overflow problem after about 40 seconds, our timeout were taking for ever to expire after the first 40 seconds. So we did use this test code to gather data:

snprintf(printbuff, sizeof(printbuff), "Timer 5 ARR %X PSC %X CR1 %X CR2 %X EGR %X RCR %X\n",
                                       TIM5->ARR, TIM5->PSC, TIM5->CR1, TIM5->CR2, TIM5->EGR, TIM5->RCR);
send_uart(printbuff, strlen(printbuff));
while (true)
{
    uint32_t mltime = TIM5->CNT;
    HAL_Delay(1000);
    uint32_t mctime = TIM5->CNT;
    uint32_t mstime = (int32_t)mctime - (int32_t)mltime;
    snprintf(printbuff, sizeof(printbuff), "Time ml %u mc %u ms %u\n", mltime, mctime, mstime);
    send_uart(printbuff, strlen(printbuff));
    if (mctime < mltime)
    {
        snprintf(printbuff, sizeof(printbuff), "Timer 5 ARR %X PSC %X CR1 %X CR2 %X EGR %X RCR %X\n",
                                               TIM5->ARR, TIM5->PSC, TIM5->CR1, TIM5->CR2, TIM5->EGR, TIM5->RCR);
        send_uart(printbuff, strlen(printbuff));
    }
}

Here are the results:

Timer 5 ARR FFFFFFFF PSC 31 CR1 1 CR2 0 EGR 0 RCR 0
Time ml 3904281 mc 103971757 ms 100067476
Time ml 104340567 mc 204371761 ms 100031194
Time ml 204757745 mc 304771761 ms 100014016
Time ml 305158453 mc 405171759 ms 100013306
Time ml 405558259 mc 505571763 ms 100013504
Time ml 505958093 mc 605971757 ms 100013664
Time ml 606357915 mc 706371767 ms 100013852
Time ml 706757741 mc 806771771 ms 100014030
Time ml 807158433 mc 907171765 ms 100013332
...
Time ml 3821875199 mc 3921971765 ms 100096566
Time ml 3922375709 mc 4022471767 ms 100096058
Time ml 4022875355 mc 4122971763 ms 100096408
Time ml 4123375861 mc 4223471771 ms 100095910
Time ml 4223875521 mc 580089 ms 71671864
Timer 5 ARR FFFFFFFF PSC 31 CR1 1 CR2 0 EGR 0 RCR 0
Time ml 596455 mc 2598089 ms 2001634
Time ml 2604590 mc 4606089 ms 2001499
Time ml 4612760 mc 6614089 ms 2001329
Time ml 6620809 mc 8622089 ms 2001280
Time ml 8628771 mc 10630089 ms 2001318
Time ml 10636941 mc 12638089 ms 2001148
...
Time ml 4289685807 mc 4291686089 ms 2000282
Time ml 4291693821 mc 4293694089 ms 2000268
Time ml 4293701817 mc 734793 ms 2000272
Timer 5 ARR FFFFFFFF PSC 31 CR1 1 CR2 0 EGR 0 RCR 0
Time ml 750989 mc 2752793 ms 2001804
Time ml 2759299 mc 4760793 ms 2001494
Time ml 4767468 mc 6768793 ms 2001325
Time ml 6775465 mc 8776793 ms 2001328
Time ml 8783479 mc 10784793 ms 2001314

So after the timer overflow, the value are not valid anymore 2001148 instead of 100096566 (aka ~1 second). Last period before first overflow is also too short 71671864. Second overflow is ok constant to ~2001148.

When setting TIM5->EGR:

// This function inits and start the timers used
void timer_init(void) {
__HAL_RCC_TIM5_CLK_ENABLE();
TIM5->PSC = (HAL_RCC_GetPCLK1Freq() / 1000000) - 1;
TIM5->EGR = TIM_EGR_UG;
TIM5->CR1 |= TIM_CR1_CEN;
}

We have the following results:

Timer 5 ARR FFFFFFFF PSC 31 CR1 1 CR2 0 EGR 0 RCR 0
Time ml 77998 mc 2079435 ms 2001437
Time ml 2085769 mc 4087435 ms 2001666
Time ml 4094113 mc 6095435 ms 2001322
Time ml 6102110 mc 8103435 ms 2001325
Time ml 8110123 mc 10111435 ms 2001312
Time ml 10118294 mc 12119435 ms 2001141
Time ml 12126463 mc 14127435 ms 2000972
...
Time ml 4287159163 mc 4289159435 ms 2000272
Time ml 4289167160 mc 4291167435 ms 2000275
Time ml 4291175156 mc 4293175435 ms 2000279
Time ml 4293183153 mc 216139 ms 2000282
Timer 5 ARR FFFFFFFF PSC 31 CR1 1 CR2 0 EGR 0 RCR 0
Time ml 232342 mc 2234139 ms 2001797
Time ml 2240651 mc 4242139 ms 2001488
Time ml 4248821 mc 6250139 ms 2001318
Time ml 6256818 mc 8258139 ms 2001321
Time ml 8264814 mc 10266139 ms 2001325
...
Time ml 4287313872 mc 4289314139 ms 2000267
Time ml 4289321868 mc 4291322139 ms 2000271
Time ml 4291329865 mc 4293330139 ms 2000274
Time ml 4293337861 mc 370843 ms 2000278
Timer 5 ARR FFFFFFFF PSC 31 CR1 1 CR2 0 EGR 0 RCR 0
Time ml 387033 mc 2388843 ms 2001810
Time ml 2395342 mc 4396843 ms 2001501
Time ml 4403530 mc 6404843 ms 2001313
Time ml 6411526 mc 8412843 ms 2001317
Time ml 8419523 mc 10420843 ms 2001320

 Wrong value of ~2000000 instead of 1 seconds. But it does never changes always ~2000000 even just before or after the overflow.

So we are thinking we have a configuration issue, what should be the right configuration?

1 ACCEPTED SOLUTION

Accepted Solutions

> I am new to STM32F412, how can we set APB divider to 1 or to the right value. I made a patch dividing the value by 2 but I would like to make a real fix to the problem.

As TDK said above, it's not a problem, simply take it into account and make the prescaler twice as big (more precisely,  ((HAL_RCC_GetPCLK1Freq() / 1000000) * 2) - 1; ).

JW

View solution in original post

13 REPLIES 13

Which STM32? How are clocks set up?

> the value are not valid anymore 2001148 instead of 100096566 (aka ~1 second).

You use a prescaler to supposedly change the main TIM clock to 1MHz, don't you. So why would 100'000'000 be the expected count for 1 second? Wouldn't that be 1'000'000?

Your first observation is related to the fact that prescaler is preloaded. That's why also the count at overflow was somewhere in between - up until the overflow the timer run without the prescaler and from the overflow it run 50x slower.

Your second observation (i.e. that after PSC is loaded either through natural overflow (=> Update) or forced Update through setting TIMx_EGR.UG) the 1 second count is 2'000'000 instead of expected 1'000'000 is due to the fact, that timers' clocks in most STM32 is two times the APB clock, if APB divider is not 1.

JW

LCE
Principal

To which baud rate is the UART set and how is it set up?
At 115k2 printing one line takes more than 1ms.
So you probably overwrite the currently used buffer, unless you have some blocking mechanism in your output function.

Setting EGR somehow did not work, as you can see in the UART output, it's still EGR = 0.

I would always reset all registers at init.

> At 115k2 printing one line takes more than 1ms.

That should not be an issue as there is one print out one second.

> Setting EGR somehow did not work, as you can see in the UART output, it's still EGR = 0.

EGR bits are write-only, they always read as 0.

JW

EGR bits are write-only, they always read as 0.

Oops... my bad.

>> At 115k2 printing one line takes more than 1ms.

> That should not be an issue as there is one print out one second.

It might be if the send_uart() function is blocking. But okay, then the time values would be even worse.

Thanks for your reply,
send_uart() is outside the timer handling so it does not affect the timer execution time, the send_uart() will only create a gap between the last mctime and the new mltime, but as we do not care about mltime - mctime but rather mctime - mltime, the time spent in send_uart() does not affect the results. 

Although EGR set to 0 at runtime, it is taken into account at boot time in init() as the behavior is different if we do not set it. It is probably cleared once processed.

We are using STM32F412.

I am new to STM32F412, how can we set APB divider to 1 or to the right value. I made a patch dividing the value by 2 but I would like to make a real fix to the problem.

From my understanding this is the TIM5 configuration we are using:

// This function inits and start the timers used
void timer_init(void) {
__HAL_RCC_TIM5_CLK_ENABLE();
TIM5->PSC = (HAL_RCC_GetPCLK1Freq() / 1000000) - 1;
TIM5->CR1 |= TIM_CR1_CEN;
}

Thanks.

Thanks for the clearing up the EGR bits behavior.

@LCE What do you mean by 

> I would always reset all registers at init.

Which additional registers should be set?