ESPHome  2023.5.5
spi.h
Go to the documentation of this file.
1 #pragma once
2 
4 #include "esphome/core/hal.h"
5 #include <vector>
6 
7 #ifdef USE_ARDUINO
8 #define USE_SPI_ARDUINO_BACKEND
9 #endif
10 
11 #ifdef USE_SPI_ARDUINO_BACKEND
12 #include <SPI.h>
13 #endif
14 
15 namespace esphome {
16 namespace spi {
17 
24 };
40 };
50 };
59 enum SPIDataRate : uint32_t {
61  DATA_RATE_75KHZ = 75000,
62  DATA_RATE_200KHZ = 200000,
63  DATA_RATE_1MHZ = 1000000,
64  DATA_RATE_2MHZ = 2000000,
65  DATA_RATE_4MHZ = 4000000,
66  DATA_RATE_8MHZ = 8000000,
67  DATA_RATE_10MHZ = 10000000,
68  DATA_RATE_20MHZ = 20000000,
69  DATA_RATE_40MHZ = 40000000,
70 };
71 
72 class SPIComponent : public Component {
73  public:
74  void set_clk(GPIOPin *clk) { clk_ = clk; }
75  void set_miso(GPIOPin *miso) { miso_ = miso; }
76  void set_mosi(GPIOPin *mosi) { mosi_ = mosi; }
77  void set_force_sw(bool force_sw) { force_sw_ = force_sw; }
78 
79  void setup() override;
80 
81  void dump_config() override;
82 
83  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE> uint8_t read_byte() {
84 #ifdef USE_SPI_ARDUINO_BACKEND
85  if (this->hw_spi_ != nullptr) {
86  return this->hw_spi_->transfer(0x00);
87  }
88 #endif // USE_SPI_ARDUINO_BACKEND
89  return this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, true, false>(0x00);
90  }
91 
92  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
93  void read_array(uint8_t *data, size_t length) {
94 #ifdef USE_SPI_ARDUINO_BACKEND
95  if (this->hw_spi_ != nullptr) {
96  this->hw_spi_->transfer(data, length);
97  return;
98  }
99 #endif // USE_SPI_ARDUINO_BACKEND
100  for (size_t i = 0; i < length; i++) {
101  data[i] = this->read_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>();
102  }
103  }
104 
105  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
106  void write_byte(uint8_t data) {
107 #ifdef USE_SPI_ARDUINO_BACKEND
108  if (this->hw_spi_ != nullptr) {
109 #ifdef USE_RP2040
110  this->hw_spi_->transfer(data);
111 #else
112  this->hw_spi_->write(data);
113 #endif
114  return;
115  }
116 #endif // USE_SPI_ARDUINO_BACKEND
117  this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, false, true>(data);
118  }
119 
120  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
121  void write_byte16(const uint16_t data) {
122 #ifdef USE_SPI_ARDUINO_BACKEND
123  if (this->hw_spi_ != nullptr) {
124 #ifdef USE_RP2040
125  this->hw_spi_->transfer16(data);
126 #else
127  this->hw_spi_->write16(data);
128 #endif
129  return;
130  }
131 #endif // USE_SPI_ARDUINO_BACKEND
132 
133  this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data >> 8);
134  this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
135  }
136 
137  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
138  void write_array16(const uint16_t *data, size_t length) {
139 #ifdef USE_SPI_ARDUINO_BACKEND
140  if (this->hw_spi_ != nullptr) {
141  for (size_t i = 0; i < length; i++) {
142 #ifdef USE_RP2040
143  this->hw_spi_->transfer16(data[i]);
144 #else
145  this->hw_spi_->write16(data[i]);
146 #endif
147  }
148  return;
149  }
150 #endif // USE_SPI_ARDUINO_BACKEND
151  for (size_t i = 0; i < length; i++) {
152  this->write_byte16<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data[i]);
153  }
154  }
155 
156  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
157  void write_array(const uint8_t *data, size_t length) {
158 #ifdef USE_SPI_ARDUINO_BACKEND
159  if (this->hw_spi_ != nullptr) {
160  auto *data_c = const_cast<uint8_t *>(data);
161 #ifdef USE_RP2040
162  this->hw_spi_->transfer(data_c, length);
163 #else
164  this->hw_spi_->writeBytes(data_c, length);
165 #endif
166  return;
167  }
168 #endif // USE_SPI_ARDUINO_BACKEND
169  for (size_t i = 0; i < length; i++) {
170  this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data[i]);
171  }
172  }
173 
174  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
175  uint8_t transfer_byte(uint8_t data) {
176  if (this->miso_ != nullptr) {
177 #ifdef USE_SPI_ARDUINO_BACKEND
178  if (this->hw_spi_ != nullptr) {
179  return this->hw_spi_->transfer(data);
180  } else {
181 #endif // USE_SPI_ARDUINO_BACKEND
182  return this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, true, true>(data);
183 #ifdef USE_SPI_ARDUINO_BACKEND
184  }
185 #endif // USE_SPI_ARDUINO_BACKEND
186  }
187  this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
188  return 0;
189  }
190 
191  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
192  void transfer_array(uint8_t *data, size_t length) {
193 #ifdef USE_SPI_ARDUINO_BACKEND
194  if (this->hw_spi_ != nullptr) {
195  if (this->miso_ != nullptr) {
196  this->hw_spi_->transfer(data, length);
197  } else {
198 #ifdef USE_RP2040
199  this->hw_spi_->transfer(data, length);
200 #else
201  this->hw_spi_->writeBytes(data, length);
202 #endif
203  }
204  return;
205  }
206 #endif // USE_SPI_ARDUINO_BACKEND
207 
208  if (this->miso_ != nullptr) {
209  for (size_t i = 0; i < length; i++) {
210  data[i] = this->transfer_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data[i]);
211  }
212  } else {
213  this->write_array<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
214  }
215  }
216 
217  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, uint32_t DATA_RATE>
218  void enable(GPIOPin *cs) {
219 #ifdef USE_SPI_ARDUINO_BACKEND
220  if (this->hw_spi_ != nullptr) {
221  uint8_t data_mode = SPI_MODE0;
222  if (!CLOCK_POLARITY && CLOCK_PHASE) {
223  data_mode = SPI_MODE1;
224  } else if (CLOCK_POLARITY && !CLOCK_PHASE) {
225  data_mode = SPI_MODE2;
226  } else if (CLOCK_POLARITY && CLOCK_PHASE) {
227  data_mode = SPI_MODE3;
228  }
229 #ifdef USE_RP2040
230  SPISettings settings(DATA_RATE, static_cast<BitOrder>(BIT_ORDER), data_mode);
231 #else
232  SPISettings settings(DATA_RATE, BIT_ORDER, data_mode);
233 #endif
234  this->hw_spi_->beginTransaction(settings);
235  } else {
236 #endif // USE_SPI_ARDUINO_BACKEND
237  this->clk_->digital_write(CLOCK_POLARITY);
238  uint32_t cpu_freq_hz = arch_get_cpu_freq_hz();
239  this->wait_cycle_ = uint32_t(cpu_freq_hz) / DATA_RATE / 2ULL;
240 #ifdef USE_SPI_ARDUINO_BACKEND
241  }
242 #endif // USE_SPI_ARDUINO_BACKEND
243 
244  if (cs != nullptr) {
245  this->active_cs_ = cs;
246  this->active_cs_->digital_write(false);
247  }
248  }
249 
250  void disable();
251 
252  float get_setup_priority() const override;
253 
254  protected:
255  inline void cycle_clock_(bool value);
256 
257  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, bool READ, bool WRITE>
258  uint8_t transfer_(uint8_t data);
259 
261  GPIOPin *miso_{nullptr};
262  GPIOPin *mosi_{nullptr};
263  GPIOPin *active_cs_{nullptr};
264  bool force_sw_{false};
265 #ifdef USE_SPI_ARDUINO_BACKEND
266  SPIClass *hw_spi_{nullptr};
267 #endif // USE_SPI_ARDUINO_BACKEND
268  uint32_t wait_cycle_;
269 };
270 
271 template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, SPIDataRate DATA_RATE>
272 class SPIDevice {
273  public:
274  SPIDevice() = default;
275  SPIDevice(SPIComponent *parent, GPIOPin *cs) : parent_(parent), cs_(cs) {}
276 
277  void set_spi_parent(SPIComponent *parent) { parent_ = parent; }
278  void set_cs_pin(GPIOPin *cs) { cs_ = cs; }
279 
280  void spi_setup() {
281  if (this->cs_) {
282  this->cs_->setup();
283  this->cs_->digital_write(true);
284  }
285  }
286 
287  void enable() { this->parent_->template enable<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, DATA_RATE>(this->cs_); }
288 
289  void disable() { this->parent_->disable(); }
290 
291  uint8_t read_byte() { return this->parent_->template read_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(); }
292 
293  void read_array(uint8_t *data, size_t length) {
294  return this->parent_->template read_array<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
295  }
296 
297  template<size_t N> std::array<uint8_t, N> read_array() {
298  std::array<uint8_t, N> data;
299  this->read_array(data.data(), N);
300  return data;
301  }
302 
303  void write_byte(uint8_t data) {
304  return this->parent_->template write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
305  }
306 
307  void write_byte16(uint16_t data) {
308  return this->parent_->template write_byte16<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
309  }
310 
311  void write_array16(const uint16_t *data, size_t length) {
312  this->parent_->template write_array16<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
313  }
314 
315  void write_array(const uint8_t *data, size_t length) {
316  this->parent_->template write_array<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
317  }
318 
319  template<size_t N> void write_array(const std::array<uint8_t, N> &data) { this->write_array(data.data(), N); }
320 
321  void write_array(const std::vector<uint8_t> &data) { this->write_array(data.data(), data.size()); }
322 
323  uint8_t transfer_byte(uint8_t data) {
324  return this->parent_->template transfer_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
325  }
326 
327  void transfer_array(uint8_t *data, size_t length) {
328  this->parent_->template transfer_array<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
329  }
330 
331  template<size_t N> void transfer_array(std::array<uint8_t, N> &data) { this->transfer_array(data.data(), N); }
332 
333  protected:
334  SPIComponent *parent_{nullptr};
335  GPIOPin *cs_{nullptr};
336 };
337 
338 } // namespace spi
339 } // namespace esphome
virtual void digital_write(bool value)=0
void write_array16(const uint16_t *data, size_t length)
Definition: spi.h:311
void transfer_array(uint8_t *data, size_t length)
Definition: spi.h:327
void cycle_clock_(bool value)
Definition: spi.cpp:111
void transfer_array(uint8_t *data, size_t length)
Definition: spi.h:192
void set_miso(GPIOPin *miso)
Definition: spi.h:75
uint32_t wait_cycle_
Definition: spi.h:268
void set_force_sw(bool force_sw)
Definition: spi.h:77
SPIDataRate
The SPI clock signal data rate.
Definition: spi.h:59
std::array< uint8_t, N > read_array()
Definition: spi.h:297
The data is sampled on a leading clock edge. (CPHA=0)
Definition: spi.h:47
The clock signal idles on HIGH.
Definition: spi.h:39
The most significant bit is transmitted/received first.
Definition: spi.h:23
void set_cs_pin(GPIOPin *cs)
Definition: spi.h:278
uint8_t transfer_byte(uint8_t data)
Definition: spi.h:323
The clock signal idles on LOW.
Definition: spi.h:34
void write_array(const std::vector< uint8_t > &data)
Definition: spi.h:321
void write_byte(uint8_t data)
Definition: spi.h:303
void read_array(uint8_t *data, size_t length)
Definition: spi.h:93
SPIClockPolarity
The SPI clock signal polarity,.
Definition: spi.h:29
uint8_t read_byte()
Definition: spi.h:291
void dump_config() override
Definition: spi.cpp:100
void write_array(const std::array< uint8_t, N > &data)
Definition: spi.h:319
void read_array(uint8_t *data, size_t length)
Definition: spi.h:293
uint8_t read_byte()
Definition: spi.h:83
The data is sampled on a trailing clock edge. (CPHA=1)
Definition: spi.h:49
void set_mosi(GPIOPin *mosi)
Definition: spi.h:76
uint32_t arch_get_cpu_freq_hz()
Definition: core.cpp:67
SPIClass * hw_spi_
Definition: spi.h:266
SPIDevice(SPIComponent *parent, GPIOPin *cs)
Definition: spi.h:275
void write_byte(uint8_t data)
Definition: spi.h:106
GPIOPin * active_cs_
Definition: spi.h:263
void transfer_array(std::array< uint8_t, N > &data)
Definition: spi.h:331
uint8_t transfer_(uint8_t data)
void setup() override
Definition: spi.cpp:22
SPIBitOrder
The bit-order for SPI devices. This defines how the data read from and written to the device is inter...
Definition: spi.h:19
void write_array(const uint8_t *data, size_t length)
Definition: spi.h:315
Definition: a4988.cpp:4
The least significant bit is transmitted/received first.
Definition: spi.h:21
void set_spi_parent(SPIComponent *parent)
Definition: spi.h:277
SPIClockPhase
The SPI clock signal phase.
Definition: spi.h:45
void write_byte16(uint16_t data)
Definition: spi.h:307
void write_byte16(const uint16_t data)
Definition: spi.h:121
void write_array16(const uint16_t *data, size_t length)
Definition: spi.h:138
void set_clk(GPIOPin *clk)
Definition: spi.h:74
uint8_t transfer_byte(uint8_t data)
Definition: spi.h:175
void enable(GPIOPin *cs)
Definition: spi.h:218
void write_array(const uint8_t *data, size_t length)
Definition: spi.h:157
float get_setup_priority() const override
Definition: spi.cpp:109