Skip to content

Fix power button hang#124

Open
LeonKohli wants to merge 1 commit intofossasia:masterfrom
LeonKohli:fix-poweroff-isr-context
Open

Fix power button hang#124
LeonKohli wants to merge 1 commit intofossasia:masterfrom
LeonKohli:fix-poweroff-isr-context

Conversation

@LeonKohli
Copy link

@LeonKohli LeonKohli commented Jan 16, 2026

Fixes badge hang when pressing power button multiple times.

The issue was that poweroff() was called directly from button ISR context, causing __WFI to execute inside an interrupt handler which hangs the CPU.

Fix defers poweroff to main loop and adds GPIOA_IRQHandler for wake interrupt handling.

Summary by Sourcery

Defer badge power-off handling from interrupt context to the main loop and add a GPIO interrupt handler for wake-related interrupts.

Bug Fixes:

  • Prevent CPU hang when the power button is pressed multiple times by avoiding poweroff execution from ISR context.

Enhancements:

  • Introduce a deferred power-off mechanism using a pending flag processed in the main loop.
  • Add a GPIOA interrupt handler to clear wake-related interrupt flags without performing shutdown logic in the ISR.

poweroff() was called directly from button ISR context (via TMR3_IRQHandler),
causing LowPower_Shutdown's __WFI to execute inside an interrupt handler.
This is invalid and causes the CPU to hang.

Fix: Set flag in ISR, handle poweroff in main loop.
Add GPIOA_IRQHandler to clear wake interrupt flags.
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jan 16, 2026

Reviewer's Guide

Defers power-off handling from ISR context to the main loop and adds a dedicated GPIOA interrupt handler to safely clear wake-related GPIO interrupt flags, preventing CPU hangs when the power button is pressed multiple times.

Sequence diagram for deferred poweroff handling from button interrupt to main loop

sequenceDiagram
    actor User
    participant GPIOA as GPIOA_pin
    participant ButtonISR as Button_ISR_change_mode
    participant Main as main_loop
    participant Power as power_module

    User->>GPIOA: Press power button
    GPIOA-->>ButtonISR: Trigger button interrupt
    activate ButtonISR
    ButtonISR->>ButtonISR: change_mode()
    ButtonISR->>ButtonISR: Set pending_poweroff = 1
    ButtonISR-->>GPIOA: Return from interrupt
    deactivate ButtonISR

    loop Main loop
        Main->>Main: Check pending_poweroff
        alt pending_poweroff == 1
            Main->>Main: pending_poweroff = 0
            Main->>Power: poweroff()
            activate Power
            Power-->>Main: Enter low power and execute __WFI safely
            deactivate Power
        else pending_poweroff == 0
            Main->>Main: TMOS_SystemProcess()
        end
    end
Loading

Sequence diagram for GPIOA wake interrupt handling

sequenceDiagram
    actor User
    participant GPIOA as GPIOA_pins
    participant GPIOA_ISR as GPIOA_IRQHandler
    participant Power as LowPower_Shutdown
    participant CPU as CPU_core

    User->>GPIOA: Power button or charge state change
    GPIOA-->>GPIOA_ISR: Trigger GPIOA interrupt
    activate GPIOA_ISR
    GPIOA_ISR->>GPIOA: GPIOA_ClearITFlagBit(KEY1_PIN | CHARGE_STT_PIN)
    GPIOA_ISR-->>GPIOA: Return from interrupt
    deactivate GPIOA_ISR

    CPU->>Power: LowPower_Shutdown configured wake sources
    Power->>CPU: Execute __WFI
    CPU-->>Power: Wake when GPIOA interrupt occurs
    Power-->>CPU: Resume normal execution in main loop
Loading

File-Level Changes

Change Details Files
Defer poweroff() invocation from ISR context to the main loop using a volatile flag.
  • Introduce a volatile pending_poweroff flag to signal a deferred power-off request from interrupt context.
  • Update change_mode() so that when the POWER_OFF mode is selected in an ISR, it sets pending_poweroff instead of calling poweroff() directly and avoids assigning poweroff() in the modes dispatch table.
  • In the main loop, poll pending_poweroff and call poweroff() from thread context when the flag is set, then clear the flag.
src/main.c
Add a GPIOA interrupt handler to clear key/charge-related interrupt flags used for wake handling.
  • Implement GPIOA_IRQHandler() marked as interrupt/high-code to service GPIOA interrupts.
  • Within the handler, clear the interrupt flags for KEY1_PIN and CHARGE_STT_PIN, leaving LowPower_Shutdown logic unchanged to manage reset after __WFI.
src/power.c

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • Since pending_poweroff is written from ISR context and read/cleared in the main loop, consider making its type an explicitly sized volatile uint8_t (or similar) and keeping all writes as simple flag sets/clears to avoid any potential multi-byte access issues on this MCU.
  • Now that POWER_OFF is handled via pending_poweroff instead of the function pointer table, double-check that every code path that sets mode = POWER_OFF goes through change_mode(); if not, you may want a single central place that translates mode == POWER_OFF into a deferred shutdown.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Since `pending_poweroff` is written from ISR context and read/cleared in the main loop, consider making its type an explicitly sized `volatile uint8_t` (or similar) and keeping all writes as simple flag sets/clears to avoid any potential multi-byte access issues on this MCU.
- Now that `POWER_OFF` is handled via `pending_poweroff` instead of the function pointer table, double-check that every code path that sets `mode = POWER_OFF` goes through `change_mode()`; if not, you may want a single central place that translates `mode == POWER_OFF` into a deferred shutdown.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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.

1 participant