Skip to content

[uart] Revert UART0 default pin workarounds (fixed in ESP-IDF 5.5.2)#14363

Merged
bdraco merged 3 commits intodevfrom
fix-uart-default-pin-pullup-removal
Feb 28, 2026
Merged

[uart] Revert UART0 default pin workarounds (fixed in ESP-IDF 5.5.2)#14363
bdraco merged 3 commits intodevfrom
fix-uart-default-pin-pullup-removal

Conversation

@bdraco
Copy link
Member

@bdraco bdraco commented Feb 27, 2026

What does this implement/fix?

Reverts PR #14130 and PR #12519 which added gpio_reset_pin() and pin->setup() workarounds for default UART0 pins on ESP-IDF.

Background

Issue #10132 reported that LD2410 sensors stopped working on default UART0 pins. PR #12519 attributed the root cause to espressif/esp-idf#17459 (commit espressif/esp-idf@9ed617fb17 removing gpio_func_sel() from uart_set_pin()) and added gpio_reset_pin() calls as a workaround. However, gpio_reset_pin() disables the input buffer, which broke UART RX. PR #14130 then added pin->setup() to re-enable it — but that introduced a new regression (#14178) where gpio_config() removes the pullup set by gpio_reset_pin(), causing floating lines on RS-485/modbus devices.

Why the workaround was misattributed

The commit espressif/esp-idf@9ed617fb17 only removed gpio_func_sel() from the GPIO matrix fallback path — the code path for non-default pins. Default UART0 pins use the IOMUX path via uart_try_set_iomux_pin(), which returns false only when the pin doesn't match the default (upin->default_gpio != io_num). For default UART0 pins it returns true, so the GPIO matrix fallback block (where gpio_func_sel was removed) is never entered.

The IOMUX path has handled default UART0 pins correctly since uart_try_set_iomux_pin was introduced in 2021, including on ESP-IDF 5.4.2 where the issue was reported:

RX path: uart_set_pin()uart_try_set_iomux_pin()gpio_iomux_in()gpio_ll_iomux_in() which calls PIN_INPUT_ENABLE() (re-enables input buffer)

TX path: uart_set_pin()uart_try_set_iomux_pin()gpio_iomux_out()gpio_ll_iomux_out() which calls gpio_ll_func_sel() (sets IOMUX function)

Upstream ESP-IDF fix

The true root cause was an ESP-IDF bootloader bug: when the console was switched away from UART0 (e.g., to USB Serial JTAG or a different UART), the bootloader did not properly release the default UART0 TX pin. The TX output remained active, causing issues when user code later reconfigured those pins for a different UART purpose.

Espressif fixed this in bootloader_console.c by adding a release_default_console_io() function that:

  1. Disables output on the UART0 TX pin (gpio_ll_output_disable())
  2. Resets the pin to GPIO function (gpio_ll_func_sel(..., PIN_FUNC_GPIO))
  3. Disconnects the UART RX signal (esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, ...))

This fix closes both espressif/esp-idf#16764 and espressif/esp-idf#17459.

The fix is included in ESP-IDF v5.5.2+ (not in v5.5.1). ESPHome currently uses ESP-IDF v5.5.3, so the workarounds are no longer needed.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected) — policy
  • Developer breaking change (an API change that could break external components) — policy
  • Undocumented C++ API change (removal or change of undocumented public methods that lambda users may depend on) — policy
  • Code quality improvements to existing code or addition of tests
  • Other

Related issue or feature (if applicable):

Pull request in esphome-docs with documentation (if applicable):

  • N/A

Test Environment

  • ESP32
  • ESP32 IDF
  • ESP8266
  • RP2040
  • BK72xx
  • RTL87xx
  • LN882x
  • nRF52840

Example entry for config.yaml:

# ESP32-C3 with PZEM-003 on default UART0 pins (no explicit pullup)
uart:
  tx_pin: GPIO21
  rx_pin: GPIO20
  baud_rate: 9600

modbus:

Checklist:

  • The code change is tested and works locally.
  • Tests have been added to verify that the new code works (under tests/ folder).

If user exposed functionality or configuration variables are added/changed:

@bdraco bdraco requested a review from a team as a code owner February 27, 2026 23:02
Copilot AI review requested due to automatic review settings February 27, 2026 23:02
@github-actions
Copy link
Contributor

To use the changes from this PR as an external component, add the following to your ESPHome configuration YAML file:

external_components:
  - source: github://pr#14363
    components: [uart]
    refresh: 1h

(Added by the PR bot)

@github-actions
Copy link
Contributor

👋 Hi there! This PR modifies 1 file(s) with codeowners.

@esphome/core - As codeowner(s) of the affected files, your review would be appreciated! 🙏

Note: Automatic review request may have failed, but you're still welcome to review.

@bdraco bdraco added this to the 2026.2.3 milestone Feb 27, 2026
@codecov-commenter
Copy link

codecov-commenter commented Feb 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.28%. Comparing base (5c56b99) to head (f1b1a4c).

Additional details and impacted files
@@           Coverage Diff           @@
##              dev   #14363   +/-   ##
=======================================
  Coverage   74.28%   74.28%           
=======================================
  Files          55       55           
  Lines       11597    11597           
  Branches     1583     1583           
=======================================
  Hits         8615     8615           
  Misses       2578     2578           
  Partials      404      404           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a regression on ESP32 ESP-IDF when using UART0 default pins (notably ESP32-C3 GPIO20 RX) by preserving the pull-up state established by gpio_reset_pin() while still re-enabling the RX input buffer required for UART0 IOMUX pins.

Changes:

  • Adjust UART0-default pin post-reset handling to avoid pin->setup() when no explicit pull/open-drain flags are configured.
  • Use gpio_input_enable() to re-enable the input buffer without modifying pull resistor configuration.
  • Keep pin->setup() for cases where users explicitly set pull-up/pull-down/open-drain in YAML.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 27, 2026

Memory Impact Analysis

Components: uart
Platform: esp32-idf

Metric Target Branch This PR Change
RAM 12,340 bytes 12,340 bytes ➡️ +0 bytes (0.00%)
Flash 232,163 bytes 231,903 bytes 📉 ✅ -260 bytes (-0.11%)
📊 Component Memory Breakdown
Component Target Flash PR Flash Change
gpio_driver 5,390 bytes 5,211 bytes 📉 -179 bytes (-3.32%)
[esphome]uart 3,591 bytes 3,533 bytes 📉 ✅ -58 bytes (-1.62%)
libc 37,198 bytes 37,183 bytes 📉 -15 bytes (-0.04%)
🔍 Symbol-Level Changes (click to expand)

Changed Symbols

Symbol Target Size PR Size Change
esphome::uart::IDFUARTComponent::load_settings(bool) 431 bytes 395 bytes 📉 -36 bytes (-8.35%)
esphome::uart::IDFUARTComponent::load_settings(bool)::{lambda(esphome::InternalGPIOPin*)#1}::oper...esphome::uart::IDFUARTComponent::load_settings(bool)::{lambda(esphome::InternalGPIOPin*)#1}::operator()(esphome::InternalGPIOPin*) const [$isra$0]
54 bytes 32 bytes 📉 -22 bytes (-40.74%)

Removed Symbols (top 15)

Symbol Size
gpio_reset_pin 179 bytes

Note: This analysis measures static RAM and Flash usage only (compile-time allocation).
Dynamic memory (heap) cannot be measured automatically.
⚠️ You must test this PR on a real device to measure free heap and ensure no runtime memory issues.

This analysis runs automatically when components change. Memory usage is measured from a representative test configuration.

@bdraco
Copy link
Member Author

bdraco commented Feb 27, 2026

#14364 will fix the unit tests

@bdraco
Copy link
Member Author

bdraco commented Feb 27, 2026

need to check the TX pin as well

@bdraco
Copy link
Member Author

bdraco commented Feb 27, 2026

actually we don't need gpio_input_enable at all

@bdraco bdraco force-pushed the fix-uart-default-pin-pullup-removal branch from 422e2fd to 188be9a Compare February 27, 2026 23:25
@bdraco
Copy link
Member Author

bdraco commented Feb 27, 2026

gpio_hal_iomux_in and gpio_hal_iomux_out should already do the right thing

@bdraco bdraco marked this pull request as draft February 27, 2026 23:29
@bdraco bdraco force-pushed the fix-uart-default-pin-pullup-removal branch from 188be9a to 0efa547 Compare February 27, 2026 23:34
@esphome esphome bot removed the small-pr PR < 30 lines label Feb 27, 2026
@bdraco bdraco changed the title [uart] Fix pin setup removing pullup on default UART0 pins [uart] Revert UART0 default pin workarounds (no longer needed on ESP-IDF 5.5.x) Feb 27, 2026
@bdraco bdraco changed the title [uart] Revert UART0 default pin workarounds (no longer needed on ESP-IDF 5.5.x) [uart] Revert UART0 default pin workarounds (fixed in ESP-IDF 5.5.2) Feb 27, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

@bdraco
Copy link
Member Author

bdraco commented Feb 28, 2026

ld2450,ld2412,ld2410 still ok

[14:16:30.335][D][ld2410:208]: LD2410 Sun Light: 1%
[14:16:31.408][D][sensor:124]: 'Still Energy' >> 100 %
[14:16:31.408][D][ld2410:208]: LD2410 Sun Light: 1%
[14:16:32.062][D][sensor:124]: 'RSSI' >> -42 dBm
[14:16:32.415][D][ld2410:208]: LD2410 Sun Light: 1%
[14:16:33.416][D][sensor:124]: 'Move Energy' >> 78 %
[14:16:33.423][D][ld2410:208]: LD2410 Sun Light: 1%

@bdraco bdraco marked this pull request as ready for review February 28, 2026 00:16
@bdraco
Copy link
Member Author

bdraco commented Feb 28, 2026

Thanks 🤞 that this is finally sorted out

@bdraco bdraco merged commit 8480e8d into dev Feb 28, 2026
39 checks passed
@bdraco bdraco deleted the fix-uart-default-pin-pullup-removal branch February 28, 2026 03:27
@github-actions github-actions bot locked and limited conversation to collaborators Mar 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modbus CRC Check failed - with latest update.

5 participants