aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/ucpd.rs125
-rw-r--r--examples/stm32g4/src/bin/usb_c_pd.rs2
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
58impl<'d, T: Instance> Drop for Ucpd<'d, T> { 58impl<'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.
229pub struct PdRx<'d, T: Instance> { 221#[derive(Debug, Clone, Copy)]
222pub enum TxError {
223 /// Concurrent receive in progress or excessive noise on the line.
224 Discarded,
225}
226
227/// Power Delivery (PD) PHY.
228pub 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
235impl<'d, T: Instance> Drop for PdRx<'d, T> { 236impl<'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
241impl<'d, T: Instance> PdRx<'d, T> { 242impl<'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));
316pub enum TxError { 316 }
317 /// Concurrent receive in progress or excessive noise on the line.
318 Discarded,
319}
320
321/// Power Delivery (PD) Transmitter.
322pub struct PdTx<'d, T: Instance> {
323 _ucpd: &'d Ucpd<'d, T>,
324 dma_ch: PeripheralRef<'d, AnyChannel>,
325 dma_req: Request,
326}
327 317
328impl<'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}