Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kinetis: Implement low power modes #7897

Closed
wants to merge 34 commits into from

Conversation

jnohlgard
Copy link
Member

@jnohlgard jnohlgard commented Oct 28, 2017

Based on #7882
Depends on #10320, #9930

Low power modes using pm_layered with automatic blocking of modes depending on what peripherals are in use.
The UART peripheral driver has been enhanced with checking of error indication flags in the RX interrupt.

TODO

  • board configuration updates for LLWU
  • Measure power consumption
  • Test peripherals
  • LPUART LLS operation similar to UART
  • Make pm_layered usage conditional on USEMODULE

Tested on FRDM-K22F, both with PIT and with LPTMR for xtimer.

The UART on the FRDM-K22F seem to collect some garbage during boot when using low power modes, resulting in the first one or two commands entered over pyterm to return error messages about command not found. Typing the same command again (by hitting enter again in pyterm) always seem to work. It does not seem to be dependent on how long we wait after boot, but rather there's some junk being collected in the internal stdio_uart RX buffer and the buffer being flushed when the first newline is received.
Tested with pyterm, picocom, and minicom to ensure that the UART is working properly both with long RX sequences (pyterm) and with single keystroke transmissions (minicom).

Example terminal output with boot garbage after flashing:

2017-10-28 15:46:08,467 - INFO # �����main(): This is RIOT! (Version: 2018.01-devel-149-g6d3d3-cheesecake-pr/kinetis-pm)
2017-10-28 15:46:08,469 - INFO # Welcome to RIOT!
> ps

2017-10-28 15:46:10,825 - INFO #  �.�ps
2017-10-28 15:46:10,828 - INFO # shell: command not found: �.�ps
> 
2017-10-28 15:46:11,411 - INFO #  ps
2017-10-28 15:46:11,420 - INFO # 	pid | name                 | state    Q | pri | stack  ( used) | base addr  | current     
2017-10-28 15:46:11,427 - INFO # 	  - | isr_stack            | -        - |   - |   1024 (  116) | 0x1fff0000 | 0x1fff03c8
2017-10-28 15:46:11,436 - INFO # 	  1 | idle                 | pending  Q |  15 |    768 (  128) | 0x1fff0714 | 0x1fff0994 
2017-10-28 15:46:11,444 - INFO # 	  2 | main                 | running  Q |   7 |   1536 (  632) | 0x1fff0a14 | 0x1fff0e8c 
2017-10-28 15:46:11,450 - INFO # 	    | SUM                  |            |     |   3328 (  876)

@jnohlgard jnohlgard added Platform: ARM Platform: This PR/issue effects ARM-based platforms Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Area: pm Area: (Low) power management State: waiting for other PR State: The PR requires another PR to be merged first State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet labels Oct 28, 2017
@jnohlgard jnohlgard force-pushed the pr/kinetis-pm branch 4 times, most recently from 6ad088b to 5b00fc7 Compare October 28, 2017 21:19
@kYc0o kYc0o mentioned this pull request Oct 29, 2017
5 tasks
@jnohlgard jnohlgard force-pushed the pr/kinetis-pm branch 2 times, most recently from 22b9865 to 09407f6 Compare November 8, 2017 15:54
@jnohlgard jnohlgard force-pushed the pr/kinetis-pm branch 3 times, most recently from aaf73f1 to 1ec64ba Compare November 10, 2017 14:37
@jnohlgard jnohlgard removed the State: waiting for other PR State: The PR requires another PR to be merged first label Nov 10, 2017
@jnohlgard jnohlgard added the State: waiting for other PR State: The PR requires another PR to be merged first label Nov 15, 2017
@jnohlgard jnohlgard changed the title [WIP] kinetis: Add low power modes support kinetis: Implement low power modes Mar 18, 2018
@jnohlgard
Copy link
Member Author

Updated and rebased. Tested on frdm-kw41z, mulle

@jnohlgard jnohlgard removed the State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet label Mar 22, 2018
@kYc0o
Copy link
Contributor

kYc0o commented Apr 9, 2018

The UART on the FRDM-K22F seem to collect some garbage during boot when using low power modes

Is this the same behaviour using another UART as STDIO? I have a gut feeling that it's maybe related to the debugger... I'll try with an external USB-UART converter to see what happens.

@ofauchon
Copy link

Hi,

I played around with pr/kinetis-pm on a Kinetix KW2xD custom board
(https://github.com/ofauchon/oflmotes/tree/master/mote-devboard/kw2xd/demo-riot/boards/oflmote-dev)

At first attempt, the MCU was not going to LLS mode and was consuming >10 mA while idle.
I had to comment out a couple of PM_BLOCK in uart.c :

https://github.com/gebart/RIOT/blob/7ab0e94f2aaa6240fb30a963498e9238c9631b7f/cpu/kinetis/periph/uart.c#L213
https://github.com/gebart/RIOT/blob/7ab0e94f2aaa6240fb30a963498e9238c9631b7f/cpu/kinetis/periph/uart.c#L432

Now the power consumption dropped to <1mA when idle.

Line 213 PM_BLOCK happens because KW2xD has no LPUART but a defined rx_cb.
I'll try to reinit the board uart without the rx_cb after RIOT init.

But I have no idea why the second 'PM_BLOCK(KINETIS_PM_STOP);' (uart.c line 432) is never unlocked..

Beyond this minor problems, this PR works fine and is really stable on my setup.

Thanks for this feature Joakim, looking forward the merge !
Hope that helps!

Olivier

@benemorius
Copy link
Member

Does anyone still have bugs with this? I'm using it in practice for a long time and it's working well for me.

@benemorius
Copy link
Member

benemorius commented Jun 20, 2019

@ofauchon

Line 213 PM_BLOCK happens because KW2xD has no LPUART but a defined rx_cb.
I'll try to reinit the board uart without the rx_cb after RIOT init.

I think it's because you didn't define a pin for uart_config.llwu_rx? In this configuration LLS is blocked on purpose because in that power mode there is no clock for the UART and therefore LLWU (low-leakage wakeup) is the only way to wake on UART RX. If you manually unblock LLS without LLWU configured you'll break UART RX. Note that you'll also need to use a slow baud rate with LLS/LLWU because it takes some time after LLWU to get a clock running before the UART can begin sampling data, and for the same reason you'll need to run from a clock source that doesn't take prohibitively long to start up.

But I have no idea why the second 'PM_BLOCK(KINETIS_PM_STOP);' (uart.c line 432) is never unlocked..

I can't explain that either. Possibly a side effect of manually forcing LLS mode? Are you certain that the transmitting device is returning the bus to idle state after transmitting? I don't have a Kinetis board with a UART (only LPUART) so I can't easily test that.

@benemorius
Copy link
Member

benemorius commented Jun 21, 2019

I've taken some current measurements with kw41z-mini, which is like frdm-kw41z but with no onboard peripherals and no DC-DC. The only thing consuming power other than the microcontroller is the LDO which adds 1.8 uA typical under all load conditions. This means that the numbers from other boards may not compare well, but this is nearly the ideal test case for current measurement purposes. Other boards may need special handling to get onboard peripherals into their lowest power states, and the minimum current may still be higher.

After programming, the board is power cycled before taking measurements. This is necessary to reset the debug hardware to prevent it from blocking PM_VLPS (it does this internally) and from adding current consumption in >PM_VLPS. (Perhaps counterintuitively, PM_LLS is the one mode unaffected by debug hardware.) Additionally, it is necessary to assert reset (or some other means of increasing power consumption) while power cycling in the event that the board is running with low enough power to continue operating from SWD/UART pin leakage and/or bypass capacitance even with main power removed. It is therefore imperative to confirm that the board actually resets when you power cycle it.

At these current levels there is significant measurement error in leakage from UART, SWD, or other connected pins. It is necessary to either disconnect all pins, or tristate them and then confirm that the measurement is the same as when the pins are disconnected. Using a Raspberry Pi as the UART and SWD host, I was able to achieve tristated leakage levels lower than my measurement resolution of 10 nA on all pins except UART TX (pi->riot) which leaks 0.5 uA in my particular case.

Using LLWU is necessary to retain UART RX functionality in PM_LLS with the default clock configuration. This requires a lower baud rate than 115200 or else the UART begins sampling too late after waiting ~6 us for MCGIRCLK to start. I found that 19200 works. I haven't tried to optimize this yet.

All of these measurements (except for the "undefined behavior") agree well with what I'm expecting to see without specifically checking the datasheet, except perhaps the lowest one (mode 0; 5 uA) which might have room for ~50% reduction. But I didn't investigate yet so it could be normal for kw41z.

All numbers below include LDO quiescent current, so subtract 1.8 uA to get the real value.

tests/periph_pm:

# kinetis starts with no blockers, so mode 0; current is 5 uA
> block 0
Blocking power mode 0. # now in mode 1; current is  62 uA
> block 1
Blocking power mode 1. # now in mode 2; current is  270 uA
> block 2
Blocking power mode 2. # now in mode 3; current is  4.7 mA
> block 3
Blocking power mode 3. # undefined behavior; expected behavior was mode==RUN and ~10 mA

tests/periph_pm: (with .llwu_rx = LLWU_WAKEUP_PIN_UNDEF)

# kinetis LPUART blocks LLS, so now in mode 1; current is 62 uA
> unblock 0
Unblocking power mode 0. # now in mode 0; current is  5 uA
> # UART RX has stopped working now, as expected

examples/gnrc_networking:

# kw41zrf blocks VLPS during rx/idle, so now in mode 2 w/ radio; current is 14 mA
> ifconfig 7 set state sleep
success: set state of interface 7 to SLEEP # now in mode 0; current is 5 uA
> ifconfig 7 set state idle 
success: set state of interface 7 to IDLE # now in mode 2 w/ radio; current is 14 mA
# ping still works
> ping6 ff02::1%7 -c 1
12 bytes from fe80::2165:632b:6241:6d7a: icmp_seq=0 ttl=255 rssi=-91 dBm time=5.249 ms

--- ff02::1 PING statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 5.249/5.249/5.249 ms

examples/gnrc_networking: (with riotboot gnrc_networking-slot0-extended.bin)

I-No7G#J��' # it's ok - I didn't change riotboot from the default 115200 baud (sorry)
# kw41zrf blocks VLPS... # from here, same as above (gnrc_networking without riotboot)
# flashing over coap-dtls also tested successfully

examples/gnrc_networking_mac: (using LWMAC - still a work in progress on this platform)

> mac duty
[LWMAC]: achieved radio duty-cycle: 5 %

LWMAC toggles the radio between sleep and idle fairly rapidly. With a fast enough multimeter (oscilloscope preferably, or use multimeter min/max mode) the current can be seen toggling between 5 uA and some much higher reading that will depend on the meter's ability to resolve small moments in time and especially the amount of bypass capacitance on the board. However, a good multimeter's averaging mode will give an accurate average here and I'm getting 0.59 mA average current.

The reason this number is not very impressive is only that LWMAC hasn't been tuned to oblige us with an impressive number yet. Actually, what's very impressive is the fact that 0.59 mA average current agrees very well with LWMAC's reported achieved radio duty-cycle of 5% of 14 mA 🎉

@benemorius
Copy link
Member

@kYc0o

I need to actually know the power consumption on the LED to calculate better the expected values.

I attempted to calculate these current consumption values from the frdm-kw41z schematic, however, as is common for low-power boards, the LEDs are being run at much lower current than the LED datasheets show on the I/V graph. Therefore the practical way to obtain the values is empirically. The calculations below are based on extrapolation of the curve, at exactly the point in the curve where it's known to turn nonlinear, which is a really bad idea.

The schematic gives part number CLV1A-FKB-CJ1M1F1BB7R4S3 for LED 1-3 and generic red LED for LED 0, with R=220 ohm for all 4 LEDs. I assumed VDD is 3.30 V.

LED0 = (3.30 V - 1.8 V) / 220 ohm = 6.8 mA
LED1 = (3.30 V - 1.8 V) / 220 ohm = 6.8 mA
LED2 = (3.30 V - 2.8 V) / 220 ohm = 2.3 mA
LED3 = (3.30 V - 2.8 V) / 220 ohm = 2.3 mA

But these values would be best obtained by measuring the voltage across each 220 ohm resistor. Then you can get a nice precise value of v / 220 ohm = x.xx mA. However it is still the case that the LEDs consume much more current than a sleeping microcontroller, so it isn't really practical to measure sleep currents while any LEDs are on.

However, I have the impression the current value is not really affected in modes 1 to 3.

That is probably explained by a combination of LED current as well as possibly having the debug circuitry active as I mentioned in the previous post. Kinetis (in hardware) will translate a PM_VLPS request to a PM_STOP request whenever the debug circuitry is active, however it does not interfere with a PM_LLS request (it just powers off the debug hardware until mode > LLS). Additionally, the debug circuitry adds about 4 mA any time it's powered.

kernel panic

That's just what happens when you unblock a mode that wasn't blocked. There's an assertion to check for that:

assert(pm_blocker.val_u8[mode] > 0);

@benemorius
Copy link
Member

benemorius commented Jun 22, 2019

I rebased this so I could clean up my branch and make sure I wasn't hiding any necessary bugfixes there. I didn't find any, but maybe master has some new commits that have fixed this for kw2x. In case someone wants to test this PR on current master, here's the rebase:

master...benemorius:pr/kinetis-pm-rebase

This also includes a fix for the issue that @MichelRottleuthner found where pm_set(RUN) wasn't handled properly. This was the cause for the inconsistent sleep behavior I encountered while attempting to measure current with mode 3 WAIT blocked. The resulting mode was dependent on which mode was entered last.

@ofauchon
Copy link

Hi Benemorius,

I just noticed that "llwu_rx" was not defined ('llwu_rx = LLWU_WAKEUP_PIN_UNDEF,') on my board definition. You were right ! And it's probably the cause of my UART problems.

You can see here how my board is configured:
https://github.com/ofauchon/oflmotes/blob/master/mote-devboard/boards/oflmote-dev/include/periph_conf.h

I'll try to rebuild my project over your rebased branch to see if everything works properly now.

Thanks again

Olivier

@benemorius
Copy link
Member

@ofauchon thank you! There's a more current one in #11789 with IIRC some changes that would apply to you.

@ofauchon
Copy link

Hi.

I could successuly build my sensor application on top of your branch
(master...benemorius:pr/kinetis-pm-rebase) and I run it on my KW2xD board.

  • During i2c measurements, radio TX, it 's blocked in 3 (which is fine for me)
  • During sleep , it's PM mode 0 (LLS) with ~ 1,5 mA consumption (I guess I need to turn off some more peripherals to save energy )

Anyway, I'm happy with this pull request and I hope It'll be merged soon !

Thanks
Olivier

@stale
Copy link

stale bot commented Jan 20, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added the State: stale State: The issue / PR has no activity for >185 days label Jan 20, 2020
@stale stale bot closed this Feb 20, 2020
@stale stale bot removed the State: stale State: The issue / PR has no activity for >185 days label Feb 20, 2020
@smlng smlng added the State: don't stale State: Tell state-bot to ignore this issue label Feb 20, 2020
@miri64
Copy link
Member

miri64 commented Jun 23, 2020

@MichelRottleuthner @benpicco anyone of you maybe want to take this over?

@benpicco
Copy link
Contributor

@benemorius already did in #11789

@miri64
Copy link
Member

miri64 commented Jun 23, 2020

Ah, then let's close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: pm Area: (Low) power management Platform: ARM Platform: This PR/issue effects ARM-based platforms State: don't stale State: Tell state-bot to ignore this issue Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.