| Crates.io | aw9523-embedded |
| lib.rs | aw9523-embedded |
| version | 0.1.0 |
| created_at | 2026-01-19 01:48:33.785781+00 |
| updated_at | 2026-01-19 01:48:33.785781+00 |
| description | A platform-agnostic embedded-hal driver for the AW9523 16-channel GPIO expander and LED driver |
| homepage | |
| repository | https://github.com/georgik/aw9523-rs |
| max_upload_size | |
| id | 2053530 |
| size | 89,239 |
A platform-agnostic embedded-hal driver for the AW9523 16-channel GPIO expander and LED driver.
no_std Compatible - Perfect for embedded systemsembedded-hal traits for maximum portabilityThe AW9523 is an I2C-controlled GPIO expander with:
Add this to your Cargo.toml:
[dependencies]
aw9523-embedded = "0.1"
embedded-hal = "1.0"
use aw9523_embedded::{Aw9523, PinMode, AW9523_PIN_0, AW9523_PIN_8, HIGH, LOW};
// Create device with I2C bus and default address
let mut gpio = Aw9523::new(i2c, 0x58);
// Initialize with default configuration
gpio.init().unwrap();
// Configure pin 0 as output and set it high
gpio.pin_mode(AW9523_PIN_0, PinMode::Output).unwrap();
gpio.digital_write(AW9523_PIN_0, HIGH).unwrap();
// Configure pin 8 as input and read its state
gpio.pin_mode(AW9523_PIN_8, PinMode::Input).unwrap();
let state = gpio.digital_read(AW9523_PIN_8).unwrap();
use aw9523_embedded::{Aw9523, PinMode, AW9523_PIN_0};
// Create and initialize device
let mut gpio = Aw9523::new(i2c, 0x58);
gpio.init().unwrap();
// Configure pin 0 for LED mode
gpio.pin_mode(AW9523_PIN_0, PinMode::LedMode).unwrap();
// Set LED brightness (0 = off, 255 = maximum)
gpio.analog_write(AW9523_PIN_0, 128).unwrap(); // 50% brightness
gpio.analog_write(AW9523_PIN_0, 255).unwrap(); // 100% brightness
use aw9523_embedded::{Aw9523, AW9523_PIN_0, AW9523_PIN_3, AW9523_PIN_5};
let mut gpio = Aw9523::new(i2c, 0x58);
gpio.init().unwrap();
// Set multiple pins high at once using bitmasks
gpio.output_gpio(AW9523_PIN_0 | AW9523_PIN_3 | AW9523_PIN_5).unwrap();
// Read all 16 pins at once
let inputs = gpio.input_gpio().unwrap();
if inputs & AW9523_PIN_5 != 0 {
// Pin 5 is high
}
// Configure multiple pins as outputs
gpio.configure_direction(AW9523_PIN_0 | AW9523_PIN_3).unwrap();
// Enable interrupts on multiple pins
gpio.interrupt_enable_gpio(AW9523_PIN_8 | AW9523_PIN_9).unwrap();
use aw9523_embedded::{Aw9523, PinMode, AW9523_PIN_10};
let mut gpio = Aw9523::new(i2c, 0x58);
gpio.init().unwrap();
// Configure pin as input
gpio.pin_mode(AW9523_PIN_10, PinMode::Input).unwrap();
// Enable interrupt for pin 10
gpio.enable_interrupt(AW9523_PIN_10, true).unwrap();
// Your code would monitor the hardware interrupt line
// and read the input state when triggered
The library provides full async support when the async feature is enabled. This allows non-blocking I2C operations using embedded-hal-async traits.
Add the async feature to your Cargo.toml:
[dependencies]
aw9523-embedded = { version = "0.1", features = ["async"] }
embedded-hal-async = "1.0"
use aw9523_embedded::{r#async::Aw9523Async, PinMode, AW9523_PIN_0, AW9523_PIN_8, HIGH};
async fn configure_gpio(i2c: impl embedded_hal_async::i2c::I2c) {
// Create async device
let mut gpio = Aw9523Async::new(i2c, 0x58);
// Initialize with default configuration
gpio.init().await.unwrap();
// Configure pin 0 as output and set it high
gpio.pin_mode(AW9523_PIN_0, PinMode::Output).await.unwrap();
gpio.digital_write(AW9523_PIN_0, HIGH).await.unwrap();
// Configure pin 8 as input and read its state
gpio.pin_mode(AW9523_PIN_8, PinMode::Input).await.unwrap();
let state = gpio.digital_read(AW9523_PIN_8).await.unwrap();
}
use aw9523_embedded::{r#async::Aw9523Async, PinMode, AW9523_PIN_0};
async fn control_leds(i2c: impl embedded_hal_async::i2c::I2c) {
let mut gpio = Aw9523Async::new(i2c, 0x58);
gpio.init().await.unwrap();
// Configure pin 0 for LED mode
gpio.pin_mode(AW9523_PIN_0, PinMode::LedMode).await.unwrap();
// Fade LED from off to full brightness
for brightness in 0..=255 {
gpio.analog_write(AW9523_PIN_0, brightness).await.unwrap();
// Add your async delay here
}
}
use aw9523_embedded::{r#async::Aw9523Async, AW9523_PIN_0, AW9523_PIN_3, AW9523_PIN_5};
async fn bulk_control(i2c: impl embedded_hal_async::i2c::I2c) {
let mut gpio = Aw9523Async::new(i2c, 0x58);
gpio.init().await.unwrap();
// Set multiple pins high at once
gpio.output_gpio(AW9523_PIN_0 | AW9523_PIN_3 | AW9523_PIN_5).await.unwrap();
// Read all 16 pins at once
let inputs = gpio.input_gpio().await.unwrap();
if inputs & AW9523_PIN_5 != 0 {
// Pin 5 is high
}
}
The async implementation works seamlessly with Embassy and other async runtimes:
use embassy_executor::Spawner;
use aw9523_embedded::{r#async::Aw9523Async, AW9523_PIN_0, HIGH, LOW};
#[embassy_executor::task]
async fn gpio_task(i2c: impl embedded_hal_async::i2c::I2c) {
let mut gpio = Aw9523Async::new(i2c, 0x58);
gpio.init().await.unwrap();
loop {
// Toggle LED
gpio.digital_write(AW9523_PIN_0, HIGH).await.unwrap();
embassy_time::Timer::after_millis(500).await;
gpio.digital_write(AW9523_PIN_0, LOW).await.unwrap();
embassy_time::Timer::after_millis(500).await;
}
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
// Initialize your I2C peripheral
let i2c = /* your async I2C setup */;
spawner.spawn(gpio_task(i2c)).unwrap();
}
| Feature | Blocking API | Async API |
|---|---|---|
| Module | Root module | aw9523_embedded::r#async |
| Struct | Aw9523 |
Aw9523Async |
| Trait | embedded_hal::i2c::I2c |
embedded_hal_async::i2c::I2c |
| Method calls | gpio.init().unwrap() |
gpio.init().await.unwrap() |
| Runtime | Blocking execution | Async/await compatible |
All methods available in the blocking API have async equivalents with identical names and signatures (except for the async keyword and .await).
init() - Initialize device with default configurationreset() - Software resetpin_mode(pin, mode) - Configure single pin (INPUT, OUTPUT, or AW9523_LED_MODE)digital_write(pin, state) - Set output pin high/lowdigital_read(pin) - Read input pin stateoutput_gpio(pins) - Set all 16 pins at once (bit mask)input_gpio() - Read all 16 pins at onceanalog_write(pin, brightness) - Set LED brightness (0-255)configure_led_mode(pins) - Enable LED mode on multiple pinsenable_interrupt(pin, enabled) - Enable/disable interrupt for a pininterrupt_enable_gpio(pins) - Configure interrupts for multiple pinsconfigure_direction(pins) - Set pin directions for all 16 pinsget_chip_id() - Read chip ID register (should return 0x23)open_drain_port0(enabled) - Configure Port 0 as open-drain or push-pullThe crate provides constants for easy pin referencing:
use aw9523_embedded::{AW9523_PIN_0, AW9523_P0_0, AW9523_PORT0_ALL};
// Individual pins: AW9523_PIN_0 through AW9523_PIN_15
// Port notation: AW9523_P0_0 through AW9523_P1_7
// Port groups: AW9523_PORT0_ALL, AW9523_PORT1_ALL
// All pins: AW9523_ALL_PINS
All constants are re-exported in the async module for convenience.
The library includes comprehensive test coverage for both blocking and async implementations:
# Run blocking tests
cargo test
# Run async tests
cargo test --features async
# Run all tests with all features
cargo test --all-features