Skip to content

MAX485 RS-485 transceiver

A half-duplex RS-485 transceiver between a UART and a shared A/B pair. The simulated part decides which bytes cross between the MCU and the bus, from the levels on DE and /RE at the moment of each byte.

Status at a glance

Aspect Status
Catalog id max485
Bus UART (DI = MCU TX, RO = MCU RX) plus two GPIO pins (DE, /RE)
Descriptor configs/devices/max485.yaml on the uart_transceiver primitive
Kit crates/core/src/peripherals/components/declarative_transceiver.rs
Gate model crates/core/src/peripherals/rs485.rs, hosted by the UART it is wired to
Example examples/arduino-uno-modbus-rtu
Tier modeled (byte level). No line-level analog behaviour.

Attachment

external_devices:
  - id: "rs485"
    type: "max485"
    connection: "usart0"      # the UART DI and RO are wired to
    config:
      de: "PD2"               # pad on DE, or high / low when tied to a rail
      re: "PD2"               # pad on /RE (active low); same pad as DE is common

Every slave on the A/B pair is one more uart_device attached to the same UART. Several slaves on one pair is a multi-drop segment: each hears every frame and answers only its own address.

What it does

Situation Result
MCU sends, DE low The byte leaves the MCU pin; no slave hears it.
MCU sends, DE high The byte is on the bus; every slave hears it.
DE high and /RE low Half-duplex echo: the MCU receives its own byte.
DE high and /RE high Driver on, receiver off: no echo.
Slave sends, /RE low The MCU receives the byte.
Slave sends, /RE high The byte is on the bus (see the log) but the MCU does not hear it.
Slave sends while DE is high Collision. The byte is not delivered.
Two slaves send in the same interval Collision. Neither byte is delivered.

Collisions are counted in the fidelity census as rs485_contention.

The level of DE and /RE is the one at the moment of the UART access. This needs a GPIO model that can publish a pad level on every write (Peripheral::watch_pad_level); the AVR ports and the generic GpioPort (STM32 families, nRF52, Kinetis, EFR32 Series 2, SAM, RA, i.MX RT) do. On a chip whose GPIO model cannot, the attach fails with an error that names the pad, instead of sampling late.

The bus log

The UART records every frame that crossed the pair, as rs485:

t=0.583ms master: 01 04 00 00 00 03 B0 0B
t=4.270ms slave s1: 01 04 06 00 D7 01 E0 04 D2 96 16

A test script asserts on it:

- peripheral_log: { peripheral: usart0, log: rs485, contains: "slave s1: 01 04 06" }

Bytes the driver puts on the bus are frames, not console text, so they are in this log and not in the UART console capture.

Limits

  • No line-level model: termination, bias, reflections and driver slew are not simulated. Termination resistors in a diagram are parts, but they do not change what the byte-level model delivers.
  • Transmission is instant, so firmware drops DE right after flush(). A master that releases DE too late (while a slave answers) gets a collision, as it would on a real bus; one that releases it too early does not lose its own last character, which hardware would.
  • A/B across several MCUs, each with its own transceiver, is not joined into one segment in this model. Slaves attach to the UART behind a transceiver.