UART with the same pin for both RX and TX doesn't work on ESP32 variants
Port, board and/or hardware
esp32 port
MicroPython version
MicroPython v1.23.0 on 2024-06-02; LOLIN_C3_MINI with ESP32-C3FH4
MicroPython v1.23.0 on 2024-06-02; LOLIN_S2_MINI with ESP32-S2FN4R2
MicroPython v1.23.0-602.g403401490d on 2024-10-25; LOLIN S3 MINI with ESP32S3
MicroPython v1.23.0 on 2024-06-02; Generic ESP32S3 module with ESP32S3
Reproduction
from micropython import const
from machine import Pin, UART, mem32
PIN_NUM = const(2)
PIN_FUNC_REG = const(0x60004554 + 4 * PIN_NUM) # GPIO_FUNCx_OUT_SEL_CFG_REG
UART_NUM = const(1)
UART_BAUDRATE = const(1000000)
pin = Pin(PIN_NUM)
# pass the same `pin` to `tx` and `rx` doesn't work!
uart = UART(UART_NUM, UART_BAUDRATE, tx=pin, rx=pin)
uart.write(b'test') # UART signal doesn't routed to `PIN_NUM `.
print(uart.read()) # nothing gets printed..
# pass only `tx` (to get the `UART_SIG` number)
uart = UART(UART_NUM, UART_BAUDRATE, tx=pin)
UART_SIG = mem32[PIN_FUNC_REG] # see "Peripheral Signals via GPIO Matrix" in datasheet
# now try again, this time overwrite `PIN_FUNC_REG` with previous value
uart = UART(UART_NUM, UART_BAUDRATE, tx=pin, rx=pin)
mem32[PIN_FUNC_REG] = UART_SIG # ESP32-C3 is 6, ESP32-S3 is 12...
uart.write(b'test')
print(uart.read()) # b'test' is printed!
Expected behaviour
I expected:
uart = UART(UART_NUM, UART_BAUDRATE, tx=pin, rx=pin)
to work- but is seems to overwrite the TX output configuration and only the RX pin is configured correctly.
My workaround is to re-write the TX output configuration after the UART initialization:
uart = UART(UART_NUM, UART_BAUDRATE, tx=pin, rx=pin)
mem32[PIN_FUNC_REG] = UART_SIG
I think the UART class needs to support this case of a single pin for both TX and RX.
I use it to control some single line smart servo motors with open-drain UART bus...
The ESP32 support this common UART configuration (like RS485),
it also support echo-cancellation that may also be a nice option for the UART class..
Observed behaviour
Tested the provided sample code on ESP32-S2, ESP32-S3, ESP32-C3 -
All have the same bug and the same suggested workaround fix.
Additional Information
No, I've provided everything above.
Code of Conduct
Yes, I agree
UART.init() not working correctly on Raspberry Pi Pico W
Using UART.init() on RPi Pico W breaks UART functionality for the respective port when changing pins. (Even when changing back to the original pins.)
>>> from machine import UART, Pin
>>> uart = UART(0, baudrate=2400, tx=Pin(0), rx=Pin(1))
>>> uart.readline()
b'\x00Data on Pin 1\r\n'
>>> uart.readline()
b'\x00Data on Pin 1\r\n'
>>> uart.init(baudrate=2400, tx=Pin(12), rx=Pin(13))
>>> uart.readline()
>>> uart.readline()
>>> uart.init(baudrate=2400, tx=Pin(0), rx=Pin(1))
>>> uart.readline()
>>> uart.readline()
>>> uart2 = UART(1, baudrate=2400, tx=Pin(4), rx=Pin(5))
>>> uart2.readline()
b'\x00Data on Pin 5\r\n'
I would expect that I can change the pins on the fly (as per the note in the documentation of UART init: https://docs.micropython.org/en/latest/library/machine.UART.html#machine.UART.init).
External wiring is between RPi Pico W and Arduino Nano with the following wires:
RPi Pico W | Arduino Nano
------------+----------------------------
1 (GP0) | (19) A00 (configured as RX)
2 (GP1) | (22) A03 (configured as TX)
16 (GP12) | (20) A01 (configured as RX)
17 (GP13) | (23) A04 (configured as TX)
21 (GP16) | (21) A02 (configured as RX)
22 (GP17) | (24) A05 (configured as TX)
11 (GP8) | (19) A00 (configured as RX)
12 (GP9) | (22) A03 (configured as TX)
18 (GND) | (29) GROUND
(UART1, first ports, deliberately connected to the same ports on the Nano as UART0, second ports.)
firmware file: RPI_PICO_W-20231005-v1.21.0.uf2
version information: MicroPython v1.21.0 on 2023-10-06; Raspberry Pi Pico W with RP2040