ESPHome 2025.9.0
Loading...
Searching...
No Matches
pca9554.cpp
Go to the documentation of this file.
1#include "pca9554.h"
2#include "esphome/core/log.h"
3
4namespace esphome {
5namespace pca9554 {
6
7// for 16 bit expanders, these addresses will be doubled.
8const uint8_t INPUT_REG = 0;
9const uint8_t OUTPUT_REG = 1;
10const uint8_t INVERT_REG = 2;
11const uint8_t CONFIG_REG = 3;
12
13static const char *const TAG = "pca9554";
14
16 this->reg_width_ = (this->pin_count_ + 7) / 8;
17 // Test to see if device exists
18 if (!this->read_inputs_()) {
19 ESP_LOGE(TAG, "PCA95xx not detected at 0x%02X", this->address_);
20 this->mark_failed();
21 return;
22 }
23
24 // No polarity inversion
25 this->write_register_(INVERT_REG, 0);
26 // All inputs at initialization
27 this->config_mask_ = 0;
28 // Invert mask as the part sees a 1 as an input
29 this->write_register_(CONFIG_REG, ~this->config_mask_);
30 // All outputs low
31 this->output_mask_ = 0;
32 this->write_register_(OUTPUT_REG, this->output_mask_);
33 // Read the inputs
34 this->read_inputs_();
35 ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(),
36 this->status_has_error());
37}
38
40 // Invalidate the cache at the start of each loop.
41 // The actual read will happen on demand when digital_read() is called
42 this->reset_pin_cache_();
43}
44
46 ESP_LOGCONFIG(TAG,
47 "PCA9554:\n"
48 " I/O Pins: %d",
49 this->pin_count_);
50 LOG_I2C_DEVICE(this)
51 if (this->is_failed()) {
52 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
53 }
54}
55
57 // Read all pins from hardware into input_mask_
58 return this->read_inputs_(); // Return true if I2C read succeeded, false on error
59}
60
62 // Return the cached pin state from input_mask_
63 return this->input_mask_ & (1 << pin);
64}
65
66void PCA9554Component::digital_write_hw(uint8_t pin, bool value) {
67 if (value) {
68 this->output_mask_ |= (1 << pin);
69 } else {
70 this->output_mask_ &= ~(1 << pin);
71 }
72 this->write_register_(OUTPUT_REG, this->output_mask_);
73}
74
75void PCA9554Component::pin_mode(uint8_t pin, gpio::Flags flags) {
76 if (flags == gpio::FLAG_INPUT) {
77 // Clear mode mask bit
78 this->config_mask_ &= ~(1 << pin);
79 } else if (flags == gpio::FLAG_OUTPUT) {
80 // Set mode mask bit
81 this->config_mask_ |= 1 << pin;
82 }
83 this->write_register_(CONFIG_REG, ~this->config_mask_);
84}
85
87 uint8_t inputs[2];
88
89 if (this->is_failed()) {
90 ESP_LOGD(TAG, "Device marked failed");
91 return false;
92 }
93
94 this->last_error_ = this->read_register(INPUT_REG * this->reg_width_, inputs, this->reg_width_);
95 if (this->last_error_ != i2c::ERROR_OK) {
96 this->status_set_warning();
97 ESP_LOGE(TAG, "read_register_(): I2C I/O error: %d", (int) this->last_error_);
98 return false;
99 }
100 this->status_clear_warning();
101 this->input_mask_ = inputs[0];
102 if (this->reg_width_ == 2) {
103 this->input_mask_ |= inputs[1] << 8;
104 }
105 return true;
106}
107
108bool PCA9554Component::write_register_(uint8_t reg, uint16_t value) {
109 uint8_t outputs[2];
110 outputs[0] = (uint8_t) value;
111 outputs[1] = (uint8_t) (value >> 8);
112 this->last_error_ = this->write_register(reg * this->reg_width_, outputs, this->reg_width_);
113 if (this->last_error_ != i2c::ERROR_OK) {
114 this->status_set_warning();
115 ESP_LOGE(TAG, "write_register_(): I2C I/O error: %d", (int) this->last_error_);
116 return false;
117 }
118
119 this->status_clear_warning();
120 return true;
121}
122
124
125// Run our loop() method early to invalidate cache before any other components access the pins
126float PCA9554Component::get_loop_priority() const { return 9.0f; } // Just after WIFI
127
129void PCA9554GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
130bool PCA9554GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
131void PCA9554GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
132std::string PCA9554GPIOPin::dump_summary() const {
133 char buffer[32];
134 snprintf(buffer, sizeof(buffer), "%u via PCA9554", pin_);
135 return buffer;
136}
137
138} // namespace pca9554
139} // namespace esphome
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
void status_set_warning(const char *message=nullptr)
bool status_has_warning() const
bool status_has_error() const
void status_clear_warning()
bool digital_read(P pin)
Read the state of the given pin.
Definition cached_gpio.h:34
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:41
uint8_t address_
store the address of the device on the bus
Definition i2c.h:302
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:32
float get_setup_priority() const override
Definition pca9554.cpp:123
size_t pin_count_
number of bits the expander has
Definition pca9554.h:42
bool digital_read_cache(uint8_t pin) override
Definition pca9554.cpp:61
bool write_register_(uint8_t reg, uint16_t value)
Definition pca9554.cpp:108
uint16_t output_mask_
The mask to write as output state - 1 means HIGH, 0 means LOW.
Definition pca9554.h:48
size_t reg_width_
width of registers
Definition pca9554.h:44
void digital_write_hw(uint8_t pin, bool value) override
Definition pca9554.cpp:66
bool digital_read_hw(uint8_t pin) override
Definition pca9554.cpp:56
float get_loop_priority() const override
Definition pca9554.cpp:126
uint16_t input_mask_
The state of the actual input pin states - 1 means HIGH, 0 means LOW.
Definition pca9554.h:50
void pin_mode(uint8_t pin, gpio::Flags flags)
Helper function to set the pin mode of a pin.
Definition pca9554.cpp:75
uint16_t config_mask_
Mask for the pin config - 1 means OUTPUT, 0 means INPUT.
Definition pca9554.h:46
void loop() override
Invalidate cache at start of each loop.
Definition pca9554.cpp:39
void setup() override
Check i2c availability and setup masks.
Definition pca9554.cpp:15
esphome::i2c::ErrorCode last_error_
Storage for last I2C error seen.
Definition pca9554.h:52
void pin_mode(gpio::Flags flags) override
Definition pca9554.cpp:129
std::string dump_summary() const override
Definition pca9554.cpp:132
PCA9554Component * parent_
Definition pca9554.h:72
void digital_write(bool value) override
Definition pca9554.cpp:131
@ FLAG_OUTPUT
Definition gpio.h:19
@ FLAG_INPUT
Definition gpio.h:18
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:33
const uint8_t INPUT_REG
Definition pca9554.cpp:8
const uint8_t INVERT_REG
Definition pca9554.cpp:10
const uint8_t CONFIG_REG
Definition pca9554.cpp:11
const uint8_t OUTPUT_REG
Definition pca9554.cpp:9
const float IO
For components that represent GPIO pins like PCF8573.
Definition component.cpp:47
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7