0
\$\begingroup\$

I've read a few documents on best practices for interrupt handling and thought I was doing things correctly, ensuring the variable set in the ISR was declared volatile. In my code the interrupt handler is operating properly, firing at the correct rate per the timer settings (checked by toggling an LED). The problem I'm encountering is that when I check the status of the flag set in the interrupt from my main loop, I get seemingly random updates at rate much much slower than expected. Some more specifics:

Timer ISR Period: 500ms
Main Loop Execution Period: 50us
Effective period of CheckPeriodicTimer() being set: anywhere from 2 - 45 seconds
MCU: STM32F030R8 48 MHz
IDE: STM32CubeIDE 1.3.1
I have tried compiling with and without optimization and am getting the same behavior.

tim.c

 volatile uint16_t PeriodicTimerFlag = TIMER_FLAG_CLEAR; volatile uint32_t TimerOverflow = 0; ... void HAL_TIM_PeriodElapsedCallback (TIM_HandleTypeDef *htim) { // check which timer if (htim->Instance == TIM1) { // check for stale flag - something is wrong (but also occurs when // debugger stops execution) if (PeriodicTimerFlag == TIMER_FLAG_SET) { TimerOverflow++; } else { // set the flag and get out of here PeriodicTimerFlag = TIMER_FLAG_SET; } } } ... uint16_t CheckPeriodicTimer (void) { return PeriodicTimerFlag; } void ClearPeriodicTimerFlag (void) { PeriodicTimerFlag = TIMER_FLAG_CLEAR; } 

main.c

... uint16_t mainPeriodicTimerFlag = TIMER_FLAG_CLEAR; ... int main(void) ... while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ //timer check mainPeriodicTimerFlag = CheckPeriodicTimer(); Task1(mainPeriodicTimerFlag); Task2(mainPeriodicTimerFlag); // Clear timer flag once done ClearPeriodicTimerFlag(); // remote mainPeriodicTimerFlag = TIMER_FLAG_CLEAR; //local } ``` 
\$\endgroup\$
2
  • \$\begingroup\$ If you have spare I/O, turn a pin on when mainPeriodicTimerFlag is set in the main loop. Turn another pin on right before you call Task1 and off after you exit. Ditto (with a third pin) for Task2. Then look at it all with an oscilloscope. \$\endgroup\$ Commented Jun 19, 2020 at 16:58
  • \$\begingroup\$ Yeah, that's where my measures are coming from. While the main loop runs every 50us, the main flag is set at a period of 2-45 seconds, randomly. \$\endgroup\$ Commented Jun 19, 2020 at 17:00

1 Answer 1

1
\$\begingroup\$

It's rather obvious - main loop continuously resets the flag every loop, even if the flag is not set. If the interrupt happens after reading the flag, then the tasks are not triggered, and the flag is cleared, so the tasks are not triggered on the next round even if the interrupt did trigger. So it only works if the interrupt happens after resetting the flag and before it is read, and thus at quite low propability.

\$\endgroup\$
2
  • \$\begingroup\$ D'oh -- I completely missed that. Best practice is to turn off interrupts, read the flag into local storage, clear the flag, turn on interrupts, and carry on. \$\endgroup\$ Commented Jun 19, 2020 at 23:05
  • \$\begingroup\$ In addition, there is no atomic access nor re-entrancy protection in the code, so in worst case main() could be reading half the variable and ending up with corrupt data. Depending on what machine code you get and how those enums are defined. \$\endgroup\$ Commented Jun 24, 2020 at 12:53

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.