aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-05-30 10:44:48 +0000
committerGitHub <[email protected]>2024-05-30 10:44:48 +0000
commit7532a06f67e7a4659317800fe13c6ea4a96cbab2 (patch)
tree4f67072ec6ce4e6dd236784b9c0aaa97f2925786
parente9cb9badf730032be0daa65fd725fa538fc92459 (diff)
parent4f76f6b9df72c10f039911d0e35ca504be750564 (diff)
Merge pull request #3007 from liarokapisv/spi_v3-fix-rx
Add proper rxonly support for spi_v3 and force tx dma stream requirem…
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/dma/util.rs1
-rw-r--r--embassy-stm32/src/i2s.rs12
-rw-r--r--embassy-stm32/src/spi/mod.rs106
-rw-r--r--tests/stm32/src/bin/spi_dma.rs65
5 files changed, 175 insertions, 13 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index fde5b4786..4f0d7356d 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -72,7 +72,7 @@ rand_core = "0.6.3"
72sdio-host = "0.5.0" 72sdio-host = "0.5.0"
73critical-section = "1.1" 73critical-section = "1.1"
74#stm32-metapac = { version = "15" } 74#stm32-metapac = { version = "15" }
75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318" } 75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad633a3e266151ea4d8fad630031a075ee02ab34" }
76 76
77vcell = "0.1.3" 77vcell = "0.1.3"
78nb = "1.0.0" 78nb = "1.0.0"
@@ -97,7 +97,7 @@ proc-macro2 = "1.0.36"
97quote = "1.0.15" 97quote = "1.0.15"
98 98
99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318", default-features = false, features = ["metadata"]} 100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad633a3e266151ea4d8fad630031a075ee02ab34", default-features = false, features = ["metadata"]}
101 101
102[features] 102[features]
103default = ["rt"] 103default = ["rt"]
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs
index 962ea2501..5aaca57c9 100644
--- a/embassy-stm32/src/dma/util.rs
+++ b/embassy-stm32/src/dma/util.rs
@@ -48,6 +48,7 @@ impl<'d> ChannelAndRequest<'d> {
48 Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options) 48 Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
49 } 49 }
50 50
51 #[allow(dead_code)]
51 pub unsafe fn write_repeated<'a, W: Word>( 52 pub unsafe fn write_repeated<'a, W: Word>(
52 &'a mut self, 53 &'a mut self,
53 repeated: &'a W, 54 repeated: &'a W,
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index c78810a38..9c0bbbb87 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -169,7 +169,7 @@ impl<'d> I2S<'d> {
169 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 169 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
170 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 170 ck: impl Peripheral<P = impl CkPin<T>> + 'd,
171 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 171 mck: impl Peripheral<P = impl MckPin<T>> + 'd,
172 txdma: impl Peripheral<P = impl TxDma<T>> + 'd, 172 #[cfg(not(spi_v3))] txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
173 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd, 173 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
174 freq: Hertz, 174 freq: Hertz,
175 config: Config, 175 config: Config,
@@ -190,7 +190,15 @@ impl<'d> I2S<'d> {
190 190
191 let mut spi_cfg = SpiConfig::default(); 191 let mut spi_cfg = SpiConfig::default();
192 spi_cfg.frequency = freq; 192 spi_cfg.frequency = freq;
193 let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg); 193 let spi = Spi::new_internal(
194 peri,
195 #[cfg(not(spi_v3))]
196 new_dma!(txdma),
197 #[cfg(spi_v3)]
198 None,
199 new_dma!(rxdma),
200 spi_cfg,
201 );
194 202
195 // TODO move i2s to the new mux infra. 203 // TODO move i2s to the new mux infra.
196 //#[cfg(all(rcc_f4, not(stm32f410)))] 204 //#[cfg(all(rcc_f4, not(stm32f410)))]
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 5fc8691ac..7fb8da5ac 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -508,6 +508,7 @@ impl<'d> Spi<'d, Async> {
508 peri: impl Peripheral<P = T> + 'd, 508 peri: impl Peripheral<P = T> + 'd,
509 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 509 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
510 miso: impl Peripheral<P = impl MisoPin<T>> + 'd, 510 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
511 #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
511 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 512 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
512 config: Config, 513 config: Config,
513 ) -> Self { 514 ) -> Self {
@@ -516,6 +517,9 @@ impl<'d> Spi<'d, Async> {
516 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()), 517 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
517 None, 518 None,
518 new_pin!(miso, AFType::Input, Speed::VeryHigh), 519 new_pin!(miso, AFType::Input, Speed::VeryHigh),
520 #[cfg(any(spi_v1, spi_f1, spi_v2))]
521 new_dma!(tx_dma),
522 #[cfg(any(spi_v3, spi_v4, spi_v5))]
519 None, 523 None,
520 new_dma!(rx_dma), 524 new_dma!(rx_dma),
521 config, 525 config,
@@ -584,11 +588,11 @@ impl<'d> Spi<'d, Async> {
584 #[allow(dead_code)] 588 #[allow(dead_code)]
585 pub(crate) fn new_internal<T: Instance>( 589 pub(crate) fn new_internal<T: Instance>(
586 peri: impl Peripheral<P = T> + 'd, 590 peri: impl Peripheral<P = T> + 'd,
587 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 591 tx_dma: Option<ChannelAndRequest<'d>>,
588 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 592 rx_dma: Option<ChannelAndRequest<'d>>,
589 config: Config, 593 config: Config,
590 ) -> Self { 594 ) -> Self {
591 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 595 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config)
592 } 596 }
593 597
594 /// SPI write, using DMA. 598 /// SPI write, using DMA.
@@ -622,12 +626,100 @@ impl<'d> Spi<'d, Async> {
622 } 626 }
623 627
624 /// SPI read, using DMA. 628 /// SPI read, using DMA.
629 #[cfg(any(spi_v3, spi_v4, spi_v5))]
630 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
631 if data.is_empty() {
632 return Ok(());
633 }
634
635 let regs = self.info.regs;
636
637 regs.cr1().modify(|w| {
638 w.set_spe(false);
639 });
640
641 let comm = regs.cfg2().modify(|w| {
642 let prev = w.comm();
643 w.set_comm(vals::Comm::RECEIVER);
644 prev
645 });
646
647 #[cfg(spi_v3)]
648 let i2scfg = regs.i2scfgr().modify(|w| {
649 w.i2smod().then(|| {
650 let prev = w.i2scfg();
651 w.set_i2scfg(match prev {
652 vals::I2scfg::SLAVERX | vals::I2scfg::SLAVEFULLDUPLEX => vals::I2scfg::SLAVERX,
653 vals::I2scfg::MASTERRX | vals::I2scfg::MASTERFULLDUPLEX => vals::I2scfg::MASTERRX,
654 _ => panic!("unsupported configuration"),
655 });
656 prev
657 })
658 });
659
660 let rx_src = regs.rx_ptr();
661
662 for mut chunk in data.chunks_mut(u16::max_value().into()) {
663 self.set_word_size(W::CONFIG);
664 set_rxdmaen(regs, true);
665
666 let tsize = chunk.len();
667
668 let transfer = unsafe {
669 self.rx_dma
670 .as_mut()
671 .unwrap()
672 .read(rx_src, &mut chunk, Default::default())
673 };
674
675 regs.cr2().modify(|w| {
676 w.set_tsize(tsize as u16);
677 });
678
679 regs.cr1().modify(|w| {
680 w.set_spe(true);
681 });
682
683 regs.cr1().modify(|w| {
684 w.set_cstart(true);
685 });
686
687 transfer.await;
688
689 finish_dma(regs);
690 }
691
692 regs.cr1().modify(|w| {
693 w.set_spe(false);
694 });
695
696 regs.cfg2().modify(|w| {
697 w.set_comm(comm);
698 });
699
700 regs.cr2().modify(|w| {
701 w.set_tsize(0);
702 });
703
704 #[cfg(spi_v3)]
705 if let Some(i2scfg) = i2scfg {
706 regs.i2scfgr().modify(|w| {
707 w.set_i2scfg(i2scfg);
708 });
709 }
710
711 Ok(())
712 }
713
714 /// SPI read, using DMA.
715 #[cfg(any(spi_v1, spi_f1, spi_v2))]
625 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 716 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
626 if data.is_empty() { 717 if data.is_empty() {
627 return Ok(()); 718 return Ok(());
628 } 719 }
629 720
630 self.set_word_size(W::CONFIG); 721 self.set_word_size(W::CONFIG);
722
631 self.info.regs.cr1().modify(|w| { 723 self.info.regs.cr1().modify(|w| {
632 w.set_spe(false); 724 w.set_spe(false);
633 }); 725 });
@@ -907,7 +999,13 @@ fn finish_dma(regs: Regs) {
907 while regs.sr().read().ftlvl().to_bits() > 0 {} 999 while regs.sr().read().ftlvl().to_bits() > 0 {}
908 1000
909 #[cfg(any(spi_v3, spi_v4, spi_v5))] 1001 #[cfg(any(spi_v3, spi_v4, spi_v5))]
910 while !regs.sr().read().txc() {} 1002 {
1003 if regs.cr2().read().tsize() == 0 {
1004 while !regs.sr().read().txc() {}
1005 } else {
1006 while !regs.sr().read().eot() {}
1007 }
1008 }
911 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 1009 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
912 while regs.sr().read().bsy() {} 1010 while regs.sr().read().bsy() {}
913 1011
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index 5d46726dd..30e679f2a 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -8,27 +8,33 @@ use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::spi::{self, Spi}; 9use embassy_stm32::spi::{self, Spi};
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::{into_ref, Peripheral as _};
11 12
12#[embassy_executor::main] 13#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(config()); 15 let p = embassy_stm32::init(config());
15 info!("Hello World!"); 16 info!("Hello World!");
16 17
17 let spi = peri!(p, SPI); 18 let spi_peri = peri!(p, SPI);
18 let sck = peri!(p, SPI_SCK); 19 let sck = peri!(p, SPI_SCK);
19 let mosi = peri!(p, SPI_MOSI); 20 let mosi = peri!(p, SPI_MOSI);
20 let miso = peri!(p, SPI_MISO); 21 let miso = peri!(p, SPI_MISO);
21 let tx_dma = peri!(p, SPI_TX_DMA); 22 let tx_dma = peri!(p, SPI_TX_DMA);
22 let rx_dma = peri!(p, SPI_RX_DMA); 23 let rx_dma = peri!(p, SPI_RX_DMA);
23 24
25 into_ref!(spi_peri, sck, mosi, miso, tx_dma, rx_dma);
26
24 let mut spi_config = spi::Config::default(); 27 let mut spi_config = spi::Config::default();
25 spi_config.frequency = Hertz(1_000_000); 28 spi_config.frequency = Hertz(1_000_000);
26 29
27 let mut spi = Spi::new( 30 let mut spi = Spi::new(
28 spi, sck, // Arduino D13 31 spi_peri.reborrow(),
29 mosi, // Arduino D11 32 sck.reborrow(), // Arduino D13
30 miso, // Arduino D12 33 mosi.reborrow(), // Arduino D11
31 tx_dma, rx_dma, spi_config, 34 miso.reborrow(), // Arduino D12
35 tx_dma.reborrow(),
36 rx_dma.reborrow(),
37 spi_config,
32 ); 38 );
33 39
34 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 40 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
@@ -76,6 +82,55 @@ async fn main(_spawner: Spawner) {
76 spi.blocking_read(&mut buf).unwrap(); 82 spi.blocking_read(&mut buf).unwrap();
77 spi.write(&buf).await.unwrap(); 83 spi.write(&buf).await.unwrap();
78 84
85 core::mem::drop(spi);
86
87 // test rx-only configuration
88
89 // stm32f207zg - spi_v1
90 // stm32f103c8 - spi_f1
91 // stm32g491re - spi_v2
92 // stm32h753zi - spi_v3
93 // stm32h563zi - spi_v4
94 // stm32wba52cg - spi_v5
95
96 #[cfg(any(stm32f207zg, stm32f103c8, stm32g491re, stm32h753zi, stm32h563zi, stm32wba52cg))]
97 {
98 let mut spi = {
99 #[cfg(stm32f207zg, stm32f103c8, stm32g491re)]
100 {
101 Spi::new_rxonly(
102 spi_peri.reborrow(),
103 sck.reborrow(),
104 miso.reborrow(),
105 tx_dma.reborrow(),
106 rx_dma.reborrow(),
107 spi_config,
108 )
109 }
110 #[cfg(stm32h753zi, stm32h563zi, stm32wba52cg)]
111 {
112 Spi::new_rxonly(
113 spi_peri.reborrow(),
114 sck.reborrow(),
115 miso.reborrow(),
116 rx_dma.reborrow(),
117 spi_config,
118 )
119 }
120 };
121
122 use embassy_stm32::gpio;
123 let mut mosi = gpio::Output::new(mosi.reborrow(), gpio::Level::Low, gpio::Speed::Low);
124
125 mosi.set_high();
126 spi.read(&mut buf).await.unwrap();
127 assert_eq!(buf, [0xff; 9]);
128
129 mosi.set_low();
130 spi.read(&mut buf).await.unwrap();
131 assert_eq!(buf, [0x00; 9]);
132 };
133
79 info!("Test OK"); 134 info!("Test OK");
80 cortex_m::asm::bkpt(); 135 cortex_m::asm::bkpt();
81} 136}