Sleeping and Interrupts

10 Nov 2009

Is it possible to put the  mbed  module into deep sleep mode and  then to wake  it  up via  any  one of the port  lines,  if these  have  been set  up  as interrupts? Reason is to reduce power  and  also to reduce  noise  when th e controller is  embedded in a sensitive  analog application?

 

Andrew

10 Nov 2009

Please note that using the low power mode can break mbed's runtime or have some weird side-effects, like drifting clock. That said, something like this should work:

void enter_sleep_mode()
{
#if defined(TARGET_LPC1768)
__wfi(); // (enter sleep mode and) wait for interrupt 
#else
LPC_SC->PCON |= 1; // set PM0 = 1: enter idle mode (assuming PM1 and PM2 are 0)
#endif
}
...
while (1)
{
enter_sleep_mode();
}

You can also turn off some peripherals you don't need with PCONP register and enter even more power-conserving modes using other bits in PCON. For details see User Manual for LPC17xx or LPC23xx depending on your mbed model.

10 Nov 2009

Hi,

A version with a timeout could be possible/useful too. Something like:

void sleep_end() {}
void sleep_us(int us = 0) {
    Timeout t;
    if(us > 0) {
        t.attach_us(&sleep_end, us);
    }
    __wfi();
}

i.e if an argument is passed, then it will wake up after a timeout even if no other interrupt has occured.

Finally, you could guarantee a sleep for an amount of time, even if interrupts happen in the mean time; it'd just put the core back to sleep until the time had passed; this is more like a sleeping/lowpower wait that is interrupt-able. Would need a little care for implementation to avoid race conditions but possible if interesting.

There were some other comments in:

Please continue the suggestions, as this would be a nice thing to fold in official solution for.

Simon

14 Nov 2009

Thanks  for the  suggestions - I'll  give  them a try.

 

Andrew

11 Dec 2010

 

 

This  is  the main processing  loop of  my program that sits in  main();

I am expecting the mbed to execute through the loop once,  and then sit at   LPC_SC->PCON |= 1 until it gets an interrupt,  after which it will go service the  IRQ (which assign a value to flag) and then go through the switch statement  and halt again.

 

Whats happening,  is  it loops  endlessly  as  evidenced by the printf("loop") statement. 

 

What am I  doing wrong?

 

LOOP:
    //wait_here();
    printf("loop\n\r");
    //do {
   
   
        switch (flag) {
            case 9211: volremote();break;     /* volume UP */
            case 9221: volremote();break;      /* volume DOWN */
            case 9231: inputselect();break;    /* Input Select */
            case 9241: mute_output();break;    /*  Mute */
            case 9251: play();break;            /* Play */
            case 9261: power_on_off();break;   /* power ON/OFF */
                   
        }
        flag=0;      /* flush the flag since we finished the task */
        //do{
        //wait_ms(200);
        //lightsensor();
        //led=!led;
        //}while (1);  /* just sit here waiting for an interrupt */
        LPC_SC->PCON |= 1; // set PM0 = 1: enter idle mode (assuming PM1 and PM2 are 0)

        goto LOOP;
       
        
        //remcontoken=FALSE;
       
        // lightsensor();
   // } while (1);
}

11 Dec 2010

Andrew, are you using LPC1768 or LPC2368 (beta) module? LPC1768 does not use PCON to go to sleep, you need to use WFI. Another issue is that the processor cannot go to sleep with the debugger attached. You can detach the debugger with an experimental firmware, but you won't be able to use semihosting (printf and local filesystem) after that. For more info see here.

11 Dec 2010

Igor,  I am using the LPC1768.  I'll have to read  through your  link carefully in the morning.

Thanks  for the info

 

12 Dec 2010

Still not luck.  But  I think mt problem is elsewhere , and I need to solve that  issue  before  trying to sort the HALT  out.  I hope you  can point me in the right direction

Here is the serial input routine,  which  is getting the correct  info - if I print out flag (or remaction), the data is correct.

void remotecontrol(void) {

    int q=0;

    myled=!myled;      /* just to let us know we are looping through here */
    wait_ms(10);
    if (remote.scanf("%s", remcon)) {
     remaction=atoi(remcon);
    }
    /* here we flush  everything to make sure that any garbage entries do not remain */
    /* because what we got in from the serial link was not a valid string */
    else {
        for (q=0;q<8;q++) {
            remcon[q]=(' '); /* clean it up for the next cycle */
           remaction=0;
        }
    }
   
    remcontoken=1;   /* this tells us the command came from the r/control */
    //printf("%d\n\r",remaction);
    flag=remaction;
    }

 

Here is the main loop

 

int main () {
    NAOE=LOW;               /* make sure the A6821's are disabled */
    wait_ms(5);
    initialize();           /* call the SBUS  routine to clean things  up */
    powersw.fall(&power1);
    Serial remote(NC, p27);
    remote.baud(1200);
    remote.format(8, Serial::None, 1);
    remote.attach(&remotecontrol);
    wait(1); 
/* this is the main operating loop  */

LOOP:
    //printf("");
    switch (flag) {
            case 9211: volumecontrol();break;     /* volume UP  - uses same as volume DOWN*/
            case 9221: volumecontrol();break;      /* volume DOWN */
            case 9231: inputselect();break;    /* Input Select */
            case 9241: mute_output();break;    /*  Mute */
            case 9251: play();break;            /* Play */
            case 9261: power_on_off();break;   /* power ON/OFF */
        }
        printf("%d____\n\r",flag);
        flag=0;      /* flush the flag since we finished the task */
        //do{} while(flag==0);        /* wait here */
        //halt();
        wait_ms(10);
        goto LOOP;
 }

Here are the problems:-

1. the  rotatry encoders and p/buttons work correctly - these all activate  IRQ's  which go away and do stuff.  For  all of the IRQ's (except serial),  I  have a very  short routine that simply assigns a number to the flag. The  intention is that I then come  back into main,  execute the switch statement,  and  then ideally halt.  for  now I am just looping  around  LOOP  GOTO.  I  tried a do{ } while(1) as well but that just hangs  everything.

2. However,   the input via the serial  link does not work at all - no resoponse

3. The push button and rotatry encoder response is 'flaky'.  Before I added the serial  input roytine,  they  worked really  well  and were very tactile.  now there's  delays,  sometimes  they miss  read etc.

I  originally  thought it was  because of the LOOP  GOTO,  and was  another  reason for trying to HALT  the mbed,  but  I  have concluded it is  because of  something else.

Here is an example of my IRQ,  this one for the power on/off  p/button.  The others are all  similar,  just the value assigned to flag changes

/*************** Power ON/OFF Interuppt **************/
void power1() {

    wait_ms(10);
    flag=9261;
   // printf("power triggered");
}