7static const char *
const TAG =
"spi-esp-idf";
8static const size_t MAX_TRANSFER_SIZE = 4092;
10class SPIDelegateHw :
public SPIDelegate {
13 bool release_device,
bool write_only)
16 release_device_(release_device),
17 write_only_(write_only) {
18 if (!this->release_device_)
21 if (this->write_only_) {
22 ESP_LOGV(
TAG,
"SPI device with CS pin %d using half-duplex mode (write-only)",
27 bool is_ready()
override {
return this->handle_ !=
nullptr; }
29 void begin_transaction()
override {
30 if (this->release_device_)
32 if (this->is_ready()) {
33 if (spi_device_acquire_bus(this->handle_, portMAX_DELAY) != ESP_OK)
34 ESP_LOGE(
TAG,
"Failed to acquire SPI bus");
37 ESP_LOGW(
TAG,
"SPI device not ready, cannot begin transaction");
41 void end_transaction()
override {
42 if (this->is_ready()) {
44 spi_device_release_bus(this->handle_);
45 if (this->release_device_) {
46 spi_bus_remove_device(this->handle_);
47 this->handle_ =
nullptr;
52 ~SPIDelegateHw()
override {
53 esp_err_t
const err = spi_bus_remove_device(this->handle_);
55 ESP_LOGE(
TAG,
"Remove device failed - err %X", err);
62 void transfer(
const uint8_t *txbuf, uint8_t *rxbuf,
size_t length)
override {
63 if (rxbuf !=
nullptr && this->write_only_) {
64 ESP_LOGE(
TAG,
"Attempted read from write-only channel");
67 spi_transaction_t desc = {};
70 size_t const partial = std::min(
length, MAX_TRANSFER_SIZE);
71 desc.length = partial * 8;
72 desc.rxlength = this->write_only_ ? 0 : partial * 8;
73 desc.tx_buffer = txbuf;
74 desc.rx_buffer = rxbuf;
76 esp_err_t err = spi_device_polling_start(this->handle_, &desc, portMAX_DELAY);
78 err = spi_device_polling_end(this->handle_, portMAX_DELAY);
81 ESP_LOGE(
TAG,
"Transmit failed - err %X", err);
92 void write(uint16_t data,
size_t num_bits)
override {
93 spi_transaction_ext_t desc = {};
94 desc.command_bits = num_bits;
95 desc.base.flags = SPI_TRANS_VARIABLE_CMD;
97 esp_err_t err = spi_device_polling_start(this->handle_, (spi_transaction_t *) &desc, portMAX_DELAY);
99 err = spi_device_polling_end(this->handle_, portMAX_DELAY);
103 ESP_LOGE(
TAG,
"Transmit failed - err %X", err);
117 void write_cmd_addr_data(
size_t cmd_bits,
uint32_t cmd,
size_t addr_bits,
uint32_t address,
const uint8_t *data,
118 size_t length, uint8_t bus_width)
override {
119 spi_transaction_ext_t desc = {};
120 if (
length == 0 && cmd_bits == 0 && addr_bits == 0) {
121 esph_log_w(
TAG,
"Nothing to transfer");
124 desc.base.flags = SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_DUMMY;
125 if (bus_width == 4) {
126 desc.base.flags |= SPI_TRANS_MODE_QIO;
127 }
else if (bus_width == 8) {
128 desc.base.flags |= SPI_TRANS_MODE_OCT;
130 desc.command_bits = cmd_bits;
131 desc.address_bits = addr_bits;
133 desc.base.rxlength = 0;
137 size_t chunk_size = std::min(
length, MAX_TRANSFER_SIZE);
138 if (data !=
nullptr && chunk_size != 0) {
139 desc.base.length = chunk_size * 8;
140 desc.base.tx_buffer =
data;
145 desc.base.length = 0;
147 esp_err_t err = spi_device_polling_start(this->handle_, (spi_transaction_t *) &desc, portMAX_DELAY);
149 err = spi_device_polling_end(this->handle_, portMAX_DELAY);
152 ESP_LOGE(
TAG,
"Transmit failed - err %X", err);
156 desc.command_bits = 0;
157 desc.address_bits = 0;
161 void transfer(uint8_t *ptr,
size_t length)
override { this->transfer(ptr, ptr,
length); }
163 uint8_t transfer(uint8_t data)
override {
165 this->transfer(&data, &rxbuf, 1);
169 void write16(uint16_t data)
override { this->write(data, 16); }
171 void write_array(
const uint8_t *ptr,
size_t length)
override { this->transfer(ptr,
nullptr,
length); }
173 void write_array16(
const uint16_t *data,
size_t length)
override {
175 this->write_array((uint8_t *) data,
length * 2);
177 uint16_t buffer[MAX_TRANSFER_SIZE / 2];
179 size_t const partial = std::min(
length, MAX_TRANSFER_SIZE / 2);
180 for (
size_t i = 0; i != partial; i++) {
181 buffer[i] = SPI_SWAP_DATA_TX(*data++, 16);
183 this->write_array((
const uint8_t *) buffer, partial * 2);
189 void read_array(uint8_t *ptr,
size_t length)
override { this->transfer(
nullptr, ptr,
length); }
193 spi_device_interface_config_t config = {};
194 config.mode =
static_cast<uint8_t
>(this->
mode_);
195 config.clock_speed_hz =
static_cast<int>(this->
data_rate_);
196 config.spics_io_num = -1;
198 config.queue_size = 1;
199 config.pre_cb =
nullptr;
200 config.post_cb =
nullptr;
202 config.flags |= SPI_DEVICE_BIT_LSBFIRST;
203 if (this->write_only_)
204 config.flags |= SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_NO_DUMMY;
205 esp_err_t
const err = spi_bus_add_device(this->channel_, &config, &this->handle_);
207 ESP_LOGE(
TAG,
"Add device failed - err %X", err);
214 spi_device_handle_t handle_{};
215 bool release_device_{
false};
216 bool write_only_{
false};
219class SPIBusHw :
public SPIBus {
221 SPIBusHw(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi,
SPIInterface channel, std::vector<uint8_t> data_pins)
222 :
SPIBus(clk, sdo, sdi), channel_(channel) {
223 spi_bus_config_t buscfg = {};
225 buscfg.flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_SCLK;
226 if (data_pins.empty()) {
229 buscfg.quadwp_io_num = -1;
230 buscfg.quadhd_io_num = -1;
232 buscfg.data0_io_num = data_pins[0];
233 buscfg.data1_io_num = data_pins[1];
234 buscfg.data2_io_num = data_pins[2];
235 buscfg.data3_io_num = data_pins[3];
236 if (data_pins.size() == 8) {
237 buscfg.data4_io_num = data_pins[4];
238 buscfg.data5_io_num = data_pins[5];
239 buscfg.data6_io_num = data_pins[6];
240 buscfg.data7_io_num = data_pins[7];
241 buscfg.flags |= SPICOMMON_BUSFLAG_OCTAL;
243 buscfg.data4_io_num = -1;
244 buscfg.data5_io_num = -1;
245 buscfg.data6_io_num = -1;
246 buscfg.data7_io_num = -1;
247 buscfg.flags |= SPICOMMON_BUSFLAG_QUAD;
250 buscfg.max_transfer_sz = MAX_TRANSFER_SIZE;
251 auto err = spi_bus_initialize(channel, &buscfg, SPI_DMA_CH_AUTO);
253 ESP_LOGE(
TAG,
"Bus init failed - err %X", err);
257 bool release_device,
bool write_only)
override {
258 return new SPIDelegateHw(this->channel_, data_rate, bit_order,
mode, cs_pin, release_device,
265 bool is_hw()
override {
return true; }
269 const std::vector<uint8_t> &data_pins) {
270 return new SPIBusHw(clk, sdo, sdi, interface, data_pins);
BedjetMode mode
BedJet operating mode.
static SPIBus * get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi, const std::vector< uint8_t > &data_pins)
virtual void end_transaction()
virtual void begin_transaction()
static int get_pin_no(GPIOPin *pin)
const std::vector< uint8_t > & data
Implementation of SPI Controller mode.
SPIMode
Modes mapping to clock phase and polarity.
SPIBitOrder
The bit-order for SPI devices. This defines how the data read from and written to the device is inter...
@ BIT_ORDER_LSB_FIRST
The least significant bit is transmitted/received first.
spi_host_device_t SPIInterface