10 years, 4 months ago.

mbed sleep problem with RTOS

Hi all,

I want to create a low power application with mbed (LPC1768) and have been following tutorial by Jim Hamblen at: https://mbed.org/cookbook/Power-Management and also http://mbed.org/users/no2chem/notebook/mbed-power-controlconsumption/

I was able to wake the mbed from Sleep() by GPIO interrupt, UART interrupt, and Ticker. I use PowerControl library.

Here is my code:

just additional GPIO and UART interrupt from the tutorial

#include "mbed.h"
#include "PowerControl/PowerControl.h"
#include "PowerControl/EthernetPowerControl.h"
// Need PowerControl *.h files from this URL
// http://mbed.org/users/no2chem/notebook/mbed-power-controlconsumption/
 
// Function to power down magic USB interface chip with new firmware
#define USR_POWERDOWN    (0x104)
int semihost_powerdown() {
    uint32_t arg;
    return __semihost(USR_POWERDOWN, &arg);
}
 
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

bool rx_uart_irq = false;
 
Serial device(p28, p27);  // tx, rx
InterruptIn button(p5);

// Circular buffers for serial TX and RX data - used by interrupt routines
const int buffer_size = 255;
// might need to increase buffer size for high baud rates
char tx_buffer[buffer_size];
char rx_buffer[buffer_size];
// Circular buffer pointers
// volatile makes read-modify-write atomic 
volatile int tx_in=0;
volatile int tx_out=0;
volatile int rx_in=0;
volatile int rx_out=0;
// Line buffers for sprintf and sscanf
char tx_line[80];
char rx_line[80];

void Rx_interrupt();
 
void blink() {
    myled2 = !myled2;
}


int main() {
    //int result;
    
    device.baud(9600);
    device.attach(&Rx_interrupt, Serial::RxIrq);
// Normal mbed power level for this setup is around 690mW
// assuming 5V used on Vin pin
// If you don't need networking...
// Power down Ethernet interface - saves around 175mW
// Also need to unplug network cable - just a cable sucks power
    PHY_PowerDown();
    myled2 = 0;
// If you don't need the PC host USB interface....
// Power down magic USB interface chip - saves around 150mW
// Needs new firmware (URL below) and USB cable not connected
// http://mbed.org/users/simon/notebook/interface-powerdown/
// Supply power to mbed using Vin pin
    //result = semihost_powerdown();
// Power consumption is now around half
 
// Turn off clock enables on unused I/O Peripherals (UARTs, Timers, PWM, SPI, CAN, I2C, A/D...)
// To save just a tiny bit more power - most are already off by default in this short code example
// See PowerControl.h for I/O device bit assignments
// Don't turn off GPIO - it is needed to blink the LEDs
    Peripheral_PowerDown( ~( LPC1768_PCONP_PCUART0 | 
                             LPC1768_PCONP_PCUART2 |
                             LPC1768_PCONP_PCGPIO |
                             0));
 
// use Ticker interrupt and Sleep instead of a wait for time delay - saves up to 70mW
// Sleep halts and waits for an interrupt instead of executing instructions
// power is saved by not constantly fetching and decoding instructions
// Exact power level reduction depends on the amount of time spent in Sleep mode
    //blinker.attach(&blink, 0.05);
    button.rise(&blink);
    while (1) {
        myled1 = 0;
        printf("bye\n");
        Sleep();
        if(rx_uart_irq == true) {
            printf("wake from uart irq\n");
            rx_uart_irq = false;
        }
        myled1 = 1;
    }
}

// Interupt Routine to read in data from serial port
void Rx_interrupt() {
    myled2 = !myled2;
    rx_uart_irq = true;
        uint32_t IRR0= LPC_UART2->IIR;
    while ((device.readable()) && (((rx_in + 1) % buffer_size) != rx_out)) {
        rx_buffer[rx_in] = LPC_UART2->RBR;
        rx_in = (rx_in + 1) % buffer_size;
    }
}
 

Here is the problem: The Sleep() doesn't put the mbed to sleep when mbed-rtos library is added. Even when I don't use any function calls from the rtos library , Sleep() doesn't work.

My explanation: Probably the rtos has a timer running in the background and it generates an interrupt every now and then. (But it kinda doesn't make sense because I haven't use any function or object from rtos library)

My question:

  • Has any one made the Sleep() function work with rtos? if yes, please point me to the right direction or if you have the solution, please share.

2 Answers

10 years, 4 months ago.

As far as I know the RTOS library configures the SysTick timer for a 1ms interrupt in order to perform scheduling. You don't have to use any RTOS functions in order for this to happen, simply importing the library completely changes your startup code. By the time you're in main(), the RTOS is up and running and main() is your first thread.

Take a look at RTX_Conf_CM.c. You should be able to uncomment the call to sleep() in os_idle_demon(). You may need to add extern void sleep(void); as well.

Untested Code!

/*----------------------------------------------------------------------------
 *      OS Idle daemon
 *---------------------------------------------------------------------------*/
extern void sleep(void);

void os_idle_demon (void) {
  /* The idle demon is a system thread, running when no other thread is      */
  /* ready to run.                                                           */
  
  /* Sleep: ideally, we should put the chip to sleep.
     Unfortunately, this usually requires disconnecting the interface chip (debugger).
     This can be done, but it would break the local file system.
  */
  for (;;) {
      //Go to sleep
      sleep();
  }
}

10 years, 4 months ago.

First of all, low power for the LPC1768 is kinda relative, it isn't exactly low power. Also the mbed board wasn't designed for it (such as power regulators which consume loads of power).

Neil is correct about the problem. Instead of his idea you could also try:

NVIC_DisableIRQ(SysTick_IRQn);

and afterwards:

NVIC_EnableIRQ(SysTick_IRQn);

Also untested btw