Issues with deepsleep() on mbed-LPC11u24

15 Jun 2013

I have spent the last couple of evenings trying to get deepsleep() to work as I expect it to on my mbed-LPC11U24. I have hit a few issues that I thought I would report here since they might help others that are trying to do the same.

First I started with the example code that I found here but I modified it to blink LED1 instead of using the LCD.

#include "mbed.h"
 
InterruptIn wakeup(p14);
DigitalOut  led(LED1); 

int main ()
{
    wakeup.rise(NULL);  // Setup rising edge interrupt (no handler function needed)
 
    led = 1;
    while (1)
    {
        deepsleep();  // Deep sleep until external interrupt
        led = !led;
    }
}

I ran that code on the device when it was only powered on VB with a regulated 3.3V source and a switch connected to p14 with 1k pull-down resistor and when the button was pressed it would short to VB. When I ran the above code in that configuration, it just appeared to hang. At first I thought it was entering deep sleep and not waking up. After some research I figured out that the problem was that it was actually hanging in an exception handler because the mbed SDK deepsleep() function attempts to make a semihost call to the mbed interface chip to disable it. This isn't possible when the device is only powered from VB since the mbed interface chip isn't even powered up in the scenario. This means that the BKPT destined for the interface chip will cause a local exception to be thrown instead.

This new code contains my work around to that issue:

#include "mbed.h"
 
InterruptIn wakeup(p14);
DigitalOut  led(LED1); 

// Pulled from mbed SDK sources but removed mbed_interface_disconnect() call
// since that would cause halt when it tried to disable the interface chip
// which isn't powered up when I am powering the device from VB.
void deepsleep(void) 
{
    // PCON[PD] set to deepsleep
    LPC_PMU->PCON = 0x1;

    // SRC[SLEEPDEEP] set to 1 = deep sleep
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    // Power up everything after powerdown
    LPC_SYSCON->PDAWAKECFG &= 0xFFFFF800;

    // wait for interrupt
    __WFI();
}

int main ()
{
    wakeup.rise(NULL);  // Setup rising edge interrupt (no handler function needed)
 
    led = 1;
    while (1)
    {
        deepsleep();  // Deep sleep until external interrupt
        led = !led;
    }
}

Running this code also leads to a hang where the device never appears to wakeup but I did notice that the device worked differently after running this code where it would take an extra press of the reset button when I plugged in the USB cable to get the interface chip to stop blinking its LED or to even just light it up. This made me think that the device was now entering deep sleep but just not waking up.

I banged my head against the wall with that issue for a few hours and then I became suspicious of this one line in the original sample:

    wakeup.rise(NULL);  // Setup rising edge interrupt (no handler function needed)

It turns out that calling rise() like this in the current SDK will actually disable the interrupt and not enable it without an interrupt handler. The final version of my code contains a dummy handler that fixes this issue in the sample code:

#include "mbed.h"
 
InterruptIn wakeup(p14);
DigitalOut  led(LED1); 

// Pulled from mbed SDK sources but removed mbed_interface_disconnect() call
// since that would cause halt when it tried to disable the interface chip
// which isn't powered up when I am powering the device from VB.
void deepsleep(void) 
{
    // PCON[PD] set to deepsleep
    LPC_PMU->PCON = 0x1;

    // SRC[SLEEPDEEP] set to 1 = deep sleep
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    // Power up everything after powerdown
    LPC_SYSCON->PDAWAKECFG &= 0xFFFFF800;

    // wait for interrupt
    __WFI();
}

static void dummyHandler(void)
{
    return;
}

int main ()
{
    wakeup.rise(dummyHandler);  // Setup rising edge interrupt
 
    led = 1;
    while (1)
    {
        deepsleep();  // Deep sleep until external interrupt
        led = !led;
    }
}

Now the code works as expected. I even measured the current when in deep sleep with this code and the current draw was down to 1.11mA. I suspect that the other people who complained that deep sleep was consuming >=14mA in their tests were actually hitting my first issue where the device wasn't even entering deep sleep.

One other thing I found as I was playing with deep sleep on the LPC11U24 version of the mbed is that it is best to upgrade to the latest mbed interface firmware. Without it I had difficulties getting new code programmed into the target device when it was in deep sleep.

15 Jun 2013

Thumb up for the discovery and sharing. Great!

15 Jun 2013

Great notes and discoveries; seems like some improvements to the SDK and example documentation needed in this area.

Simon

15 Jun 2013

Simon Ford wrote:

Great notes and discoveries; seems like some improvements to the SDK and example documentation needed in this area.

Thanks! I hope that they prove helpful.

On the SDK improvements in this area, I wonder if it would be enough to make mbed_interface_connected() WEAK like mbed_interface_uid() so that the programmer could override it in scenarios like this where they have manually disabled the mbed interface on a mbed-LPC11U24 device by not powering it up or they are using their own custom board?

Maybe it is enough to just document the fact that a dummy interrupt handler needs to be used for this deep sleep sample rather than passing in NULL?

-Adam

22 Aug 2013

Thanks a lot for posting this . It was of great help!!

23 Aug 2013

PRIYA JN,

You are welcome! I am glad that it saved someone else from lots of head scratching.

-Adam

14 Oct 2013

IS THERE ANY WAY TO WAKE IT up without using the external interrupt???like a watchdog timer or something????if so please do post the procedure and the code !

14 Oct 2013

ASIF AHMAD wrote:

IS THERE ANY WAY TO WAKE IT up without using the external interrupt???like a watchdog timer or something????if so please do post the procedure and the code !

note: i just use the sleep function!!?

23 Jan 2014

I used the following code

Break Your MBED

#include "mbed.h"
 
InterruptIn wakeup(p14);
DigitalOut  led(LED1); 
 
// Pulled from mbed SDK sources but removed mbed_interface_disconnect() call
// since that would cause halt when it tried to disable the interface chip
// which isn't powered up when I am powering the device from VB.
void deepsleep(void) 
{
    // PCON[PD] set to deepsleep
    LPC_PMU->PCON = 0x1;
 
    // SRC[SLEEPDEEP] set to 1 = deep sleep
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
 
    // Power up everything after powerdown
    LPC_SYSCON->PDAWAKECFG &= 0xFFFFF800;
 
    // wait for interrupt
    __WFI();
}
 
static void dummyHandler(void)
{
    return;
}
 
int main ()
{
    wakeup.rise(&dummyHandler);  // Setup rising edge interrupt
 
    led = 1;
    while (1)
    {
        deepsleep();  // Deep sleep until external interrupt
        led = !led;
    }
}

I added the & to pass by reference to the dummy handler so that I could actually throw a little code in there. Guess what, now when I load new programs to my mbed they will stay on the drive, but the processor will only run this code. I have disconnected usb, pressed power button, etc. Any ideas?