aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/stm32h5/src/bin/usb_c_pd.rs92
1 files changed, 92 insertions, 0 deletions
diff --git a/examples/stm32h5/src/bin/usb_c_pd.rs b/examples/stm32h5/src/bin/usb_c_pd.rs
new file mode 100644
index 000000000..00cb3b3da
--- /dev/null
+++ b/examples/stm32h5/src/bin/usb_c_pd.rs
@@ -0,0 +1,92 @@
1//! This example targets the NUCLEO-H563ZI platform.
2//! USB-C CC lines are protected by a TCPP01-M12 chipset.
3#![no_std]
4#![no_main]
5
6use defmt::{error, info, Format};
7use embassy_executor::Spawner;
8use embassy_stm32::gpio::Output;
9use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd};
10use embassy_stm32::{bind_interrupts, peripherals, Config};
11use embassy_time::{with_timeout, Duration};
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 UCPD1 => ucpd::InterruptHandler<peripherals::UCPD1>;
16});
17
18#[derive(Debug, Format)]
19enum CableOrientation {
20 Normal,
21 Flipped,
22 DebugAccessoryMode,
23}
24
25// Returns true when the cable
26async fn wait_attached<T: ucpd::Instance>(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation {
27 loop {
28 let (cc1, cc2) = cc_phy.vstate();
29 if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST {
30 // Detached, wait until attached by monitoring the CC lines.
31 cc_phy.wait_for_vstate_change().await;
32 continue;
33 }
34
35 // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms).
36 if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change())
37 .await
38 .is_ok()
39 {
40 // State has changed, restart detection procedure.
41 continue;
42 };
43
44 // State was stable for the complete debounce period, check orientation.
45 return match (cc1, cc2) {
46 (_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected
47 (CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected
48 _ => CableOrientation::DebugAccessoryMode, // Both connected (special cable)
49 };
50 }
51}
52
53#[embassy_executor::main]
54async fn main(_spawner: Spawner) {
55 let config = Config::default();
56 let p = embassy_stm32::init(config);
57
58 info!("Hello World!");
59
60 // This pin controls the dead-battery mode on the attached TCPP01-M12.
61 // If low, TCPP01-M12 disconnects CC lines and presents dead-battery resistance on CC lines, thus set high.
62 let _tcpp01_m12_ndb = Output::new(p.PA9, embassy_stm32::gpio::Level::High, embassy_stm32::gpio::Speed::Low);
63
64 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB13, p.PB14, Default::default());
65 ucpd.cc_phy().set_pull(CcPull::Sink);
66
67 info!("Waiting for USB connection...");
68 let cable_orientation = wait_attached(ucpd.cc_phy()).await;
69 info!("USB cable connected, orientation: {}", cable_orientation);
70
71 let cc_sel = match cable_orientation {
72 CableOrientation::Normal => {
73 info!("Starting PD communication on CC1 pin");
74 CcSel::CC1
75 }
76 CableOrientation::Flipped => {
77 info!("Starting PD communication on CC2 pin");
78 CcSel::CC2
79 }
80 CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"),
81 };
82 let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.GPDMA1_CH0, p.GPDMA1_CH1, cc_sel);
83
84 loop {
85 // Enough space for the longest non-extended data message.
86 let mut buf = [0_u8; 30];
87 match pd_phy.receive(buf.as_mut()).await {
88 Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]),
89 Err(e) => error!("USB PD RX: {}", e),
90 }
91 }
92}