ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
pca6416a.cpp
Go to the documentation of this file.
1#include "pca6416a.h"
2#include "esphome/core/log.h"
3
5
22
23static const char *const TAG = "pca6416a";
24
26 // Test to see if device exists
27 uint8_t value;
28 if (!this->read_register_(PCA6416A_INPUT0, &value)) {
29 ESP_LOGE(TAG, "PCA6416A not available under 0x%02X", this->address_);
30 this->mark_failed();
31 return;
32 }
33
34 // Test to see if the device supports pull-up resistors
35 if (this->read_register(PCAL6416A_PULL_EN0, &value, 1) == i2c::ERROR_OK) {
36 this->has_pullup_ = true;
37 }
38
39 // No polarity inversion
42 // Set all pins to input
45 // Read current output register state
48
49 ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(),
50 this->status_has_error());
51
52 if (this->interrupt_pin_ != nullptr) {
53 this->interrupt_pin_->setup();
55 this->set_invalidate_on_read_(false);
56 }
57 this->disable_loop();
58}
59
62 // Invalidate cache at the start of each loop
63 this->reset_pin_cache_();
64 // Only disable the loop once INT has actually gone HIGH. Input transitions that straddle the
65 // I2C read leave INT asserted without re-firing a falling edge, which would strand us with
66 // stale state forever; keep looping until the line is released so we self-heal.
67 if (this->interrupt_pin_ != nullptr && this->interrupt_pin_->digital_read()) {
68 this->disable_loop();
69 }
70}
71
73 if (this->has_pullup_) {
74 ESP_LOGCONFIG(TAG, "PCAL6416A:");
75 } else {
76 ESP_LOGCONFIG(TAG, "PCA6416A:");
77 }
78 LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
79 LOG_I2C_DEVICE(this)
80 if (this->is_failed()) {
81 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
82 }
83}
84
86 uint8_t reg_addr = pin < 8 ? PCA6416A_INPUT0 : PCA6416A_INPUT1;
87 uint8_t value = 0;
88 if (!this->read_register_(reg_addr, &value)) {
89 return false;
90 }
91
92 // Update the appropriate part of input_mask_
93 if (pin < 8) {
94 this->input_mask_ = (this->input_mask_ & 0xFF00) | value;
95 } else {
96 this->input_mask_ = (this->input_mask_ & 0x00FF) | (uint16_t(value) << 8);
97 }
98 return true;
99}
100
101bool PCA6416AComponent::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); }
102
103void PCA6416AComponent::digital_write_hw(uint8_t pin, bool value) {
104 uint8_t reg_addr = pin < 8 ? PCA6416A_OUTPUT0 : PCA6416A_OUTPUT1;
105 this->update_register_(pin, value, reg_addr);
106}
107
109 uint8_t io_dir = pin < 8 ? PCA6416A_CONFIG0 : PCA6416A_CONFIG1;
110 uint8_t pull_en = pin < 8 ? PCAL6416A_PULL_EN0 : PCAL6416A_PULL_EN1;
111 uint8_t pull_dir = pin < 8 ? PCAL6416A_PULL_DIR0 : PCAL6416A_PULL_DIR1;
112 if (flags == gpio::FLAG_INPUT) {
113 this->update_register_(pin, true, io_dir);
114 if (has_pullup_) {
115 this->update_register_(pin, true, pull_dir);
116 this->update_register_(pin, false, pull_en);
117 }
118 if (this->interrupt_pin_ == nullptr) {
119 this->enable_loop();
120 }
121 } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) {
122 this->update_register_(pin, true, io_dir);
123 if (has_pullup_) {
124 this->update_register_(pin, true, pull_dir);
125 this->update_register_(pin, true, pull_en);
126 } else {
127 ESP_LOGW(TAG, "Your PCA6416A does not support pull-up resistors");
128 }
129 if (this->interrupt_pin_ == nullptr) {
130 this->enable_loop();
131 }
132 } else if (flags == gpio::FLAG_OUTPUT) {
133 this->update_register_(pin, false, io_dir);
134 }
135}
136
137bool PCA6416AComponent::read_register_(uint8_t reg, uint8_t *value) {
138 if (this->is_failed()) {
139 ESP_LOGD(TAG, "Device marked failed");
140 return false;
141 }
142
143 this->last_error_ = this->read_register(reg, value, 1);
144 if (this->last_error_ != i2c::ERROR_OK) {
145 this->status_set_warning();
146 ESP_LOGE(TAG, "read_register_(): I2C I/O error: %d", (int) this->last_error_);
147 return false;
148 }
149
150 this->status_clear_warning();
151 return true;
152}
153
154bool PCA6416AComponent::write_register_(uint8_t reg, uint8_t value) {
155 if (this->is_failed()) {
156 ESP_LOGD(TAG, "Device marked failed");
157 return false;
158 }
159
160 this->last_error_ = this->write_register(reg, &value, 1);
161 if (this->last_error_ != i2c::ERROR_OK) {
162 this->status_set_warning();
163 ESP_LOGE(TAG, "write_register_(): I2C I/O error: %d", (int) this->last_error_);
164 return false;
165 }
166
167 this->status_clear_warning();
168 return true;
169}
170
171void PCA6416AComponent::update_register_(uint8_t pin, bool pin_value, uint8_t reg_addr) {
172 uint8_t bit = pin % 8;
173 uint8_t reg_value = 0;
174 if (reg_addr == PCA6416A_OUTPUT0) {
175 reg_value = this->output_0_;
176 } else if (reg_addr == PCA6416A_OUTPUT1) {
177 reg_value = this->output_1_;
178 } else {
179 this->read_register_(reg_addr, &reg_value);
180 }
181
182 if (pin_value) {
183 reg_value |= 1 << bit;
184 } else {
185 reg_value &= ~(1 << bit);
186 }
187
188 this->write_register_(reg_addr, reg_value);
189
190 if (reg_addr == PCA6416A_OUTPUT0) {
191 this->output_0_ = reg_value;
192 } else if (reg_addr == PCA6416A_OUTPUT1) {
193 this->output_1_ = reg_value;
194 }
195}
196
198
201bool PCA6416AGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
202void PCA6416AGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
203size_t PCA6416AGPIOPin::dump_summary(char *buffer, size_t len) const {
204 return buf_append_printf(buffer, len, 0, "%u via PCA6416A", this->pin_);
205}
206
207} // namespace esphome::pca6416a
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
bool status_has_warning() const
Definition component.h:278
bool status_has_error() const
Definition component.h:280
void disable_loop()
Disable this component's loop.
void status_clear_warning()
Definition component.h:289
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
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len) const
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:34
uint8_t address_
store the address of the device on the bus
Definition i2c.h:270
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:25
void digital_write_hw(uint8_t pin, bool value) override
Definition pca6416a.cpp:103
bool write_register_(uint8_t reg, uint8_t value)
Definition pca6416a.cpp:154
static void IRAM_ATTR gpio_intr(PCA6416AComponent *arg)
Definition pca6416a.cpp:60
bool read_register_(uint8_t reg, uint8_t *value)
Definition pca6416a.cpp:137
esphome::i2c::ErrorCode last_error_
Storage for last I2C error seen.
Definition pca6416a.h:45
void update_register_(uint8_t pin, bool pin_value, uint8_t reg_addr)
Definition pca6416a.cpp:171
uint16_t input_mask_
Cache for input values (16-bit combined for both banks)
Definition pca6416a.h:43
bool has_pullup_
Only the PCAL6416A has pull-up resistors.
Definition pca6416a.h:47
void pin_mode(uint8_t pin, gpio::Flags flags)
Helper function to set the pin mode of a pin.
Definition pca6416a.cpp:108
void setup() override
Check i2c availability and setup masks.
Definition pca6416a.cpp:25
float get_setup_priority() const override
Definition pca6416a.cpp:197
bool digital_read_hw(uint8_t pin) override
Definition pca6416a.cpp:85
bool digital_read_cache(uint8_t pin) override
Definition pca6416a.cpp:101
uint8_t output_0_
The mask to write as output state - 1 means HIGH, 0 means LOW.
Definition pca6416a.h:40
size_t dump_summary(char *buffer, size_t len) const override
Definition pca6416a.cpp:203
void digital_write(bool value) override
Definition pca6416a.cpp:202
PCA6416AComponent * parent_
Definition pca6416a.h:68
void pin_mode(gpio::Flags flags) override
Definition pca6416a.cpp:200
uint16_t flags
@ INTERRUPT_FALLING_EDGE
Definition gpio.h:51
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_PULLUP
Definition gpio.h:30
@ FLAG_INPUT
Definition gpio.h:27
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:14
constexpr float IO
For components that represent GPIO pins like PCF8573.
Definition component.h:39
const void size_t len
Definition hal.h:64