UART API

The UART API provides access to the ESP32’s Universal Asynchronous Receiver/Transmitter hardware. Use it when you need serial communication with sensors, modems, external MCUs, industrial adapters, or RS-232/RS-485 transceivers.

Xedge32 supports both polling and callback-driven receive handling. In most cases, the callback-based approach is preferred because it is more responsive and avoids constant polling from Lua.

The transmit side can also operate efficiently in a semi-asynchronous style as long as the TX ring buffer has enough free space to accept the outgoing data.

Creating a UART Object

Function signature:

uart = esp32.uart(port [, config])

Parameters

port

UART port number, for example 0.

config

Optional table with the following settings:

  • callback: Receive callback function. Setting this enables interrupt-driven RX handling.

  • databits: Data bits from 5 to 8. Default is 8.

  • baudrate: Baud rate. Default is 9600.

  • rxbufsize: Receive buffer size. Default is 1024.

  • txbufsize: Transmit buffer size. Default is 1024.

  • txpin: TX GPIO. Defaults to the port’s default pin.

  • rxpin: RX GPIO. Defaults to the port’s default pin.

  • rtspin: RTS GPIO. Disabled by default.

  • ctspin: CTS GPIO. Disabled by default.

  • stopbits: Stop-bit setting. Use 1 or 2 explicitly. Values other than 1 and 2 are interpreted as 1.5.

  • parity: Either "EVEN" or "ODD".

  • flowctrl: Either "RTS", "CTS", or "CTSRTS".

  • rs485: Enables RS-485 half-duplex mode. Requires rtspin when used with a suitable transceiver such as ADM483.

  • timeout: Default 0. Without pattern, this defines how long to wait before triggering the callback, measured in UART character times.

  • pattern: Enables pattern detection, for example "+++". Requires a callback.

Additional options when pattern is enabled:

  • maxlen: Maximum number of recorded pattern positions. Default is 0.

  • timeout: Maximum gap allowed between characters in the same pattern.

  • postidle: Minimum idle time required after the pattern.

  • preidle: Minimum idle time required before the pattern.

For the lower-level hardware behavior behind pattern detection, see the ESP-IDF function uart_enable_pattern_det_baud_intr().

Receive Callback Signatures

When using a callback, Xedge32 calls one of the following forms:

function(data, pattern)

data is a Lua string containing one or more received characters. pattern is a boolean set to true when the data corresponds to a detected pattern.

function(nil, emsg)

Called for receive-side errors or special UART conditions.

Possible emsg values:

  • "full": RX buffer full; queue reset.

  • "overflow": RX FIFO overflow; queue reset.

  • "frame": Framing error.

  • "parity": Parity error.

  • "databreak": Data-and-break event.

  • "break": Break event.

UART Object Methods

uart:read([timeout])

Reads data from the RX queue and optionally waits up to timeout milliseconds. Do not combine this method with a receive callback on the same object.

uart:write(data)

Writes data to the UART. The call blocks until the data has been pushed into the TX FIFO or TX ring buffer. If the transmit side is full, the call waits.

uart:txsize()

Returns the remaining free space in the TX ring buffer. This is useful when you want to decide how much data you can queue without blocking.

uart:close()

Releases the UART object and its associated resources.

UART Echo Example

The following example opens UART port 2, configures GPIO 4 and GPIO 5 as TX and RX, and echoes all received data back to the sender.

local uart
local cfg = {
   baudrate = 115200,
   txpin = 4,
   rxpin = 5,
   callback = function(data, err)
      if data then
         uart:write(data)
      else
         trace("Err", err)
      end
   end
}

uart = esp32.uart(2, cfg)

This callback-driven pattern is a good default when you need responsive serial input handling without writing your own polling loop.

Practical Guidance

  • Prefer callbacks over uart:read() when the device should react to incoming serial data promptly.

  • Use uart:txsize() if you are streaming large bursts and want to avoid unexpected blocking.

  • Enable rs485 only when your hardware design specifically requires half-duplex RS-485 control through RTS.