diff options
| -rw-r--r-- | embassy-stm32/src/ucpd.rs | 125 | ||||
| -rw-r--r-- | examples/stm32g4/src/bin/usb_c_pd.rs | 2 |
2 files changed, 59 insertions, 68 deletions
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 0a6f7df71..02c81c2b6 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs | |||
| @@ -57,11 +57,7 @@ pub struct Ucpd<'d, T: Instance> { | |||
| 57 | 57 | ||
| 58 | impl<'d, T: Instance> Drop for Ucpd<'d, T> { | 58 | impl<'d, T: Instance> Drop for Ucpd<'d, T> { |
| 59 | fn drop(&mut self) { | 59 | fn drop(&mut self) { |
| 60 | T::REGS.cr().modify(|w| { | 60 | T::REGS.cfgr1().write(|w| w.set_ucpden(false)); |
| 61 | w.set_ccenable(Ccenable::DISABLED); | ||
| 62 | w.set_cc1tcdis(true); | ||
| 63 | w.set_cc2tcdis(true); | ||
| 64 | }); | ||
| 65 | } | 61 | } |
| 66 | } | 62 | } |
| 67 | 63 | ||
| @@ -99,12 +95,6 @@ impl<'d, T: Instance> Ucpd<'d, T> { | |||
| 99 | // 1.75us * 17 = ~30us | 95 | // 1.75us * 17 = ~30us |
| 100 | w.set_ifrgap(17 - 1); | 96 | w.set_ifrgap(17 - 1); |
| 101 | 97 | ||
| 102 | // TODO: Currently only SOP messages are supported. | ||
| 103 | w.set_rxordseten(0x1); | ||
| 104 | |||
| 105 | // Enable DMA and the peripheral | ||
| 106 | w.set_txdmaen(true); | ||
| 107 | w.set_rxdmaen(true); | ||
| 108 | w.set_ucpden(true); | 98 | w.set_ucpden(true); |
| 109 | }); | 99 | }); |
| 110 | 100 | ||
| @@ -155,7 +145,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { | |||
| 155 | 145 | ||
| 156 | /// Waits for a change in voltage state on either CC line. | 146 | /// Waits for a change in voltage state on either CC line. |
| 157 | pub async fn wait_for_cc_vstate_change(&self) -> (CcVState, CcVState) { | 147 | pub async fn wait_for_cc_vstate_change(&self) -> (CcVState, CcVState) { |
| 158 | let _on_drop = OnDrop::new(|| critical_section::with(|_| self.enable_cc_interrupts(false))); | 148 | let _on_drop = OnDrop::new(|| self.enable_cc_interrupts(false)); |
| 159 | let prev_vstate = self.cc_vstate(); | 149 | let prev_vstate = self.cc_vstate(); |
| 160 | poll_fn(|cx| { | 150 | poll_fn(|cx| { |
| 161 | let vstate = self.cc_vstate(); | 151 | let vstate = self.cc_vstate(); |
| @@ -171,47 +161,49 @@ impl<'d, T: Instance> Ucpd<'d, T> { | |||
| 171 | } | 161 | } |
| 172 | 162 | ||
| 173 | fn enable_cc_interrupts(&self, enable: bool) { | 163 | fn enable_cc_interrupts(&self, enable: bool) { |
| 174 | critical_section::with(|_| { | 164 | T::REGS.imr().modify(|w| { |
| 175 | T::REGS.imr().modify(|w| { | 165 | w.set_typecevt1ie(enable); |
| 176 | w.set_typecevt1ie(enable); | 166 | w.set_typecevt2ie(enable); |
| 177 | w.set_typecevt2ie(enable); | ||
| 178 | }) | ||
| 179 | }); | 167 | }); |
| 180 | } | 168 | } |
| 181 | 169 | ||
| 182 | /// Returns PD receiver and transmitter. | 170 | /// Returns PD receiver and transmitter. |
| 183 | pub fn pd( | 171 | pub fn pd_phy( |
| 184 | &mut self, | 172 | &mut self, |
| 185 | rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, | 173 | rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, |
| 186 | tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, | 174 | tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, |
| 187 | cc_sel: CcSel, | 175 | cc_sel: CcSel, |
| 188 | ) -> (PdRx<'_, T>, PdTx<'_, T>) { | 176 | ) -> PdPhy<'_, T> { |
| 189 | let r = T::REGS; | 177 | let r = T::REGS; |
| 190 | 178 | ||
| 179 | // TODO: Currently only SOP messages are supported. | ||
| 180 | r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); | ||
| 181 | |||
| 182 | r.cfgr1().modify(|w| { | ||
| 183 | // TODO: Currently only SOP messages are supported. | ||
| 184 | w.set_rxordseten(0x1); | ||
| 185 | |||
| 186 | // Enable DMA | ||
| 187 | w.set_txdmaen(true); | ||
| 188 | w.set_rxdmaen(true); | ||
| 189 | }); | ||
| 190 | |||
| 191 | // Enable the receiver on one of the two CC lines. | 191 | // Enable the receiver on one of the two CC lines. |
| 192 | r.cr().modify(|w| { | 192 | r.cr().modify(|w| { |
| 193 | w.set_phyccsel(cc_sel); | 193 | w.set_phyccsel(cc_sel); |
| 194 | w.set_phyrxen(true); | 194 | w.set_phyrxen(true); |
| 195 | }); | 195 | }); |
| 196 | 196 | ||
| 197 | // TODO: Currently only SOP messages are supported. | ||
| 198 | r.tx_ordsetr().write(|w| w.set_txordset(0b10001_11000_11000_11000)); | ||
| 199 | |||
| 200 | into_ref!(rx_dma, tx_dma); | 197 | into_ref!(rx_dma, tx_dma); |
| 201 | let rx_dma_req = rx_dma.request(); | 198 | let rx_dma_req = rx_dma.request(); |
| 202 | let tx_dma_req = tx_dma.request(); | 199 | let tx_dma_req = tx_dma.request(); |
| 203 | ( | 200 | PdPhy { |
| 204 | PdRx { | 201 | _ucpd: self, |
| 205 | _ucpd: self, | 202 | rx_dma_ch: rx_dma.map_into(), |
| 206 | dma_ch: rx_dma.map_into(), | 203 | rx_dma_req, |
| 207 | dma_req: rx_dma_req, | 204 | tx_dma_ch: tx_dma.map_into(), |
| 208 | }, | 205 | tx_dma_req, |
| 209 | PdTx { | 206 | } |
| 210 | _ucpd: self, | ||
| 211 | dma_ch: tx_dma.map_into(), | ||
| 212 | dma_req: tx_dma_req, | ||
| 213 | }, | ||
| 214 | ) | ||
| 215 | } | 207 | } |
| 216 | } | 208 | } |
| 217 | 209 | ||
| @@ -225,20 +217,29 @@ pub enum RxError { | |||
| 225 | Overrun, | 217 | Overrun, |
| 226 | } | 218 | } |
| 227 | 219 | ||
| 228 | /// Power Delivery (PD) Receiver. | 220 | /// Transmit Error. |
| 229 | pub struct PdRx<'d, T: Instance> { | 221 | #[derive(Debug, Clone, Copy)] |
| 222 | pub enum TxError { | ||
| 223 | /// Concurrent receive in progress or excessive noise on the line. | ||
| 224 | Discarded, | ||
| 225 | } | ||
| 226 | |||
| 227 | /// Power Delivery (PD) PHY. | ||
| 228 | pub struct PdPhy<'d, T: Instance> { | ||
| 230 | _ucpd: &'d Ucpd<'d, T>, | 229 | _ucpd: &'d Ucpd<'d, T>, |
| 231 | dma_ch: PeripheralRef<'d, AnyChannel>, | 230 | rx_dma_ch: PeripheralRef<'d, AnyChannel>, |
| 232 | dma_req: Request, | 231 | rx_dma_req: Request, |
| 232 | tx_dma_ch: PeripheralRef<'d, AnyChannel>, | ||
| 233 | tx_dma_req: Request, | ||
| 233 | } | 234 | } |
| 234 | 235 | ||
| 235 | impl<'d, T: Instance> Drop for PdRx<'d, T> { | 236 | impl<'d, T: Instance> Drop for PdPhy<'d, T> { |
| 236 | fn drop(&mut self) { | 237 | fn drop(&mut self) { |
| 237 | T::REGS.cr().modify(|w| w.set_phyrxen(false)); | 238 | T::REGS.cr().modify(|w| w.set_phyrxen(false)); |
| 238 | } | 239 | } |
| 239 | } | 240 | } |
| 240 | 241 | ||
| 241 | impl<'d, T: Instance> PdRx<'d, T> { | 242 | impl<'d, T: Instance> PdPhy<'d, T> { |
| 242 | /// Receives a PD message into the provided buffer. | 243 | /// Receives a PD message into the provided buffer. |
| 243 | /// | 244 | /// |
| 244 | /// Returns the number of received bytes or an error. | 245 | /// Returns the number of received bytes or an error. |
| @@ -261,8 +262,8 @@ impl<'d, T: Instance> PdRx<'d, T> { | |||
| 261 | transfer_options.complete_transfer_ir = false; | 262 | transfer_options.complete_transfer_ir = false; |
| 262 | 263 | ||
| 263 | Transfer::new_read( | 264 | Transfer::new_read( |
| 264 | &self.dma_ch, | 265 | &self.rx_dma_ch, |
| 265 | self.dma_req, | 266 | self.rx_dma_req, |
| 266 | r.rxdr().as_ptr() as *mut u8, | 267 | r.rxdr().as_ptr() as *mut u8, |
| 267 | buf, | 268 | buf, |
| 268 | transfer_options, | 269 | transfer_options, |
| @@ -282,6 +283,7 @@ impl<'d, T: Instance> PdRx<'d, T> { | |||
| 282 | } | 283 | } |
| 283 | 284 | ||
| 284 | async fn wait_rx_done(&self) -> Result<(), RxError> { | 285 | async fn wait_rx_done(&self) -> Result<(), RxError> { |
| 286 | let _on_drop = OnDrop::new(|| self.enable_rx_interrupt(false)); | ||
| 285 | poll_fn(|cx| { | 287 | poll_fn(|cx| { |
| 286 | let r = T::REGS; | 288 | let r = T::REGS; |
| 287 | let sr = r.sr().read(); | 289 | let sr = r.sr().read(); |
| @@ -301,31 +303,18 @@ impl<'d, T: Instance> PdRx<'d, T> { | |||
| 301 | }); | 303 | }); |
| 302 | Poll::Ready(ret) | 304 | Poll::Ready(ret) |
| 303 | } else { | 305 | } else { |
| 304 | // Enable receiver interrupt. | ||
| 305 | T::waker().register(cx.waker()); | 306 | T::waker().register(cx.waker()); |
| 306 | r.imr().modify(|w| w.set_rxmsgendie(true)); | 307 | self.enable_rx_interrupt(true); |
| 307 | Poll::Pending | 308 | Poll::Pending |
| 308 | } | 309 | } |
| 309 | }) | 310 | }) |
| 310 | .await | 311 | .await |
| 311 | } | 312 | } |
| 312 | } | ||
| 313 | 313 | ||
| 314 | /// Transmit Error. | 314 | fn enable_rx_interrupt(&self, enable: bool) { |
| 315 | #[derive(Debug, Clone, Copy)] | 315 | T::REGS.imr().modify(|w| w.set_rxmsgendie(enable)); |
| 316 | pub enum TxError { | 316 | } |
| 317 | /// Concurrent receive in progress or excessive noise on the line. | ||
| 318 | Discarded, | ||
| 319 | } | ||
| 320 | |||
| 321 | /// Power Delivery (PD) Transmitter. | ||
| 322 | pub struct PdTx<'d, T: Instance> { | ||
| 323 | _ucpd: &'d Ucpd<'d, T>, | ||
| 324 | dma_ch: PeripheralRef<'d, AnyChannel>, | ||
| 325 | dma_req: Request, | ||
| 326 | } | ||
| 327 | 317 | ||
| 328 | impl<'d, T: Instance> PdTx<'d, T> { | ||
| 329 | /// Transmits a PD message. | 318 | /// Transmits a PD message. |
| 330 | pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), TxError> { | 319 | pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), TxError> { |
| 331 | let r = T::REGS; | 320 | let r = T::REGS; |
| @@ -346,8 +335,8 @@ impl<'d, T: Instance> PdTx<'d, T> { | |||
| 346 | // Start the DMA and let it do its thing in the background. | 335 | // Start the DMA and let it do its thing in the background. |
| 347 | let _dma = unsafe { | 336 | let _dma = unsafe { |
| 348 | Transfer::new_write( | 337 | Transfer::new_write( |
| 349 | &self.dma_ch, | 338 | &self.tx_dma_ch, |
| 350 | self.dma_req, | 339 | self.tx_dma_req, |
| 351 | buf, | 340 | buf, |
| 352 | r.txdr().as_ptr() as *mut u8, | 341 | r.txdr().as_ptr() as *mut u8, |
| 353 | TransferOptions::default(), | 342 | TransferOptions::default(), |
| @@ -365,6 +354,7 @@ impl<'d, T: Instance> PdTx<'d, T> { | |||
| 365 | } | 354 | } |
| 366 | 355 | ||
| 367 | async fn wait_tx_done(&self) -> Result<(), TxError> { | 356 | async fn wait_tx_done(&self) -> Result<(), TxError> { |
| 357 | let _on_drop = OnDrop::new(|| self.enable_tx_interrupts(false)); | ||
| 368 | poll_fn(|cx| { | 358 | poll_fn(|cx| { |
| 369 | let r = T::REGS; | 359 | let r = T::REGS; |
| 370 | if r.sr().read().txmsgdisc() { | 360 | if r.sr().read().txmsgdisc() { |
| @@ -372,19 +362,20 @@ impl<'d, T: Instance> PdTx<'d, T> { | |||
| 372 | } else if r.sr().read().txmsgsent() { | 362 | } else if r.sr().read().txmsgsent() { |
| 373 | Poll::Ready(Ok(())) | 363 | Poll::Ready(Ok(())) |
| 374 | } else { | 364 | } else { |
| 375 | // Enable transmit interrupts. | ||
| 376 | T::waker().register(cx.waker()); | 365 | T::waker().register(cx.waker()); |
| 377 | r.imr().modify(|w| { | 366 | self.enable_tx_interrupts(true); |
| 378 | w.set_txmsgdiscie(true); | ||
| 379 | w.set_txmsgsentie(true); | ||
| 380 | }); | ||
| 381 | Poll::Pending | 367 | Poll::Pending |
| 382 | } | 368 | } |
| 383 | }) | 369 | }) |
| 384 | .await | 370 | .await |
| 385 | } | 371 | } |
| 386 | 372 | ||
| 387 | fn clear_tx_flags(&self) {} | 373 | fn enable_tx_interrupts(&self, enable: bool) { |
| 374 | T::REGS.imr().modify(|w| { | ||
| 375 | w.set_txmsgdiscie(enable); | ||
| 376 | w.set_txmsgsentie(enable); | ||
| 377 | }); | ||
| 378 | } | ||
| 388 | } | 379 | } |
| 389 | 380 | ||
| 390 | /// Interrupt handler. | 381 | /// Interrupt handler. |
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 1443cb773..fd2400bd5 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs | |||
| @@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) { | |||
| 67 | } | 67 | } |
| 68 | CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"), | 68 | CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"), |
| 69 | }; | 69 | }; |
| 70 | let (mut _rx, mut _tx) = ucpd.pd(p.DMA1_CH1, p.DMA1_CH2, cc_sel); | 70 | let mut pd_phy = ucpd.pd_phy(p.DMA1_CH1, p.DMA1_CH2, cc_sel); |
| 71 | 71 | ||
| 72 | loop {} | 72 | loop {} |
| 73 | } | 73 | } |
