ESPHome  2024.2.1
spi.cpp
Go to the documentation of this file.
1 #include "spi.h"
2 #include "esphome/core/log.h"
4 
5 namespace esphome {
6 namespace spi {
7 
8 const char *const TAG = "spi";
9 
10 SPIDelegate *const SPIDelegate::NULL_DELEGATE = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
11  new SPIDelegateDummy();
12 // https://bugs.llvm.org/show_bug.cgi?id=48040
13 
14 bool SPIDelegate::is_ready() { return true; }
15 
16 GPIOPin *const NullPin::NULL_PIN = new NullPin(); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
17 
19  GPIOPin *cs_pin) {
20  if (this->devices_.count(device) != 0) {
21  ESP_LOGE(TAG, "SPI device already registered");
22  return this->devices_[device];
23  }
24  SPIDelegate *delegate = this->spi_bus_->get_delegate(data_rate, bit_order, mode, cs_pin); // NOLINT
25  this->devices_[device] = delegate;
26  return delegate;
27 }
28 
30  if (this->devices_.count(device) == 0) {
31  esph_log_e(TAG, "SPI device not registered");
32  return;
33  }
34  delete this->devices_[device]; // NOLINT
35  this->devices_.erase(device);
36 }
37 
39  ESP_LOGD(TAG, "Setting up SPI bus...");
40 
41  if (this->sdo_pin_ == nullptr)
42  this->sdo_pin_ = NullPin::NULL_PIN;
43  if (this->sdi_pin_ == nullptr)
44  this->sdi_pin_ = NullPin::NULL_PIN;
45  if (this->clk_pin_ == nullptr) {
46  ESP_LOGE(TAG, "No clock pin for SPI");
47  this->mark_failed();
48  return;
49  }
50 
51  if (this->using_hw_) {
52  this->spi_bus_ =
53  SPIComponent::get_bus(this->interface_, this->clk_pin_, this->sdo_pin_, this->sdi_pin_, this->data_pins_);
54  if (this->spi_bus_ == nullptr) {
55  ESP_LOGE(TAG, "Unable to allocate SPI interface");
56  this->mark_failed();
57  }
58  } else {
59  this->spi_bus_ = new SPIBus(this->clk_pin_, this->sdo_pin_, this->sdi_pin_); // NOLINT
60  this->clk_pin_->setup();
61  this->clk_pin_->digital_write(true);
62  this->sdo_pin_->setup();
63  this->sdi_pin_->setup();
64  }
65 }
66 
68  ESP_LOGCONFIG(TAG, "SPI bus:");
69  LOG_PIN(" CLK Pin: ", this->clk_pin_)
70  LOG_PIN(" SDI Pin: ", this->sdi_pin_)
71  LOG_PIN(" SDO Pin: ", this->sdo_pin_)
72  for (size_t i = 0; i != this->data_pins_.size(); i++) {
73  ESP_LOGCONFIG(TAG, " Data pin %u: GPIO%d", i, this->data_pins_[i]);
74  }
75  if (this->spi_bus_->is_hw()) {
76  ESP_LOGCONFIG(TAG, " Using HW SPI: %s", this->interface_name_);
77  } else {
78  ESP_LOGCONFIG(TAG, " Using software SPI");
79  }
80 }
81 
82 void SPIDelegateDummy::begin_transaction() { ESP_LOGE(TAG, "SPIDevice not initialised - did you call spi_setup()?"); }
83 
84 uint8_t SPIDelegateBitBash::transfer(uint8_t data) { return this->transfer_(data, 8); }
85 
86 void SPIDelegateBitBash::write(uint16_t data, size_t num_bits) { this->transfer_(data, num_bits); }
87 
88 uint16_t SPIDelegateBitBash::transfer_(uint16_t data, size_t num_bits) {
89  // Clock starts out at idle level
90  this->clk_pin_->digital_write(clock_polarity_);
91  uint8_t out_data = 0;
92 
93  for (uint8_t i = 0; i != num_bits; i++) {
94  uint8_t shift;
96  shift = num_bits - 1 - i;
97  } else {
98  shift = i;
99  }
100 
101  if (clock_phase_ == CLOCK_PHASE_LEADING) {
102  // sampling on leading edge
103  this->sdo_pin_->digital_write(data & (1 << shift));
104  this->cycle_clock_();
105  out_data |= uint16_t(this->sdi_pin_->digital_read()) << shift;
106  this->clk_pin_->digital_write(!this->clock_polarity_);
107  this->cycle_clock_();
108  this->clk_pin_->digital_write(this->clock_polarity_);
109  } else {
110  // sampling on trailing edge
111  this->cycle_clock_();
112  this->clk_pin_->digital_write(!this->clock_polarity_);
113  this->sdo_pin_->digital_write(data & (1 << shift));
114  this->cycle_clock_();
115  out_data |= uint16_t(this->sdi_pin_->digital_read()) << shift;
116  this->clk_pin_->digital_write(this->clock_polarity_);
117  }
118  }
119  App.feed_wdt();
120  return out_data;
121 }
122 
123 } // namespace spi
124 } // namespace esphome
void unregister_device(SPIClient *device)
Definition: spi.cpp:29
The data is sampled on a leading clock edge. (CPHA=0)
Definition: spi.h:66
A pin to replace those that don&#39;t exist.
Definition: spi.h:105
SPIDelegate * register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate, GPIOPin *cs_pin)
Definition: spi.cpp:18
The most significant bit is transmitted/received first.
Definition: spi.h:42
void write(uint16_t data, size_t num_bits) override
Definition: spi.cpp:86
uint16_t transfer_(uint16_t data, size_t num_bits)
Definition: spi.cpp:88
void dump_config() override
Definition: spi.cpp:67
uint8_t transfer(uint8_t data) override
Definition: spi.cpp:84
const char *const TAG
Definition: spi.cpp:8
BedjetMode mode
BedJet operating mode.
Definition: bedjet_codec.h:151
SPIMode
Modes mapping to clock phase and polarity.
Definition: spi.h:76
Application App
Global storage of Application pointer - only one Application can exist.
Base class for SPIDevice, un-templated.
Definition: spi.h:373
void begin_transaction() override
Definition: spi.cpp:82
static SPIDelegate *const NULL_DELEGATE
Definition: spi.h:253
static SPIBus * get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi, const std::vector< uint8_t > &data_pins)
Definition: spi_arduino.cpp:88
void setup() override
Definition: spi.cpp:38
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
A dummy SPIDelegate that complains if it&#39;s used.
Definition: spi.h:260
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
static GPIOPin *const NULL_PIN
Definition: spi.h:124
virtual bool is_ready()
Definition: spi.cpp:14
SPIBitOrder bit_order_
Definition: spi.h:249