This guide covers all configuration options available for the PCAL95555 driver.
I2C Address Configuration
The PCA9555 / PCAL9555A I2C address is configured via hardware pins A0-A2. Each pin represents one bit of the 3-bit address field. Both chip variants use the same address scheme.
| Pin | Address Bit | Description |
| A0 | Bit 0 | Least significant address bit |
| A1 | Bit 1 | |
| A2 | Bit 2 | Most significant address bit |
Default I2C address: 0x20 (all address pins to GND)
Address Range: 0x20 to 0x27 (7-bit I2C addresses)
Address Pin Configuration Table
| A2 | A1 | A0 | I2C Address (7-bit) | Constructor Call |
| LOW | LOW | LOW | 0x20 (default) | PCAL95555(bus, false, false, false) |
| LOW | LOW | HIGH | 0x21 | PCAL95555(bus, true, false, false) |
| LOW | HIGH | LOW | 0x22 | PCAL95555(bus, false, true, false) |
| LOW | HIGH | HIGH | 0x23 | PCAL95555(bus, true, true, false) |
| HIGH | LOW | LOW | 0x24 | PCAL95555(bus, false, false, true) |
| HIGH | LOW | HIGH | 0x25 | PCAL95555(bus, true, false, true) |
| HIGH | HIGH | LOW | 0x26 | PCAL95555(bus, false, true, true) |
| HIGH | HIGH | HIGH | 0x27 | PCAL95555(bus, true, true, true) |
Dynamic Address Changes
If your I2C interface supports GPIO control of address pins (via SetAddressPins()), you can change the address dynamically:
Option 1: Using address directly (recommended)
if (gpio.ChangeAddress(0x21)) {
printf("Address changed to 0x%02X\n", gpio.GetAddress());
}
if (gpio.ChangeAddress(0x25)) {
printf("Address changed to 0x%02X\n", gpio.GetAddress());
}
Option 2: Using pin levels
if (gpio.ChangeAddress(true, false, false)) {
printf("Address changed to 0x%02X\n", gpio.GetAddress());
}
Get current address and address bits:
uint8_t addr = gpio.GetAddress();
uint8_t bits = gpio.GetAddressBits();
Note: Dynamic address changes require hardware support. If address pins are hardwired, ChangeAddress() will still update internal state but won't change hardware pins.
Kconfig Configuration (Optional)
If your project uses Kconfig (e.g., ESP-IDF), the driver supports compile-time configuration.
The Kconfig compile-time macros are defined in a dedicated header: inc/pcal95555_kconfig.hpp. This file is automatically included by the main pcal95555.hpp header – no additional includes are needed.
Kconfig file: Kconfig
Configuration Options
- Per-pin direction: Configure each pin as input (1) or output (0)
- Per-pin pull-up/pull-down: Enable pull resistors and select direction
- Per-pin initial output: Set initial output state
- Port open-drain: Configure ports for open-drain or push-pull mode
Using Kconfig
- Run
idf.py menuconfig (or your Kconfig tool)
- Navigate to component configuration
- Configure per-pin settings as needed
- Use
InitFromConfig() to apply settings:
Runtime Configuration
Pin Direction
Set individual pin direction:
gpio.SetPinDirection(0, pcal95555::PCAL95555<MyI2c>::GPIODir::Output);
gpio.SetPinDirection(1, pcal95555::PCAL95555<MyI2c>::GPIODir::Input);
gpio.SetMultipleDirections(0x000F, pcal95555::PCAL95555<MyI2c>::GPIODir::Output);
Pull Resistors (PCAL9555A only)
Note: These features require the PCAL9555A. On a standard PCA9555, these methods return false and set Error::UnsupportedFeature. Check with HasAgileIO() first.
if (gpio.HasAgileIO()) {
gpio.SetPullEnable(0, true);
gpio.SetPullDirection(0, true);
gpio.SetPullEnable(1, true);
gpio.SetPullDirection(1, false);
}
Drive Strength (PCAL9555A only)
Note: Requires PCAL9555A. Returns false with Error::UnsupportedFeature on PCA9555.
gpio.SetDriveStrength(0, pcal95555::PCAL95555<MyI2c>::DriveStrength::Level3);
Drive Strength Levels:
Level0: 25% drive strength (¼)
Level1: 50% drive strength (½)
Level2: 75% drive strength (¾)
Level3: 100% drive strength (full)
Output Mode (PCAL9555A only)
Note: Requires PCAL9555A. Returns false with Error::UnsupportedFeature on PCA9555.
gpio.SetOutputMode(true, false);
Polarity Inversion
Invert input polarity:
gpio.SetPinPolarity(0, pcal95555::PCAL95555<MyI2c>::Polarity::Inverted);
gpio.SetMultiplePolarities(0x00FF, pcal95555::PCAL95555<MyI2c>::Polarity::Inverted);
Default Configuration
ResetToDefault()
Resets all registers to power-on defaults:
Default State:
- All pins: Inputs with pull-ups enabled
- Drive strength: Full
- Output mode: Push-pull
- Interrupts: Masked (disabled)
- Polarity: Normal (not inverted)
Location: src/pcal95555.ipp
Chip Variant Configuration
The driver auto-detects the chip variant (PCA9555 vs PCAL9555A) during initialization. You can also force a specific variant via the constructor to skip the detection probe:
pcal95555::PCAL95555<MyI2c> gpio(&i2c, 0x20);
pcal95555::PCAL95555<MyI2c> gpio(&i2c, 0x20, pcal95555::ChipVariant::PCA9555);
pcal95555::PCAL95555<MyI2c> gpio(&i2c, 0x20, pcal95555::ChipVariant::PCAL9555A);
Query the detected variant at runtime:
if (gpio.HasAgileIO()) {
}
auto variant = gpio.GetChipVariant();
Interrupt Configuration
Basic Interrupt Setup
gpio.ConfigureInterrupt(5, InterruptState::Enabled);
gpio.ConfigureInterrupt(3, InterruptState::Disabled);
gpio.ConfigureInterrupts({
{0, InterruptState::Enabled},
{5, InterruptState::Enabled},
{10, InterruptState::Enabled},
{3, InterruptState::Disabled}
});
gpio.SetInterruptCallback([](uint16_t status) {
printf("Interrupt on pins: 0x%04X\n", status);
});
gpio.HandleInterrupt();
Per-Pin Interrupt Callbacks
gpio.RegisterPinInterrupt(5, InterruptEdge::Rising, [](uint16_t pin, bool state) {
printf("Pin %d went HIGH\n", pin);
});
gpio.RegisterPinInterrupt(3, InterruptEdge::Falling, [](uint16_t pin, bool state) {
printf("Pin %d went LOW\n", pin);
});
gpio.RegisterPinInterrupt(7, InterruptEdge::Both, [](uint16_t pin, bool state) {
printf("Pin %d changed to %s\n", pin, state ? "HIGH" : "LOW");
});
gpio.RegisterInterruptHandler();
Get Interrupt Status
uint16_t status = gpio.GetInterruptStatus();
Recommended Settings
For Input Pins
gpio.SetPinDirection(pin, pcal95555::PCAL95555<MyI2c>::GPIODir::Input);
gpio.SetPullEnable(pin, true);
gpio.SetPullDirection(pin, true);
For Output Pins
gpio.SetPinDirection(pin, pcal95555::PCAL95555<MyI2c>::GPIODir::Output);
gpio.SetDriveStrength(pin, pcal95555::PCAL95555<MyI2c>::DriveStrength::Level3);
gpio.WritePin(pin, false);
For Interrupt-Driven Inputs
gpio.SetPinDirection(pin, pcal95555::PCAL95555<MyI2c>::GPIODir::Input);
gpio.SetPullEnable(pin, true);
gpio.SetPullDirection(pin, true);
gpio.EnableInputLatch(pin, true);
gpio.ConfigureInterrupt(pin, InterruptState::Enabled);
Next Steps