Thomas Edel

Bare metal VLPS mode with KL43Z and FRDM-KL43Z

Discussion created by Thomas Edel on Jan 10, 2017
Latest reply on Jan 11, 2017 by Kerry Zhou

I was having some difficulty implementing VLPS mode, so I pared my program way down in order to isolate the VLPS settings and operation from everything else.  It seems as though bare metal code is sometimes difficult to find, so I thought some others might appreciate my code as an example.  Note that I am somewhat of a newbie at this, so don't take this code to be best practices. 

Note that, in the LPTMR0 interrupt, I turn the interrupt enable off, rather than the flag, so that I can test the flag in my larger code after coming out of the interrupt, and go back into VLPS mode if the wake-up interrupt was not from the LPTMR0.  

The result should be a 500Hz square wave on the Port B3 pin and very low current to the MCU (about 3uA average).  

To determine MCU current on the FRDM-KL43Z board, remove R0 and cut the short across J17 on the bottom of the board, and measure the voltage across R2 (the 10 ohm resistor connected across header J17).  I measured about 0.03mV/10ohms = 3uA in VLPS mode.   Remember that power to the board must be cycled after programming and debugging to disconnect the debug circuit in order to truly enter VLPS mode and get that low current. 

I'm not terribly experienced at this, so feel free to comment about how to improve it, especially if you see potential problems lurking.

Anyway, here is the code for those interested; just three files:  main.c, events.c, and events.h.  Use it freely at your own risk!

 

First main.c:


#include "fsl_device_registers.h"
#include "Events.h"
void delay_stop(unsigned int);
int main(void){

   // Define NVIC Interrupt Set-Enable register location:
   static unsigned int *NVIC_ISER = (unsigned int *) 0xE000E100;

   // Similar for NVIC "Interrupt Clear-Pending Register":

   static unsigned int *NVIC_ICPR = (unsigned int *) 0xE000E280;

   __disable_irq(); // SET PRIMASK = 1 to mask all interrupts
   SMC_PMPROT = 0x20; // Set protection bits to allow VLPR & VLPS
   SMC_PMCTRL = 0x02; // Set Power Mode Control Register for VLPS
   SCB->SCR |= 0x00000004; // ARM Register; SleepDeep bit set
   SIM_SCGC5 |= 0x000401; // Enable LPTMR0 and Port B gates
   SIM_SCGC6 |= 0x20000000; // Enable RTC gate control

   // (Be careful to leave bit 0 set at default FTF= 1, or VLPS mode won't work!)
   PORTB_PCR3 = 0x100; // GPIO FOR OSCILLISCOPE: PTB3, GPIO = Alt 1
   GPIOB_PDDR |= 0x8; // PTB3 Direction = output
   GPIOB_PCOR = 0x8; // PTB3 = 0 = initial setting
   OSC0_CR = 0x86; // 32kHz crystal select; RTC_CR setting overrides(?)
   RTC_CR = 0x1900; // Enable load C and 32,768Hz oscillator
   RTC_TSR = 1; // Set to clear Time Invalid Flag and interrupt.
   RTC_SR = 0x10; // Enable RTC
   MCG_C2 |= 0x4; // External Clock Source Select, 1 = OSC = 32kHz
   *NVIC_ISER = 0x10000000; // Enable IRQ 28 LPTMR0 interrupt
   *NVIC_ICPR = 0x10000000; // Clear all pending interrupts
   __enable_irq(); // SET PRIMASK = 0 to turn ALL interrupts ON
   for (;;) { // Loop forever for testing.
      int k = 10; // Set loop counter; provides good breakpoint
      while (k > 0){ //
         delay_stop(3200); // Time delay with VLPS; td = count/32kHz = 1ms
         GPIOB_PTOR = 0x8; // Toggle output for scope (PTB3)
         k--;
      }
   }
}
void delay_stop(unsigned int delay3){
   SCB->SCR |= 0x00000004; // Set ARM SLEEPDEEP bit (redundant).
   LPTMR0_CSR = 0x00; // Turn Timer OFF to change settings.
   LPTMR0_PSR = 0x06; // Glitch filter bypassed, ERCLK32K select.
   LPTMR0_CMR = delay3; // Set new time delay match value
   LPTMR0_CSR = 0x41; // Turn Timer & interrupt ON
   while (LPTMR0_CSR < 0x80){ // Wait for LPTMR0 flag in VLPS mode
      __DSB(); // Use of memory barrier is recommended for portability.
      __WFI(); // Go into VLPS mode to save power.
   }
   LPTMR0_CSR = 0x00; // Turn Timer, flag, and interrupt OFF
   return;
}

 

Then events.c:

 

#include "fsl_device_registers.h"
void LPTMR0_IRQHandler(void)
{
   LPTMR0_CSR = (LPTMR0_CSR & 0x3F);
   // Turn Interrupt Enable bit OFF (b6).
   // Leave Flag TCF ON for verification later.
   // Do NOT write 1 to bit 7, or flag will be cleared!
}

 

And events.h:

 

#ifndef SOURCES_EVENTS_H_
#define SOURCES_EVENTS_H_
#endif /* SOURCES_EVENTS_H_ */

Outcomes