pca9554 cache reads (#5137)

This commit is contained in:
Steve Rodgers 2023-08-11 17:50:33 -07:00 committed by Jesse Hills
parent 99a765dc06
commit be6f95d43e
No known key found for this signature in database
GPG key ID: BEAAE804EFD8E83A
2 changed files with 29 additions and 2 deletions

View file

@ -26,7 +26,7 @@ void PCA9554Component::setup() {
this->config_mask_ = 0;
// Invert mask as the part sees a 1 as an input
this->write_register_(CONFIG_REG, ~this->config_mask_);
// All ouputs low
// All outputs low
this->output_mask_ = 0;
this->write_register_(OUTPUT_REG, this->output_mask_);
// Read the inputs
@ -34,6 +34,14 @@ void PCA9554Component::setup() {
ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(),
this->status_has_error());
}
void PCA9554Component::loop() {
// The read_inputs_() method will cache the input values from the chip.
this->read_inputs_();
// Clear all the previously read flags.
this->was_previously_read_ = 0x00;
}
void PCA9554Component::dump_config() {
ESP_LOGCONFIG(TAG, "PCA9554:");
LOG_I2C_DEVICE(this)
@ -43,7 +51,16 @@ void PCA9554Component::dump_config() {
}
bool PCA9554Component::digital_read(uint8_t pin) {
this->read_inputs_();
// Note: We want to try and avoid doing any I2C bus read transactions here
// to conserve I2C bus bandwidth. So what we do is check to see if we
// have seen a read during the time esphome is running this loop. If we have,
// we do an I2C bus transaction to get the latest value. If we haven't
// we return a cached value which was read at the time loop() was called.
if (this->was_previously_read_ & (1 << pin))
this->read_inputs_(); // Force a read of a new value
// Indicate we saw a read request for this pin in case a
// read happens later in the same loop.
this->was_previously_read_ |= (1 << pin);
return this->input_mask_ & (1 << pin);
}
@ -98,6 +115,10 @@ bool PCA9554Component::write_register_(uint8_t reg, uint8_t value) {
float PCA9554Component::get_setup_priority() const { return setup_priority::IO; }
// Run our loop() method very early in the loop, so that we cache read values before
// before other components call our digital_read() method.
float PCA9554Component::get_loop_priority() const { return 9.0f; } // Just after WIFI
void PCA9554GPIOPin::setup() { pin_mode(flags_); }
void PCA9554GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
bool PCA9554GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }

View file

@ -13,6 +13,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice {
/// Check i2c availability and setup masks
void setup() override;
/// Poll for input changes periodically
void loop() override;
/// Helper function to read the value of a pin.
bool digital_read(uint8_t pin);
/// Helper function to write the value of a pin.
@ -22,6 +24,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice {
float get_setup_priority() const override;
float get_loop_priority() const override;
void dump_config() override;
protected:
@ -35,6 +39,8 @@ class PCA9554Component : public Component, public i2c::I2CDevice {
uint8_t output_mask_{0x00};
/// The state of the actual input pin states - 1 means HIGH, 0 means LOW
uint8_t input_mask_{0x00};
/// Flags to check if read previously during this loop
uint8_t was_previously_read_ = {0x00};
/// Storage for last I2C error seen
esphome::i2c::ErrorCode last_error_;
};