Arm Community
Arm Community
  • Site
  • User
  • Site
  • Search
  • User
Arm Community blogs
Arm Community blogs
Embedded and Microcontrollers blog Utilising The LLS Mode And The LLWU For The Kl25z Series
  • Blogs
  • Mentions
  • Sub-Groups
  • Tags
  • Jump...
  • Cancel
More blogs in Arm Community blogs
  • AI blog

  • Announcements

  • Architectures and Processors blog

  • Automotive blog

  • Embedded and Microcontrollers blog

  • Internet of Things (IoT) blog

  • Laptops and Desktops blog

  • Mobile, Graphics, and Gaming blog

  • Operating Systems blog

  • Servers and Cloud Computing blog

  • SoC Design and Simulation blog

  • Tools, Software and IDEs blog

Tags
  • adxl-345
  • energy-harvesting
  • accelerometer
  • llwu
  • remote-control
  • Cortex-M0+
  • lls
Actions
  • RSS
  • More
  • Cancel
Related blog posts
Related forum threads

Utilising The LLS Mode And The LLWU For The Kl25z Series

Elliott Smith
Elliott Smith
December 2, 2013

This blog post is concerned with how we got the MCU in the Batteryless Energy Harvesting Remote Control to go into a Low Leakage Mode. It is also concerned with the Low Leakage Wake Up Unit (LLWU) and how this can be used to wake up the remote control from sleep.

In the Energy Harvesting Remote Control we used an MCU from the Freescale KL25 sub family of MCU’s have a number of different sleep modes that can be utilised for low power applications. We wanted to be able to enter into a stop mode to reduce power consumption after a degree of inactivity. We also wanted to be able to wake the MCU from a user input. The Low Leakage Stop (LLS) Modes and the Low Leakage Wake Up Unit (LLWU) are ideal for this application.

There are two modes we could have chosen to use the LLWU to wake the MCU up, Low Leakage Stop (LLS) mode or Very Low Leakage Stop (VLLS) mode (of which there are 3 options VLLS0, VLLS1 or VLLS3). The LLS mode leaves most of the peripherals in state retention mode and its normal recovery method is a Wakeup Interrupt. The VLLS mode disables most of the peripherals and its normal recovery method is a Wakeup Reset. See the Reference Manual for the MkL25Z series for more details.

We opted to put the MCU into the Low Leakage Stop Mode. The current in this mode is somewhere around 1.9uA. In VLLS0 mode this could have been reduced down to 381nA. We decided to use the LLS mode to avoid the reset, this would ultimately save time. We also wanted to wake the remote control using an Accelerometer, because the LLS mode keeps peripherals in a state of retention, this was ideal.  The Low Leakage Stop Mode has a sufficiently low current to allow the remote control to charge up.

We entered into a LLS mode as shown in the code below:

void SMC_sleep(void)
{
    //Enable the LLWU Pins before putting the MCU into a sleep state:
  PORTC->PCR[6] |= (0x1 << 8);
  FPTC->PDDR &= ~(0x1 << 6);

    PORTB->PCR[0] |= (0x1 << 8);
  FPTB->PDDR &= ~(0x1);

    LLWU_pinEnable(10,3);
    LLWU_pinEnable(5,3);

    NVIC_EnableIRQ(LLW_IRQn);
  SMC_sleepDeep(0);

}

void SMC_sleepDeep(int mode)
{
  volatile unsigned int dummyread;

  /* The PMPROT register allows the MCU to enter the LLS modes.*/
  SMC->PMPROT = SMC_PMPROT_ALLS_MASK;   

  /* Set the STOPM field to 0b011 for LLS mode */
  SMC->PMCTRL &= ~SMC_PMCTRL_STOPM_MASK; 
  SMC->PMCTRL |=  SMC_PMCTRL_STOPM(0x3); 

  /*wait for write to complete to SMC before stopping core */  
  dummyread = SMC->PMCTRL;
  dummyread++;

  /* Set the SLEEPDEEP bit to enable deep sleep mode (STOP) */
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

  __wfi();
}


To wake the remote control up we added two options. One of the LLWU pins for the KL25z series is TSI channel 0. We configured this so a touch on this electrode would wake up the remote control. Another solution we also incorporated was to get the remote control to wake up from an Accelerometer. This was configured using one of the ADXL345 accelerometer interrupt pins and was used to wake the MCU up if any activity was detected. The code to enable the LLWU pin is shown below, we configured the LLWU to wake the MCU up if there was any change experienced on the pins, but they could also have been configured for rising or falling edge:

/*------------------------------------------------------------------------------
  Enable a pin for use with the low leakage wake up unit
 *------------------------------------------------------------------------------*/
void LLWU_pinEnable(int pin, int mode)
{    
    if(pin < 4){
        switch(mode){
                case 0:
                LLWU->PE1 |=     (0x0 << (pin*2));
                break;
                case 1:
                LLWU->PE1 |=     (0x1 << (pin*2));
                break;
                case 2:
                LLWU->PE1 |=     (0x2 << (pin*2));
                break;
                case 3:
                LLWU->PE1 |=     (0x3 << (pin*2));
                break;    
            }    
    }
    else if((pin >= 4) && (pin < 8)){
        switch(mode){
                case 0:
                LLWU->PE2 |=     (0x0 << ((pin-4)*2));
                break;
                case 1:
                LLWU->PE2 |=     (0x1 << ((pin-4)*2));
                break;
                case 2:
                LLWU->PE2 |=     (0x2 << ((pin-4)*2));
                break;
                case 3:
                LLWU->PE2 |=     (0x3 << ((pin-4)*2));
                break;    
            }        
    }    
    else if((pin >= 8) && (pin < 12)){
        switch(mode){
                case 0:
                LLWU->PE3 |=     (0x0 << ((pin-8)*2));
                break;
                case 1:
                LLWU->PE3 |=     (0x1 << ((pin-8)*2));
                break;
                case 2:
                LLWU->PE3 |=     (0x2 << ((pin-8)*2));
                break;
                case 3:
                LLWU->PE3 |=     (0x3 << ((pin-8)*2));
                break;        
            }    
    }
    else if((pin >= 12) && (pin < 16)){
        switch(mode){
                case 0:
                LLWU->PE4 |=     (0x0 << ((pin-12)*2));
                break;
                case 1:
                LLWU->PE4 |=     (0x1 << ((pin-12)*2));
                break;
                case 2:
                LLWU->PE4 |=     (0x2 << ((pin-12)*2));
                break;
                case 3:
                LLWU->PE4 |=     (0x3 << ((pin-12)*2));
                break;    
            }    
    }
    NVIC_EnableIRQ(LLW_IRQn);
}


It was important to enable the interrupt in this section of code, this was done once the pin and mode were determined. The code called when the LLWU pins experience a change is shown below:

void LLW_IRQHandler()
{
        LLWU_clear();
        PMC->REGSC |= (1UL << 3);
        SystemCoreClockUpdate();                      /* Get Core Clock Frequency */
        SysTick_Config(SystemCoreClock/1000);         /* Generate interrupt each 1 ms    */

}


This is the code required to ensure that the MCU has fully woken from the stop mode.

A note on the Accelerometer used:

The accelerometer we used was an ADXL345. The code below shows how we configured the interrupt for this accelerometer:

void sensor_int(void)
{            
          char cmd[1];
          char interrupt=0;

          FPTC->PDOR |= (1UL << 11);
          Delay(500);
          I2C_configure();

          setInterruptEnableControl(0x00);           //disable all interrupts intially

          setActivityThreshold(150);                 //set the threshold for determining activity

          setActivityInactivityControl(0x70);        //set activity to be detected on any axis

          setInterruptMappingControl(0xEF);          //send interrupt for activity to interrupt pin 1
        
          setInterruptEnableControl(0x7E);           //enable interrupt for activity
    
          interrupt = getInterruptSource();          //get interrupt source for testing
    
}


The Datasheet for this accelerometer shows that an interrupt can be triggered for a single tap, a double tap, activity, inactivity and free fall. In our case we configured the accelerometer interrupt simply for activity.

Anonymous
Embedded and Microcontrollers blog
  • Formally verifying a floating-point division routine with Gappa – part 2

    Simon Tatham
    Simon Tatham
    A method of testing whether a numerical error analysis using Gappa really matches the code it is intended to describe.
    • September 4, 2025
  • Formally verifying a floating-point division routine with Gappa – part 1

    Simon Tatham
    Simon Tatham
    Learn the basics of using Gappa for numerical error analysis, using floating-point division in Arm machine code as a case study.
    • September 4, 2025
  • Adapting Kubernetes for high-performance IoT Edge deployments

    Alexandre Peixoto Ferreira
    Alexandre Peixoto Ferreira
    In this blog post, we address heterogeneity in IoT edge deployments using Kubernetes.
    • August 21, 2024