Skip to content

machine.UART: Fix the double timeout with uart.read(), uart.write() and uart.readinto(). #17938

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

robert-hh
Copy link
Contributor

@robert-hh robert-hh commented Aug 16, 2025

Summary

When uart.read(), uart.write() and uart_readinto() timed out because less data was transferred than expected, but some, the delay was uart.timeout + uart.timeout.char instead of just uart,timeout_char().

This PR changes the behavior into the expected one. It consists of 3 commits. The first changes uart.read() and uart.write(). The impact of that change is limited to the machine.UART class. The second commit changes stream.readinto() and may affect all uses of that function.
The third commit changes the ESP32's machine_uart.c to deal properly with the timeout_char argument for uart.read().

uart.readline() is unchanged.

This PR addresses issue #17611.

Testing

Tested with STM32(Pyboard V1.1 and PYBD_SF6), RP2 Pico, MIMXRT(Teensy 4.1), SAMD51, ESP32, NRF (nrf52840) and a CC3200 board using strings of varying length. Typical results:

RP2

UART(0, baudrate=38400, bits=8, parity=None, stop=1, tx=0, rx=1, txbuf=256, rxbuf=256, timeout=200, timeout_char=50, invert=None, irq=0)

uart.read() msg=""  timeout=201 ms
uart.read() msg="123"  timeout=52 ms
uart.read() msg="12345"  timeout=1 ms

uart.readline() msg=""  timeout=201 ms
uart.readline() msg="12345"  timeout=202 ms
uart.readline() msg="12345\n"  timeout=2 ms

uart.readinto(bytearray(5)) msg="" timeout=201 ms
uart.readinto(bytearray(5)) msg="123" timeout=52 ms
uart.readinto(bytearray(5)) msg="12345" timeout=1 ms

CC3200

UART(1, pins=(Pin("GP16"), Pin("GP17")))

uart.read() msg=""  timeout=36 ms
uart.read() msg="123"  timeout=38 ms (from 74 ms without the change)
uart.read() msg="12345"  timeout=5 ms

uart.readline() msg=""  timeout=35 ms
uart.readline() msg="12345"  timeout=41 ms
uart.readline() msg="12345\n"  timeout=6 ms

uart.readinto(bytearray(5)) msg="" timeout=35 ms
uart.readinto(bytearray(5)) msg="123" timeout=39 ms
uart.readinto(bytearray(5)) msg="12345" timeout=5 ms

Trade-offs and Alternatives

If the impact of the changes to a stream module seems unsafe, the second commit may be omitted, causing the behavior of uart.readinto() unchanged.

Copy link

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:   +16 +0.002% standard
      stm32:   +60 +0.015% PYBV10
     mimxrt:   +56 +0.015% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:   +60 +0.022% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

Do not try to read/write again after timeout happened once.

Signed-off-by: robert-hh <robert@hammelrath.com>
Avoiding the double timeout when used with the UART class.

Signed-off-by: robert-hh <robert@hammelrath.com>
Before, it was ignored.
Tested with ESP32, ESP32S3, ESP32C6.

Signed-off-by: robert-hh <robert@hammelrath.com>
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.

1 participant