1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-28 08:02:23 +01:00
Files
esphome/esphome/components/spi/spi.cpp
Clyde Stubbs 5c26f95a4b Refactor SPI code; Add ESP-IDF hardware support (#5311)
* Checkpoint

* Checkpoint

* Checkpoint

* Revert hal change

* Checkpoint

* Checkpoint

* Checkpoint

* Checkpoint

* ESP-IDF working

* clang-format

* use bus_list

* Add spi_device; fix 16 bit transfer.

* Enable multi_conf;
Fix LSB 16 bit transactions

* Formatting fixes

* Clang-format, codeowners

* Add test

* Formatting

* clang tidy

* clang-format

* clang-tidy

* clang-format

* Checkpoint

* Checkpoint

* Checkpoint

* Revert hal change

* Checkpoint

* Checkpoint

* Checkpoint

* Checkpoint

* ESP-IDF working

* clang-format

* use bus_list

* Add spi_device; fix 16 bit transfer.

* Enable multi_conf;
Fix LSB 16 bit transactions

* Formatting fixes

* Clang-format, codeowners

* Add test

* Formatting

* clang tidy

* clang-format

* clang-tidy

* clang-format

* Clang-tidy

* Clang-format

* clang-tidy

* clang-tidy

* Fix ESP8266

* RP2040

* RP2040

* Avoid use of spi1 as id

* Refactor SPI code.
Add support for ESP-IDF hardware SPI

* Force SW only for RP2040

* Break up large transfers

* Add interface: option for spi.
validate pins in python.

* Can't use match/case with Python 3.9.
Check for inverted pins.

* Work around target_platform issue with

* Remove debug code

* Optimize write_array16

* Show errors in hex

* Only one spi on ESP32Cx variants

* Ensure bus is claimed before asserting /CS.

* Check on init/deinit

* Allow maximum rate write only SPI on GPIO MUXed pins.

* Clang-format

* Clang-tidy

* Fix issue with reads.

* Finger trouble...

* Make comment about missing SPI on Cx variants

* Pacify CI clang-format. Did not complain locally??

* Restore 8266 to its former SPI glory

* Fix per clang-format

* Move validation and choice of SPI into Python code.

* Add test for interface: config

* Fix issues found on self-review.

---------

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2023-09-08 02:27:19 -05:00

117 lines
3.6 KiB
C++

#include "spi.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"
namespace esphome {
namespace spi {
const char *const TAG = "spi";
SPIDelegate *const SPIDelegate::NULL_DELEGATE = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
new SPIDelegateDummy();
// https://bugs.llvm.org/show_bug.cgi?id=48040
bool SPIDelegate::is_ready() { return true; }
GPIOPin *const NullPin::NULL_PIN = new NullPin(); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
SPIDelegate *SPIComponent::register_device(SPIClient *device, SPIMode mode, SPIBitOrder bit_order, uint32_t data_rate,
GPIOPin *cs_pin) {
if (this->devices_.count(device) != 0) {
ESP_LOGE(TAG, "SPI device already registered");
return this->devices_[device];
}
SPIDelegate *delegate = this->spi_bus_->get_delegate(data_rate, bit_order, mode, cs_pin); // NOLINT
this->devices_[device] = delegate;
return delegate;
}
void SPIComponent::unregister_device(SPIClient *device) {
if (this->devices_.count(device) == 0) {
esph_log_e(TAG, "SPI device not registered");
return;
}
delete this->devices_[device]; // NOLINT
this->devices_.erase(device);
}
void SPIComponent::setup() {
ESP_LOGD(TAG, "Setting up SPI bus...");
if (this->sdo_pin_ == nullptr)
this->sdo_pin_ = NullPin::NULL_PIN;
if (this->sdi_pin_ == nullptr)
this->sdi_pin_ = NullPin::NULL_PIN;
if (this->clk_pin_ == nullptr) {
ESP_LOGE(TAG, "No clock pin for SPI");
this->mark_failed();
return;
}
if (this->using_hw_) {
this->spi_bus_ = SPIComponent::get_bus(this->interface_, this->clk_pin_, this->sdo_pin_, this->sdi_pin_);
if (this->spi_bus_ == nullptr) {
ESP_LOGE(TAG, "Unable to allocate SPI interface");
this->mark_failed();
}
} else {
this->spi_bus_ = new SPIBus(this->clk_pin_, this->sdo_pin_, this->sdi_pin_); // NOLINT
this->clk_pin_->setup();
this->clk_pin_->digital_write(true);
this->sdo_pin_->setup();
this->sdi_pin_->setup();
}
}
void SPIComponent::dump_config() {
ESP_LOGCONFIG(TAG, "SPI bus:");
LOG_PIN(" CLK Pin: ", this->clk_pin_)
LOG_PIN(" SDI Pin: ", this->sdi_pin_)
LOG_PIN(" SDO Pin: ", this->sdo_pin_)
if (this->spi_bus_->is_hw()) {
ESP_LOGCONFIG(TAG, " Using HW SPI: %s", this->interface_name_);
} else {
ESP_LOGCONFIG(TAG, " Using software SPI");
}
}
void SPIDelegateDummy::begin_transaction() { ESP_LOGE(TAG, "SPIDevice not initialised - did you call spi_setup()?"); }
uint8_t SPIDelegateBitBash::transfer(uint8_t data) {
// Clock starts out at idle level
this->clk_pin_->digital_write(clock_polarity_);
uint8_t out_data = 0;
for (uint8_t i = 0; i < 8; i++) {
uint8_t shift;
if (bit_order_ == BIT_ORDER_MSB_FIRST) {
shift = 7 - i;
} else {
shift = i;
}
if (clock_phase_ == CLOCK_PHASE_LEADING) {
// sampling on leading edge
this->sdo_pin_->digital_write(data & (1 << shift));
this->cycle_clock_();
out_data |= uint8_t(this->sdi_pin_->digital_read()) << shift;
this->clk_pin_->digital_write(!this->clock_polarity_);
this->cycle_clock_();
this->clk_pin_->digital_write(this->clock_polarity_);
} else {
// sampling on trailing edge
this->cycle_clock_();
this->clk_pin_->digital_write(!this->clock_polarity_);
this->sdo_pin_->digital_write(data & (1 << shift));
this->cycle_clock_();
out_data |= uint8_t(this->sdi_pin_->digital_read()) << shift;
this->clk_pin_->digital_write(this->clock_polarity_);
}
}
App.feed_wdt();
return out_data;
}
} // namespace spi
} // namespace esphome