Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
0650097
wip: epr mode
elagil Sep 5, 2025
6e3eedb
feat: message for EPR data object
elagil Sep 16, 2025
04eab38
fix: example builds
elagil Sep 16, 2025
703838c
chore: bump version
elagil Sep 16, 2025
95f295c
chore: update deps
elagil Sep 16, 2025
82afcf7
fix: heapless feature
elagil Sep 16, 2025
a1e1dc8
fix: example buids
elagil Sep 16, 2025
f2ed239
fix: example build and deps for latest embassy
elagil Sep 16, 2025
a63287c
chore: wip, restructure
elagil Sep 21, 2025
a8543ef
chore: update embassy
elagil Sep 21, 2025
06e137b
style: formatting
elagil Sep 21, 2025
eac1e5c
test: fix test build
elagil Sep 21, 2025
b1d2aab
refactor: moving files and modules
elagil Sep 23, 2025
ac2b4d5
chore: update embassy
elagil Sep 23, 2025
87328b2
feat: add extended message infrastructure and chunking support
okhsunrog Dec 8, 2025
a7ecada
feat: add EPR message types and parsing
okhsunrog Dec 8, 2025
91cda13
feat: implement EPR mode in sink policy engine
okhsunrog Dec 8, 2025
75e08ef
feat: complete EPR implementation with full integration test
okhsunrog Dec 8, 2025
d84d3f7
fix: correct hard reset logic per USB PD spec R3.2
okhsunrog Dec 8, 2025
277e3bb
feat: implement sink capabilities and EPR mode protocol compliance
okhsunrog Dec 8, 2025
afa6021
fix: correct protocol error handling order per USB PD spec
okhsunrog Dec 8, 2025
96fdac7
fix: add serde derives to SinkCapabilities
okhsunrog Dec 8, 2025
14729b7
fix: policy engine spec compliance fixes
okhsunrog Dec 8, 2025
51ad3d9
fix: handle EPR_Source_Capabilities in WaitForCapabilities and EPR exit
okhsunrog Dec 8, 2025
2df04e9
feat: implement SinkRequestTimer per USB PD spec 6.6.4.1
okhsunrog Dec 8, 2025
738eff8
fix: correct extended message formatting per USB PD spec
okhsunrog Dec 8, 2025
439fdc4
fix: set EPR Sink Operational PDP in EPR_Mode(Enter) message
okhsunrog Dec 8, 2025
ed15352
feat: use chunked mode for extended messages
okhsunrog Dec 8, 2025
8c3b06c
feat: add EPR example for STM32G431
okhsunrog Dec 8, 2025
03fe8db
fix: sort imports for CI
okhsunrog Dec 8, 2025
45dcc21
fix: policy engine spec compliance fixes
okhsunrog Dec 9, 2025
fd15c75
fix: correct hard reset counter to allow 3 attempts per spec
okhsunrog Dec 9, 2025
cb3a3cf
fix: use correct 25mV units for AVS voltage (not 20mV like PPS)
okhsunrog Dec 10, 2025
b5dd12e
ci: add embassy-stm32-g431cb-epr example to build
okhsunrog Dec 10, 2025
4480e80
fix: improve EPR PDO detection and add EPR entry failure callback
okhsunrog Dec 11, 2025
107110c
Address code review feedback for EPR support
okhsunrog Jan 21, 2026
a8860a8
Remove unnecessary unchunked_extended_messages_supported setter
okhsunrog Jan 21, 2026
a6506e2
Apply additional code review suggestions
okhsunrog Jan 21, 2026
caee754
Improve ChunkedMessageAssembler API safety and ergonomics
okhsunrog Jan 21, 2026
0dcce2d
Add validation for oversized chunks in assembler
okhsunrog Jan 21, 2026
a503803
Use extend_from_slice() for chunk data copying
okhsunrog Jan 21, 2026
93bbb12
Implement Iterator trait for ChunkedMessageSender
okhsunrog Jan 21, 2026
3bf67d0
Remove redundant next_chunk() method
okhsunrog Jan 21, 2026
bf1506d
Apply rustfmt formatting fixes
okhsunrog Jan 21, 2026
0585c38
Fix clippy warnings and formatting
okhsunrog Jan 21, 2026
8e6b56c
Remove unnecessary u32 casts in power.rs
okhsunrog Jan 21, 2026
5e6987f
Fix VDMModeEntry/Exit timer values per USB PD R3.2 spec
okhsunrog Jan 21, 2026
1ee51fa
Address PR review feedback: code cleanup and improvements
okhsunrog Feb 5, 2026
172d75b
Remove debug eprintln! calls from DummySinkEprDevice
okhsunrog Feb 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/ci/build.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
#!/bin/bash
set -euo pipefail

for dir in usbpd usbpd-traits examples/embassy-nucleo-h563zi examples/embassy-stm32-g431cb;
export RUSTFLAGS="-D warnings"

for dir in usbpd usbpd-traits examples/embassy-nucleo-h563zi examples/embassy-stm32-g431cb examples/embassy-stm32-g431cb-epr;
do
pushd $dir
cargo +nightly fmt --check
cargo clippy -- -D warnings
cargo clippy
cargo build --release
popd
done

for dir in usbpd usbpd-traits
do
pushd $dir
cargo clippy --features defmt -- -D warnings
cargo clippy --features defmt
popd
done

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
usbpd
examples/embassy-nucleo-h563zi
examples/embassy-stm32-g431cb
examples/embassy-stm32-g431cb-epr

- name: Build
run: bash .github/ci/build.sh
Expand Down
2 changes: 1 addition & 1 deletion embassy
Submodule embassy updated 582 files
1 change: 0 additions & 1 deletion examples/embassy-nucleo-h563zi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ embassy-time = { path = "../../embassy/embassy-time", features = [
"defmt-timestamp-uptime",
"tick-hz-32_768",
] }

embassy-futures = { path = "../../embassy/embassy-futures" }

defmt = "1.0.1"
Expand Down
2 changes: 1 addition & 1 deletion examples/embassy-nucleo-h563zi/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ async fn main(spawner: Spawner) {
led_yellow,
led_red,
};
unwrap!(spawner.spawn(power::ucpd_task(ucpd_resources)));
spawner.spawn(unwrap!(power::ucpd_task(ucpd_resources)));
}
}
25 changes: 20 additions & 5 deletions examples/embassy-nucleo-h563zi/src/power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, PdPhy, Ucpd};
use embassy_stm32::{Peri, bind_interrupts, peripherals};
use embassy_time::{Duration, Ticker, Timer, with_timeout};
use uom::si::electric_potential;
use usbpd::protocol_layer::message::pdo::SourceCapabilities;
use usbpd::protocol_layer::message::request::{self, CurrentRequest, VoltageRequest};
use usbpd::protocol_layer::message::units::ElectricPotential;
use usbpd::protocol_layer::message::data::request::{self, CurrentRequest, VoltageRequest};
use usbpd::protocol_layer::message::data::source_capabilities::SourceCapabilities;
use usbpd::sink::device_policy_manager::{DevicePolicyManager, Event};
use usbpd::sink::policy_engine::Sink;
use usbpd::timers::Timer as SinkTimer;
use usbpd::units::ElectricPotential;
use usbpd_traits::Driver as SinkDriver;
use {defmt_rtt as _, panic_probe as _};

Expand Down Expand Up @@ -128,21 +128,31 @@ enum TestCapabilities {
Safe5V,
Pps3V6,
Pps4V2,
RequestEprSourceCapabilities,
}

struct Device<'d> {
ticker: Ticker,
test_capabilities: TestCapabilities,
led: &'d mut Output<'static>,
source_capabilities: Option<SourceCapabilities>,
}

impl DevicePolicyManager for Device<'_> {
async fn inform(&mut self, source_capabilities: &SourceCapabilities) {
info!("New caps received {}", source_capabilities);

self.source_capabilities = Some(source_capabilities.clone());
}

async fn get_event(&mut self, source_capabilities: &SourceCapabilities) -> Event {
// Periodically request another power level.
self.ticker.next().await;
self.led.toggle();
self.source_capabilities = Some(source_capabilities.clone());

info!("Test capabilities: {}", self.test_capabilities);

let (power_source, new_test_capabilties) = match self.test_capabilities {
TestCapabilities::Safe5V => (
request::PowerSource::new_fixed(CurrentRequest::Highest, VoltageRequest::Safe5V, source_capabilities),
Expand All @@ -162,8 +172,12 @@ impl DevicePolicyManager for Device<'_> {
ElectricPotential::new::<electric_potential::millivolt>(4200),
source_capabilities,
),
TestCapabilities::Safe5V,
TestCapabilities::RequestEprSourceCapabilities,
),
TestCapabilities::RequestEprSourceCapabilities => {
self.test_capabilities = TestCapabilities::Safe5V;
return Event::RequestEprSourceCapabilities;
}
};

let event = if let Ok(power_source) = power_source {
Expand Down Expand Up @@ -220,7 +234,8 @@ pub async fn ucpd_task(mut ucpd_resources: UcpdResources) {

let driver = UcpdSinkDriver::new(pd_phy);
let device = Device {
ticker: Ticker::every(Duration::from_secs(8)),
source_capabilities: None,
ticker: Ticker::every(Duration::from_secs(3)),
test_capabilities: TestCapabilities::Safe5V,
led: &mut ucpd_resources.led_red,
};
Expand Down
8 changes: 8 additions & 0 deletions examples/embassy-stm32-g431cb-epr/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = 'probe-rs run --chip STM32G431CBTx --connect-under-reset'

[build]
target = "thumbv7em-none-eabihf"

[env]
DEFMT_LOG = "info"
67 changes: 67 additions & 0 deletions examples/embassy-stm32-g431cb-epr/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[package]
edition = "2024"
name = "usbpd-epr-example"
version = "0.1.0"
license = "MIT"

[dependencies]
embassy-stm32 = { path = "../../embassy/embassy-stm32", features = [
"defmt",
"time-driver-any",
"memory-x",
"unstable-pac",
"exti",
] }
embassy-sync = { path = "../../embassy/embassy-sync", features = ["defmt"] }
embassy-executor = { path = "../../embassy/embassy-executor", features = [
"arch-cortex-m",
"executor-thread",
"defmt",
] }
embassy-time = { path = "../../embassy/embassy-time", features = [
"defmt",
"defmt-timestamp-uptime",
"tick-hz-100_000",
] }
embassy-futures = { path = "../../embassy/embassy-futures" }

defmt = "1.0.1"
defmt-rtt = "1.0.0"

cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
embedded-hal = "1"
panic-probe = { version = "1.0.0", features = ["print-defmt"] }
heapless = { version = "0.9.1", default-features = false }
static_cell = "2.1.1"
micromath = "2.1.0"

uom = { version = "0.36.0", default-features = false, features = ["si"] }
usbpd = { path = "../../usbpd", features = ["defmt"] }
usbpd-traits = { path = "../../usbpd-traits", features = ["defmt"] }

# cargo build/run
[profile.dev]
codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
opt-level = 3 # <-
overflow-checks = true # <-

# cargo build/run --release
[profile.release]
codegen-units = 1
debug = 2
debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = 3 # <-
overflow-checks = false # <-

[features]
default = ["stm32g431cb"]

stm32g431cb = ["embassy-stm32/stm32g431cb"]
# Enable AVS (Adjustable Voltage Supply) instead of Fixed EPR mode
avs = []
19 changes: 19 additions & 0 deletions examples/embassy-stm32-g431cb-epr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Embassy EPR Example

Demonstrates USB PD Extended Power Range (EPR) negotiation using the [embassy](https://embassy.dev/) framework.
It targets an STM32G431 microcontroller and makes use of its UCPD peripheral.

## Features

This example demonstrates:
- Initial SPR power negotiation
- Automatic EPR mode entry when source is EPR capable
- Requesting 28V @ 4A (112W) EPR power
- Printing source capabilities with PDO details

## Configuration

The target power can be configured via constants in `power.rs`:
- `TARGET_EPR_VOLTAGE_RAW`: Target voltage (default: 28V)
- `TARGET_EPR_CURRENT_RAW`: Target current (default: 4A)
- `OPERATIONAL_PDP_WATTS`: Operational PDP for EPR mode entry (default: 112W)
5 changes: 5 additions & 0 deletions examples/embassy-stm32-g431cb-epr/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main() {
println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tlink.x");
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
}
2 changes: 2 additions & 0 deletions examples/embassy-stm32-g431cb-epr/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#![no_std]
pub mod power;
27 changes: 27 additions & 0 deletions examples/embassy-stm32-g431cb-epr/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![no_std]
#![no_main]

use defmt::info;
use embassy_executor::Spawner;
use usbpd_epr_example::power::{self, UcpdResources};
use {defmt_rtt as _, panic_probe as _};

#[embassy_executor::main]
async fn main(spawner: Spawner) {
let mut stm32_config = embassy_stm32::Config::default();
// HSI must be enabled for UCPD
stm32_config.rcc.hsi = true;

let p = embassy_stm32::init(stm32_config);

info!("USB PD EPR Example");

let ucpd_resources = UcpdResources {
pin_cc1: p.PB6,
pin_cc2: p.PB4,
ucpd: p.UCPD1,
rx_dma: p.DMA1_CH1,
tx_dma: p.DMA1_CH2,
};
spawner.spawn(power::ucpd_task(ucpd_resources).unwrap());
}
Loading