20#include "driver/gpio.h"
21#include "driver/spi_master.h"
23#include "esp_rom_sys.h"
47 spi_host_device_t
host = SPI2_HOST;
69 : config_(config), spi_device_(nullptr), initialized_(false) {}
75 if (spi_device_ !=
nullptr) {
76 spi_bus_remove_device(spi_device_);
77 spi_bus_free(config_.
host);
78 spi_device_ =
nullptr;
91 if (!initializeGPIO()) {
92 ESP_LOGE(TAG,
"Failed to initialize GPIO pins");
96 if (!initializeSPI()) {
97 ESP_LOGE(TAG,
"Failed to initialize SPI bus");
101 if (!addSPIDevice()) {
102 ESP_LOGE(TAG,
"Failed to add SPI device");
103 spi_bus_free(config_.
host);
108#if (ESP32_MAX22200_ENABLE_VERBOSE_BUS_LOGGING != 0)
109 ESP_LOGI(TAG,
"SPI interface initialized successfully");
124 bool Transfer(
const uint8_t *tx_data, uint8_t *rx_data,
size_t length) {
125 if (!initialized_ || spi_device_ ==
nullptr) {
126 ESP_LOGE(TAG,
"SPI not initialized");
130 spi_transaction_t trans = {};
131 trans.length = length * 8;
132 trans.tx_buffer = tx_data;
133 trans.rx_buffer = rx_data;
135 esp_err_t ret = spi_device_transmit(spi_device_, &trans);
137 ESP_LOGE(TAG,
"SPI transfer failed: %s", esp_err_to_name(ret));
141 if (
LOG_SPI_HEX && tx_data !=
nullptr && rx_data !=
nullptr && length > 0) {
144 n += snprintf(buf + n,
sizeof(buf) - n,
"SPI(%zu) TX:", length);
145 for (
size_t i = 0; i < length && n < (int)
sizeof(buf) - 6; i++)
146 n += snprintf(buf + n,
sizeof(buf) - n,
" %02X", tx_data[i]);
147 n += snprintf(buf + n,
sizeof(buf) - n,
" RX:");
148 for (
size_t i = 0; i < length && n < (int)
sizeof(buf) - 6; i++)
149 n += snprintf(buf + n,
sizeof(buf) - n,
" %02X", rx_data[i]);
150 ESP_LOGI(TAG,
"%s", buf);
173 bool Configure(uint32_t speed_hz, uint8_t mode,
bool msb_first =
true) {
175 ESP_LOGE(TAG,
"SPI not initialized");
192 return initialized_ && (spi_device_ !=
nullptr);
200 esp_rom_delay_us(us);
232 gpio_set_level(
static_cast<gpio_num_t
>(gpio_pin), level);
251 int level = gpio_get_level(
static_cast<gpio_num_t
>(config_.
fault_pin));
264 gpio_set_level(
static_cast<gpio_num_t
>(config_.
triga_pin), active ? 1 : 0);
274 gpio_set_level(
static_cast<gpio_num_t
>(config_.
trigb_pin), active ? 1 : 0);
285 spi_device_handle_t spi_device_;
287 static constexpr const char *TAG =
"Esp32Max22200SpiBus";
293 bool initializeGPIO() {
295 auto configure_output = [
this](int16_t pin,
const char *name,
int initial) ->
bool {
296 if (pin < 0)
return true;
297 gpio_config_t
cfg = {
298 .pin_bit_mask = (1ULL << pin),
299 .mode = GPIO_MODE_OUTPUT,
300 .pull_up_en = GPIO_PULLUP_DISABLE,
301 .pull_down_en = GPIO_PULLDOWN_DISABLE,
302 .intr_type = GPIO_INTR_DISABLE};
303 if (gpio_config(&
cfg) != ESP_OK) {
304 ESP_LOGE(TAG,
"Failed to configure %s pin (GPIO%d)", name, pin);
307 gpio_set_level(
static_cast<gpio_num_t
>(pin), initial);
308#if (ESP32_MAX22200_ENABLE_VERBOSE_BUS_LOGGING != 0)
309 ESP_LOGI(TAG,
"%s pin (GPIO%d) initialized, level=%d", name, pin, initial);
313 if (!configure_output(config_.enable_pin,
"ENABLE", 0))
return false;
314 if (!configure_output(config_.cmd_pin,
"CMD", 1))
return false;
315 if (!configure_output(config_.triga_pin,
"TRIGA", 1))
return false;
316 if (!configure_output(config_.trigb_pin,
"TRIGB", 1))
return false;
319 if (config_.fault_pin >= 0) {
320 gpio_config_t
cfg = {
321 .pin_bit_mask = (1ULL << config_.fault_pin),
322 .mode = GPIO_MODE_INPUT,
323 .pull_up_en = GPIO_PULLUP_ENABLE,
324 .pull_down_en = GPIO_PULLDOWN_DISABLE,
325 .intr_type = GPIO_INTR_DISABLE};
326 if (gpio_config(&
cfg) != ESP_OK) {
327 ESP_LOGE(TAG,
"Failed to configure FAULT pin (GPIO%d)", config_.fault_pin);
330#if (ESP32_MAX22200_ENABLE_VERBOSE_BUS_LOGGING != 0)
331 ESP_LOGI(TAG,
"FAULT pin (GPIO%d) initialized as input (active-low, inactive-high)", config_.fault_pin);
346 bool initializeSPI() {
348 esp_err_t ret = ESP_OK;
349 ret = gpio_set_pull_mode(
static_cast<gpio_num_t
>(config_.miso_pin), GPIO_PULLUP_ONLY);
351 ESP_LOGW(TAG,
"MISO pullup set failed: %s (external pullup on SDO recommended)", esp_err_to_name(ret));
354 spi_bus_config_t bus_cfg = {};
355 bus_cfg.mosi_io_num = config_.mosi_pin;
356 bus_cfg.miso_io_num = config_.miso_pin;
357 bus_cfg.sclk_io_num = config_.sclk_pin;
358 bus_cfg.quadwp_io_num = -1;
359 bus_cfg.quadhd_io_num = -1;
360 bus_cfg.max_transfer_sz = 64;
361 bus_cfg.flags = SPICOMMON_BUSFLAG_MASTER;
363 ret = spi_bus_initialize(config_.host, &bus_cfg, SPI_DMA_CH_AUTO);
365 ESP_LOGE(TAG,
"Failed to initialize SPI bus: %s", esp_err_to_name(ret));
376 bool addSPIDevice() {
377 spi_device_interface_config_t dev_cfg = {};
378 dev_cfg.command_bits = 0;
379 dev_cfg.address_bits = 0;
380 dev_cfg.dummy_bits = 0;
381 dev_cfg.clock_speed_hz = config_.frequency;
382 dev_cfg.mode = config_.mode;
383 dev_cfg.duty_cycle_pos = 128;
384 dev_cfg.spics_io_num = config_.cs_pin;
385 dev_cfg.queue_size = config_.queue_size;
386 dev_cfg.cs_ena_pretrans = config_.cs_ena_pretrans;
387 dev_cfg.cs_ena_posttrans = config_.cs_ena_posttrans;
389 dev_cfg.input_delay_ns = 0;
390 dev_cfg.pre_cb =
nullptr;
391 dev_cfg.post_cb =
nullptr;
393 esp_err_t ret = spi_bus_add_device(config_.host, &dev_cfg, &spi_device_);
395 ESP_LOGE(TAG,
"Failed to add SPI device: %s", esp_err_to_name(ret));
417 config.
host = SPI2_HOST;
418 config.
miso_pin =
static_cast<gpio_num_t
>(SPIPins::MISO);
419 config.
mosi_pin =
static_cast<gpio_num_t
>(SPIPins::MOSI);
420 config.
sclk_pin =
static_cast<gpio_num_t
>(SPIPins::SCLK);
421 config.
cs_pin =
static_cast<gpio_num_t
>(SPIPins::CS);
425 config.
mode = SPIParams::MODE;
433 config.
cmd_pin = ControlPins::CMD;
437 return std::make_unique<Esp32Max22200SpiBus>(config);
#define ESP32_MAX22200_ENABLE_DETAILED_SPI_LOGGING
Definition c21_cycle_test.cpp:61
ESP32 SPI transport implementation for MAX22200 driver.
Definition esp32_max22200_bus.hpp:38
~Esp32Max22200SpiBus()
Destructor - cleans up SPI resources.
Definition esp32_max22200_bus.hpp:74
bool Transfer(const uint8_t *tx_data, uint8_t *rx_data, size_t length)
Definition esp32_max22200_bus.hpp:124
bool HasTrigB() const
Definition esp32_max22200_bus.hpp:281
void DelayUs(uint32_t us)
Blocking delay in microseconds (for MAX22200 power-up, etc.). Uses ESP-ROM delay so it is safe before...
Definition esp32_max22200_bus.hpp:199
bool HasTrigA() const
Definition esp32_max22200_bus.hpp:279
bool IsReady() const
Check if SPI interface is ready.
Definition esp32_max22200_bus.hpp:191
void SetTrigB(bool active)
Set TRIGB pin level (direct-drive trigger B)
Definition esp32_max22200_bus.hpp:272
void SetChipSelect(bool state)
Set chip select state.
Definition esp32_max22200_bus.hpp:160
void GpioSet(max22200::CtrlPin pin, max22200::GpioSignal signal)
Set a control pin to the specified signal state.
Definition esp32_max22200_bus.hpp:216
static constexpr bool LOG_SPI_HEX
Perform a full-duplex SPI data transfer.
Definition esp32_max22200_bus.hpp:122
bool Initialize()
Initialize the SPI bus.
Definition esp32_max22200_bus.hpp:86
Esp32Max22200SpiBus(const SPIConfig &config)
Constructor with SPI configuration (pins must be set by caller)
Definition esp32_max22200_bus.hpp:68
bool Configure(uint32_t speed_hz, uint8_t mode, bool msb_first=true)
Configure SPI parameters.
Definition esp32_max22200_bus.hpp:173
void SetTrigA(bool active)
Set TRIGA pin level (direct-drive trigger A)
Definition esp32_max22200_bus.hpp:262
bool GpioRead(max22200::CtrlPin pin, max22200::GpioSignal &signal)
Read the current state of a control pin.
Definition esp32_max22200_bus.hpp:247
CRTP-based template interface for SPI communication.
Definition max22200_spi_interface.hpp:114
auto CreateEsp32Max22200SpiBus() noexcept -> std::unique_ptr< Esp32Max22200SpiBus >
Factory function to create a configured Esp32Max22200SpiBus instance.
Definition esp32_max22200_bus.hpp:411
Hardware configuration for MAX22200 driver on ESP32-C6.
CRTP-based template interface for SPI communication.
Definition esp32_max22200_test_config.hpp:55
Definition c21_cycle_test.cpp:82
GpioSignal
Abstract signal level for control pins.
Definition max22200_spi_interface.hpp:85
@ ACTIVE
Pin function is asserted.
@ INACTIVE
Pin function is deasserted.
CtrlPin
Identifies the hardware control pins of the MAX22200.
Definition max22200_spi_interface.hpp:71
@ FAULT
Fault status output (active-low, open-drain)
@ CMD
Command mode select (HIGH = SPI register, LOW = direct drive)
@ ENABLE
Output enable (active-high on the physical pin)
SPI configuration structure.
Definition esp32_max22200_bus.hpp:46
int16_t triga_pin
TRIGA trigger pin (direct drive, -1 = not configured)
Definition esp32_max22200_bus.hpp:55
uint32_t frequency
SPI frequency in Hz (default 10MHz)
Definition esp32_max22200_bus.hpp:57
gpio_num_t sclk_pin
SCLK pin (set from board config)
Definition esp32_max22200_bus.hpp:50
uint8_t cs_ena_pretrans
CS asserted N clock cycles before transaction.
Definition esp32_max22200_bus.hpp:60
int16_t trigb_pin
TRIGB trigger pin (direct drive, -1 = not configured)
Definition esp32_max22200_bus.hpp:56
int16_t enable_pin
ENABLE pin (active-high, -1 = not configured)
Definition esp32_max22200_bus.hpp:52
int16_t fault_pin
FAULT pin (active-low, inactive-high; open-drain input; -1 = not configured)
Definition esp32_max22200_bus.hpp:53
gpio_num_t miso_pin
MISO pin (set from board config)
Definition esp32_max22200_bus.hpp:48
uint8_t cs_ena_posttrans
CS held N clock cycles after transaction.
Definition esp32_max22200_bus.hpp:61
uint8_t queue_size
Transaction queue size.
Definition esp32_max22200_bus.hpp:59
spi_host_device_t host
SPI host (e.g. SPI2_HOST for ESP32-C6)
Definition esp32_max22200_bus.hpp:47
int16_t cmd_pin
CMD pin (active-high = SPI mode, -1 = not configured)
Definition esp32_max22200_bus.hpp:54
uint8_t mode
SPI mode (default 0: CPOL=0, CPHA=0)
Definition esp32_max22200_bus.hpp:58
gpio_num_t cs_pin
CS pin (set from board config)
Definition esp32_max22200_bus.hpp:51
gpio_num_t mosi_pin
MOSI pin (set from board config)
Definition esp32_max22200_bus.hpp:49