954: rp: fix async SPI read and write r=lulf a=newAM

Closes #953 

Co-authored-by: Alex Martens <alex@thinglab.org>
This commit is contained in:
bors[bot] 2022-09-19 07:26:10 +00:00 committed by GitHub
commit 6663390224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 16 deletions

View File

@ -75,6 +75,25 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
)
}
pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
ch: impl Peripheral<P = C> + 'a,
to: *mut W,
len: usize,
dreq: u8,
) -> Transfer<'a, C> {
let dummy: u32 = 0;
copy_inner(
ch,
&dummy as *const u32,
to as *mut u32,
len,
W::size(),
false,
false,
dreq,
)
}
pub unsafe fn copy<'a, C: Channel, W: Word>(
ch: impl Peripheral<P = C> + 'a,
from: &[W],

View File

@ -325,30 +325,52 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
}
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let ch = self.tx_dma.as_mut().unwrap();
let transfer = unsafe {
let tx_ch = self.tx_dma.as_mut().unwrap();
let tx_transfer = unsafe {
self.inner.regs().dmacr().modify(|reg| {
reg.set_txdmae(true);
});
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
crate::dma::write(ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ)
crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ)
};
transfer.await;
tx_transfer.await;
let p = self.inner.regs();
unsafe {
while p.sr().read().bsy() {}
// clear RX FIFO contents to prevent stale reads
while p.sr().read().rne() {
let _: u16 = p.dr().read().data();
}
// clear RX overrun interrupt
p.icr().write(|w| w.set_roric(true));
}
Ok(())
}
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let ch = self.rx_dma.as_mut().unwrap();
let transfer = unsafe {
self.inner.regs().dmacr().modify(|reg| {
unsafe {
self.inner.regs().dmacr().write(|reg| {
reg.set_rxdmae(true);
});
reg.set_txdmae(true);
})
};
let tx_ch = self.tx_dma.as_mut().unwrap();
let tx_transfer = unsafe {
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
crate::dma::read(ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ)
crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ)
};
transfer.await;
let rx_ch = self.rx_dma.as_mut().unwrap();
let rx_transfer = unsafe {
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ)
};
join(tx_transfer, rx_transfer).await;
Ok(())
}
@ -364,20 +386,20 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
let (_, from_len) = crate::dma::slice_ptr_parts(tx_ptr);
let (_, to_len) = crate::dma::slice_ptr_parts_mut(rx_ptr);
assert_eq!(from_len, to_len);
unsafe {
self.inner.regs().dmacr().write(|reg| {
reg.set_rxdmae(true);
reg.set_txdmae(true);
})
};
let tx_ch = self.tx_dma.as_mut().unwrap();
let tx_transfer = unsafe {
self.inner.regs().dmacr().modify(|reg| {
reg.set_txdmae(true);
});
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
crate::dma::write(tx_ch, tx_ptr, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ)
};
let rx_ch = self.rx_dma.as_mut().unwrap();
let rx_transfer = unsafe {
self.inner.regs().dmacr().modify(|reg| {
reg.set_rxdmae(true);
});
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ)