Skip to content

SPI protocol

The three frame formats, the CRC, and the frame sequences the driver sends for a read and a write, with what each costs on the bus.

The source is the datasheet's "SPI Transaction" section (Figures 20 to 31). The driver's side is rawReadRegister() and writeRegister() in src/as5047u.ipp.

Frame formats

Format MOSI (host to chip) MISO (chip to host) Use
16 bit [15] don't care, [14] R = 1, [13:0] address [15] warning, [14] error, [13:0] data Reads only, no CRC
24 bit [23] don't care, [22] RW, [21:8] address, [7:0] CRC [23] warning, [22] error, [21:8] data, [7:0] CRC Reads and writes
32 bit [31:24] PAD, [23] don't care, [22] RW, [21:8] address, [7:0] CRC [31] warning, [30] error, [29:16] data, [15:8] CRC, [7:0] PAD Daisy chains

RW is 1 for a read and 0 for a write. The warning and error bits report a problem in the previous command frame; the details are in ERRFL. The driver records them from every reply with a valid CRC (every 16-bit reply) as the sticky flags ReplyWarning and ReplyError. They do not fail the access: the data in the reply is still the register content, and the ERRFL read that follows every access says what the problem was.

Pick the format with the constructor or SetFrameFormat():

FrameFormat Bytes per frame Reads Writes
SPI_16 2 16-bit frames Sent as 24-bit frames, then back to 16 bit
SPI_24 3 24-bit frames 24-bit frames
SPI_32 4 32-bit frames, PAD from SetPad() 32-bit frames

The datasheet allows 16-bit frames for reads only, so the driver promotes every write in SPI_16 mode to a 24-bit frame.

CRC

Parameter Value
Width 8 bit
Polynomial 0x1D (x8 + x4 + x3 + x2 + 1)
Initial value 0xC4
Reflection None, in or out
Final XOR 0xFF
Covered bits 24-bit frames and the 32-bit command frame: bits 23:8. 32-bit reply: bits 31:16. The PAD is never covered

The initial value makes an all-zero frame invalid: 0x000000 would otherwise be a valid command. The driver computes it with AS5047U<>::ComputeCRC8(uint16_t), a constexpr function; the host tests check it against an independent implementation for all 65536 inputs.

A frame whose CRC is wrong is not executed and sets CRC_error in ERRFL. In the other direction the driver checks the CRC of every 24- and 32-bit reply whose content it uses (the data of a read, the ERRFL value, both replies of a write): a mismatch means the reply was corrupted on MISO, so the access fails, sets the ReplyCrcError sticky flag and is repeated when the call has retries left. A read that fails this way returns 0, never the corrupted value (API guide). 16-bit frames carry no CRC, so nothing protects their replies.

Read

The chip executes a command at the rising edge of CSn and returns the result during the next frame. One driver read is therefore four frames: the read command, a NOP that clocks the data out, then the same for ERRFL, so that every read also collects the error flags.

sequenceDiagram
    participant D as Driver
    participant C as AS5047U
    D->>C: read ANGLECOM (0x3FFF)
    C-->>D: (previous reply, discarded)
    D->>C: read NOP (0x0000)
    C-->>D: ANGLECOM data
    D->>C: read ERRFL (0x0001)
    C-->>D: (NOP reply, discarded)
    D->>C: read NOP (0x0000)
    C-->>D: ERRFL, cleared on the chip by this read
    Note over D: ERRFL bits are ORed into the sticky flags

Write

A write is a command frame with RW = 0 followed by a data frame with the new 14-bit value. During the data frame the chip sends the old content; during the next frame it sends the new content. The driver sends a NOP as that next frame and compares what comes back with what it wrote.

sequenceDiagram
    participant D as Driver
    participant C as AS5047U
    D->>C: write command, address n
    C-->>D: (previous reply)
    D->>C: data frame: new value
    C-->>D: old content of n
    D->>C: read NOP
    C-->>D: new content of n
    Note over D: equal: return true. Different: read ERRFL, retry or return false

On a mismatch the driver reads ERRFL, which goes into the sticky flags, and tries again up to retries times. It prints nothing: the reason for a failed write is in GetStickyErrorFlags().

What a call costs

Frames per call, from the sequences above. Times are derived for 24-bit frames at 10 MHz (2.4 µs of clock per frame, plus at least 350 ns of CSn high between frames and your port's own overhead); they are not measurements.

Call Frames Clock time at 10 MHz
GetAngle(), GetVelocity(), GetAGC(), ReadReg<>() 4 9.6 µs (6.4 µs with SPI_16)
GetZeroPosition() 8 19.2 µs
WriteReg() 3 7.2 µs
SetDirection(), SetABIResolution() and other one-field setters 7 (read, then write) 16.8 µs
ConfigureInterface() 14 33.6 µs

A failed write verification adds four frames for ERRFL and repeats the write. A rejected reply (wrong CRC) ends the access at that frame; a retry starts it again.

Daisy chains and the PAD byte

In a 32-bit frame the PAD byte leads the MOSI frame and trails the MISO frame. The datasheet allows any number of PAD bits before the MOSI data so that the host can tell which device's reply it is reading. The driver sends one PAD byte, the value set with SetPad(), at the start of every 32-bit frame; it does not interpret the PAD on MISO.