Construct a new PCAL95555 driver instance using address pin levels.
Construct a new PCAL95555 driver instance using address pin levels.
Initialization happens automatically on first method call, or explicitly via EnsureInitialized(). Initialization includes setting address pins, verifying I2C communication, and auto-detecting the chip variant.
// Auto-detect chip variant (default) PCAL95555 driver(bus, false, false, false);
// Force PCA9555 mode (skip Agile I/O detection) PCAL95555 driver(bus, false, false, false, ChipVariant::PCA9555);
// Force PCAL9555A mode PCAL95555 driver(bus, true, false, false, ChipVariant::PCAL9555A);
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <utility>
#include <stdio.h>
#include <string.h>
#include "pcal95555_version.h"
};
};
};
enum class Error : uint16_t {
};
return static_cast<Error>(
static_cast<uint16_t
>(lhs) |
static_cast<uint16_t
>(rhs));
}
return static_cast<Error>(
static_cast<uint16_t
>(lhs) &
static_cast<uint16_t
>(rhs));
}
inline constexpr Error operator~(
Error e)
noexcept {
return static_cast<Error>(~static_cast<uint16_t>(e));
}
struct PinReadResult {
[[nodiscard]] uint8_t
size()
const noexcept {
return count; }
[[nodiscard]]
bool empty()
const noexcept {
return count == 0; }
[[nodiscard]]
const std::pair<uint8_t, bool>&
operator[](uint8_t i)
const noexcept {
}
void push_back(uint8_t pin,
bool value)
noexcept {
}
}
[[nodiscard]]
bool contains(uint8_t pin)
const noexcept {
for (uint8_t i = 0; i <
count; ++i) {
if (
data[i].first == pin)
return true;
}
return false;
}
[[nodiscard]]
const std::pair<uint8_t, bool>*
find(uint8_t pin)
const noexcept {
for (uint8_t i = 0; i <
count; ++i) {
if (
data[i].first == pin)
return &
data[i];
}
return nullptr;
}
using iterator =
typename std::array<std::pair<uint8_t, bool>,
kMaxPins>::const_iterator;
};
};
template <typename I2cType>
class PCAL95555 {
public:
PCAL95555(I2cType* bus, bool a0_level, bool a1_level, bool a2_level,
explicit PCAL95555(I2cType* bus, uint8_t address,
return HF_PCAL95555_VERSION_STRING;
}
return HF_PCAL95555_VERSION_MAJOR;
}
return HF_PCAL95555_VERSION_MINOR;
}
return HF_PCAL95555_VERSION_PATCH;
}
bool SetDirections(std::initializer_list<std::pair<uint8_t, GPIODir>> configs)
noexcept;
bool ReadPin(uint8_t pin)
noexcept;
bool ReadPin(uint8_t pin,
bool& level)
noexcept;
bool WritePin(uint8_t pin,
bool value)
noexcept;
bool WritePins(std::initializer_list<std::pair<uint8_t, bool>> configs)
noexcept;
PinReadResult
ReadPins(std::initializer_list<uint8_t> pins)
noexcept;
bool SetPullEnables(std::initializer_list<std::pair<uint8_t, bool>> configs)
noexcept;
bool SetPullDirections(std::initializer_list<std::pair<uint8_t, bool>> configs)
noexcept;
bool SetDriveStrengths(std::initializer_list<std::pair<uint8_t, DriveStrength>> configs)
noexcept;
bool ConfigureInterrupts(std::initializer_list<std::pair<uint8_t, InterruptState>> configs)
noexcept;
bool SetOutputMode(
bool port_0_open_drain,
bool port_1_open_drain)
noexcept;
bool SetPolarities(std::initializer_list<std::pair<uint8_t, Polarity>> configs)
noexcept;
bool EnableInputLatches(std::initializer_list<std::pair<uint8_t, bool>> configs)
noexcept;
std::function<void(uint8_t pin, bool state)> callback);
[[nodiscard]] uint8_t
GetAddress()
const noexcept;
bool ChangeAddress(
bool a0_level,
bool a1_level,
bool a2_level)
noexcept;
protected:
private:
struct PinInterruptCallback {
std::function<void(uint8_t pin,
bool state)>
callback;
};
constexpr uint8_t BASE_ADDRESS = 0x20;
constexpr uint8_t MAX_BITS = 0x07;
return BASE_ADDRESS + (bits & MAX_BITS);
}
bool readDualPort(uint8_t reg0, uint8_t reg1, uint8_t& val0, uint8_t& val1)
noexcept;
bool writeDualPort(uint8_t reg0, uint8_t reg1, uint8_t val0, uint8_t val1)
noexcept;
};
#define PCAL95555_HEADER_INCLUDED
#if defined(__has_include)
#if __has_include("../src/pcal95555.ipp")
#include "../src/pcal95555.ipp"
#else
#endif
#else
#include "../src/pcal95555.ipp"
#endif
#undef PCAL95555_HEADER_INCLUDED
return HF_PCAL95555_VERSION_STRING;
}
}
#ifndef HF_PCAL95555_NO_GLOBAL_ALIASES
using pcal95555::operator|;
using pcal95555::operator&;
using pcal95555::operator~;
#endif
bool SetPullEnables(std::initializer_list< std::pair< uint8_t, bool > > configs) noexcept
Definition pcal95555.ipp:568
bool EnableMultipleInputLatches(uint16_t mask, bool enable) noexcept
Enable or disable input latch for multiple pins using a bitmask.
Definition pcal95555.ipp:1135
bool readDualPort(uint8_t reg0, uint8_t reg1, uint8_t &val0, uint8_t &val1) noexcept
Read both port registers (port0 and port1) in one call.
Definition pcal95555.ipp:261
bool writeRegister(uint8_t reg, uint8_t value) noexcept
Write a single byte to a device register with retry logic.
Definition pcal95555.ipp:154
bool EnsureInitialized() noexcept
Definition pcal95555.ipp:75
bool RegisterPinInterrupt(uint8_t pin, InterruptEdge edge, std::function< void(uint8_t pin, bool state)> callback)
Definition pcal95555.ipp:878
bool ReadDualPortRegister(uint8_t reg0, uint8_t reg1, uint16_t &value) noexcept
Read a dual-port register pair into a 16-bit pin mask.
Definition pcal95555.ipp:964
void InitFromConfig() noexcept
Initialize the device using values from Kconfig.
Definition pcal95555.ipp:221
bool initialize() noexcept
Perform actual initialization of the driver.
Definition pcal95555.ipp:97
bool SetPullEnable(uint8_t pin, bool enable) noexcept
Enable or disable the pull-up/pull-down resistor on a pin.
Definition pcal95555.ipp:537
ChipVariant user_variant_
Definition pcal95555.hpp:1133
bool SetMultipleOutputs(uint16_t mask, bool value) noexcept
Definition pcal95555.ipp:429
uint16_t previous_pin_states_
Definition pcal95555.hpp:1127
bool SetDriveStrength(uint8_t pin, DriveStrength level) noexcept
Configure the output drive strength for a GPIO pin.
Definition pcal95555.ipp:656
bool RegisterInterruptHandler() noexcept
Definition pcal95555.ipp:934
bool a1_level_
Definition pcal95555.hpp:1130
bool SetPinPolarity(uint8_t pin, Polarity polarity) noexcept
Configure input polarity inversion for a single pin.
Definition pcal95555.ipp:1061
uint8_t dev_addr_
Definition pcal95555.hpp:1121
bool SetPullDirections(std::initializer_list< std::pair< uint8_t, bool > > configs) noexcept
Definition pcal95555.ipp:597
bool GetPullConfiguration(uint16_t &enable_mask, uint16_t &direction_mask) noexcept
Read the current pull resistor configuration from hardware registers.
Definition pcal95555.ipp:626
void SetRetries(int retries) noexcept
Configure retry mechanism for I2C transactions.
Definition pcal95555.ipp:148
bool EnableInputLatches(std::initializer_list< std::pair< uint8_t, bool > > configs) noexcept
Definition pcal95555.ipp:1151
PinReadResult ReadPins(std::initializer_list< uint8_t > pins) noexcept
Definition pcal95555.ipp:495
uint16_t readPinStates() noexcept
Read current pin states from input port registers.
Definition pcal95555.ipp:946
bool detectChipVariant() noexcept
Detect the chip variant by probing an Agile I/O register.
Definition pcal95555.ipp:1238
static constexpr uint8_t GetDriverVersionMinor() noexcept
Get the compiled driver minor version number.
Definition pcal95555.hpp:341
bool EnableInputLatch(uint8_t pin, bool enable) noexcept
Enable or disable the input latch for a single pin.
Definition pcal95555.ipp:1120
bool HasError(Error e) const noexcept
Check if a specific error flag is set.
Definition pcal95555.ipp:1184
void ClearErrorFlags(uint16_t mask=0xFFFF) noexcept
Clear specific error flags by raw bitmask.
Definition pcal95555.ipp:1199
bool SetOutputMode(bool port_0_open_drain, bool port_1_open_drain) noexcept
Configure per-port output mode (push-pull or open-drain).
Definition pcal95555.ipp:865
uint8_t xfer_byte_
Definition pcal95555.hpp:1134
static constexpr const char * GetDriverVersion() noexcept
Definition pcal95555.hpp:325
bool a0_level_
Definition pcal95555.hpp:1129
bool readRegister(uint8_t reg, uint8_t &value) noexcept
Read a device register with retry logic.
Definition pcal95555.ipp:171
bool modifyDualPortByMask(uint8_t reg0, uint8_t reg1, uint16_t mask, bool bit_value) noexcept
Batch mask read-modify-write on a dual-port register pair.
Definition pcal95555.ipp:303
static constexpr uint8_t GetDriverVersionPatch() noexcept
Get the compiled driver patch version number.
Definition pcal95555.hpp:349
uint16_t GetErrorFlags() const noexcept
Retrieve currently latched error flags.
Definition pcal95555.ipp:1179
bool SetDirections(std::initializer_list< std::pair< uint8_t, GPIODir > > configs) noexcept
Definition pcal95555.ipp:355
void ClearError(Error e) noexcept
Clear a single error flag.
Definition pcal95555.ipp:1194
bool WriteDualPortRegister(uint8_t reg0, uint8_t reg1, uint16_t value) noexcept
Write a dual-port register pair from a 16-bit pin mask (no readback).
Definition pcal95555.ipp:981
bool ConfigureInterruptMask(uint16_t mask) noexcept
Definition pcal95555.ipp:834
bool a2_level_
Definition pcal95555.hpp:1131
uint8_t GetAddress() const noexcept
Get the current I2C address of the device.
Definition pcal95555.ipp:1290
bool HasAgileIO() const noexcept
Definition pcal95555.ipp:1215
bool SetDriveStrengths(std::initializer_list< std::pair< uint8_t, DriveStrength > > configs) noexcept
Definition pcal95555.ipp:684
void clearError(Error error_code) noexcept
Definition pcal95555.ipp:1209
bool SetPolarities(std::initializer_list< std::pair< uint8_t, Polarity > > configs) noexcept
Definition pcal95555.ipp:1092
uint8_t address_bits_
Definition pcal95555.hpp:1122
static constexpr uint8_t GetDriverVersionMajor() noexcept
Get the compiled driver major version number.
Definition pcal95555.hpp:333
bool ConfigureInterrupts(std::initializer_list< std::pair< uint8_t, InterruptState > > configs) noexcept
Definition pcal95555.ipp:788
uint8_t GetAddressBits() const noexcept
Get the current A2-A0 address bits.
Definition pcal95555.ipp:1296
bool changeAddressImpl(uint8_t new_bits) noexcept
Shared implementation for ChangeAddress overloads.
Definition pcal95555.ipp:1303
ChipVariant GetChipVariant() const noexcept
Get the detected chip variant.
Definition pcal95555.ipp:1221
bool WritePin(uint8_t pin, bool value) noexcept
Write a logical level to a GPIO output pin.
Definition pcal95555.ipp:413
bool ForceMarkInitialized(ChipVariant variant) noexcept
Mark the driver initialized without the probe read.
Definition pcal95555.ipp:83
bool SetPullDirection(uint8_t pin, bool pull_up) noexcept
Select internal pull-up or pull-down resistor direction.
Definition pcal95555.ipp:552
static constexpr uint8_t calculateAddress(uint8_t bits)
Calculate I2C address from A2-A0 bits.
Definition pcal95555.hpp:1142
void SetInterruptCallback(const std::function< void(uint16_t)> &callback) noexcept
Definition pcal95555.ipp:928
bool ChangeAddress(bool a0_level, bool a1_level, bool a2_level) noexcept
Definition pcal95555.ipp:1349
PinInterruptCallback pin_callbacks_[16]
Definition pcal95555.hpp:1126
std::function< void(uint16_t)> irq_callback_
Definition pcal95555.hpp:1125
uint16_t error_flags_
Definition pcal95555.hpp:1124
bool ReadPin(uint8_t pin) noexcept
Read the current logical level of a GPIO pin.
Definition pcal95555.ipp:384
bool SetMultipleDirections(uint16_t mask, GPIODir dir) noexcept
Set the direction for multiple GPIO pins at once using a bitmask.
Definition pcal95555.ipp:339
bool ConfigureInterrupt(uint8_t pin, InterruptState state) noexcept
Definition pcal95555.ipp:749
bool initialized_
Definition pcal95555.hpp:1128
ChipVariant chip_variant_
Definition pcal95555.hpp:1132
void setError(Error error_code) noexcept
Definition pcal95555.ipp:1204
bool SetMultiplePolarities(uint16_t mask, Polarity polarity) noexcept
Configure input polarity for multiple pins using a bitmask.
Definition pcal95555.ipp:1076
bool requireAgileIO() noexcept
Check that the chip supports Agile I/O, setting error if not.
Definition pcal95555.ipp:1227
void HandleInterrupt() noexcept
Internal handler to process an interrupt event.
Definition pcal95555.ipp:992
bool SetPinDirection(uint8_t pin, GPIODir dir) noexcept
Set the direction of a single GPIO pin.
Definition pcal95555.ipp:324
bool modifySinglePinRegister(uint8_t reg0, uint8_t reg1, uint8_t pin, bool bit_value) noexcept
Single-pin read-modify-write on a dual-port register pair.
Definition pcal95555.ipp:290
bool WritePins(std::initializer_list< std::pair< uint8_t, bool > > configs) noexcept
Definition pcal95555.ipp:466
uint16_t GetInterruptStatus() noexcept
Retrieve and clear the interrupt status.
Definition pcal95555.ipp:849
int retries_
Definition pcal95555.hpp:1123
bool TogglePin(uint8_t pin) noexcept
Toggle the output state of a GPIO pin.
Definition pcal95555.ipp:444
bool HasAnyError() const noexcept
Check if any error flag is set.
Definition pcal95555.ipp:1189
bool UnregisterPinInterrupt(uint8_t pin) noexcept
Unregister callback for a specific pin interrupt.
Definition pcal95555.ipp:906
void ResetToDefault() noexcept
Reset all registers to their power-on default state.
Definition pcal95555.ipp:185
bool writeDualPort(uint8_t reg0, uint8_t reg1, uint8_t val0, uint8_t val1) noexcept
Write both port registers (port0 and port1) in one call.
Definition pcal95555.ipp:278
I2cType * i2c_
Definition pcal95555.hpp:1120
uint16_t ReadAllInputs() noexcept
Definition pcal95555.ipp:956
Definition pcal95555.hpp:21
const char * GetDriverVersion() noexcept
Definition pcal95555.hpp:1255
InterruptState
Definition pcal95555.hpp:96
@ Enabled
Interrupt enabled (mask bit = 0)
@ Disabled
Interrupt disabled/masked (mask bit = 1)
GPIODir
Definition pcal95555.hpp:77
DriveStrength
Definition pcal95555.hpp:83
Pcal95555Reg
Register addresses for the PCA9555 / PCAL9555A I/O expander chips.
Definition pcal95555.hpp:47
@ INPUT_LATCH_0
Input latch port 0 [PCAL9555A only].
@ PULL_SELECT_0
Pull-up/pull-down selection port 0 [PCAL9555A only].
@ PULL_ENABLE_0
Pull-up/pull-down enable port 0 [PCAL9555A only].
@ CONFIG_PORT_1
Configuration (direction) port 1 [PCA9555 + PCAL9555A].
@ OUTPUT_PORT_1
Output port 1 [PCA9555 + PCAL9555A].
@ OUTPUT_PORT_0
Output port 0 [PCA9555 + PCAL9555A].
@ DRIVE_STRENGTH_2
Output drive strength port 1 low nibble [PCAL9555A only].
@ INPUT_PORT_1
Input port 1 (read-only) [PCA9555 + PCAL9555A].
@ INT_MASK_1
Interrupt mask port 1 [PCAL9555A only].
@ OUTPUT_CONF
Output port configuration [PCAL9555A only].
@ DRIVE_STRENGTH_0
Output drive strength port 0 low nibble [PCAL9555A only].
@ DRIVE_STRENGTH_1
Output drive strength port 0 high nibble [PCAL9555A only].
@ CONFIG_PORT_0
Configuration (direction) port 0 [PCA9555 + PCAL9555A].
@ PULL_SELECT_1
Pull-up/pull-down selection port 1 [PCAL9555A only].
@ INPUT_PORT_0
Input port 0 (read-only) [PCA9555 + PCAL9555A].
@ INT_STATUS_1
Interrupt status port 1 (read-only) [PCAL9555A only].
@ POLARITY_INV_1
Polarity inversion port 1 [PCA9555 + PCAL9555A].
@ DRIVE_STRENGTH_3
Output drive strength port 1 high nibble [PCAL9555A only].
@ INPUT_LATCH_1
Input latch port 1 [PCAL9555A only].
@ POLARITY_INV_0
Polarity inversion port 0 [PCA9555 + PCAL9555A].
@ INT_STATUS_0
Interrupt status port 0 (read-only) [PCAL9555A only].
@ PULL_ENABLE_1
Pull-up/pull-down enable port 1 [PCAL9555A only].
@ INT_MASK_0
Interrupt mask port 0 [PCAL9555A only].
ChipVariant
Identifies the detected or user-specified chip variant.
Definition pcal95555.hpp:203
@ PCAL9555A
NXP PCAL9555A with Agile I/O (registers 0x00-0x07 + 0x40-0x4F)
@ Unknown
Not yet detected (pre-initialization)
@ PCA9555
Standard PCA9555 (registers 0x00-0x07 only)
Polarity
Definition pcal95555.hpp:80
Error
Definition pcal95555.hpp:103
@ InvalidPin
Provided pin index out of range.
@ InvalidAddress
Provided I2C address is out of valid range (0x20-0x27)
@ UnsupportedFeature
Feature requires PCAL9555A but chip is PCA9555.
@ I2CReadFail
An I2C read operation failed.
@ I2CWriteFail
An I2C write operation failed.
@ InvalidMask
A mask-form call got a mask that selects no pin (0)
OutputMode
Definition pcal95555.hpp:86
InterruptEdge
Definition pcal95555.hpp:89
@ Falling
Trigger on falling edge (HIGH to LOW)
@ Both
Trigger on both edges.
@ Rising
Trigger on rising edge (LOW to HIGH)
Template implementation of PCAL95555 I/O expander driver.
CRTP-based I2C interface for PCAL95555 driver.
ESP-IDF Kconfig default macros for PCAL95555 driver initialization.
InterruptEdge edge
Definition pcal95555.hpp:1114
PinInterruptCallback()
Definition pcal95555.hpp:1117
std::function< void(uint8_t pin, bool state)> callback
Definition pcal95555.hpp:1113
bool registered
Definition pcal95555.hpp:1115
iterator begin() const noexcept
Definition pcal95555.hpp:191
iterator end() const noexcept
Definition pcal95555.hpp:192
const std::pair< uint8_t, bool > & operator[](uint8_t i) const noexcept
Access entry by index (no bounds check).
Definition pcal95555.hpp:159
uint8_t size() const noexcept
Number of populated entries.
Definition pcal95555.hpp:153
bool contains(uint8_t pin) const noexcept
Check whether a pin number is already stored in the result set.
Definition pcal95555.hpp:173
const std::pair< uint8_t, bool > * find(uint8_t pin) const noexcept
Definition pcal95555.hpp:182
uint8_t count
Number of valid entries in data[].
Definition pcal95555.hpp:148
typename std::array< std::pair< uint8_t, bool >, kMaxPins >::const_iterator iterator
Definition pcal95555.hpp:190
bool empty() const noexcept
True when no entries have been added.
Definition pcal95555.hpp:156
std::array< std::pair< uint8_t, bool >, kMaxPins > data
Pin number / value pairs.
Definition pcal95555.hpp:145
void push_back(uint8_t pin, bool value) noexcept
Append a pin/value pair. Silently drops entries beyond kMaxPins.
Definition pcal95555.hpp:164
static constexpr uint8_t kMaxPins
Maximum number of entries (constrained by hardware: 16 GPIO pins).
Definition pcal95555.hpp:142