aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSjoerd Simons <[email protected]>2024-08-18 21:06:13 +0200
committerSjoerd Simons <[email protected]>2024-08-18 21:19:16 +0200
commit1b0661ebb17fca93d11891a1c488005d3d644784 (patch)
tree919b6ec0beabb996d7a90ca9f04daed409101e6e
parentd8459685fd1e53a0fb57f44d950e0bc4f450c5f7 (diff)
[UCPD] Add support for non-SOP packets
Allow capturing (and distinguishing) non-SOP packets as well. The default configuration will just configure SOP packets. For ease of use the default receive function signature is unchanged as for PD sinks (which is likely the common usage) just SOP is enough so no need to differentiate.
-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),