Merge #664
664: stm32: more spi fixes r=Dirbaio a=Dirbaio Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
This commit is contained in:
		
						commit
						ff1215c6f9
					
				| @ -7,7 +7,7 @@ use embassy_hal_common::unborrow; | |||||||
| use futures::future::join; | use futures::future::join; | ||||||
| 
 | 
 | ||||||
| use self::sealed::WordSize; | use self::sealed::WordSize; | ||||||
| use crate::dma::{NoDma, Transfer}; | use crate::dma::{slice_ptr_parts, NoDma, Transfer}; | ||||||
| use crate::gpio::sealed::{AFType, Pin as _}; | use crate::gpio::sealed::{AFType, Pin as _}; | ||||||
| use crate::gpio::AnyPin; | use crate::gpio::AnyPin; | ||||||
| use crate::pac::spi::Spi as Regs; | use crate::pac::spi::Spi as Regs; | ||||||
| @ -440,9 +440,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||||||
| 
 | 
 | ||||||
|         tx_f.await; |         tx_f.await; | ||||||
| 
 | 
 | ||||||
|         // flush here otherwise `finish_dma` hangs waiting for the rx fifo to empty
 |  | ||||||
|         flush_rx_fifo(T::REGS); |  | ||||||
| 
 |  | ||||||
|         finish_dma(T::REGS); |         finish_dma(T::REGS); | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
| @ -465,6 +462,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||||||
|             set_rxdmaen(T::REGS, true); |             set_rxdmaen(T::REGS, true); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // SPIv3 clears rxfifo on SPE=0
 | ||||||
|  |         #[cfg(not(spi_v3))] | ||||||
|  |         flush_rx_fifo(T::REGS); | ||||||
|  | 
 | ||||||
|         let clock_byte_count = data.len(); |         let clock_byte_count = data.len(); | ||||||
| 
 | 
 | ||||||
|         let rx_request = self.rxdma.request(); |         let rx_request = self.rxdma.request(); | ||||||
| @ -501,14 +502,19 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> |     async fn transfer_inner<W: Word>( | ||||||
|  |         &mut self, | ||||||
|  |         read: *mut [W], | ||||||
|  |         write: *const [W], | ||||||
|  |     ) -> Result<(), Error> | ||||||
|     where |     where | ||||||
|         Tx: TxDma<T>, |         Tx: TxDma<T>, | ||||||
|         Rx: RxDma<T>, |         Rx: RxDma<T>, | ||||||
|     { |     { | ||||||
|         assert_eq!(read.len(), write.len()); |         let (_, rx_len) = slice_ptr_parts(read); | ||||||
| 
 |         let (_, tx_len) = slice_ptr_parts(write); | ||||||
|         if read.len() == 0 { |         assert_eq!(rx_len, tx_len); | ||||||
|  |         if rx_len == 0 { | ||||||
|             return Ok(()); |             return Ok(()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -520,8 +526,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||||||
|             set_rxdmaen(T::REGS, true); |             set_rxdmaen(T::REGS, true); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // TODO: This is unnecessary in some versions because
 |         // SPIv3 clears rxfifo on SPE=0
 | ||||||
|         // clearing SPE automatically clears the fifos
 |         #[cfg(not(spi_v3))] | ||||||
|         flush_rx_fifo(T::REGS); |         flush_rx_fifo(T::REGS); | ||||||
| 
 | 
 | ||||||
|         let rx_request = self.rxdma.request(); |         let rx_request = self.rxdma.request(); | ||||||
| @ -552,6 +558,22 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         Tx: TxDma<T>, | ||||||
|  |         Rx: RxDma<T>, | ||||||
|  |     { | ||||||
|  |         self.transfer_inner(read, write).await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         Tx: TxDma<T>, | ||||||
|  |         Rx: RxDma<T>, | ||||||
|  |     { | ||||||
|  |         self.transfer_inner(data, data).await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { |     pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { | ||||||
|         self.set_word_size(W::WORDSIZE); |         self.set_word_size(W::WORDSIZE); | ||||||
|         for word in words.iter() { |         for word in words.iter() { | ||||||
| @ -705,26 +727,7 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn spin_until_idle(regs: Regs) { | #[cfg(not(spi_v3))] | ||||||
|     #[cfg(any(spi_v1, spi_f1))] |  | ||||||
|     unsafe { |  | ||||||
|         while regs.sr().read().bsy() {} |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     #[cfg(spi_v2)] |  | ||||||
|     unsafe { |  | ||||||
|         while regs.sr().read().ftlvl() > 0 {} |  | ||||||
|         while regs.sr().read().frlvl() > 0 {} |  | ||||||
|         while regs.sr().read().bsy() {} |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     #[cfg(spi_v3)] |  | ||||||
|     unsafe { |  | ||||||
|         while !regs.sr().read().txc() {} |  | ||||||
|         while regs.sr().read().rxplvl().0 > 0 {} |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn flush_rx_fifo(regs: Regs) { | fn flush_rx_fifo(regs: Regs) { | ||||||
|     unsafe { |     unsafe { | ||||||
|         #[cfg(not(spi_v3))] |         #[cfg(not(spi_v3))] | ||||||
| @ -765,9 +768,15 @@ fn set_rxdmaen(regs: Regs, val: bool) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn finish_dma(regs: Regs) { | fn finish_dma(regs: Regs) { | ||||||
|     spin_until_idle(regs); |  | ||||||
| 
 |  | ||||||
|     unsafe { |     unsafe { | ||||||
|  |         #[cfg(spi_v2)] | ||||||
|  |         while regs.sr().read().ftlvl() > 0 {} | ||||||
|  | 
 | ||||||
|  |         #[cfg(spi_v3)] | ||||||
|  |         while !regs.sr().read().txc() {} | ||||||
|  |         #[cfg(not(spi_v3))] | ||||||
|  |         while regs.sr().read().bsy() {} | ||||||
|  | 
 | ||||||
|         regs.cr1().modify(|w| { |         regs.cr1().modify(|w| { | ||||||
|             w.set_spe(false); |             w.set_spe(false); | ||||||
|         }); |         }); | ||||||
| @ -935,9 +944,7 @@ cfg_if::cfg_if! { | |||||||
|                 &'a mut self, |                 &'a mut self, | ||||||
|                 words: &'a mut [W], |                 words: &'a mut [W], | ||||||
|             ) -> Self::TransferInPlaceFuture<'a> { |             ) -> Self::TransferInPlaceFuture<'a> { | ||||||
|                 // TODO: Implement async version
 |                 self.transfer_in_place(words) | ||||||
|                 let result = self.blocking_transfer_in_place(words); |  | ||||||
|                 async move { result } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -37,9 +37,30 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||||||
|     // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor.
 |     // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor.
 | ||||||
|     // so we should get the data we sent back.
 |     // so we should get the data we sent back.
 | ||||||
|     let mut buf = data; |     let mut buf = data; | ||||||
|  |     spi.blocking_transfer(&mut buf, &data).unwrap(); | ||||||
|  |     assert_eq!(buf, data); | ||||||
|  | 
 | ||||||
|     spi.blocking_transfer_in_place(&mut buf).unwrap(); |     spi.blocking_transfer_in_place(&mut buf).unwrap(); | ||||||
|     assert_eq!(buf, data); |     assert_eq!(buf, data); | ||||||
| 
 | 
 | ||||||
|  |     // Check read/write don't hang. We can't check they transfer the right data
 | ||||||
|  |     // without fancier test mechanisms.
 | ||||||
|  |     spi.blocking_write(&buf).unwrap(); | ||||||
|  |     spi.blocking_read(&mut buf).unwrap(); | ||||||
|  |     spi.blocking_write(&buf).unwrap(); | ||||||
|  |     spi.blocking_read(&mut buf).unwrap(); | ||||||
|  |     spi.blocking_write(&buf).unwrap(); | ||||||
|  | 
 | ||||||
|  |     // Check transfer doesn't break after having done a write, due to garbage in the FIFO
 | ||||||
|  |     spi.blocking_transfer(&mut buf, &data).unwrap(); | ||||||
|  |     assert_eq!(buf, data); | ||||||
|  | 
 | ||||||
|  |     // Check zero-length operations, these should be noops.
 | ||||||
|  |     spi.blocking_transfer::<u8>(&mut [], &[]).unwrap(); | ||||||
|  |     spi.blocking_transfer_in_place::<u8>(&mut []).unwrap(); | ||||||
|  |     spi.blocking_read::<u8>(&mut []).unwrap(); | ||||||
|  |     spi.blocking_write::<u8>(&[]).unwrap(); | ||||||
|  | 
 | ||||||
|     info!("Test OK"); |     info!("Test OK"); | ||||||
|     cortex_m::asm::bkpt(); |     cortex_m::asm::bkpt(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -47,6 +47,27 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||||||
|     spi.transfer(&mut buf, &data).await.unwrap(); |     spi.transfer(&mut buf, &data).await.unwrap(); | ||||||
|     assert_eq!(buf, data); |     assert_eq!(buf, data); | ||||||
| 
 | 
 | ||||||
|  |     spi.transfer_in_place(&mut buf).await.unwrap(); | ||||||
|  |     assert_eq!(buf, data); | ||||||
|  | 
 | ||||||
|  |     // Check read/write don't hang. We can't check they transfer the right data
 | ||||||
|  |     // without fancier test mechanisms.
 | ||||||
|  |     spi.write(&buf).await.unwrap(); | ||||||
|  |     spi.read(&mut buf).await.unwrap(); | ||||||
|  |     spi.write(&buf).await.unwrap(); | ||||||
|  |     spi.read(&mut buf).await.unwrap(); | ||||||
|  |     spi.write(&buf).await.unwrap(); | ||||||
|  | 
 | ||||||
|  |     // Check transfer doesn't break after having done a write, due to garbage in the FIFO
 | ||||||
|  |     spi.transfer(&mut buf, &data).await.unwrap(); | ||||||
|  |     assert_eq!(buf, data); | ||||||
|  | 
 | ||||||
|  |     // Check zero-length operations, these should be noops.
 | ||||||
|  |     spi.transfer::<u8>(&mut [], &[]).await.unwrap(); | ||||||
|  |     spi.transfer_in_place::<u8>(&mut []).await.unwrap(); | ||||||
|  |     spi.read::<u8>(&mut []).await.unwrap(); | ||||||
|  |     spi.write::<u8>(&[]).await.unwrap(); | ||||||
|  | 
 | ||||||
|     info!("Test OK"); |     info!("Test OK"); | ||||||
|     cortex_m::asm::bkpt(); |     cortex_m::asm::bkpt(); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user