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>
97 lines
3.3 KiB
C
97 lines
3.3 KiB
C
#ifndef POWER_MGMT_H
|
|
#define POWER_MGMT_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
/*
|
|
* power_mgmt — STM32F7 STOP-mode sleep/wake manager (Issue #178).
|
|
*
|
|
* State machine:
|
|
* PM_ACTIVE ──(idle ≥ PM_IDLE_TIMEOUT_MS or sleep cmd)──► PM_SLEEP_PENDING
|
|
* PM_SLEEP_PENDING ──(fade complete, ≥ PM_FADE_MS)──► PM_SLEEPING (WFI)
|
|
* PM_SLEEPING ──(EXTI wake)──► PM_WAKING ──(clocks restored)──► PM_ACTIVE
|
|
*
|
|
* Any call to power_mgmt_activity() during SLEEP_PENDING or SLEEPING
|
|
* immediately transitions back toward PM_ACTIVE.
|
|
*
|
|
* Wake sources (EXTI, falling edge on UART idle-high RX pin or IMU INT):
|
|
* EXTI1 PA1 UART4_RX — CRSF/ELRS start bit
|
|
* EXTI7 PB7 USART1_RX — JLink start bit
|
|
* EXTI4 PC4 MPU6000 INT — IMU motion (handler owned by mpu6000.c)
|
|
*
|
|
* Peripheral gating on sleep entry (clock disable, state preserved):
|
|
* Disabled: SPI3/I2S3 (audio amp), SPI2 (OSD), USART6, UART5 (debug)
|
|
* Active: SPI1 (IMU), UART4 (CRSF), USART1 (JLink), I2C1 (baro/mag)
|
|
*
|
|
* Sleep LED (LED1, active-low PC15):
|
|
* PM_SLEEP_PENDING: triangle-wave pulse, period PM_LED_PERIOD_MS
|
|
* All other states: 0 (caller uses normal LED logic)
|
|
*
|
|
* IWDG:
|
|
* Fed immediately before WFI. STOP wakeup <10 ms typical — well within
|
|
* WATCHDOG_TIMEOUT_MS (50 ms).
|
|
*
|
|
* Safety interlock:
|
|
* Caller MUST NOT call power_mgmt_tick() while armed; call
|
|
* power_mgmt_activity() instead to keep the idle timer reset.
|
|
*
|
|
* JLink integration:
|
|
* JLINK_CMD_SLEEP (0x09) → power_mgmt_request_sleep()
|
|
* Any valid JLink frame → power_mgmt_activity() (handled in main loop)
|
|
*/
|
|
|
|
typedef enum {
|
|
PM_ACTIVE = 0, /* Normal, all peripherals running */
|
|
PM_SLEEP_PENDING = 1, /* Idle timeout reached; LED fade-out in progress */
|
|
PM_SLEEPING = 2, /* In STOP mode (WFI); execution blocked in tick() */
|
|
PM_WAKING = 3, /* Transitional; clocks/peripherals being restored */
|
|
} PowerState;
|
|
|
|
/* ---- API ---- */
|
|
|
|
/*
|
|
* power_mgmt_init() — configure wake EXTI lines (EXTI1, EXTI7).
|
|
* Call after crsf_init() and jlink_init().
|
|
*/
|
|
void power_mgmt_init(void);
|
|
|
|
/*
|
|
* power_mgmt_activity() — record cmd_vel event (CRSF frame, JLink frame).
|
|
* Resets idle timer; aborts any pending/active sleep.
|
|
*/
|
|
void power_mgmt_activity(void);
|
|
|
|
/*
|
|
* power_mgmt_request_sleep() — force sleep regardless of idle timer
|
|
* (called on JLINK_CMD_SLEEP). Next tick() enters PM_SLEEP_PENDING.
|
|
*/
|
|
void power_mgmt_request_sleep(void);
|
|
|
|
/*
|
|
* power_mgmt_tick(now_ms) — drive state machine. May block in WFI during
|
|
* STOP mode. Returns state after this tick.
|
|
* MUST NOT be called while balance_state == BALANCE_ARMED.
|
|
*/
|
|
PowerState power_mgmt_tick(uint32_t now_ms);
|
|
|
|
/* power_mgmt_state() — non-blocking read of current state. */
|
|
PowerState power_mgmt_state(void);
|
|
|
|
/*
|
|
* power_mgmt_led_brightness() — 0-255 brightness for sleep-pending pulse.
|
|
* Returns 0 when not in PM_SLEEP_PENDING; caller uses normal LED logic.
|
|
*/
|
|
uint8_t power_mgmt_led_brightness(void);
|
|
|
|
/*
|
|
* power_mgmt_current_ma() — estimated total current draw (mA) based on
|
|
* gating state; populated in JLINK_TLM_POWER telemetry.
|
|
*/
|
|
uint16_t power_mgmt_current_ma(void);
|
|
|
|
/* power_mgmt_idle_ms() — ms elapsed since last power_mgmt_activity() call. */
|
|
uint32_t power_mgmt_idle_ms(void);
|
|
|
|
#endif /* POWER_MGMT_H */
|