Hi all,
1. What I'm trying to do:
a- Put KL03 into VLPS mode
b- Switch from using the 48MHz HIRC to the 2MHz LIRC2M
c- Reduce power consumption from a few mA's to something lower than 100uA
d- Go from VLPS back to RUN mode on an SPI slave mode receive through AWIC
2. How I'm doing it:
a- Here are the 2 functions I am using to enter and exit VLPS:
void vlps_enter(void)
{
SMC_PMCTRL = SMC_PMCTRL_STOPM(2));
dummyread = SMC_PMCTRL;
(void)dummyread;
SCB_SCR |= SCB_SCR_SLEEPDEEP_MASK;
dsb();
wfi();
isb();
}
void vlps_exit(void)
{
SMC_PMCTRL &= ~SMC_PMCTRL_STOPM_MASK;
SCB_SCR &= ~(SCB_SCR_SLEEPDEEP_MASK | SCB_SCR_SLEEPONEXIT_MASK);
}
b- Here are the 2 functions I use to switch from HIRC to LIRC2M:
void set_HIRC(void)
{
MCG_MC |= MCG_MC_HIRCEN_MASK;
MCG_C1 = MCG_C1_CLKS(0);
MCG_C2 = 0;
while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x00);
}
void set_LIRC(void)
{
MCG_MC = 0;
MCG_C1 = MCG_C1_CLKS(1);
MCG_C2 = 0;
while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x01);
}
c- At bootup I run this to enable HIRC and enable going into VLPS and VLLS modes:
set_HIRC();
SMC_PMPROT = (SMC_PMPROT_AVLP_MASK | SMC_PMPROT_AVLLS_MASK);
d- When the conditions to enter VLPS are met (KL03 is idle and has no pending tasks), I call the 2 functions like this:
set_LIRC();
vlps_enter();
// KL03 is in VLPS here
vlps_exit();
set_HIRC();
d- My KL03 is configured as an SPI slave (with SPISWAI bit set in SPI0_C2 register) and expect that the KL03 would exit VLPS whenever an SPI transfer is coming its way
3. What I'm seeing:
a- With the code I have above, I measured current consumption at 0.9mA which seems very high to me in VLPS and there's no peripherals running (no ADC, no LPUART... nothing)
b- Another problem is that with this code, the KL03 never properly wakes up and processes the SPI transfer it's receiving.
c- However, if I just remove the set_LIRC() call, power consumption goes to 1.8mA and the SPI transfer works great and I have no issues (other than the high power consumption)
4. My questions:
a- The power numbers I'm seeing are high, is there anything else I need to change to get very low numbers in the 100uA range?
b- Any thoughts on wether the switch to LIRC2M is actually needed?
c- Any idea why if I switch to LIRC2M, the SPI wakeup doesn't work?
Any help is greatly appreciated.
Thanks!
Solved! Go to Solution.
Hi,
The issue is Errata #8068. The RTC clock is enabled by default. It has to be disabled before you enter low power.
// Errata 8068 fix
SIM->SCGC6 |=SIM_SCGC6_RTC_MASK; // enable clock to RTC
RTC->TSR = 0x00; // dummy write to RTC TSR per errata 8068
SIM->SCGC6 &= ~SIM_SCGC6_RTC_MASK; // disable clock to RTC
The attached code (main.c) get you now to 1.74uA in VLPS.
Michael Steffen
Senior Field Applications Engineer
Member of the Technical Staff
Freescale
Will: Thanks for this post and for persevering to an answer ... Only took me 1 1/2 days to resolve the same problem, thanks to your post (1 1/2 days trying all the application note recommendations, then 1/2 hour to find your post and the solution).
Thanks also to Michael for the correct answer!
-Thomas
Hi,
The issue is Errata #8068. The RTC clock is enabled by default. It has to be disabled before you enter low power.
// Errata 8068 fix
SIM->SCGC6 |=SIM_SCGC6_RTC_MASK; // enable clock to RTC
RTC->TSR = 0x00; // dummy write to RTC TSR per errata 8068
SIM->SCGC6 &= ~SIM_SCGC6_RTC_MASK; // disable clock to RTC
The attached code (main.c) get you now to 1.74uA in VLPS.
Michael Steffen
Senior Field Applications Engineer
Member of the Technical Staff
Freescale
Michael, thanks for the answer, I've just spent more than two days hunting problems with entering VLLS. See Can't enter VLLS0 on KL03
But this begs the question — shouldn't the startup code that KDS generates for the MKL03 be modified to have the errata fix in it?
Hi Michael,
Thanks for pointing that out. I'll give it a shot.
Do you happen now why a SPI wake up from VLPS is not working for me? Anything special that needs to be done there? Also, is going from HIRC to LIRC needed when going into VLPS (I don't think so I need to do it, but would like to confirm)?
Thanks!
The errata fix helped Michael. I am now able to see power consumption in the uA level.
I'm still working through some SPI wakeup problems.
Found this in the K20 family pdf:
In stop and VLPS modes, the clocks to the SPI module are disabled. The module is not
functional, but it is powered so that it retains state.
So, 1st verify this is the same as in your K03.
In the same document it goes on to suggest a way to use VLPS and SPI. It looks like they use a GPIO to sense the SPI CS line activity. It looks like GPIO pin activity can wake up a processor in VLPS. However it goes on to say there is a risk that the 1st SPI transaction will not work.
Or you can investigate running in VLPR so that the SPI module still gets a clock. However I think the SPI speed is limited in VLPR mode.
I don't think there is a reason you can't go from the 48MHz clock to VLPS. The thing you probably can't do w/o jazzing up the processor is switch between different low speed clock directly. Like switching from 2MHz to 8MHz with out going to 48MHz first.
Thanks for your help Rick.
I was finally able to get the power consumption down to the uA level but still have some problems with the SPI wakeup in VLPS. And I'm no longer changing between HIRC and LIRC clocks.
According to the data sheet, an SPI reception should trigger an interrupt that wakes the CPU up. I can see that happening sometimes but some other times, the operations that follow the SPI transfer are failing.
Hello Will X, I'm finding the same problems that you had to put KL03 to VLPS. I'm doing the same sequence:
SMC_PMPROT = 0x22; // enabling AVLP and AVLLS
SMC_PMCTRL = (SMC_PMCTRL_RUNM(2) + SMC_PMCTRL_STOPM(2)); // RUN mode VLPR and STOP VLPS
dummyread = SMC_PMCTRL;
while (!(SMC_PMSTAT & 0x04)); // waiting for VLPR
/* HERE I CAN SEE THE CURRENT GOING DOWN AROUND 1mA */
PortInit() // Config the GPIOs
LPTMR_Init() // Config LPTimer to generate an Interruption each 1 sec.
while(1) {
GoVLPS();
GPIOA_PTOR = 0x20; // toogle the PA5 to check if its comming out from VLPS every sec.
}
void GoVLPS(void){
SCB_SCR |= SCB_SCR_SLEEPDEEP_MASK;
__asm("DSB");
__ams("WFI");
}
Did you disable any MCU block as debugger, clock, or somethin else to reach units of uA?
I can see that the MCU is going to a Low Power mode because it's waitinf for an interrupt (the pin A5 is toogling 1 sec Hi 1 sec Lo). However, the current is around 200uA and I expect something under 50uA. Any idea?
Thanks and regards
Ivan
FYI, I was doing some similar current checks on a LK27 (FRDM-KL27Z Freescale development board). BEWARE!!! You need to do the current checks with out the debugger!!! Here's my thread:
As to why the SPI isn't getting you out of VLPS, I thought you needed an interrupt to get out of VLPS. I went down the path of setting bits in VNIC on the '27 for a timer to get out of VLPS.
Thanks for your reply Rick.
The numbers I quoted are withe debugger detached. Attaching the debugger adds about 0.5mA for me.
And my SPI interrupt is enabled. If I don't change from HIRC to LIRC2M, the SPI IRQ works fine. Only when I switch to the lower clock that the SPI doesn't wake up.
WRT the current. So you managed to get the current down to where you expected it?? Note, pressing the red "X" on the debugger tool was not enough for me. Neither was pressing reset on the development board. I needed to cycle the power to the processor to get really low currents.
I'm not sure about the interrupt. If the interrupt really works when you stay out of VLPS - I think it should work when you are in VLPS. Check to make sure you clear the interrupt flag before getting out of the interrupt routine. But you would have had to do that even if you never entered VLPS. Humm. Have to think about this one. FYI, since I can't use the debugger to tell me where my code is executing, I started using the LEDs on the Freescale development boards to indicate I was in main() or one of my interrupts.
No, I'm still having problems getting the current to the low level I expect it to be at.
I'm assuming that to get to the lowest possible power consumption I need to do the following: go into VLPS AND switch from the HIRC 48MHz clock to the LIRC 2MHz clock.
At the moment, I have 2 problems:
1. When I try to do both of these things, my application doesn't work because of the SPI transfer not waking it up.
2. Going into VLPS and not changing the clock used is consuming 1.8mA now which is still high. If I change the clock, it drops even more to 0.9mA but I would expect it to be much lower.
The code I'm using is in my original post and it matches the SDK code that Jeremy pointed me too and other sample codes I found in the community.
Any help or guidance would be greatly appreciated.
Hi Will,
I was wondering if you can share the whole demo, then I can run it with FRDM-KL03 board for checking.
I'm looking forward to your reply.
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hey Jeremy,
Here's the code I have. I trimmed down my project to this and I'm still seeing 0.9mA.
void vlps_enter(void)
{
SMC_PMCTRL = SMC_PMCTRL_STOPM(2));
dummyread = SMC_PMCTRL;
(void)dummyread;
SCB_SCR |= SCB_SCR_SLEEPDEEP_MASK;
dsb();
wfi();
isb();
}
void vlps_exit(void)
{
SMC_PMCTRL &= ~SMC_PMCTRL_STOPM_MASK;
SCB_SCR &= ~(SCB_SCR_SLEEPDEEP_MASK | SCB_SCR_SLEEPONEXIT_MASK);
}
void set_HIRC(void)
{
MCG_MC |= MCG_MC_HIRCEN_MASK;
MCG_C1 = MCG_C1_CLKS(0);
MCG_C2 = 0;
while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x00);
}
void set_LIRC(void)
{
MCG_MC = 0;
MCG_C1 = MCG_C1_CLKS(1);
MCG_C2 = 0;
while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x01);
}
void main()
{
/* Set the KL03 clock to be the max at 48MHz */
set_HIRC();
SMC_PMPROT = SMC_PMPROT_AVLP_MASK;
while(1)
{
set_LIRC();
vlps_enter();
// KL03 is in VLPS here
vlps_exit();
set_HIRC();
}
}
If I comment out the 2 calls to set_LIRC() and set_HIRC() inside of the while loop, I get a power consumption of 1.6mA.
Hi Will X,
I'm working on this code now and I'll inform you ASAP if I work it out.
And you can also share some updating in the community.
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Jeremy,
Were you able to run my code on your end and measure the power consumption?
Thanks!
Hi Will,
I've got the different result from you, I used the code from the SDK instead of yours, then the current consumption will drop to 1.85uA when the MCU entered the VLPS mode.
I ran the code on the FRDM-KL03Z board.
Wish it helps.
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thanks for letting me know.
Can you point me to exactly which sample code from the SDK you used? There's a ton of examples there so pointing me to the one you ran would be great.
Hi Will,
FSL's shared a Kinetis SDK_1.0.0 Standone for FRDM-KL03Z and it includes a low_power_rtc demo which illustrates the ways to enter and exit different low power modes.
This demo resides in ~\Freescale\KSDK_1.0.0-KL03Z\demos and you can download the SDK through the link as below.
Hope it helps.
Have a great day,
Ping
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thanks Jeremy.
I am trying to look into that but that SDK is a total mess. And me development environment is on Mac so I'm having a lot of problems to figure out how to load it on the FRDM-KL03Z.
Are you able to load my code and run it yourself?
void vlps_enter(void)
{
SMC_PMCTRL = SMC_PMCTRL_STOPM(2));
dummyread = SMC_PMCTRL;
(void)dummyread;
SCB_SCR |= SCB_SCR_SLEEPDEEP_MASK;
dsb();
wfi();
isb();
}
void vlps_exit(void)
{
SMC_PMCTRL &= ~SMC_PMCTRL_STOPM_MASK;
SCB_SCR &= ~(SCB_SCR_SLEEPDEEP_MASK | SCB_SCR_SLEEPONEXIT_MASK);
}
void set_HIRC(void)
{
MCG_MC |= MCG_MC_HIRCEN_MASK;
MCG_C1 = MCG_C1_CLKS(0);
MCG_C2 = 0;
while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x00);
}
void set_LIRC(void)
{
MCG_MC = 0;
MCG_C1 = MCG_C1_CLKS(1);
MCG_C2 = 0;
while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x01);
}
void main()
{
/* Set the KL03 clock to be the max at 48MHz */
set_HIRC();
SMC_PMPROT = SMC_PMPROT_AVLP_MASK;
while(1)
{
//set_LIRC();
vlps_enter();
// KL03 is in VLPS here
vlps_exit();
//set_HIRC();
}
}