Skip to content

Communication protocols

What goes over the wire: the SPI datagram, the UART frames, and how the driver uses them to read and write registers.

You need this page to write a port, to read a logic-analyser trace or to access a register the API does not cover. The interface classes in inc/tmc51x0_comm_interface.hpp implement everything here.

SPI datagram

Each access is 40 bits, MSB first, with CSN low for the whole datagram:

Bits Host to chip Chip to host
39 W: 1 = write, 0 = read SPI_STATUS bit 7
38..32 Register address SPI_STATUS bits 6..0
31..0 Data (zero for a read) Data latched by the previous datagram

So a write of VMAX (0x27) = 0x00ABCDEF is the bytes A7 00 AB CD EF, and a read of XACTUAL (0x21) is 21 00 00 00 00. The data of a read comes back with the next datagram, so the driver sends the read twice and takes the value from the second reply. After a write it sends a read of the same address and checks the reply, which carries the value just written. Each register access therefore costs two datagrams.

SPI_STATUS

The first byte of every SPI reply:

Bit Name Meaning
7 status_stop_r Right stop switch active (RAMP_STAT[1])
6 status_stop_l Left stop switch active (RAMP_STAT[0])
5 position_reached Target position reached (RAMP_STAT[9])
4 velocity_reached Target velocity reached (RAMP_STAT[8])
3 standstill Motor at standstill (DRV_STATUS[31])
2 sg2 StallGuard2 flag (DRV_STATUS[24])
1 driver_error Driver error; clear GSTAT (GSTAT[1])
0 reset_flag The chip was reset; clear GSTAT (GSTAT[0])

tmc51x0::SpiStatus decodes it (PositionReached(), DriverError(), ...). The driver logs driver_error (rate-limited) but does not fail the access because of it: read GSTAT and DRV_STATUS to find the cause.

UART frames

Every byte is 8N1, LSB first; multi-byte data is sent high byte first. Each frame starts with the sync nibble (0x05 in the first byte) and ends with a CRC8.

Frame Bytes Layout
Write 8 05, node address, register address | 0x80, 4 data bytes, CRC
Read request 4 05, node address, register address, CRC
Read reply 8 05, FF (master address), register address, 4 data bytes, CRC

The CRC is CRC8 with polynomial x⁸ + x² + x + 1 over all preceding bytes, each byte taken LSB first, as in the datasheet's reference code. A write gets no reply; the chip counts accepted writes in IFCNT. The driver checks the CRC of every reply and returns COMM_ERROR on a mismatch.

On a single wire the MCU receives its own transmission. Your port must discard that echo, so UartReceive() returns only the chip's reply (Porting).

Register map

Range Group Examples
0x00–0x0F General configuration GCONF, GSTAT, IFCNT, NODECONF, IOIN / OUTPUT, DRV_CONF, GLOBAL_SCALER
0x10–0x15 Velocity-dependent control IHOLD_IRUN, TPOWERDOWN, TSTEP, TPWMTHRS, TCOOLTHRS, THIGH
0x20–0x2D Ramp generator RAMPMODE, XACTUAL, VACTUAL, VSTART, A1, V1, AMAX, VMAX, DMAX, D1, VSTOP, XTARGET
0x33–0x36 Ramp generator features VDCMIN, SW_MODE, RAMP_STAT, XLATCH
0x38–0x3D Encoder ENCMODE, X_ENC, ENC_CONST, ENC_STATUS, ENC_LATCH, ENC_DEVIATION
0x60–0x73 Motor driver MSLUT0..7, CHOPCONF, COOLCONF, DCCTRL, DRV_STATUS, PWMCONF, PWM_SCALE, LOST_STEPS

Most registers are write-only; the driver keeps a copy of what it wrote. GSTAT, RAMP_STAT and ENC_STATUS are cleared by writing 1 to a bit. The addresses are constants in tmc51x0::Registers and the bit fields are unions such as CHOPCONF_Register in inc/registers/.

Raw register access

auto& comm = driver.GetComm();
const uint8_t where = driver.communication.GetDaisyChainPosition();   // SPI: chain position

auto drv_status = comm.ReadRegister(tmc51x0::Registers::DRV_STATUS, where);
if (drv_status) {
  std::printf("DRV_STATUS = 0x%08lX\n", static_cast<unsigned long>(drv_status.Value()));
}
comm.WriteRegister(tmc51x0::Registers::TPOWERDOWN, 10, where);         // write-only register

GetComm() returns your port; ReadRegister() and WriteRegister() take the chip's daisy-chain position (SPI) or node address (UART) as the last argument. Writing a register behind the driver's back makes its copy stale: prefer the subsystem calls for anything they cover.

Next: TMC5130.