cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F3 stop mode problem (WFE)

arnold2
Associate II
Posted on January 30, 2013 at 15:17

Hi,

we have a problem with the STOP mode of the STM32F3. We have the feeling, that the F3 immediately returns from STOP mode, if ANY interrupt is enabled and has been activated before entering the STOP mode. The second entry into STOP mode is working (does not return without an event). We have a little demo for the STM32F3DISCOVERY board, that demonstrates this behaviour (the main.c is attached).

To provoke the error, do the following:

1. disable (''comment-out'') the second WFE in line 58

2. Build and run the project

3. Press and release the button. Nothing to be seen, but in fact the LED is switched on and off very fast (can be seen with an osci; the same signal is on PA3 for verfication).

With the following change the error could be ''worked around'' (at least in my tests):

1. Enable the 2nd WFE and all following NOPs

2. Build and run the project

3. Press and Release the button.  After releasing the button the blue LED is switched on, the MCU is in STOP mode now.

4. Press and release the button. The MCU wakes up, the LED is switched off.

Another problem occurs, if you remove the 4 NOPs after the 2nd WFE. Then the core goes into hardfault handler.

With an STM32F1 and L1 we don't have these problems! Can anyone else confirm this behaviour and/or has an explanation for it? Any general comments and hints related to the STOP mode especially with the STM32F3xx are appreciated. Has anyone the STOP mode of the STM32F3 working??

thanks in advance,

Ren�

#stm32f3-stop-mode-problem-wfe
16 REPLIES 16
Amel NASRI
ST Employee
Posted on February 15, 2013 at 12:17

Hi René,

Try this sequence of code and let me know if you still face the same issue:

/* init the TIM7 */

RCC->APB1ENR |= RCC_APB1ENR_TIM7EN;

TIM7->PSC = 7; // => 1 MHz timer clock frequency (at PCLK=8 MHz)

TIM7->ARR = 1000 - 1; // => 1 kHz interrupt rate

TIM7->DIER = TIM_DIER_UIE; // enable the update interrupt

NVIC_EnableIRQ( TIM7_IRQn );

TIM7->CR1 |= TIM_CR1_CEN; // start the timer

RCC->APB1ENR |= RCC_APB1Periph_PWR;

/* Configure PA0 pin as input floating */

RCC->AHBENR |= RCC_AHBPeriph_GPIOA;

RCC->APB2ENR |= RCC_APB2Periph_SYSCFG;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

GPIO_Init(GPIOA, &GPIO_InitStructure);

EXTI_InitStructure.EXTI_Line = EXTI_Line0;

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);

PWR_WakeUpPinCmd(PWR_WakeUpPin_1, ENABLE);

/* Configure the pin to be toggled: PB2 */

RCC->AHBENR |= RCC_AHBPeriph_GPIOB;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_Init(GPIOB, &GPIO_InitStructure);

/* Configure PWR registers to enter STOP mode */

PWR->CR &= 0xFFFFFFFC; // clear the PDDS and LPDS bits

PWR->CR |= 0x00000000; // STOP Mode: Regulator on

// PWR->CR |= 0x00000001; // STOP Mode: Regulator off

/* Set SLEEPDEEP bit of Cortex System Control Register */

SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

__WFE();

/* after waking-up from STOP mode this is the first instruction to be executed */

SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);

/* Configure PB1 as Output */

GPIOB->ODR = 0x00000002;

If you think that the interrupt is the problem root cause, try to disable it just before entering stop mode (not only clear the pending interrupts).

I have a doubt if the MCU really enter stop mode with examples you provided -to re-check-.

Regards,

ST.MCU

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

arnold2
Associate II
Posted on February 15, 2013 at 13:54

Hi st.mcu,

I have tested it. If I add a TIM7 interrupt handler and let the example run as it is, it works as it is expected to.

BUT! And that's the important point. It only works as long as there has not been an interrupt BEFORE the WFE is executed. I have added a tick counter to your example and if I wait for it to become > 0, before calling WFE, WFE returns IMMEDIATELY, regardless of disabled IRQ or not.

See below your modified example code. I have changed the output port from PB2 to PE8 (I am testing this with an STM32F3DISCOVERY board), I have added the TIM7 ISR and the tick counter and I am waiting for the tick counter to become > 0, before calling WFE. Additionally I have added a __disable_irq() according to your recommendation. If I disable the while(ticks==0) loop, the firmware works and the output port is switched AFTER the PA0 input is toggled. If you wait for ticks to become != 0, the example does NOT work. WFE returns immediately and the output port is switched on IMMEDIATLY after reset. To make sure, the debugger doesn't make trouble, I have disconnected the probe, powered off the target and tested it without debug probe. Same effect. WFE returns immediately.

Could you please test the code with the modifications I made (except the one related to the output port)? Are you getting the same behaviour?

#include <stdint.h>

#include <stm32f37x.h>

volatile uint32_t ticks = 0;

void TIM7_IRQHandler(void);

void TIM7_IRQHandler(void)

{

    TIM_ClearITPendingBit( TIM7, TIM_IT_Update );

    ticks++;

}

int main(void)

{

    int v = 0;

    

    GPIO_InitTypeDef GPIO_InitStructure;

    EXTI_InitTypeDef EXTI_InitStructure;

    

    /* init the TIM7 */

    RCC->APB1ENR |= RCC_APB1ENR_TIM7EN;

    TIM7->PSC = 7; // => 1 MHz timer clock frequency (at PCLK=8 MHz)

    TIM7->ARR = 1000 - 1; // => 1 kHz interrupt rate

    TIM7->DIER = TIM_DIER_UIE; // enable the update interrupt

    NVIC_EnableIRQ( TIM7_IRQn );

    TIM7->CR1 |= TIM_CR1_CEN; // start the timer

    

    RCC->APB1ENR |= RCC_APB1Periph_PWR;

    

    /* Configure PA0 pin as input floating */

    RCC->AHBENR |= RCC_AHBPeriph_GPIOA;

    RCC->APB2ENR |= RCC_APB2Periph_SYSCFG;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    

    EXTI_InitStructure.EXTI_Line = EXTI_Line0;

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;

    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

    EXTI_InitStructure.EXTI_LineCmd = ENABLE;

    EXTI_Init(&EXTI_InitStructure);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);

    PWR_WakeUpPinCmd(PWR_WakeUpPin_1, ENABLE);

    

    /* Configure the pin to be toggled: PE2 */

    RCC->AHBENR |= RCC_AHBPeriph_GPIOE;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_Init(GPIOE, &GPIO_InitStructure);

    

    /* Configure PWR registers to enter STOP mode */

    PWR->CR &= 0xFFFFFFFC; // clear the PDDS and LPDS bits

    PWR->CR |= 0x00000000; // STOP Mode: Regulator on

    // PWR->CR |= 0x00000001; // STOP Mode: Regulator off

    

    while( ticks == 0 )

    {

        v++;

        v++;

    }

    

    __disable_irq();

    

    /* Set SLEEPDEEP bit of Cortex System Control Register */

    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    __WFE();

    /* after waking-up from STOP mode this is the first instruction to be executed */

    SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);

    

    /* Configure PE8 as Output */

    GPIOE->ODR = 0x00000100;    

    

    return( 0 );

} //$(ProjectDir)/STM32F37x_StdPeriph_Driver/incint main(void)

To be more clearly, my assumption is as follows: If there has ever been an interrupt before trying to put the STM32F3 into STOP mode using WFE, WFE returns immediately. So I guess, that the internal 1 bit event register is set, although no interrupt source is configured to generate an event. That's why WFE returns immediately.

Amel NASRI
ST Employee
Posted on February 21, 2013 at 18:00

Hi René,

Sorry for this delayed reply. I tested the code you provided and got the same result: it works only if there are 2 WFE commands. Checking the power consumption values, it seems that the mcu doesn't enter stop mode if only one WFE command is executed. Seeing the following explanation for WFE command from ARM, I suspect that the event register is 1. But I don't have an explanation why. This is the ARM explanation:

WFE

is a hint instruction. If the event register is 0,

WFE

suspends execution until one of the following events occurs: - an exception, unless masked by the exception mask registers or the current priority level - an exception enters the Pending state, if

SEVONPEND

in the System Control Register is set - a Debug Entry request, if Debug is enabled

- an event signaled by a peripheral or another processor in a multiprocessor system using the

SEV

instruction.

If the event register is 1,

WFE

clears it to 0 and returns immediately. That is why the second WFE works fine.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

arnold2
Associate II
Posted on February 21, 2013 at 19:49

Hi,

thank you for (at least) the confirmation of what I have seen!

My guess is, that there is a bug (or a ''device limitation'' to speak in terms of the ST documentation) in the STM32F3. The event register shouldn't be set. It should only be set, if an interrupt becomes pending, THAT IS CONFIGURED to set the event register, for example one of the EXTI pins. But in the F3 it seems, that EVERY interrupt sets the event register. At least I have seen this for the SysTick timer and for other timers (as in the example you provided). With the STM32L1 and the STM32F1 I haven't seen this behaviour.

If this actually is a bug, it would be fine, if there was an entry in the errata sheet about that. My workaround for now is, to make sure, that at least one interrupt becomes pending before I call WFE (I am using the systick counter for that). Then I call WFE twice. The first one returns immediately and the second one puts the chip in STOP mode. In the tests I have made so far, that seems to work. But if there is actually a bug in the chip, what do I have to be aware of else...

yzhang1985
Associate III
Posted on October 06, 2015 at 20:09

Looks like I'm having almost the same problem 2 years later with STM32F4 and STM32F7. I use WFI and it also immediately wakes up from STOP. I found turning

off SysTick before entering STOP allows it to stay in STOP mode until the real time clock alarm interrupt wakes it up:

while (true)

{

    HAL_RTCEx_SetWakeUpTimer_IT(&RTCHandle, 0x2000, RTC_WAKEUPCLOCK_RTCCLK_DIV16);

    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;

    HAL_RTCEx_DeactivateWakeUpTimer(&RTCHandle);

    SYSCLKConfig_STOP();     // restore PLL as system clock

    HAL_Delay(1000);

}

Maybe this will also allow WFE not experience spurious wakeups. I don't have a multicore processor, so I can't test. Why isn't turning off SysTick in the STM32F4/7 Cube HAL?

Posted on October 06, 2015 at 20:37

SysTick is a system handler, but acts like an interrupt.

WFI = Wait For Interrupt

Not surprising that when waiting for an interrupt, any will do, it's hardly spurious or unexpected.

The OP isn't using HAL

Why isn't turning off SysTick in the STM32F4/7 Cube HAL?

Huh?

Not sure what that means exactly, but the HAL enables the SysTick so that HAL_Delay() and other assorted timeouts function.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
yzhang1985
Associate III
Posted on October 08, 2015 at 11:35

I meant that ST should disable  and re-enable  SysTick inside HAL_PWR_EnterSTOPMode().