2024-05-09 05:26 AM
I have a strange problem. I have a global uint32_t variable that counts up in the main loop and every 100 ms it gets reset in a timer-ISR. This works, but sometimes it does not.
Here is the value of the variable MainCounter read out by the debugger:
The ISR is definitely called every time as the toggling variable test shows. Also inside the ISR MainCounter really is zero, I checked. But sometimes this zero does not "reach" the main loop.
Please help, I have absolutely no idea how this is even possible.
Solved! Go to Solution.
2024-05-09 10:26 AM
Likely because operation "MainCounter++" is not atomic. It consists of two instructions, the interrupt can hit between them.
2024-05-09 05:33 AM
>>I have absolutely no idea how this is even possible.
a) Optimization On, b) variables that should be flagged as volatile are not..
You'll need to show minimum code
2024-05-09 06:04 AM
volatile uint32_t MainCounter = 0;
int main(void) {
...
while (1) {
MainCounter++;
}
}
void TimerISR(void) {
extern volatile uint32_t MainCounter;
static uint32_t reduction_counter = 0;
if (++reduction_counter == 1000) {
reduction_counter = 0;
MainCounter = 0;
}
}
No optimization, no cache
.data, .bss and stack are in DTCMRAM
It gets worse the shorter the main while loop is. With only the incrementation as in the example above, it is more like: it works sometimes.
2024-05-09 06:12 AM
If it doesn't reset, then likely because TimerISR() is NOT called. Look at how it's called and watch for RMW on SR, ie TIM->SR &= ~1 type usage
if (++reduction_counter >= 1000) { // might make this more defensive
2024-05-09 06:30 AM
It is called, see first post. I also checked with toggling IO because I don't trust the debugger.
2024-05-09 06:50 AM - edited 2024-05-09 06:53 AM
void TimerISR(void) {
extern volatile uint32_t MainCounter;
this isnt good practice, right is
extern volatile uint32_t MainCounter;
void TimerISR(void) {
too TimerISR isnt native ISR call. How you call it?
2024-05-09 07:02 AM
@MM..1 wrote:too TimerISR isnt native ISR call. How you call it?
I didn't, this was just an example. Here is real, new, good practice code:
extern volatile uint32_t MainCounter;
void TIM1_UP_IRQHandler(void) {
LL_TIM_ClearFlag_UPDATE(TIM1);
MainCounter = 0;
}
The result is the same.
I also switched the test board and removed everything besides TIM1 from .ioc and all other unnecessary code, no difference.
2024-05-09 07:09 AM - edited 2024-05-09 07:15 AM
And hope TIM and main is on same core. H745 is dual. Too isnt watchdog reset here ?
And LL sometimes require data risc management aka __DSB etc. try swap lines
2024-05-09 07:22 AM
2024-05-09 07:33 AM
both cores doing it (-O0)
now compiled with -Ofast for both cores, CM7 looks better*
(* at least in this example, the first time I encounter this problem, code was compiled with -Ofast as well)