ESPHome  2022.6.3
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 
78  void setup() override;
79 
80  void dump_config() override;
81 
82  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE> uint8_t read_byte() {
83 #ifdef USE_SPI_ARDUINO_BACKEND
84  if (this->hw_spi_ != nullptr) {
85  return this->hw_spi_->transfer(0x00);
86  }
87 #endif // USE_SPI_ARDUINO_BACKEND
88  return this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, true, false>(0x00);
89  }
90 
91  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
92  void read_array(uint8_t *data, size_t length) {
93 #ifdef USE_SPI_ARDUINO_BACKEND
94  if (this->hw_spi_ != nullptr) {
95  this->hw_spi_->transfer(data, length);
96  return;
97  }
98 #endif // USE_SPI_ARDUINO_BACKEND
99  for (size_t i = 0; i < length; i++) {
100  data[i] = this->read_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>();
101  }
102  }
103 
104  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
105  void write_byte(uint8_t data) {
106 #ifdef USE_SPI_ARDUINO_BACKEND
107  if (this->hw_spi_ != nullptr) {
108  this->hw_spi_->write(data);
109  return;
110  }
111 #endif // USE_SPI_ARDUINO_BACKEND
112  this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, false, true>(data);
113  }
114 
115  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
116  void write_byte16(const uint16_t data) {
117 #ifdef USE_SPI_ARDUINO_BACKEND
118  if (this->hw_spi_ != nullptr) {
119  this->hw_spi_->write16(data);
120  return;
121  }
122 #endif // USE_SPI_ARDUINO_BACKEND
123 
124  this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data >> 8);
125  this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
126  }
127 
128  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
129  void write_array16(const uint16_t *data, size_t length) {
130 #ifdef USE_SPI_ARDUINO_BACKEND
131  if (this->hw_spi_ != nullptr) {
132  for (size_t i = 0; i < length; i++) {
133  this->hw_spi_->write16(data[i]);
134  }
135  return;
136  }
137 #endif // USE_SPI_ARDUINO_BACKEND
138  for (size_t i = 0; i < length; i++) {
139  this->write_byte16<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data[i]);
140  }
141  }
142 
143  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
144  void write_array(const uint8_t *data, size_t length) {
145 #ifdef USE_SPI_ARDUINO_BACKEND
146  if (this->hw_spi_ != nullptr) {
147  auto *data_c = const_cast<uint8_t *>(data);
148  this->hw_spi_->writeBytes(data_c, length);
149  return;
150  }
151 #endif // USE_SPI_ARDUINO_BACKEND
152  for (size_t i = 0; i < length; i++) {
153  this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data[i]);
154  }
155  }
156 
157  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
158  uint8_t transfer_byte(uint8_t data) {
159  if (this->miso_ != nullptr) {
160 #ifdef USE_SPI_ARDUINO_BACKEND
161  if (this->hw_spi_ != nullptr) {
162  return this->hw_spi_->transfer(data);
163  } else {
164 #endif // USE_SPI_ARDUINO_BACKEND
165  return this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, true, true>(data);
166 #ifdef USE_SPI_ARDUINO_BACKEND
167  }
168 #endif // USE_SPI_ARDUINO_BACKEND
169  }
170  this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
171  return 0;
172  }
173 
174  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
175  void transfer_array(uint8_t *data, size_t length) {
176 #ifdef USE_SPI_ARDUINO_BACKEND
177  if (this->hw_spi_ != nullptr) {
178  if (this->miso_ != nullptr) {
179  this->hw_spi_->transfer(data, length);
180  } else {
181  this->hw_spi_->writeBytes(data, length);
182  }
183  return;
184  }
185 #endif // USE_SPI_ARDUINO_BACKEND
186 
187  if (this->miso_ != nullptr) {
188  for (size_t i = 0; i < length; i++) {
189  data[i] = this->transfer_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data[i]);
190  }
191  } else {
192  this->write_array<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
193  }
194  }
195 
196  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, uint32_t DATA_RATE>
197  void enable(GPIOPin *cs) {
198 #ifdef USE_SPI_ARDUINO_BACKEND
199  if (this->hw_spi_ != nullptr) {
200  uint8_t data_mode = SPI_MODE0;
201  if (!CLOCK_POLARITY && CLOCK_PHASE) {
202  data_mode = SPI_MODE1;
203  } else if (CLOCK_POLARITY && !CLOCK_PHASE) {
204  data_mode = SPI_MODE2;
205  } else if (CLOCK_POLARITY && CLOCK_PHASE) {
206  data_mode = SPI_MODE3;
207  }
208  SPISettings settings(DATA_RATE, BIT_ORDER, data_mode);
209  this->hw_spi_->beginTransaction(settings);
210  } else {
211 #endif // USE_SPI_ARDUINO_BACKEND
212  this->clk_->digital_write(CLOCK_POLARITY);
213  uint32_t cpu_freq_hz = arch_get_cpu_freq_hz();
214  this->wait_cycle_ = uint32_t(cpu_freq_hz) / DATA_RATE / 2ULL;
215 #ifdef USE_SPI_ARDUINO_BACKEND
216  }
217 #endif // USE_SPI_ARDUINO_BACKEND
218 
219  if (cs != nullptr) {
220  this->active_cs_ = cs;
221  this->active_cs_->digital_write(false);
222  }
223  }
224 
225  void disable();
226 
227  float get_setup_priority() const override;
228 
229  protected:
230  inline void cycle_clock_(bool value);
231 
232  template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, bool READ, bool WRITE>
233  uint8_t transfer_(uint8_t data);
234 
236  GPIOPin *miso_{nullptr};
237  GPIOPin *mosi_{nullptr};
238  GPIOPin *active_cs_{nullptr};
239 #ifdef USE_SPI_ARDUINO_BACKEND
240  SPIClass *hw_spi_{nullptr};
241 #endif // USE_SPI_ARDUINO_BACKEND
242  uint32_t wait_cycle_;
243 };
244 
245 template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, SPIDataRate DATA_RATE>
246 class SPIDevice {
247  public:
248  SPIDevice() = default;
249  SPIDevice(SPIComponent *parent, GPIOPin *cs) : parent_(parent), cs_(cs) {}
250 
251  void set_spi_parent(SPIComponent *parent) { parent_ = parent; }
252  void set_cs_pin(GPIOPin *cs) { cs_ = cs; }
253 
254  void spi_setup() {
255  if (this->cs_) {
256  this->cs_->setup();
257  this->cs_->digital_write(true);
258  }
259  }
260 
261  void enable() { this->parent_->template enable<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, DATA_RATE>(this->cs_); }
262 
263  void disable() { this->parent_->disable(); }
264 
265  uint8_t read_byte() { return this->parent_->template read_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(); }
266 
267  void read_array(uint8_t *data, size_t length) {
268  return this->parent_->template read_array<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
269  }
270 
271  template<size_t N> std::array<uint8_t, N> read_array() {
272  std::array<uint8_t, N> data;
273  this->read_array(data.data(), N);
274  return data;
275  }
276 
277  void write_byte(uint8_t data) {
278  return this->parent_->template write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
279  }
280 
281  void write_byte16(uint16_t data) {
282  return this->parent_->template write_byte16<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
283  }
284 
285  void write_array16(const uint16_t *data, size_t length) {
286  this->parent_->template write_array16<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
287  }
288 
289  void write_array(const uint8_t *data, size_t length) {
290  this->parent_->template write_array<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
291  }
292 
293  template<size_t N> void write_array(const std::array<uint8_t, N> &data) { this->write_array(data.data(), N); }
294 
295  void write_array(const std::vector<uint8_t> &data) { this->write_array(data.data(), data.size()); }
296 
297  uint8_t transfer_byte(uint8_t data) {
298  return this->parent_->template transfer_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data);
299  }
300 
301  void transfer_array(uint8_t *data, size_t length) {
302  this->parent_->template transfer_array<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data, length);
303  }
304 
305  template<size_t N> void transfer_array(std::array<uint8_t, N> &data) { this->transfer_array(data.data(), N); }
306 
307  protected:
308  SPIComponent *parent_{nullptr};
309  GPIOPin *cs_{nullptr};
310 };
311 
312 } // namespace spi
313 } // namespace esphome
virtual void digital_write(bool value)=0
void write_array16(const uint16_t *data, size_t length)
Definition: spi.h:285
void transfer_array(uint8_t *data, size_t length)
Definition: spi.h:301
void cycle_clock_(bool value)
Definition: spi.cpp:107
void transfer_array(uint8_t *data, size_t length)
Definition: spi.h:175
void set_miso(GPIOPin *miso)
Definition: spi.h:75
uint32_t wait_cycle_
Definition: spi.h:242
SPIDataRate
The SPI clock signal data rate.
Definition: spi.h:59
std::array< uint8_t, N > read_array()
Definition: spi.h:271
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:252
uint8_t transfer_byte(uint8_t data)
Definition: spi.h:297
The clock signal idles on LOW.
Definition: spi.h:34
void write_array(const std::vector< uint8_t > &data)
Definition: spi.h:295
void write_byte(uint8_t data)
Definition: spi.h:277
void read_array(uint8_t *data, size_t length)
Definition: spi.h:92
SPIClockPolarity
The SPI clock signal polarity,.
Definition: spi.h:29
uint8_t read_byte()
Definition: spi.h:265
void dump_config() override
Definition: spi.cpp:96
void write_array(const std::array< uint8_t, N > &data)
Definition: spi.h:293
void read_array(uint8_t *data, size_t length)
Definition: spi.h:267
uint8_t read_byte()
Definition: spi.h:82
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:66
SPIClass * hw_spi_
Definition: spi.h:240
SPIDevice(SPIComponent *parent, GPIOPin *cs)
Definition: spi.h:249
void write_byte(uint8_t data)
Definition: spi.h:105
GPIOPin * active_cs_
Definition: spi.h:238
void transfer_array(std::array< uint8_t, N > &data)
Definition: spi.h:305
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:289
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:251
SPIClockPhase
The SPI clock signal phase.
Definition: spi.h:45
void write_byte16(uint16_t data)
Definition: spi.h:281
void write_byte16(const uint16_t data)
Definition: spi.h:116
void write_array16(const uint16_t *data, size_t length)
Definition: spi.h:129
void set_clk(GPIOPin *clk)
Definition: spi.h:74
uint8_t transfer_byte(uint8_t data)
Definition: spi.h:158
void enable(GPIOPin *cs)
Definition: spi.h:197
void write_array(const uint8_t *data, size_t length)
Definition: spi.h:144
float get_setup_priority() const override
Definition: spi.cpp:105