From 75630a36f855aac87e7919d88aed3557b421a436 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sat, 8 Jun 2019 17:45:55 +0200 Subject: [PATCH] Add HW SPI support (#623) * Add HW SPI support * Update spi.cpp * Lint * ESP32 Compile Fix --- esphome/components/spi/spi.cpp | 64 +++++++++++++++++++++++++++------- esphome/components/spi/spi.h | 44 +++++++++++++++++++++-- 2 files changed, 93 insertions(+), 15 deletions(-) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index e3172660df..bf2a18955a 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -8,20 +8,10 @@ namespace spi { static const char *TAG = "spi"; -template void SPIComponent::enable(GPIOPin *cs, uint32_t wait_cycle) { - this->debug_enable(cs->get_pin()); - this->wait_cycle_ = wait_cycle; - - this->clk_->digital_write(CLOCK_POLARITY); - - this->active_cs_ = cs; - this->active_cs_->digital_write(false); -} - -template void SPIComponent::enable(GPIOPin *cs, uint32_t wait_cycle); -template void SPIComponent::enable(GPIOPin *cs, uint32_t wait_cycle); - void ICACHE_RAM_ATTR HOT SPIComponent::disable() { + if (this->hw_spi_ != nullptr) { + this->hw_spi_->endTransaction(); + } ESP_LOGVV(TAG, "Disabling SPI Chip on pin %u...", this->active_cs_->get_pin()); this->active_cs_->digital_write(true); this->active_cs_ = nullptr; @@ -30,6 +20,53 @@ void SPIComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up SPI bus..."); this->clk_->setup(); this->clk_->digital_write(true); + + bool use_hw_spi = true; + if (this->clk_->is_inverted()) + use_hw_spi = false; + const bool has_miso = this->miso_ != nullptr; + const bool has_mosi = this->mosi_ != nullptr; + if (has_miso && this->miso_->is_inverted()) + use_hw_spi = false; + if (has_mosi && this->mosi_->is_inverted()) + use_hw_spi = false; + int8_t clk_pin = this->clk_->get_pin(); + int8_t miso_pin = has_miso ? this->miso_->get_pin() : -1; + int8_t mosi_pin = has_mosi ? this->mosi_->get_pin() : -1; +#ifdef ARDUINO_ARCH_ESP8266 + if (clk_pin == 6 && miso_pin == 7 && mosi_pin == 8) { + // pass + } else if (clk_pin == 14 && miso_pin == 12 && mosi_pin == 13) { + // pass + } else { + use_hw_spi = false; + } + + if (use_hw_spi) { + this->hw_spi_ = &SPI; + this->hw_spi_->pins(clk_pin, miso_pin, mosi_pin, 0); + this->hw_spi_->begin(); + return; + } +#endif +#ifdef ARDUINO_ARCH_ESP32 + static uint8_t spi_bus_num = 0; + if (spi_bus_num >= 2) { + use_hw_spi = false; + } + + if (use_hw_spi) { + if (spi_bus_num == 0) { + this->hw_spi_ = &SPI; + } else { + this->hw_spi_ = new SPIClass(VSPI); + } + spi_bus_num++; + this->hw_spi_->begin(clk_pin, miso_pin, mosi_pin); + return; + } +#endif + if (this->miso_ != nullptr) { this->miso_->setup(); } @@ -43,6 +80,7 @@ void SPIComponent::dump_config() { LOG_PIN(" CLK Pin: ", this->clk_); LOG_PIN(" MISO Pin: ", this->miso_); LOG_PIN(" MOSI Pin: ", this->mosi_); + ESP_LOGCONFIG(TAG, " Using HW SPI: %s", YESNO(this->hw_spi_ != nullptr)); } float SPIComponent::get_setup_priority() const { return setup_priority::BUS; } diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index f2d76b54e2..ccef6192f3 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -2,6 +2,7 @@ #include "esphome/core/component.h" #include "esphome/core/esphal.h" +#include namespace esphome { namespace spi { @@ -67,11 +68,18 @@ class SPIComponent : public Component { void dump_config() override; template uint8_t read_byte() { + if (this->hw_spi_ != nullptr) { + return this->hw_spi_->transfer(0x00); + } return this->transfer_(0x00); } template void read_array(uint8_t *data, size_t length) { + if (this->hw_spi_ != nullptr) { + this->hw_spi_->transfer(data, length); + return; + } for (size_t i = 0; i < length; i++) { data[i] = this->read_byte(); } @@ -79,11 +87,20 @@ class SPIComponent : public Component { template void write_byte(uint8_t data) { + if (this->hw_spi_ != nullptr) { + this->hw_spi_->write(data); + return; + } this->transfer_(data); } template void write_array(const uint8_t *data, size_t length) { + if (this->hw_spi_ != nullptr) { + auto *data_c = const_cast(data); + this->hw_spi_->writeBytes(data_c, length); + return; + } for (size_t i = 0; i < length; i++) { this->write_byte(data[i]); } @@ -91,17 +108,39 @@ class SPIComponent : public Component { template uint8_t transfer_byte(uint8_t data) { + if (this->hw_spi_ != nullptr) { + return this->hw_spi_->transfer(data); + } return this->transfer_(data); } template void transfer_array(uint8_t *data, size_t length) { + if (this->hw_spi_ != nullptr) { + this->hw_spi_->transfer(data, length); + return; + } for (size_t i = 0; i < length; i++) { data[i] = this->transfer_byte(data[i]); } } - template void enable(GPIOPin *cs, uint32_t wait_cycle); + template + void enable(GPIOPin *cs) { + SPIComponent::debug_enable(cs->get_pin()); + + if (this->hw_spi_ != nullptr) { + uint8_t data_mode = (uint8_t(CLOCK_POLARITY) << 1) | uint8_t(CLOCK_PHASE); + SPISettings settings(DATA_RATE, BIT_ORDER, data_mode); + this->hw_spi_->beginTransaction(settings); + } else { + this->clk_->digital_write(CLOCK_POLARITY); + this->wait_cycle_ = uint32_t(F_CPU) / DATA_RATE / 2ULL; + } + + this->active_cs_ = cs; + this->active_cs_->digital_write(false); + } void disable(); @@ -121,6 +160,7 @@ class SPIComponent : public Component { GPIOPin *miso_{nullptr}; GPIOPin *mosi_{nullptr}; GPIOPin *active_cs_{nullptr}; + SPIClass *hw_spi_{nullptr}; uint32_t wait_cycle_; }; @@ -138,7 +178,7 @@ class SPIDevice { this->cs_->digital_write(true); } - void enable() { this->parent_->template enable(this->cs_, uint32_t(F_CPU) / DATA_RATE / 2ULL); } + void enable() { this->parent_->template enable(this->cs_); } void disable() { this->parent_->disable(); }