diff options
| author | Sjoerd Simons <[email protected]> | 2024-08-18 21:06:13 +0200 |
|---|---|---|
| committer | Sjoerd Simons <[email protected]> | 2024-08-18 21:19:16 +0200 |
| commit | 1b0661ebb17fca93d11891a1c488005d3d644784 (patch) | |
| tree | 919b6ec0beabb996d7a90ca9f04daed409101e6e | |
| parent | d8459685fd1e53a0fb57f44d950e0bc4f450c5f7 (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.rs | 77 | ||||
| -rw-r--r-- | examples/stm32g4/src/bin/usb_c_pd.rs | 2 | ||||
| -rw-r--r-- | tests/stm32/src/bin/ucpd.rs | 4 |
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}; | |||
| 27 | use crate::interrupt; | 27 | use crate::interrupt; |
| 28 | use crate::interrupt::typelevel::Interrupt; | 28 | use crate::interrupt::typelevel::Interrupt; |
| 29 | use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; | 29 | use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; |
| 30 | pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; | 30 | pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; |
| 31 | use crate::rcc::{self, RccPeripheral}; | 31 | use crate::rcc::{self, RccPeripheral}; |
| 32 | 32 | ||
| 33 | pub(crate) fn init( | 33 | pub(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)] | ||
| 92 | pub 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 | |||
| 105 | impl 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. |
| 90 | pub struct Ucpd<'d, T: Instance> { | 118 | pub 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))] | ||
| 329 | pub 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), |
