Skip to content

espressif/qspibus: mark QSPIBus pins never-reset so the display survives VM cleanup - #11670

Open
kccarbone wants to merge 1 commit into
adafruit:mainfrom
kccarbone:qspibus-never-reset
Open

kccarbone wants to merge 1 commit into
adafruit:mainfrom
kccarbone:qspibus-never-reset

Conversation

@kccarbone

Copy link
Copy Markdown

common_hal_qspibus_qspibus_construct() claims its pins but never marks them never-reset. cleanup_after_vm() calls reset_all_pins() after the boot.py phase (whether or not a boot.py exists) and again after code.py. That resets every pin that isn't in the never-reset mask, and then rebuilds _in_use_pin_mask from the never-reset mask. So clock, data0-3 and cs are detached from the SPI2 peripheral and marked free, but the QSPIBus object, and the display on top of it, stays alive. After that, display transfers go nowhere and no error is raised.

Symptom

On the Waveshare ESP32-S3-Touch-AMOLED-2.41 (waveshare_esp32_s3_amoled_241), board.DISPLAY stays black. On the device:

  • the QSPI pins report as free while board.DISPLAY's QSPIBus is still active
  • the RM690B0's TE line pulses 0 times per second, so the panel is getting no traffic

Fix

After each claim_pin(), call common_hal_never_reset_pin(). This covers clock, data0-3, cs, and the optional dcx and reset pins. paralleldisplaybus/ParallelBus.c (espressif) and shared-module/fourwire/FourWire.c already do this for their display pins.

No change is needed in deinit(). It already calls reset_pin_number() on every bus pin, and on espressif that clears the never-reset bit. So displayio.release_displays() or an explicit deinit still frees the pins.

Testing

  • make BOARD=waveshare_esp32_s3_amoled_241 builds on main (ESP-IDF v6.1-dev).
  • tools/codeformat.py reports no changes.
  • On hardware: I tested the same change on a 10.3.1-based build on a V2 unit of this board. That build used a local board definition for the V2 hardware, which is not part of this PR. With the fix, TE pulses at 60/s, the pins stay claimed after VM cleanup, and a displayio demo renders. Without it, the display is black.
  • Not tested on V1 hardware or on a build from main itself. The bug is in the shared QSPIBus driver, not the board definition, so V1 users should see the same black screen and get the same fix.

QSPIBus first shipped in 10.2.0, and waveshare_esp32_s3_amoled_241 is the only board in the tree that uses it.

🤖 Generated with Claude Code

QSPIBus claimed its pins but never marked them never-reset, so
reset_all_pins() in cleanup_after_vm() (run after the boot.py phase and
after code.py) detached clock, data0-3 and cs from the SPI peripheral
and marked them free while the display bus stayed alive. On the
Waveshare ESP32-S3-Touch-AMOLED-2.41, board.DISPLAY stayed black: the
QSPI pins reported free and the panel's TE line never pulsed.

Mark clock, data0-3, cs and the optional dcx and reset pins never-reset
right after claiming them, as paralleldisplaybus and fourwire already
do. deinit() needs no change: it releases the pins with
reset_pin_number(), which also clears the never-reset bit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@dhalbert dhalbert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We are working on eliminating never_reset and related logic, one port at a time. See #11439, #11485, #11487, #11489. We just haven't gotten to espressif yet. So this code will change in the future anyway.

I am not sure of the schedule but we want to do this for espressif before 11.0.0 final.

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