| Crates.io | ap33772s-driver |
| lib.rs | ap33772s-driver |
| version | 0.1.4 |
| created_at | 2025-09-13 04:54:34.483117+00 |
| updated_at | 2025-10-19 01:02:08.270641+00 |
| description | A platform-agnostic driver for the AP33772S USB-PD Sink Controller |
| homepage | |
| repository | https://github.com/hnz1102/ap33772s-driver.git |
| max_upload_size | |
| id | 1837214 |
| size | 48,879 |
A platform-agnostic Rust driver for the AP33772S USB Power Delivery (USB-PD) Sink Controller.
embedded-hal traits for maximum compatibilityalloc feature)The AP33772S supports negotiation for the following standard voltages:
Note: Previous versions incorrectly indicated support for 36V and 48V. The AP33772S hardware actually supports a maximum of 28V.
The driver supports both Standard Power Range (SPR) and Extended Power Range (EPR) modes. Custom voltages and currents are also supported through programmable PDOs up to the 28V maximum.
Add this to your Cargo.toml:
[dependencies]
ap33772s-driver = "0.1.4"
For std environments, enable the std feature:
[dependencies]
ap33772s-driver = { version = "0.1.4", features = ["std"] }
use ap33772s_driver::{AP33772S, PDVoltage};
// Create driver instance
let mut pd_controller = AP33772S::new();
// Initialize the controller (requires I2C implementation)
pd_controller.init(&mut i2c)?;
// Request 12V from the USB-PD source
pd_controller.request_voltage(&mut i2c, PDVoltage::V12)?;
// Read current status
let status = pd_controller.get_status(&mut i2c)?;
println!("Voltage: {}mV, Current: {}mA", status.voltage_mv, status.current_ma);
// Request custom voltage/current (if supported by source)
pd_controller.request_custom_voltage(&mut i2c, 15000, 2000)?; // 15V, 2A
// Get available power capabilities
for pdo in pd_controller.get_pdo_list() {
println!("PDO {}: {}mV, {}mA, {}mW",
pdo.pdo_index, pdo.voltage_mv, pdo.current_ma, pdo.max_power_mw);
}
This driver uses the embedded-hal I2C traits, making it compatible with any platform that provides an I2C implementation. Here are examples for popular platforms:
use esp_idf_hal::i2c::*;
use ap33772s_driver::AP33772S;
// Set up I2C
let i2c_config = I2cConfig::new().baudrate(100.kHz().into());
let mut i2c = I2cDriver::new(peripherals.i2c0, sda_pin, scl_pin, &i2c_config)?;
// Use the driver
let mut pd_controller = AP33772S::new();
pd_controller.init(&mut i2c)?;
use stm32f4xx_hal::i2c::I2c;
use ap33772s_driver::AP33772S;
let mut i2c = I2c::new(/* I2C peripheral setup */);
let mut pd_controller = AP33772S::new();
pd_controller.init(&mut i2c)?;
use rppal::i2c::I2c;
use ap33772s_driver::AP33772S;
let mut i2c = I2c::new()?;
let mut pd_controller = AP33772S::new();
pd_controller.init(&mut i2c)?;
The driver uses a comprehensive error type that wraps the underlying I2C errors:
match pd_controller.request_voltage(&mut i2c, PDVoltage::V12) {
Ok(()) => println!("Voltage request successful"),
Err(ap33772s_driver::Error::Timeout) => println!("PD negotiation timed out"),
Err(ap33772s_driver::Error::NegotiationFailed) => println!("PD negotiation failed"),
Err(ap33772s_driver::Error::ProtectionFault) => println!("Protection fault occurred"),
Err(e) => println!("Other error: {:?}", e),
}
The driver provides access to all AP33772S registers through constants:
REG_STATUS, REG_CONFIG, REG_SYSTEMREG_VOLTAGE, REG_CURRENT, REG_TEMPREG_VREQ, REG_IREQ, REG_PD_REQMSGREG_SRCPDO, REG_SRC_SPR_PDO1..REG_SRC_EPR_PDO13Configure the built-in protection features:
// Enable all protections
pd_controller.configure_protections(
&mut i2c,
true, // Under-voltage protection
true, // Over-voltage protection
true, // Over-current protection
true, // Over-temperature protection
true // De-rating function
)?;
The driver automatically enumerates all available PDOs from the connected source:
for pdo in pd_controller.get_pdo_list() {
println!("PDO {}: {}V @ {}A ({}W) - {}",
pdo.pdo_index,
pdo.voltage_mv as f32 / 1000.0,
pdo.current_ma as f32 / 1000.0,
pdo.max_power_mw as f32 / 1000.0,
if pdo.is_fixed { "Fixed" } else { "Programmable" }
);
}
Control the output voltage manually:
// Auto control (default)
pd_controller.set_vout_auto_control(&mut i2c)?;
// Force output off
pd_controller.force_vout_off(&mut i2c)?;
// Force output on
pd_controller.force_vout_on(&mut i2c)?;
Perform a USB-PD hard reset:
pd_controller.hard_reset(&mut i2c)?;
V36, V40, and V48 variants from the PDVoltage enumIf your code was using unsupported voltage options:
// Before (will no longer compile)
pd_controller.request_voltage(&mut i2c, &mut delay, PDVoltage::V36)?;
pd_controller.request_voltage(&mut i2c, &mut delay, PDVoltage::V48)?;
// After (use maximum supported voltage or custom voltage)
pd_controller.request_voltage(&mut i2c, &mut delay, PDVoltage::V28)?;
// Or use custom voltage up to 28V
pd_controller.request_custom_voltage(&mut i2c, &mut delay, 28000, 3000)?;
This update ensures the driver accurately represents the actual hardware capabilities of the AP33772S controller and prevents attempts to negotiate unsupported voltages.
request_custom_voltage method to prioritize Variable Power Data Objects (APDOs) over Fixed PDOs when availableis_fixed flag// The driver will now automatically select the best PDO type
// If a Variable PDO can provide 15V, it will be chosen over a 20V Fixed PDO
pd_controller.request_custom_voltage(&mut i2c, &mut delay, 15000, 2000)?; // 15V, 2A
This update significantly improves power efficiency and voltage accuracy when working with modern USB-PD sources that support Variable PDOs.
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.