HF-TMC9660 Driver
Hardware Agnostic C++ Driver for the TMC9660
Loading...
Searching...
No Matches
TMC9660CommInterface.hpp
Go to the documentation of this file.
1
34#pragma once
35#include <array>
36#include <cstdint>
37#include <cstdlib>
38#include <span>
39
41enum class CommMode { SPI, UART };
42
44enum class SPIStatus : uint8_t {
45 OK = 0xFF,
46 CHECKSUM_ERROR = 0x00,
47 FIRST_CMD = 0x0C,
48 NOT_READY = 0xF0,
49};
50
52static constexpr uint8_t tmclChecksum(const uint8_t *bytes, size_t n) noexcept {
53 uint8_t sum = 0;
54 for (size_t i = 0; i < n; ++i)
55 sum += bytes[i];
56 return sum;
57}
58
59// -----------------------------------------------------------------------
60// TMCL scripting support structures and enums
61// -----------------------------------------------------------------------
62
64struct TMCLReply {
66 uint8_t status = 0;
67 uint8_t opcode = 0;
68 uint32_t value = 0;
69
70 [[nodiscard]] bool isOK() const noexcept {
71 return spiStatus == SPIStatus::OK && (status == 100 || status == 101);
72 }
73
75 static bool fromSpi(std::span<const uint8_t, 8> in, TMCLReply &r) noexcept {
76 if (tmclChecksum(in.data(), 7) != in[7])
77 return false;
78 r.spiStatus = static_cast<SPIStatus>(in[0]);
79 if (r.spiStatus == SPIStatus::NOT_READY || r.spiStatus == SPIStatus::CHECKSUM_ERROR)
80 return false;
81 r.status = in[1];
82 r.opcode = in[2];
83 r.value = (static_cast<uint32_t>(in[3]) << 24) | (static_cast<uint32_t>(in[4]) << 16) |
84 (static_cast<uint32_t>(in[5]) << 8) | static_cast<uint32_t>(in[6]);
85 return true;
86 }
87
89 static bool fromUart(std::span<const uint8_t, 9> in, uint8_t addr, TMCLReply &r) noexcept {
90 // byte0 : host address (ignored)
91 // byte1 : sync bit + module address (7-bit)
92 if ((in[1] & 0x7F) != (addr & 0x7F))
93 return false;
94 if (tmclChecksum(in.data(), 8) != in[8])
95 return false; // checksum over first 8 bytes
96 r.spiStatus = SPIStatus::OK; // UART has no SPI status field
97 r.status = in[2];
98 r.opcode = in[3];
99 r.value = (static_cast<uint32_t>(in[4]) << 24) | (static_cast<uint32_t>(in[5]) << 16) |
100 (static_cast<uint32_t>(in[6]) << 8) | static_cast<uint32_t>(in[7]);
101 return true;
102 }
103};
104
110struct TMCLFrame {
111 uint8_t opcode = 0;
112 uint16_t type = 0;
113 uint8_t motor = 0;
114 uint32_t value = 0;
115
120 void toSpi(std::span<uint8_t, 8> out) const noexcept {
121 out[0] = opcode;
122 out[1] = static_cast<uint8_t>(type >> 4);
123 out[2] = static_cast<uint8_t>((type << 4) | (motor & 0x0F));
124 out[3] = static_cast<uint8_t>(value >> 24);
125 out[4] = static_cast<uint8_t>(value >> 16);
126 out[5] = static_cast<uint8_t>(value >> 8);
127 out[6] = static_cast<uint8_t>(value);
128 out[7] = tmclChecksum(out.data(), 7);
129 }
130
136 void toUart(uint8_t addr, std::span<uint8_t, 9> out) const noexcept {
137 out[0] = addr | 0x80; // sync bit set
138 out[1] = opcode;
139 out[2] = static_cast<uint8_t>(type >> 4);
140 out[3] = static_cast<uint8_t>((type << 4) | (motor & 0x0F));
141 out[4] = static_cast<uint8_t>(value >> 24);
142 out[5] = static_cast<uint8_t>(value >> 16);
143 out[6] = static_cast<uint8_t>(value >> 8);
144 out[7] = static_cast<uint8_t>(value);
145 out[8] = tmclChecksum(out.data(), 8);
146 }
147
153 static TMCLFrame fromSpi(std::span<const uint8_t, 8> in) noexcept {
154 TMCLFrame f;
155 f.opcode = in[0];
156 f.type = static_cast<uint16_t>(in[1]) << 4 | (in[2] >> 4);
157 f.motor = in[2] & 0x0F;
158 f.value = (static_cast<uint32_t>(in[3]) << 24) | (static_cast<uint32_t>(in[4]) << 16) |
159 (static_cast<uint32_t>(in[5]) << 8) | static_cast<uint32_t>(in[6]);
160 return f;
161 }
162
169 static bool fromSpiChecked(std::span<const uint8_t, 8> in, TMCLFrame &outFrame) noexcept {
170 TMCLReply reply{};
171 if (!TMCLReply::fromSpi(in, reply))
172 return false;
173 outFrame.opcode = reply.opcode;
174 outFrame.value = reply.value;
175 return true;
176 }
177
185 static bool fromUart(std::span<const uint8_t, 9> in, uint8_t expectedAddr,
186 TMCLFrame &outFrame) noexcept {
187 TMCLReply rep{};
188 if (!TMCLReply::fromUart(in, expectedAddr, rep))
189 return false;
190 outFrame.opcode = rep.opcode;
191 outFrame.value = rep.value;
192 return true;
193 }
194
201 static constexpr uint8_t calculateChecksum(const uint8_t *bytes, size_t n) noexcept {
202 uint8_t sum = 0;
203 for (size_t i = 0; i < n; ++i)
204 sum += bytes[i];
205 return sum;
206 }
207};
208
225public:
226 virtual ~TMC9660CommInterface() noexcept = default;
227
229 virtual CommMode mode() const noexcept = 0;
230
238 virtual bool transfer(const TMCLFrame &tx, TMCLReply &reply, uint8_t address) noexcept = 0;
239};
240
249public:
250 CommMode mode() const noexcept override {
251 return CommMode::SPI;
252 }
259 virtual bool spiTransfer(std::array<uint8_t, 8> &tx, std::array<uint8_t, 8> &rx) noexcept = 0;
260
261 bool transfer(const TMCLFrame &tx, TMCLReply &reply, uint8_t) noexcept override {
262 std::array<uint8_t, 8> txBuf, rxBuf;
263 tx.toSpi(txBuf);
264 if (!spiTransfer(txBuf, rxBuf))
265 return false;
266 return TMCLReply::fromSpi(rxBuf, reply);
267 }
268};
269
278public:
279 CommMode mode() const noexcept override {
280 return CommMode::UART;
281 }
287 virtual bool sendUartDatagram(const std::array<uint8_t, 9> &data) noexcept = 0;
288
294 virtual bool receiveUartDatagram(std::array<uint8_t, 9> &data) noexcept = 0;
295
296 bool transfer(const TMCLFrame &tx, TMCLReply &reply, uint8_t address) noexcept override {
297 std::array<uint8_t, 9> frame;
298 tx.toUart(address, frame);
299 if (!sendUartDatagram(frame))
300 return false;
301 if (!receiveUartDatagram(frame))
302 return false;
303 return TMCLReply::fromUart(frame, address, reply);
304 }
305};
CommMode
Supported physical communication modes.
Definition TMC9660CommInterface.hpp:41
SPIStatus
SPI status codes as per TMC9660 Parameter Mode.
Definition TMC9660CommInterface.hpp:44
static constexpr uint8_t tmclChecksum(const uint8_t *bytes, size_t n) noexcept
Calculate 8-bit checksum (sum of bytes)
Definition TMC9660CommInterface.hpp:52
SPI implementation of TMC9660CommInterface.
Definition TMC9660CommInterface.hpp:248
bool transfer(const TMCLFrame &tx, TMCLReply &reply, uint8_t) noexcept override
Perform a full duplex TMCL transfer.
Definition TMC9660CommInterface.hpp:261
CommMode mode() const noexcept override
Return underlying communication mode.
Definition TMC9660CommInterface.hpp:250
virtual bool spiTransfer(std::array< uint8_t, 8 > &tx, std::array< uint8_t, 8 > &rx) noexcept=0
Low-level SPI transfer of 8 bytes.
SPI status codes as per TMC9660 Parameter Mode.
Definition TMC9660CommInterface.hpp:224
virtual CommMode mode() const noexcept=0
Return underlying communication mode.
virtual ~TMC9660CommInterface() noexcept=default
virtual bool transfer(const TMCLFrame &tx, TMCLReply &reply, uint8_t address) noexcept=0
Perform a full duplex TMCL transfer.
UART implementation of TMC9660CommInterface.
Definition TMC9660CommInterface.hpp:277
virtual bool receiveUartDatagram(std::array< uint8_t, 9 > &data) noexcept=0
Receive raw 9-byte UART TMCL datagram.
bool transfer(const TMCLFrame &tx, TMCLReply &reply, uint8_t address) noexcept override
Perform a full duplex TMCL transfer.
Definition TMC9660CommInterface.hpp:296
CommMode mode() const noexcept override
Return underlying communication mode.
Definition TMC9660CommInterface.hpp:279
virtual bool sendUartDatagram(const std::array< uint8_t, 9 > &data) noexcept=0
Send raw 9-byte UART TMCL datagram.
Frame structure for TMCL commands and replies.
Definition TMC9660CommInterface.hpp:110
void toUart(uint8_t addr, std::span< uint8_t, 9 > out) const noexcept
Serialize frame into 9-byte UART buffer, including sync bit and checksum.
Definition TMC9660CommInterface.hpp:136
uint16_t type
Parameter or command type (BYTE 1-2, bits 8-19).
Definition TMC9660CommInterface.hpp:112
void toSpi(std::span< uint8_t, 8 > out) const noexcept
Serialize frame into 8-byte SPI buffer.
Definition TMC9660CommInterface.hpp:120
static TMCLFrame fromSpi(std::span< const uint8_t, 8 > in) noexcept
Deserialize an SPI buffer into a TMCLFrame without status check.
Definition TMC9660CommInterface.hpp:153
uint8_t opcode
Operation code field (BYTE 0, bits 0-7).
Definition TMC9660CommInterface.hpp:111
uint32_t value
32-bit data value (BYTE 4-7, bits 24-55).
Definition TMC9660CommInterface.hpp:114
static constexpr uint8_t calculateChecksum(const uint8_t *bytes, size_t n) noexcept
Calculate 8-bit checksum (sum of bytes).
Definition TMC9660CommInterface.hpp:201
static bool fromSpiChecked(std::span< const uint8_t, 8 > in, TMCLFrame &outFrame) noexcept
Deserialize an SPI buffer with status and checksum validation.
Definition TMC9660CommInterface.hpp:169
static bool fromUart(std::span< const uint8_t, 9 > in, uint8_t expectedAddr, TMCLFrame &outFrame) noexcept
Deserialize a UART buffer with address and checksum validation.
Definition TMC9660CommInterface.hpp:185
uint8_t motor
Motor or bank identifier (BYTE 3, bits 20-23).
Definition TMC9660CommInterface.hpp:113
Reply structure returned by sendCommand()
Definition TMC9660CommInterface.hpp:64
SPIStatus spiStatus
SPI status byte.
Definition TMC9660CommInterface.hpp:65
uint8_t opcode
Echoed operation code.
Definition TMC9660CommInterface.hpp:67
uint32_t value
Optional returned value.
Definition TMC9660CommInterface.hpp:68
uint8_t status
TMCL status code (100=OK, 101=LOADED)
Definition TMC9660CommInterface.hpp:66
bool isOK() const noexcept
Definition TMC9660CommInterface.hpp:70
static bool fromSpi(std::span< const uint8_t, 8 > in, TMCLReply &r) noexcept
Decode reply from SPI datagram.
Definition TMC9660CommInterface.hpp:75
static bool fromUart(std::span< const uint8_t, 9 > in, uint8_t addr, TMCLReply &r) noexcept
Decode reply from UART datagram.
Definition TMC9660CommInterface.hpp:89