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.
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!
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.
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.