feat(power): STOP-mode sleep/wake power manager — Issue #178 #186

Merged
sl-jetson merged 1 commits from sl-firmware/issue-178-power-mgmt into main 2026-03-02 10:56:52 -05:00
Collaborator

Summary

Closes #178.

STM32F7 STOP-mode power management: <10ms wake latency, 30s idle timeout, peripheral gating, Jetson sleep command, power telemetry.

Changes

New files

  • include/power_mgmt.hPowerState enum, full API
  • src/power_mgmt.c — state machine, EXTI wake sources, PLL restore, peripheral clock gating, sleep LED, current estimates
  • test/test_power_mgmt.py — 72 tests, all passing

Modified files

  • include/config.hPM_IDLE_TIMEOUT_MS=30000, PM_FADE_MS=3000, PM_LED_PERIOD_MS=2000, per-subsystem current constants, PM_TLM_HZ=1
  • include/jlink.hJLINK_CMD_SLEEP=0x09, JLINK_TLM_POWER=0x81, jlink_tlm_power_t (11 bytes), sleep_req in JLinkState, jlink_send_power_telemetry() declaration
  • src/jlink.cJLINK_CMD_SLEEP dispatch, jlink_send_power_telemetry() implementation
  • src/main.cpower_mgmt_init(), activity tracking, sleep_req handler, power_mgmt_tick(), sleep LED PWM, JLINK_TLM_POWER at 1 Hz

Design notes

Feature Implementation
Wake sources EXTI1(PA1/CRSF) + EXTI7(PB7/JLink) + EXTI4(PC4/IMU)
Gated peripherals SPI3/I2S3, SPI2(OSD), USART6, UART5
Always-on SPI1(IMU), UART4(CRSF), USART1(JLink), I2C1
PLL restore HSI→PLLM8/N216/P2=216 MHz; uwTick saved/restored
IWDG Fed before WFI; ~4ms wake << 50ms timeout
Safety power_mgmt_tick() only called when BALANCE_DISARMED
Sleep LED Triangle-wave pulse (2s period), software PWM on LED1
Jetson control JLINK_CMD_SLEEP → immediate sleep regardless of idle timer
Power telemetry JLINK_TLM_POWER at 1 Hz: state + current estimates + idle_ms

Test results

72 passed in 0.05s
## Summary Closes #178. STM32F7 STOP-mode power management: <10ms wake latency, 30s idle timeout, peripheral gating, Jetson sleep command, power telemetry. ## Changes ### New files - **`include/power_mgmt.h`** — `PowerState` enum, full API - **`src/power_mgmt.c`** — state machine, EXTI wake sources, PLL restore, peripheral clock gating, sleep LED, current estimates - **`test/test_power_mgmt.py`** — 72 tests, all passing ### Modified files - **`include/config.h`** — `PM_IDLE_TIMEOUT_MS=30000`, `PM_FADE_MS=3000`, `PM_LED_PERIOD_MS=2000`, per-subsystem current constants, `PM_TLM_HZ=1` - **`include/jlink.h`** — `JLINK_CMD_SLEEP=0x09`, `JLINK_TLM_POWER=0x81`, `jlink_tlm_power_t` (11 bytes), `sleep_req` in `JLinkState`, `jlink_send_power_telemetry()` declaration - **`src/jlink.c`** — `JLINK_CMD_SLEEP` dispatch, `jlink_send_power_telemetry()` implementation - **`src/main.c`** — `power_mgmt_init()`, activity tracking, `sleep_req` handler, `power_mgmt_tick()`, sleep LED PWM, `JLINK_TLM_POWER` at 1 Hz ## Design notes | Feature | Implementation | |---|---| | Wake sources | EXTI1(PA1/CRSF) + EXTI7(PB7/JLink) + EXTI4(PC4/IMU) | | Gated peripherals | SPI3/I2S3, SPI2(OSD), USART6, UART5 | | Always-on | SPI1(IMU), UART4(CRSF), USART1(JLink), I2C1 | | PLL restore | HSI→PLLM8/N216/P2=216 MHz; `uwTick` saved/restored | | IWDG | Fed before WFI; ~4ms wake << 50ms timeout | | Safety | `power_mgmt_tick()` only called when `BALANCE_DISARMED` | | Sleep LED | Triangle-wave pulse (2s period), software PWM on LED1 | | Jetson control | `JLINK_CMD_SLEEP` → immediate sleep regardless of idle timer | | Power telemetry | `JLINK_TLM_POWER` at 1 Hz: state + current estimates + idle_ms | ## Test results ``` 72 passed in 0.05s ```
sl-webui added 1 commit 2026-03-02 10:53:20 -05:00
Adds STM32F7 STOP-mode power management with <10ms wake latency:

- power_mgmt.c: state machine (ACTIVE→SLEEP_PENDING→SLEEPING→WAKING),
  30s idle timeout (PM_IDLE_TIMEOUT_MS), 3s LED fade before STOP,
  gate SPI3/I2S3+SPI2+USART6+UART5 on sleep (clock-only, state preserved),
  EXTI1(PA1/CRSF)+EXTI7(PB7/JLink)+EXTI4(PC4/IMU) wake sources,
  PLL restore after STOP (PLLM=8/N=216/P=2 → 216MHz), uwTick save/restore
- Peripheral gating: I2S3, SPI2(OSD), USART6, UART5 disabled during STOP;
  SPI1(IMU), UART4(CRSF), USART1(JLink), I2C1 remain active as wake sources
- Sleep LED: triangle-wave pulse (2s period) on LED1 during SLEEP_PENDING,
  software PWM in main loop (1-bit, pm_pwm_phase vs brightness)
- IWDG: fed just before WFI; <10ms wake << 50ms WATCHDOG_TIMEOUT_MS
- JLink: JLINK_CMD_SLEEP=0x09, JLINK_TLM_POWER=0x81 (11-byte power frame
  at 1Hz: power_state, est_total_ma, est_audio_ma, est_osd_ma, idle_ms)
- main.c: power_mgmt_init(), activity() on CRSF/JLink/armed, tick() when
  disarmed, sleep_req handler, LED PWM, JLINK_TLM_POWER telemetry
- config.h: PM_* constants, PM_CURRENT_*_MA estimates, PM_TLM_HZ
- test_power_mgmt.py: 72 tests passing (state machine, LED, gating,
  current estimates, JLink protocol, wake latency, hardware constants)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sl-jetson merged commit 077f26d9d6 into main 2026-03-02 10:56:52 -05:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: seb/saltylab-firmware#186
No description provided.