PI4IOE5V I/O Expander
The Pi4ioe5v I/O expander component allows the user to configure inputs, outputs, polarity inversion, and internal pulls via I2C.
API Reference
Header File
Classes
-
class Pi4ioe5v : public espp::BasePeripheral<>
PI4IOE5V I2C GPIO Expander driver.
Class for communicating with and controlling a PI4IOE5V GPIO expander. The PI4IOE5V is an 8-bit I2C GPIO expander with interrupt capability and configurable pull-up/pull-down resistors. It operates at [1.65V, 5.5V] and supports I2C Fast-mode (400kHz) and Fast-mode Plus (1MHz).
The register layout used here matches the PI4IOE5V6408 datasheet.
Datasheet for the PI4IOE5V can be found here: https://www.diodes.com/datasheet/download/PI4IOE5V6408.pdf
Example
// make the I2C that we'll use to communicate espp::I2c i2c({ .port = I2C_NUM_1, .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO, .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE, }); // Configure PI4IOE5V: 8-bit port with mixed inputs/outputs espp::Pi4ioe5v exp({ .device_address = espp::Pi4ioe5v::DEFAULT_ADDRESS, .direction_mask = 0xF0, // upper 4 bits as outputs, lower 4 bits as inputs .interrupt_mask = 0xFF, // all interrupts disabled for now .initial_output = 0xA0, // initial pattern for outputs .write = std::bind_front(&espp::I2c::write, &i2c), .write_then_read = std::bind_front(&espp::I2c::write_read, &i2c), .auto_init = false, .log_level = espp::Logger::Verbosity::INFO, }); std::error_code ec; // Initialize separately from the constructor since we set auto_init to false if (!exp.initialize(ec)) { logger.error("PI4IOE5V initialization failed: {}", ec.message()); return; } // Configure pull resistors for input pins (lower 4 bits) exp.set_pull_resistor_for_pin(0xF0, espp::Pi4ioe5v::PullResistor::PULL_UP, ec); if (ec) { logger.error("Failed to configure pull resistors: {}", ec.message()); } // Create task to periodically toggle outputs and read inputs auto task_fn = [&](std::mutex &m, std::condition_variable &cv) { static auto start = std::chrono::high_resolution_clock::now(); static uint8_t output_pattern = 0x50; auto now = std::chrono::high_resolution_clock::now(); auto seconds = std::chrono::duration<float>(now - start).count(); // Toggle output pattern on upper 4 bits output_pattern ^= 0xF0; exp.output(output_pattern, ec); if (ec) { logger.error("Failed to set outputs: {}", ec.message()); return true; // stop the task } // Read all pins auto pins = exp.get_pins(ec); if (ec) { logger.error("Failed to read pins: {}", ec.message()); return true; // stop the task } // Read current output state auto outputs = exp.get_output(ec); if (ec) { logger.error("Failed to read outputs: {}", ec.message()); return true; // stop the task } fmt::print("{:.3f}, inputs: {:#04x}, outputs: {:#04x}\n", seconds, pins, outputs); // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed { std::unique_lock<std::mutex> lk(m); cv.wait_for(lk, 500ms); } // don't want to stop the task return false; }; auto task = espp::Task({.callback = task_fn, .task_config = {.name = "PI4IOE5V Task", .stack_size_bytes = 4 * 1024}, .log_level = espp::Logger::Verbosity::WARN}); fmt::print("% time(s), inputs (lower 4 bits), outputs (upper 4 bits)\n"); task.start();
Public Types
-
enum class PullResistor : uint8_t
The Pull Resistor configuration.
Values:
-
enumerator NO_PULL
No pull resistor enabled.
-
enumerator PULL_UP
Pull-up resistor enabled.
-
enumerator PULL_DOWN
Pull-down resistor enabled.
-
enumerator NO_PULL
-
typedef std::function<bool(uint8_t)> probe_fn
Function to probe the peripheral
- Param address:
The address to probe
- Return:
True if the peripheral is found at the given address
Public Functions
-
inline explicit Pi4ioe5v(const Config &config)
Construct the Pi4ioe5v. Will call initialize() if auto_init is true.
- Parameters:
config – Configuration structure for configuring the PI4IOE5V
-
inline bool initialize(std::error_code &ec)
Initialize the component class.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline uint8_t get_pins(std::error_code &ec)
Read the pin values.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
The pin values as an 8 bit mask.
-
inline bool output(uint8_t value, std::error_code &ec)
Write the pin values.
Note
This will overwrite any previous pin values for all output pins.
Note
Only affects pins configured as outputs.
Note
Pins configured as high-z will remain high-z.
Note
All pins default to high-z on power-up.
- Parameters:
value – The pin values to apply.
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline bool clear_pins(uint8_t mask, std::error_code &ec)
Clear the pin values according to the provided mask.
Reads the current pin values and clears any bits set in the mask.
- Parameters:
mask – The pin values as an 8 bit mask to clear.
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline bool set_pins(uint8_t value, std::error_code &ec)
Set the pin values according to the provided value.
Reads the current pin values and sets any bits set in the mask.
Note
Only affects pins configured as outputs.
- Parameters:
value – The pin values as an 8 bit mask to set.
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline uint8_t get_output(std::error_code &ec)
Read the output pin values.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
The pin values as an 8 bit mask.
-
inline uint8_t get_input(std::error_code &ec)
Read the input pin values.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
The pin values as an 8 bit mask.
-
inline uint8_t get_direction(std::error_code &ec)
Read the i/o direction for the pins.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
The direction as an 8 bit mask (1 = output, 0 = input).
-
inline bool set_direction(uint8_t mask, std::error_code &ec)
Set the i/o direction for the pins according to mask.
- Parameters:
mask – The mask indicating direction (1 = output, 0 = input)
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline bool set_pull_resistor_for_pin(uint8_t pin_mask, PullResistor pull, std::error_code &ec)
Set the pull resistor for the provided pins.
- Parameters:
pin_mask – The pin mask to configure for pull resistor.
pull – The pull resistor to configure.
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline bool set_interrupt_mask(uint8_t mask, std::error_code &ec)
Configure interrupt mask for the pins.
- Parameters:
mask – The pin mask to configure for interrupt (1 = disable interrupt, 0 = enable).
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline uint8_t get_interrupt_status(std::error_code &ec)
Read interrupt status.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
The interrupt status as an 8 bit mask (1 = interrupt triggered).
-
inline bool set_input_default(uint8_t value, std::error_code &ec)
Set input default values for input interrupts.
- Parameters:
value – The default value for the pins. An opposite value on input pins will trigger an interrupt.
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline bool set_output_high_impedance(uint8_t mask, std::error_code &ec)
Set output high impedance control.
- Parameters:
mask – The mask indicating which outputs should be high impedance (1 = high-Z).
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline bool reset(std::error_code &ec)
Perform a software reset of the device.
Note
This will reset all registers to their default values.
Note
This will cause the reset interrupt bit to be set in the CHIP_ID_CTRL register, which can be cleared by reading the register.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
true if successful, false if an error occurred.
-
inline uint8_t get_manufacturer_id(std::error_code &ec)
Read the manufacturer ID.
Note
The manufacturer ID is contained in bits 5,6,7 of the CHIP_ID_CTRL register. The expected value is 0b101 (Diodes Incorporated).
Note
The manufacturer ID will be shifted to the least significant bits in the return value.
Note
This read will also clear the reset interrupt bit if it was set.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
The manufacturer ID.
-
inline uint8_t get_firmware_revision(std::error_code &ec)
Read the firmware revision.
Note
The firmware revision is contained in bits 2,3,4 of the CHIP_ID_CTRL register.
Note
The firmware revision will be shifted to the least significant bits in the return value.
Note
This read will also clear the reset interrupt bit if it was set.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
The firmware revision.
-
inline uint8_t get_chip_id(std::error_code &ec)
Read the chip ID.
Note
This read will also clear the reset interrupt bit if it was set.
- Parameters:
ec – Error code to set if an error occurs.
- Returns:
The chip ID.
-
inline bool probe(std::error_code &ec) const
Probe the peripheral
Note
This function is thread safe
Note
If the probe function is not set, this function will return false and set the error code to operation_not_supported
Note
This function is only available if UseAddress is true
- Parameters:
ec – The error code to set if there is an error
- Returns:
True if the peripheral is found
-
inline void set_address(uint8_t address)
Set the address of the peripheral
Note
This function is thread safe
Note
This function is only available if UseAddress is true
- Parameters:
address – The address of the peripheral
-
inline void set_probe(const probe_fn &probe)
Set the probe function
Note
This function is thread safe
Note
This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.
Note
This function is only available if UseAddress is true
- Parameters:
probe – The probe function
-
inline void set_write(const write_fn &write)
Set the write function
Note
This function is thread safe
Note
This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.
- Parameters:
write – The write function
-
inline void set_read(const read_fn &read)
Set the read function
Note
This function is thread safe
Note
This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.
- Parameters:
read – The read function
-
inline void set_read_register(const read_register_fn &read_register)
Set the read register function
Note
This function is thread safe
Note
This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.
- Parameters:
read_register – The read register function
-
inline void set_write_then_read(const write_then_read_fn &write_then_read)
Set the write then read function
Note
This function is thread safe
Note
This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then
- Parameters:
write_then_read – The write then read function
-
inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)
Set the delay between the write and read operations in write_then_read
Note
This function is thread safe
Note
This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.
Note
This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.
- Parameters:
delay – The delay between the write and read operations in write_then_read
-
inline void set_config(const Config &config)
Set the configuration for the peripheral
Note
This function is thread safe
Note
The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.
- Parameters:
config – The configuration for the peripheral
-
inline void set_config(Config &&config)
Set the configuration for the peripheral
Note
This function is thread safe
Note
The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.
- Parameters:
config – The configuration for the peripheral
-
inline const Config &config() const
Get the configuration for the peripheral
- Returns:
The configuration for the peripheral
-
inline uint8_t address() const
Get the address of the peripheral
- Returns:
The address of the peripheral
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns:
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters:
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns:
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters:
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters:
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns:
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters:
rate_limit – The rate limit to use for the logger
Public Static Attributes
-
static constexpr uint8_t ADDRESS_LOW = 0x43
Address with addr pin low.
-
static constexpr uint8_t ADDRESS_HIGH = 0x44
Address with addr pin high.
-
static constexpr uint8_t DEFAULT_ADDRESS = ADDRESS_LOW
Default I2C address.
-
struct Config
Configuration information for the Pi4ioe5v.
Public Members
-
uint8_t device_address = DEFAULT_ADDRESS
I2C address to use to talk to this PI4IOE5V.
-
uint8_t direction_mask = 0x00
Direction mask (0 = input, 1 = output).
-
uint8_t input_defaults = 0x00
Default input values for input interrupts. A change from this level will trigger an interrupt.
-
std::optional<uint8_t> initial_output = std::nullopt
Initial output value (only for pins set as outputs). If not set, outputs will be low or high-z depending on high_z_mask.
-
std::optional<uint8_t> high_z_mask = std::nullopt
Mask of pins to set as high impedance outputs. Overrides initial_output for these pins. All pins default to high-z on power-up.
-
std::optional<uint8_t> pull_up_mask = std::nullopt
Mask of pins to enable pull-up resistors on.
-
std::optional<uint8_t> pull_down_mask = std::nullopt
Mask of pins to enable pull-down resistors on.
-
BasePeripheral::write_fn write
Function to write to the device.
-
BasePeripheral::write_then_read_fn write_then_read
Function to write then read from the device.
-
bool auto_init = true
Automatically initialize the device.
-
uint8_t device_address = DEFAULT_ADDRESS
-
enum class PullResistor : uint8_t