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

[Tracking] kinetis: Implement low power modes #11789

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

benemorius
Copy link
Member

@benemorius benemorius commented Jul 4, 2019

Contribution description

Taken from #7897

Implements low power modes using pm_layered with blocking of modes depending on what peripherals are in use and what state they are in. Defaults to unblocking all low power modes otherwise.

The GPIO, UART, I2C, LPTMR, and PIT peripheral drivers are updated to block power modes as appropriate. Other peripherals should continue working unaffected by this PR.

  • Kinetis boards that have a UART or LPUART RX callback configured need to add uart_config.llwu_rx = LLWU_WAKEUP_PIN_UNDEF to periph_conf.h. I think this PR updates them all but I didn't verify it. Missing this definition results in LLS mode being unblocked without any way to wake on UART activity.

  • Kinetis boards using LPTMR need to add LPTMR.llwu = LLWU_WAKEUP_MODULE_LPTMR0 to periph_conf.h. I think this PR updates them all.

  • Kinetis boards using a radio driver that hasn't added calls to pm_block() / pm_unblock() will break on this PR. I only realized this just now. Which drivers are in use? kw2xrf at86rf2xx? I think at86rf2xx won't break since it has an independent clock but I'm not sure about kw2xrf. Actually, at86rf2xx will need a LLWU pin configured for at86 IRQ or if that's not available it will need LLS blocked to keep the GPIO IRQ working.

I only have kw41z to test this on but hopefully with some feedback it should be working on other platforms too. I'm not sure if I2C has ever been tested. It needed a blocker since it yields until an IRQ instead of spinning like other peripherals.

Since #7897 I fixed some problems with the PM blocking logic in the UART driver and it's possible that the issues observed on pba-d-01-kw2x are resolved now but I don't have this board to test with.

Testing procedure

#11731 could be useful to help test this.

On frdm-kw41z with STDIO_UART_BAUDRATE=115200 running tests/periph_pm should start up with mode 0 (KINETIS_PM_LLS) blocked and everything else unblocked:

main(): This is RIOT! (Version: 2019.07-devel-929-g881951-HEAD)
This application allows you to test the CPU power management.
The available power modes are 0 - 3. Lower-numbered power modes
save more power, but may require an event/interrupt to wake up
the CPU. Reset the CPU if needed.
mode 0 blockers: 1 
mode 1 blockers: 0 
mode 2 blockers: 0 
mode 3 blockers: 0 
lowest allowed mode: 1
>

Slow the baudrate with CFLAGS+=-DSTDIO_UART_BAUDRATE=9600 make to allow mode 0 unblocked:

mode 0 blockers: 0 
mode 1 blockers: 0 
mode 2 blockers: 0 
mode 3 blockers: 0 
lowest allowed mode: 0
>

After verifying that the shell continues working from mode 0, it should be safe to test blocking and forcing other modes and observe the current consumption in each mode without worry of breaking the shell or other bad things happening:

lowest allowed mode: 0
> block 0
Blocking power mode 0.
> block 1
Blocking power mode 1.
> pm show
mode 0 blockers: 1 
mode 1 blockers: 1 
mode 2 blockers: 0 
mode 3 blockers: 0 
lowest allowed mode: 2
> set 1
CPU is entering power mode 1.
Now waiting for a wakeup event... #enter pressed
CPU has returned from power mode 1.
> 
> 

Take care not to unblock a mode that isn't blocked as there's an assertion for that (#11731 prints a friendly error instead).

Aside from that, the shell should remain responsive no matter what, and it's a bug if it doesn't. That's assuming that it was verified that it stayed working from mode 0 to begin with. A board with a valid UART LLWU pin defined (uart_config.llwu_rx != LLWU_WAKEUP_PIN_UNDEF) is required for this to work. Otherwise uart_poweron() will block mode 0 and if you unblock it manually or force mode 0 the shell will stop responding to input.

In case of an unresponsive shell on startup, change cpu/kinetis/include/periph_cpu.h:PM_BLOCKER_INITIAL to { .val_u32 = 0x01010101 } to block all modes on startup and then manually unblock them to see which ones break.

Concerning PM interfering with UART RX

Perhaps it is worth stating explicitly here that any Kinetis which is capable of uA sleeping in LLS mode and capable of waking by LLWU on the STDIO RX pin is capable of uA sleeping while maintaining a fully functioning shell with no dropped characters. If that doesn't work on this PR, it's a bug.

Concerning knowing why power modes are blocked

One known downside of the current pm_layered paradigm is that we don't keep track of who blocked what. I've experienced the confusion resulting from this lately while testing wider ranges of configurations that result in a wider variety of blocked PM states.

To address this, I've added LOG_INFO outputs that result in notices like this during (typically) startup:

[gpio] will block power mode 0 for pin interrupt while enabled
[uart] Blocking power mode 2 because module periph_gpio_irq is needed to sleep with RX enabled
[uart] Blocking power mode 2 because baudrate > 57600
[kw41zrf] will block power mode 1 while radio is awake

I find it helpful. I made some effort to have the outputs printed during startup/init instead of each time modes are blocked/unblocked in cases where the latter might happen much more often than the former.

Perhaps we might consider enforcing a policy that any code which blocks power modes must follow this pattern? Now is a good time to start while not many calls to pm_block() have yet been added.

Issues/PRs references

This comment has current consumption reference values as well as some information about PM usage and current measurement procedures.

@smlng smlng requested review from smlng and MrKevinWeiss July 4, 2019 06:42
@smlng smlng self-assigned this Jul 4, 2019
@smlng smlng added Area: cpu Area: CPU/MCU ports Area: pm Area: (Low) power management Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation labels Jul 4, 2019
@smlng smlng added this to the Release 2019.10 milestone Jul 4, 2019
@aabadie aabadie requested a review from fjmolinas July 4, 2019 08:29
@benemorius
Copy link
Member Author

I realized that the solution to unbreaking at86rf2xx was to redefine the problem as the fact that the GPIO peripheral was not addressed by this PR yet. The GPIO peripheral needs updating too because gpio_init_int() has a power mode dependency.

I've addressed this by having the GPIO peripheral use the LLWU peripheral when it's able to, and blocking PM_LLS when it isn't.

This should unbreak any off-chip radios. I tested it with an at86rf233 attached to a kw41z board. Using a randomly selected pin for at86 IRQ, it booted with PM_LLS blocked and a functioning radio. After moving at86 IRQ to one of the 16 pins that support LLWU, it booted with no modes blocked and using LLWU for the IRQ and again a functioning radio. It's really great to see pm_layered coming together like this!

I'll push the commit for this shortly.

@benemorius
Copy link
Member Author

I could start splitting things out of this PR if it would help with review. Let me know.

@leandrolanzieri
Copy link
Contributor

I could start splitting things out of this PR if it would help with review. Let me know.

@smlng?

@miri64
Copy link
Member

miri64 commented Jun 25, 2020

Or @MrKevinWeiss?

@benemorius
Copy link
Member Author

I've started splitting this PR up and I think that's the better way to do it. So far there is #13742 and I'll continue splitting after that is merged.

@miri64 miri64 added the Type: tracking The issue tracks and organizes the sub-tasks of a larger effort label Jun 26, 2020
@miri64 miri64 changed the title kinetis: Implement low power modes [Tracking] kinetis: Implement low power modes Jun 26, 2020
@MrKevinWeiss
Copy link
Contributor

I'll try to help where I can!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: cpu Area: CPU/MCU ports Area: pm Area: (Low) power management Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Type: tracking The issue tracks and organizes the sub-tasks of a larger effort
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants