diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-09-10 23:03:58 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-09-10 23:03:58 +0000 |
| commit | fac71e594e6cecc78d8d77e129236491194125c6 (patch) | |
| tree | 3f98080c8b86aa85ca3ff12804ad532c0843a573 | |
| parent | 0bf9a2591b062f2f8409fe27c590e1783b139e38 (diff) | |
| parent | 1b0661ebb17fca93d11891a1c488005d3d644784 (diff) | |
Merge pull request #3271 from sjoerdsimons/ucpd-sop-filters
[UCPD] Add support for non-SOP packets
| -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), |
