2024-04-24 06:47 AM
Hi,
I have timer with period 1 sec (80 MHz clock):
htim2.Init.Prescaler = 80-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1000000-1;
Global var (volatile uint32_t) increased every time counter wraps around
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) {
globalSeconds++;
}
}
In the code, timestamp (timer counter and var) collected and send later over UART (speed 921600)
do {
sec = globalSeconds;
us = TIM2->CNT;
} while (sec != globalSeconds);
When I get values on pc, I noticed that seconds are not always correct. It happens when usec timer counter wraps around:
34.995010
34.999530
34.100404
34.100858
I'm a bit puzzled about it, coz globalSeconds changed only in one place in the code by TIM2 interrupt.
The only explanation I could imagine, that HAL_TIM_PeriodElapsedCallback() is not called (INT disabled?)...
Even if handling of INT was delayed by other INT, eventually it shall increase globalSeconds counter.
Could other interrupts (two UARTs, SPI) or high MCU load cause trouble with HAL_TIM_PeriodElapsedCallback()?
Any ideas are welcome :)
Regards,
Lex
2024-04-24 08:10 AM
How is globalSeconds defined?
The most straighforward thing to do is to toggle a pin at the place where globalSeconds is incremented, and observe using oscilloscope/logic analyzer.
JW
2024-04-25 12:09 AM
Thanks for advise! At least I could prove that it is not stepped up. globalSeconds definition is below:
volatile uint32_t globalSeconds = 0;
Solution is using 3d-party library and SDK to control another chip connected over SPI. I recall some part of code from the SDK blocks interrupts to process SPI data...
/Lex
2024-04-25 07:07 AM - edited 2024-04-25 07:14 AM
You do not need an interrupt! Just let the timer overflow at 0xFFFFFFFF. As long as you read the timer value at least once every 4000 seconds you can simply detect the occasional single overflow in software!
Code snippet (untested, but I've used similar code)
static uint64_t microSecondsOld = 0;
uint32_t val = TIM2->CNT;
uint64_t microSecondsNew = microSecondsOld & 0xFFFFFFFF00000000ULL | val;
if (microSecondsNew < microSecondsOld)
{
//overflow occured
microSecondsNew += 1ULL<<32;
}
microSecondsOld = microSecondsNew;
Just be aware the variable is not atomic so you should disable interrupts when modifying it (I didn't for simplicity sake).