mirror of
https://github.com/esphome/esphome.git
synced 2025-07-28 14:16:40 +00:00
Added Banking support to tca9555, fixed input bug (#8003)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
f4b5f32cb4
commit
8d33c6de36
@ -8,30 +8,45 @@ namespace esphome {
|
|||||||
namespace gpio_expander {
|
namespace gpio_expander {
|
||||||
|
|
||||||
/// @brief A class to cache the read state of a GPIO expander.
|
/// @brief A class to cache the read state of a GPIO expander.
|
||||||
|
/// This class caches reads between GPIO Pins which are on the same bank.
|
||||||
|
/// This means that for reading whole Port (ex. 8 pins) component needs only one
|
||||||
|
/// I2C/SPI read per main loop call. It assumes, that one bit in byte identifies one GPIO pin
|
||||||
|
/// Template parameters:
|
||||||
|
/// T - Type which represents internal register. Could be uint8_t or uint16_t. Adjust to
|
||||||
|
/// match size of your internal GPIO bank register.
|
||||||
|
/// N - Number of pins
|
||||||
template<typename T, T N> class CachedGpioExpander {
|
template<typename T, T N> class CachedGpioExpander {
|
||||||
public:
|
public:
|
||||||
bool digital_read(T pin) {
|
bool digital_read(T pin) {
|
||||||
if (!this->read_cache_invalidated_[pin]) {
|
uint8_t bank = pin / (sizeof(T) * BITS_PER_BYTE);
|
||||||
this->read_cache_invalidated_[pin] = true;
|
if (this->read_cache_invalidated_[bank]) {
|
||||||
return this->digital_read_cache(pin);
|
this->read_cache_invalidated_[bank] = false;
|
||||||
|
if (!this->digital_read_hw(pin))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return this->digital_read_hw(pin);
|
return this->digital_read_cache(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void digital_write(T pin, bool value) { this->digital_write_hw(pin, value); }
|
void digital_write(T pin, bool value) { this->digital_write_hw(pin, value); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// @brief Call component low level function to read GPIO state from device
|
||||||
virtual bool digital_read_hw(T pin) = 0;
|
virtual bool digital_read_hw(T pin) = 0;
|
||||||
|
/// @brief Call component read function from internal cache.
|
||||||
virtual bool digital_read_cache(T pin) = 0;
|
virtual bool digital_read_cache(T pin) = 0;
|
||||||
|
/// @brief Call component low level function to write GPIO state to device
|
||||||
virtual void digital_write_hw(T pin, bool value) = 0;
|
virtual void digital_write_hw(T pin, bool value) = 0;
|
||||||
|
const uint8_t cache_byte_size_ = N / (sizeof(T) * BITS_PER_BYTE);
|
||||||
|
|
||||||
|
/// @brief Invalidate cache. This function should be called in component loop().
|
||||||
void reset_pin_cache_() {
|
void reset_pin_cache_() {
|
||||||
for (T i = 0; i < N; i++) {
|
for (T i = 0; i < this->cache_byte_size_; i++) {
|
||||||
this->read_cache_invalidated_[i] = false;
|
this->read_cache_invalidated_[i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<bool, N> read_cache_invalidated_{};
|
static const uint8_t BITS_PER_BYTE = 8;
|
||||||
|
std::array<bool, N / (sizeof(T) * BITS_PER_BYTE)> read_cache_invalidated_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gpio_expander
|
} // namespace gpio_expander
|
||||||
|
@ -76,15 +76,20 @@ bool TCA9555Component::read_gpio_modes_() {
|
|||||||
bool TCA9555Component::digital_read_hw(uint8_t pin) {
|
bool TCA9555Component::digital_read_hw(uint8_t pin) {
|
||||||
if (this->is_failed())
|
if (this->is_failed())
|
||||||
return false;
|
return false;
|
||||||
bool success;
|
uint8_t data;
|
||||||
uint8_t data[2];
|
uint8_t bank_number = pin < 8 ? 0 : 1;
|
||||||
success = this->read_bytes(TCA9555_INPUT_PORT_REGISTER_0, data, 2);
|
uint8_t register_to_read = bank_number ? TCA9555_INPUT_PORT_REGISTER_1 : TCA9555_INPUT_PORT_REGISTER_0;
|
||||||
this->input_mask_ = (uint16_t(data[1]) << 8) | (uint16_t(data[0]) << 0);
|
if (!this->read_bytes(register_to_read, &data, 1)) {
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
this->status_set_warning("Failed to read input register");
|
this->status_set_warning("Failed to read input register");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
uint8_t second_half = this->input_mask_ >> 8;
|
||||||
|
uint8_t first_half = this->input_mask_;
|
||||||
|
if (bank_number) {
|
||||||
|
this->input_mask_ = (data << 8) | (uint16_t(first_half) << 0);
|
||||||
|
} else {
|
||||||
|
this->input_mask_ = (uint16_t(second_half) << 8) | (data << 0);
|
||||||
|
}
|
||||||
|
|
||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user