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