ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
mcp23016.cpp
Go to the documentation of this file.
1#include "mcp23016.h"
2#include "esphome/core/log.h"
3#include <cstdio>
4
6
7static const char *const TAG = "mcp23016";
8
10 uint16_t iocon;
11 // MCP23016 registers operate as paired 16-bit registers. Addressing the
12 // odd register (e.g. IOCON1) reads/writes that register first, then wraps
13 // to the even register (IOCON0) in the same pair. Starting from the odd
14 // address gives the correct byte order for 1 << pin mapping:
15 // high byte = port 1 (pins 8-15), low byte = port 0 (pins 0-7).
16 if (!this->read_reg_(MCP23016_IOCON1, &iocon)) {
17 this->mark_failed();
18 return;
19 }
20
21 // Read current output register state
22 this->read_reg_(MCP23016_OLAT1, &this->olat_);
23
24 // all pins input
25 this->write_reg_(MCP23016_IODIR1, 0xFFFF);
26
27 if (this->interrupt_pin_ != nullptr) {
28 this->interrupt_pin_->setup();
30 this->set_invalidate_on_read_(false);
31 }
32 this->disable_loop();
33}
34
37 // Invalidate cache at the start of each loop
38 this->reset_pin_cache_();
39 // Only disable the loop once INT has actually gone HIGH. Input transitions that straddle the
40 // I2C read leave INT asserted without re-firing a falling edge, which would strand us with
41 // stale state forever; keep looping until the line is released so we self-heal.
42 if (this->interrupt_pin_ != nullptr && this->interrupt_pin_->digital_read()) {
43 this->disable_loop();
44 }
45}
46bool MCP23016::digital_read_hw(uint8_t pin) { return this->read_reg_(MCP23016_GP1, &this->input_mask_); }
47
48bool MCP23016::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); }
49void MCP23016::digital_write_hw(uint8_t pin, bool value) { this->update_reg_(pin, value, MCP23016_OLAT1); }
51 if (flags == gpio::FLAG_INPUT) {
52 this->update_reg_(pin, true, MCP23016_IODIR1);
53 if (this->interrupt_pin_ == nullptr) {
54 this->enable_loop();
55 }
56 } else if (flags == gpio::FLAG_OUTPUT) {
57 this->update_reg_(pin, false, MCP23016_IODIR1);
58 }
59}
61bool MCP23016::read_reg_(uint8_t reg, uint16_t *value) {
62 if (this->is_failed())
63 return false;
64
65 return this->read_byte_16(reg, value);
66}
67bool MCP23016::write_reg_(uint8_t reg, uint16_t value) {
68 if (this->is_failed())
69 return false;
70
71 return this->write_byte_16(reg, value);
72}
73void MCP23016::update_reg_(uint8_t pin, bool pin_value, uint8_t reg_addr) {
74 uint16_t reg_value = 0;
75
76 if (reg_addr == MCP23016_OLAT1) {
77 reg_value = this->olat_;
78 } else {
79 this->read_reg_(reg_addr, &reg_value);
80 }
81
82 if (pin_value) {
83 reg_value |= 1 << pin;
84 } else {
85 reg_value &= ~(1 << pin);
86 }
87
88 this->write_reg_(reg_addr, reg_value);
89
90 if (reg_addr == MCP23016_OLAT1) {
91 this->olat_ = reg_value;
92 }
93}
94
97bool MCP23016GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
98void MCP23016GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
99size_t MCP23016GPIOPin::dump_summary(char *buffer, size_t len) const {
100 return buf_append_printf(buffer, len, 0, "%u via MCP23016", this->pin_);
101}
102
103} // namespace esphome::mcp23016
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:272
void enable_loop_soon_any_context()
Thread and ISR-safe version of enable_loop() that can be called from any context.
void enable_loop()
Enable this component's loop.
Definition component.h:246
void disable_loop()
Disable this component's loop.
virtual void setup()=0
virtual bool digital_read()=0
void attach_interrupt(void(*func)(T *), T *arg, gpio::InterruptType type) const
Definition gpio.h:107
bool digital_read(P pin)
Read the state of the given pin.
Definition cached_gpio.h:37
bool read_byte_16(uint8_t a_register, uint16_t *data)
Definition i2c.h:249
bool write_byte_16(uint8_t a_register, uint16_t data) const
Definition i2c.h:267
void pin_mode(gpio::Flags flags) override
Definition mcp23016.cpp:96
size_t dump_summary(char *buffer, size_t len) const override
Definition mcp23016.cpp:99
void digital_write(bool value) override
Definition mcp23016.cpp:98
void setup() override
Definition mcp23016.cpp:9
void pin_mode(uint8_t pin, gpio::Flags flags)
Definition mcp23016.cpp:50
bool digital_read_cache(uint8_t pin) override
Definition mcp23016.cpp:48
InternalGPIOPin * interrupt_pin_
Definition mcp23016.h:56
void digital_write_hw(uint8_t pin, bool value) override
Definition mcp23016.cpp:49
static void IRAM_ATTR gpio_intr(MCP23016 *arg)
Definition mcp23016.cpp:35
bool digital_read_hw(uint8_t pin) override
Definition mcp23016.cpp:46
void update_reg_(uint8_t pin, bool pin_value, uint8_t reg_a)
Definition mcp23016.cpp:73
float get_setup_priority() const override
Definition mcp23016.cpp:60
bool read_reg_(uint8_t reg, uint16_t *value)
Definition mcp23016.cpp:61
bool write_reg_(uint8_t reg, uint16_t value)
Definition mcp23016.cpp:67
uint16_t flags
@ INTERRUPT_FALLING_EDGE
Definition gpio.h:51
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_INPUT
Definition gpio.h:27
constexpr float IO
For components that represent GPIO pins like PCF8573.
Definition component.h:39
const void size_t len
Definition hal.h:64