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