2022-06-14 01:04 PM
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 ?
Solved! Go to Solution.
2022-06-15 07:43 AM
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.
2022-06-15 07:43 AM
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.
2022-06-15 10:20 AM
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.
2022-06-15 09:51 PM
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.
2022-06-16 12:03 AM
Thanks. Now i see. I did not realize that wfi instruction also enables interrupts.