Skip to content

PlatformIO image panics in TFT_eSPI init on ESP32-S3: SPI_PORT resolves to FSPI = 0 #284

Closed

Description

@Strycher

Found on the first hardware run of any PlatformIO-built Field Compass image (um_feather, um_feathers3 @ 253f7af, 2026-09-07 evening, #283). The board boot-loops:

Initializing ST7796U TFT... Guru Meditation Error: Core 1 panic'ed (StoreProhibited)
EXCVADDR: 0x00000010   PC 0x42004363 = TFT_eSPI::begin_tft_write() TFT_eSPI.cpp:81 (SET_BUS_WRITE_MODE), from TFT_eSPI::init() <- initTFT() display.cpp:18 <- setup()

Verified with addr2line and objdump against the flashed ELF (sha 1905d2e7f): the faulting instruction is 's32i a9, a8, 0' with a8 = 16 and a9 = 1<<27 (SPI_USR_MOSI), i.e. a write to address 0x10 = SPI_USER_REG(SPI_PORT) with the register base evaluating to 0.

Cause, all verified in the pinned toolchain (platform 55.03.38-1, core 3.3.8, TFT_eSPI 2.5.43):

  • Processors/TFT_eSPI_ESP32_S3.h line 83: for ESP32-S3 with neither USE_HSPI_PORT nor USE_FSPI_PORT, SPI_PORT is FSPI.
  • cores/esp32/esp32-hal-spi.h line 35: on ESP32-S3, FSPI is 0 (bus index), not a GPSPI number.
  • esp32s3 soc.h line 36: REG_SPI_BASE(i) is 0 for i < 2 (only GPSPI2 and GPSPI3 exist). TFT_eSPI's own fallback definition is under #ifndef REG_SPI_BASE, so it never applies.
  • Result: _spi_cmd/_spi_user/_spi_mosi_dlen/_spi_w are NULL + offset; the first SPI write faults.

The feather_s3 (Adafruit) image built from the same flags has the identical instruction sequence (checked in both the #280 baseline ELF and the #283 build), so the Adafruit PlatformIO image has never worked either. C:\Dev.field_compass\flash-history.jsonl confirms no feather_s3 PlatformIO image was ever flashed; the #193 'first complete PlatformIO build' (#184/#185) was verified by compiling and linking, not on hardware. This is not a pin or wiring problem and not specific to the UM board.

Upstream TFT_eSPI master has since changed the ESP32-S3 default to 'SPI_PORT 2' (GPSPI2). In 2.5.43 the equivalent is -D USE_FSPI_PORT=1: SPI_PORT becomes 2 and TFT_eSPI instantiates its own SPIClass(FSPI), which is SPI2_HOST, the same controller the Arduino SPI object (SD, FRAM) uses. The alternative, USE_HSPI_PORT, would put the TFT on GPSPI3 while SD/FRAM stay on GPSPI2 with both routed to GPIO 36/35/37; the later SPI.begin for the SD card would steal the pin matrix from the TFT. The design comment at src.ino:575 says the TFT shares the FSPI bus, so USE_FSPI_PORT matches the design.

Fix: add -D USE_FSPI_PORT=1 to the shared build_flags in platformio.ini (both envs) with this rationale. Test, falsifiable: after re-flash the boot log prints 'Initializing ST7796U TFT... OK', the panel flashes red then shows the init screen, and the SD/FRAM init lines that follow SPI.begin still report their devices; if the panel goes dark after 'Initializing hardware...', the second SPIClass on the shared bus is the next suspect.

Consequence for the record: the PlatformIO migration (Epic #154, B2 #184) has not had a hardware-verified image until this is fixed; B6 #188 parity work should note it.

Activity

  1. Strycher commented on Sep 8, 2026

    @Strycher
    OwnerAuthor

    Hardware result, um_feather, 2026-09-08 00:11 EDT, image d6fa305 (USE_FSPI_PORT + SD/FRAM on TFT_eSPI::getSPIinstance()): tft.init() no longer faults, 'Initializing SD card... OK (30436 MB)', 'Initializing FRAM... OK (mfg:0x04 prod:0x4803, 256KB)'. On 8af7ce5 (USE_FSPI_PORT alone) the first SD.begin never returned. Same board, same wiring, only change = one SPIClass per controller. The SD hang was the second driver on GPSPI2. Remaining on this branch: the TFT panel shows backlight only (SPI bus proven by SD/FRAM; CS/DC/RST wiring or panel power still open, tracked in #283).

  2. added
    board:testingBoard sync: Testing column
    and removed
    board:readyBoard sync: Ready column
    on Sep 8, 2026
  3. Strycher commented on Sep 8, 2026

    @Strycher
    OwnerAuthor

    In PR #288 (8af7ce5 + d6fa305). Verified on um_feather across every boot from 2026-09-08 00:11 on: tft.init() completes, SD mounts, FRAM answers, TFT draws. Both root causes stand as written: SPI_PORT = FSPI = 0 in TFT_eSPI 2.5.43 on the S3 (fixed by USE_FSPI_PORT), and a second SPIClass on GPSPI2 hanging the first SD mount (fixed by SD/FRAM using TFT_eSPI::getSPIinstance()). CLAUDE.md now says so in the Display row.

  4. added 2 commits that reference this issue on Sep 8, 2026
  5. added 2 commits that reference this issue on Sep 8, 2026
  6. added
    board:doneBoard sync: Done column
    and removed
    board:testingBoard sync: Testing column
    on Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions