Wake from LLS (Low Leakage Stop) using falling edge on O/I pin. (Current demand returns but code is not executed?)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Wake from LLS (Low Leakage Stop) using falling edge on O/I pin. (Current demand returns but code is not executed?)

Jump to solution
1,306 Views
rickstuart
Contributor V

Trying to get a KL27 Freescale processor to wake up from a low power (LLS) state on a I/O pin's falling edge. However, as best as I can tell, the processor current demand returns, but the processor does not continue to execute the program.

If I leave the debugger connected (which draws about 80uA of additional current) I can run the program into LLS mode, then press a switch which drops the voltage on I/O pin C1.  The processor current demand returns to several mAs.  But the LED flashing behavior indicating the processor has continued executing code never occurs.  If I break the program using the debugger, I see it has stopped on the line of code following the WFI (Wait For Interrupt) line of code.  (I can repeat this test with the same results with the debugger not operating.  Of course I then have no way to know for sure where the program is hung.)

I was expecting the interrupt service routine for the LLWU (Low Leakage Wake Up) feature to execute.  This should have flashed the blue LED.  Then for the execution of the code to continue in the main() routine flashing the red LED.  Then for the KL27 processor to return to low power mode waiting for the next button press which would have dropped the voltage on I/O pin C1.  Instead the (as stated above) the processor current demand returns and subsequent button presses changes nothing.  No LED activity and no current changes.

So additional code to detect activity on ports B, C, D or E was added.  The service routine for this feature flashes a green LED.  Now the behavior is very different.  Upon the first button press the current raises from 2.3uA to 1.9mA.  But there is no LED activity.  Upon the second button press the green LED flashes then the red LED flashes then the current drops to 2.3uA.  Guessing, the processor exits the LLS state after the first button press but does not execute any code.  Then, the second button press causes the PORTBCDE_IRQHandler to be called.  This flashes the green LED.  Then execution continues in the main routine flashing the red LED.  And finally the processor returns to LLS mode.

Why?

Why does the processor demand much more current but apparently not execute any code after first I/O pin C1 transitions from high to low?

(All tests and code were executed on a Freescale FRDM-KL27Z development board.)

-thanks

Code:

// start of code

// INCLUDES /////////////////////////////////////////////////////////

//-------------------------------------------------------------------

#include "MKL27Z644.h"                       // KL27 M0+ register definitions

// FUNCTION HEADERS /////////////////////////////////////////////////

//-------------------------------------------------------------------

void MCU_Init(void);                         // initializes MCU for Freedom Board

void MCU_Delay(uint32_t delay);              // delay in multiples of 1ms

//---------------------------------------------------------------------

void RGB(uint8_t Red,uint8_t Green,uint8_t Blue);    // RGB-LED Control: 1=on, 0=off, for each of the 3 colors

// *** MAIN *********************************************************

//-------------------------------------------------------------------

int main(void)

{

  MCU_Init();                                  // MCU Initialization; has to be done prior to anything else

  RGB(0,0,0);                                  // Start with all LEDs off

  __asm("CPSIE i");                            // Enable all Interrupts

  NVIC->ICPR[0] = (uint32_t)(1 << (PORTBCDE_IRQn & 0x1F));     // Clear PORTBCDE Interrupt in NVIC Core register

  NVIC->ISER[0] = (uint32_t)(1 << (PORTBCDE_IRQn & 0x1F));     // Set PORTBCDE Interrupt in NVIC Core register

  volatile int dummyread;

  RGB(0,0,0);

  SMC_PMPROT = SMC_PMPROT_ALLS_MASK;

  SMC_PMCTRL = SMC_PMCTRL_STOPM(3); // (MC2) Set STOPM = 0b11

  // Enable hi to lo transition for LLWU_P6 / pin-C1.

  LLWU_PE2 = 0x20;

  // Set the SLEEPDEEP bit to enable deep sleep mode.

  // (W/o this we only drop to about 3.1mA down from 4.6mA.)

  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

  for(;;) 

  {

    // Clear WUF6 (aka LLWU_P6) by writing a 1 to the flag bit.

    // (Need to do this to get the uC down from drawing ~2-3mA to <5uA.

    LLWU_F1 = 0x40;

  

    RGB(0,0,0);

    __asm("WFI");                                                       // Enter low power mode

  

    dummyread = PMC_REGSC;

  

    GPIOB_PTOR|=(1<<18);                       // Toggle RED LED

    MCU_Delay(200);  

  }

}

//-------------------------------------------------------------------

// ******************************************************************

// FUNCTION BODIES //////////////////////////////////////////////////

//-------------------------------------------------------------------

void MCU_Init(void)

{

// Crucial

__asm("CPSID i");                            // Disable interrupts

//Disable Watchdog

SIM_COPC=0x00;                               // Disable COP watchdog

//System Registers

SIM_SCGC5|=SIM_SCGC5_PORTA_MASK;             // Enable PortA clock

SIM_SCGC5|=SIM_SCGC5_PORTB_MASK;             // Enable PortB clock

SIM_SCGC5|=SIM_SCGC5_PORTC_MASK;             // Enable PortC clock

SIM_SCGC5|=SIM_SCGC5_PORTD_MASK;             // Enable PortD clock

SIM_SCGC5|=SIM_SCGC5_PORTE_MASK;             // Enable PortE clock

// System clock initialization

MCG_MC|=MCG_MC_HIRCEN_MASK;                  // Enable 48MHz HIRC

MCG_C1=MCG_C1_CLKS(0);                       // Enable Main Clock Source of the 48MHz HIRC

SIM_CLKDIV1&=~(SIM_CLKDIV1_OUTDIV1(1));      // Set Core Clock/1=48MHz

SIM_CLKDIV1|=(SIM_CLKDIV1_OUTDIV4(1));       // Set Bus Clock/2=24MHz

// System Tick Init

SysTick->CTRL=0;                             // Disable the SysTick Timer

SysTick->LOAD=48000;                         // Core Clock/1=48MHz, Period=1ms/(1/48000000Hz)=48000

SysTick->VAL=0;                              // Clear the current counter value to 0

SysTick->CTRL=(SysTick_CTRL_ENABLE_Msk

             |SysTick_CTRL_CLKSOURCE_Msk);   // Enable SYS TICK timer and set clock source to processor clock (core clock)

// GPIO Init

PORTC->PCR[1] |= PORT_PCR_MUX(1)|            // Enable Port Pin PTC1 as GPIO

                 PORT_PCR_PE_MASK|           // Select the resistor to pull up or down on port pin

                 PORT_PCR_PS_MASK|           // Select a pull up resistor

                 PORT_PCR_IRQC(0x08);        // Configure interrupt pin to trigger on a logic low (0)

GPIOC->PDDR&=~(1<<1);                        // make sure GPIO PTC1 pin is configured as an input

PORTB_PCR18=PORT_PCR_MUX(1);                 // Set Pin B18 to GPIO function

PORTB_PCR19=PORT_PCR_MUX(1);                 // Set Pin B19 to GPIO function

PORTA_PCR13=PORT_PCR_MUX(1);                 // Set Pin A13 to GPIO function

GPIOB_PDDR|=(1<<18);                         // Set Pin B18 as output

GPIOB_PDDR|=(1<<19);                         // Set Pin B19 as output

GPIOA_PDDR|=(1<<13);                         // Set Pin A13 as output

}

//---------------------------------------------------------------------

void MCU_Delay (uint32_t delay)              // Delay in multiples of 1ms (e.g. use 1000 for 1 second)

{

  uint32_t delw;

  for (delw=0;delw<delay;delw++)

  {

    while (!(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk));

  }

}

//---------------------------------------------------------------------

void RGB(uint8_t Red,uint8_t Green,uint8_t Blue) // RGB-LED Control: 1=on, 0=off, for each of the 3 colors

{

if (Red   ==1) GPIOB_PCOR|=(1<<18); else GPIOB_PSOR|=(1<<18);

if (Green ==1) GPIOB_PCOR|=(1<<19); else GPIOB_PSOR|=(1<<19);

if (Blue  ==1) GPIOA_PCOR|=(1<<13); else GPIOA_PSOR|=(1<<13);

}

//---------------------------------------------------------------------

// INTERRUPT BODIES /////////////////////////////////////////////////

//-------------------------------------------------------------------

void PORTBCDE_IRQHandler (void)

{

  PORTC->PCR[1]|= PORT_PCR_ISF_MASK;         // Clear interrupt flag

  GPIOB_PTOR|=(1<<19);                       // Toggle GREEN LED

  MCU_Delay(200);                            // Delay 200ms

}

void LLWU_IRQHandler (void)

{

  GPIOB_PTOR|=(1<<13);                       // Toggle BLUE LED

  MCU_Delay(200);                            // Delay 200ms

}

// end of code

Tags (3)
0 Kudos
1 Solution
742 Views
mjbcswitzerland
Specialist V

Hi Rick

In your LLWU interrupt handler check the source of the wake up (in your case it will only be the single LLWU_Px that you programmed) and reset its interrupt flag by writing a '1' back to it (i.e put LLWU_F1 = 0x40; into LLWU_IRQHandler() as well).

This will probably solve your difficulty because if you don't reset the interrupt flag you will find that the processor is jumping in and out of this interrupt routine forever (and look to be hanging) rather than continuing with the code flow.

Get developer's information to the LLWU at http://www.utasker.com/kinetis/LLWU.html

Regards

Mark

Kinetis: µTasker Kinetis support

KL25: µTasker Kinetis FRDM-KL25Z support / µTasker Kinetis TWR-KL25Z48M support

KL26: µTasker Kinetis FRDM-KL26Z support / µTasker Kinetis Teensy LC support

For the complete "out-of-the-box" Kinetis experience and faster time to market

View solution in original post

0 Kudos
4 Replies
743 Views
mjbcswitzerland
Specialist V

Hi Rick

In your LLWU interrupt handler check the source of the wake up (in your case it will only be the single LLWU_Px that you programmed) and reset its interrupt flag by writing a '1' back to it (i.e put LLWU_F1 = 0x40; into LLWU_IRQHandler() as well).

This will probably solve your difficulty because if you don't reset the interrupt flag you will find that the processor is jumping in and out of this interrupt routine forever (and look to be hanging) rather than continuing with the code flow.

Get developer's information to the LLWU at http://www.utasker.com/kinetis/LLWU.html

Regards

Mark

Kinetis: µTasker Kinetis support

KL25: µTasker Kinetis FRDM-KL25Z support / µTasker Kinetis TWR-KL25Z48M support

KL26: µTasker Kinetis FRDM-KL26Z support / µTasker Kinetis Teensy LC support

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
742 Views
rickstuart
Contributor V

Thanks Mark, I cleaned up the code.  Also missing was code to enable LLWU interrupts.  To close out this thread here is the working code (using SW3 on a FRDM-KL27Z Freescale board to wake up the processor from LLS mode and flash the RGB LED to indicate activity):

// code start

// INCLUDES /////////////////////////////////////////////////////////

//-------------------------------------------------------------------

#include "MKL27Z644.h"                       // KL27 M0+ register definitions

// FUNCTION HEADERS /////////////////////////////////////////////////

//-------------------------------------------------------------------

void MCU_Init(void);                         // initializes MCU for Freedom Board

void MCU_Delay(uint32_t delay);              // delay in multiples of 1ms

//---------------------------------------------------------------------

void RGB(uint8_t Red,uint8_t Green,uint8_t Blue);    // RGB-LED Control: 1=on, 0=off, for each of the 3 colors

// *** MAIN *********************************************************

//-------------------------------------------------------------------

int main(void)

{

  MCU_Init();                                  // MCU Initialization; has to be done prior to anything else

  RGB(0,0,0);                                  // Start with all LEDs off

  __asm("CPSIE i");                            // Enable all Interrupts

  NVIC->ICPR[0] = (uint32_t)(1 << (LLWU_IRQn & 0x1F));         // Clear LLUW Interrupt in NVIC Core register

  NVIC->ISER[0] = (uint32_t)(1 << (LLWU_IRQn & 0x1F));         // Set LLUW Interrupt in NVIC Core register

  volatile int dummyread;

  

  // Allow any of the Low-Leakage Stop modes.

  SMC_PMPROT = SMC_PMPROT_ALLS_MASK;

  // Allow entry into the Low-Leakage Stop (LLS) mode.

  SMC_PMCTRL = SMC_PMCTRL_STOPM(3);

  // Enable hi to lo transition for LLWU_P6 / pin-C1.

  LLWU_PE2 = 0x20;

  // Set the SLEEPDEEP bit to enable deep sleep mode.

  // (W/o this we only drop to about 3.1mA down from 4.6mA.)

  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

  for(;;)

  {

    __asm("WFI");                                                       // Enter low power mode

  

    dummyread = PMC_REGSC;

  

    RGB(1,0,0);                                // Turn on RED LED

    MCU_Delay(200);                            // Delay 200ms

    RGB(0,0,0);

  }

}

//-------------------------------------------------------------------

// ******************************************************************

// FUNCTION BODIES //////////////////////////////////////////////////

//-------------------------------------------------------------------

void MCU_Init(void)

{

  // Crucial

  __asm("CPSID i");                            // Disable interrupts

  //Disable Watchdog

  SIM_COPC=0x00;                               // Disable COP watchdog

  //System Registers

  SIM_SCGC5|=SIM_SCGC5_PORTA_MASK;             // Enable PortA clock

  SIM_SCGC5|=SIM_SCGC5_PORTB_MASK;             // Enable PortB clock

  SIM_SCGC5|=SIM_SCGC5_PORTC_MASK;             // Enable PortC clock

  SIM_SCGC5|=SIM_SCGC5_PORTD_MASK;             // Enable PortD clock

  SIM_SCGC5|=SIM_SCGC5_PORTE_MASK;             // Enable PortE clock

  // System clock initialization

  MCG_MC|=MCG_MC_HIRCEN_MASK;                  // Enable 48MHz HIRC

  MCG_C1=MCG_C1_CLKS(0);                       // Enable Main Clock Source of the 48MHz HIRC

  SIM_CLKDIV1&=~(SIM_CLKDIV1_OUTDIV1(1));      // Set Core Clock/1=48MHz

  SIM_CLKDIV1|=(SIM_CLKDIV1_OUTDIV4(1));       // Set Bus Clock/2=24MHz

  // System Tick Init

  SysTick->CTRL=0;                             // Disable the SysTick Timer

  SysTick->LOAD=48000;                         // Core Clock/1=48MHz, Period=1ms/(1/48000000Hz)=48000

  SysTick->VAL=0;                              // Clear the current counter value to 0

  SysTick->CTRL=(SysTick_CTRL_ENABLE_Msk

                 |SysTick_CTRL_CLKSOURCE_Msk);   // Enable SYS TICK timer and set clock source to processor clock (core clock)

  // GPIO Init

  PORTC->PCR[1] |= PORT_PCR_MUX(1)|            // Enable Port Pin PTC1 as GPIO

    PORT_PCR_PE_MASK|           // Select the resistor to pull up or down on port pin

      PORT_PCR_PS_MASK|           // Select a pull up resistor

        PORT_PCR_IRQC(0x08);        // Configure interrupt pin to trigger on a logic low (0)

  GPIOC->PDDR&=~(1<<1);                        // make sure GPIO PTC1 pin is configured as an input

  PORTB_PCR18=PORT_PCR_MUX(1);                 // Set Pin B18 to GPIO function

  PORTB_PCR19=PORT_PCR_MUX(1);                 // Set Pin B19 to GPIO function

  PORTA_PCR13=PORT_PCR_MUX(1);                 // Set Pin A13 to GPIO function

  GPIOB_PDDR|=(1<<18);                         // Set Pin B18 as output

  GPIOB_PDDR|=(1<<19);                         // Set Pin B19 as output

  GPIOA_PDDR|=(1<<13);                         // Set Pin A13 as output

}

//---------------------------------------------------------------------

void MCU_Delay (uint32_t delay)              // Delay in multiples of 1ms (e.g. use 1000 for 1 second)

{

  uint32_t delw;

  for (delw=0;delw<delay;delw++)

  {

    while (!(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk));

  }

}

//---------------------------------------------------------------------

void RGB(uint8_t Red,uint8_t Green,uint8_t Blue) // RGB-LED Control: 1=on, 0=off, for each of the 3 colors

{

  if (Red   ==1) GPIOB_PCOR|=(1<<18); else GPIOB_PSOR|=(1<<18);

  if (Green ==1) GPIOB_PCOR|=(1<<19); else GPIOB_PSOR|=(1<<19);

  if (Blue  ==1) GPIOA_PCOR|=(1<<13); else GPIOA_PSOR|=(1<<13);

}

//---------------------------------------------------------------------

// INTERRUPT BODIES /////////////////////////////////////////////////

//-------------------------------------------------------------------

void LLWU_IRQHandler (void)

{

  // Clear WUF6 (aka LLWU_P6) by writing a 1 to the flag bit.

  LLWU_F1 = 0x40;                            // Clear interrupt flag

  RGB(0,0,1);                                // Turn on BLUE LED

  MCU_Delay(200);                            // Delay 200ms

  RGB(0,0,0);

}

// code end

0 Kudos
742 Views
mjbcswitzerland
Specialist V

Hi Rick

Glad to hear you solved it.

Do you by any chance have a circuit diagram to the FRDM-KL27Z?

I haven't been able to find one (???)

Regards

Mark

0 Kudos
742 Views
rickstuart
Contributor V

I asked.  There are some bits of the FRDM-KL27Z schematic in the user's guide. I think someone is going to look into the whole schematic.

> That is odd - I'll see what I can do.

0 Kudos