Skip to content

Fix PM1 button and wake IRQ handling and correct the power API docs - #329

Merged
lovyan03 merged 2 commits into
m5stack:developfrom
ainyan03:pm1_audit_fixes
Aug 18, 2026
Merged

Fix PM1 button and wake IRQ handling and correct the power API docs#329
lovyan03 merged 2 commits into
m5stack:developfrom
ainyan03:pm1_audit_fixes

Conversation

@ainyan03

@ainyan03 ainyan03 commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Problem

A register-level audit of M5PM1_Class against the PM1 datasheet found
several defects:

  • getPekPress() reported a double click with the same value as a single
    click, and cleared the whole IRQ Status 3 register on any click — erasing a
    pending WAKEUP flag as a side effect. It also cleared flags that arrived
    between its read and its write.
  • clearWakeSource() used a read-modify-write: a wake bit that rose between
    the read and the write was written back as zero and lost. Worse, the read
    path folds an I2C failure into 0, so a single failed read caused the
    write to wipe every wake flag regardless of the mask.
  • gpio_function_t exposed wake = 0b10, which the datasheet defines as
    Reserved (the real wake configuration lives in separate registers this
    class does not touch), and setGPIOFunction() accepted any cast value,
    shifting out-of-range encodings into neighboring pins' mux fields.
  • getBatteryCharge(bool*) and getBatteryVoltage(uint16_t*) dereferenced
    their output pointers without a null check.
  • Several comments were wrong: the DCDC rail is 3.3 V, not 5 V
    (PWR_CFG bit1 = 3.3V_DCDC_EN), and the charge current/voltage/status
    methods documented parameter ranges for registers the PM1 does not have —
    they are permanent stubs.

Fix

  • getPekPress() keeps the AXP-shaped contract (0 / 2; the PM1 does not
    report long presses) and consumes the SINGLE and DOUBLE click flags with a
    single selective write-zero-to-clear access that preserves WAKEUP. A double
    click still reports 2 so Power.getKeyState() consumers see a click, and
    the new wasPekDoubleClicked() reports the distinction without extra I2C
    traffic. If the clear write fails the event stays pending and 0 is
    returned instead of consuming it.
  • clearWakeSource() performs one selective write with no read, masked to
    the documented bits [6:0]. The docs now state the write-zero-to-clear
    assumption explicitly, since the datasheet does not specify the polarity.
  • gpio_function_t::wake is removed and setGPIOFunction() rejects
    anything but gpio, irq, and special.
  • Null guards added to the two output-pointer getters, matching the
    neighboring APIs.
  • Doc corrections for the 3.3 V DCDC rail and the charge-control stubs; the
    dead commented-out implementations referencing nonexistent registers are
    removed.

Breaking change

gpio_function_t::wake no longer exists; code naming it fails to compile.
It never worked — it wrote a reserved encoding.

Post-review amendment

A second local adversarial review round (two independent passes over the
final diff) converged on one real defect: the double-click latch was
set-only, so a stale double could be attributed to a much later single
click. The latch is now reassigned on every successfully reported click.
The wasPekDoubleClicked() doc also states the single-task polling
expectation, and the charge getter docs no longer show value ranges for
registers that do not exist.

@lovyan03
lovyan03 merged commit b4eb4d2 into m5stack:develop Aug 18, 2026
27 checks passed
@ainyan03
ainyan03 deleted the pm1_audit_fixes branch August 18, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants