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_ */
Minor correction: With delay3=3200, the square wave is 5 Hz, not 500Hz. Use delay3 = 32 for 500Hz.
Hi Thomas Edel,
Thanks for your code sharing.
1. power consumption test
You also can use the digital multimeter, current mode to test the currect direct .
Just remove both R1, R2, and series your digital multimeter, current mode into it.
2. About the bare metal code
You also can refer to the KL25 bare metal code for the low power.
http://www.nxp.com/assets/downloads/data/en/lab-test-software/KL25_SC.exe
kl25_sc_rev10\klxx-sc-baremetal\build\iar\low_power_demo
Have a great day,
Kerry
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------