diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-03-15 01:39:38 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-03-15 01:39:38 +0000 |
| commit | ff1215c6f9295d960c5111d30f27ca047605414d (patch) | |
| tree | cf065e87589733f37d7c15c99d20b5e9132cd4c4 | |
| parent | 8ef8ab170766051be22cc93ec0359f1f95dc6027 (diff) | |
| parent | 059b16423458a80c5cb4e1630260d6c564a88e84 (diff) | |
Merge #664
664: stm32: more spi fixes r=Dirbaio a=Dirbaio
Co-authored-by: Dario Nieuwenhuis <[email protected]>
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 77 | ||||
| -rw-r--r-- | tests/stm32/src/bin/spi.rs | 21 | ||||
| -rw-r--r-- | tests/stm32/src/bin/spi_dma.rs | 21 |
3 files changed, 84 insertions, 35 deletions
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 5271d941c..d8ffabb11 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -7,7 +7,7 @@ use embassy_hal_common::unborrow; | |||
| 7 | use futures::future::join; | 7 | use futures::future::join; |
| 8 | 8 | ||
| 9 | use self::sealed::WordSize; | 9 | use self::sealed::WordSize; |
| 10 | use crate::dma::{NoDma, Transfer}; | 10 | use crate::dma::{slice_ptr_parts, NoDma, Transfer}; |
| 11 | use crate::gpio::sealed::{AFType, Pin as _}; | 11 | use crate::gpio::sealed::{AFType, Pin as _}; |
| 12 | use crate::gpio::AnyPin; | 12 | use crate::gpio::AnyPin; |
| 13 | use crate::pac::spi::Spi as Regs; | 13 | use crate::pac::spi::Spi as Regs; |
| @@ -440,9 +440,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 440 | 440 | ||
| 441 | tx_f.await; | 441 | tx_f.await; |
| 442 | 442 | ||
| 443 | // flush here otherwise `finish_dma` hangs waiting for the rx fifo to empty | ||
| 444 | flush_rx_fifo(T::REGS); | ||
| 445 | |||
| 446 | finish_dma(T::REGS); | 443 | finish_dma(T::REGS); |
| 447 | 444 | ||
| 448 | Ok(()) | 445 | Ok(()) |
| @@ -465,6 +462,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 465 | set_rxdmaen(T::REGS, true); | 462 | set_rxdmaen(T::REGS, true); |
| 466 | } | 463 | } |
| 467 | 464 | ||
| 465 | // SPIv3 clears rxfifo on SPE=0 | ||
| 466 | #[cfg(not(spi_v3))] | ||
| 467 | flush_rx_fifo(T::REGS); | ||
| 468 | |||
| 468 | let clock_byte_count = data.len(); | 469 | let clock_byte_count = data.len(); |
| 469 | 470 | ||
| 470 | let rx_request = self.rxdma.request(); | 471 | let rx_request = self.rxdma.request(); |
| @@ -501,14 +502,19 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 501 | Ok(()) | 502 | Ok(()) |
| 502 | } | 503 | } |
| 503 | 504 | ||
| 504 | pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> | 505 | async fn transfer_inner<W: Word>( |
| 506 | &mut self, | ||
| 507 | read: *mut [W], | ||
| 508 | write: *const [W], | ||
| 509 | ) -> Result<(), Error> | ||
| 505 | where | 510 | where |
| 506 | Tx: TxDma<T>, | 511 | Tx: TxDma<T>, |
| 507 | Rx: RxDma<T>, | 512 | Rx: RxDma<T>, |
| 508 | { | 513 | { |
| 509 | assert_eq!(read.len(), write.len()); | 514 | let (_, rx_len) = slice_ptr_parts(read); |
| 510 | 515 | let (_, tx_len) = slice_ptr_parts(write); | |
| 511 | if read.len() == 0 { | 516 | assert_eq!(rx_len, tx_len); |
| 517 | if rx_len == 0 { | ||
| 512 | return Ok(()); | 518 | return Ok(()); |
| 513 | } | 519 | } |
| 514 | 520 | ||
| @@ -520,8 +526,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 520 | set_rxdmaen(T::REGS, true); | 526 | set_rxdmaen(T::REGS, true); |
| 521 | } | 527 | } |
| 522 | 528 | ||
| 523 | // TODO: This is unnecessary in some versions because | 529 | // SPIv3 clears rxfifo on SPE=0 |
| 524 | // clearing SPE automatically clears the fifos | 530 | #[cfg(not(spi_v3))] |
| 525 | flush_rx_fifo(T::REGS); | 531 | flush_rx_fifo(T::REGS); |
| 526 | 532 | ||
| 527 | let rx_request = self.rxdma.request(); | 533 | let rx_request = self.rxdma.request(); |
| @@ -552,6 +558,22 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 552 | Ok(()) | 558 | Ok(()) |
| 553 | } | 559 | } |
| 554 | 560 | ||
| 561 | pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> | ||
| 562 | where | ||
| 563 | Tx: TxDma<T>, | ||
| 564 | Rx: RxDma<T>, | ||
| 565 | { | ||
| 566 | self.transfer_inner(read, write).await | ||
| 567 | } | ||
| 568 | |||
| 569 | pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> | ||
| 570 | where | ||
| 571 | Tx: TxDma<T>, | ||
| 572 | Rx: RxDma<T>, | ||
| 573 | { | ||
| 574 | self.transfer_inner(data, data).await | ||
| 575 | } | ||
| 576 | |||
| 555 | pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { | 577 | pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { |
| 556 | self.set_word_size(W::WORDSIZE); | 578 | self.set_word_size(W::WORDSIZE); |
| 557 | for word in words.iter() { | 579 | for word in words.iter() { |
| @@ -705,26 +727,7 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { | |||
| 705 | } | 727 | } |
| 706 | } | 728 | } |
| 707 | 729 | ||
| 708 | fn spin_until_idle(regs: Regs) { | 730 | #[cfg(not(spi_v3))] |
| 709 | #[cfg(any(spi_v1, spi_f1))] | ||
| 710 | unsafe { | ||
| 711 | while regs.sr().read().bsy() {} | ||
| 712 | } | ||
| 713 | |||
| 714 | #[cfg(spi_v2)] | ||
| 715 | unsafe { | ||
| 716 | while regs.sr().read().ftlvl() > 0 {} | ||
| 717 | while regs.sr().read().frlvl() > 0 {} | ||
| 718 | while regs.sr().read().bsy() {} | ||
| 719 | } | ||
| 720 | |||
| 721 | #[cfg(spi_v3)] | ||
| 722 | unsafe { | ||
| 723 | while !regs.sr().read().txc() {} | ||
| 724 | while regs.sr().read().rxplvl().0 > 0 {} | ||
| 725 | } | ||
| 726 | } | ||
| 727 | |||
| 728 | fn flush_rx_fifo(regs: Regs) { | 731 | fn flush_rx_fifo(regs: Regs) { |
| 729 | unsafe { | 732 | unsafe { |
| 730 | #[cfg(not(spi_v3))] | 733 | #[cfg(not(spi_v3))] |
| @@ -765,9 +768,15 @@ fn set_rxdmaen(regs: Regs, val: bool) { | |||
| 765 | } | 768 | } |
| 766 | 769 | ||
| 767 | fn finish_dma(regs: Regs) { | 770 | fn finish_dma(regs: Regs) { |
| 768 | spin_until_idle(regs); | ||
| 769 | |||
| 770 | unsafe { | 771 | unsafe { |
| 772 | #[cfg(spi_v2)] | ||
| 773 | while regs.sr().read().ftlvl() > 0 {} | ||
| 774 | |||
| 775 | #[cfg(spi_v3)] | ||
| 776 | while !regs.sr().read().txc() {} | ||
| 777 | #[cfg(not(spi_v3))] | ||
| 778 | while regs.sr().read().bsy() {} | ||
| 779 | |||
| 771 | regs.cr1().modify(|w| { | 780 | regs.cr1().modify(|w| { |
| 772 | w.set_spe(false); | 781 | w.set_spe(false); |
| 773 | }); | 782 | }); |
| @@ -935,9 +944,7 @@ cfg_if::cfg_if! { | |||
| 935 | &'a mut self, | 944 | &'a mut self, |
| 936 | words: &'a mut [W], | 945 | words: &'a mut [W], |
| 937 | ) -> Self::TransferInPlaceFuture<'a> { | 946 | ) -> Self::TransferInPlaceFuture<'a> { |
| 938 | // TODO: Implement async version | 947 | self.transfer_in_place(words) |
| 939 | let result = self.blocking_transfer_in_place(words); | ||
| 940 | async move { result } | ||
| 941 | } | 948 | } |
| 942 | } | 949 | } |
| 943 | } | 950 | } |
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index 47d0017ac..b079472d5 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs | |||
| @@ -37,9 +37,30 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 37 | // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. | 37 | // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. |
| 38 | // so we should get the data we sent back. | 38 | // so we should get the data we sent back. |
| 39 | let mut buf = data; | 39 | let mut buf = data; |
| 40 | spi.blocking_transfer(&mut buf, &data).unwrap(); | ||
| 41 | assert_eq!(buf, data); | ||
| 42 | |||
| 40 | spi.blocking_transfer_in_place(&mut buf).unwrap(); | 43 | spi.blocking_transfer_in_place(&mut buf).unwrap(); |
| 41 | assert_eq!(buf, data); | 44 | assert_eq!(buf, data); |
| 42 | 45 | ||
| 46 | // Check read/write don't hang. We can't check they transfer the right data | ||
| 47 | // without fancier test mechanisms. | ||
| 48 | spi.blocking_write(&buf).unwrap(); | ||
| 49 | spi.blocking_read(&mut buf).unwrap(); | ||
| 50 | spi.blocking_write(&buf).unwrap(); | ||
| 51 | spi.blocking_read(&mut buf).unwrap(); | ||
| 52 | spi.blocking_write(&buf).unwrap(); | ||
| 53 | |||
| 54 | // Check transfer doesn't break after having done a write, due to garbage in the FIFO | ||
| 55 | spi.blocking_transfer(&mut buf, &data).unwrap(); | ||
| 56 | assert_eq!(buf, data); | ||
| 57 | |||
| 58 | // Check zero-length operations, these should be noops. | ||
| 59 | spi.blocking_transfer::<u8>(&mut [], &[]).unwrap(); | ||
| 60 | spi.blocking_transfer_in_place::<u8>(&mut []).unwrap(); | ||
| 61 | spi.blocking_read::<u8>(&mut []).unwrap(); | ||
| 62 | spi.blocking_write::<u8>(&[]).unwrap(); | ||
| 63 | |||
| 43 | info!("Test OK"); | 64 | info!("Test OK"); |
| 44 | cortex_m::asm::bkpt(); | 65 | cortex_m::asm::bkpt(); |
| 45 | } | 66 | } |
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index 59a5bcd0c..3e9521ae7 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs | |||
| @@ -47,6 +47,27 @@ async fn main(_spawner: Spawner, p: Peripherals) { | |||
| 47 | spi.transfer(&mut buf, &data).await.unwrap(); | 47 | spi.transfer(&mut buf, &data).await.unwrap(); |
| 48 | assert_eq!(buf, data); | 48 | assert_eq!(buf, data); |
| 49 | 49 | ||
| 50 | spi.transfer_in_place(&mut buf).await.unwrap(); | ||
| 51 | assert_eq!(buf, data); | ||
| 52 | |||
| 53 | // Check read/write don't hang. We can't check they transfer the right data | ||
| 54 | // without fancier test mechanisms. | ||
| 55 | spi.write(&buf).await.unwrap(); | ||
| 56 | spi.read(&mut buf).await.unwrap(); | ||
| 57 | spi.write(&buf).await.unwrap(); | ||
| 58 | spi.read(&mut buf).await.unwrap(); | ||
| 59 | spi.write(&buf).await.unwrap(); | ||
| 60 | |||
| 61 | // Check transfer doesn't break after having done a write, due to garbage in the FIFO | ||
| 62 | spi.transfer(&mut buf, &data).await.unwrap(); | ||
| 63 | assert_eq!(buf, data); | ||
| 64 | |||
| 65 | // Check zero-length operations, these should be noops. | ||
| 66 | spi.transfer::<u8>(&mut [], &[]).await.unwrap(); | ||
| 67 | spi.transfer_in_place::<u8>(&mut []).await.unwrap(); | ||
| 68 | spi.read::<u8>(&mut []).await.unwrap(); | ||
| 69 | spi.write::<u8>(&[]).await.unwrap(); | ||
| 70 | |||
| 50 | info!("Test OK"); | 71 | info!("Test OK"); |
| 51 | cortex_m::asm::bkpt(); | 72 | cortex_m::asm::bkpt(); |
| 52 | } | 73 | } |
