Stop UART1 from grabbing the SPI flash pins on ESP32 - #1271
Merged
Merged
Conversation
HardwareSerial::begin() substitutes the core's default pins when both rxPin and txPin are negative and the driver is not installed yet. On ESP32 classic those defaults are GPIO 9 and 10, which are the SD_DATA2/SD_DATA3 lines of the SPI flash. Attaching UART1 to them stops code fetch from flash, so the device panics with IllegalInstruction on a PC that reads back as 0xFFFFFFFF, reboots, and does the same on the next boot. The uart_set_pin() call right after begin() was meant to place the UART on the configured pin, but the crash happens inside begin() before it is reached. Only ESP32 classic is affected, and only when HAN RX is not GPIO16: GPIO16 selects UART2, whose defaults 16/17 are correct, while S2, S3 and C3 default UART1 to pins that are not connected to the flash. Passing the pins to begin() means an out-of-range pin now reaches the ESP_ERROR_CHECK inside uartBegin() instead of being ignored, so reject pins the SoC does not have along with the existing invalid-pin cases. The UI offers GPIO 20 and 24 on ESP32, neither of which exists. Reported for WT32-ETH01 in #1270. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🔧 PR Build ArtifactsVersion: All environments built successfully. Download the zip files:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the boot loop reported for WT32-ETH01 in #1270.
What happens
setupHanPort()callshwSerial->begin(baud, serialConfig, -1, -1, invert)and then moves the UART to the configured pin withuart_set_pin(). ButHardwareSerial::begin()substitutes the core's default pins when bothrxPinandtxPinare negative and the driver is not yet installed, and for UART1 on ESP32 classic those defaults are GPIO 9 and 10 — theSD_DATA2/SD_DATA3lines of the SPI flash.Muxing them away from the flash controller stops code fetch, so the device panics inside
begin(), beforeuart_set_pin()is ever reached. It reboots, runs the same setup, and crashes again.The register dump in the report identifies it precisely:
A120x3FF49054PERIPHS_IO_MUX_SD_DATA2_U, the IO_MUX register for GPIO9A10,A3,A59A1117U1RXD_IN_IDX, the UART1 RX input signalffffffffIt also explains why the
(D) Hardware serialline is missing before some of the crashes: thatPSTRformat string lives in the flash that just went away.Scope
Only ESP32 classic, and only when HAN RX is not GPIO16 — GPIO16 selects UART2, whose defaults 16/17 happen to be the right pins. S2, S3 and C3 default UART1 to 18, 15 and 18, none of which are flash pins. Not a v2.6 regression; the same call is in v2.5.7.
The change
Pass the pins to
begin()so the core never falls back to its defaults.uartBegin()performs the sameuart_set_pin()internally, so the existing call below it is now redundant; I left it rather than unwind theuart_numbookkeeping around it.That routes an out-of-range pin into the
ESP_ERROR_CHECKinsideuartBegin(), where it would abort instead of being silently ignored, so the existing invalid-pin guard now also rejects pins the SoC does not have. This is reachable today:UartSelectOptions.svelteoffers GPIO 20 and 24 on ESP32, neither of which exists.Verification
All six device targets build and
pio test -e nativepasses 24/24. I have no WT32-ETH01, so confirmation on hardware is still needed — the expected result is thatsetupHanPortcompletes and the boot loop stops.Noticed while here, not changed
PassiveMeterCommunicator.cpp:630—if(rxpin == 3 || rxpin == 113) hwSerial = &Serial;is dead on ESP32, because the#if defined(ESP32)block just below unconditionally overwriteshwSerialwith&Serial1. HAN RX on GPIO3 therefore puts UART1 on the console pin instead of using UART0.UartSelectOptions.svelte.🤖 Generated with Claude Code