Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STM32h5 UCPD example #3678

Merged
merged 4 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
42 changes: 42 additions & 0 deletions embassy-stm32/src/ucpd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,23 @@ impl<'d, T: Instance> Ucpd<'d, T> {
w.set_ucpden(true);
});

#[cfg(stm32h5)]
r.cfgr2().write(|w| {
w.set_rxafilten(true);
});

// Software trim according to RM0481, p. 2650/2668
#[cfg(stm32h5)]
{
let trim_rd_cc1 = unsafe { *(0x4002_242C as *const u32) & 0xF };
let trim_rd_cc2 = unsafe { ((*(0x4002_242C as *const u32)) >> 8) & 0xF };

r.cfgr3().write(|w| {
w.set_trim_cc1_rd(trim_rd_cc1 as u8);
w.set_trim_cc2_rd(trim_rd_cc2 as u8);
});
}

Self {
cc_phy: CcPhy { _lifetime: PhantomData },
}
Expand Down Expand Up @@ -278,6 +295,31 @@ impl<'d, T: Instance> CcPhy<'d, T> {
});
});

// Software trim according to RM0481, p. 2650/2668
#[cfg(stm32h5)]
T::REGS.cfgr3().modify(|w| match cc_pull {
CcPull::Source1_5A => {
#[cfg(stm32h5)]
{
let trim_1a5_cc1 = unsafe { *(0x08FF_F844 as *const u32) & 0xF };
let trim_1a5_cc2 = unsafe { ((*(0x08FF_F844 as *const u32)) >> 16) & 0xF };

w.set_trim_cc1_rp(trim_1a5_cc1 as u8);
w.set_trim_cc2_rp(trim_1a5_cc2 as u8);
};
}
_ => {
#[cfg(stm32h5)]
{
let trim_3a0_cc1 = unsafe { (*(0x4002_242C as *const u32) >> 4) & 0xF };
let trim_3a0_cc2 = unsafe { ((*(0x4002_242C as *const u32)) >> 12) & 0xF };

w.set_trim_cc1_rp(trim_3a0_cc1 as u8);
w.set_trim_cc2_rp(trim_3a0_cc2 as u8);
};
}
});

// Disable dead-battery pull-down resistors which are enabled by default on boot.
critical_section::with(|cs| {
init(
Expand Down
92 changes: 92 additions & 0 deletions examples/stm32h5/src/bin/usb_c_pd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//! This example targets the NUCLEO-H563ZI platform.
//! USB-C CC lines are protected by a TCPP01-M12 chipset.
#![no_std]
#![no_main]

use defmt::{error, info, Format};
use embassy_executor::Spawner;
use embassy_stm32::gpio::Output;
use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd};
use embassy_stm32::{bind_interrupts, peripherals, Config};
use embassy_time::{with_timeout, Duration};
use {defmt_rtt as _, panic_probe as _};

bind_interrupts!(struct Irqs {
UCPD1 => ucpd::InterruptHandler<peripherals::UCPD1>;
});

#[derive(Debug, Format)]
enum CableOrientation {
Normal,
Flipped,
DebugAccessoryMode,
}

// Returns true when the cable
async fn wait_attached<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation {
loop {
let (cc1, cc2) = cc_phy.vstate();
if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST {
// Detached, wait until attached by monitoring the CC lines.
cc_phy.wait_for_vstate_change().await;
continue;
}

// Attached, wait for CC lines to be stable for tCCDebounce (100..200ms).
if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change())
.await
.is_ok()
{
// State has changed, restart detection procedure.
continue;
};

// State was stable for the complete debounce period, check orientation.
return match (cc1, cc2) {
(_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected
(CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected
_ => CableOrientation::DebugAccessoryMode, // Both connected (special cable)
};
}
}

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let config = Config::default();
let p = embassy_stm32::init(config);

info!("Hello World!");

// This pin controls the dead-battery mode on the attached TCPP01-M12.
elagil marked this conversation as resolved.
Show resolved Hide resolved
// If low, TCPP01-M12 disconnects CC lines and presents dead-battery resistance on CC lines, thus set high.
let _tcpp01_m12_ndb = Output::new(p.PA9, embassy_stm32::gpio::Level::High, embassy_stm32::gpio::Speed::Low);

let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB13, p.PB14, Default::default());
ucpd.cc_phy().set_pull(CcPull::Sink);

info!("Waiting for USB connection...");
let cable_orientation = wait_attached(ucpd.cc_phy()).await;
info!("USB cable connected, orientation: {}", cable_orientation);

let cc_sel = match cable_orientation {
CableOrientation::Normal => {
info!("Starting PD communication on CC1 pin");
CcSel::CC1
}
CableOrientation::Flipped => {
info!("Starting PD communication on CC2 pin");
CcSel::CC2
}
CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"),
};
let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.GPDMA1_CH0, p.GPDMA1_CH1, cc_sel);

loop {
// Enough space for the longest non-extended data message.
let mut buf = [0_u8; 30];
match pd_phy.receive(buf.as_mut()).await {
Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]),
Err(e) => error!("USB PD RX: {}", e),
}
}
}
Loading