ESPHome 2026.1.0-dev
Loading...
Searching...
No Matches
spi.h
Go to the documentation of this file.
1#pragma once
4#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6#include <map>
7#include <utility>
8#include <vector>
9
10#ifdef USE_ESP32
11
12#include "driver/spi_master.h"
13
14using SPIInterface = spi_host_device_t;
15
16#elif defined(USE_ARDUINO)
17
18#include <SPI.h>
19
20#ifdef USE_RP2040
21using SPIInterface = SPIClassRP2040 *;
22#else
23using SPIInterface = SPIClass *;
24#endif
25
26#elif defined(CLANG_TIDY)
27
28using SPIInterface = void *; // Stub for platforms without SPI (e.g., Zephyr)
29
30#endif // USE_ESP32 / USE_ARDUINO
31
35namespace esphome::spi {
36
70
76enum SPIMode {
77 MODE0 = 0,
78 MODE1 = 1,
79 MODE2 = 2,
80 MODE3 = 3,
81};
87enum SPIDataRate : uint32_t {
91 DATA_RATE_1MHZ = 1000000,
92 DATA_RATE_2MHZ = 2000000,
93 DATA_RATE_4MHZ = 4000000,
94 DATA_RATE_5MHZ = 5000000,
95 DATA_RATE_8MHZ = 8000000,
96 DATA_RATE_10MHZ = 10000000,
97 DATA_RATE_20MHZ = 20000000,
98 DATA_RATE_40MHZ = 40000000,
99 DATA_RATE_80MHZ = 80000000,
100};
101
105class NullPin : public GPIOPin {
106 friend class SPIComponent;
107
108 friend class SPIDelegate;
109
110 friend class Utility;
111
112 public:
113 void setup() override {}
114
115 void pin_mode(gpio::Flags flags) override {}
116
117 gpio::Flags get_flags() const override { return gpio::Flags::FLAG_NONE; }
118
119 bool digital_read() override { return false; }
120
121 void digital_write(bool value) override {}
122
123 std::string dump_summary() const override { return std::string(); }
124
125 protected:
126 static GPIOPin *const NULL_PIN; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
127 // https://bugs.llvm.org/show_bug.cgi?id=48040
128};
129
130class Utility {
131 public:
132 static int get_pin_no(GPIOPin *pin) {
133 if (pin == nullptr || !pin->is_internal())
134 return -1;
135 if (((InternalGPIOPin *) pin)->is_inverted())
136 return -1;
137 return ((InternalGPIOPin *) pin)->get_pin();
138 }
139
141 if (polarity == CLOCK_POLARITY_HIGH) {
142 return phase == CLOCK_PHASE_LEADING ? MODE2 : MODE3;
143 }
144 return phase == CLOCK_PHASE_LEADING ? MODE0 : MODE1;
145 }
146
148 switch (mode) {
149 case MODE0:
150 case MODE2:
151 return CLOCK_PHASE_LEADING;
152 default:
154 }
155 }
156
158 switch (mode) {
159 case MODE0:
160 case MODE1:
161 return CLOCK_POLARITY_LOW;
162 default:
163 return CLOCK_POLARITY_HIGH;
164 }
165 }
166};
167
168class SPIDelegateDummy;
169
170// represents a device attached to an SPI bus, with a defined clock rate, mode and bit order. On Arduino this is
171// a thin wrapper over SPIClass.
173 friend class SPIClient;
174
175 public:
176 SPIDelegate() = default;
177
178 SPIDelegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin)
179 : bit_order_(bit_order), data_rate_(data_rate), mode_(mode), cs_pin_(cs_pin) {
180 if (this->cs_pin_ == nullptr)
182 this->cs_pin_->setup();
183 this->cs_pin_->digital_write(true);
184 }
185
186 virtual ~SPIDelegate(){};
187
188 // enable CS if configured.
189 virtual void begin_transaction() { this->cs_pin_->digital_write(false); }
190
191 // end the transaction
192 virtual void end_transaction() { this->cs_pin_->digital_write(true); }
193
194 // transfer one byte, return the byte that was read.
195 virtual uint8_t transfer(uint8_t data) = 0;
196
197 // transfer a buffer, replace the contents with read data
198 virtual void transfer(uint8_t *ptr, size_t length) { this->transfer(ptr, ptr, length); }
199
200 virtual void transfer(const uint8_t *txbuf, uint8_t *rxbuf, size_t length) {
201 for (size_t i = 0; i != length; i++)
202 rxbuf[i] = this->transfer(txbuf[i]);
203 }
204
210 virtual void write(uint16_t data, size_t num_bits) {
211 esph_log_e("spi_device", "variable length write not implemented");
212 }
213
214 virtual void write_cmd_addr_data(size_t cmd_bits, uint32_t cmd, size_t addr_bits, uint32_t address,
215 const uint8_t *data, size_t length, uint8_t bus_width) {
216 esph_log_e("spi_device", "write_cmd_addr_data not implemented");
217 }
218 // write 16 bits
219 virtual void write16(uint16_t data) {
220 if (this->bit_order_ == BIT_ORDER_MSB_FIRST) {
221 uint16_t buffer;
222 buffer = (data >> 8) | (data << 8);
223 this->write_array(reinterpret_cast<const uint8_t *>(&buffer), 2);
224 } else {
225 this->write_array(reinterpret_cast<const uint8_t *>(&data), 2);
226 }
227 }
228
229 virtual void write_array16(const uint16_t *data, size_t length) {
230 for (size_t i = 0; i != length; i++) {
231 this->write16(data[i]);
232 }
233 }
234
235 // write the contents of a buffer, ignore read data (buffer is unchanged.)
236 virtual void write_array(const uint8_t *ptr, size_t length) {
237 for (size_t i = 0; i != length; i++)
238 this->transfer(ptr[i]);
239 }
240
241 // read into a buffer, write nulls
242 virtual void read_array(uint8_t *ptr, size_t length) {
243 for (size_t i = 0; i != length; i++)
244 ptr[i] = this->transfer(0);
245 }
246
247 // check if device is ready
248 virtual bool is_ready();
249
250 protected:
252 uint32_t data_rate_{1000000};
255 static SPIDelegate *const NULL_DELEGATE; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
256};
257
263 public:
264 SPIDelegateDummy() = default;
265
266 uint8_t transfer(uint8_t data) override { return 0; }
267 void end_transaction() override{};
268
269 void begin_transaction() override;
270};
271
277 public:
278 SPIDelegateBitBash(uint32_t clock, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, GPIOPin *clk_pin,
279 GPIOPin *sdo_pin, GPIOPin *sdi_pin)
280 : SPIDelegate(clock, bit_order, mode, cs_pin), clk_pin_(clk_pin), sdo_pin_(sdo_pin), sdi_pin_(sdi_pin) {
281 // this calculation is pretty meaningless except at very low bit rates.
282 this->wait_cycle_ = uint32_t(arch_get_cpu_freq_hz()) / this->data_rate_ / 2ULL;
285 }
286
287 uint8_t transfer(uint8_t data) override;
288
289 void write(uint16_t data, size_t num_bits) override;
290
291 void write16(uint16_t data) override { this->write(data, 16); };
292
293 protected:
297 uint32_t last_transition_{0};
298 uint32_t wait_cycle_;
301
302 void HOT cycle_clock_() {
303 while (this->last_transition_ - arch_get_cpu_cycle_count() < this->wait_cycle_)
304 continue;
305 this->last_transition_ += this->wait_cycle_;
306 }
307 uint16_t transfer_(uint16_t data, size_t num_bits);
308};
309
310class SPIBus {
311 public:
312 SPIBus() = default;
313
314 SPIBus(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi) : clk_pin_(clk), sdo_pin_(sdo), sdi_pin_(sdi) {}
315
316 virtual SPIDelegate *get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin,
317 bool release_device, bool write_only) {
318 return new SPIDelegateBitBash(data_rate, bit_order, mode, cs_pin, this->clk_pin_, this->sdo_pin_, this->sdi_pin_);
319 }
320
321 virtual bool is_hw() { return false; }
322
323 protected:
327};
328
329class SPIClient;
330
331class SPIComponent : public Component {
332 public:
333 SPIDelegate *register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate,
334 GPIOPin *cs_pin, bool release_device, bool write_only);
335 void unregister_device(SPIClient *device);
336
337 void set_clk(GPIOPin *clk) { this->clk_pin_ = clk; }
338
339 void set_miso(GPIOPin *sdi) { this->sdi_pin_ = sdi; }
340
341 void set_mosi(GPIOPin *sdo) { this->sdo_pin_ = sdo; }
342 void set_data_pins(std::vector<uint8_t> pins) { this->data_pins_ = std::move(pins); }
343
344 void set_interface(SPIInterface interface) {
345 this->interface_ = interface;
346 this->using_hw_ = true;
347 }
348
349 void set_interface_name(const char *name) { this->interface_name_ = name; }
350
351 float get_setup_priority() const override { return setup_priority::BUS; }
352
353 void setup() override;
354 void dump_config() override;
355 size_t get_bus_width() const {
356 if (this->data_pins_.empty()) {
357 return 1;
358 }
359 return this->data_pins_.size();
360 }
361
362 protected:
363 GPIOPin *clk_pin_{nullptr};
364 GPIOPin *sdi_pin_{nullptr};
365 GPIOPin *sdo_pin_{nullptr};
366 std::vector<uint8_t> data_pins_{};
367
369 bool using_hw_{false};
370 const char *interface_name_{nullptr};
372 std::map<SPIClient *, SPIDelegate *> devices_;
373
374 static SPIBus *get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi,
375 const std::vector<uint8_t> &data_pins);
376};
377
384 public:
385 SPIClient(SPIBitOrder bit_order, SPIMode mode, uint32_t data_rate)
386 : bit_order_(bit_order), mode_(mode), data_rate_(data_rate) {}
387
388 virtual void spi_setup() {
389 esph_log_d("spi_device", "mode %u, data_rate %ukHz", (unsigned) this->mode_, (unsigned) (this->data_rate_ / 1000));
390 this->delegate_ = this->parent_->register_device(this, this->mode_, this->bit_order_, this->data_rate_, this->cs_,
391 this->release_device_, this->write_only_);
392 }
393
394 virtual void spi_teardown() {
395 this->parent_->unregister_device(this);
397 }
398
399 bool spi_is_ready() { return this->delegate_->is_ready(); }
400 void set_release_device(bool release) { this->release_device_ = release; }
401 void set_write_only(bool write_only) { this->write_only_ = write_only; }
402
403 protected:
406 uint32_t data_rate_{1000000};
408 GPIOPin *cs_{nullptr};
409 bool release_device_{false};
410 bool write_only_{false};
412};
413
422template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, SPIDataRate DATA_RATE>
423class SPIDevice : public SPIClient {
424 public:
425 SPIDevice() : SPIClient(BIT_ORDER, Utility::get_mode(CLOCK_POLARITY, CLOCK_PHASE), DATA_RATE) {}
426
427 SPIDevice(SPIComponent *parent, GPIOPin *cs_pin) {
428 this->set_spi_parent(parent);
429 this->set_cs_pin(cs_pin);
430 }
431
432 void spi_setup() override { SPIClient::spi_setup(); }
433
435
436 void set_spi_parent(SPIComponent *parent) { this->parent_ = parent; }
437
438 void set_cs_pin(GPIOPin *cs) { this->cs_ = cs; }
439
440 void set_data_rate(uint32_t data_rate) { this->data_rate_ = data_rate; }
441
442 void set_bit_order(SPIBitOrder order) { this->bit_order_ = order; }
443
444 void set_mode(SPIMode mode) { this->mode_ = mode; }
445
446 uint8_t read_byte() { return this->delegate_->transfer(0); }
447
448 void read_array(uint8_t *data, size_t length) { return this->delegate_->read_array(data, length); }
449
455 void write(uint16_t data, size_t num_bits) { this->delegate_->write(data, num_bits); };
456
457 /* Write command, address and data. Command and address will be written as single-bit SPI,
458 * data phase can be multiple bit (currently only 1 or 4)
459 * @param cmd_bits Number of bits to write in the command phase
460 * @param cmd The command value to write
461 * @param addr_bits Number of bits to write in addr phase
462 * @param address Address data
463 * @param data Plain data bytes
464 * @param length Number of data bytes
465 * @param bus_width The number of data lines to use for the data phase.
466 */
467 void write_cmd_addr_data(size_t cmd_bits, uint32_t cmd, size_t addr_bits, uint32_t address, const uint8_t *data,
468 size_t length, uint8_t bus_width = 1) {
469 this->delegate_->write_cmd_addr_data(cmd_bits, cmd, addr_bits, address, data, length, bus_width);
470 }
471
472 void write_byte(uint8_t data) { this->delegate_->write_array(&data, 1); }
473
479 void transfer_array(uint8_t *data, size_t length) { this->delegate_->transfer(data, length); }
480
481 uint8_t transfer_byte(uint8_t data) { return this->delegate_->transfer(data); }
482
485 void write_byte16(uint16_t data) { this->delegate_->write16(data); }
486
493 void write_array16(const uint16_t *data, size_t length) { this->delegate_->write_array16(data, length); }
494
495 void enable() { this->delegate_->begin_transaction(); }
496
497 void disable() { this->delegate_->end_transaction(); }
498
499 void write_array(const uint8_t *data, size_t length) { this->delegate_->write_array(data, length); }
500
501 template<size_t N> void write_array(const std::array<uint8_t, N> &data) { this->write_array(data.data(), N); }
502
503 void write_array(const std::vector<uint8_t> &data) { this->write_array(data.data(), data.size()); }
504
505 template<size_t N> void transfer_array(std::array<uint8_t, N> &data) { this->transfer_array(data.data(), N); }
506};
507
508} // namespace esphome::spi
BedjetMode mode
BedJet operating mode.
uint8_t address
Definition bl0906.h:4
virtual void setup()=0
virtual void digital_write(bool value)=0
virtual bool is_internal()
Definition gpio.h:69
A pin to replace those that don't exist.
Definition spi.h:105
std::string dump_summary() const override
Definition spi.h:123
gpio::Flags get_flags() const override
Definition spi.h:117
static GPIOPin *const NULL_PIN
Definition spi.h:126
bool digital_read() override
Definition spi.h:119
void setup() override
Definition spi.h:113
void pin_mode(gpio::Flags flags) override
Definition spi.h:115
void digital_write(bool value) override
Definition spi.h:121
virtual bool is_hw()
Definition spi.h:321
GPIOPin * sdo_pin_
Definition spi.h:325
GPIOPin * clk_pin_
Definition spi.h:324
SPIBus(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi)
Definition spi.h:314
virtual SPIDelegate * get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, bool release_device, bool write_only)
Definition spi.h:316
GPIOPin * sdi_pin_
Definition spi.h:326
Base class for SPIDevice, un-templated.
Definition spi.h:383
void set_release_device(bool release)
Definition spi.h:400
virtual void spi_teardown()
Definition spi.h:394
uint32_t data_rate_
Definition spi.h:406
void set_write_only(bool write_only)
Definition spi.h:401
SPIBitOrder bit_order_
Definition spi.h:404
SPIDelegate * delegate_
Definition spi.h:411
virtual void spi_setup()
Definition spi.h:388
SPIComponent * parent_
Definition spi.h:407
SPIClient(SPIBitOrder bit_order, SPIMode mode, uint32_t data_rate)
Definition spi.h:385
void setup() override
Definition spi.cpp:38
size_t get_bus_width() const
Definition spi.h:355
void set_interface(SPIInterface interface)
Definition spi.h:344
void unregister_device(SPIClient *device)
Definition spi.cpp:29
static SPIBus * get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi, const std::vector< uint8_t > &data_pins)
std::map< SPIClient *, SPIDelegate * > devices_
Definition spi.h:372
float get_setup_priority() const override
Definition spi.h:351
void set_clk(GPIOPin *clk)
Definition spi.h:337
void set_data_pins(std::vector< uint8_t > pins)
Definition spi.h:342
void dump_config() override
Definition spi.cpp:65
void set_miso(GPIOPin *sdi)
Definition spi.h:339
SPIInterface interface_
Definition spi.h:368
SPIDelegate * register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate, GPIOPin *cs_pin, bool release_device, bool write_only)
Definition spi.cpp:17
const char * interface_name_
Definition spi.h:370
void set_interface_name(const char *name)
Definition spi.h:349
void set_mosi(GPIOPin *sdo)
Definition spi.h:341
std::vector< uint8_t > data_pins_
Definition spi.h:366
An implementation of SPI that relies only on software toggling of pins.
Definition spi.h:276
uint8_t transfer(uint8_t data) override
Definition spi.cpp:82
SPIClockPolarity clock_polarity_
Definition spi.h:299
SPIDelegateBitBash(uint32_t clock, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, GPIOPin *clk_pin, GPIOPin *sdo_pin, GPIOPin *sdi_pin)
Definition spi.h:278
void write(uint16_t data, size_t num_bits) override
Definition spi.cpp:84
SPIClockPhase clock_phase_
Definition spi.h:300
uint16_t transfer_(uint16_t data, size_t num_bits)
Definition spi.cpp:86
void write16(uint16_t data) override
Definition spi.h:291
A dummy SPIDelegate that complains if it's used.
Definition spi.h:262
uint8_t transfer(uint8_t data) override
Definition spi.h:266
void end_transaction() override
Definition spi.h:267
void begin_transaction() override
Definition spi.cpp:80
virtual uint8_t transfer(uint8_t data)=0
SPIDelegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin)
Definition spi.h:178
virtual void end_transaction()
Definition spi.h:192
virtual ~SPIDelegate()
Definition spi.h:186
virtual void begin_transaction()
Definition spi.h:189
virtual void read_array(uint8_t *ptr, size_t length)
Definition spi.h:242
virtual void write(uint16_t data, size_t num_bits)
write a variable length data item, up to 16 bits.
Definition spi.h:210
virtual bool is_ready()
Definition spi.cpp:13
virtual void transfer(uint8_t *ptr, size_t length)
Definition spi.h:198
virtual void write_array(const uint8_t *ptr, size_t length)
Definition spi.h:236
virtual void write_cmd_addr_data(size_t cmd_bits, uint32_t cmd, size_t addr_bits, uint32_t address, const uint8_t *data, size_t length, uint8_t bus_width)
Definition spi.h:214
SPIBitOrder bit_order_
Definition spi.h:251
virtual void write16(uint16_t data)
Definition spi.h:219
virtual void transfer(const uint8_t *txbuf, uint8_t *rxbuf, size_t length)
Definition spi.h:200
virtual void write_array16(const uint16_t *data, size_t length)
Definition spi.h:229
static SPIDelegate *const NULL_DELEGATE
Definition spi.h:255
The SPIDevice is what components using the SPI will create.
Definition spi.h:423
void set_data_rate(uint32_t data_rate)
Definition spi.h:440
void write_byte16(uint16_t data)
Write 16 bit data.
Definition spi.h:485
void write_array(const std::array< uint8_t, N > &data)
Definition spi.h:501
void spi_setup() override
Definition spi.h:432
void set_cs_pin(GPIOPin *cs)
Definition spi.h:438
void set_mode(SPIMode mode)
Definition spi.h:444
void transfer_array(uint8_t *data, size_t length)
Write the array data, replace with received data.
Definition spi.h:479
void set_bit_order(SPIBitOrder order)
Definition spi.h:442
void set_spi_parent(SPIComponent *parent)
Definition spi.h:436
void transfer_array(std::array< uint8_t, N > &data)
Definition spi.h:505
uint8_t read_byte()
Definition spi.h:446
void write_byte(uint8_t data)
Definition spi.h:472
void write(uint16_t data, size_t num_bits)
Write a single data item, up to 32 bits.
Definition spi.h:455
void write_array16(const uint16_t *data, size_t length)
Write an array of data as 16 bit values, byte-swapping if required.
Definition spi.h:493
uint8_t transfer_byte(uint8_t data)
Definition spi.h:481
void write_array(const uint8_t *data, size_t length)
Definition spi.h:499
void write_array(const std::vector< uint8_t > &data)
Definition spi.h:503
void write_cmd_addr_data(size_t cmd_bits, uint32_t cmd, size_t addr_bits, uint32_t address, const uint8_t *data, size_t length, uint8_t bus_width=1)
Definition spi.h:467
SPIDevice(SPIComponent *parent, GPIOPin *cs_pin)
Definition spi.h:427
void spi_teardown() override
Definition spi.h:434
void read_array(uint8_t *data, size_t length)
Definition spi.h:448
static int get_pin_no(GPIOPin *pin)
Definition spi.h:132
static SPIClockPhase get_phase(SPIMode mode)
Definition spi.h:147
static SPIClockPolarity get_polarity(SPIMode mode)
Definition spi.h:157
static SPIMode get_mode(SPIClockPolarity polarity, SPIClockPhase phase)
Definition spi.h:140
uint16_t flags
@ FLAG_NONE
Definition gpio.h:17
const float BUS
For communication buses like i2c/spi.
Definition component.cpp:78
Implementation of SPI Controller mode.
Definition spi.cpp:5
SPIMode
Modes mapping to clock phase and polarity.
Definition spi.h:76
@ MODE0
Definition spi.h:77
@ MODE2
Definition spi.h:79
@ MODE1
Definition spi.h:78
@ MODE3
Definition spi.h:80
SPIDataRate
The SPI clock signal frequency, which determines the transfer bit rate/second.
Definition spi.h:87
@ DATA_RATE_200KHZ
Definition spi.h:90
@ DATA_RATE_20MHZ
Definition spi.h:97
@ DATA_RATE_1KHZ
Definition spi.h:88
@ DATA_RATE_2MHZ
Definition spi.h:92
@ DATA_RATE_5MHZ
Definition spi.h:94
@ DATA_RATE_8MHZ
Definition spi.h:95
@ DATA_RATE_80MHZ
Definition spi.h:99
@ DATA_RATE_10MHZ
Definition spi.h:96
@ DATA_RATE_4MHZ
Definition spi.h:93
@ DATA_RATE_1MHZ
Definition spi.h:91
@ DATA_RATE_40MHZ
Definition spi.h:98
@ DATA_RATE_75KHZ
Definition spi.h:89
SPIBitOrder
The bit-order for SPI devices. This defines how the data read from and written to the device is inter...
Definition spi.h:38
@ BIT_ORDER_LSB_FIRST
The least significant bit is transmitted/received first.
Definition spi.h:40
@ BIT_ORDER_MSB_FIRST
The most significant bit is transmitted/received first.
Definition spi.h:42
SPIClockPolarity
The SPI clock signal polarity,.
Definition spi.h:48
@ CLOCK_POLARITY_HIGH
The clock signal idles on HIGH.
Definition spi.h:58
@ CLOCK_POLARITY_LOW
The clock signal idles on LOW.
Definition spi.h:53
SPIClockPhase
The SPI clock signal phase.
Definition spi.h:64
@ CLOCK_PHASE_LEADING
The data is sampled on a leading clock edge. (CPHA=0)
Definition spi.h:66
@ CLOCK_PHASE_TRAILING
The data is sampled on a trailing clock edge. (CPHA=1)
Definition spi.h:68
uint32_t arch_get_cpu_cycle_count()
Definition core.cpp:50
uint32_t arch_get_cpu_freq_hz()
Definition core.cpp:51
spi_host_device_t SPIInterface
Definition spi.h:14
uint16_t length
Definition tt21100.cpp:0