From 9373ebe3530660aecac3854cdaaf3d368209d5a7 Mon Sep 17 00:00:00 2001 From: Greg Gibeling Date: Mon, 22 Jan 2024 17:14:47 -0800 Subject: [PATCH] SN74HC595 support for inverted & restore modes without relay pulsing --- esphome/components/sn74hc595/sn74hc595.cpp | 41 +++++++++++++++++----- esphome/components/sn74hc595/sn74hc595.h | 10 +++--- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/esphome/components/sn74hc595/sn74hc595.cpp b/esphome/components/sn74hc595/sn74hc595.cpp index 8a37c3bece..08325b5662 100644 --- a/esphome/components/sn74hc595/sn74hc595.cpp +++ b/esphome/components/sn74hc595/sn74hc595.cpp @@ -48,31 +48,53 @@ void SN74HC595Component::digital_write_(uint16_t pin, bool value) { return; } if (value) { - this->output_bytes_[pin / 8] |= (1 << (pin % 8)); + this->value_bytes_[pin / 8] |= (1 << (pin % 8)); } else { - this->output_bytes_[pin / 8] &= ~(1 << (pin % 8)); + this->value_bytes_[pin / 8] &= ~(1 << (pin % 8)); } this->write_gpio(); } +void SN74HC595Component::set_inverted_(uint16_t pin, bool inverted) { + if (pin >= this->sr_count_ * 8) { + ESP_LOGE(TAG, "Pin %u is out of range! Maximum pin number with %u chips in series is %u", pin, this->sr_count_, + (this->sr_count_ * 8) - 1); + return; + } + if (inverted) { + this->inverted_bytes_[pin / 8] |= (1 << (pin % 8)); + } else { + this->inverted_bytes_[pin / 8] &= ~(1 << (pin % 8)); + } +} void SN74HC595GPIOComponent::write_gpio() { - for (auto byte = this->output_bytes_.rbegin(); byte != this->output_bytes_.rend(); byte++) { + auto value = this->value_bytes_.rbegin(); + auto inverted = this->inverted_bytes_.rbegin(); + while (value != this->value_bytes_.rend() && inverted != this->inverted_bytes_.rend()) { for (int8_t i = 7; i >= 0; i--) { - bool bit = (*byte >> i) & 1; - this->data_pin_->digital_write(bit); + bool value_bit = (*value >> i) & 1; + bool value_inverted = (*inverted >> i) & 1; + this->data_pin_->digital_write(value_bit != value_inverted); this->clock_pin_->digital_write(true); this->clock_pin_->digital_write(false); } + value++; + inverted++; } SN74HC595Component::write_gpio(); } #ifdef USE_SPI void SN74HC595SPIComponent::write_gpio() { - for (auto byte = this->output_bytes_.rbegin(); byte != this->output_bytes_.rend(); byte++) { + auto value = this->value_bytes_.rbegin(); + auto inverted = this->inverted_bytes_.rbegin(); + while (value != this->value_bytes_.rend() && inverted != this->inverted_bytes_.rend()) { this->enable(); - this->transfer_byte(*byte); + this->transfer_byte((*byte) ^ (*inverted)); this->disable(); + + value++; + inverted++; } SN74HC595Component::write_gpio(); } @@ -92,7 +114,10 @@ void SN74HC595Component::write_gpio() { float SN74HC595Component::get_setup_priority() const { return setup_priority::IO; } void SN74HC595GPIOPin::digital_write(bool value) { - this->parent_->digital_write_(this->pin_, value != this->inverted_); + this->parent_->digital_write_(this->pin_, value); +} +void SN74HC595GPIOPin::set_inverted(bool inverted) { + this->parent_->set_inverted_(this->pin_, inverted); } std::string SN74HC595GPIOPin::dump_summary() const { return str_snprintf("%u via SN74HC595", 18, pin_); } diff --git a/esphome/components/sn74hc595/sn74hc595.h b/esphome/components/sn74hc595/sn74hc595.h index cb9d7bf140..0855a80f4a 100644 --- a/esphome/components/sn74hc595/sn74hc595.h +++ b/esphome/components/sn74hc595/sn74hc595.h @@ -29,12 +29,14 @@ class SN74HC595Component : public Component { } void set_sr_count(uint8_t count) { this->sr_count_ = count; - this->output_bytes_.resize(count); + this->value_bytes_.resize(count); + this->inverted_bytes_.resize(count); } protected: friend class SN74HC595GPIOPin; void digital_write_(uint16_t pin, bool value); + void set_inverted_(uint16_t pin, bool inverted); virtual void write_gpio(); void pre_setup_(); @@ -44,7 +46,8 @@ class SN74HC595Component : public Component { GPIOPin *oe_pin_; uint8_t sr_count_; bool have_oe_pin_{false}; - std::vector output_bytes_; + std::vector value_bytes_; + std::vector inverted_bytes_; }; /// Helper class to expose a SC74HC595 pin as an internal output GPIO pin. @@ -57,11 +60,10 @@ class SN74HC595GPIOPin : public GPIOPin, public Parented { std::string dump_summary() const override; void set_pin(uint16_t pin) { pin_ = pin; } - void set_inverted(bool inverted) { inverted_ = inverted; } + void set_inverted(bool inverted); protected: uint16_t pin_; - bool inverted_; }; class SN74HC595GPIOComponent : public SN74HC595Component {