This guide helps you diagnose and resolve common issues when using the PCAL95555 driver.
Common Error Messages
Error: Device Not Detected
Symptoms:
ResetToDefault() or other operations fail
- No response from device
Causes:
- Wrong I2C address
- Hardware connections incorrect
- Pull-up resistors missing
Solutions:
- Check I2C address:
- Default is 0x20 (all A0-A2 pins to GND)
- Use I2C scanner to verify device address
- Update address pin levels in constructor if different:
PCAL95555 driver(bus, true, false, false);
- Use
GetAddress() to verify current address: uint8_t addr = driver.GetAddress();
printf("Current address: 0x%02X\n", addr);
- Verify hardware connections:
- Check SDA/SCL connections
- Verify 4.7kΩ pull-up resistors on SCL and SDA
- Ensure power connections (VDD and GND)
- Test I2C bus:
- Verify I2C bus is properly initialized
- Check I2C bus speed (try 100 kHz if 400 kHz fails)
Error: I2C Communication Failures
Symptoms:
- Operations fail intermittently
- Timeout errors
Solutions:
- Increase retries:
- Check bus speed: Reduce I2C speed if using long wires
- Verify signal integrity: Check for noise on I2C lines
Incorrect Pin States
Symptoms:
- Pins don't respond to writes
- Reads return wrong values
Checklist:
- [ ] Verify pin direction is set correctly
- [ ] Check pin is configured as output before writing
- [ ] Verify pull resistors are configured if needed
- [ ] Check for external loads affecting pin state
Runtime Errors
Initialization Fails
Checklist:
- [ ] I2C interface is properly implemented
- [ ] I2C bus is initialized
- [ ] Hardware connections are correct
- [ ] I2C address matches hardware configuration
Pin Operations Fail
Checklist:
- [ ] Pin number is valid (0-15)
- [ ] Pin direction is set correctly
- [ ] I2C communication is working
- [ ] Error flags are checked
Error: Invalid Address (InvalidAddress)
Symptoms:
- Constructor or
ChangeAddress() sets Error::InvalidAddress (flag 0x0020)
- Methods fail after providing an out-of-range address
Cause: The I2C address provided is outside the valid range 0x20-0x27. The PCA9555/PCAL9555A only responds to addresses in this range (determined by the A0-A2 hardware pins).
Solutions:
- Check address parameter: Ensure the address is between
0x20 and 0x27:
PCAL95555 driver(bus, 0x20);
PCAL95555 driver(bus, 0x50);
- Use pin-level constructor: The pin-level constructor always computes a valid address:
PCAL95555 driver(bus, false, false, false);
- Check error flags: After construction, verify no errors:
if (driver.GetErrorFlags() & static_cast<uint16_t>(Error::InvalidAddress)) {
printf("Invalid I2C address!\n");
}
Error: ChipVariant Shows "Unknown"
Symptoms:
GetChipVariant() returns ChipVariant::Unknown
HasAgileIO() returns false
Cause: The 3-step chip detection probe could not confirm the chip type. This usually means the bus was unhealthy during initialization.
Solutions:
- Check I2C pull-up resistors (4.7kΩ on SDA and SCL)
- Verify power supply is stable
- Ensure no other I2C master is on the bus
- Force the variant in the constructor to skip detection:
PCAL95555 driver(bus, 0x20, pcal95555::ChipVariant::PCA9555);
FAQ
Q: Why do my pin writes not work?
A: Common causes:
- Pin not configured as output: Call
SetPinDirection(pin, GPIODir::Output) first
- Wrong pin number: Valid pins are 0-15
- I2C communication failure: Check I2C bus and connections
Q: How do I use interrupts?
A: There are two ways to handle interrupts:
Method 1: Per-pin callbacks (recommended)
gpio.SetPinDirection(pin, GPIODir::Input);
gpio.SetPullEnable(pin, true);
gpio.EnableInputLatch(pin, true);
gpio.ConfigureInterrupt(pin, InterruptState::Enabled);
gpio.RegisterPinInterrupt(pin, InterruptEdge::Rising, [](uint16_t p, bool state) {
printf("Pin %d interrupt!\n", p);
});
gpio.RegisterInterruptHandler();
gpio.HandleInterrupt();
Method 2: Global callback
gpio.SetInterruptCallback([](uint16_t status) {
printf("Interrupt on pins: 0x%04X\n", status);
});
Q: Can I use multiple devices?
A: Yes! Configure different I2C addresses via A0-A2 pins, then create separate driver instances. You can even mix PCA9555 and PCAL9555A on the same bus:
pcal95555::PCAL95555<MyI2c> gpio1(&i2c, false, false, false);
pcal95555::PCAL95555<MyI2c> gpio2(&i2c, true, false, false);
You can also change the address dynamically if your I2C interface supports GPIO control:
if (gpio1.ChangeAddress(true, false, false)) {
printf("Address changed to 0x%02X\n", gpio1.GetAddress());
}
Q: How do I know which chip I have (PCA9555 vs PCAL9555A)?
A: The driver auto-detects during initialization:
gpio.EnsureInitialized();
if (gpio.HasAgileIO()) {
printf("PCAL9555A (extended features available)\n");
} else {
printf("PCA9555 (standard GPIO only)\n");
}
You can also check the chip marking. PCA9555 has part number "PCA9555"; PCAL9555A has "PCAL9555A".
Q: What's the difference between pull-up and pull-down?
A:
- Pull-up: Resistor connects pin to VDD (default high when floating)
- Pull-down: Resistor connects pin to GND (default low when floating)
Choose based on your circuit requirements.
Q: What drive strength levels are available?
A: The driver supports four drive strength levels:
Level0: 25% drive strength (¼)
Level1: 50% drive strength (½)
Level2: 75% drive strength (¾)
Level3: 100% drive strength (full)
Example:
gpio.SetDriveStrength(pin, DriveStrength::Level1);
Q: How do I check for errors?
A: Use error flags to check for errors:
uint16_t errors = gpio.GetErrorFlags();
if (errors & static_cast<uint16_t>(Error::I2CReadFail)) {
}
if (errors & static_cast<uint16_t>(Error::I2CWriteFail)) {
}
if (errors & static_cast<uint16_t>(Error::InvalidPin)) {
}
if (errors & static_cast<uint16_t>(Error::UnsupportedFeature)) {
}
if (errors & static_cast<uint16_t>(Error::InvalidAddress)) {
}
gpio.ClearErrorFlags();
Note: ReadPins() now properly reports Error::I2CReadFail when the underlying I2C read fails, instead of silently returning empty results.
Navigation ⬅️ Examples | Back to Index