HF-TMC51x0 Driver (TMC5130 & TMC5160) 0.1.0-dev
Hardware Agnostic C++ Driver for the TMC51x0 (TMC5130 & TMC5160)
Loading...
Searching...
No Matches
esp32_tmc51x0_bus.hpp
Go to the documentation of this file.
1
22#pragma once
23
25#include "driver/gpio.h"
26#include "driver/ledc.h"
27#include "driver/spi_master.h"
28#include "driver/uart.h"
29#include "esp_log.h"
30#include "esp_rom_sys.h"
31#include "freertos/FreeRTOS.h"
32#include "freertos/semphr.h"
33#include "freertos/task.h"
34#include <cstdarg>
35#include <cstddef>
36#include <cstdint>
37#include <cstdio>
38#include <cstring>
39
40static const char* BUS_TAG = "TMC51x0_Bus";
41
57 // SPI bus pins (required for SPI communication)
58 int spi_mosi{-1};
59 int spi_miso{-1};
60 int spi_sclk{-1};
61 int spi_cs{-1};
62
63 // TMC51x0 control pins (from TMC51x0PinConfig)
65
69 Esp32SpiPinConfig() = default;
70
81 Esp32SpiPinConfig(int mosi, int miso, int sclk, int cs, int en, int dir = -1, int step = -1) noexcept
82 : spi_mosi(mosi), spi_miso(miso), spi_sclk(sclk), spi_cs(cs), tmc51x0_pins(en, dir, step) {}
83
92 Esp32SpiPinConfig(int mosi, int miso, int sclk, int cs, const tmc51x0::TMC51x0PinConfig& tmc_pins) noexcept
93 : spi_mosi(mosi), spi_miso(miso), spi_sclk(sclk), spi_cs(cs), tmc51x0_pins(tmc_pins) {}
94};
95
120class Esp32SPI : public tmc51x0::SpiCommInterface<Esp32SPI> {
121public:
150 Esp32SPI(spi_host_device_t host, const Esp32SpiPinConfig& pin_config,
151 uint32_t clock_speed_hz = 4000000,
152 const tmc51x0::PinActiveLevels& active_levels = tmc51x0::PinActiveLevels{}) noexcept
153 : SpiCommInterface(), // Active level management handled in this derived class
154 active_levels_(active_levels), // Store the struct directly
155 host_(host), mosi_pin_(static_cast<gpio_num_t>(pin_config.spi_mosi)),
156 miso_pin_(static_cast<gpio_num_t>(pin_config.spi_miso)),
157 sclk_pin_(static_cast<gpio_num_t>(pin_config.spi_sclk)),
158 cs_pin_(static_cast<gpio_num_t>(pin_config.spi_cs)),
159 en_pin_(static_cast<gpio_num_t>(pin_config.tmc51x0_pins.en_pin)),
160 dir_pin_(static_cast<gpio_num_t>(pin_config.tmc51x0_pins.dir_pin != -1
161 ? pin_config.tmc51x0_pins.dir_pin
162 : pin_config.tmc51x0_pins.ref_right_pin)),
163 step_pin_(static_cast<gpio_num_t>(pin_config.tmc51x0_pins.step_pin != -1
164 ? pin_config.tmc51x0_pins.step_pin
165 : pin_config.tmc51x0_pins.ref_left_pin)),
166 clock_speed_hz_(clock_speed_hz), device_handle_(nullptr), initialized_(false) {
167 // Initialize pin mapping array (all pins unmapped by default, use -1)
168 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
169 for (size_t i = 0; i < sizeof(pin_mapping_) / sizeof(pin_mapping_[0]); ++i) {
170 pin_mapping_[i] = UNMAPPED_PIN;
171 }
172
173 // Apply pin configuration (handles compound pins automatically)
174 ApplyPinConfig(pin_config.tmc51x0_pins);
175 }
176
177private:
186
193 [[nodiscard]] bool SignalToGpioLevel(tmc51x0::TMC51x0CtrlPin pin, tmc51x0::GpioSignal signal) const noexcept {
194 bool active_level = active_levels_.GetActiveLevel(pin);
195 return (signal == tmc51x0::GpioSignal::ACTIVE) ? active_level : !active_level;
196 }
197
204 [[nodiscard]] tmc51x0::GpioSignal GpioLevelToSignal(tmc51x0::TMC51x0CtrlPin pin, bool gpio_level) const noexcept {
205 bool active_level = active_levels_.GetActiveLevel(pin);
206 return (gpio_level == active_level) ? tmc51x0::GpioSignal::ACTIVE : tmc51x0::GpioSignal::INACTIVE;
207 }
208
209public:
224 void ConfigureActiveLevels(const tmc51x0::PinActiveLevels& active_levels) noexcept {
225 active_levels_ = active_levels; // Simply copy the struct
226 }
227
232 [[nodiscard]] const tmc51x0::PinActiveLevels& GetActiveLevels() const noexcept {
233 return active_levels_; // Return reference to stored struct
234 }
235
254 Esp32SPI(spi_host_device_t host, gpio_num_t mosi_pin, gpio_num_t miso_pin, gpio_num_t sclk_pin, gpio_num_t cs_pin,
255 const tmc51x0::TMC51x0PinConfig& pin_config, uint32_t clock_speed_hz = 4000000,
256 const tmc51x0::PinActiveLevels& active_levels = tmc51x0::PinActiveLevels{}) noexcept
257 : SpiCommInterface(), // Active level management handled in this derived class
258 active_levels_(active_levels), // Store the struct directly
259 host_(host), mosi_pin_(mosi_pin), miso_pin_(miso_pin), sclk_pin_(sclk_pin), cs_pin_(cs_pin),
260 en_pin_(static_cast<gpio_num_t>(pin_config.en_pin)),
261 dir_pin_(static_cast<gpio_num_t>(pin_config.dir_pin != -1 ? pin_config.dir_pin : pin_config.ref_right_pin)),
262 step_pin_(static_cast<gpio_num_t>(pin_config.step_pin != -1 ? pin_config.step_pin : pin_config.ref_left_pin)),
263 clock_speed_hz_(clock_speed_hz), device_handle_(nullptr), initialized_(false) {
264 // Initialize pin mapping array (all pins unmapped by default, use -1)
265 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
266 for (size_t i = 0; i < sizeof(pin_mapping_) / sizeof(pin_mapping_[0]); ++i) {
267 pin_mapping_[i] = UNMAPPED_PIN;
268 }
269
270 // Apply pin configuration (handles compound pins automatically)
271 ApplyPinConfig(pin_config);
272 }
273
293 Esp32SPI(spi_host_device_t host, gpio_num_t mosi_pin, gpio_num_t miso_pin, gpio_num_t sclk_pin, gpio_num_t cs_pin,
294 gpio_num_t en_pin, gpio_num_t dir_pin = static_cast<gpio_num_t>(-1),
295 gpio_num_t step_pin = static_cast<gpio_num_t>(-1), uint32_t clock_speed_hz = 4000000,
296 const tmc51x0::PinActiveLevels& active_levels = tmc51x0::PinActiveLevels{}) noexcept
297 : SpiCommInterface(), // Active level management handled in this derived class
298 active_levels_(active_levels), // Store the struct directly
299 host_(host), mosi_pin_(mosi_pin), miso_pin_(miso_pin), sclk_pin_(sclk_pin), cs_pin_(cs_pin), en_pin_(en_pin),
300 dir_pin_(dir_pin), step_pin_(step_pin), clock_speed_hz_(clock_speed_hz), device_handle_(nullptr),
301 initialized_(false) {
302 // Initialize pin mapping array (all pins unmapped by default, use -1)
303 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
304 for (size_t i = 0; i < sizeof(pin_mapping_) / sizeof(pin_mapping_[0]); ++i) {
305 pin_mapping_[i] = UNMAPPED_PIN;
306 }
307
308 // Set default pin mappings
309 pin_mapping_[static_cast<size_t>(tmc51x0::TMC51x0CtrlPin::EN)] = en_pin;
310 if (dir_pin != UNMAPPED_PIN) {
311 pin_mapping_[static_cast<size_t>(tmc51x0::TMC51x0CtrlPin::DIR)] = dir_pin;
312 pin_mapping_[static_cast<size_t>(tmc51x0::TMC51x0CtrlPin::REFR_DIR)] = dir_pin; // Same physical pin
313 }
314 if (step_pin != UNMAPPED_PIN) {
315 pin_mapping_[static_cast<size_t>(tmc51x0::TMC51x0CtrlPin::STEP)] = step_pin;
316 pin_mapping_[static_cast<size_t>(tmc51x0::TMC51x0CtrlPin::REFL_STEP)] = step_pin; // Same physical pin
317 }
318 }
319
323 ~Esp32SPI() noexcept {
324 Deinitialize();
325 }
326
341 bool ApplyPinConfig(const tmc51x0::TMC51x0PinConfig& pin_config) noexcept {
342 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
343
344 // Basic control pins
345 if (pin_config.en_pin != -1) {
346 SetPinMapping(tmc51x0::TMC51x0CtrlPin::EN, static_cast<gpio_num_t>(pin_config.en_pin));
347 }
348
349 // DIR/REFR_DIR compound pin (pin 18)
350 gpio_num_t dir_gpio = UNMAPPED_PIN;
351 if (pin_config.dir_pin != -1) {
352 dir_gpio = static_cast<gpio_num_t>(pin_config.dir_pin);
353 } else if (pin_config.ref_right_pin != -1) {
354 dir_gpio = static_cast<gpio_num_t>(pin_config.ref_right_pin);
355 }
356 if (dir_gpio != UNMAPPED_PIN) {
358 SetPinMapping(tmc51x0::TMC51x0CtrlPin::REFR_DIR, dir_gpio); // Same physical pin
359 }
360
361 // STEP/REFL_STEP compound pin (pin 17)
362 gpio_num_t step_gpio = UNMAPPED_PIN;
363 if (pin_config.step_pin != -1) {
364 step_gpio = static_cast<gpio_num_t>(pin_config.step_pin);
365 } else if (pin_config.ref_left_pin != -1) {
366 step_gpio = static_cast<gpio_num_t>(pin_config.ref_left_pin);
367 }
368 if (step_gpio != UNMAPPED_PIN) {
370 SetPinMapping(tmc51x0::TMC51x0CtrlPin::REFL_STEP, step_gpio); // Same physical pin
371 }
372
373 // Diagnostic pins
374 if (pin_config.diag0_pin != -1) {
375 SetPinMapping(tmc51x0::TMC51x0CtrlPin::DIAG0, static_cast<gpio_num_t>(pin_config.diag0_pin));
376 }
377 if (pin_config.diag1_pin != -1) {
378 SetPinMapping(tmc51x0::TMC51x0CtrlPin::DIAG1, static_cast<gpio_num_t>(pin_config.diag1_pin));
379 }
380
381 // ENCA/DCIN compound pin (pin 24)
382 gpio_num_t enca_gpio = UNMAPPED_PIN;
383 if (pin_config.enc_a_pin != -1) {
384 enca_gpio = static_cast<gpio_num_t>(pin_config.enc_a_pin);
385 } else if (pin_config.dc_in_pin != -1) {
386 enca_gpio = static_cast<gpio_num_t>(pin_config.dc_in_pin);
387 }
388 if (enca_gpio != UNMAPPED_PIN) {
390 SetPinMapping(tmc51x0::TMC51x0CtrlPin::DCIN, enca_gpio); // Same physical pin
391 }
392
393 // ENCB/DCEN compound pin (pin 23)
394 gpio_num_t encb_gpio = UNMAPPED_PIN;
395 if (pin_config.enc_b_pin != -1) {
396 encb_gpio = static_cast<gpio_num_t>(pin_config.enc_b_pin);
397 } else if (pin_config.dc_en_pin != -1) {
398 encb_gpio = static_cast<gpio_num_t>(pin_config.dc_en_pin);
399 }
400 if (encb_gpio != UNMAPPED_PIN) {
402 SetPinMapping(tmc51x0::TMC51x0CtrlPin::DCEN, encb_gpio); // Same physical pin
403 }
404
405 // ENCN/DCO compound pin (pin 25)
406 gpio_num_t encn_gpio = UNMAPPED_PIN;
407 if (pin_config.enc_n_pin != -1) {
408 encn_gpio = static_cast<gpio_num_t>(pin_config.enc_n_pin);
409 } else if (pin_config.dc_out_pin != -1) {
410 encn_gpio = static_cast<gpio_num_t>(pin_config.dc_out_pin);
411 }
412 if (encn_gpio != UNMAPPED_PIN) {
414 SetPinMapping(tmc51x0::TMC51x0CtrlPin::DCO, encn_gpio); // Same physical pin
415 }
416
417 // Clock pin
418 if (pin_config.clk_pin != -1) {
419 SetPinMapping(tmc51x0::TMC51x0CtrlPin::CLK, static_cast<gpio_num_t>(pin_config.clk_pin));
420 }
421
422 // Mode configuration pins (if available as control pins)
423 // ⚠️ WARNING: These are typically hardwired. Only configure if connected to GPIO.
424 if (pin_config.spi_mode_pin != -1) {
425 SetPinMapping(tmc51x0::TMC51x0CtrlPin::SPI_MODE, static_cast<gpio_num_t>(pin_config.spi_mode_pin));
426 }
427 if (pin_config.sd_mode_pin != -1) {
428 SetPinMapping(tmc51x0::TMC51x0CtrlPin::SD_MODE, static_cast<gpio_num_t>(pin_config.sd_mode_pin));
429 }
430
431 return true;
432 }
433
449 bool SetPinMapping(tmc51x0::TMC51x0CtrlPin pin, gpio_num_t gpio_pin) noexcept {
450 size_t index = static_cast<size_t>(pin);
451 if (index >= sizeof(pin_mapping_) / sizeof(pin_mapping_[0])) {
452 return false;
453 }
454 pin_mapping_[index] = gpio_pin;
455
456 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
457 // Configure GPIO direction based on pin type
458 if (gpio_pin != UNMAPPED_PIN) {
459 // Diagnostic pins are outputs (read-only from MCU perspective)
461 gpio_set_direction(gpio_pin, GPIO_MODE_INPUT); // MCU reads TMC51x0 output
462 gpio_set_pull_mode(gpio_pin, GPIO_PULLUP_ONLY); // Diagnostic pins have pullups
463 }
464 // Encoder pins are inputs (when SD_MODE=0)
467 gpio_set_direction(gpio_pin, GPIO_MODE_INPUT);
468 gpio_set_pull_mode(gpio_pin, GPIO_PULLUP_ONLY);
469 }
470 // DC Step pins (when SD_MODE=1, SPI_MODE=1)
472 gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT); // DCEN and DCIN are inputs to TMC51x0
473 } else if (pin == tmc51x0::TMC51x0CtrlPin::DCO) {
474 gpio_set_direction(gpio_pin, GPIO_MODE_INPUT); // DCO is output from TMC51x0
475 gpio_set_pull_mode(gpio_pin, GPIO_PULLUP_ONLY);
476 }
477 // Reference switch pins can be inputs (when used as reference switches, SD_MODE=0)
479 gpio_set_direction(gpio_pin, GPIO_MODE_INPUT);
480 gpio_set_pull_mode(gpio_pin, GPIO_PULLUP_ONLY); // Typically active LOW
481 active_levels_.SetActiveLevel(pin, false); // Active LOW for reference switches
482 }
483 // CLK pin can be output (for external clock) or input (for reading clock state)
484 else if (pin == tmc51x0::TMC51x0CtrlPin::CLK) {
485 // Default to input, user can configure as output if needed for PWM clock
486 gpio_set_direction(gpio_pin, GPIO_MODE_INPUT);
487 }
488 // Mode configuration pins (SPI_MODE, SD_MODE) - INPUT by default (read-only)
489 // These pins are typically hardwired on dev boards. Only set as OUTPUT if user
490 // explicitly calls communication.SetOperatingMode() or GpioSet() to control them.
492 gpio_set_direction(gpio_pin, GPIO_MODE_INPUT); // Input to read chip mode (hardwired on dev boards)
493 gpio_set_pull_mode(gpio_pin, GPIO_PULLUP_ONLY); // Pullup for stable reading
494 }
495 // Other pins default to output
496 else {
497 gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
498 }
499 }
500 return true;
501 }
502
508 [[nodiscard]] gpio_num_t GetPinMapping(tmc51x0::TMC51x0CtrlPin pin) const noexcept {
509 size_t index = static_cast<size_t>(pin);
510 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
511 if (index >= sizeof(pin_mapping_) / sizeof(pin_mapping_[0])) {
512 return UNMAPPED_PIN;
513 }
514 return pin_mapping_[index];
515 }
516
522 if (initialized_) {
523 return tmc51x0::Result<void>();
524 }
525
526 if (spi_mutex_ == nullptr) {
527 spi_mutex_ = xSemaphoreCreateMutex();
528 if (spi_mutex_ == nullptr) {
529 ESP_LOGE(BUS_TAG, "Failed to create SPI mutex");
531 }
532 }
533
534 // Configure GPIO pins that are mapped
535 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
536 if (en_pin_ != UNMAPPED_PIN) {
537 gpio_set_direction(en_pin_, GPIO_MODE_OUTPUT);
538 // Disable by default using signal abstraction (EN is active LOW, so INACTIVE = HIGH = disabled)
540 if (!en_result.IsOk()) {
541 ESP_LOGW(BUS_TAG, "Failed to set EN pin during initialization (non-critical)");
542 // Continue anyway - this is not critical for initialization
543 }
544 }
545 if (dir_pin_ != UNMAPPED_PIN) {
546 gpio_set_direction(dir_pin_, GPIO_MODE_OUTPUT);
547 // Set DIR to inactive by default using signal abstraction
549 if (!dir_result.IsOk()) {
550 ESP_LOGW(BUS_TAG, "Failed to set DIR pin during initialization (non-critical)");
551 // Continue anyway - this is not critical for initialization
552 }
553 }
554 if (step_pin_ != UNMAPPED_PIN) {
555 gpio_set_direction(step_pin_, GPIO_MODE_OUTPUT);
556 // Set STEP to inactive by default using signal abstraction
558 if (!step_result.IsOk()) {
559 ESP_LOGW(BUS_TAG, "Failed to set STEP pin during initialization (non-critical)");
560 // Continue anyway - this is not critical for initialization
561 }
562 }
563
564 // Configure SPI bus
565 spi_bus_config_t bus_config = {};
566 bus_config.mosi_io_num = mosi_pin_;
567 bus_config.miso_io_num = miso_pin_;
568 bus_config.sclk_io_num = sclk_pin_;
569 bus_config.quadwp_io_num = -1;
570 bus_config.quadhd_io_num = -1;
571 // Size large enough for the core driver's scratch requirement:
572 // (TMC51X0_SPI_MAX_CHAIN_DEVICES + 2) * 5 bytes (40 bits per device)
573 const int max_transfer_sz_bytes =
574 static_cast<int>((TMC51X0_SPI_MAX_CHAIN_DEVICES + 2U) * 5U);
575 bus_config.max_transfer_sz = max_transfer_sz_bytes;
576 bus_config.flags = SPICOMMON_BUSFLAG_MASTER;
577
578 esp_err_t ret = spi_bus_initialize(host_, &bus_config, SPI_DMA_CH_AUTO);
579 if (ret != ESP_OK) {
580 ESP_LOGE(BUS_TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
582 }
583
584 // Configure SPI device (Mode 3: CPOL=1, CPHA=1)
585 spi_device_interface_config_t dev_config = {};
586 dev_config.clock_speed_hz = clock_speed_hz_;
587 dev_config.mode = 3; // SPI Mode 3 for TMC51x0
588 dev_config.spics_io_num = cs_pin_;
589 dev_config.queue_size = 1;
590 dev_config.cs_ena_pretrans = 2;
591 dev_config.cs_ena_posttrans = 2;
592
593 ret = spi_bus_add_device(host_, &dev_config, &device_handle_);
594 if (ret != ESP_OK) {
595 ESP_LOGE(BUS_TAG, "Failed to add SPI device: %s", esp_err_to_name(ret));
596 spi_bus_free(host_);
598 }
599
600 initialized_ = true;
601 ESP_LOGI(BUS_TAG, "SPI interface initialized successfully");
602 return tmc51x0::Result<void>();
603 }
604
609 tmc51x0::CommMode GetMode() const noexcept {
611 }
612
620 bool EnsureInitialized() noexcept {
621 if (initialized_) {
622 return true;
623 }
624 auto result = Initialize();
625 return result.IsOk();
626 }
627
633 if (!initialized_) {
634 return tmc51x0::Result<void>();
635 }
636
637 if (device_handle_) {
638 esp_err_t ret = spi_bus_remove_device(device_handle_);
639 if (ret != ESP_OK) {
640 ESP_LOGE(BUS_TAG, "Failed to remove SPI device: %s", esp_err_to_name(ret));
642 }
643 device_handle_ = nullptr;
644 }
645
646 esp_err_t ret = spi_bus_free(host_);
647 if (ret != ESP_OK) {
648 ESP_LOGE(BUS_TAG, "Failed to free SPI bus: %s", esp_err_to_name(ret));
650 }
651
652 initialized_ = false;
653 ESP_LOGI(BUS_TAG, "SPI interface deinitialized");
654
655 if (spi_mutex_ != nullptr) {
656 vSemaphoreDelete(spi_mutex_);
657 spi_mutex_ = nullptr;
658 }
659 return tmc51x0::Result<void>();
660 }
661
678 tmc51x0::Result<void> SpiTransfer(const uint8_t* tx, uint8_t* rx, size_t length) noexcept {
679 // Caller must ensure Initialize() (or EnsureInitialized()) was invoked once before use.
680 if (!initialized_ || !device_handle_) {
681 ESP_LOGE(BUS_TAG, "SPI interface not initialized");
683 }
684
685 if (spi_mutex_ != nullptr) {
686 xSemaphoreTake(spi_mutex_, portMAX_DELAY);
687 }
688
689 spi_transaction_t trans = {};
690 trans.length = length * 8;
691 trans.tx_buffer = tx;
692 trans.rx_buffer = rx;
693
694 esp_err_t ret = spi_device_transmit(device_handle_, &trans);
695
696 if (spi_mutex_ != nullptr) {
697 xSemaphoreGive(spi_mutex_);
698 }
699 if (ret != ESP_OK) {
700 ESP_LOGE(BUS_TAG, "SPI transfer failed: %s", esp_err_to_name(ret));
702 }
703
704 return tmc51x0::Result<void>();
705 }
706
721 // Diagnostic pins and DCO are read-only (outputs from TMC51x0)
724 ESP_LOGW(BUS_TAG, "Pin is read-only (output from TMC51x0)");
726 }
727 // Encoder pins are read-only when used as encoder inputs (SD_MODE=0)
730 ESP_LOGW(BUS_TAG, "Encoder pins are read-only (use DCEN/DCIN for DC Step mode)");
732 }
733
734 gpio_num_t gpio_pin = GetPinMapping(pin);
735 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
736 if (gpio_pin == UNMAPPED_PIN) {
737 ESP_LOGW(BUS_TAG, "Pin not mapped: %d", static_cast<int>(pin));
739 }
740
741 // If user is trying to set SPI_MODE or SD_MODE pins, configure them as OUTPUT
742 // (they default to INPUT for read-only mode on hardwired dev boards)
744 gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
745 }
746
747 bool level = SignalToGpioLevel(pin, signal);
748 gpio_set_level(gpio_pin, level ? 1 : 0);
749 return tmc51x0::Result<void>();
750 }
751
763 gpio_num_t gpio_pin = GetPinMapping(pin);
764 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
765 if (gpio_pin == UNMAPPED_PIN) {
766 ESP_LOGW(BUS_TAG, "Pin not mapped: %d", static_cast<int>(pin));
768 }
769
770 int level = gpio_get_level(gpio_pin);
771 tmc51x0::GpioSignal signal = GpioLevelToSignal(pin, level != 0);
773 }
774
778 void DebugLog(int level, const char* tag, const char* format, va_list args) noexcept {
779 esp_log_level_t esp_level;
780 switch (level) {
781 case 0:
782 esp_level = ESP_LOG_ERROR;
783 break;
784 case 1:
785 esp_level = ESP_LOG_WARN;
786 break;
787 case 2:
788 esp_level = ESP_LOG_INFO;
789 break;
790 case 3:
791 esp_level = ESP_LOG_DEBUG;
792 break;
793 default:
794 esp_level = ESP_LOG_VERBOSE;
795 break;
796 }
797
798 // NOTE:
799 // - `esp_log_writev()` does NOT add the "I (time) TAG:" prefix unless you pass a format
800 // string created via ESP-IDF log macros.
801 // - To ensure logs show the standard ESP-IDF prefix, we format into a buffer and re-log
802 // via ESP_LOG_LEVEL().
803 //
804 // This is used by the core driver via TMC51X0_LOG_DEBUG() -> CommInterface::LogDebug().
805 char msg[512];
806 va_list args_copy;
807 va_copy(args_copy, args);
808 vsnprintf(msg, sizeof(msg), format, args_copy);
809 va_end(args_copy);
810
811 // Strip trailing newlines to avoid double-spacing (ESP_LOG_* adds its own newline).
812 size_t len = strlen(msg);
813 while (len > 0 && (msg[len - 1] == '\n' || msg[len - 1] == '\r')) {
814 msg[len - 1] = '\0';
815 --len;
816 }
817
818 ESP_LOG_LEVEL(esp_level, tag, "%s", msg);
819 }
820
824 void DelayMs(uint32_t ms) noexcept {
825 vTaskDelay(pdMS_TO_TICKS(ms));
826 }
827
831 void DelayUs(uint32_t us) noexcept {
832 esp_rom_delay_us(us);
833 }
834
855 tmc51x0::Result<void> SetClkFreq(uint32_t frequency_hz) noexcept {
856 gpio_num_t clk_pin = GetPinMapping(tmc51x0::TMC51x0CtrlPin::CLK);
857 constexpr gpio_num_t UNMAPPED_PIN = static_cast<gpio_num_t>(-1);
858
859 if (clk_pin == UNMAPPED_PIN) {
860 // If CLK is hard-wired to GND for internal osc, treat as OK for frequency_hz == 0.
861 if (frequency_hz == 0) {
862 return tmc51x0::Result<void>();
863 }
864 ESP_LOGW(BUS_TAG, "CLK pin not mapped; external clock request unsupported");
866 }
867
868 if (frequency_hz == 0) {
869 // Internal clock mode: Set CLK pin to GND (LOW)
870 gpio_set_direction(clk_pin, GPIO_MODE_OUTPUT);
871 gpio_set_level(clk_pin, 0); // Drive LOW (GND) for internal oscillator
872 ESP_LOGI(BUS_TAG, "CLK pin set to GND (internal 12 MHz oscillator enabled)");
873 return tmc51x0::Result<void>();
874 } else {
875 // External clock mode: Not implemented via PWM
876 // User must provide external clock signal on CLK pin
877 ESP_LOGW(BUS_TAG, "External clock generation not implemented. Provide external clock signal on CLK pin (frequency: %u Hz)", frequency_hz);
879 }
880 }
881
882private:
883 spi_host_device_t host_;
884 gpio_num_t mosi_pin_;
885 gpio_num_t miso_pin_;
886 gpio_num_t sclk_pin_;
887 gpio_num_t cs_pin_;
888 gpio_num_t en_pin_;
889 gpio_num_t dir_pin_;
890 gpio_num_t step_pin_;
892 spi_device_handle_t device_handle_;
893 SemaphoreHandle_t spi_mutex_{nullptr};
895
902 gpio_num_t pin_mapping_[16]{}; // Updated to support all pin types (16 pins: EN through SD_MODE)
903
904 bool configureGpioPins() noexcept {
905 // GPIO pins are configured in Initialize() and SetPinMapping()
906 return true;
907 }
908};
909
910// ============================================================================
911// ESP32 UART Communication Interface
912// ============================================================================
913
920 int uart_tx{-1};
921 int uart_rx{-1};
922
925
927
928 Esp32UartPinConfig(int tx, int rx, int en, int dir = -1, int step = -1) noexcept
929 : uart_tx(tx), uart_rx(rx), tmc51x0_pins(en, dir, step) {}
930
931 Esp32UartPinConfig(int tx, int rx,
932 const tmc51x0::TMC51x0PinConfig& tmc_pins) noexcept
933 : uart_tx(tx), uart_rx(rx), tmc51x0_pins(tmc_pins) {}
934};
935
951class Esp32UART : public tmc51x0::UartCommInterface<Esp32UART> {
952public:
960 Esp32UART(uart_port_t uart_num, const Esp32UartPinConfig& pin_config,
961 uint32_t baud_rate = 115200,
962 const tmc51x0::PinActiveLevels& active_levels = tmc51x0::PinActiveLevels{}) noexcept
964 active_levels_(active_levels),
965 uart_num_(uart_num),
966 tx_pin_(static_cast<gpio_num_t>(pin_config.uart_tx)),
967 rx_pin_(static_cast<gpio_num_t>(pin_config.uart_rx)),
968 en_pin_(static_cast<gpio_num_t>(pin_config.tmc51x0_pins.en_pin)),
969 baud_rate_(baud_rate),
970 initialized_(false) {
971 constexpr gpio_num_t UNMAPPED = static_cast<gpio_num_t>(-1);
972 for (size_t i = 0; i < sizeof(pin_mapping_) / sizeof(pin_mapping_[0]); ++i) {
973 pin_mapping_[i] = UNMAPPED;
974 }
975 ApplyPinConfig(pin_config.tmc51x0_pins);
976 }
977
978 ~Esp32UART() noexcept { Deinitialize(); }
979
980 // -- Pin config helpers (same pattern as Esp32SPI) -------------------------
981
982 bool ApplyPinConfig(const tmc51x0::TMC51x0PinConfig& pc) noexcept {
983 constexpr gpio_num_t UNMAPPED = static_cast<gpio_num_t>(-1);
984 if (pc.en_pin != -1) SetPinMapping(tmc51x0::TMC51x0CtrlPin::EN, static_cast<gpio_num_t>(pc.en_pin));
985
986 gpio_num_t dir_gpio = UNMAPPED;
987 if (pc.dir_pin != -1) dir_gpio = static_cast<gpio_num_t>(pc.dir_pin);
988 else if (pc.ref_right_pin != -1) dir_gpio = static_cast<gpio_num_t>(pc.ref_right_pin);
989 if (dir_gpio != UNMAPPED) {
992 }
993
994 gpio_num_t step_gpio = UNMAPPED;
995 if (pc.step_pin != -1) step_gpio = static_cast<gpio_num_t>(pc.step_pin);
996 else if (pc.ref_left_pin != -1) step_gpio = static_cast<gpio_num_t>(pc.ref_left_pin);
997 if (step_gpio != UNMAPPED) {
1000 }
1001
1002 if (pc.diag0_pin != -1) SetPinMapping(tmc51x0::TMC51x0CtrlPin::DIAG0, static_cast<gpio_num_t>(pc.diag0_pin));
1003 if (pc.diag1_pin != -1) SetPinMapping(tmc51x0::TMC51x0CtrlPin::DIAG1, static_cast<gpio_num_t>(pc.diag1_pin));
1004 if (pc.clk_pin != -1) SetPinMapping(tmc51x0::TMC51x0CtrlPin::CLK, static_cast<gpio_num_t>(pc.clk_pin));
1005 return true;
1006 }
1007
1008 bool SetPinMapping(tmc51x0::TMC51x0CtrlPin pin, gpio_num_t gpio_pin) noexcept {
1009 size_t idx = static_cast<size_t>(pin);
1010 if (idx >= sizeof(pin_mapping_) / sizeof(pin_mapping_[0])) return false;
1011 pin_mapping_[idx] = gpio_pin;
1012
1013 constexpr gpio_num_t UNMAPPED = static_cast<gpio_num_t>(-1);
1014 if (gpio_pin != UNMAPPED) {
1016 gpio_set_direction(gpio_pin, GPIO_MODE_INPUT);
1017 gpio_set_pull_mode(gpio_pin, GPIO_PULLUP_ONLY);
1019 gpio_set_direction(gpio_pin, GPIO_MODE_INPUT);
1020 gpio_set_pull_mode(gpio_pin, GPIO_PULLUP_ONLY);
1021 active_levels_.SetActiveLevel(pin, false);
1022 } else {
1023 gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
1024 }
1025 }
1026 return true;
1027 }
1028
1029 [[nodiscard]] gpio_num_t GetPinMapping(tmc51x0::TMC51x0CtrlPin pin) const noexcept {
1030 size_t idx = static_cast<size_t>(pin);
1031 constexpr gpio_num_t UNMAPPED = static_cast<gpio_num_t>(-1);
1032 if (idx >= sizeof(pin_mapping_) / sizeof(pin_mapping_[0])) return UNMAPPED;
1033 return pin_mapping_[idx];
1034 }
1035
1036 // -- Initialization --------------------------------------------------------
1037
1039 if (initialized_) return tmc51x0::Result<void>();
1040
1041 // Configure EN pin
1042 constexpr gpio_num_t UNMAPPED = static_cast<gpio_num_t>(-1);
1043 if (en_pin_ != UNMAPPED) {
1044 gpio_set_direction(en_pin_, GPIO_MODE_OUTPUT);
1046 }
1047
1048 // Configure UART peripheral
1049 uart_config_t uart_config = {};
1050 uart_config.baud_rate = static_cast<int>(baud_rate_);
1051 uart_config.data_bits = UART_DATA_8_BITS;
1052 uart_config.parity = UART_PARITY_DISABLE;
1053 uart_config.stop_bits = UART_STOP_BITS_1;
1054 uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
1055 uart_config.source_clk = UART_SCLK_DEFAULT;
1056
1057 esp_err_t ret = uart_param_config(uart_num_, &uart_config);
1058 if (ret != ESP_OK) {
1059 ESP_LOGE(BUS_TAG, "UART param config failed: %s", esp_err_to_name(ret));
1061 }
1062
1063 ret = uart_set_pin(uart_num_, tx_pin_, rx_pin_, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
1064 if (ret != ESP_OK) {
1065 ESP_LOGE(BUS_TAG, "UART set pin failed: %s", esp_err_to_name(ret));
1067 }
1068
1069 constexpr int kRxBufSize = 256;
1070 constexpr int kTxBufSize = 0; // TX uses blocking write
1071 ret = uart_driver_install(uart_num_, kRxBufSize, kTxBufSize, 0, nullptr, 0);
1072 if (ret != ESP_OK) {
1073 ESP_LOGE(BUS_TAG, "UART driver install failed: %s", esp_err_to_name(ret));
1075 }
1076
1077 // Flush any stale data
1078 uart_flush_input(uart_num_);
1079
1080 initialized_ = true;
1081 ESP_LOGI(BUS_TAG, "UART interface initialized (port %d, baud %u, TX=%d, RX=%d)",
1082 uart_num_, baud_rate_, static_cast<int>(tx_pin_), static_cast<int>(rx_pin_));
1083 return tmc51x0::Result<void>();
1084 }
1085
1087 if (!initialized_) return tmc51x0::Result<void>();
1088 uart_driver_delete(uart_num_);
1089 initialized_ = false;
1090 return tmc51x0::Result<void>();
1091 }
1092
1093 // -- UART transport (called by UartCommInterface base) ---------------------
1094
1095 tmc51x0::Result<void> UartSend(const uint8_t* data, size_t length) noexcept {
1097
1098 // Flush RX buffer to discard any echo or stale bytes
1099 uart_flush_input(uart_num_);
1100
1101 int written = uart_write_bytes(uart_num_, data, length);
1102 if (written < 0 || static_cast<size_t>(written) != length) {
1103 ESP_LOGE(BUS_TAG, "UART send failed: wrote %d/%zu bytes", written, length);
1105 }
1106 // Wait for TX FIFO to drain
1107 esp_err_t ret = uart_wait_tx_done(uart_num_, pdMS_TO_TICKS(50));
1108 if (ret != ESP_OK) {
1109 ESP_LOGW(BUS_TAG, "UART TX drain timeout");
1110 }
1111
1112 // On single-wire setups the TMC5160 echoes our TX back on RX.
1113 // Flush those echo bytes so UartReceive() sees only the reply.
1114 vTaskDelay(pdMS_TO_TICKS(2));
1115 uart_flush_input(uart_num_);
1116
1117 return tmc51x0::Result<void>();
1118 }
1119
1120 tmc51x0::Result<void> UartReceive(uint8_t* data, size_t length) noexcept {
1122
1123 // TMC5160 reply comes after SENDDELAY bit-times. At 115200 baud that is
1124 // ~70 us per bit time; with SENDDELAY=8 that's ~0.6 ms. We use a generous
1125 // 100 ms timeout to cover slow baud rates and long send delays.
1126 constexpr TickType_t kTimeoutTicks = pdMS_TO_TICKS(100);
1127
1128 int received = uart_read_bytes(uart_num_, data, length, kTimeoutTicks);
1129 if (received < 0 || static_cast<size_t>(received) != length) {
1130 ESP_LOGE(BUS_TAG, "UART receive failed: got %d/%zu bytes", received, length);
1132 }
1133 return tmc51x0::Result<void>();
1134 }
1135
1136 // -- NAI/NAO pin control (for sequential programming) ----------------------
1137
1138 tmc51x0::Result<void> SetNaiPin(bool active) noexcept {
1139 // NAI is on SDI_CFG1 (pin 15) in UART mode -- not always wired to ESP32.
1140 // If not mapped, this is a no-op (single-node systems don't need it).
1141 return tmc51x0::Result<void>();
1142 }
1143
1145 // NAO is on SDO_CFG0 (pin 16) in UART mode -- not always wired to ESP32.
1146 return tmc51x0::Result<bool>(false);
1147 }
1148
1149 // -- GPIO (same interface as Esp32SPI) -------------------------------------
1150
1152
1156 }
1157 gpio_num_t gpio = GetPinMapping(pin);
1158 constexpr gpio_num_t UNMAPPED = static_cast<gpio_num_t>(-1);
1159 if (gpio == UNMAPPED) return tmc51x0::Result<void>(tmc51x0::ErrorCode::INVALID_VALUE);
1160
1161 bool level = (signal == tmc51x0::GpioSignal::ACTIVE)
1164 gpio_set_level(gpio, level ? 1 : 0);
1165 return tmc51x0::Result<void>();
1166 }
1167
1169 gpio_num_t gpio = GetPinMapping(pin);
1170 constexpr gpio_num_t UNMAPPED = static_cast<gpio_num_t>(-1);
1172
1173 int level = gpio_get_level(gpio);
1174 bool active_level = active_levels_.GetActiveLevel(pin);
1175 tmc51x0::GpioSignal sig = ((level != 0) == active_level)
1179 }
1180
1181 void DebugLog(int level, const char* tag, const char* format, va_list args) noexcept {
1182 esp_log_level_t esp_level;
1183 switch (level) {
1184 case 0: esp_level = ESP_LOG_ERROR; break;
1185 case 1: esp_level = ESP_LOG_WARN; break;
1186 case 2: esp_level = ESP_LOG_INFO; break;
1187 case 3: esp_level = ESP_LOG_DEBUG; break;
1188 default: esp_level = ESP_LOG_VERBOSE; break;
1189 }
1190 char msg[512];
1191 va_list args_copy;
1192 va_copy(args_copy, args);
1193 vsnprintf(msg, sizeof(msg), format, args_copy);
1194 va_end(args_copy);
1195 size_t len = strlen(msg);
1196 while (len > 0 && (msg[len - 1] == '\n' || msg[len - 1] == '\r')) { msg[--len] = '\0'; }
1197 ESP_LOG_LEVEL(esp_level, tag, "%s", msg);
1198 }
1199
1200 void DelayMs(uint32_t ms) noexcept { vTaskDelay(pdMS_TO_TICKS(ms)); }
1201 void DelayUs(uint32_t us) noexcept { esp_rom_delay_us(us); }
1202
1203private:
1205 uart_port_t uart_num_;
1206 gpio_num_t tx_pin_;
1207 gpio_num_t rx_pin_;
1208 gpio_num_t en_pin_;
1209 uint32_t baud_rate_;
1211 gpio_num_t pin_mapping_[16]{};
1212};
ESP32 SPI implementation of TMC51x0 communication interface.
Definition esp32_tmc51x0_bus.hpp:120
bool initialized_
Definition esp32_tmc51x0_bus.hpp:894
Esp32SPI(spi_host_device_t host, gpio_num_t mosi_pin, gpio_num_t miso_pin, gpio_num_t sclk_pin, gpio_num_t cs_pin, const tmc51x0::TMC51x0PinConfig &pin_config, uint32_t clock_speed_hz=4000000, const tmc51x0::PinActiveLevels &active_levels=tmc51x0::PinActiveLevels{}) noexcept
Construct ESP32 SPI communication interface with separate SPI pins and TMC51x0 pin config.
Definition esp32_tmc51x0_bus.hpp:254
void DebugLog(int level, const char *tag, const char *format, va_list args) noexcept
Debug logging.
Definition esp32_tmc51x0_bus.hpp:778
gpio_num_t pin_mapping_[16]
Pin mapping array: maps TMC51x0CtrlPin enum to ESP32 GPIO numbers.
Definition esp32_tmc51x0_bus.hpp:902
Esp32SPI(spi_host_device_t host, gpio_num_t mosi_pin, gpio_num_t miso_pin, gpio_num_t sclk_pin, gpio_num_t cs_pin, gpio_num_t en_pin, gpio_num_t dir_pin=static_cast< gpio_num_t >(-1), gpio_num_t step_pin=static_cast< gpio_num_t >(-1), uint32_t clock_speed_hz=4000000, const tmc51x0::PinActiveLevels &active_levels=tmc51x0::PinActiveLevels{}) noexcept
Construct ESP32 SPI communication interface (legacy constructor for backward compatibility)
Definition esp32_tmc51x0_bus.hpp:293
spi_host_device_t host_
Definition esp32_tmc51x0_bus.hpp:883
tmc51x0::GpioSignal GpioLevelToSignal(tmc51x0::TMC51x0CtrlPin pin, bool gpio_level) const noexcept
Convert physical GPIO level to signal state.
Definition esp32_tmc51x0_bus.hpp:204
const tmc51x0::PinActiveLevels & GetActiveLevels() const noexcept
Get current active level configuration.
Definition esp32_tmc51x0_bus.hpp:232
tmc51x0::Result< void > SpiTransfer(const uint8_t *tx, uint8_t *rx, size_t length) noexcept
Perform SPI transfer.
Definition esp32_tmc51x0_bus.hpp:678
tmc51x0::Result< void > GpioSet(tmc51x0::TMC51x0CtrlPin pin, tmc51x0::GpioSignal signal) noexcept
Set GPIO pin state.
Definition esp32_tmc51x0_bus.hpp:720
tmc51x0::Result< void > SetClkFreq(uint32_t frequency_hz) noexcept
Set external clock frequency on CLK pin.
Definition esp32_tmc51x0_bus.hpp:855
void ConfigureActiveLevels(const tmc51x0::PinActiveLevels &active_levels) noexcept
Configure pin active levels from PinActiveLevels struct.
Definition esp32_tmc51x0_bus.hpp:224
tmc51x0::PinActiveLevels active_levels_
Pin active level configuration storage.
Definition esp32_tmc51x0_bus.hpp:185
uint32_t clock_speed_hz_
Definition esp32_tmc51x0_bus.hpp:891
gpio_num_t mosi_pin_
Definition esp32_tmc51x0_bus.hpp:884
gpio_num_t sclk_pin_
Definition esp32_tmc51x0_bus.hpp:886
gpio_num_t en_pin_
Definition esp32_tmc51x0_bus.hpp:888
SemaphoreHandle_t spi_mutex_
Definition esp32_tmc51x0_bus.hpp:893
void DelayUs(uint32_t us) noexcept
Delay microseconds.
Definition esp32_tmc51x0_bus.hpp:831
gpio_num_t GetPinMapping(tmc51x0::TMC51x0CtrlPin pin) const noexcept
Get pin mapping for a TMC51x0 control pin.
Definition esp32_tmc51x0_bus.hpp:508
bool SignalToGpioLevel(tmc51x0::TMC51x0CtrlPin pin, tmc51x0::GpioSignal signal) const noexcept
Convert signal state to physical GPIO level.
Definition esp32_tmc51x0_bus.hpp:193
tmc51x0::Result< void > Initialize() noexcept
Initialize the SPI interface.
Definition esp32_tmc51x0_bus.hpp:521
gpio_num_t dir_pin_
Definition esp32_tmc51x0_bus.hpp:889
bool ApplyPinConfig(const tmc51x0::TMC51x0PinConfig &pin_config) noexcept
Apply pin configuration structure (handles compound pins automatically)
Definition esp32_tmc51x0_bus.hpp:341
~Esp32SPI() noexcept
Destructor - cleans up SPI resources.
Definition esp32_tmc51x0_bus.hpp:323
bool EnsureInitialized() noexcept
Ensure SPI interface is initialized, initializing if necessary.
Definition esp32_tmc51x0_bus.hpp:620
Esp32SPI(spi_host_device_t host, const Esp32SpiPinConfig &pin_config, uint32_t clock_speed_hz=4000000, const tmc51x0::PinActiveLevels &active_levels=tmc51x0::PinActiveLevels{}) noexcept
Construct ESP32 SPI communication interface with complete pin configuration.
Definition esp32_tmc51x0_bus.hpp:150
void DelayMs(uint32_t ms) noexcept
Delay milliseconds.
Definition esp32_tmc51x0_bus.hpp:824
gpio_num_t cs_pin_
Definition esp32_tmc51x0_bus.hpp:887
tmc51x0::Result< void > Deinitialize() noexcept
Deinitialize the SPI interface.
Definition esp32_tmc51x0_bus.hpp:632
gpio_num_t step_pin_
Definition esp32_tmc51x0_bus.hpp:890
bool configureGpioPins() noexcept
Definition esp32_tmc51x0_bus.hpp:904
bool SetPinMapping(tmc51x0::TMC51x0CtrlPin pin, gpio_num_t gpio_pin) noexcept
Set pin mapping for a TMC51x0 control pin.
Definition esp32_tmc51x0_bus.hpp:449
tmc51x0::CommMode GetMode() const noexcept
Get communication mode (always SPI for this interface)
Definition esp32_tmc51x0_bus.hpp:609
spi_device_handle_t device_handle_
Definition esp32_tmc51x0_bus.hpp:892
gpio_num_t miso_pin_
Definition esp32_tmc51x0_bus.hpp:885
tmc51x0::Result< tmc51x0::GpioSignal > GpioRead(tmc51x0::TMC51x0CtrlPin pin) noexcept
Read GPIO pin state.
Definition esp32_tmc51x0_bus.hpp:762
ESP32 UART implementation of TMC51x0 communication interface.
Definition esp32_tmc51x0_bus.hpp:951
bool initialized_
Definition esp32_tmc51x0_bus.hpp:1210
tmc51x0::Result< void > GpioSet(tmc51x0::TMC51x0CtrlPin pin, tmc51x0::GpioSignal signal) noexcept
Definition esp32_tmc51x0_bus.hpp:1153
gpio_num_t rx_pin_
Definition esp32_tmc51x0_bus.hpp:1207
tmc51x0::Result< tmc51x0::GpioSignal > GpioRead(tmc51x0::TMC51x0CtrlPin pin) noexcept
Definition esp32_tmc51x0_bus.hpp:1168
tmc51x0::Result< void > UartReceive(uint8_t *data, size_t length) noexcept
Definition esp32_tmc51x0_bus.hpp:1120
tmc51x0::PinActiveLevels active_levels_
Definition esp32_tmc51x0_bus.hpp:1204
gpio_num_t GetPinMapping(tmc51x0::TMC51x0CtrlPin pin) const noexcept
Definition esp32_tmc51x0_bus.hpp:1029
bool ApplyPinConfig(const tmc51x0::TMC51x0PinConfig &pc) noexcept
Definition esp32_tmc51x0_bus.hpp:982
void DebugLog(int level, const char *tag, const char *format, va_list args) noexcept
Definition esp32_tmc51x0_bus.hpp:1181
gpio_num_t en_pin_
Definition esp32_tmc51x0_bus.hpp:1208
tmc51x0::Result< void > Deinitialize() noexcept
Definition esp32_tmc51x0_bus.hpp:1086
gpio_num_t tx_pin_
Definition esp32_tmc51x0_bus.hpp:1206
~Esp32UART() noexcept
Definition esp32_tmc51x0_bus.hpp:978
tmc51x0::Result< bool > GetNaoPin() noexcept
Definition esp32_tmc51x0_bus.hpp:1144
tmc51x0::Result< void > Initialize() noexcept
Definition esp32_tmc51x0_bus.hpp:1038
bool SetPinMapping(tmc51x0::TMC51x0CtrlPin pin, gpio_num_t gpio_pin) noexcept
Definition esp32_tmc51x0_bus.hpp:1008
tmc51x0::Result< void > UartSend(const uint8_t *data, size_t length) noexcept
Definition esp32_tmc51x0_bus.hpp:1095
tmc51x0::Result< void > SetNaiPin(bool active) noexcept
Definition esp32_tmc51x0_bus.hpp:1138
tmc51x0::CommMode GetMode() const noexcept
Definition esp32_tmc51x0_bus.hpp:1151
void DelayMs(uint32_t ms) noexcept
Definition esp32_tmc51x0_bus.hpp:1200
gpio_num_t pin_mapping_[16]
Definition esp32_tmc51x0_bus.hpp:1211
uart_port_t uart_num_
Definition esp32_tmc51x0_bus.hpp:1205
uint32_t baud_rate_
Definition esp32_tmc51x0_bus.hpp:1209
void DelayUs(uint32_t us) noexcept
Definition esp32_tmc51x0_bus.hpp:1201
Esp32UART(uart_port_t uart_num, const Esp32UartPinConfig &pin_config, uint32_t baud_rate=115200, const tmc51x0::PinActiveLevels &active_levels=tmc51x0::PinActiveLevels{}) noexcept
Construct ESP32 UART communication interface.
Definition esp32_tmc51x0_bus.hpp:960
Result type for operations that return a value.
Definition tmc51x0_result.hpp:90
CRTP-based SPI implementation of TMC5160CommInterface.
Definition tmc51x0_comm_interface.hpp:1660
SpiCommInterface() noexcept
Construct SPI communication interface.
Definition tmc51x0_comm_interface.hpp:1689
CRTP-based UART implementation of TMC5160CommInterface.
Definition tmc51x0_comm_interface.hpp:2935
UartCommInterface() noexcept
Construct UART communication interface with pin active level configuration.
Definition tmc51x0_comm_interface.hpp:2951
static const char * BUS_TAG
Definition esp32_tmc51x0_bus.hpp:40
GpioSignal
GPIO signal states with board-agnostic naming.
Definition tmc51x0_comm_interface.hpp:319
@ ACTIVE
Active signal state (logical high)
@ INACTIVE
Inactive signal state (logical low)
@ NOT_INITIALIZED
Driver not initialized.
@ UNSUPPORTED
Feature not supported by this chip variant.
@ COMM_ERROR
Communication interface error (SPI/UART)
@ INVALID_VALUE
Invalid parameter value.
TMC51x0CtrlPin
TMC51x0 control pin identifiers with board-agnostic naming.
Definition tmc51x0_comm_interface.hpp:258
@ EN
Enable pin (DRV_ENN, pin 28) - Active HIGH disables power stage.
CommMode
Supported physical communication modes for TMC51x0.
Definition tmc51x0_comm_interface.hpp:221
Complete ESP32 SPI bus and TMC51x0 pin configuration structure.
Definition esp32_tmc51x0_bus.hpp:56
Esp32SpiPinConfig()=default
Default constructor - all pins unmapped (-1)
int spi_cs
SPI chip select pin (CS)
Definition esp32_tmc51x0_bus.hpp:61
int spi_mosi
SPI MOSI pin (Master Out, Slave In)
Definition esp32_tmc51x0_bus.hpp:58
Esp32SpiPinConfig(int mosi, int miso, int sclk, int cs, int en, int dir=-1, int step=-1) noexcept
Constructor with SPI pins and basic TMC51x0 pins.
Definition esp32_tmc51x0_bus.hpp:81
int spi_sclk
SPI clock pin (SCLK)
Definition esp32_tmc51x0_bus.hpp:60
int spi_miso
SPI MISO pin (Master In, Slave Out)
Definition esp32_tmc51x0_bus.hpp:59
tmc51x0::TMC51x0PinConfig tmc51x0_pins
TMC51x0 control pin configuration.
Definition esp32_tmc51x0_bus.hpp:64
Esp32SpiPinConfig(int mosi, int miso, int sclk, int cs, const tmc51x0::TMC51x0PinConfig &tmc_pins) noexcept
Constructor with SPI pins and full TMC5160 pin config.
Definition esp32_tmc51x0_bus.hpp:92
ESP32 UART pin configuration structure.
Definition esp32_tmc51x0_bus.hpp:919
tmc51x0::TMC51x0PinConfig tmc51x0_pins
TMC51x0 control pins (EN, DIAG0, DIAG1, etc.)
Definition esp32_tmc51x0_bus.hpp:924
Esp32UartPinConfig(int tx, int rx, const tmc51x0::TMC51x0PinConfig &tmc_pins) noexcept
Definition esp32_tmc51x0_bus.hpp:931
Esp32UartPinConfig()=default
int uart_rx
UART RX pin (ESP32 RX <- TMC5160 SWP/SWIOP)
Definition esp32_tmc51x0_bus.hpp:921
Esp32UartPinConfig(int tx, int rx, int en, int dir=-1, int step=-1) noexcept
Definition esp32_tmc51x0_bus.hpp:928
int uart_tx
UART TX pin (ESP32 TX -> TMC5160 SWN/SWPN)
Definition esp32_tmc51x0_bus.hpp:920
Pin active level configuration structure.
Definition tmc51x0_comm_interface.hpp:352
bool GetActiveLevel(TMC51x0CtrlPin pin) const noexcept
Get active level for a specific pin.
Definition tmc51x0_comm_interface.hpp:398
void SetActiveLevel(TMC51x0CtrlPin pin, bool active_level) noexcept
Set active level for a specific pin.
Definition tmc51x0_comm_interface.hpp:442
TMC51x0 GPIO pin configuration structure.
Definition tmc51x0_comm_interface.hpp:521
int dc_out_pin
DC Step ready output (ENCN_DCO_CFG6, pin 25) - Same as enc_n_pin.
Definition tmc51x0_comm_interface.hpp:549
int clk_pin
Clock input (CLK, pin 12) - Optional.
Definition tmc51x0_comm_interface.hpp:553
int enc_b_pin
Encoder B (ENCB_DCEN_CFG4, pin 23) - Same as dc_en_pin.
Definition tmc51x0_comm_interface.hpp:541
int ref_left_pin
Left reference switch (REFL_STEP, pin 17) - Same as step_pin.
Definition tmc51x0_comm_interface.hpp:530
int diag1_pin
DIAG1 pin (DIAG1_SWP, pin 27) - Optional.
Definition tmc51x0_comm_interface.hpp:537
int dc_en_pin
Definition tmc51x0_comm_interface.hpp:547
int en_pin
EN pin (DRV_ENN, pin 28) - Required.
Definition tmc51x0_comm_interface.hpp:523
int enc_n_pin
Encoder N (ENCN_DCO_CFG6, pin 25) - Same as dc_out_pin.
Definition tmc51x0_comm_interface.hpp:542
int spi_mode_pin
Definition tmc51x0_comm_interface.hpp:560
int dc_in_pin
Definition tmc51x0_comm_interface.hpp:545
int sd_mode_pin
hardwired. HIGH=External step/dir, LOW=Internal ramp
Definition tmc51x0_comm_interface.hpp:562
int ref_right_pin
Right reference switch (REFR_DIR, pin 18) - Same as dir_pin.
Definition tmc51x0_comm_interface.hpp:532
int diag0_pin
DIAG0 pin (DIAG0_SWN, pin 26) - Optional.
Definition tmc51x0_comm_interface.hpp:536
int step_pin
STEP pin (REFL_STEP, pin 17) - Optional, same as ref_left_pin.
Definition tmc51x0_comm_interface.hpp:526
int dir_pin
DIR pin (REFR_DIR, pin 18) - Optional, same as ref_right_pin.
Definition tmc51x0_comm_interface.hpp:524
int enc_a_pin
Encoder A (ENCA_DCIN_CFG5, pin 24) - Same as dc_in_pin.
Definition tmc51x0_comm_interface.hpp:540
Communication interfaces for TMC51x0 stepper motor driver using SPI and UART.
#define TMC51X0_SPI_MAX_CHAIN_DEVICES
Definition tmc51x0_comm_interface.hpp:1672