Power Mode 2 entry on a interrupt function (cc2530)

Hello,

i tried to enter in a low power mode from a interrupt subrutine, but i can`t return. I read in the datasheet about that, but i don´t know what i'm doing wrong.  In this code, i want to blink a LED on p1.0 while timer 1 is running and variable "i" is less than 10. When i = 10, i enter to a low power mode (PM2) on the ISR of timer 1, and i try to wake up clearing a bit on port 2 using its ISR. But i can´t return. Any help? Thank you!

 

#include "ioCC2530.h"

/************************************************/
void contador_on(void);
void contador_off(void);

/**************************************************/
unsigned char i=0;

void main(void)
{  
  unsigned long y,x=0;
  P1 &=~0x01;
  P1DIR |= 0x01;
  P1 |= 0x01;
 
  PICTL |= 0x08;      // Interrupción por flanco de bajada en puerto 2
  P2IEN |= 0x01;      // Interrupcion habilitada en el p2.0
  IEN2 |= 0x02;       // Habilitadas las interrupciones para puerto 2
  IEN0 |= 0x80;       // Habilitadas las interupciones (máscara general off)*/
 
  contador_on();
  for(;;){
    for(y=0;y<20000;y++)            // Toggle a LED on p1.0
        P1 &=~0x01;
    asm("NOP");
    // OTRAS ACCIONES
    for(y=0;y<20000;y++)
        P1 |= 0x01;
  }
}


void contador_on(void)        // Inicialize and activation of timer 1
{
  T1CNTL |= 0x00;             // Reset del contador mediante escritura registro
  T1CTL |= 0x0C;              // Tick frecuency / 128
  T1CTL |= 0x01;              // Se activa el contador del timer
  TIMIF |= 0x40;              // Máscara OFF de interrupción por overflow de timer 1
  IEN1 |= 0x02;               // Habilitadas las interrupciones para timer 1
  IEN0 |= 0x80;               // Habilitadas las interupciones (máscara general off)
}


void contador_off(void)       // Stop the timer 1
{
  T1CTL &=~ 0x0F;             // Se desactiva el contador del timer
  T1CNTL |= 0x00;             // Reset del contador mediante escritura registro
  TIMIF &=~ 0x40;             // Máscara ON de interrupción por overflow de timer 1
  IEN1 &=~ 0x02;              // Deshabilitadas las interrupciones para timer 1
}


#pragma vector = 0x33         // 0x33 -> vector interrupcion para puerto 2 en evento pin entrada
__interrupt __root void P2_ISR(void)
{
  P2IFG &=~ 0x01;             // Puesta a cero del flag de interrupc P2IFG.bit0
  IRCON2 &=~ 0x01;            // Puesta a cero del flag de interrupc IRCON2.P2IF
  //contador_off();
  IRCON &=~ 0x02;             // Puesta a cero del flag de interrupc IRCON.T1IF 
  if (i >= 10){
    SLEEPCMD &=~ 0x03;
    contador_on();
    P1 |= 0x01;
  }
  i=0;                        // Reinicio contador para desactivación
}

#pragma vector = 0x4B         // 0x4B -> vector interrupcion para timer 1 por desbordamiento
__interrupt __root void timer1_ISR(void)
{
  IRCON &=~ 0x02;            // Puesta a cero del flag de interrupc
  T1STAT &=~ 0x20;           // Puesta a cero del flag de overflow del timer 1
  i++;
  if(i >= 10){
      contador_off();
      P1 &=~0x01;
      SLEEPCMD |= 0x02;
      PCON = 0x01;
      asm("NOP");
      asm("NOP");
      asm("NOP");
    }
}

 

 

  • You can't wake up from PM2 from Timer1. The reason for this is that the system clock will stop in PM2 in order to save power, and timer 1 will stop counting. The only peripherals that are active in PM2 are the sleep timer and GPIO, which means that the only interrupts that can wake you up from PM2 are the sleep timer interrupts and GPIO interrupts. So to use PM2 in your application, you should use the sleep timer for timing the LED blink.

  • In reply to hec:

    hello Hec,

    first of all, thank you very much for your quick answer, buy maybe i didn´t explain very well. i try to enter from the timer 1, here i activate the low power mode, and it doesn´t wake up until the p2.0 is cleared (using the ISR of port 2). I can´t return using this GPIO ISR and IAR send me a warning message saying : " idata and xdata is filled 100%".  Any idea? Really thankful!

  • In reply to David Medina:

    Hi,

    Sorry about the misunderstanding. I tried your code and saw the behavior that you report. The reason for this is that you cannot wake up on an interrupt which does not have higher priority than the interrupt in which you went to sleep. When you try to do so, the chip will lock up, including the debug interface, and the lock-up of the debug interface casued the warning messages that you see.

    In order to wake up correctly, you either have to go to sleep from outside any ISR, or to set a higher priority for the interrupt that will wake you than for the ISR from which you go to sleep. Unfortunately, Timer 1 and Port 2 are in the same interrupt priority group, so it is not possible to set different priority for these two. This means that you must either change one of the interrupt sources or redesign the program so that you go to power mode from the main loop, not directly from an ISR. You can for instance set a flag in the ISR that tells the main program that it is time to go to sleep.

  • In reply to hec:

    Hello Hec,

    thank you very much for your help. i tried to wake up outside the ISR before and it's true it's work, but i couldn't understand why not in ISR. this info will be very helpful for my project. i think i will do some changes on my code to run this propertly. Again, thanks for your help and time.