mirror of
https://github.com/esphome/esphome.git
synced 2025-09-28 08:02:23 +01:00
* 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>
117 lines
3.6 KiB
C++
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
|