ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
spi.cpp
Go to the documentation of this file.
1#include "spi.h"
2#include "esphome/core/log.h"
4
5#ifdef USE_ZEPHYR
6#include "spi_zephyr.h"
7#endif
8
9namespace esphome::spi {
10
11ESPHOME_LOG_TAG(TAG, "spi");
12
13SPIDelegate *const SPIDelegate::NULL_DELEGATE = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
14 new SPIDelegateDummy();
15// https://bugs.llvm.org/show_bug.cgi?id=48040
16
17bool SPIDelegate::is_ready() { return true; }
18
19GPIOPin *const NullPin::NULL_PIN = new NullPin(); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
20
22 GPIOPin *cs_pin, bool release_device, bool write_only) {
23 if (this->devices_.contains(device)) {
24 ESP_LOGE(TAG, "Device already registered");
25 return this->devices_[device];
26 }
27 if (this->spi_bus_ == nullptr) {
28 return SPIDelegate::NULL_DELEGATE; // the bus failed in setup(); the device stays not ready
29 }
30 SPIDelegate *delegate =
31 this->spi_bus_->get_delegate(data_rate, bit_order, mode, cs_pin, release_device, write_only); // NOLINT
32 this->devices_[device] = delegate;
33 return delegate;
34}
35
37 if (this->spi_bus_ == nullptr) {
38 return; // nothing was registered on a failed bus
39 }
40 if (!this->devices_.contains(device)) {
41 esph_log_e(TAG, "Device not registered");
42 return;
43 }
44 delete this->devices_[device]; // NOLINT
45 this->devices_.erase(device);
46}
47
49 if (this->sdo_pin_ == nullptr)
51 if (this->sdi_pin_ == nullptr)
53 if (this->clk_pin_ == nullptr) {
54 ESP_LOGE(TAG, "No clock pin");
55 this->mark_failed();
56 return;
57 }
58
59 if (this->using_hw_) {
60 this->spi_bus_ =
61 SPIComponent::get_bus(this->interface_, this->clk_pin_, this->sdo_pin_, this->sdi_pin_, this->data_pins_);
62 if (this->spi_bus_ == nullptr) {
63 ESP_LOGE(TAG, "Unable to allocate SPI interface");
64 this->mark_failed();
65 }
66 } else {
67 this->spi_bus_ = new SPIBus(this->clk_pin_, this->sdo_pin_, this->sdi_pin_); // NOLINT
68 this->clk_pin_->setup();
69 this->clk_pin_->digital_write(true);
70 this->sdo_pin_->setup();
71 this->sdi_pin_->setup();
72 }
73}
74
76 ESP_LOGCONFIG(TAG, "SPI bus:");
77 LOG_PIN(" CLK Pin: ", this->clk_pin_);
78 LOG_PIN(" SDI Pin: ", this->sdi_pin_);
79 LOG_PIN(" SDO Pin: ", this->sdo_pin_);
80 for (size_t i = 0; i != this->data_pins_.size(); i++) {
81 ESP_LOGCONFIG(TAG, " Data pin %zu: GPIO%d", i, this->data_pins_[i]);
82 }
83 if (this->spi_bus_ == nullptr) {
84 return;
85 }
86 if (this->spi_bus_->is_hw()) {
87 ESP_LOGCONFIG(TAG, " Using HW SPI: %s", this->interface_name_);
88 } else {
89 ESP_LOGCONFIG(TAG, " Using software SPI");
90 }
91}
92
93void SPIDelegateDummy::begin_transaction() { ESP_LOGE(TAG, "SPIDevice not initialised - did you call spi_setup()?"); }
94
95uint8_t SPIDelegateBitBash::transfer(uint8_t data) { return this->transfer_(data, 8); }
96
97void SPIDelegateBitBash::write(uint16_t data, size_t num_bits) { this->transfer_(data, num_bits); }
98
99uint16_t SPIDelegateBitBash::transfer_(uint16_t data, size_t num_bits) {
100 // Clock starts out at idle level
102 uint16_t out_data = 0;
103
104 for (uint8_t i = 0; i != num_bits; i++) {
105 uint8_t shift;
107 shift = num_bits - 1 - i;
108 } else {
109 shift = i;
110 }
111
113 // sampling on leading edge
114 this->sdo_pin_->digital_write(data & (1 << shift));
115 this->cycle_clock_();
116 out_data |= uint16_t(this->sdi_pin_->digital_read()) << shift;
118 this->cycle_clock_();
120 } else {
121 // sampling on trailing edge
122 this->cycle_clock_();
124 this->sdo_pin_->digital_write(data & (1 << shift));
125 this->cycle_clock_();
126 out_data |= uint16_t(this->sdi_pin_->digital_read()) << shift;
128 }
129 }
130 App.feed_wdt();
131 return out_data;
132}
133
134#if defined(USE_ZEPHYR)
135
137 const std::vector<uint8_t> &data_pins) {
138 if (!device_is_ready(interface)) {
139 ESP_LOGE(TAG, "SPI device is not ready");
140 return nullptr;
141 }
142 return new ZephyrSPIBus(interface); // NOLINT
143}
144
145#elif !defined(USE_ESP32) && !defined(USE_ARDUINO)
146// Stub for unsupported platforms (host, etc.) - hardware SPI is unavailable
148 const std::vector<uint8_t> &data_pins) {
149 return nullptr;
150}
151#endif
152
153} // namespace esphome::spi
BedjetMode mode
BedJet operating mode.
void feed_wdt()
Feed the task watchdog.
void mark_failed()
Mark this component as failed.
virtual void setup()=0
virtual void digital_write(bool value)=0
virtual bool digital_read()=0
A pin to replace those that don't exist.
Definition spi.h:113
static GPIOPin *const NULL_PIN
Definition spi.h:138
virtual bool is_hw()
Definition spi.h:340
virtual SPIDelegate * get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, bool release_device, bool write_only)
Definition spi.h:335
Base class for SPIDevice, un-templated.
Definition spi.h:404
void setup() override
Definition spi.cpp:48
void unregister_device(SPIClient *device)
Definition spi.cpp:36
static SPIBus * get_bus(SPIInterface interface, GPIOPin *clk, GPIOPin *sdo, GPIOPin *sdi, const std::vector< uint8_t > &data_pins)
Definition spi.cpp:136
std::map< SPIClient *, SPIDelegate * > devices_
Definition spi.h:393
void dump_config() override
Definition spi.cpp:75
SPIInterface interface_
Definition spi.h:389
SPIDelegate * register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate, GPIOPin *cs_pin, bool release_device, bool write_only)
Definition spi.cpp:21
const char * interface_name_
Definition spi.h:391
std::vector< uint8_t > data_pins_
Definition spi.h:387
uint8_t transfer(uint8_t data) override
Definition spi.cpp:95
SPIClockPolarity clock_polarity_
Definition spi.h:318
void write(uint16_t data, size_t num_bits) override
Definition spi.cpp:97
SPIClockPhase clock_phase_
Definition spi.h:319
uint16_t transfer_(uint16_t data, size_t num_bits)
Definition spi.cpp:99
A dummy SPIDelegate that complains if it's used.
Definition spi.h:281
void begin_transaction() override
Definition spi.cpp:93
virtual bool is_ready()
Definition spi.cpp:17
SPIBitOrder bit_order_
Definition spi.h:267
static SPIDelegate *const NULL_DELEGATE
Definition spi.h:274
Implementation of SPI Controller mode.
Definition spi.cpp:9
SPIMode
Modes mapping to clock phase and polarity.
Definition spi.h:84
SPIBitOrder
The bit-order for SPI devices. This defines how the data read from and written to the device is inter...
Definition spi.h:46
@ BIT_ORDER_MSB_FIRST
The most significant bit is transmitted/received first.
Definition spi.h:50
ESPHOME_LOG_TAG(TAG, "spi")
@ CLOCK_PHASE_LEADING
The data is sampled on a leading clock edge. (CPHA=0)
Definition spi.h:74
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t
spi_host_device_t SPIInterface
Definition spi.h:15