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