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