cancel
Showing results for 
Search instead for 
Did you mean: 

How to correctly chain 3 timers and fix the overflow and wraparound issues.

BCano.1
Associate III

I have to implement a lifetime counter with microseconds granularity using a STM32L432KC to control an AFBR-S50 sensor. The timer has to count "forever" and this board only has 1 32bit timer, so this timer is for the seconds, i think is the only way. So this timer could count several years. Problem is i also need microseconds.

In the sensor documentation they chain 2 32bits counters, but i need three. one 16 bit for microseconds, one 16 bit for miliseconds and 1 32bits for the seconds. The prescaler for the first one is "SystemCoreClock / 1000000 -1" and the counter period is "1000", the second is chained to this, prescaler is 0 and counter period is also "1000". And the third is chained to the second, prescaler also 0 and counter period 0xffff.

The first issue with this is i have done a test waiting for 5 minutes and comparing the result with mi cronograph and it has too much delay. The MCU has counter 36 seconds (in 5 minutes) more than the cronograph. How can be this possible?

The second problem is with the wraparound issue of the counters. to resolve this, they read the timers in a loop and iterate the loop while in two consecutive read of the timer, the first is bigger than the second. So the timer goes up direction, the second read always has to be bigger than the first except when counter resets, so thats fine.

I have two possible wraparounds so i added other condition to the loop. second read of both timers have be bigger than first. I think this is ok, but not completely sure.

The main issue is program is failing because the calc of total microseconds for which i use this formula:

ltc= msTimerValue * 1000 + usTimerValue

exceeds 999.999 and if both timers has counter periods of 1000 i dont know how this could happen. The max value of both timers should be 999.

I'm really new to electronics and this kind of controllers, and dont have a lot of experience with glitches and other things.

I really appreciate some help.

Thanks

1 ACCEPTED SOLUTION

Accepted Solutions
KnarfB
Principal III

The counter period you set (ARR register) should be 1000-1 respectively 0xffffffff for the 32-bit timer.

Watch the timer registers while debugging your prog to find the root cause of your main issue.

No code, no idea.

Using timers to implement a lifetime counter running "forever" means "as long as the MCU is powered on". This doesn't sound fail-safe to me. Think of using the RTC with a backup power supply (battery, supercap)

hth

KnarfB

View solution in original post

9 REPLIES 9
KnarfB
Principal III

The counter period you set (ARR register) should be 1000-1 respectively 0xffffffff for the 32-bit timer.

Watch the timer registers while debugging your prog to find the root cause of your main issue.

No code, no idea.

Using timers to implement a lifetime counter running "forever" means "as long as the MCU is powered on". This doesn't sound fail-safe to me. Think of using the RTC with a backup power supply (battery, supercap)

hth

KnarfB

BCano.1
Associate III

Thank you very much KnarfB. The post was too long and i though it would not be convenient to add more info. But you're right i should have added code.

I will test with 1000-1 period to see if precission and other issues improve.

This is the code:

do{
		us = __HAL_TIM_GET_COUNTER(&htim15);
		ms = __HAL_TIM_GET_COUNTER(&htim1);
		s = __HAL_TIM_GET_COUNTER(&htim2);
 
		*lct = ms * 1000 + us;
		*hct = s;
}while ( (us > __HAL_TIM_GET_COUNTER(&htim15)) | (ms > __HAL_TIM_GET_COUNTER(&htim1)));

 About the LTC, yes, its a little bit strange. I have to learn more about it. But the sensor stores the current count and is supposed the number is added everytime.

TDK
Guru

> The max value of both timers should be 999.

Max CNT value is ARR, which it sounds like you set as 1000, not 999.

Might want to move the lct and hct calculation outside the loop. It doesn't matter if the counters wrap around during that portion, but having the check later will cause it to happen more frequently.

You also have an issue where us/ms could tick over between reading ms and s. This will not be caught by your checks and will results in a reported time ~1s in the future. Might want to replace the check with just:

do{
	us = __HAL_TIM_GET_COUNTER(&htim15);
	ms = __HAL_TIM_GET_COUNTER(&htim1);
	s = __HAL_TIM_GET_COUNTER(&htim2);
} while (us != __HAL_TIM_GET_COUNTER(&htim15));
 
*lct = ms * 1000 + us;
*hct = s;

Also need to ensure the timers are in perfect sync and not delayed by a few ticks.

If you feel a post has answered your question, please click "Accept as Solution".

> The first issue with this is i have done a test waiting for 5 minutes and comparing the result with mi

> cronograph and it has too much delay. The MCU has counter 36 seconds (in 5 minutes) more than the > cronograph. How can be this possible?

What's the primary clock source to mcu? How exactly are the RCC registers set? Read out and check/post them. What is the value of SystemCoreClock variable?

JW

BCano.1
Associate III

Thank you very much for your improvements to the loop, the main issue was the ARR register being 1000 instead 999 as you said, now its working great, but i definitely will try that. Thanks!

Hello! the main issue was ARR register. I was setting 1000 instead 999. Thank you very much!

BCano.1
Associate III

I tried your code but seems to be not working, never ends the loop. I think because we are doing microseconds, never meets the condition. It lasts more than 1 microsecond to execute both reads.

Piranha
Chief II

You can get the idea of an alternate approach from my post in this topic:

https://community.st.com/s/question/0D53W000013JV5nSAG/32f417-rtc-errata-sheet-if-reading-subseconds-is-this-code-ok

The bonus - it doesn't require reading the same values multiple times.

Hello, thanks for the info. I will test your approach. thanks.