RP2 UART timeout is incorrect
To repro link pins 0 and 1 and paste the following:
from machine import UART, Pin
uart = UART(0, 115200, rx=Pin(1, Pin.IN), tx=Pin(0, Pin.OUT), timeout=1000_000, timeout_char=1000_000)
uart.readline()
It times out after 15s rather than 16.6minutes.
Setting a long timeout is a hack to resolve https://github.com/micropython/micropython/issues/10867. In my opinion it should be possible to disable the timeout (set it to infinity). In uasyncio systems, uasyncio should provide any timeouts required by the application.
UART reaching timeout after first byte.
Port, board and/or hardware
Raspberry Pi Pico with RP2040
MicroPython version
MicroPython v1.25.0 on 2025-04-15;
Reproduction
When i set UART.timeout=200 and UART.timeout_char=50 and ask for 5 bytes and receive immediately just 3, then the reception takes 253ms.
from machine import Pin, UART
import time
uart = UART(1)
uart.init(38400,
bits=8,
parity=0, # even
stop=1,
tx=Pin(8),
rx=Pin(9, pull=Pin.PULL_UP),
txbuf=16,
rxbuf=16,
timeout=200, # ms
timeout_char=50) # ms
print(uart)
for addr in range(60):
t1 = time.ticks_ms()
uart.write(bytes((0xA5, addr))) # 0xA5, address
rx = uart.read(5)
t2 = time.ticks_ms()
print('RX "%s" %u ms' % (
''.join(["%02X" % b for b in rx]),
time.ticks_diff(t2, t1)))
UART(1, baudrate=38400, bits=8, parity=0, stop=1, tx=8, rx=9, txbuf=32, rxbuf=32, timeout=200, timeout_char=50, invert=None, irq=0)
RX "000054" 253 ms
RX "0053" 253 ms
RX "0052" 253 ms
RX "000051" 254 ms
RX "000050" 253 ms
RX "000037" 253 ms
RX "00455C95" 254 ms
RX "0000002F" 254 ms
RX "000000200E" 2 ms
RX "000000002D" 3 ms
RX "0000010B20" 2 ms
RX "18B32E32" 254 ms
RX "0000002A" 254 ms
It takes just 3ms with the exact number of bytes (5 in this example).
Expected behaviour
The total duration should be around timeout_char (not timeout + timeout_char) when the device respond immediately with less bytes than requested.
Observed behaviour
When receiving fewer bytes than asked, the observed duration of the reception is timeout + timeout_char.
Additional Information
I didn't find anything wrong in the implementation of the RP port:
https://github.com/micropython/micropython/blob/f498a16c7db6d4b2de200b3e0856528dfe0613c3/ports/rp2/machine_uart.c#L593
I thinks the issue lies in stream.c.
I guess one of the loop is calling again mp_machine_uart_read if the count of bytes is not reached.
Code of Conduct
Yes, I agree