RPBP — DMX subsystem (subsys = 0x08)¶
DMX512-A transmitter driven by a PIO state machine on PIO2. TX-only in v1; RX is a future extension once we wire up RDM (DMX remote-device management) bidirectional support.
The PIO program emits the slot bytes at 250 kbaud 8N2; the C driver generates the BREAK + Mark-After-Break (MAB) sequence by directly driving the pin while the SM is paused. This split keeps the PIO program tiny and the BREAK timing host-tunable.
Hardware: an external RS-485 transceiver (MAX485 / SN75176 / SN65HVD12 …) MUST be wired between the GPIO and the XLR-5 connector. The GPIO carries 3.3 V single-ended; the transceiver converts to the differential pair DMX requires.
Access path: vendor RPBP. Linux has no in-kernel DMX subsystem;
OLA (Open Lighting Architecture) is the de-facto userspace stack.
A future char-device wrapper (driver/TODO.md #M12) will let OLA
bind to /dev/rpbridge-dmxN.
Capabilities¶
buses.dmx[*] carries:
| key | type | meaning |
|---|---|---|
idx |
uint | universe index (always 0 in v1) |
tx_pin |
uint | GPIO feeding the RS-485 transceiver |
max_slots |
uint | always 512 (DMX512-A spec ceiling) |
direction |
text | "tx" (v1) |
Feature flag: dmx.tx.
Opcodes¶
0x00 GET_INFO¶
Request: empty.
Response (10 bytes):
c(u8) — universe count.p(u8) — GPIO carrying TX (before the transceiver).r(u8) — running flag (0/1).x(u8) — reserved.slt(LE u16) — currently configured slot count.brk(LE u16) — BREAK length in µs (≥ 88).mab(LE u16) — MAB length in µs (≥ 8).
0x01 SET_SLOTS¶
Request: [idx u8][offset LE u16][bytes …]. Copies bytes into the
universe buffer at slot offset. Slot 0 is the start code (typically
0x00); slots 1..512 are DMX channels.
Constraints:
offset + lenMUST NOT exceed 513 (start code + 512 channels).- Total wire payload ≤ MTU (4 KiB).
- Updates land in the next emitted frame.
0x02 START¶
Request: [idx u8]. Begins continuous frame transmission at ~40 Hz.
Each frame uses the current slot buffer.
0x03 STOP¶
Request: [idx u8]. Halts transmission, leaves the line idle HIGH
so the transceiver disables cleanly.
0x04 SET_BREAK¶
Request: [idx u8][break_us LE u16][mab_us LE u16]. Adjust the
BREAK and MAB durations. Spec minima:
break_us≥ 88 µs (clamped on the device side; values < 88 are silently raised).0keeps the current value.mab_us≥ 8 µs (clamped).0keeps the current value.
Useful for older receivers that need longer BREAKs.
Frame timing¶
A full 513-slot frame at 250 kbaud is approximately:
The driver schedules one frame every 25 ms, giving ~40 Hz refresh with a small scheduling margin. That matches USITT's recommended floor and is what most lighting consoles expect.
Examples¶
Send a single channel value¶
GET_INFO → running=0, slot_count=512
SET_SLOTS idx=0, offset=1, bytes=[0xFF] # ch1 = full
START idx=0
Stop the stream cleanly¶
Custom break for a finicky receiver¶
Error semantics¶
| Status | Cause |
|---|---|
ENOENT |
idx ≠ 0 |
EINVAL |
offset/len out of range, slot_count out of range |
EAGAIN |
transmitter not initialised |
EBUSY |
pin/PIO conflict at firmware boot |
ENOTSUP |
board built without RPBRIDGE_HAVE_DMX |
Hardware wiring (typical)¶
RP2350 GP44 ───┬──────► DI (transceiver input)
│
GND ────┼──────► GND
│
+5V ────┼──────► VCC (MAX485 needs 5 V; some
3.3 V transceivers like
SN65HVD12 work directly)
│
┌─────┴─────┐
│ MAX485 │
└─────┬─────┘
A ──┬─── XLR-5 pin 3
B ──┴─── XLR-5 pin 2
XLR-5 pin 1 = GND
DE/RE on the transceiver is tied HIGH (continuous transmit). For a half-duplex setup, route DE to a GPIO and toggle it around frames — not needed for v1's TX-only mode.