ESPHome  2025.2.0
spi.h
Go to the documentation of this file.
1 #pragma once
2 
5 #include "esphome/core/hal.h"
6 #include "esphome/core/log.h"
7 #include <map>
8 #include <utility>
9 #include <vector>
10 
11 #ifdef USE_ARDUINO
12 
13 #include <SPI.h>
14 
15 #ifdef USE_RP2040
16 using SPIInterface = SPIClassRP2040 *;
17 #else
18 using SPIInterface = SPIClass *;
19 #endif
20 
21 #endif
22 
23 #ifdef USE_ESP_IDF
24 
25 #include "driver/spi_master.h"
26 
27 using SPIInterface = spi_host_device_t;
28 
29 #endif // USE_ESP_IDF
30 
34 namespace esphome {
35 namespace spi {
36 
43 };
59 };
69 };
70 
76 enum SPIMode {
77  MODE0 = 0,
78  MODE1 = 1,
79  MODE2 = 2,
80  MODE3 = 3,
81 };
87 enum SPIDataRate : uint32_t {
89  DATA_RATE_75KHZ = 75000,
90  DATA_RATE_200KHZ = 200000,
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 
105 class 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 
130 class 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 
140  static SPIMode get_mode(SPIClockPolarity polarity, SPIClockPhase phase) {
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:
153  return CLOCK_PHASE_TRAILING;
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 
168 class 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.
172 class SPIDelegate {
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)
181  this->cs_pin_ = NullPin::NULL_PIN;
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};
253  SPIMode mode_{MODE0};
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;
283  this->clock_polarity_ = Utility::get_polarity(this->mode_);
284  this->clock_phase_ = Utility::get_phase(this->mode_);
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:
294  GPIOPin *clk_pin_;
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 
310 class 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  return new SPIDelegateBitBash(data_rate, bit_order, mode, cs_pin, this->clk_pin_, this->sdo_pin_, this->sdi_pin_);
318  }
319 
320  virtual bool is_hw() { return false; }
321 
322  protected:
323  GPIOPin *clk_pin_{};
324  GPIOPin *sdo_pin_{};
325  GPIOPin *sdi_pin_{};
326 };
327 
328 class SPIClient;
329 
330 class SPIComponent : public Component {
331  public:
332  SPIDelegate *register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate,
333  GPIOPin *cs_pin);
334  void unregister_device(SPIClient *device);
335 
336  void set_clk(GPIOPin *clk) { this->clk_pin_ = clk; }
337 
338  void set_miso(GPIOPin *sdi) { this->sdi_pin_ = sdi; }
339 
340  void set_mosi(GPIOPin *sdo) { this->sdo_pin_ = sdo; }
341  void set_data_pins(std::vector<uint8_t> pins) { this->data_pins_ = std::move(pins); }
342 
343  void set_interface(SPIInterface interface) {
344  this->interface_ = interface;
345  this->using_hw_ = true;
346  }
347 
348  void set_interface_name(const char *name) { this->interface_name_ = name; }
349 
350  float get_setup_priority() const override { return setup_priority::BUS; }
351 
352  void setup() override;
353  void dump_config() override;
354 
355  protected:
356  GPIOPin *clk_pin_{nullptr};
357  GPIOPin *sdi_pin_{nullptr};
358  GPIOPin *sdo_pin_{nullptr};
359  std::vector<uint8_t> data_pins_{};
360 
361  SPIInterface interface_{};
362  bool using_hw_{false};
363  const char *interface_name_{nullptr};
364  SPIBus *spi_bus_{};
365  std::map<SPIClient *, SPIDelegate *> devices_;
366 
367  static SPIBus *get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi,
368  const std::vector<uint8_t> &data_pins);
369 };
370 
375 class SPIClient {
376  public:
377  SPIClient(SPIBitOrder bit_order, SPIMode mode, uint32_t data_rate)
378  : bit_order_(bit_order), mode_(mode), data_rate_(data_rate) {}
379 
380  virtual void spi_setup() {
381  esph_log_d("spi_device", "mode %u, data_rate %ukHz", (unsigned) this->mode_, (unsigned) (this->data_rate_ / 1000));
382  this->delegate_ = this->parent_->register_device(this, this->mode_, this->bit_order_, this->data_rate_, this->cs_);
383  }
384 
385  virtual void spi_teardown() {
386  this->parent_->unregister_device(this);
387  this->delegate_ = SPIDelegate::NULL_DELEGATE;
388  }
389 
390  bool spi_is_ready() { return this->delegate_->is_ready(); }
391 
392  protected:
394  SPIMode mode_{MODE0};
395  uint32_t data_rate_{1000000};
396  SPIComponent *parent_{nullptr};
397  GPIOPin *cs_{nullptr};
399 };
400 
409 template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, SPIDataRate DATA_RATE>
410 class SPIDevice : public SPIClient {
411  public:
412  SPIDevice() : SPIClient(BIT_ORDER, Utility::get_mode(CLOCK_POLARITY, CLOCK_PHASE), DATA_RATE) {}
413 
414  SPIDevice(SPIComponent *parent, GPIOPin *cs_pin) {
415  this->set_spi_parent(parent);
416  this->set_cs_pin(cs_pin);
417  }
418 
419  void spi_setup() override { SPIClient::spi_setup(); }
420 
421  void spi_teardown() override { SPIClient::spi_teardown(); }
422 
423  void set_spi_parent(SPIComponent *parent) { this->parent_ = parent; }
424 
425  void set_cs_pin(GPIOPin *cs) { this->cs_ = cs; }
426 
427  void set_data_rate(uint32_t data_rate) { this->data_rate_ = data_rate; }
428 
429  void set_bit_order(SPIBitOrder order) { this->bit_order_ = order; }
430 
431  void set_mode(SPIMode mode) { this->mode_ = mode; }
432 
433  uint8_t read_byte() { return this->delegate_->transfer(0); }
434 
435  void read_array(uint8_t *data, size_t length) { return this->delegate_->read_array(data, length); }
436 
442  void write(uint16_t data, size_t num_bits) { this->delegate_->write(data, num_bits); };
443 
444  /* Write command, address and data. Command and address will be written as single-bit SPI,
445  * data phase can be multiple bit (currently only 1 or 4)
446  * @param cmd_bits Number of bits to write in the command phase
447  * @param cmd The command value to write
448  * @param addr_bits Number of bits to write in addr phase
449  * @param address Address data
450  * @param data Plain data bytes
451  * @param length Number of data bytes
452  * @param bus_width The number of data lines to use for the data phase.
453  */
454  void write_cmd_addr_data(size_t cmd_bits, uint32_t cmd, size_t addr_bits, uint32_t address, const uint8_t *data,
455  size_t length, uint8_t bus_width = 1) {
456  this->delegate_->write_cmd_addr_data(cmd_bits, cmd, addr_bits, address, data, length, bus_width);
457  }
458 
459  void write_byte(uint8_t data) { this->delegate_->write_array(&data, 1); }
460 
466  void transfer_array(uint8_t *data, size_t length) { this->delegate_->transfer(data, length); }
467 
468  uint8_t transfer_byte(uint8_t data) { return this->delegate_->transfer(data); }
469 
472  void write_byte16(uint16_t data) { this->delegate_->write16(data); }
473 
480  void write_array16(const uint16_t *data, size_t length) { this->delegate_->write_array16(data, length); }
481 
482  void enable() { this->delegate_->begin_transaction(); }
483 
484  void disable() { this->delegate_->end_transaction(); }
485 
486  void write_array(const uint8_t *data, size_t length) { this->delegate_->write_array(data, length); }
487 
488  template<size_t N> void write_array(const std::array<uint8_t, N> &data) { this->write_array(data.data(), N); }
489 
490  void write_array(const std::vector<uint8_t> &data) { this->write_array(data.data(), data.size()); }
491 
492  template<size_t N> void transfer_array(std::array<uint8_t, N> &data) { this->transfer_array(data.data(), N); }
493 };
494 
495 } // namespace spi
496 } // namespace esphome
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:480
virtual void spi_teardown()
Definition: spi.h:385
void transfer_array(uint8_t *data, size_t length)
Write the array data, replace with received data.
Definition: spi.h:466
const char * name
Definition: stm32flash.h:78
SPIClassRP2040 * SPIInterface
Definition: spi.h:16
virtual void read_array(uint8_t *ptr, size_t length)
Definition: spi.h:242
SPIClockPolarity clock_polarity_
Definition: spi.h:299
SPIDataRate
The SPI clock signal frequency, which determines the transfer bit rate/second.
Definition: spi.h:87
virtual void transfer(uint8_t *ptr, size_t length)
Definition: spi.h:198
void spi_setup() override
Definition: spi.h:419
friend class SPIDelegate
Definition: spi.h:108
The data is sampled on a leading clock edge. (CPHA=0)
Definition: spi.h:66
void set_mosi(GPIOPin *sdo)
Definition: spi.h:340
std::string dump_summary() const override
Definition: spi.h:123
The clock signal idles on HIGH.
Definition: spi.h:58
A pin to replace those that don&#39;t exist.
Definition: spi.h:105
static SPIMode get_mode(SPIClockPolarity polarity, SPIClockPhase phase)
Definition: spi.h:140
std::map< SPIClient *, SPIDelegate * > devices_
Definition: spi.h:365
void pin_mode(gpio::Flags flags) override
Definition: spi.h:115
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
The most significant bit is transmitted/received first.
Definition: spi.h:42
virtual bool is_hw()
Definition: spi.h:320
virtual void write(uint16_t data, size_t num_bits)
write a variable length data item, up to 16 bits.
Definition: spi.h:210
void set_cs_pin(GPIOPin *cs)
Definition: spi.h:425
void end_transaction() override
Definition: spi.h:267
uint8_t transfer_byte(uint8_t data)
Definition: spi.h:468
The clock signal idles on LOW.
Definition: spi.h:53
virtual void setup()=0
void write_array(const std::vector< uint8_t > &data)
Definition: spi.h:490
void write_byte(uint8_t data)
Definition: spi.h:459
bool spi_is_ready()
Definition: spi.h:390
void spi_teardown() override
Definition: spi.h:421
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:454
SPIClockPolarity
The SPI clock signal polarity,.
Definition: spi.h:48
uint8_t read_byte()
Definition: spi.h:433
static int get_pin_no(GPIOPin *pin)
Definition: spi.h:132
The SPIDevice is what components using the SPI will create.
Definition: spi.h:410
bool digital_read() override
Definition: spi.h:119
virtual void spi_setup()
Definition: spi.h:380
void write_array(const std::array< uint8_t, N > &data)
Definition: spi.h:488
void read_array(uint8_t *data, size_t length)
Definition: spi.h:435
const float BUS
For communication buses like i2c/spi.
Definition: component.cpp:16
The data is sampled on a trailing clock edge. (CPHA=1)
Definition: spi.h:68
virtual bool is_internal()
Definition: gpio.h:69
void write(uint16_t data, size_t num_bits)
Write a single data item, up to 32 bits.
Definition: spi.h:442
void setup() override
Definition: spi.h:113
BedjetMode mode
BedJet operating mode.
Definition: bedjet_codec.h:183
virtual void transfer(const uint8_t *txbuf, uint8_t *rxbuf, size_t length)
Definition: spi.h:200
SPIMode
Modes mapping to clock phase and polarity.
Definition: spi.h:76
void set_mode(SPIMode mode)
Definition: spi.h:431
uint32_t arch_get_cpu_freq_hz()
Definition: core.cpp:61
uint8_t transfer(uint8_t data) override
Definition: spi.h:266
virtual void end_transaction()
Definition: spi.h:192
void set_miso(GPIOPin *sdi)
Definition: spi.h:338
Base class for SPIDevice, un-templated.
Definition: spi.h:375
virtual void begin_transaction()
Definition: spi.h:189
SPIClient(SPIBitOrder bit_order, SPIMode mode, uint32_t data_rate)
Definition: spi.h:377
virtual void write16(uint16_t data)
Definition: spi.h:219
void set_bit_order(SPIBitOrder order)
Definition: spi.h:429
virtual ~SPIDelegate()
Definition: spi.h:186
const uint32_t flags
Definition: stm32flash.h:85
static SPIClockPolarity get_polarity(SPIMode mode)
Definition: spi.h:157
static SPIDelegate *const NULL_DELEGATE
Definition: spi.h:255
virtual SPIDelegate * get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin)
Definition: spi.h:316
void set_data_pins(std::vector< uint8_t > pins)
Definition: spi.h:341
SPIClockPhase clock_phase_
Definition: spi.h:300
An implementation of SPI that relies only on software toggling of pins.
Definition: spi.h:276
void transfer_array(std::array< uint8_t, N > &data)
Definition: spi.h:492
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
void set_interface(SPIInterface interface)
Definition: spi.h:343
A dummy SPIDelegate that complains if it&#39;s used.
Definition: spi.h:262
void write_array(const uint8_t *data, size_t length)
Definition: spi.h:486
uint16_t length
Definition: tt21100.cpp:12
gpio::Flags get_flags() const override
Definition: spi.h:117
SPIDelegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin)
Definition: spi.h:178
virtual void write_array(const uint8_t *ptr, size_t length)
Definition: spi.h:236
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
friend class SPIComponent
Definition: spi.h:106
The least significant bit is transmitted/received first.
Definition: spi.h:40
uint8_t address
Definition: bl0906.h:211
void set_spi_parent(SPIComponent *parent)
Definition: spi.h:423
SPIClockPhase
The SPI clock signal phase.
Definition: spi.h:64
SPIBus(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi)
Definition: spi.h:314
void set_interface_name(const char *name)
Definition: spi.h:348
void write_byte16(uint16_t data)
Write 16 bit data.
Definition: spi.h:472
void set_data_rate(uint32_t data_rate)
Definition: spi.h:427
void digital_write(bool value) override
Definition: spi.h:121
void set_clk(GPIOPin *clk)
Definition: spi.h:336
static GPIOPin *const NULL_PIN
Definition: spi.h:126
uint32_t arch_get_cpu_cycle_count()
Definition: core.cpp:57
void write16(uint16_t data) override
Definition: spi.h:291
SPIDevice(SPIComponent *parent, GPIOPin *cs_pin)
Definition: spi.h:414
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
stm32_cmd_t * cmd
Definition: stm32flash.h:96
static SPIClockPhase get_phase(SPIMode mode)
Definition: spi.h:147
virtual void write_array16(const uint16_t *data, size_t length)
Definition: spi.h:229
float get_setup_priority() const override
Definition: spi.h:350