SPI subsystem (subsys = 2)¶
The SPI subsystem exposes the two RP2350 PL022 instances — SPI #0
on the PMOD header and SPI #1 on the breakout header with three
slave-select lines (CS0/CS1/CS2).
| Opcode | Name | Description |
|---|---|---|
0x00 |
XFER |
Full-duplex transfer with optional CS frame. |
0x01 |
SET_MODE |
CPOL/CPHA (mode 0..3). LSB-first rejected. |
0x02 |
SET_FREQ |
Set the baud rate; returns actual applied. |
0x03 |
GET_FREQ |
Read back the active baud. |
0x04 |
CS_ASSERT |
Drive a CS pin LOW (manual control). |
0x05 |
CS_RELEASE |
Drive a CS pin HIGH. |
All opcodes carry binary arguments. The CBOR flag is ignored (v1).
0x00 — XFER¶
Args (8 B header + variable TX payload):
[0] instance (0..1)
[1] cs_pin (GP number, 0xFF = no CS manipulation)
[2] flags (see RPBP_SPI_FLAG_*)
[3] reserved (MUST be 0)
[4..5] tx_len LE u16
[6..7] rx_len LE u16
[8..] tx_data tx_len bytes
Flags:
| Bit | Name | Effect |
|---|---|---|
| 0 | HOLD_CS |
Leave CS asserted after the transfer for multi-op transactions |
Wire behaviour
On the wire the transfer is always a full-duplex burst of
max(tx_len, rx_len) frames. TX is zero-padded past tx_len; only
the first rx_len MISO bytes are returned to the host. CS is driven
LOW before the first byte and HIGH after the last (unless
HOLD_CS=1, or cs_pin == 0xFF for externally-managed CS).
Reply body: [rx_len LE u16][rx_data].
Status: OK / EINVAL / EMSGSIZE / EBUSY (broker) / EIO.
0x01 — SET_MODE¶
Args (2 B): [instance][mode_bits]
Mode bits:
| Bit | Name | Meaning |
|---|---|---|
| 0 | CPHA |
0 = sample on leading edge, 1 = trailing |
| 1 | CPOL |
0 = clock idle low, 1 = idle high |
| 2 | LSB_FIRST |
Bit order — rejected with ENOTSUP (PL022 is MSB-only) |
Bits 3..7 MUST be zero. SPI modes 0..3 map to the canonical
(CPOL, CPHA) pairs.
0x02 — SET_FREQ¶
Args (5 B): [instance][freq_hz LE u32].
Reply body: [applied_hz LE u32]. Hardware lands on discrete
divisors so the applied rate is typically a bit lower than requested.
0x03 — GET_FREQ¶
Args (1 B): [instance]. Reply body: [freq_hz LE u32].
0x04 / 0x05 — CS_ASSERT / CS_RELEASE¶
Args (1 B): [cs_pin]. Claims the pin on first use
(PIN_OWNER_SPI, function PIN_FUNC_SPI_CS). Subsequent calls toggle
the level. Empty reply body; status reflects broker conflicts.
Capability advertising¶
Each instance appears in buses.spi as:
The top-level features array carries "spi.mode-0-3" so hosts can
gate behaviour without walking the bus map.
Linux userland¶
The host-side driver maps each (instance, cs_pin) pair to a
/dev/spidev<bus>.<cs> device exposed by the spidev kernel module
(see docs/driver/subsystems.md). Transfers use the standard
SPI_IOC_MESSAGE ioctl; the Rust driver translates each message
entry into a single XFER frame plus an optional tail with HOLD_CS=1
when the cs_change=0 flag is requested.