Porting¶
Run the driver on a new MCU by writing one class with one method: the SPI transfer.
The driver never calls your SDK directly. It calls transfer() on a class you derive from
as5047u::SpiInterface<Self> (in inc/as5047u_spi_interface.hpp). The base
class uses CRTP: the call is resolved at compile time, so there are no virtual functions, no vtable and nothing to
allocate.
Figure description and sources
From top to bottom. Your application talks to one AS5047U
Drawn from: inc/as5047u_registers.hpp register structs; inc/as5047u_spi_interface.hpp SpiInterface; figure module docs/diagrams/figures/driver-layers.py.
What you implement¶
| Method | Contract |
|---|---|
bool transfer(const uint8_t* tx, uint8_t* rx, std::size_t len) |
Pull CSn low, clock out len bytes from tx while storing len bytes into rx, release CSn. Return true when the frame went out, false on a bus error. len is 2, 3 or 4. The driver always passes both buffers |
The driver builds every byte of every frame, including the CRC and the PAD; your port only moves bytes.
The port¶
class MySpi : public as5047u::SpiInterface<MySpi> {
public:
// One frame of 2, 3 or 4 bytes, full duplex, CSn low for the whole frame.
// SPI mode 1 (CPOL = 0, CPHA = 1), MSB first, up to 10 MHz.
// Return false on a bus error: the driver call that sent the frame then fails.
bool transfer(const uint8_t* tx, uint8_t* rx, std::size_t len) {
platform_cs_low();
const bool ok = platform_spi_exchange(tx, rx, len);
platform_cs_high(); // the chip executes the frame here; >= 350 ns high
return ok;
}
};
Rules the transfer must follow:
- SPI mode 1 (CPOL = 0, CPHA = 1), MSB first, up to 10 MHz. The clock idles low and the chip samples MOSI on the falling edge; modes 0, 2 and 3 do not work.
- One frame per call. CSn goes low before the first byte and high after the last. The chip executes the frame on the rising edge of CSn, so never merge two calls into one chip-select period, and never split one.
- CSn timing. At least 350 ns from CSn low to the first clock edge, and at least 350 ns of CSn high between frames (Hardware).
- Blocking. Return only when the frame is complete and
rxis filled. The driver uses the reply of one call to build the next.
Bus errors¶
Return false from transfer() when your SDK reports a failure. The driver stops the access that sent the frame:
the setters, WriteReg() and ProgramOTP() return false, ReadReg(reg) returns false, and every failed
frame sets AS5047U_Error::BusError in the sticky flags, which is how the measurement getters (they return a
value, 0 for a failed read) report it. A read-modify-write setter whose read fails writes nothing. Calls with a
retries argument repeat a failed access.
Return a bool, not your SDK's status code: the driver rejects any other return type at compile time, so an
esp_err_t (where 0 is success) cannot be read as false. A port written for the earlier contract, with a void
transfer(), still compiles; the driver treats it as never failing.
Reference implementation¶
The ESP32 examples use esp32_as5047u_bus.hpp: an ESP-IDF
spi_master device in mode 1 with hardware chip select (spics_io_num), one spi_device_transmit() per frame,
and optional logging of every frame. Start from it for any ESP-IDF target.
Check your port¶
- Build it: the port on this page is compiled by the host CI from
tests/docs/, with the driver instantiated over it (template class as5047u::AS5047U<MySpi>;). - Read DIA with
GetDiagnostics():LoopsFinished= 1 and a plausibleVDD_modeprove that reads work. - Read ERRFL with
GetErrorFlags()twice: the second read should be 0. A persistentFraming_errororCRC_errorpoints at the mode, CSn handling or the frame length. - Write a setting and read it back:
SetDirection(false)must returntrue, andReadReg<AS5047U_REG::SETTINGS2>()must showDIR= 1. - On a logic analyzer, the read of ANGLECOM in
SPI_24mode is7F FF BD(0xBDis the CRC of0x7FFF), followed by the NOP40 00 1B.
Threads¶
The driver is not thread-safe. Give each sensor one owner task, or guard every call on a driver object (and its port) with one mutex. Several sensors on separate chip selects can share a bus only if the bus driver serializes whole frames.