Cortex Kinetis KW2xD Low Power Modes

Hello,

I’m using RIOT with KW2xD Kinetis MCU for Wireless sensors.

I could observe that the board’s current is 10mA when idle which is too high for long battery operation.

The application note : http://cache.freescale.com/files/32bit/doc/app_note/AN4503.pdf), says there are Very Low Power Run / Wait / Stop modes.

There are at lease these functions to integrate in RIOT Kernel.

void enter_vlpr(void); => Enter low power run mode void exit_vlpr(void); => Go back in regular power run mode void enter_vlps(void); => Go to low power sleep

What is the correct way to integrate this low power mode in Riot Power management? Are there existing implementation for these low power modes for other MCUs to take in example ?

Thanks

Olivier

Hi Olivier,

Unfortunately, it seems that low power management hasn't gotten a lot of love for most platforms yet. The basic API is in place though, if you wish to implement it on your platform.

Relevant files: sys/include/pm_layered.h sys/pm_layered/pm.c drivers/include/periph/pm.h drivers/periph_common/pm.c

The PR that introduced power management: https://github.com/RIOT-OS/RIOT/pull/6160

This command will let you find a few areas where the API has been used: grep -r -e 'pm_[un]*block' -e pm_set

In general I think the idea is to number the power modes such that you: * Start by giving your lowest power mode 0 * Then find the next lowest power mode that supports features that are   a superset of the features supported by 0, and make that mode 1 * Repeat until you run out of power modes.

You then write a function pm_set in cpu/*/periph/pm.c that implements switching the power modes. And also you set up anything that can't run in a certain power mode to pm_block that mode, and then to pm_unblock when it stops running. I think the kernel then handles the rest.

There may be some details I missed, because I am not super-familiar with the system, but this should give you a good start.

Good luck! Matthew Blue

Hi Olivier, Welcome to RIOT! There is a pull request to integrate stop modes for the Kinetis CPUs 1. There’s no VLPR or VLPW yet, but STOP, VLPS, and LLS are working. It does need a rebase though. We could use some help reviewing this and some other related Kinetis pull requests 2, 3, 4 if you would like to help with this. Feel free to open new PRs for any other improvements you may have.

Best regards, Joakim

Joakim, Matthew,

Thanks for your help.

@Joakim: I cloned your repository, I checkout the pr/kinetis-pm branch and rebase from master Then I turned ENABLE_LEDS 1 in pm.c to facilitate debugging.

I build a sample application with a very simple main() loop:

while (1){ printf("*** pause 5s ***\n"); xtimer_sleep(5); }

With this setup, I could run the above code, but the MCU is idling in KINETIS_PM_WAIT mode (Lowest power saving ?).

Maybe I missed something in my Makefiles or includes (llwu, pm_layered ?) to enable the advanced power saving modes ?

Are there changes to make on the board I use (pba-d-01-kw2x) too ?

Do you have a test application I can use as a reference implementation ?

Thanks

Olivier Fauchon

My guess is that your board uses xtimer with the PIT timer hardware, try using the LPTMR instead. See the frdm-kw41z configuration for an example config (board.h, periph_conf.h). I think Mulle has a config example as well but it is disabled by default. You might find the timer refactoring PRs helpful 1, 2, 3 (any help with testing and reviewing is welcome!) You might also have the UART RX blocking power modes if you don’t configure the llwu pin in the UART config. Clocking mode will affect the reliability of the UART in low power mode, some clock modes take too long to recover from sleep mode so you will miss the first few characters on RX. Use FEI if unsure.

Best regards, Joakim

/Joakim

Hi Joakim,

You were right…

Low power mode were blocked by PIT timers (PM_BLOCK at init) So I switched my board to LPTMR (board/pba-d-01-kw2x).

With this change I could reduce power consumption from 10 mA to ~1mA, and xtimers were still working

Note I rebased your pr/kinetis-pm branch to upstream/RIOT/master to work on latest code.

As soon as I cleanup my work, I’ll send a PR for LPTMR on “pba-d-01-kw2x”.

And I’ll review your other “timer refactoring” PRs ASAP.

Feel free to ask if you need more testing and help so your PRs get merged.

Thanks. Olivier

Hi Olivier, Thanks for the offer of helping! Could you write a short review on each of the PRs that you have used/tested to let others know what the state is and whether anything is not working as intended? A review from a non-maintainer can not be used to approve and merge PRs, but it does give an indication to the people with the proper access that a PR is ready or if it needs more work.

Also, if you have a FRDM-KW41Z board, the PR https://github.com/RIOT-OS/RIOT/pull/9147 needs a review, and is a fairly small fix.

Best regards, Joakim

Hi Joakim,

I have been busy designing my own board (based on phywave module) https://github.com/ofauchon/oflmotes/blob/master/mote-devboard/kw2xd/circuit/v1/devboard_kw2xd_v1.0_board.png

Now I’m back to RIOT-OS tests. I can see your Low Power contributions:

… had been merged to Master. That’s great!

Can you confirm me Kinetis Low Power Modes are fully supported in Riot/master ?

Should I switch my board from PIT to LPTMR to enable these low power modes ?

Thanks

Olivier Fauchon.

Hi again Oliver,

Hi Joakim,

I have been busy designing my own board (based on phywave module) https://github.com/ofauchon/oflmotes/blob/master/mote-devboard/kw2xd/circuit/v1/devboard_kw2xd_v1.0_board.png

Cool!

Now I'm back to RIOT-OS tests. I can see your Low Power contributions:

[1]: kinetis: Implement low power modes by jnohlgard · Pull Request #7897 · RIOT-OS/RIOT · GitHub [2]: kinetis: Refactor RTT driver by jnohlgard · Pull Request #8930 · RIOT-OS/RIOT · GitHub [3]: kinetis: Refactor PIT timer driver implementation by jnohlgard · Pull Request #8933 · RIOT-OS/RIOT · GitHub [4]: cpu/kinetis: Refactor LPTMR timer implementation by jnohlgard · Pull Request #8814 · RIOT-OS/RIOT · GitHub

... had been merged to Master. That's great!

#7897 is still pending. If you would like to help you could run some tests on your board with that PR and report your results. There is still one issue reported in the PR discussion thread which I have not looked into yet related to the phytec board and UART in low power modes.

Can you confirm me Kinetis Low Power Modes are fully supported in Riot/master ?

Not yet, #7897 is still awaiting review and testing

Should I switch my board from PIT to LPTMR to enable these low power modes ?

Unless you have a reason for requiring better than 30.5 µs precision on xtimer, I don't see any reason for not using LPTMR as XTIMER_DEV.

Recently added is one more PR which improves the LPTMR, in particular it will fix a timer rollover when timer_set is called with timeout=0. See kinetis: lptmr reload instead of spinning by jnohlgard · Pull Request #10020 · RIOT-OS/RIOT · GitHub

Best regards, Joakim

Hi. It seems the board I use don’t have LPTMR declared :

https://github.com/RIOT-OS/RIOT/blob/master/boards/pba-d-01-kw2x/include/periph_conf.h

#define PIT_NUMOF (2U) #define PIT_CONFIG {
{
.prescaler_ch = 0,
.count_ch = 1,
},
{
.prescaler_ch = 2,
.count_ch = 3,
},
} #define LPTMR_NUMOF (0U) #define LPTMR_CONFIG {} #define TIMER_NUMOF ((PIT_NUMOF) + (LPTMR_NUMOF))

Can you confirm I need to declare LPTMR to get Low Power Mode working ? Do you have example of working LPTMR declarations ?

Thanks Olivier

Hi again,

Hi. It seems the board I use don't have LPTMR declared :

RIOT/boards/pba-d-01-kw2x/include/periph_conf.h at master · RIOT-OS/RIOT · GitHub

#define PIT_NUMOF (2U) #define PIT_CONFIG { \         { \             .prescaler_ch = 0, \             .count_ch = 1, \         }, \         { \             .prescaler_ch = 2, \             .count_ch = 3, \         }, \     } #define LPTMR_NUMOF (0U) #define LPTMR_CONFIG {} #define TIMER_NUMOF ((PIT_NUMOF) + (LPTMR_NUMOF))

Can you confirm I need to declare LPTMR to get Low Power Mode working ?

You will need LPTMR if you want to be able to use low power modes when you are using the xtimer module, which is usually required for things like network timeouts etc.

Do you have example of working LPTMR declarations ?

Yes, look at the other Kinetis based boards in the tree. Here is one example from FRDM-K22F:

#define LPTMR_NUMOF (1U) #define LPTMR_CONFIG { \     { \         .dev = LPTMR0, \         .irqn = LPTMR0_IRQn, \         .src = 2, \         .base_freq = 32768u, \     }, \ }

/Joakim

Hi Joakim.

I 've been playing with your PR here: https://github.com/gebart/RIOT/tree/pr/kinetis-pm.

To make it work with my custom board, I made some changes in my local board definition:

  • include/periph_conf.h

#define LPTMR_NUMOF (1U) #define LPTMR_CONFIG {
{
.dev = LPTMR0,
.base_freq = 32768u,
.llwu = LLWU_WAKEUP_MODULE_LPTMR0,
.src = 2,
.irqn = LPTMR0_IRQn,
},
}

  • include/board.h

/* LPTMR xtimer configuration */

#define XTIMER_DEV (TIMER_LPTMR_DEV(0)) #define XTIMER_CHAN (0) /* LPTMR is 16 bits wide and runs at 32768 Hz (clocked by the RTC) */ #define XTIMER_WIDTH (16) #define XTIMER_BACKOFF (5) #define XTIMER_ISR_BACKOFF (5) #define XTIMER_OVERHEAD (4) #define XTIMER_HZ (32768ul)

Is that right ?

After that, I found out low power modes were blocked because of some PM_BLOCK() in UART.

As a workaround, I added uart_poweroff(UART_DEV(0)) before xtimer_sleep() in my main thread loop. (So the uart don’t limit pm_set_lowest() )

Since I flashed this new binary, I cannot connect anymore my board through openocd/jlink/swd.

I’m wondering if my board is bricked (maybe the low power mode shuts down JTAG too fast after boot ? )

As soon as I have a new working board, I’ll continue working on your code.

(Of course I’ll add safeguard so low power mode cannot activate that fast at poweron)

Any ideas/comment welcome

Thanks Olivier.

I haven’t found a way to get the debugger to connect reliably with low power modes without manual intervention.

If you hold the reset button on the development board when you do a make flash until you get to the point where it has identified the CPU it should work. Release the reset and then the flashing should complete successfully. I haven’t tested on the kw2xd, but it works on at least the k22f and the kw41z. Hope this helps. /Joakim