HF-Core Platform 0.1.0-dev
Hardware-Agnostic Handler Layer & RTOS Utilities for HardFOC
Loading...
Searching...
No Matches
Tmc9660Handler.h
Go to the documentation of this file.
1
86#ifndef COMPONENT_HANDLER_TMC9660_HANDLER_H_
87#define COMPONENT_HANDLER_TMC9660_HANDLER_H_
88
89#include <cstdint>
90#include <memory>
91#include <array>
92#include <atomic>
93#include <type_traits>
94#include <variant>
95#include "core/hf-core-drivers/external/hf-tmc9660-driver/inc/tmc9660.hpp"
96#include "core/hf-core-drivers/external/hf-tmc9660-driver/inc/tmc9660_comm_interface.hpp"
97#include "base/BaseGpio.h"
98#include "base/BaseAdc.h"
99#include "base/BaseTemperature.h"
100#include "base/BaseSpi.h"
101#include "base/BaseUart.h"
102#include "RtosMutex.h"
103#include <utility> // for std::as_const
104
110
124 BaseGpio& rst;
125 BaseGpio& drv_en;
126 BaseGpio& faultn;
127 BaseGpio& wake;
128
130 BaseGpio& get(tmc9660::TMC9660CtrlPin pin) noexcept {
131 switch (pin) {
132 case tmc9660::TMC9660CtrlPin::RST: return rst;
133 case tmc9660::TMC9660CtrlPin::DRV_EN: return drv_en;
134 case tmc9660::TMC9660CtrlPin::FAULTN: return faultn;
135 case tmc9660::TMC9660CtrlPin::WAKE: return wake;
136 default: return rst;
137 }
138 }
139
141 const BaseGpio& get(tmc9660::TMC9660CtrlPin pin) const noexcept {
142 switch (pin) {
143 case tmc9660::TMC9660CtrlPin::RST: return rst;
144 case tmc9660::TMC9660CtrlPin::DRV_EN: return drv_en;
145 case tmc9660::TMC9660CtrlPin::FAULTN: return faultn;
146 case tmc9660::TMC9660CtrlPin::WAKE: return wake;
147 default: return rst;
148 }
149 }
150};
151
183class HalSpiTmc9660Comm : public tmc9660::SpiCommInterface<HalSpiTmc9660Comm> {
184public:
205 HalSpiTmc9660Comm(BaseSpi& spi, BaseGpio& rst, BaseGpio& drv_en,
206 BaseGpio& faultn, BaseGpio& wake,
207 bool rst_active_high = true, bool drv_en_active_high = true,
208 bool faultn_active_low = false, bool wake_active_low = false) noexcept;
209
213
220 bool spiTransferTMCL(std::array<uint8_t, 8>& tx, std::array<uint8_t, 8>& rx) noexcept;
221
228 bool spiTransferBootloader(std::array<uint8_t, 5>& tx, std::array<uint8_t, 5>& rx) noexcept;
229
240 bool gpioSet(tmc9660::TMC9660CtrlPin pin, tmc9660::GpioSignal signal) noexcept;
241
252 bool gpioRead(tmc9660::TMC9660CtrlPin pin, tmc9660::GpioSignal& signal) noexcept;
253
261 void debugLog(int level, const char* tag, const char* format, va_list args) noexcept;
262
267 void delayMs(uint32_t ms) noexcept;
268
277 void delayUs(uint32_t us) noexcept;
278
280
281private:
282 BaseSpi& spi_;
284};
285
305class HalUartTmc9660Comm : public tmc9660::UartCommInterface<HalUartTmc9660Comm> {
306public:
320 HalUartTmc9660Comm(BaseUart& uart, BaseGpio& rst, BaseGpio& drv_en,
321 BaseGpio& faultn, BaseGpio& wake,
322 bool rst_active_high = true, bool drv_en_active_high = true,
323 bool faultn_active_low = false, bool wake_active_low = false) noexcept;
324
327
333 bool uartSendTMCL(const std::array<uint8_t, 9>& data) noexcept;
334
340 bool uartReceiveTMCL(std::array<uint8_t, 9>& data) noexcept;
341
348 bool uartTransferBootloader(const std::array<uint8_t, 8>& tx,
349 std::array<uint8_t, 8>& rx) noexcept;
350
352 bool gpioSet(tmc9660::TMC9660CtrlPin pin, tmc9660::GpioSignal signal) noexcept;
353
355 bool gpioRead(tmc9660::TMC9660CtrlPin pin, tmc9660::GpioSignal& signal) noexcept;
356
358 void debugLog(int level, const char* tag, const char* format, va_list args) noexcept;
359
361 void delayMs(uint32_t ms) noexcept;
362
364 void delayUs(uint32_t us) noexcept;
365
367
368private:
369 BaseUart& uart_;
371};
372
374
380
453public:
454 //==========================================================================
457 //==========================================================================
458
460 using SpiDriver = tmc9660::TMC9660<HalSpiTmc9660Comm>;
461
463 using UartDriver = tmc9660::TMC9660<HalUartTmc9660Comm>;
464
466 using DriverVariant = std::variant<std::monostate, SpiDriver*, UartDriver*>;
467
469 using ConstDriverVariant = std::variant<std::monostate, const SpiDriver*, const UartDriver*>;
470
472
473 //==========================================================================
476 //==========================================================================
477
492 static const tmc9660::BootloaderConfig kDefaultBootConfig;
493
495
496 //==========================================================================
499 //==========================================================================
500
521 Tmc9660Handler(BaseSpi& spi, BaseGpio& rst, BaseGpio& drv_en,
522 BaseGpio& faultn, BaseGpio& wake,
523 uint8_t address = 0,
524 const tmc9660::BootloaderConfig* bootCfg = &kDefaultBootConfig);
525
539 Tmc9660Handler(BaseUart& uart, BaseGpio& rst, BaseGpio& drv_en,
540 BaseGpio& faultn, BaseGpio& wake,
541 uint8_t address = 0,
542 const tmc9660::BootloaderConfig* bootCfg = &kDefaultBootConfig);
543
548
553
558
560
561 //==========================================================================
564 //==========================================================================
565
594 bool failOnVerifyError = false);
595
601
609
611
612 //==========================================================================
616 //==========================================================================
617
634 class Gpio : public BaseGpio {
635 public:
642
645
648
651
653 bool Deinitialize() noexcept override;
654
656 bool IsPinAvailable() const noexcept override;
657
659 hf_u8_t GetMaxPins() const noexcept override;
660
663
665
666 protected:
669
672
675
678
680 hf_gpio_err_t SetPinLevelImpl(hf_gpio_level_t level) noexcept override;
681
683 hf_gpio_err_t GetPinLevelImpl(hf_gpio_level_t& level) noexcept override;
684
686 hf_gpio_pull_mode_t GetPullModeImpl() const noexcept override;
687
690
693
695
696 private:
697 Tmc9660Handler& parent_;
698 uint8_t gpioNumber_;
699 char description_[32];
701 };
702
729 class Adc : public BaseAdc {
730 public:
736
739
742
745
747 bool Deinitialize() noexcept override;
748
760 hf_u8_t GetMaxChannels() const noexcept override;
761
767 bool IsChannelAvailable(hf_channel_id_t channel_id) const noexcept override;
768
780
792
805
816
819
822
824 hf_adc_err_t ResetStatistics() noexcept override;
825
827 hf_adc_err_t ResetDiagnostics() noexcept override;
828
830
834
843
851 hf_adc_err_t ReadCurrentSenseChannel(uint8_t current_channel, hf_u32_t& raw_value, float& voltage) noexcept;
852
861
869 hf_adc_err_t ReadTemperatureChannel(uint8_t temp_channel, hf_u32_t& raw_value, float& voltage) noexcept;
870
878 hf_adc_err_t ReadMotorDataChannel(uint8_t motor_channel, hf_u32_t& raw_value, float& voltage) noexcept;
879
881
882 private:
883 Tmc9660Handler& parent_;
887 std::atomic<hf_adc_err_t> last_error_;
888
891
904 hf_adc_err_t ReadChannelLocked(hf_channel_id_t channel_id,
905 hf_u32_t& raw, float& voltage) noexcept;
906
909
911 uint64_t GetCurrentTimeUs() const noexcept;
912
914 void UpdateDiagnostics(hf_adc_err_t error) noexcept;
915
917 const char* GetChannelTypeString(hf_channel_id_t channel_id) const noexcept;
918 };
919
938 class Temperature : public BaseTemperature {
939 public:
945
948
951
954
956 bool Deinitialize() noexcept override;
957
963 hf_temp_err_t ReadTemperatureCelsiusImpl(float* temperature_celsius) noexcept override;
964
971
976 hf_u32_t GetCapabilities() const noexcept override;
977
979
980 private:
981 Tmc9660Handler& parent_;
985 std::atomic<hf_temp_err_t> last_error_;
986
989
991 uint64_t GetCurrentTimeUs() const noexcept;
992
994 void UpdateDiagnostics(hf_temp_err_t error) noexcept;
995 };
996
998
999 //==========================================================================
1003 //==========================================================================
1004
1016
1022 Adc& adc();
1023
1030
1032
1033 //==========================================================================
1036 //==========================================================================
1037
1043
1049
1051
1052 //==========================================================================
1055 //==========================================================================
1056
1067
1073
1075
1076 //==========================================================================
1080 //==========================================================================
1081
1110
1113
1128
1131
1137 if (auto* spi = driverViaSpi()) {
1138 return spi;
1139 }
1140 if (auto* uart = driverViaUart()) {
1141 return uart;
1142 }
1143 return std::monostate{};
1144 }
1145
1148 if (auto* spi = driverViaSpi()) {
1149 return spi;
1150 }
1151 if (auto* uart = driverViaUart()) {
1152 return uart;
1153 }
1154 return std::monostate{};
1155 }
1156
1158
1159 //==========================================================================
1163 //==========================================================================
1164
1179 template <typename Func>
1180 auto visitDriver(Func&& func) noexcept {
1181 using ReturnType = decltype(func(*spi_driver_));
1183 if (!EnsureInitializedLocked()) {
1184 if constexpr (std::is_void_v<ReturnType>) {
1185 return;
1186 } else {
1187 return ReturnType{};
1188 }
1189 }
1190 if (use_spi_) {
1191 if (spi_driver_) return func(*spi_driver_);
1192 } else {
1193 if (uart_driver_) return func(*uart_driver_);
1194 }
1195 if constexpr (std::is_void_v<ReturnType>) {
1196 return;
1197 } else {
1198 return ReturnType{};
1199 }
1200 }
1201
1203 template <typename Func>
1204 auto visitDriver(Func&& func) const noexcept {
1205 using ReturnType = decltype(func(std::as_const(*spi_driver_)));
1207 auto* self = const_cast<Tmc9660Handler*>(this);
1208 if (!self->EnsureInitializedLocked()) {
1209 if constexpr (std::is_void_v<ReturnType>) {
1210 return;
1211 } else {
1212 return ReturnType{};
1213 }
1214 }
1215 if (use_spi_) {
1216 if (spi_driver_) return func(std::as_const(*spi_driver_));
1217 } else {
1218 if (uart_driver_) return func(std::as_const(*uart_driver_));
1219 }
1220 if constexpr (std::is_void_v<ReturnType>) {
1221 return;
1222 } else {
1223 return ReturnType{};
1224 }
1225 }
1226
1228
1229private:
1230 //==========================================================================
1231 // Private Helpers
1232 //==========================================================================
1233
1236
1240 using ReturnType = decltype(func(*spi_driver_));
1241 if (use_spi_) {
1242 if (spi_driver_) return func(*spi_driver_);
1243 } else {
1244 if (uart_driver_) return func(*uart_driver_);
1245 }
1246 if constexpr (std::is_void_v<ReturnType>) {
1247 return;
1248 } else {
1249 return ReturnType{};
1250 }
1251 }
1252
1253 //==========================================================================
1254 // Private Members
1255 //==========================================================================
1256
1258
1262 std::unique_ptr<HalSpiTmc9660Comm> spi_comm_;
1263 std::unique_ptr<HalUartTmc9660Comm> uart_comm_;
1265
1269 std::unique_ptr<SpiDriver> spi_driver_;
1270 std::unique_ptr<UartDriver> uart_driver_;
1272
1276 std::array<std::unique_ptr<Gpio>, 2> gpioWrappers_;
1277 std::unique_ptr<Adc> adcWrapper_;
1278 std::unique_ptr<Temperature> temperatureWrapper_;
1280
1283 const tmc9660::BootloaderConfig* bootCfg_;
1286
1291
1292 char description_[64]{};
1293};
1294
1296
1297#endif // COMPONENT_HANDLER_TMC9660_HANDLER_H_
Concrete SPI communication adapter for TMC9660 using BaseSpi and BaseGpio.
Definition Tmc9660Handler.h:183
void delayMs(uint32_t ms) noexcept
Delay execution for the specified number of milliseconds.
Definition Tmc9660Handler.cpp:198
Tmc9660CtrlPins ctrl_pins_
Host-side control pin references.
Definition Tmc9660Handler.h:283
bool spiTransferBootloader(std::array< uint8_t, 5 > &tx, std::array< uint8_t, 5 > &rx) noexcept
Perform a 5-byte full-duplex SPI transfer for bootloader mode.
Definition Tmc9660Handler.cpp:176
BaseSpi & spi_
SPI bus interface (not owned).
Definition Tmc9660Handler.h:282
bool spiTransferTMCL(std::array< uint8_t, 8 > &tx, std::array< uint8_t, 8 > &rx) noexcept
Perform an 8-byte full-duplex SPI transfer for TMCL parameter mode.
Definition Tmc9660Handler.cpp:168
bool gpioRead(tmc9660::TMC9660CtrlPin pin, tmc9660::GpioSignal &signal) noexcept
Read a TMC9660 control pin's current logical signal state.
Definition Tmc9660Handler.cpp:189
void debugLog(int level, const char *tag, const char *format, va_list args) noexcept
Route TMC9660 driver debug output to the HardFOC Logger.
Definition Tmc9660Handler.cpp:194
bool gpioSet(tmc9660::TMC9660CtrlPin pin, tmc9660::GpioSignal signal) noexcept
Set a TMC9660 control pin to a given logical signal state.
Definition Tmc9660Handler.cpp:184
void delayUs(uint32_t us) noexcept
Delay execution for the specified number of microseconds.
Definition Tmc9660Handler.cpp:199
HalSpiTmc9660Comm(BaseSpi &spi, BaseGpio &rst, BaseGpio &drv_en, BaseGpio &faultn, BaseGpio &wake, bool rst_active_high=true, bool drv_en_active_high=true, bool faultn_active_low=false, bool wake_active_low=false) noexcept
Construct the SPI communication adapter.
Definition Tmc9660Handler.cpp:159
Concrete UART communication adapter for TMC9660 using BaseUart and BaseGpio.
Definition Tmc9660Handler.h:305
void delayUs(uint32_t us) noexcept
Delay execution for the specified number of microseconds.
Definition Tmc9660Handler.cpp:258
bool uartTransferBootloader(const std::array< uint8_t, 8 > &tx, std::array< uint8_t, 8 > &rx) noexcept
Perform an 8-byte UART bootloader transfer (send + receive).
Definition Tmc9660Handler.cpp:230
bool uartReceiveTMCL(std::array< uint8_t, 9 > &data) noexcept
Receive a 9-byte TMCL reply datagram over UART.
Definition Tmc9660Handler.cpp:222
HalUartTmc9660Comm(BaseUart &uart, BaseGpio &rst, BaseGpio &drv_en, BaseGpio &faultn, BaseGpio &wake, bool rst_active_high=true, bool drv_en_active_high=true, bool faultn_active_low=false, bool wake_active_low=false) noexcept
Construct the UART communication adapter.
Definition Tmc9660Handler.cpp:205
void debugLog(int level, const char *tag, const char *format, va_list args) noexcept
Route TMC9660 driver debug output to the HardFOC Logger.
Definition Tmc9660Handler.cpp:253
bool uartSendTMCL(const std::array< uint8_t, 9 > &data) noexcept
Send a 9-byte TMCL datagram over UART.
Definition Tmc9660Handler.cpp:214
Tmc9660CtrlPins ctrl_pins_
Host-side control pin references.
Definition Tmc9660Handler.h:370
bool gpioSet(tmc9660::TMC9660CtrlPin pin, tmc9660::GpioSignal signal) noexcept
Set a TMC9660 control pin to a given logical signal state.
Definition Tmc9660Handler.cpp:243
void delayMs(uint32_t ms) noexcept
Delay execution for the specified number of milliseconds.
Definition Tmc9660Handler.cpp:257
BaseUart & uart_
UART bus interface (not owned).
Definition Tmc9660Handler.h:369
bool gpioRead(tmc9660::TMC9660CtrlPin pin, tmc9660::GpioSignal &signal) noexcept
Read a TMC9660 control pin's current logical signal state.
Definition Tmc9660Handler.cpp:248
BaseAdc adapter for all TMC9660 ADC channels.
Definition Tmc9660Handler.h:729
~Adc() noexcept override=default
Default destructor.
BaseGpio adapter for a single TMC9660 internal GPIO channel.
Definition Tmc9660Handler.h:634
~Gpio() noexcept override=default
Default destructor.
BaseTemperature adapter for the TMC9660 internal chip temperature sensor.
Definition Tmc9660Handler.h:938
~Temperature() noexcept override=default
Default destructor.
Unified, non-templated handler for a single TMC9660 motor controller device.
Definition Tmc9660Handler.h:452
bool use_spi_
true = SPI communication active, false = UART.
Definition Tmc9660Handler.h:1257
std::variant< std::monostate, SpiDriver *, UartDriver * > DriverVariant
Non-owning variant holding either driver type or empty (monostate).
Definition Tmc9660Handler.h:466
auto visitDriverInternal(Func &&func) noexcept
Internal no-lock visitDriver for use from already-locked contexts.
Definition Tmc9660Handler.h:1239
std::unique_ptr< UartDriver > uart_driver_
TMC9660 driver for UART mode (or nullptr).
Definition Tmc9660Handler.h:1270
std::variant< std::monostate, const SpiDriver *, const UartDriver * > ConstDriverVariant
Const version of DriverVariant.
Definition Tmc9660Handler.h:469
bool IsDriverReady() const noexcept
Check if the TMC9660 driver has been initialized and is ready.
Definition Tmc9660Handler.cpp:374
uint8_t device_address_
7-bit TMCL device address.
Definition Tmc9660Handler.h:1284
const tmc9660::BootloaderConfig * bootCfg_
Bootloader config (not owned; must outlive handler).
Definition Tmc9660Handler.h:1283
const tmc9660::BootloaderConfig & bootConfig() const noexcept
Get the bootloader configuration in use.
Definition Tmc9660Handler.h:1048
std::unique_ptr< SpiDriver > spi_driver_
TMC9660 driver for SPI mode (or nullptr).
Definition Tmc9660Handler.h:1269
Tmc9660Handler(BaseSpi &spi, BaseGpio &rst, BaseGpio &drv_en, BaseGpio &faultn, BaseGpio &wake, uint8_t address=0, const tmc9660::BootloaderConfig *bootCfg=&kDefaultBootConfig)
Construct a handler for a TMC9660 connected via SPI.
Definition Tmc9660Handler.cpp:264
Temperature & temperature()
Get a reference to the Temperature wrapper.
Definition Tmc9660Handler.cpp:395
std::unique_ptr< HalUartTmc9660Comm > uart_comm_
UART communication adapter (or nullptr).
Definition Tmc9660Handler.h:1263
static const tmc9660::BootloaderConfig kDefaultBootConfig
Default bootloader configuration based on TMC9660-3PH-EVAL board settings.
Definition Tmc9660Handler.h:27
auto visitDriver(Func &&func) noexcept
Execute a function on the underlying typed TMC9660 driver.
Definition Tmc9660Handler.h:1180
bool EnsureInitialized() noexcept
Ensure driver is initialized (lazy init entrypoint).
Definition Tmc9660Handler.cpp:362
tmc9660::TMC9660< HalSpiTmc9660Comm > SpiDriver
TMC9660 driver instantiated with SPI communication.
Definition Tmc9660Handler.h:460
tmc9660::TMC9660< HalUartTmc9660Comm > UartDriver
TMC9660 driver instantiated with UART communication.
Definition Tmc9660Handler.h:463
std::unique_ptr< Temperature > temperatureWrapper_
Chip temperature wrapper.
Definition Tmc9660Handler.h:1278
bool EnsureInitializedLocked() noexcept
Ensure initialized while handler_mutex_ is already held.
Definition Tmc9660Handler.cpp:367
Adc & adc()
Get a reference to the ADC wrapper.
Definition Tmc9660Handler.cpp:390
SpiDriver * driverViaSpi() noexcept
Get the TMC9660 driver instance connected via SPI (nullptr if using UART).
Definition Tmc9660Handler.cpp:408
std::array< std::unique_ptr< Gpio >, 2 > gpioWrappers_
GPIO17 [0] and GPIO18 [1].
Definition Tmc9660Handler.h:1276
auto visitDriver(Func &&func) const noexcept
Const overload of visitDriver().
Definition Tmc9660Handler.h:1204
RtosMutex handler_mutex_
Recursive mutex for thread-safe access.
Definition Tmc9660Handler.h:1289
std::unique_ptr< Adc > adcWrapper_
Multi-channel ADC wrapper.
Definition Tmc9660Handler.h:1277
const char * GetDescription() const noexcept
Get a human-readable description of the handler.
Definition Tmc9660Handler.cpp:983
std::unique_ptr< HalSpiTmc9660Comm > spi_comm_
SPI communication adapter (or nullptr).
Definition Tmc9660Handler.h:1262
DriverVariant GetDriver() noexcept
Get the active driver pointer without requiring visitor usage.
Definition Tmc9660Handler.h:1136
UartDriver * driverViaUart() noexcept
Get the TMC9660 driver instance connected via UART (nullptr if using SPI).
Definition Tmc9660Handler.cpp:420
tmc9660::CommMode GetCommMode() const noexcept
Get the communication mode in use (SPI or UART).
Definition Tmc9660Handler.cpp:404
~Tmc9660Handler() noexcept
Destructor. Releases the driver, communication adapter, and all wrappers.
char description_[64]
Human-readable handler description.
Definition Tmc9660Handler.h:1292
Gpio & gpio(uint8_t gpioNumber)
Get a reference to the GPIO wrapper for a TMC9660 internal GPIO pin.
Definition Tmc9660Handler.cpp:383
bool Initialize(bool performReset=true, bool retrieveBootloaderInfo=true, bool failOnVerifyError=false)
Initialize the TMC9660 device.
Definition Tmc9660Handler.cpp:305
void DumpDiagnostics() noexcept
Dump comprehensive diagnostics to the system log.
Definition Tmc9660Handler.cpp:936
ConstDriverVariant GetDriver() const noexcept
Const overload of GetDriver().
Definition Tmc9660Handler.h:1147
Shared helper holding the four TMC9660 host-side control pin references.
Definition Tmc9660Handler.h:123
BaseGpio & wake
WAKE control pin GPIO (not owned).
Definition Tmc9660Handler.h:127
const BaseGpio & get(tmc9660::TMC9660CtrlPin pin) const noexcept
Resolve a TMC9660CtrlPin enum (const).
Definition Tmc9660Handler.h:141
BaseGpio & faultn
FAULTN status pin GPIO (not owned).
Definition Tmc9660Handler.h:126
BaseGpio & get(tmc9660::TMC9660CtrlPin pin) noexcept
Resolve a TMC9660CtrlPin enum to the corresponding BaseGpio reference.
Definition Tmc9660Handler.h:130
BaseGpio & rst
RST control pin GPIO (not owned).
Definition Tmc9660Handler.h:124
BaseGpio & drv_en
DRV_EN control pin GPIO (not owned).
Definition Tmc9660Handler.h:125