diff --git a/components/TCA6408/tca6408.cpp b/components/TCA6408/tca6408.cpp index 657f5f2..b240d68 100644 --- a/components/TCA6408/tca6408.cpp +++ b/components/TCA6408/tca6408.cpp @@ -12,11 +12,23 @@ static const uint8_t TCA6408_POLARITY_PORT = 0x02; static const uint8_t TCA6408_CONFIG_PORT = 0x03; void TCA6408Component::setup() { - ESP_LOGCONFIG(TAG, "Setting up TCA6408..."); + ESP_LOGCONFIG(TAG, "Setting up TCA6408 at address 0x%02X...", this->address_); - if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK || - this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK || - !this->read_gpio_outputs_()) { + // Initialize registers to known state + if (this->write_register(TCA6408_POLARITY_PORT, 0x00) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Failed to write polarity register"); + this->mark_failed(); + return; + } + + if (this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_) != i2c::ERROR_OK) { + ESP_LOGE(TAG, "Failed to write config register"); + this->mark_failed(); + return; + } + + if (!this->read_gpio_outputs_()) { + ESP_LOGE(TAG, "Failed to read output register"); this->mark_failed(); return; } @@ -24,13 +36,16 @@ void TCA6408Component::setup() { if (this->interrupt_pin_ != nullptr) { this->interrupt_pin_->setup(); this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE); + this->interrupt_pin_->attach_interrupt(&TCA6408Component::gpio_intr, this, + gpio::INTERRUPT_FALLING_EDGE); this->set_invalidate_on_read_(false); - ESP_LOGCONFIG(TAG, " Interrupt mode enabled"); + ESP_LOGCONFIG(TAG, " Interrupt mode enabled (active-low INT)"); } else { this->enable_loop(); ESP_LOGCONFIG(TAG, " Polling mode enabled"); } + + ESP_LOGCONFIG(TAG, " Setup complete"); } void IRAM_ATTR TCA6408Component::gpio_intr(TCA6408Component *arg) { @@ -42,9 +57,11 @@ void TCA6408Component::loop() { if (this->interrupt_triggered_) { this->interrupt_triggered_ = false; - this->digital_read_hw(0); + // Reading input port clears the interrupt on TCA6408 + this->digital_read_hw(0); // pin number is ignored, reads all 8 bits this->reset_pin_cache_(); + // If INT line is high again, disable loop until next interrupt if (this->interrupt_pin_ && this->interrupt_pin_->digital_read()) { this->disable_loop(); } @@ -56,11 +73,13 @@ void TCA6408Component::dump_config() { LOG_I2C_DEVICE(this); ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_); LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); + ESP_LOGCONFIG(TAG, " Mode Mask: 0x%02X (1=input)", this->mode_mask_); + ESP_LOGCONFIG(TAG, " Polarity Mask: 0x%02X", this->polarity_mask_); } bool TCA6408Component::read_gpio_outputs_() { if (this->is_failed()) return false; - uint8_t data; + uint8_t data = 0; if (this->read_register(TCA6408_OUTPUT_PORT, &data) != i2c::ERROR_OK) { this->status_set_warning(); return false; @@ -87,9 +106,9 @@ void TCA6408Component::digital_write_hw(uint8_t pin, bool value) { if (this->is_failed()) return; if (value) { - this->output_mask_ |= (1 << pin); + this->output_mask_ |= (1U << pin); } else { - this->output_mask_ &= ~(1 << pin); + this->output_mask_ &= ~(1U << pin); } if (this->write_register(TCA6408_OUTPUT_PORT, this->output_mask_) != i2c::ERROR_OK) { @@ -101,9 +120,9 @@ void TCA6408Component::digital_write_hw(uint8_t pin, bool value) { void TCA6408Component::pin_mode(uint8_t pin, gpio::Flags flags) { if (flags & gpio::FLAG_OUTPUT) { - this->mode_mask_ &= ~(1 << pin); + this->mode_mask_ &= ~(1U << pin); // 0 = output } else { - this->mode_mask_ |= (1 << pin); + this->mode_mask_ |= (1U << pin); // 1 = input if (this->interrupt_pin_ == nullptr) { this->enable_loop(); } @@ -111,24 +130,25 @@ void TCA6408Component::pin_mode(uint8_t pin, gpio::Flags flags) { this->write_register(TCA6408_CONFIG_PORT, this->mode_mask_); } +void TCA6408Component::set_polarity_inversion(uint8_t pin, bool inverted) { + if (inverted) { + this->polarity_mask_ |= (1U << pin); + } else { + this->polarity_mask_ &= ~(1U << pin); + } + this->write_register(TCA6408_POLARITY_PORT, this->polarity_mask_); +} + bool TCA6408Component::digital_read_cache(uint8_t pin) { - bool value = (this->input_mask_ & (1 << pin)) != 0; - if (this->polarity_mask_ & (1 << pin)) { + bool value = (this->input_mask_ & (1U << pin)) != 0; + // Apply hardware polarity inversion if set + if (this->polarity_mask_ & (1U << pin)) { value = !value; } return value; } -void TCA6408Component::set_polarity_inversion(uint8_t pin, bool inverted) { - if (inverted) { - this->polarity_mask_ |= (1 << pin); - } else { - this->polarity_mask_ &= ~(1 << pin); - } - this->write_register(TCA6408_POLARITY_PORT, this->polarity_mask_); -} - -// ==================== TCA6408GPIOPin ==================== +// ====================== TCA6408GPIOPin ====================== void TCA6408GPIOPin::setup() { this->pin_mode(this->flags_); @@ -150,15 +170,15 @@ void TCA6408GPIOPin::pin_mode(gpio::Flags flags) { } bool TCA6408GPIOPin::digital_read() { - return this->parent_->digital_read(this->pin_); + return this->parent_->digital_read(this->pin_) != this->inverted_; } void TCA6408GPIOPin::digital_write(bool value) { - this->parent_->digital_write(this->pin_, value); + this->parent_->digital_write(this->pin_, value != this->inverted_); } size_t TCA6408GPIOPin::dump_summary(char *buffer, size_t len) const { - return snprintf(buffer, len, "%u via TCA6408", this->pin_); + return snprintf(buffer, len, "%u via TCA6408@0x%02X", this->pin_, this->parent_->address_); } } // namespace tca6408