ESPHome  2023.9.1
spi.h
Go to the documentation of this file.
1 #pragma once
2 
4 #include "esphome/core/hal.h"
5 #include "esphome/core/log.h"
7 #include <vector>
8 #include <map>
9 
10 #ifdef USE_ARDUINO
11 
12 #include <SPI.h>
13 
14 #ifdef USE_RP2040
15 using SPIInterface = SPIClassRP2040 *;
16 #else
17 using SPIInterface = SPIClass *;
18 #endif
19 
20 #endif
21 
22 #ifdef USE_ESP_IDF
23 
24 #include "driver/spi_master.h"
25 
26 using SPIInterface = spi_host_device_t;
27 
28 #endif // USE_ESP_IDF
29 
33 namespace esphome {
34 namespace spi {
35 
42 };
58 };
68 };
69 
75 enum SPIMode {
76  MODE0 = 0,
77  MODE1 = 1,
78  MODE2 = 2,
79  MODE3 = 3,
80 };
86 enum SPIDataRate : uint32_t {
88  DATA_RATE_75KHZ = 75000,
89  DATA_RATE_200KHZ = 200000,
90  DATA_RATE_1MHZ = 1000000,
91  DATA_RATE_2MHZ = 2000000,
92  DATA_RATE_4MHZ = 4000000,
93  DATA_RATE_5MHZ = 5000000,
94  DATA_RATE_8MHZ = 8000000,
95  DATA_RATE_10MHZ = 10000000,
96  DATA_RATE_20MHZ = 20000000,
97  DATA_RATE_40MHZ = 40000000,
98  DATA_RATE_80MHZ = 80000000,
99 };
100 
104 class NullPin : public GPIOPin {
105  friend class SPIComponent;
106 
107  friend class SPIDelegate;
108 
109  friend class Utility;
110 
111  public:
112  void setup() override {}
113 
114  void pin_mode(gpio::Flags flags) override {}
115 
116  bool digital_read() override { return false; }
117 
118  void digital_write(bool value) override {}
119 
120  std::string dump_summary() const override { return std::string(); }
121 
122  protected:
123  static GPIOPin *const NULL_PIN; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
124  // https://bugs.llvm.org/show_bug.cgi?id=48040
125 };
126 
127 class Utility {
128  public:
129  static int get_pin_no(GPIOPin *pin) {
130  if (pin == nullptr || !pin->is_internal())
131  return -1;
132  if (((InternalGPIOPin *) pin)->is_inverted())
133  return -1;
134  return ((InternalGPIOPin *) pin)->get_pin();
135  }
136 
137  static SPIMode get_mode(SPIClockPolarity polarity, SPIClockPhase phase) {
138  if (polarity == CLOCK_POLARITY_HIGH) {
139  return phase == CLOCK_PHASE_LEADING ? MODE2 : MODE3;
140  }
141  return phase == CLOCK_PHASE_LEADING ? MODE0 : MODE1;
142  }
143 
145  switch (mode) {
146  case MODE0:
147  case MODE2:
148  return CLOCK_PHASE_LEADING;
149  default:
150  return CLOCK_PHASE_TRAILING;
151  }
152  }
153 
155  switch (mode) {
156  case MODE0:
157  case MODE1:
158  return CLOCK_POLARITY_LOW;
159  default:
160  return CLOCK_POLARITY_HIGH;
161  }
162  }
163 };
164 
165 class SPIDelegateDummy;
166 
167 // represents a device attached to an SPI bus, with a defined clock rate, mode and bit order. On Arduino this is
168 // a thin wrapper over SPIClass.
169 class SPIDelegate {
170  friend class SPIClient;
171 
172  public:
173  SPIDelegate() = default;
174 
175  SPIDelegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin)
176  : bit_order_(bit_order), data_rate_(data_rate), mode_(mode), cs_pin_(cs_pin) {
177  if (this->cs_pin_ == nullptr)
178  this->cs_pin_ = NullPin::NULL_PIN;
179  this->cs_pin_->setup();
180  this->cs_pin_->digital_write(true);
181  }
182 
183  virtual ~SPIDelegate(){};
184 
185  // enable CS if configured.
186  virtual void begin_transaction() { this->cs_pin_->digital_write(false); }
187 
188  // end the transaction
189  virtual void end_transaction() { this->cs_pin_->digital_write(true); }
190 
191  // transfer one byte, return the byte that was read.
192  virtual uint8_t transfer(uint8_t data) = 0;
193 
194  // transfer a buffer, replace the contents with read data
195  virtual void transfer(uint8_t *ptr, size_t length) { this->transfer(ptr, ptr, length); }
196 
197  virtual void transfer(const uint8_t *txbuf, uint8_t *rxbuf, size_t length) {
198  for (size_t i = 0; i != length; i++)
199  rxbuf[i] = this->transfer(txbuf[i]);
200  }
201 
202  // write 16 bits
203  virtual void write16(uint16_t data) {
204  if (this->bit_order_ == BIT_ORDER_MSB_FIRST) {
205  uint16_t buffer;
206  buffer = (data >> 8) | (data << 8);
207  this->write_array(reinterpret_cast<const uint8_t *>(&buffer), 2);
208  } else {
209  this->write_array(reinterpret_cast<const uint8_t *>(&data), 2);
210  }
211  }
212 
213  virtual void write_array16(const uint16_t *data, size_t length) {
214  for (size_t i = 0; i != length; i++) {
215  this->write16(data[i]);
216  }
217  }
218 
219  // write the contents of a buffer, ignore read data (buffer is unchanged.)
220  virtual void write_array(const uint8_t *ptr, size_t length) {
221  for (size_t i = 0; i != length; i++)
222  this->transfer(ptr[i]);
223  }
224 
225  // read into a buffer, write nulls
226  virtual void read_array(uint8_t *ptr, size_t length) {
227  for (size_t i = 0; i != length; i++)
228  ptr[i] = this->transfer(0);
229  }
230 
231  // check if device is ready
232  virtual bool is_ready();
233 
234  protected:
236  uint32_t data_rate_{1000000};
237  SPIMode mode_{MODE0};
239  static SPIDelegate *const NULL_DELEGATE; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
240 };
241 
247  public:
248  SPIDelegateDummy() = default;
249 
250  uint8_t transfer(uint8_t data) override { return 0; }
251 
252  void begin_transaction() override;
253 };
254 
260  public:
261  SPIDelegateBitBash(uint32_t clock, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, GPIOPin *clk_pin,
262  GPIOPin *sdo_pin, GPIOPin *sdi_pin)
263  : SPIDelegate(clock, bit_order, mode, cs_pin), clk_pin_(clk_pin), sdo_pin_(sdo_pin), sdi_pin_(sdi_pin) {
264  // this calculation is pretty meaningless except at very low bit rates.
265  this->wait_cycle_ = uint32_t(arch_get_cpu_freq_hz()) / this->data_rate_ / 2ULL;
266  this->clock_polarity_ = Utility::get_polarity(this->mode_);
267  this->clock_phase_ = Utility::get_phase(this->mode_);
268  }
269 
270  uint8_t transfer(uint8_t data) override;
271 
272  protected:
276  uint32_t last_transition_{0};
277  uint32_t wait_cycle_;
280 
281  void HOT cycle_clock_() {
282  while (this->last_transition_ - arch_get_cpu_cycle_count() < this->wait_cycle_)
283  continue;
284  this->last_transition_ += this->wait_cycle_;
285  }
286 };
287 
288 class SPIBus {
289  public:
290  SPIBus() = default;
291 
292  SPIBus(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi) : clk_pin_(clk), sdo_pin_(sdo), sdi_pin_(sdi) {}
293 
294  virtual SPIDelegate *get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin) {
295  return new SPIDelegateBitBash(data_rate, bit_order, mode, cs_pin, this->clk_pin_, this->sdo_pin_, this->sdi_pin_);
296  }
297 
298  virtual bool is_hw() { return false; }
299 
300  protected:
301  GPIOPin *clk_pin_{};
302  GPIOPin *sdo_pin_{};
303  GPIOPin *sdi_pin_{};
304 };
305 
306 class SPIClient;
307 
308 class SPIComponent : public Component {
309  public:
310  SPIDelegate *register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate,
311  GPIOPin *cs_pin);
312  void unregister_device(SPIClient *device);
313 
314  void set_clk(GPIOPin *clk) { this->clk_pin_ = clk; }
315 
316  void set_miso(GPIOPin *sdi) { this->sdi_pin_ = sdi; }
317 
318  void set_mosi(GPIOPin *sdo) { this->sdo_pin_ = sdo; }
319 
320  void set_interface(SPIInterface interface) {
321  this->interface_ = interface;
322  this->using_hw_ = true;
323  }
324 
325  void set_interface_name(const char *name) { this->interface_name_ = name; }
326 
327  float get_setup_priority() const override { return setup_priority::BUS; }
328 
329  void setup() override;
330  void dump_config() override;
331 
332  protected:
333  GPIOPin *clk_pin_{nullptr};
334  GPIOPin *sdi_pin_{nullptr};
335  GPIOPin *sdo_pin_{nullptr};
336  SPIInterface interface_{};
337  bool using_hw_{false};
338  const char *interface_name_{nullptr};
339  SPIBus *spi_bus_{};
340  std::map<SPIClient *, SPIDelegate *> devices_;
341 
342  static SPIBus *get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi);
343 };
344 
348 class SPIClient {
349  public:
350  SPIClient(SPIBitOrder bit_order, SPIMode mode, uint32_t data_rate)
351  : bit_order_(bit_order), mode_(mode), data_rate_(data_rate) {}
352 
353  virtual void spi_setup() {
354  esph_log_d("spi_device", "mode %u, data_rate %ukHz", (unsigned) this->mode_, (unsigned) (this->data_rate_ / 1000));
355  this->delegate_ = this->parent_->register_device(this, this->mode_, this->bit_order_, this->data_rate_, this->cs_);
356  }
357 
358  virtual void spi_teardown() {
359  this->parent_->unregister_device(this);
360  this->delegate_ = SPIDelegate::NULL_DELEGATE;
361  }
362 
363  bool spi_is_ready() { return this->delegate_->is_ready(); }
364 
365  protected:
367  SPIMode mode_{MODE0};
368  uint32_t data_rate_{1000000};
369  SPIComponent *parent_{nullptr};
370  GPIOPin *cs_{nullptr};
372 };
373 
382 template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, SPIDataRate DATA_RATE>
383 class SPIDevice : public SPIClient {
384  public:
385  SPIDevice() : SPIClient(BIT_ORDER, Utility::get_mode(CLOCK_POLARITY, CLOCK_PHASE), DATA_RATE) {}
386 
387  SPIDevice(SPIComponent *parent, GPIOPin *cs_pin) {
388  this->set_spi_parent(parent);
389  this->set_cs_pin(cs_pin);
390  }
391 
392  void spi_setup() override { SPIClient::spi_setup(); }
393 
394  void spi_teardown() override { SPIClient::spi_teardown(); }
395 
396  void set_spi_parent(SPIComponent *parent) { this->parent_ = parent; }
397 
398  void set_cs_pin(GPIOPin *cs) { this->cs_ = cs; }
399 
400  void set_data_rate(uint32_t data_rate) { this->data_rate_ = data_rate; }
401 
402  void set_bit_order(SPIBitOrder order) { this->bit_order_ = order; }
403 
404  void set_mode(SPIMode mode) { this->mode_ = mode; }
405 
406  uint8_t read_byte() { return this->delegate_->transfer(0); }
407 
408  void read_array(uint8_t *data, size_t length) { return this->delegate_->read_array(data, length); }
409 
410  void write_byte(uint8_t data) { this->delegate_->write_array(&data, 1); }
411 
412  void transfer_array(uint8_t *data, size_t length) { this->delegate_->transfer(data, length); }
413 
414  uint8_t transfer_byte(uint8_t data) { return this->delegate_->transfer(data); }
415 
416  // the driver will byte-swap if required.
417  void write_byte16(uint16_t data) { this->delegate_->write16(data); }
418 
419  // avoid use of this if possible. It's inefficient and ugly.
420  void write_array16(const uint16_t *data, size_t length) { this->delegate_->write_array16(data, length); }
421 
422  void enable() { this->delegate_->begin_transaction(); }
423 
424  void disable() { this->delegate_->end_transaction(); }
425 
426  void write_array(const uint8_t *data, size_t length) { this->delegate_->write_array(data, length); }
427 
428  template<size_t N> void write_array(const std::array<uint8_t, N> &data) { this->write_array(data.data(), N); }
429 
430  void write_array(const std::vector<uint8_t> &data) { this->write_array(data.data(), data.size()); }
431 
432  template<size_t N> void transfer_array(std::array<uint8_t, N> &data) { this->transfer_array(data.data(), N); }
433 };
434 
435 } // namespace spi
436 } // namespace esphome
void write_array16(const uint16_t *data, size_t length)
Definition: spi.h:420
virtual void spi_teardown()
Definition: spi.h:358
void transfer_array(uint8_t *data, size_t length)
Definition: spi.h:412
const char * name
Definition: stm32flash.h:78
SPIClassRP2040 * SPIInterface
Definition: spi.h:15
virtual void read_array(uint8_t *ptr, size_t length)
Definition: spi.h:226
SPIClockPolarity clock_polarity_
Definition: spi.h:278
SPIDataRate
The SPI clock signal frequency, which determines the transfer bit rate/second.
Definition: spi.h:86
virtual void transfer(uint8_t *ptr, size_t length)
Definition: spi.h:195
void spi_setup() override
Definition: spi.h:392
friend class SPIDelegate
Definition: spi.h:107
The data is sampled on a leading clock edge. (CPHA=0)
Definition: spi.h:65
void set_mosi(GPIOPin *sdo)
Definition: spi.h:318
std::string dump_summary() const override
Definition: spi.h:120
The clock signal idles on HIGH.
Definition: spi.h:57
A pin to replace those that don&#39;t exist.
Definition: spi.h:104
static SPIMode get_mode(SPIClockPolarity polarity, SPIClockPhase phase)
Definition: spi.h:137
std::map< SPIClient *, SPIDelegate * > devices_
Definition: spi.h:340
void pin_mode(gpio::Flags flags) override
Definition: spi.h:114
SPIDelegateBitBash(uint32_t clock, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, GPIOPin *clk_pin, GPIOPin *sdo_pin, GPIOPin *sdi_pin)
Definition: spi.h:261
The most significant bit is transmitted/received first.
Definition: spi.h:41
virtual bool is_hw()
Definition: spi.h:298
void set_cs_pin(GPIOPin *cs)
Definition: spi.h:398
uint8_t transfer_byte(uint8_t data)
Definition: spi.h:414
The clock signal idles on LOW.
Definition: spi.h:52
virtual void setup()=0
void write_array(const std::vector< uint8_t > &data)
Definition: spi.h:430
void write_byte(uint8_t data)
Definition: spi.h:410
bool spi_is_ready()
Definition: spi.h:363
void spi_teardown() override
Definition: spi.h:394
SPIClockPolarity
The SPI clock signal polarity,.
Definition: spi.h:47
uint8_t read_byte()
Definition: spi.h:406
static int get_pin_no(GPIOPin *pin)
Definition: spi.h:129
The SPIDevice is what components using the SPI will create.
Definition: spi.h:383
bool digital_read() override
Definition: spi.h:116
virtual void spi_setup()
Definition: spi.h:353
void write_array(const std::array< uint8_t, N > &data)
Definition: spi.h:428
void read_array(uint8_t *data, size_t length)
Definition: spi.h:408
const float BUS
For communication buses like i2c/spi.
Definition: component.cpp:15
The data is sampled on a trailing clock edge. (CPHA=1)
Definition: spi.h:67
virtual bool is_internal()
Definition: gpio.h:62
void setup() override
Definition: spi.h:112
BedjetMode mode
BedJet operating mode.
Definition: bedjet_codec.h:151
virtual void transfer(const uint8_t *txbuf, uint8_t *rxbuf, size_t length)
Definition: spi.h:197
SPIMode
Modes mapping to clock phase and polarity.
Definition: spi.h:75
void set_mode(SPIMode mode)
Definition: spi.h:404
uint32_t arch_get_cpu_freq_hz()
Definition: core.cpp:61
uint8_t transfer(uint8_t data) override
Definition: spi.h:250
virtual void end_transaction()
Definition: spi.h:189
void set_miso(GPIOPin *sdi)
Definition: spi.h:316
Base class for SPIDevice, un-templated.
Definition: spi.h:348
virtual void begin_transaction()
Definition: spi.h:186
SPIClient(SPIBitOrder bit_order, SPIMode mode, uint32_t data_rate)
Definition: spi.h:350
virtual void write16(uint16_t data)
Definition: spi.h:203
void set_bit_order(SPIBitOrder order)
Definition: spi.h:402
virtual ~SPIDelegate()
Definition: spi.h:183
const uint32_t flags
Definition: stm32flash.h:85
static SPIClockPolarity get_polarity(SPIMode mode)
Definition: spi.h:154
static SPIDelegate *const NULL_DELEGATE
Definition: spi.h:239
virtual SPIDelegate * get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin)
Definition: spi.h:294
SPIClockPhase clock_phase_
Definition: spi.h:279
An implementation of SPI that relies only on software toggling of pins.
Definition: spi.h:259
void transfer_array(std::array< uint8_t, N > &data)
Definition: spi.h:432
SPIBitOrder
The bit-order for SPI devices. This defines how the data read from and written to the device is inter...
Definition: spi.h:37
void set_interface(SPIInterface interface)
Definition: spi.h:320
A dummy SPIDelegate that complains if it&#39;s used.
Definition: spi.h:246
void write_array(const uint8_t *data, size_t length)
Definition: spi.h:426
uint16_t length
Definition: tt21100.cpp:12
SPIDelegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin)
Definition: spi.h:175
virtual void write_array(const uint8_t *ptr, size_t length)
Definition: spi.h:220
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
The least significant bit is transmitted/received first.
Definition: spi.h:39
void set_spi_parent(SPIComponent *parent)
Definition: spi.h:396
SPIClockPhase
The SPI clock signal phase.
Definition: spi.h:63
SPIBus(GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi)
Definition: spi.h:292
void set_interface_name(const char *name)
Definition: spi.h:325
void write_byte16(uint16_t data)
Definition: spi.h:417
void set_data_rate(uint32_t data_rate)
Definition: spi.h:400
void digital_write(bool value) override
Definition: spi.h:118
void set_clk(GPIOPin *clk)
Definition: spi.h:314
static GPIOPin *const NULL_PIN
Definition: spi.h:123
uint32_t arch_get_cpu_cycle_count()
Definition: core.cpp:57
SPIDevice(SPIComponent *parent, GPIOPin *cs_pin)
Definition: spi.h:387
static SPIClockPhase get_phase(SPIMode mode)
Definition: spi.h:144
virtual void write_array16(const uint16_t *data, size_t length)
Definition: spi.h:213
float get_setup_priority() const override
Definition: spi.h:327