AW9523 I/O Expander
The AW9523 I/O expander component allows the user to configure inputs, outputs, interrupts, etc. via a serial interface such as I2C. It also supports dimming control for LEDs attached to the expander’s port pins, when those pins are configured into a special LED mode.
API Reference
Header File
Classes
-
class Aw9523 : public espp::BasePeripheral<>
Class for communicating with and controlling a AW9523 GPIO expander including interrupt configuration and LED drive capability. Datasheet hosted by adafruit.com here: https://cdn-shop.adafruit.com/product-files/4886/AW9523+English+Datasheet.pdf
AW9523 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, }); // now make the aw9523 which handles GPIO espp::Aw9523 aw9523( {// since this uses LEDs, both of the address pins are pulled up in // hardware to have the LEDs default to off .device_address = espp::Aw9523::DEFAULT_ADDRESS | 0b11, // set P0_0 - P0_5 to be inputs .port_0_direction_mask = 0b00111111, // set P1_0 - P1_1 to be inputs .port_1_direction_mask = 0b00000011, .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), .write_then_read = std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), .log_level = espp::Logger::Verbosity::WARN}); std::error_code ec; aw9523.initialize(ec); // Initialized separately from the constructor. if (ec) { fmt::print("aw9523 initialization failed: {}\n", ec.message()); return; } // set P1_5, P1_6, and P1_7 to be leds int r_led = (1 << 13); int g_led = (1 << 14); int b_led = (1 << 15); // for the port led mask, 0 = LED, 1 = GPIO so we invert the pins above uint16_t leds = ~(r_led | g_led | b_led); aw9523.configure_led(leds, ec); if (ec) { fmt::print("aw9523 led configuration failed: {}\n", ec.message()); return; } // and finally, make the task to periodically poll the aw9523 and print // the state. NOTE: the Aw9523 does not internally manage its own state // update, so whatever rate we use here is the rate at which the state will // update. auto task_fn = [&](std::mutex &m, std::condition_variable &cv) { static auto start = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now(); auto seconds = std::chrono::duration<float>(now - start).count(); static uint8_t r_brightness = 0; static uint8_t g_brightness = 0; static uint8_t b_brightness = 0; // returns the pins as P0_0 lsb, P1_7 msb auto pins = aw9523.get_pins(ec); if (ec) { fmt::print("aw9523 get pins failed: {}\n", ec.message()); return true; // stop the task } // equivalent to: // auto pins = (aw9523.get_pins(espp::Aw9523::Port::PORT1, ec) << 8) | // aw9523.get_pins(espp::Aw9523::Port::PORT0, ec); int r_up = (pins & (1 << 0)); // P0_0 int g_up = (pins & (1 << 1)); // P0_1 int b_up = (pins & (1 << 9)); // P1_0 int r_down = (pins & (1 << 2)); // P0_2 int g_down = (pins & (1 << 3)); // P0_3 int b_down = (pins & (1 << 8)); // P1_8 // use the buttons to modify the brightness values (with wrap) static uint8_t increment = 1; if (r_up) { r_brightness += increment; } else if (r_down) { r_brightness -= increment; } if (g_up) { g_brightness += increment; } else if (g_down) { g_brightness -= increment; } if (b_up) { b_brightness += increment; } else if (b_down) { b_brightness -= increment; } aw9523.led(r_led, r_brightness, ec); aw9523.led(g_led, g_brightness, ec); aw9523.led(b_led, b_brightness, ec); if (ec) { fmt::print("aw9523 led failed: {}\n", ec.message()); return true; // stop the task } fmt::print("{:.3f}, {:#x}, {}, {}, {}\n", seconds, pins, r_brightness, g_brightness, b_brightness); // 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, 50ms); } // don't want to stop the task return false; }; auto task = espp::Task({.callback = task_fn, .task_config = { .name = "Aw9523 Task", .stack_size_bytes = 5 * 1024, }, .log_level = espp::Logger::Verbosity::WARN}); fmt::print("%time(s), pin values, r, g, b\n"); task.start();
Public Types
-
enum class Port
The two GPIO ports the Aw9523 has.
Values:
-
enumerator PORT0
Port 0.
-
enumerator PORT1
Port 1.
-
enumerator PORT0
-
enum class OutputDriveModeP0 : int
The output drive mode configuration for PORT 0 pins.
Values:
-
enumerator OPEN_DRAIN
In this mode it needs a pull-up reistor. This is the default mode.
-
enumerator PUSH_PULL
In this mode it needs no pull-up resistor.
-
enumerator OPEN_DRAIN
-
enum class MaxLedCurrent : int
The max current allowed when driving LEDs.
Values:
-
enumerator IMAX
Full drive current (37mA), default.
-
enumerator IMAX_75
75% drive current
-
enumerator IMAX_50
50% drive current
-
enumerator IMAX_25
25% drive current
-
enumerator IMAX
-
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 Aw9523(const Config &config)
Construct the Aw9523. Will call initialize() if auto_init is true.
- Parameters
config – Config structure for configuring the AW9523
-
inline void initialize(std::error_code &ec)
Initialize the component class.
- Parameters
ec – Error code to set if an error occurs.
-
inline uint8_t get_pins(Port port, std::error_code &ec)
Read the pin values on the provided port.
- Parameters
port – The Port for which to read the pins
ec – Error code to set if an error occurs.
- Returns
The pin values as an 8 bit mask.
-
inline uint16_t get_pins(std::error_code &ec)
Read the pin values on both Port 0 and Port 1.
- Parameters
ec – Error code to set if an error occurs.
- Returns
The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).
-
inline void output(Port port, uint8_t value, std::error_code &ec)
Write the pin values on the provided port.
Note
This will overwrite any previous pin values on the port for all output pins on the port.
- Parameters
port – The Port for which to write the pins
value – The pin values to apply.
ec – Error code to set if an error occurs.
-
inline void output(uint8_t p0, uint8_t p1, std::error_code &ec)
Write the pin values on both Port 0 and Port 1.
Note
This will overwrite any previous pin values on the port for all output pins on the ports.
- Parameters
p0 – The pin values to apply to Port 0.
p1 – The pin values to apply to Port 1.
ec – Error code to set if an error occurs.
-
inline void output(uint16_t value, std::error_code &ec)
Write the pin values on both Port 0 and Port 1.
Note
This will overwrite any previous pin values on the port for all output pins on the ports.
- Parameters
value – The pin values to apply as a 16 bit value (P0_0 lsb, P1_7 msb).
ec – Error code to set if an error occurs.
-
inline void clear_pins(Port port, uint8_t mask, std::error_code &ec)
Clear the pin values on the provided port according to the provided mask.
Reads the current pin values and clears any bits set in the mask.
- Parameters
port – The Port for which to clear the pin outputs.
mask – The pin values as an 8 bit mask to clear.
ec – Error code to set if an error occurs.
-
inline void clear_pins(uint8_t p0, uint8_t p1, std::error_code &ec)
Clear the pin values for Port 0 and Port 1 according to the provided masks.
Reads the current pin values and clears any bits set in the masks.
- Parameters
p0 – The pin values as an 8 bit mask for Port 0 to clear.
p1 – The pin values as an 8 bit mask for Port 1 to clear.
ec – Error code to set if an error occurs.
-
inline void clear_pins(uint16_t mask, std::error_code &ec)
Clear the pin values for Port 0 and Port 1 according to the provided mask.
Reads the current pin values and clears any bits set in the mask.
- Parameters
mask – The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb) to clear.
ec – Error code to set if an error occurs.
-
inline void set_pins(Port port, uint8_t mask, std::error_code &ec)
Set the pin values on the provided port according to the provided mask.
Reads the current pin values and sets any bits set in the mask.
- Parameters
port – The Port for which to set the pin outputs.
mask – The pin values as an 8 bit mask to set.
ec – Error code to set if an error occurs.
-
inline void set_pins(uint8_t p0, uint8_t p1, std::error_code &ec)
Set the pin values for Port 0 and Port 1 according to the provided masks.
Reads the current pin values and sets any bits set in the masks.
- Parameters
p0 – The pin values for Port 0 as an 8 bit mask to set.
p1 – The pin values for Port 1 as an 8 bit mask to set.
ec – Error code to set if an error occurs.
-
inline void set_pins(uint16_t mask, std::error_code &ec)
Set the pin values for Port 0 and Port 1 according to the provided mask.
Reads the current pin values and sets any bits set in the mask.
- Parameters
mask – The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb) to set.
ec – Error code to set if an error occurs.
-
inline uint8_t get_output(Port port, std::error_code &ec)
Read the output pin values on the provided port.
- Parameters
port – The Port for which to read the pins
ec – Error code to set if an error occurs.
- Returns
The pin values as an 8 bit mask.
-
inline uint16_t get_output(std::error_code &ec)
Read the output pin values on both Port 0 and Port 1.
- Parameters
ec – Error code to set if an error occurs.
- Returns
The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).
-
inline void set_interrupt(Port port, uint8_t mask, std::error_code &ec)
Configure the provided pins to interrupt on change.
- Parameters
port – The port associated with the provided pin mask.
mask – The pin mask to configure for interrupt (0=interrupt).
ec – Error code to set if an error occurs.
-
inline void set_interrupt(uint8_t p0, uint8_t p1, std::error_code &ec)
Configure the provided pins to interrupt on change.
- Parameters
p0 – The pin mask for Port 0 to configure for interrupt (0=interrupt).
p1 – The pin mask for Port 1 to configure for interrupt (0=interrupt).
ec – Error code to set if an error occurs.
-
inline void set_direction(Port port, uint8_t mask, std::error_code &ec)
Set the i/o direction for the pins according to mask.
- Parameters
port – The port associated with the provided pin mask.
mask – The mask indicating direction (1 = input, 0 = output)
ec – Error code to set if an error occurs.
-
inline void set_direction(uint8_t p0, uint8_t p1, std::error_code &ec)
Set the i/o direction for the pins on Port 0 and Port 1.
- Parameters
p0 – The mask for Port 0 indicating direction (1 = input, 0 = output)
p1 – The mask for Port 1 indicating direction (1 = input, 0 = output)
ec – Error code to set if an error occurs.
-
inline void configure_led(Port port, uint8_t mask, std::error_code &ec)
Enable/disable the LED function on the associated port pins.
- Parameters
port – The port associated with the provided pin mask.
mask – The mask indicating LED function (1 = GPIO, 0 = LED)
ec – Error code to set if an error occurs.
-
inline void configure_led(uint8_t p0, uint8_t p1, std::error_code &ec)
Enable/disable the LED function on the associated port pins.
- Parameters
p0 – The mask for Port 0 indicating LED function (1 = GPIO, 0 = LED)
p1 – The mask for Port 1 indicating LED function (1 = GPIO, 0 = LED)
ec – Error code to set if an error occurs.
-
inline void configure_led(uint16_t mask, std::error_code &ec)
Enable/disable the LED function on the associated port pins.
- Parameters
mask – The bit mask for Port 0 and Port 1 [(Port 1 << 8) | (Port 0)] indicating LED function (1 = GPIO, 0 = LED)
ec – Error code to set if an error occurs.
-
inline void led(uint16_t pin, uint8_t brightness, std::error_code &ec)
Set the pin’s LED to new brightness value.
- Parameters
pin – The pin bit corresponding to the pin (P0_0 lsb, P1_7 msb).
brightness – The brightness value [0,255] to set the LED to.
ec – Error code to set if an error occurs.
-
inline void configure_global_control(OutputDriveModeP0 output_drive_mode_p0, MaxLedCurrent max_led_current, std::error_code &ec)
Configure the global control register.
- Parameters
output_drive_mode_p0 – Output drive mode for Port 0.
max_led_current – Maximum LED current for each LED pin.
ec – Error code to set if an error occurs.
- inline bool probe (std::error_code &ec) requires(UseAddress)
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) requires(UseAddress)
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) requires(UseAddress)
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 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 DEFAULT_ADDRESS = 0x58
Lower 2 bits are AD1, AD0 pins on the chip.
-
struct Config
Configuration information for the Aw9523.
Public Members
-
uint8_t device_address = DEFAULT_ADDRESS
I2C address to use to talk to this AW9523B.
-
uint8_t port_0_direction_mask = 0x00
Direction mask (1 = input) for port 0.
-
uint8_t port_1_direction_mask = 0x00
Direction mask (1 = input) for port 1.
-
OutputDriveModeP0 output_drive_mode_p0 = OutputDriveModeP0::OPEN_DRAIN
Output drive mode for Port 0.
-
MaxLedCurrent max_led_current = MaxLedCurrent::IMAX
Max current allowed on each LED.
-
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 Port