diff options
| author | Alex Martens <[email protected]> | 2022-09-18 12:02:05 -0700 |
|---|---|---|
| committer | Alex Martens <[email protected]> | 2022-09-18 12:02:05 -0700 |
| commit | ab1a6889a62e86a80af6fc572ffa992cfb9ef960 (patch) | |
| tree | 4486533bbb111191b91fce46915d094e6df06755 | |
| parent | 336ebe54c0f32fd729d50889850032222c6c6ca4 (diff) | |
rp: fix async SPI read and write
| -rw-r--r-- | embassy-rp/src/dma.rs | 38 | ||||
| -rw-r--r-- | embassy-rp/src/spi.rs | 59 |
2 files changed, 79 insertions, 18 deletions
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index acf338225..b256cc2f0 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs | |||
| @@ -56,6 +56,25 @@ pub unsafe fn read<'a, C: Channel, W: Word>( | |||
| 56 | ) | 56 | ) |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | pub unsafe fn read_repeated<'a, C: Channel, W: Word>( | ||
| 60 | ch: impl Peripheral<P = C> + 'a, | ||
| 61 | from: *const W, | ||
| 62 | len: usize, | ||
| 63 | dreq: u8, | ||
| 64 | ) -> Transfer<'a, C> { | ||
| 65 | let mut dummy: u32 = 0; | ||
| 66 | copy_inner( | ||
| 67 | ch, | ||
| 68 | from as *const u32, | ||
| 69 | &mut dummy as *mut u32, | ||
| 70 | len, | ||
| 71 | W::size(), | ||
| 72 | false, | ||
| 73 | false, | ||
| 74 | dreq, | ||
| 75 | ) | ||
| 76 | } | ||
| 77 | |||
| 59 | pub unsafe fn write<'a, C: Channel, W: Word>( | 78 | pub unsafe fn write<'a, C: Channel, W: Word>( |
| 60 | ch: impl Peripheral<P = C> + 'a, | 79 | ch: impl Peripheral<P = C> + 'a, |
| 61 | from: *const [W], | 80 | from: *const [W], |
| @@ -75,6 +94,25 @@ pub unsafe fn write<'a, C: Channel, W: Word>( | |||
| 75 | ) | 94 | ) |
| 76 | } | 95 | } |
| 77 | 96 | ||
| 97 | pub unsafe fn write_repeated<'a, C: Channel, W: Word>( | ||
| 98 | ch: impl Peripheral<P = C> + 'a, | ||
| 99 | to: *mut W, | ||
| 100 | len: usize, | ||
| 101 | dreq: u8, | ||
| 102 | ) -> Transfer<'a, C> { | ||
| 103 | let dummy: u32 = 0; | ||
| 104 | copy_inner( | ||
| 105 | ch, | ||
| 106 | &dummy as *const u32, | ||
| 107 | to as *mut u32, | ||
| 108 | len, | ||
| 109 | W::size(), | ||
| 110 | false, | ||
| 111 | false, | ||
| 112 | dreq, | ||
| 113 | ) | ||
| 114 | } | ||
| 115 | |||
| 78 | pub unsafe fn copy<'a, C: Channel, W: Word>( | 116 | pub unsafe fn copy<'a, C: Channel, W: Word>( |
| 79 | ch: impl Peripheral<P = C> + 'a, | 117 | ch: impl Peripheral<P = C> + 'a, |
| 80 | from: &[W], | 118 | from: &[W], |
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 74f0b04de..e7cd99929 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs | |||
| @@ -325,30 +325,53 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 327 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 328 | let ch = self.tx_dma.as_mut().unwrap(); | 328 | unsafe { |
| 329 | let transfer = unsafe { | 329 | self.inner.regs().dmacr().write(|reg| { |
| 330 | self.inner.regs().dmacr().modify(|reg| { | 330 | reg.set_rxdmae(true); |
| 331 | reg.set_txdmae(true); | 331 | reg.set_txdmae(true); |
| 332 | }); | 332 | }) |
| 333 | }; | ||
| 334 | let tx_ch = self.tx_dma.as_mut().unwrap(); | ||
| 335 | let tx_transfer = unsafe { | ||
| 336 | // If we don't assign future to a variable, the data register pointer | ||
| 337 | // is held across an await and makes the future non-Send. | ||
| 338 | crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) | ||
| 339 | }; | ||
| 340 | let rx_ch = self.rx_dma.as_mut().unwrap(); | ||
| 341 | let rx_transfer = unsafe { | ||
| 333 | // If we don't assign future to a variable, the data register pointer | 342 | // If we don't assign future to a variable, the data register pointer |
| 334 | // is held across an await and makes the future non-Send. | 343 | // is held across an await and makes the future non-Send. |
| 335 | crate::dma::write(ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) | 344 | crate::dma::read_repeated( |
| 345 | rx_ch, | ||
| 346 | self.inner.regs().dr().ptr() as *const u8, | ||
| 347 | buffer.len(), | ||
| 348 | T::RX_DREQ, | ||
| 349 | ) | ||
| 336 | }; | 350 | }; |
| 337 | transfer.await; | 351 | join(tx_transfer, rx_transfer).await; |
| 338 | Ok(()) | 352 | Ok(()) |
| 339 | } | 353 | } |
| 340 | 354 | ||
| 341 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 355 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 342 | let ch = self.rx_dma.as_mut().unwrap(); | 356 | unsafe { |
| 343 | let transfer = unsafe { | 357 | self.inner.regs().dmacr().write(|reg| { |
| 344 | self.inner.regs().dmacr().modify(|reg| { | ||
| 345 | reg.set_rxdmae(true); | 358 | reg.set_rxdmae(true); |
| 346 | }); | 359 | reg.set_txdmae(true); |
| 360 | }) | ||
| 361 | }; | ||
| 362 | let tx_ch = self.tx_dma.as_mut().unwrap(); | ||
| 363 | let tx_transfer = unsafe { | ||
| 364 | // If we don't assign future to a variable, the data register pointer | ||
| 365 | // is held across an await and makes the future non-Send. | ||
| 366 | crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ) | ||
| 367 | }; | ||
| 368 | let rx_ch = self.rx_dma.as_mut().unwrap(); | ||
| 369 | let rx_transfer = unsafe { | ||
| 347 | // If we don't assign future to a variable, the data register pointer | 370 | // If we don't assign future to a variable, the data register pointer |
| 348 | // is held across an await and makes the future non-Send. | 371 | // is held across an await and makes the future non-Send. |
| 349 | crate::dma::read(ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) | 372 | crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) |
| 350 | }; | 373 | }; |
| 351 | transfer.await; | 374 | join(tx_transfer, rx_transfer).await; |
| 352 | Ok(()) | 375 | Ok(()) |
| 353 | } | 376 | } |
| 354 | 377 | ||
| @@ -364,20 +387,20 @@ impl<'d, T: Instance> Spi<'d, T, Async> { | |||
| 364 | let (_, from_len) = crate::dma::slice_ptr_parts(tx_ptr); | 387 | let (_, from_len) = crate::dma::slice_ptr_parts(tx_ptr); |
| 365 | let (_, to_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); | 388 | let (_, to_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); |
| 366 | assert_eq!(from_len, to_len); | 389 | assert_eq!(from_len, to_len); |
| 390 | unsafe { | ||
| 391 | self.inner.regs().dmacr().write(|reg| { | ||
| 392 | reg.set_rxdmae(true); | ||
| 393 | reg.set_txdmae(true); | ||
| 394 | }) | ||
| 395 | }; | ||
| 367 | let tx_ch = self.tx_dma.as_mut().unwrap(); | 396 | let tx_ch = self.tx_dma.as_mut().unwrap(); |
| 368 | let tx_transfer = unsafe { | 397 | let tx_transfer = unsafe { |
| 369 | self.inner.regs().dmacr().modify(|reg| { | ||
| 370 | reg.set_txdmae(true); | ||
| 371 | }); | ||
| 372 | // If we don't assign future to a variable, the data register pointer | 398 | // If we don't assign future to a variable, the data register pointer |
| 373 | // is held across an await and makes the future non-Send. | 399 | // is held across an await and makes the future non-Send. |
| 374 | crate::dma::write(tx_ch, tx_ptr, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) | 400 | crate::dma::write(tx_ch, tx_ptr, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) |
| 375 | }; | 401 | }; |
| 376 | let rx_ch = self.rx_dma.as_mut().unwrap(); | 402 | let rx_ch = self.rx_dma.as_mut().unwrap(); |
| 377 | let rx_transfer = unsafe { | 403 | let rx_transfer = unsafe { |
| 378 | self.inner.regs().dmacr().modify(|reg| { | ||
| 379 | reg.set_rxdmae(true); | ||
| 380 | }); | ||
| 381 | // If we don't assign future to a variable, the data register pointer | 404 | // If we don't assign future to a variable, the data register pointer |
| 382 | // is held across an await and makes the future non-Send. | 405 | // is held across an await and makes the future non-Send. |
| 383 | crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) | 406 | crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) |
