Configuration¶
What you can set before and at start-up: the address and variant, retries, the power-up state and the
compile-time pin configuration that InitFromConfig() applies.
Address and variant¶
Both constructors take the I2C port by pointer and an optional pcal95555::ChipVariant:
| Constructor | Address |
|---|---|
PCAL95555(bus, a0, a1, a2, variant = Unknown) |
0x20 + (a2 << 2 | a1 << 1 | a0) |
PCAL95555(bus, uint8_t address, variant = Unknown) |
address, clamped to 0x20 to 0x27 without an error |
// Skip auto-detection when the board fixes the part.
void make_drivers(MyI2c& bus) {
using pcal95555::ChipVariant;
Gpio auto_detect(&bus, uint8_t{0x20}); // probes 0x4F once
Gpio known_pcal(&bus, uint8_t{0x21}, ChipVariant::PCAL9555A);
Gpio known_pca(&bus, true, true, false, ChipVariant::PCA9555); // 0x23
(void)auto_detect;
(void)known_pcal;
(void)known_pca;
}
Unknown (the default) runs the detection probe described in PCA9555 and PCAL9555A.
Start-up sequence¶
bool apply_startup_config(Gpio& gpio) {
gpio.SetRetries(2); // each register access tries up to 3 times
gpio.ResetToDefault(); // datasheet power-up values (both banks on a PCAL9555A)
gpio.InitFromConfig(); // then the CONFIG_PCAL95555_* values
return !gpio.HasAnyError();
}
| Call | Effect |
|---|---|
SetRetries(n) |
Each register access is tried n + 1 times before it fails; default n = 1. The detection probe always runs without retries |
ResetToDefault() |
Writes the datasheet power-up value of every register: outputs high, no inversion, all inputs; on a PCAL9555A also full drive, no latch, pull-ups on, interrupts masked, push-pull |
InitFromConfig() |
Writes the compile-time configuration below: Output Port and Configuration registers; on a PCAL9555A also pull enable, pull select and output mode. Does nothing when CONFIG_PCAL95555_INIT_FROM_KCONFIG is 0 |
Compile-time pin configuration¶
InitFromConfig() reads CONFIG_PCAL95555_* macros. inc/pcal95555_kconfig.hpp
defines every one that is not already defined, and the Kconfig file at the repository root
describes the same options as an ESP-IDF menu.
| Macro | Default | Meaning |
|---|---|---|
CONFIG_PCAL95555_INIT_FROM_KCONFIG |
1 |
InitFromConfig() applies the values below; 0 makes it a no-op |
CONFIG_PCAL95555_Pp_n_DIR |
1 |
Pin Pp_n is an input (1) or output (0) |
CONFIG_PCAL95555_Pp_n_OUTPUT |
0 |
Initial output level |
CONFIG_PCAL95555_Pp_n_PULL |
0 |
Pull resistor enabled (PCAL9555A) |
CONFIG_PCAL95555_Pp_n_PULL_UP |
1 |
Pull-up (1) or pull-down (0) (PCAL9555A) |
CONFIG_PCAL95555_PORT0_OD, CONFIG_PCAL95555_PORT1_OD |
0 |
Port in open-drain mode (PCAL9555A) |
p is the port (0 or 1) and n the pin (0 to 7), for example CONFIG_PCAL95555_P1_3_DIR. The header combines
them into 16-bit values (CONFIG_PCAL95555_INIT_DIRECTION, _INIT_OUTPUT, _INIT_PULL_ENABLE, _INIT_PULL_UP)
that you can also define directly, for example with target_compile_definitions().
The defaults are not the power-up state
With every macro at its default, InitFromConfig() drives all outputs low in the Output Port register and, on
a PCAL9555A, disables every pull resistor (the chip powers up with pull-ups on). Define the macros you need
before calling it, or call only ResetToDefault().
ESP-IDF menuconfig
The ESP-IDF component wrapper in examples/esp32/components/hf_pcal95555/ sources the root Kconfig, so
idf.py menuconfig shows the options under PCAL95555 GPIO expander and the driver reads them from
sdkconfig.h. A bool set to n is absent from sdkconfig.h; while that menu is enabled
(CONFIG_PCAL95555 defined) the driver reads an absent option as 0, not as the default above. If you copy
the component elsewhere, keep its Kconfig pointing at the driver's root Kconfig.
CONFIG_PCAL95555_DEFAULT_ADDRESS in Kconfig is not read by the driver.
Run-time settings¶
Everything else (directions, polarity, pulls, drive strength, latch, output mode, interrupt mask) is a run-time call; the API guide shows each one. Recommended settings by pin use:
| Pin use | PCA9555 | PCAL9555A |
|---|---|---|
| Push button to ground | Input; external pull-up if the line is long | Input, pull-up (power-up default), latch if presses are short |
| LED to VDD (sinking) | Output, high = off | Output, drive Level3 (power-up default) |
| Shared or wired-OR line | Not possible: push-pull only | SetOutputMode() open drain for that port, then output |
| Interrupt input | Input | Input, then ConfigureInterrupt(pin, InterruptState::Enabled) |
Next: Porting.