Skip to main content
Graduate II
June 14, 2022
Solved

conditional transition to sleep mode

  • June 14, 2022
  • 3 replies
  • 1893 views

In many aplications i am using simple template, where interrupt routines (for example UART receive) raise flags (volatile variables) and main() function polling these flags and processing these events (for example parsing incoming UART charaters). I would like to put MCU to sleep when there is nothing to do - when all flags are cleared. But i can not simply write:

if(!flag1 && !flag2 ...){
 go_to_sleep();
}

because of potential race condition. Flag can be set during if statement evaluation and there is risk, that MCU will go sleep with raised some flag. Is there any mechanism how to sleep STM8S (and possibly STM8L) safe - only if flags are cleared ?

just for interest:

STM32 handles that problem by calling "send event" instruction (at place where flag is raised), which prevents falling asleep.

AVR have separated bit for "sleep enable" and this bit can be cleared in IRQ routine, where flag is raised and also prevent MCU from going to sleep mode.

How to do that with STM8 ?

    This topic has been closed for replies.
    Best answer by Cristian Gyorgy

    Hi!

    Below is one of the ways I do it (with priority event handling), but it is in assembler:

    forever:
    		sim
    		ld A, EVENT_REG
    		jrne f_tst
    f_slp:		wfi
    		sim
    		ld A, EVENT_REG
    		jreq f_slp
    f_tst:		rim
    		bcp A, #(1<<EVENT_0)
    		jrne f_event_0
    		bcp A, #(1<<EVENT_1)
    		jrne f_event_1
    		;...
    		bcp A, #(1<<EVENT_7)
    		jreq forever
    		call Handle_Event_7
    		jp forever
    f_event_0:
    		...
    		jp forever
    f_event_1:
    		...
    		jp forever

    Some explanations:

    like you wrote, interrupts do basic immediate tasks and set a flag (the EVENTs in the code snip) to signal further processing. In the forever loop, if any of the event flag is set, the flags are tested one by one and if set the event task handler is executed.

    If one of the events gets set continuously or too often, the following events will not be handled - but I want it to run this way, as the last event is the one to reset the watchdog, and in case it does not get executed in time, I know something is not running the way I planned it. This can be easily changed by using calls instead of jumps to event handlers.

    How you would write this in C or how C compilers do their loops I cannot tell.

    3 replies

    Visitor II
    June 15, 2022

    Hi!

    Below is one of the ways I do it (with priority event handling), but it is in assembler:

    forever:
    		sim
    		ld A, EVENT_REG
    		jrne f_tst
    f_slp:		wfi
    		sim
    		ld A, EVENT_REG
    		jreq f_slp
    f_tst:		rim
    		bcp A, #(1<<EVENT_0)
    		jrne f_event_0
    		bcp A, #(1<<EVENT_1)
    		jrne f_event_1
    		;...
    		bcp A, #(1<<EVENT_7)
    		jreq forever
    		call Handle_Event_7
    		jp forever
    f_event_0:
    		...
    		jp forever
    f_event_1:
    		...
    		jp forever

    Some explanations:

    like you wrote, interrupts do basic immediate tasks and set a flag (the EVENTs in the code snip) to signal further processing. In the forever loop, if any of the event flag is set, the flags are tested one by one and if set the event task handler is executed.

    If one of the events gets set continuously or too often, the following events will not be handled - but I want it to run this way, as the last event is the one to reset the watchdog, and in case it does not get executed in time, I know something is not running the way I planned it. This can be easily changed by using calls instead of jumps to event handlers.

    How you would write this in C or how C compilers do their loops I cannot tell.

    Graduate II
    June 15, 2022

    Thanks for reply. But what happens if interrupt takes place after line 3 or after line 7 (and before jrne/jreq instruction) ? If i read asm correctly, program then should sleep with pending event.

    Visitor II
    June 16, 2022

    At line 2, the sim instruction disables interrupts before testing the event flags. If none are set, it goes to sleep (wfi) - but this is the good part, when executing teh wfi instruction the interrupts are enabled again and the pending interrupt is being executed, so it will not go to sleep but continue code execution after wfi.

    Before testing the events in EVENT_REG, I always disable interrupts to make sure it does not change while I test it.

    When there is a pending event, until I identify and handle it, I enable interrupts again, in line 9, the rim instruction.

    Graduate II
    June 16, 2022

    Thanks. Now i see. I did not realize that wfi instruction also enables interrupts.