Skip to main content
Graduate
May 9, 2024
Solved

STM32H745 - resetting of a variable in ISR does not work occasionally

  • May 9, 2024
  • 4 replies
  • 4663 views

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:

Kurngop32_1-1715256571202.png

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.

    This topic has been closed for replies.
    Best answer by Pavel A.

    Likely because operation "MainCounter++" is not atomic. It consists of two instructions, the interrupt can hit between them.

     

     

    4 replies

    Graduate II
    May 9, 2024

    >>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

    Kurngop32Author
    Graduate
    May 9, 2024
    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.

    Graduate II
    May 9, 2024

    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

    Kurngop32Author
    Graduate
    May 9, 2024

    It is called, see first post. I also checked with toggling IO because I don't trust the debugger.

    Graduate II
    May 9, 2024

     

    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?

     

    Kurngop32Author
    Graduate
    May 9, 2024

    @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.

    Pavel A.Answer
    Super User
    May 9, 2024

    Likely because operation "MainCounter++" is not atomic. It consists of two instructions, the interrupt can hit between them.

     

     
    Kurngop32Author
    Graduate
    May 9, 2024

    This was my first thought, but my second thought was: this is a problem of the (8-bit microcontroller) past.

    So if this is an actual problem, I’m a bit disappointed right now and it looks like I have to rethink a lot of code.

    Super User
    May 10, 2024

    Don't rethink, just use the proper thing: atomics.

    #include <stdatomic.h>
    
    volatile atomic_int MainCounter;
    
    void TIM1_UP_IRQHandler(void)
    {
     ........
     MainCounter = 0;
    }
    
    int main(void) {
    	MainCounter = 0;
    .......
    	while (1) {
    		MainCounter++;
    	}
    }