mirror of
https://github.com/esphome/esphome.git
synced 2026-09-15 00:58:40 +00:00
Fix MCP23x17 MIRROR bit, add dump_config logging, and clear PI4IOE5V6408 latched interrupts
- MCP23017/MCP23S17: Enable MIRROR bit in IOCON when interrupt_pin is configured so INTA and INTB are ORed together, allowing a single interrupt wire to catch changes on all 16 pins - All MCP23xxx variants: Log interrupt_pin in dump_config for debugging - PI4IOE5V6408: Read interrupt status register during setup to clear any latched state that could hold INT line low - MCP23XXXBase: Move setup_interrupt_pin_() to protected visibility
This commit is contained in:
@@ -23,10 +23,13 @@ void MCP23008::setup() {
|
||||
this->write_reg(mcp23x08_base::MCP23X08_IOCON, iocon | IOCON_ODR);
|
||||
}
|
||||
|
||||
this->setup_interrupt_pin();
|
||||
this->setup_interrupt_pin_();
|
||||
}
|
||||
|
||||
void MCP23008::dump_config() { ESP_LOGCONFIG(TAG, "MCP23008:"); }
|
||||
void MCP23008::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MCP23008:");
|
||||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
|
||||
}
|
||||
|
||||
bool MCP23008::read_reg(uint8_t reg, uint8_t *value) {
|
||||
if (this->is_failed())
|
||||
|
||||
@@ -6,7 +6,8 @@ namespace mcp23017 {
|
||||
|
||||
static const char *const TAG = "mcp23017";
|
||||
|
||||
static constexpr uint8_t IOCON_ODR = 0x04; // Open-drain output for INT pin
|
||||
static constexpr uint8_t IOCON_MIRROR = 0x40; // Mirror INTA/INTB pins
|
||||
static constexpr uint8_t IOCON_ODR = 0x04; // Open-drain output for INT pin
|
||||
|
||||
void MCP23017::setup() {
|
||||
uint8_t iocon;
|
||||
@@ -19,16 +20,26 @@ void MCP23017::setup() {
|
||||
this->read_reg(mcp23x17_base::MCP23X17_OLATA, &this->olat_a_);
|
||||
this->read_reg(mcp23x17_base::MCP23X17_OLATB, &this->olat_b_);
|
||||
|
||||
uint8_t iocon_flags = 0;
|
||||
if (this->open_drain_ints_) {
|
||||
// enable open-drain interrupt pins, 3.3V-safe
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONA, iocon | IOCON_ODR);
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONB, iocon | IOCON_ODR);
|
||||
iocon_flags |= IOCON_ODR;
|
||||
}
|
||||
if (this->interrupt_pin_ != nullptr) {
|
||||
// Mirror INTA/INTB so either pin fires for changes on any port
|
||||
iocon_flags |= IOCON_MIRROR;
|
||||
}
|
||||
if (iocon_flags != 0) {
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONA, iocon | iocon_flags);
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONB, iocon | iocon_flags);
|
||||
}
|
||||
|
||||
this->setup_interrupt_pin();
|
||||
this->setup_interrupt_pin_();
|
||||
}
|
||||
|
||||
void MCP23017::dump_config() { ESP_LOGCONFIG(TAG, "MCP23017:"); }
|
||||
void MCP23017::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MCP23017:");
|
||||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
|
||||
}
|
||||
|
||||
bool MCP23017::read_reg(uint8_t reg, uint8_t *value) {
|
||||
if (this->is_failed())
|
||||
|
||||
@@ -35,12 +35,13 @@ void MCP23S08::setup() {
|
||||
this->write_reg(mcp23x08_base::MCP23X08_IOCON, IOCON_SEQOP | IOCON_HAEN | IOCON_ODR);
|
||||
}
|
||||
|
||||
this->setup_interrupt_pin();
|
||||
this->setup_interrupt_pin_();
|
||||
}
|
||||
|
||||
void MCP23S08::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MCP23S08:");
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
|
||||
}
|
||||
|
||||
bool MCP23S08::read_reg(uint8_t reg, uint8_t *value) {
|
||||
|
||||
@@ -7,9 +7,10 @@ namespace mcp23s17 {
|
||||
static const char *const TAG = "mcp23s17";
|
||||
|
||||
// IOCON register bits
|
||||
static constexpr uint8_t IOCON_SEQOP = 0x20; // Sequential operation mode
|
||||
static constexpr uint8_t IOCON_HAEN = 0x08; // Hardware address enable
|
||||
static constexpr uint8_t IOCON_ODR = 0x04; // Open-drain output for INT pin
|
||||
static constexpr uint8_t IOCON_SEQOP = 0x20; // Sequential operation mode
|
||||
static constexpr uint8_t IOCON_MIRROR = 0x40; // Mirror INTA/INTB pins
|
||||
static constexpr uint8_t IOCON_HAEN = 0x08; // Hardware address enable
|
||||
static constexpr uint8_t IOCON_ODR = 0x04; // Open-drain output for INT pin
|
||||
|
||||
void MCP23S17::set_device_address(uint8_t device_addr) {
|
||||
if (device_addr != 0) {
|
||||
@@ -37,18 +38,26 @@ void MCP23S17::setup() {
|
||||
this->read_reg(mcp23x17_base::MCP23X17_OLATA, &this->olat_a_);
|
||||
this->read_reg(mcp23x17_base::MCP23X17_OLATB, &this->olat_b_);
|
||||
|
||||
uint8_t iocon_flags = IOCON_SEQOP | IOCON_HAEN;
|
||||
if (this->open_drain_ints_) {
|
||||
// enable open-drain interrupt pins, 3.3V-safe (addressed, only this chip)
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONA, IOCON_SEQOP | IOCON_HAEN | IOCON_ODR);
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONB, IOCON_SEQOP | IOCON_HAEN | IOCON_ODR);
|
||||
iocon_flags |= IOCON_ODR;
|
||||
}
|
||||
if (this->interrupt_pin_ != nullptr) {
|
||||
// Mirror INTA/INTB so either pin fires for changes on any port
|
||||
iocon_flags |= IOCON_MIRROR;
|
||||
}
|
||||
if (this->open_drain_ints_ || this->interrupt_pin_ != nullptr) {
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONA, iocon_flags);
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONB, iocon_flags);
|
||||
}
|
||||
|
||||
this->setup_interrupt_pin();
|
||||
this->setup_interrupt_pin_();
|
||||
}
|
||||
|
||||
void MCP23S17::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MCP23S17:");
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
|
||||
}
|
||||
|
||||
bool MCP23S17::read_reg(uint8_t reg, uint8_t *value) {
|
||||
|
||||
@@ -18,15 +18,6 @@ template<uint8_t N> class MCP23XXXBase : public Component, public gpio_expander:
|
||||
void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; }
|
||||
float get_setup_priority() const override { return setup_priority::IO; }
|
||||
|
||||
void setup_interrupt_pin() {
|
||||
if (this->interrupt_pin_ != nullptr) {
|
||||
this->interrupt_pin_->setup();
|
||||
this->interrupt_pin_->attach_interrupt(&MCP23XXXBase::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE);
|
||||
this->set_invalidate_on_read_(false);
|
||||
this->disable_loop();
|
||||
}
|
||||
}
|
||||
|
||||
void loop() override {
|
||||
this->reset_pin_cache_();
|
||||
if (this->interrupt_pin_ != nullptr) {
|
||||
@@ -35,6 +26,14 @@ template<uint8_t N> class MCP23XXXBase : public Component, public gpio_expander:
|
||||
}
|
||||
|
||||
protected:
|
||||
void setup_interrupt_pin_() {
|
||||
if (this->interrupt_pin_ != nullptr) {
|
||||
this->interrupt_pin_->setup();
|
||||
this->interrupt_pin_->attach_interrupt(&MCP23XXXBase::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE);
|
||||
this->set_invalidate_on_read_(false);
|
||||
this->disable_loop();
|
||||
}
|
||||
}
|
||||
static void IRAM_ATTR gpio_intr(MCP23XXXBase *arg) { arg->enable_loop_soon_any_context(); }
|
||||
|
||||
// read a given register
|
||||
|
||||
@@ -35,6 +35,9 @@ void PI4IOE5V6408Component::setup() {
|
||||
}
|
||||
|
||||
if (this->interrupt_pin_ != nullptr) {
|
||||
// Clear any latched interrupt status from before boot
|
||||
uint8_t status;
|
||||
this->read_byte(PI4IOE5V6408_REGISTER_INTERRUPT_STATUS, &status);
|
||||
this->interrupt_pin_->setup();
|
||||
this->interrupt_pin_->attach_interrupt(&PI4IOE5V6408Component::gpio_intr, this, gpio::INTERRUPT_FALLING_EDGE);
|
||||
this->set_invalidate_on_read_(false);
|
||||
|
||||
Reference in New Issue
Block a user