Skip to content

Bound the PWRGOOD wait in epd_board_v7 so power-on can't hang forever#481

Open
rktdno wants to merge 1 commit into
vroland:mainfrom
rktdno:fix/pwrgood-timeout
Open

Bound the PWRGOOD wait in epd_board_v7 so power-on can't hang forever#481
rktdno wants to merge 1 commit into
vroland:mainfrom
rktdno:fix/pwrgood-timeout

Conversation

@rktdno

@rktdno rktdno commented Jun 6, 2026

Copy link
Copy Markdown

Problem

epd_board_poweron() and epd_board_measure_vcom() in src/board/epd_board_v7.c busy-wait on the PCA9555 PWRGOOD bit with no timeout and no yield:

while (!(pca9555_read_input(config_reg.i2c.pca, 1) & CFG_PIN_PWRGOOD)) {
}

If the TPS65185 never reaches power-good — e.g. a supply/brownout dip during the power-up current surge, or a glitched I²C read — this loop spins forever and freezes the calling task. Since it also has no vTaskDelay, it busy-spins the core while stuck.

I hit this in the field on a battery-powered LilyGO T5 E-Paper S3 Pro (board_v7): as the battery drained, the power-up surge during a refresh dipped the rail, PWRGOOD never asserted, and the panel hung until a manual reset.

Fix

Bound both loops with a ~5 s timeout and a vTaskDelay(1) yield, then log + return on timeout — mirroring the TPS_REG_PG wait that immediately follows each of them (which already does exactly this). No change on healthy hardware; a stuck rail now fails gracefully instead of hanging the task.

🤖 Generated with Claude Code

epd_board_poweron() and epd_board_measure_vcom() busy-wait on the PCA9555
PWRGOOD bit with no timeout and no yield:

    while (!(pca9555_read_input(config_reg.i2c.pca, 1) & CFG_PIN_PWRGOOD)) {
    }

If the TPS65185 never reaches power-good (e.g. a supply/brownout dip during
the power-up current surge, or a glitched I2C read), this spins forever and
freezes the calling task. Seen in the field on a battery-powered LilyGO T5
E-Paper S3 Pro: a low-battery dip during a refresh left the panel hung until
a manual reset.

Bound both loops with a ~5s timeout plus a vTaskDelay yield, mirroring the
TPS_REG_PG wait immediately below each (which already does exactly this), and
log + return on timeout instead of hanging.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vroland

vroland commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Makes sense, thanks! Small nitpick: Can you extract the number of retries into a module-level define? Also, depending on the configured FreeRTOS tick rate the timeout may be longer or shorter. The smallest is 1ms giving us ~500ms which should be fine, but if there is a trivial way to make it tickrate-independent we may want to do that.

@martinberlin

Copy link
Copy Markdown
Collaborator

You could simply use something like:

 vTaskDelay(pdMS_TO_TICKS(10)); // 10 milliseconds 

And just loop accordingly to make it 5 seconds (Which is a lot) anyways my feedback about this would be:

If PWR_GOOD signal does not come, most probably your display won't update anyways since the power lines will be not powered. So with timeout or without it, will inevitably fail.

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.

3 participants