cancel
Showing results for 
Search instead for 
Did you mean: 

WFE - Exiting stop mode.

paulsmitton9
Associate III
Posted on June 26, 2008 at 15:20

WFE - Exiting stop mode.

7 REPLIES 7
paulsmitton9
Associate III
Posted on May 17, 2011 at 12:37

4.3.3 of the reference manual says:

If the WFE instruction is used to enter Sleep mode,

the MCU exits Sleep mode as soon as an event occurs.

This event can be either an interrupt enabled in the

peripheral control register but not in the NVIC, or

an EXTI line configured in event mode.

Has anybody managed to set WFE and exit it using ''an

interrupt enabled in the peripheral control register

but not in the NVIC'' ?

This implies any interrupt flag will do it, but it only

wakes up for me if the interrupt is set in the nvic

(and executes).

joseph239955
Associate II
Posted on May 17, 2011 at 12:37

Hi Paul,

I haven't tried it myself, but it looks like there are two way to do it.

The ST reference manual seems to be referring the method 1 below:

1) Using the Event mask register.

Beside from enabling the interrupt in the peripheral control,

you also need to set the Event Mask Register (EXTI_EMR) (section 8.3.2)

to enable the peripheral to trigger the event signal. And base on the

circuit diagram in figure 16 (section 8.2.2) you also need to make

sure you set the interrupt source as rising edge trigger or falling edge

trigger. (so in total you must set up as least two registers on top of the peripheral's interrupt enable).

2) Use SEVONPEND feature on NVIC

This control bit is in bit[4] of NVIC System Control Register (0xE000ED10)

is SEVONPEND control for NVIC. When a new interrupt pending occurred,

this should be able to generate a internal event in the NVIC to wake up

the core.

regards,

Joseph

[ This message was edited by: joseph.yiu on 22-06-2008 00:00 ]

paulsmitton9
Associate III
Posted on May 17, 2011 at 12:37

Thanks Joseph!

To use the event mask resister, I think the event needs to be one of those linked to an exti line.

However, setting the SEVONPEND bit works perfectly :)

If anyone's looking, theres a firmware library function to do it:

NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, ENABLE);

paulsmitton9
Associate III
Posted on May 17, 2011 at 12:37

I have noticed that my __WFE(); sometimes returns immdiately.

This is described in D.7.68 of the ARMv7M Architecture Application Level Reference Manual:

If the Event Register is set, Wait For Event clears it and returns immediately.

By calling WFE twice in succession:

If the Event Register is Set, the first WFE will clear it, and the second will sleep.

If the Event Register is not set, the first will sleep until it is set, and then the second will clear it.

However, this is clearly unsafe, since if the actual event occurs before the first WFE (e.g. delayed by an interrupt) then it will sleep until a further event occurs (if one ever does).

Does anybody know the address of the Event Register to clear it properly?

The arm ''Application Level'' manual suggests calling ClearEventRegister(), and the proper manual is not available for download.

joseph239955
Associate II
Posted on May 17, 2011 at 12:37

Hi Paul,

Use the following assembly sequence:

SEV ; Send Event , this set the event register to 1

WFE ; 1st WFE will not cause sleep, but will cause event reg to clear

WFE ; 2nd WFE will cause sleep

Joseph

paulsmitton9
Associate III
Posted on May 17, 2011 at 12:37

Excellent, thanks again Joseph!

Just another note to anyone else trying this; before calling WFE make sure that you clear the pending bit in the nvic that you are waiting to see change (e.g. call NVIC_ClearIRQChannelPendingBit).

joseph239955
Associate II
Posted on May 17, 2011 at 12:37

You're welcome Paul.

I forgot to mention a corner case:

If you use SEV - WFE - WFE sequence, and if there is a interrupt take place between the two WFE, the event register will get set again and the second WFE will not enter sleep.

Alternatively, you could use a loop to handle this

int loopexit = 0;

while (loopexit == 0) {

__WFE(); // Try to sleep

if (Check_If_Work_Need_To_Be_Done()) {

Do_Some_Work();

}

loopexit = Check_If_Want_To_Exit_Sleep();

}

In this way it doesn't matter what is the current value of the event register, as it will repeat the __WFE until it entered sleep or if you want it to exit from sleep.

regards,

Joseph