aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/ucpd.rs77
-rw-r--r--examples/stm32g4/src/bin/usb_c_pd.rs2
-rw-r--r--tests/stm32/src/bin/ucpd.rs4
3 files changed, 76 insertions, 7 deletions
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index 40aea75cb..ee0a2c7c1 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -27,7 +27,7 @@ use crate::dma::{ChannelAndRequest, TransferOptions};
27use crate::interrupt; 27use crate::interrupt;
28use crate::interrupt::typelevel::Interrupt; 28use crate::interrupt::typelevel::Interrupt;
29use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; 29use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
30pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; 30pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState};
31use crate::rcc::{self, RccPeripheral}; 31use crate::rcc::{self, RccPeripheral};
32 32
33pub(crate) fn init( 33pub(crate) fn init(
@@ -86,6 +86,34 @@ pub enum CcPull {
86 Source3_0A, 86 Source3_0A,
87} 87}
88 88
89/// UCPD configuration
90#[non_exhaustive]
91#[derive(Copy, Clone, Debug)]
92pub struct Config {
93 /// Receive SOP packets
94 pub sop: bool,
95 /// Receive SOP' packets
96 pub sop_prime: bool,
97 /// Receive SOP'' packets
98 pub sop_double_prime: bool,
99 /// Receive SOP'_Debug packets
100 pub sop_prime_debug: bool,
101 /// Receive SOP''_Debug packets
102 pub sop_double_prime_debug: bool,
103}
104
105impl Default for Config {
106 fn default() -> Self {
107 Self {
108 sop: true,
109 sop_prime: false,
110 sop_double_prime: false,
111 sop_prime_debug: false,
112 sop_double_prime_debug: false,
113 }
114 }
115}
116
89/// UCPD driver. 117/// UCPD driver.
90pub struct Ucpd<'d, T: Instance> { 118pub struct Ucpd<'d, T: Instance> {
91 cc_phy: CcPhy<'d, T>, 119 cc_phy: CcPhy<'d, T>,
@@ -98,6 +126,7 @@ impl<'d, T: Instance> Ucpd<'d, T> {
98 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 126 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
99 cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd, 127 cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd,
100 cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd, 128 cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd,
129 config: Config,
101 ) -> Self { 130 ) -> Self {
102 into_ref!(cc1, cc2); 131 into_ref!(cc1, cc2);
103 cc1.set_as_analog(); 132 cc1.set_as_analog();
@@ -129,9 +158,15 @@ impl<'d, T: Instance> Ucpd<'d, T> {
129 // 1.75us * 17 = ~30us 158 // 1.75us * 17 = ~30us
130 w.set_ifrgap(17 - 1); 159 w.set_ifrgap(17 - 1);
131 160
132 // TODO: Currently only hard reset and SOP messages can be received.
133 // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing). 161 // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing).
134 w.set_rxordseten(0b1001); 162 let rxordset = (config.sop as u16) << 0
163 | (config.sop_prime as u16) << 1
164 | (config.sop_double_prime as u16) << 2
165 // Hard reset
166 | 0x1 << 3
167 | (config.sop_prime_debug as u16) << 4
168 | (config.sop_double_prime_debug as u16) << 5;
169 w.set_rxordseten(rxordset);
135 170
136 // Enable DMA 171 // Enable DMA
137 w.set_txdmaen(true); 172 w.set_txdmaen(true);
@@ -288,6 +323,22 @@ impl<'d, T: Instance> CcPhy<'d, T> {
288 } 323 }
289} 324}
290 325
326/// Receive SOP.
327#[derive(Debug, Clone, Copy)]
328#[cfg_attr(feature = "defmt", derive(defmt::Format))]
329pub enum Sop {
330 /// SOP
331 Sop,
332 /// SOP'
333 SopPrime,
334 /// SOP''
335 SopDoublePrime,
336 /// SOP'_Debug
337 SopPrimeDebug,
338 /// SOP''_Debug
339 SopDoublePrimeDebug,
340}
341
291/// Receive Error. 342/// Receive Error.
292#[derive(Debug, Clone, Copy)] 343#[derive(Debug, Clone, Copy)]
293#[cfg_attr(feature = "defmt", derive(defmt::Format))] 344#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -340,6 +391,13 @@ impl<'d, T: Instance> PdPhy<'d, T> {
340 /// 391 ///
341 /// Returns the number of received bytes or an error. 392 /// Returns the number of received bytes or an error.
342 pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> { 393 pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
394 self.receive_with_sop(buf).await.map(|(_sop, size)| size)
395 }
396
397 /// Receives SOP and a PD message into the provided buffer.
398 ///
399 /// Returns the start of packet type and number of received bytes or an error.
400 pub async fn receive_with_sop(&mut self, buf: &mut [u8]) -> Result<(Sop, usize), RxError> {
343 let r = T::REGS; 401 let r = T::REGS;
344 402
345 let dma = unsafe { 403 let dma = unsafe {
@@ -388,7 +446,18 @@ impl<'d, T: Instance> PdPhy<'d, T> {
388 } 446 }
389 } 447 }
390 448
391 Ok(r.rx_payszr().read().rxpaysz().into()) 449 let sop = match r.rx_ordsetr().read().rxordset() {
450 Rxordset::SOP => Sop::Sop,
451 Rxordset::SOPPRIME => Sop::SopPrime,
452 Rxordset::SOPDOUBLEPRIME => Sop::SopDoublePrime,
453 Rxordset::SOPPRIMEDEBUG => Sop::SopPrimeDebug,
454 Rxordset::SOPDOUBLEPRIMEDEBUG => Sop::SopDoublePrimeDebug,
455 Rxordset::CABLERESET => return Err(RxError::HardReset),
456 // Extension headers are not supported
457 _ => unreachable!(),
458 };
459
460 Ok((sop, r.rx_payszr().read().rxpaysz().into()))
392 } 461 }
393 462
394 fn enable_rx_interrupt(enable: bool) { 463 fn enable_rx_interrupt(enable: bool) {
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs
index 7caea634f..2e87d3931 100644
--- a/examples/stm32g4/src/bin/usb_c_pd.rs
+++ b/examples/stm32g4/src/bin/usb_c_pd.rs
@@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) {
55 55
56 info!("Hello World!"); 56 info!("Hello World!");
57 57
58 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4); 58 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4, Default::default());
59 ucpd.cc_phy().set_pull(CcPull::Sink); 59 ucpd.cc_phy().set_pull(CcPull::Sink);
60 60
61 info!("Waiting for USB connection..."); 61 info!("Waiting for USB connection...");
diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs
index a6d13b34a..bd7b35d6b 100644
--- a/tests/stm32/src/bin/ucpd.rs
+++ b/tests/stm32/src/bin/ucpd.rs
@@ -106,8 +106,8 @@ async fn main(_spawner: Spawner) {
106 info!("Hello World!"); 106 info!("Hello World!");
107 107
108 // Wire between PD0 and PA8 108 // Wire between PD0 and PA8
109 let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15); 109 let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15, Default::default());
110 let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2); 110 let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2, Default::default());
111 111
112 join( 112 join(
113 source(ucpd1, p.DMA1_CH1, p.DMA1_CH2), 113 source(ucpd1, p.DMA1_CH1, p.DMA1_CH2),