cancel
Showing results for 
Search instead for 
Did you mean: 

WFI problem

adrian4
Associate II
Posted on June 25, 2009 at 20:54

WFI problem

11 REPLIES 11
adrian4
Associate II
Posted on May 17, 2011 at 13:13

Hi,

I have a problem with the WFI instruction on the STM32F101.

My application has an OFF mode where all the peripherals are stopped and the STM32 put into stop mode with the function PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);

A pushbutton is connected to an I/O line and an EXTI interrupt is enabled for this line to wake up.

The EXTI interrupt handler sets a flag in memory to indicate this was the cause of the restart, and a software reboot generated.

This all works fine and the system can be reliably stopped and restarted using this mechanism.

However, in an attempt to reduce the operating currrent I recently made a change to use the WFI feature in my main loop:

while (1) // Start of main loop

{

// Stall here until 100ms has passed since last time here

Main_100ms_Timer1Flag = 0;

while (Main_100ms_Timer1Flag == 0)

{ // Flag is set by a timer interrupt every 100ms

__WFI(); // Wait for interrupt

}

//... Main background tasks

}

Now with the WFI instruction, the stop and wake up still works but when it reboots something goes

wrong and it hangs. My application still seems to boot and from startup manages to print a certain amount of debug information out on one of the UARTs so some interrupts must be running, but it still hangs.

This only happens when I have the WFI instruction in the code, even though it is not active at the point the stop, sleep and reboot process is executed.

I have explored the NVIC settings and perform a Deinit on startup so do not believe this is the problem.

Can anyone help shed some light?

joseph239955
Associate II
Posted on May 17, 2011 at 13:13

I am not 100% sure if this is the case for STM32, but some microcontroller designs might powerdown the processor when deep sleep mode is used. If the sleep mode is enter by the vendor's driver library functions, then the function first save the CPU state into SRAM, then enter deep sleep and power down. When the processor wake up, the boot loader detect the previous sleep event from SRAM and then restore processor state and allow program execution to be resumed from where it was.

But if you directly execute __WFI(), the state saving process will not be carried out. As a result, when it wake up, the boot loader just restart you application from the beginning.

Hope this helps.

16-32micros
Associate III
Posted on May 17, 2011 at 13:13

Hi Adrian,

Could you check if you have cleared the Flag called ''FLITFEN'' in the RCC_AHBENR register to disable the Flash during Sleep mode ? I'm refering to errata ''Flash memory read after WFI/WFE instruction'' case, may be it is your case but not sure.

Cheers,

STOne-32.

adrian4
Associate II
Posted on May 17, 2011 at 13:13

Thanks Joseph and STOne-32.

I can confirm that the FLITFEN bit was set (default value) as suggested in the errata: ''When using the Flash memory with two wait states and prefetch on, the FLITF clock must not be stopped during the Sleep mode – the FLITFEN bit in the RCC_AHBENR register must be set (keep the reset value).''

Basically it seems to reboot fine from stop using the PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); function,

but only if this is the only WFI instruction in the code.

With the other WFI in there, the reboot works, the application restarts and gets to a certain point (after which interrupts have been running) but fails shortly afterwards.

In comparing differences between the two versions with and without the second WFI, I found the BFHFMIGN bit in CFG_CTRL register is set in the one that works just before the STOP function is called. It is clear in the one that doesn't.

This is the last place I have visibility as the debug session is disconnected when we go to the stop state and I cannot get debug access following the reboot by this path without reloading and destroying the evidence.

I have attached a document with a more detailed description of the problem.

Thanks in advance for any advice.

16-32micros
Associate III
Posted on May 17, 2011 at 13:13

Hi Adrian,

It seems a complex case to understand without having your code and reproducing it. I recommend you to Enable the features to be able to debug with Keil even if you are in STOP or Sleep Modes by setting the required bits in ''DBGMCU_CR'' register at address ''0xE0042004'' please refer to RM0008, sub-section : ''Debug MCU configuration register'' and then let us know what you found. It seems that you catch a Fault in this case between exception , to be checked ? Do you have also configured your stack alignment to be set to 8-byte aligned in ''SCB_CCR'' register : Refer to PM0056 , section : System control block (SCB).

Hope this will give you some ideas to progress debugging your application,

Cheers,

STOne-32.

adrian4
Associate II
Posted on May 17, 2011 at 13:13

Thanks STOne-32.

I have now managed to debug to a greater level and can now see that it is the main loop WFI that is causing interrupts to be ignored, but only after a PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); has been previously performed and exited with an interrupt.

The boot sequence is:

1) Boot from hard reset

2) Main code performs initialisation

3) Main code prints some debug using USART interrupts

4) Main code while(1) loop starts

5) Main while loop waits on a timer interrupt using WFI whilst idle

6) Timer interrupt sets a flag which allows main while loop to iterate once

then return to 5.

All this works fine for many iterations without problem.

Then in the main loop, when the condition is detected that requires unit to go to low power, it calls a function that configures and enables an EXTI interrupt and finishes with the ST lib function call:

PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);

This works as expected, stops execution and cpu clock and the supply current correctly reduces.

Then when the EXTI interrupt is triggered, the EXTI interrupt handler is invoked which clears the causal EXTI interrupt flag and returns back to the main function where a software reboot is performed using this code:

NVIC_DeInit();

JumpAddress = *(vu32*)0x00000004; // Reset vector

Jump_To_Loader = (pFunction) JumpAddress;

// Setup the IAP loader's Stack Pointer - from the Vector Table

// (the first entry in the vector table holds the initial SP value)

__MSR_MSP( *(vu32*)0x00000000 );

Jump_To_Loader();

This also works and the app is successfully restarted (so the byte align business must also be OK)

But this time it only gets as far as step 5 in the sequence above. I can tell this because the debug strings can be seen from the serial port at the right baud rate and then it just stops.

Step 5 is the WFI instruction that was working correctly before.

I can also repeat this with the DBGMCU_CR bit set to allow debug during sleep and setting a breakpoint on the line before WFI, which it gets to.

So it would appear that the sleep function part of the WFI works but the exit by interrupt is blocked. It is as if some internal logic involving this mechanism (maybe NVIC?) has been affected by the previous

PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); instuction leaving something in a residual state. Note that my reboot code calls NVIC_DeInit(); which you would have thought would clear any residual conditions.

A hard reset clears the fault and the correct operation can be resumed.

I hope this is enough information for someone to help diagnose what is wrong.

Cheers

Adrian

st3
Associate II
Posted on May 17, 2011 at 13:13

Could it be that there's a clock somewhere that's required, but hasn't been re-started?

adrian4
Associate II
Posted on May 17, 2011 at 13:13

Thanks ST7.

I don't think it could be a clock not restarting problem because the reboot sequence uses the same initialisation code as from the hard reset, which always works.

Nevertheless its something to explore so I'll check it out.

Thanks.

andreas2
Associate II
Posted on May 17, 2011 at 13:13

Your problem is likely due to not performing a proper reset.

After entering STOP mode, you have the SLEEPDEEP bit set in the Cortex System Control Register (SCB->SCR). Then you perform the NVIC_DeInit() ''reset'', which only resets the NVIC registers, not the SCB registers (including the SLEEPDEEP bit). So when you execute what you think is a normal WFI, you're actually putting the system in STOP mode again.

You might be able to call NVIC_SCBDeInit() too, to better emulate a true reset, but why bother when you can just issue a full reset including fetching stack pointer and reset vector: NVIC_GenerateSystemReset()

Besides, your fake reboot will also get you into trouble if you are, or will be, running on the process stack. And probably in a multitude of other ways as well.