Add HW SPI support (#623)

* Add HW SPI support

* Update spi.cpp

* Lint

* ESP32 Compile Fix
This commit is contained in:
Otto Winter 2019-06-08 17:45:55 +02:00 committed by GitHub
parent d2be58ba31
commit 75630a36f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 93 additions and 15 deletions

View file

@ -8,20 +8,10 @@ namespace spi {
static const char *TAG = "spi";
template<SPIClockPolarity CLOCK_POLARITY> 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<CLOCK_POLARITY_LOW>(GPIOPin *cs, uint32_t wait_cycle);
template void SPIComponent::enable<CLOCK_POLARITY_HIGH>(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; }

View file

@ -2,6 +2,7 @@
#include "esphome/core/component.h"
#include "esphome/core/esphal.h"
#include <SPI.h>
namespace esphome {
namespace spi {
@ -67,11 +68,18 @@ class SPIComponent : public Component {
void dump_config() override;
template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE> uint8_t read_byte() {
if (this->hw_spi_ != nullptr) {
return this->hw_spi_->transfer(0x00);
}
return this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, true, false>(0x00);
}
template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
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<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>();
}
@ -79,11 +87,20 @@ class SPIComponent : public Component {
template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
void write_byte(uint8_t data) {
if (this->hw_spi_ != nullptr) {
this->hw_spi_->write(data);
return;
}
this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, false, true>(data);
}
template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
void write_array(const uint8_t *data, size_t length) {
if (this->hw_spi_ != nullptr) {
auto *data_c = const_cast<uint8_t *>(data);
this->hw_spi_->writeBytes(data_c, length);
return;
}
for (size_t i = 0; i < length; i++) {
this->write_byte<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data[i]);
}
@ -91,17 +108,39 @@ class SPIComponent : public Component {
template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
uint8_t transfer_byte(uint8_t data) {
if (this->hw_spi_ != nullptr) {
return this->hw_spi_->transfer(data);
}
return this->transfer_<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, true, true>(data);
}
template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE>
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<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE>(data[i]);
}
}
template<SPIClockPolarity CLOCK_POLARITY> void enable(GPIOPin *cs, uint32_t wait_cycle);
template<SPIBitOrder BIT_ORDER, SPIClockPolarity CLOCK_POLARITY, SPIClockPhase CLOCK_PHASE, uint32_t DATA_RATE>
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<CLOCK_POLARITY>(this->cs_, uint32_t(F_CPU) / DATA_RATE / 2ULL); }
void enable() { this->parent_->template enable<BIT_ORDER, CLOCK_POLARITY, CLOCK_PHASE, DATA_RATE>(this->cs_); }
void disable() { this->parent_->disable(); }