cancel
Showing results for 
Search instead for 
Did you mean: 

conditional transition to sleep mode

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 ?

1 ACCEPTED SOLUTION

Accepted Solutions
Cristian Gyorgy
Senior III

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.

View solution in original post

4 REPLIES 4
Cristian Gyorgy
Senior III

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.

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.

Cristian Gyorgy
Senior III

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.

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