9 years, 7 months ago.

mBuino not waking up from sleep.

The code below is running on an mBuino built using the online compiler with the target set to LPC11U24 since the mBuino platform isn't listed yet in the compiler (same CPU and everything else seems to work fine with that setting).

The system is set to flash an LED when awake and toggle a second LED whenever the button is pressed (the button pulls pin P0_4 to GND). If 15 seconds go by without a button press it sleeps until the button is next pressed.

While awake the button interrupt is being generated correctly, the LED toggles and the timeout before entering sleep is reset correctly. Once asleep it never wakes up.

What have I missed?

#include "mbed.h"

InterruptIn Button(P0_4);

DigitalOut LEDOut1(P0_7);
DigitalOut LEDOut2(P0_8);

Timeout idleTimer;

//Turn off LEDs and sleep
void goToSleep()
{
    LEDOut1=0;
    LEDOut2=0;
    sleep();
}

// on button press toggle LED2 and reset the time until we go to sleep.
void onButton()
{
    idleTimer.detach();
    LEDOut2 = !LEDOut2;
    idleTimer.attach(goToSleep,15);
}

int main()
{
    Button.mode(PullUp);
    Button.fall(onButton);
    idleTimer.attach(goToSleep,15);

    while (true) {
        LEDOut1 = !LEDOut1;
        wait(0.2);
    }
}

Final solution to save people digging through comments below:

There were 2 problems, sleep is broken on LPC11U24 based devices without an interface chip.

Instead use:

void mySleep() {
    LPC_PMU->PCON = 0x0;
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
}

void myDeepSleep() {
    LPC_PMU->PCON = 0x1;
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    LPC_SYSCON->PDAWAKECFG &= 0xFFFFF800;
    __WFI();
}

The second issue is that you can't call sleep from inside an interrupt. Or to be more accurate you can sleep but the wake up interrupt must then be higher priority than the one which puts you to sleep, normally it'll be a lot simpler to avoid that situation all together and only call sleep from the main loop. (The bit about being able to wake if the wake up is a higher priority is untested speculation at this point but does make sense)

posted by Andy A 05 Sep 2014

Also see: http://mbed.org/forum/electronics/topic/5138/ for current draw numbers.

posted by Andy A 09 Sep 2014

Update: The latest release of the mBed library has the mBuino set up correctly, the library sleep and deepsleep functions will work correctly. Not of much use yet since it's not yet listed as a platform so you can't select it but that should be fixed soon.

posted by Andy A 15 Sep 2014

1 Answer

9 years, 7 months ago.

The mbed LPC11u24 also cannot enter sleep if the interface IC is not connected, such was when it is powered via the battery pin which is intended for low power applications: If it would be fixed it wouldn't be backwards compatible for systems which rely on the LPC11u24 crashing when attempting to enter sleep. (You might notice a slight undercurrent of me not really agreeing on that decission).

Luckily there is a solution: If you compile for the Seeeduino arch or the dipcortex m0 instead, the broken code should not be included.

Accepted Answer

That seems like a logical decision, after all it's good practice to rely on the CPU crashing when you issue certain commands.

Unfortunately the solution of building the code for the other platforms doesn't seem to clear the problem. :-(

posted by Andy A 05 Sep 2014

Hmmm I thought those had seperate device.h files to disable semihosting, but can't find it, might only apply to the LPC11u35s which use the same code. (The mbuino is gettign its own device.h file, so in there it will work correctly). In the meantime what should work is copy the functions from this file: https://mbed.org/users/mbed_official/code/mbed-src/file/e2f2e83d7c41/targets/hal/TARGET_NXP/TARGET_LPC11UXX/sleep.c, and remove the parts in the #if DEVICE_SEMIHOST statements. Those calls to disconnect the interface are not working, since there is no active interface, and lock up your device. (And give them a different name to make it compile).

Edit: Well it is going to work for the mbuino if they wouldn't have copy pasted that device.h file, but I guess that will be fixed, someday.

posted by Erik - 05 Sep 2014

The sleep function in the code above is now:

void goToSleep()
{
    LEDOut1=0;
    LEDOut2=0;

#if 1
    // sleep
    LPC_PMU->PCON = 0x0;
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
#else
    // deepsleep
    LPC_PMU->PCON = 0x1;
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    LPC_SYSCON->PDAWAKECFG &= 0xFFFFF800;
#endif
    __WFI();

}

No difference, it still doesn't wake up from either sleep or deepsleep.

Looking at the device.h the mBuino also supports a local file system ;-)

posted by Andy A 05 Sep 2014

Removed comment I just added on the value being used for PDAWAKECFG, it was incorrect because &= != =

posted by Andy A 05 Sep 2014

Tbh what it should do is copy the current running peripherals into the PDAWakeCFG register, so they run again when it wakes up.

Anyway I tried some stuff on an LPC1768 (only one I got here right now), and it seems what the WFI function doesn't like being called in an interrupt. Or what right now while I am typing suddenly pops into my mind: if it is in an interrupt routine when WFI is called, possibly only higher priority interrupts, so those which can interrupt the current interrupt, will trigger a wake up. (And the normal sleep() function doesn't work on my LPC1768).

So either change priority of interrupts, or only set a volatile var and then in the main loop enter sleep, then it should work fine.

posted by Erik - 05 Sep 2014

That did it. Thanks for the help.

posted by Andy A 05 Sep 2014