Silicon Labs


Silicon Labs a leading provider of microcontroller, sensing and wireless connectivity solutions for the Internet of Things (IoT).

You are viewing an older revision! See the latest version

Using the improved mbed sleep API

Introduction

Starting with the introduction of asynchronous I/O APIs to mbed, sleeping has become a lot more powerful. Initially supported by Silicon Labs, the new behavior of sleep() will allow you to take full advantage of the target's low-power capabilities by combining it with an asynchronous programming model.

Behavior

Starting with mbed release 99 on Silicon Labs platforms, sleep() will no longer only halt the core, something known as the WFI (wait for interrupt) instruction in the ARM world.

Calling sleep() will now, based on a specific platform's implementation, dynamically determine what sleep mode to go to. This is done by checking which peripherals are actually in use, and what events the user program is listening for. Unused peripherals and/or clock trees can be switched off by the sleep implementation, resulting in a very easy way to save power in your application.

Pitfalls

Currently, there are some known pitfalls:

  • If you are mixing asynchronous API calls with synchronous (old-style) calls, there is a possibility the synchronous call actually returns before the I/O transaction is fully complete. This is especially true for the transmit functions of Serial and I2C, where the data to send can be living in a FIFO buffer somewhere in the system waiting to be sent by the corresponding peripheral, but from a code standpoint, the transmission is complete. Calling sleep() shortly after (synchronously) transmitting data through I2C or Serial will thus result in undefined behavior. If the data is still in the FIFO at the time of going to sleep, the data transfer will get corrupted.

    Calling sleep() is perfectly safe when used in conjunction with the asynchronous APIs, since the system will rely on the completion callback to tell it that it is safe to switch that peripheral off.
  • sleep() will return after any interrupt / event, regardless of whether or not a callback has actually been registered to it. This means that for most use cases, you will have to wrap it in a while statement. See the demo code at the bottom of the page for a real-world example of this.

Wrapping sleep() in a while() loop

LowPowerTimeout halfSecondTimeout;
bool expired = false;

void callback(void) {
    expired = true;
}

void main(void) {
    /* 
    * For some reason, we want to stop the program flow for half a second
    * Instead of using wait(), which is ridiculous from a power consumption standpoint,
    * we register a timeout and sleep until the delay has passed
    */
    halfSecondTimeout.attach(callback, 0.5f);
    
    //Ensure that we only continue the program flow here after the timeout expired.
    while(!expired) sleep();

    ....
}

All wikipages