From 726b0e73d9eaad69c00d7ca7839fe09c0a001d91 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Fri, 7 Jun 2019 14:25:57 +0200 Subject: [PATCH] Add more efficient SPI implementation (#622) * Add more efficient SPI implementation * Lint * Add 200KHZ * Updates * Fix write_byte * Update from datasheet * Shift clock * Fix calculation --- esphome/components/max31855/max31855.cpp | 2 - esphome/components/max31855/max31855.h | 7 +- esphome/components/max6675/max6675.cpp | 2 - esphome/components/max6675/max6675.h | 7 +- esphome/components/max7219/max7219.cpp | 1 - esphome/components/max7219/max7219.h | 5 +- esphome/components/pn532/pn532.cpp | 1 - esphome/components/pn532/pn532.h | 6 +- esphome/components/spi/spi.cpp | 215 +++++++++++++----- esphome/components/spi/spi.h | 144 ++++++++++-- .../components/ssd1306_spi/ssd1306_spi.cpp | 2 - esphome/components/ssd1306_spi/ssd1306_spi.h | 6 +- .../waveshare_epaper/waveshare_epaper.cpp | 3 - .../waveshare_epaper/waveshare_epaper.h | 10 +- 14 files changed, 300 insertions(+), 111 deletions(-) diff --git a/esphome/components/max31855/max31855.cpp b/esphome/components/max31855/max31855.cpp index 18a00b10d7..0462ed4342 100644 --- a/esphome/components/max31855/max31855.cpp +++ b/esphome/components/max31855/max31855.cpp @@ -82,7 +82,5 @@ void MAX31855Sensor::read_data_() { this->status_clear_warning(); } -bool MAX31855Sensor::is_device_msb_first() { return true; } - } // namespace max31855 } // namespace esphome diff --git a/esphome/components/max31855/max31855.h b/esphome/components/max31855/max31855.h index f9cdf335f1..1d0fc79ac0 100644 --- a/esphome/components/max31855/max31855.h +++ b/esphome/components/max31855/max31855.h @@ -7,7 +7,10 @@ namespace esphome { namespace max31855 { -class MAX31855Sensor : public sensor::Sensor, public PollingComponent, public spi::SPIDevice { +class MAX31855Sensor : public sensor::Sensor, + public PollingComponent, + public spi::SPIDevice { public: void setup() override; void dump_config() override; @@ -16,8 +19,6 @@ class MAX31855Sensor : public sensor::Sensor, public PollingComponent, public sp void update() override; protected: - bool is_device_msb_first() override; - void read_data_(); }; diff --git a/esphome/components/max6675/max6675.cpp b/esphome/components/max6675/max6675.cpp index 8ea7feb963..53442b9cb1 100644 --- a/esphome/components/max6675/max6675.cpp +++ b/esphome/components/max6675/max6675.cpp @@ -48,7 +48,5 @@ void MAX6675Sensor::read_data_() { this->status_clear_warning(); } -bool MAX6675Sensor::is_device_msb_first() { return true; } - } // namespace max6675 } // namespace esphome diff --git a/esphome/components/max6675/max6675.h b/esphome/components/max6675/max6675.h index 48f51fbe11..09bd9df3b8 100644 --- a/esphome/components/max6675/max6675.h +++ b/esphome/components/max6675/max6675.h @@ -7,7 +7,10 @@ namespace esphome { namespace max6675 { -class MAX6675Sensor : public sensor::Sensor, public PollingComponent, public spi::SPIDevice { +class MAX6675Sensor : public sensor::Sensor, + public PollingComponent, + public spi::SPIDevice { public: void setup() override; void dump_config() override; @@ -16,8 +19,6 @@ class MAX6675Sensor : public sensor::Sensor, public PollingComponent, public spi void update() override; protected: - bool is_device_msb_first() override; - void read_data_(); }; diff --git a/esphome/components/max7219/max7219.cpp b/esphome/components/max7219/max7219.cpp index bc3c3ae0c9..db43ff19f6 100644 --- a/esphome/components/max7219/max7219.cpp +++ b/esphome/components/max7219/max7219.cpp @@ -155,7 +155,6 @@ void MAX7219Component::send_to_all_(uint8_t a_register, uint8_t data) { this->send_byte_(a_register, data); this->disable(); } -bool MAX7219Component::is_device_msb_first() { return true; } void MAX7219Component::update() { for (uint8_t i = 0; i < this->num_chips_ * 8; i++) this->buffer_[i] = 0; diff --git a/esphome/components/max7219/max7219.h b/esphome/components/max7219/max7219.h index e2379fa69b..1920268ba4 100644 --- a/esphome/components/max7219/max7219.h +++ b/esphome/components/max7219/max7219.h @@ -16,7 +16,9 @@ class MAX7219Component; using max7219_writer_t = std::function; -class MAX7219Component : public PollingComponent, public spi::SPIDevice { +class MAX7219Component : public PollingComponent, + public spi::SPIDevice { public: void set_writer(max7219_writer_t &&writer); @@ -54,7 +56,6 @@ class MAX7219Component : public PollingComponent, public spi::SPIDevice { protected: void send_byte_(uint8_t a_register, uint8_t data); void send_to_all_(uint8_t a_register, uint8_t data); - bool is_device_msb_first() override; uint8_t intensity_{15}; /// Intensity of the display from 0 to 15 (most) uint8_t num_chips_{1}; diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp index 07a41444ce..93000a7421 100644 --- a/esphome/components/pn532/pn532.cpp +++ b/esphome/components/pn532/pn532.cpp @@ -335,7 +335,6 @@ bool PN532::wait_ready_() { return true; } -bool PN532::is_device_msb_first() { return false; } void PN532::dump_config() { ESP_LOGCONFIG(TAG, "PN532:"); switch (this->error_code_) { diff --git a/esphome/components/pn532/pn532.h b/esphome/components/pn532/pn532.h index d349c7a150..49d5878265 100644 --- a/esphome/components/pn532/pn532.h +++ b/esphome/components/pn532/pn532.h @@ -11,7 +11,9 @@ namespace pn532 { class PN532BinarySensor; class PN532Trigger; -class PN532 : public PollingComponent, public spi::SPIDevice { +class PN532 : public PollingComponent, + public spi::SPIDevice { public: void setup() override; @@ -26,8 +28,6 @@ class PN532 : public PollingComponent, public spi::SPIDevice { void register_trigger(PN532Trigger *trig) { this->triggers_.push_back(trig); } protected: - bool is_device_msb_first() override; - /// Write the full command given in data to the PN532 void pn532_write_command_(const std::vector &data); bool pn532_write_command_check_ack_(const std::vector &data); diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index db4b71c29a..e3172660df 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -8,73 +8,19 @@ namespace spi { static const char *TAG = "spi"; -void ICACHE_RAM_ATTR HOT SPIComponent::write_byte(uint8_t data) { - uint8_t send_bits = data; - if (this->msb_first_) - send_bits = reverse_bits_8(data); +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(true); - if (!this->high_speed_) - delayMicroseconds(5); - - for (size_t i = 0; i < 8; i++) { - if (!this->high_speed_) - delayMicroseconds(5); - this->clk_->digital_write(false); - - // sampling on leading edge - this->mosi_->digital_write(send_bits & (1 << i)); - if (!this->high_speed_) - delayMicroseconds(5); - this->clk_->digital_write(true); - } - - ESP_LOGVV(TAG, " Wrote 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", BYTE_TO_BINARY(data), data); -} - -uint8_t ICACHE_RAM_ATTR HOT SPIComponent::read_byte() { - this->clk_->digital_write(true); - - uint8_t data = 0; - for (size_t i = 0; i < 8; i++) { - if (!this->high_speed_) - delayMicroseconds(5); - data |= uint8_t(this->miso_->digital_read()) << i; - this->clk_->digital_write(false); - if (!this->high_speed_) - delayMicroseconds(5); - this->clk_->digital_write(true); - } - - if (this->msb_first_) { - data = reverse_bits_8(data); - } - - ESP_LOGVV(TAG, " Received 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", BYTE_TO_BINARY(data), data); - - return data; -} -void ICACHE_RAM_ATTR HOT SPIComponent::read_array(uint8_t *data, size_t length) { - for (size_t i = 0; i < length; i++) - data[i] = this->read_byte(); -} - -void ICACHE_RAM_ATTR HOT SPIComponent::write_array(uint8_t *data, size_t length) { - for (size_t i = 0; i < length; i++) { - App.feed_wdt(); - this->write_byte(data[i]); - } -} - -void ICACHE_RAM_ATTR HOT SPIComponent::enable(GPIOPin *cs, bool msb_first, bool high_speed) { - ESP_LOGVV(TAG, "Enabling SPI Chip on pin %u...", cs->get_pin()); - cs->digital_write(false); + this->clk_->digital_write(CLOCK_POLARITY); this->active_cs_ = cs; - this->msb_first_ = msb_first; - this->high_speed_ = high_speed; + 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() { ESP_LOGVV(TAG, "Disabling SPI Chip on pin %u...", this->active_cs_->get_pin()); this->active_cs_->digital_write(true); @@ -100,5 +46,150 @@ void SPIComponent::dump_config() { } float SPIComponent::get_setup_priority() const { return setup_priority::BUS; } +void SPIComponent::debug_tx(uint8_t value) { + ESP_LOGVV(TAG, " TX 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", BYTE_TO_BINARY(value), value); +} +void SPIComponent::debug_rx(uint8_t value) { + ESP_LOGVV(TAG, " RX 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", BYTE_TO_BINARY(value), value); +} +void SPIComponent::debug_enable(uint8_t pin) { ESP_LOGVV(TAG, "Enabling SPI Chip on pin %u...", pin); } + +void SPIComponent::cycle_clock_(bool value) { + uint32_t start = ESP.getCycleCount(); + while (start - ESP.getCycleCount() < this->wait_cycle_) + ; + this->clk_->digital_write(value); + start += this->wait_cycle_; + while (start - ESP.getCycleCount() < this->wait_cycle_) + ; +} + +// NOLINTNEXTLINE +#pragma GCC optimize("unroll-loops") +// NOLINTNEXTLINE +#pragma GCC optimize("O2") + +template +uint8_t HOT SPIComponent::transfer_(uint8_t data) { + // Clock starts out at idle level + this->clk_->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 + if (WRITE) { + this->mosi_->digital_write(data & (1 << shift)); + } + + // SAMPLE! + this->cycle_clock_(!CLOCK_POLARITY); + + if (READ) { + out_data |= uint8_t(this->miso_->digital_read()) << shift; + } + + this->cycle_clock_(CLOCK_POLARITY); + } else { + // sampling on trailing edge + this->cycle_clock_(!CLOCK_POLARITY); + + if (WRITE) { + this->mosi_->digital_write(data & (1 << shift)); + } + + // SAMPLE! + this->cycle_clock_(CLOCK_POLARITY); + + if (READ) { + out_data |= uint8_t(this->miso_->digital_read()) << shift; + } + } + } + +#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE + if (WRITE) { + SPIComponent::debug_tx(data); + } + if (READ) { + SPIComponent::debug_rx(out_data); + } +#endif + + App.feed_wdt(); + + return out_data; +} + +// Generate with (py3): +// +// from itertools import product +// bit_orders = ['BIT_ORDER_LSB_FIRST', 'BIT_ORDER_MSB_FIRST'] +// clock_pols = ['CLOCK_POLARITY_LOW', 'CLOCK_POLARITY_HIGH'] +// clock_phases = ['CLOCK_PHASE_LEADING', 'CLOCK_PHASE_TRAILING'] +// reads = [False, True] +// writes = [False, True] +// cpp_bool = {False: 'false', True: 'true'} +// for b, cpol, cph, r, w in product(bit_orders, clock_pols, clock_phases, reads, writes): +// if not r and not w: +// continue +// print(f"template uint8_t SPIComponent::transfer_<{b}, {cpol}, {cph}, {cpp_bool[r]}, {cpp_bool[w]}>(uint8_t +// data);") + +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); +template uint8_t SPIComponent::transfer_( + uint8_t data); + } // namespace spi } // namespace esphome diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index 600e1a0cd2..f2d76b54e2 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -6,6 +6,56 @@ namespace esphome { namespace spi { +/// The bit-order for SPI devices. This defines how the data read from and written to the device is interpreted. +enum SPIBitOrder { + /// The least significant bit is transmitted/received first. + BIT_ORDER_LSB_FIRST, + /// The most significant bit is transmitted/received first. + BIT_ORDER_MSB_FIRST, +}; +/** The SPI clock signal polarity, + * + * This defines how the clock signal is used. Flipping this effectively inverts the clock signal. + */ +enum SPIClockPolarity { + /** The clock signal idles on LOW. (CPOL=0) + * + * A rising edge means a leading edge for the clock. + */ + CLOCK_POLARITY_LOW = false, + /** The clock signal idles on HIGH. (CPOL=1) + * + * A falling edge means a trailing edge for the clock. + */ + CLOCK_POLARITY_HIGH = true, +}; +/** The SPI clock signal phase. + * + * This defines when the data signals are sampled. Most SPI devices use the LEADING clock phase. + */ +enum SPIClockPhase { + /// The data is sampled on a leading clock edge. (CPHA=0) + CLOCK_PHASE_LEADING, + /// The data is sampled on a trailing clock edge. (CPHA=1) + CLOCK_PHASE_TRAILING, +}; +/** The SPI clock signal data rate. This defines for what duration the clock signal is HIGH/LOW. + * So effectively the rate of bytes can be calculated using + * + * effective_byte_rate = spi_data_rate / 16 + * + * Implementations can use the pre-defined constants here, or use an integer in the template definition + * to manually use a specific data rate. + */ +enum SPIDataRate : uint32_t { + DATA_RATE_1KHZ = 1000, + DATA_RATE_200KHZ = 200000, + DATA_RATE_1MHZ = 1000000, + DATA_RATE_2MHZ = 2000000, + DATA_RATE_4MHZ = 4000000, + DATA_RATE_8MHZ = 8000000, +}; + class SPIComponent : public Component { public: void set_clk(GPIOPin *clk) { clk_ = clk; } @@ -16,59 +66,117 @@ class SPIComponent : public Component { void dump_config() override; - uint8_t read_byte(); + template uint8_t read_byte() { + return this->transfer_(0x00); + } - void read_array(uint8_t *data, size_t length); + template + void read_array(uint8_t *data, size_t length) { + for (size_t i = 0; i < length; i++) { + data[i] = this->read_byte(); + } + } - void write_byte(uint8_t data); + template + void write_byte(uint8_t data) { + this->transfer_(data); + } - void write_array(uint8_t *data, size_t length); + template + void write_array(const uint8_t *data, size_t length) { + for (size_t i = 0; i < length; i++) { + this->write_byte(data[i]); + } + } - void enable(GPIOPin *cs, bool msb_first, bool high_speed); + template + uint8_t transfer_byte(uint8_t data) { + return this->transfer_(data); + } + + template + void transfer_array(uint8_t *data, size_t length) { + for (size_t i = 0; i < length; i++) { + data[i] = this->transfer_byte(data[i]); + } + } + + template void enable(GPIOPin *cs, uint32_t wait_cycle); void disable(); float get_setup_priority() const override; protected: + inline void cycle_clock_(bool value); + + static void debug_enable(uint8_t pin); + static void debug_tx(uint8_t value); + static void debug_rx(uint8_t value); + + template + uint8_t transfer_(uint8_t data); + GPIOPin *clk_; GPIOPin *miso_{nullptr}; GPIOPin *mosi_{nullptr}; GPIOPin *active_cs_{nullptr}; - bool msb_first_{true}; - bool high_speed_{false}; + uint32_t wait_cycle_; }; +template class SPIDevice { public: SPIDevice() = default; SPIDevice(SPIComponent *parent, GPIOPin *cs) : parent_(parent), cs_(cs) {} - void set_spi_parent(SPIComponent *parent) { this->parent_ = parent; } - void set_cs_pin(GPIOPin *cs) { this->cs_ = cs; } + void set_spi_parent(SPIComponent *parent) { parent_ = parent; } + void set_cs_pin(GPIOPin *cs) { cs_ = cs; } void spi_setup() { this->cs_->setup(); this->cs_->digital_write(true); } - void enable() { this->parent_->enable(this->cs_, this->is_device_msb_first(), this->is_device_high_speed()); } + void enable() { this->parent_->template enable(this->cs_, uint32_t(F_CPU) / DATA_RATE / 2ULL); } void disable() { this->parent_->disable(); } - uint8_t read_byte() { return this->parent_->read_byte(); } + uint8_t read_byte() { return this->parent_->template read_byte(); } - void read_array(uint8_t *data, size_t length) { return this->parent_->read_array(data, length); } + void read_array(uint8_t *data, size_t length) { + return this->parent_->template read_array(data, length); + } - void write_byte(uint8_t data) { return this->parent_->write_byte(data); } + template std::array read_array() { + std::array data; + this->read_array(data.data(), N); + return data; + } - void write_array(uint8_t *data, size_t length) { this->parent_->write_array(data, length); } + void write_byte(uint8_t data) { + return this->parent_->template write_byte(data); + } + + void write_array(const uint8_t *data, size_t length) { + this->parent_->template write_array(data, length); + } + + template void write_array(const std::array &data) { this->write_array(data.data(), N); } + + void write_array(const std::vector &data) { this->write_array(data.data(), data.size()); } + + uint8_t transfer_byte(uint8_t data) { + return this->parent_->template transfer_byte(data); + } + + void transfer_array(uint8_t *data, size_t length) { + this->parent_->template transfer_array(data, length); + } + + template void transfer_array(std::array &data) { this->transfer_array(data.data(), N); } protected: - virtual bool is_device_msb_first() = 0; - - virtual bool is_device_high_speed() { return false; } - SPIComponent *parent_{nullptr}; GPIOPin *cs_{nullptr}; }; diff --git a/esphome/components/ssd1306_spi/ssd1306_spi.cpp b/esphome/components/ssd1306_spi/ssd1306_spi.cpp index aeead612ff..d87f412f70 100644 --- a/esphome/components/ssd1306_spi/ssd1306_spi.cpp +++ b/esphome/components/ssd1306_spi/ssd1306_spi.cpp @@ -7,7 +7,6 @@ namespace ssd1306_spi { static const char *TAG = "ssd1306_spi"; -bool SPISSD1306::is_device_msb_first() { return true; } void SPISSD1306::setup() { ESP_LOGCONFIG(TAG, "Setting up SPI SSD1306..."); this->spi_setup(); @@ -52,7 +51,6 @@ void HOT SPISSD1306::write_display_data() { this->disable(); } } -bool SPISSD1306::is_device_high_speed() { return true; } } // namespace ssd1306_spi } // namespace esphome diff --git a/esphome/components/ssd1306_spi/ssd1306_spi.h b/esphome/components/ssd1306_spi/ssd1306_spi.h index 5d0640bd84..c58ebc800a 100644 --- a/esphome/components/ssd1306_spi/ssd1306_spi.h +++ b/esphome/components/ssd1306_spi/ssd1306_spi.h @@ -7,7 +7,9 @@ namespace esphome { namespace ssd1306_spi { -class SPISSD1306 : public ssd1306_base::SSD1306, public spi::SPIDevice { +class SPISSD1306 : public ssd1306_base::SSD1306, + public spi::SPIDevice { public: void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } @@ -19,8 +21,6 @@ class SPISSD1306 : public ssd1306_base::SSD1306, public spi::SPIDevice { void command(uint8_t value) override; void write_display_data() override; - bool is_device_msb_first() override; - bool is_device_high_speed() override; GPIOPin *dc_pin_; }; diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 2fe12dc102..c4d73c49f6 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -42,7 +42,6 @@ void WaveshareEPaper::data(uint8_t value) { this->write_byte(value); this->end_data_(); } -bool WaveshareEPaper::is_device_msb_first() { return true; } bool WaveshareEPaper::wait_until_idle_() { if (this->busy_pin_ == nullptr) { return true; @@ -81,7 +80,6 @@ void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, int color) this->buffer_[pos] &= ~(0x80 >> subpos); } uint32_t WaveshareEPaper::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal() / 8u; } -bool WaveshareEPaper::is_device_high_speed() { return true; } void WaveshareEPaper::start_command_() { this->dc_pin_->digital_write(false); this->enable(); @@ -495,7 +493,6 @@ void HOT WaveshareEPaper4P2In::display() { } int WaveshareEPaper4P2In::get_width_internal() { return 400; } int WaveshareEPaper4P2In::get_height_internal() { return 300; } -bool WaveshareEPaper4P2In::is_device_high_speed() { return false; } void WaveshareEPaper4P2In::dump_config() { LOG_DISPLAY("", "Waveshare E-Paper", this); ESP_LOGCONFIG(TAG, " Model: 4.2in"); diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 192e85275e..a8b85c93e9 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -7,14 +7,16 @@ namespace esphome { namespace waveshare_epaper { -class WaveshareEPaper : public PollingComponent, public spi::SPIDevice, public display::DisplayBuffer { +class WaveshareEPaper : public PollingComponent, + public display::DisplayBuffer, + public spi::SPIDevice { public: void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } float get_setup_priority() const override; void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } void set_busy_pin(GPIOPin *busy) { this->busy_pin_ = busy; } - bool is_device_msb_first() override; void command(uint8_t value); void data(uint8_t value); @@ -51,8 +53,6 @@ class WaveshareEPaper : public PollingComponent, public spi::SPIDevice, public d uint32_t get_buffer_length_(); - bool is_device_high_speed() override; - void start_command_(); void end_command_(); void start_data_(); @@ -166,8 +166,6 @@ class WaveshareEPaper4P2In : public WaveshareEPaper { int get_width_internal() override; int get_height_internal() override; - - bool is_device_high_speed() override; }; class WaveshareEPaper7P5In : public WaveshareEPaper {