aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-09-23 00:17:08 +0000
committerGitHub <[email protected]>2024-09-23 00:17:08 +0000
commite70b7099f186d43e12958ea0f4791a326338007d (patch)
tree1becfe2d2571f8618ff7986fa16c96c42363c33a
parent9705f3332b7d858aee94903ce433fba93d62332c (diff)
parenta71098d824346a25ab9fb376627c0383d0f9250a (diff)
Merge pull request #3363 from embassy-rs/spi-word-tests
stm32/spi: fix non-u8 word sizes, add tests.
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/dma/gpdma.rs14
-rw-r--r--embassy-stm32/src/spi/mod.rs72
-rw-r--r--tests/stm32/src/bin/spi.rs98
-rw-r--r--tests/stm32/src/bin/spi_dma.rs116
5 files changed, 174 insertions, 130 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 575c4f20c..8fc8da006 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-acaf04256034066bd5b3a8426224ccf3e4cb7d19" } 75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9b7414490b10ffbd5beb1b0dcf14adb018cbe37f" }
76 76
77vcell = "0.1.3" 77vcell = "0.1.3"
78nb = "1.0.0" 78nb = "1.0.0"
@@ -99,7 +99,7 @@ proc-macro2 = "1.0.36"
99quote = "1.0.15" 99quote = "1.0.15"
100 100
101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-acaf04256034066bd5b3a8426224ccf3e4cb7d19", default-features = false, features = ["metadata"] } 102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9b7414490b10ffbd5beb1b0dcf14adb018cbe37f", default-features = false, features = ["metadata"] }
103 103
104[features] 104[features]
105default = ["rt"] 105default = ["rt"]
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index f9d66ca86..a877bb8d4 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -216,7 +216,10 @@ impl<'a> Transfer<'a> {
216 data_size: WordSize, 216 data_size: WordSize,
217 _options: TransferOptions, 217 _options: TransferOptions,
218 ) -> Self { 218 ) -> Self {
219 assert!(mem_len > 0 && mem_len <= 0xFFFF); 219 // BNDT is specified as bytes, not as number of transfers.
220 let Ok(bndt) = (mem_len * data_size.bytes()).try_into() else {
221 panic!("DMA transfers may not be larger than 65535 bytes.");
222 };
220 223
221 let info = channel.info(); 224 let info = channel.info();
222 let ch = info.dma.ch(info.num); 225 let ch = info.dma.ch(info.num);
@@ -226,9 +229,6 @@ impl<'a> Transfer<'a> {
226 229
227 let this = Self { channel }; 230 let this = Self { channel };
228 231
229 #[cfg(dmamux)]
230 super::dmamux::configure_dmamux(&*this.channel, request);
231
232 ch.cr().write(|w| w.set_reset(true)); 232 ch.cr().write(|w| w.set_reset(true));
233 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs 233 ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs
234 ch.llr().write(|_| {}); // no linked list 234 ch.llr().write(|_| {}); // no linked list
@@ -245,10 +245,8 @@ impl<'a> Transfer<'a> {
245 }); 245 });
246 w.set_reqsel(request); 246 w.set_reqsel(request);
247 }); 247 });
248 ch.br1().write(|w| { 248 ch.tr3().write(|_| {}); // no address offsets.
249 // BNDT is specified as bytes, not as number of transfers. 249 ch.br1().write(|w| w.set_bndt(bndt));
250 w.set_bndt((mem_len * data_size.bytes()) as u16)
251 });
252 250
253 match dir { 251 match dir {
254 Dir::MemoryToPeripheral => { 252 Dir::MemoryToPeripheral => {
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index dfac4bc89..d034c028e 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -311,51 +311,29 @@ impl<'d, M: PeriMode> Spi<'d, M> {
311 } 311 }
312 } 312 }
313 313
314 /// Set SPI word size. Disables SPI if needed, you have to enable it back yourself.
314 fn set_word_size(&mut self, word_size: word_impl::Config) { 315 fn set_word_size(&mut self, word_size: word_impl::Config) {
315 if self.current_word_size == word_size { 316 if self.current_word_size == word_size {
316 return; 317 return;
317 } 318 }
318 319
320 self.info.regs.cr1().modify(|w| {
321 w.set_spe(false);
322 });
323
319 #[cfg(any(spi_v1, spi_f1))] 324 #[cfg(any(spi_v1, spi_f1))]
320 { 325 self.info.regs.cr1().modify(|reg| {
321 self.info.regs.cr1().modify(|reg| { 326 reg.set_dff(word_size);
322 reg.set_spe(false); 327 });
323 reg.set_dff(word_size)
324 });
325 self.info.regs.cr1().modify(|reg| {
326 reg.set_spe(true);
327 });
328 }
329 #[cfg(spi_v2)] 328 #[cfg(spi_v2)]
330 { 329 self.info.regs.cr2().modify(|w| {
331 self.info.regs.cr1().modify(|w| { 330 w.set_frxth(word_size.1);
332 w.set_spe(false); 331 w.set_ds(word_size.0);
333 }); 332 });
334 self.info.regs.cr2().modify(|w| {
335 w.set_frxth(word_size.1);
336 w.set_ds(word_size.0);
337 });
338 self.info.regs.cr1().modify(|w| {
339 w.set_spe(true);
340 });
341 }
342 #[cfg(any(spi_v3, spi_v4, spi_v5))] 333 #[cfg(any(spi_v3, spi_v4, spi_v5))]
343 { 334 self.info.regs.cfg1().modify(|w| {
344 self.info.regs.cr1().modify(|w| { 335 w.set_dsize(word_size);
345 w.set_csusp(true); 336 });
346 });
347 while self.info.regs.sr().read().eot() {}
348 self.info.regs.cr1().modify(|w| {
349 w.set_spe(false);
350 });
351 self.info.regs.cfg1().modify(|w| {
352 w.set_dsize(word_size);
353 });
354 self.info.regs.cr1().modify(|w| {
355 w.set_csusp(false);
356 w.set_spe(true);
357 });
358 }
359 337
360 self.current_word_size = word_size; 338 self.current_word_size = word_size;
361 } 339 }
@@ -365,9 +343,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
365 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 343 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
366 #[cfg(any(spi_v3, spi_v4, spi_v5))] 344 #[cfg(any(spi_v3, spi_v4, spi_v5))]
367 self.info.regs.cr1().modify(|w| w.set_spe(false)); 345 self.info.regs.cr1().modify(|w| w.set_spe(false));
346 self.set_word_size(W::CONFIG);
368 self.info.regs.cr1().modify(|w| w.set_spe(true)); 347 self.info.regs.cr1().modify(|w| w.set_spe(true));
369 flush_rx_fifo(self.info.regs); 348 flush_rx_fifo(self.info.regs);
370 self.set_word_size(W::CONFIG);
371 for word in words.iter() { 349 for word in words.iter() {
372 // this cannot use `transfer_word` because on SPIv2 and higher, 350 // this cannot use `transfer_word` because on SPIv2 and higher,
373 // the SPI RX state machine hangs if no physical pin is connected to the SCK AF. 351 // the SPI RX state machine hangs if no physical pin is connected to the SCK AF.
@@ -402,9 +380,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
402 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 380 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
403 #[cfg(any(spi_v3, spi_v4, spi_v5))] 381 #[cfg(any(spi_v3, spi_v4, spi_v5))]
404 self.info.regs.cr1().modify(|w| w.set_spe(false)); 382 self.info.regs.cr1().modify(|w| w.set_spe(false));
383 self.set_word_size(W::CONFIG);
405 self.info.regs.cr1().modify(|w| w.set_spe(true)); 384 self.info.regs.cr1().modify(|w| w.set_spe(true));
406 flush_rx_fifo(self.info.regs); 385 flush_rx_fifo(self.info.regs);
407 self.set_word_size(W::CONFIG);
408 for word in words.iter_mut() { 386 for word in words.iter_mut() {
409 *word = transfer_word(self.info.regs, W::default())?; 387 *word = transfer_word(self.info.regs, W::default())?;
410 } 388 }
@@ -418,9 +396,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
418 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 396 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
419 #[cfg(any(spi_v3, spi_v4, spi_v5))] 397 #[cfg(any(spi_v3, spi_v4, spi_v5))]
420 self.info.regs.cr1().modify(|w| w.set_spe(false)); 398 self.info.regs.cr1().modify(|w| w.set_spe(false));
399 self.set_word_size(W::CONFIG);
421 self.info.regs.cr1().modify(|w| w.set_spe(true)); 400 self.info.regs.cr1().modify(|w| w.set_spe(true));
422 flush_rx_fifo(self.info.regs); 401 flush_rx_fifo(self.info.regs);
423 self.set_word_size(W::CONFIG);
424 for word in words.iter_mut() { 402 for word in words.iter_mut() {
425 *word = transfer_word(self.info.regs, *word)?; 403 *word = transfer_word(self.info.regs, *word)?;
426 } 404 }
@@ -437,9 +415,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
437 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? 415 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
438 #[cfg(any(spi_v3, spi_v4, spi_v5))] 416 #[cfg(any(spi_v3, spi_v4, spi_v5))]
439 self.info.regs.cr1().modify(|w| w.set_spe(false)); 417 self.info.regs.cr1().modify(|w| w.set_spe(false));
418 self.set_word_size(W::CONFIG);
440 self.info.regs.cr1().modify(|w| w.set_spe(true)); 419 self.info.regs.cr1().modify(|w| w.set_spe(true));
441 flush_rx_fifo(self.info.regs); 420 flush_rx_fifo(self.info.regs);
442 self.set_word_size(W::CONFIG);
443 let len = read.len().max(write.len()); 421 let len = read.len().max(write.len());
444 for i in 0..len { 422 for i in 0..len {
445 let wb = write.get(i).copied().unwrap_or_default(); 423 let wb = write.get(i).copied().unwrap_or_default();
@@ -648,10 +626,10 @@ impl<'d> Spi<'d, Async> {
648 return Ok(()); 626 return Ok(());
649 } 627 }
650 628
651 self.set_word_size(W::CONFIG);
652 self.info.regs.cr1().modify(|w| { 629 self.info.regs.cr1().modify(|w| {
653 w.set_spe(false); 630 w.set_spe(false);
654 }); 631 });
632 self.set_word_size(W::CONFIG);
655 633
656 let tx_dst = self.info.regs.tx_ptr(); 634 let tx_dst = self.info.regs.tx_ptr();
657 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) }; 635 let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
@@ -685,6 +663,8 @@ impl<'d> Spi<'d, Async> {
685 w.set_spe(false); 663 w.set_spe(false);
686 }); 664 });
687 665
666 self.set_word_size(W::CONFIG);
667
688 let comm = regs.cfg2().modify(|w| { 668 let comm = regs.cfg2().modify(|w| {
689 let prev = w.comm(); 669 let prev = w.comm();
690 w.set_comm(vals::Comm::RECEIVER); 670 w.set_comm(vals::Comm::RECEIVER);
@@ -707,7 +687,6 @@ impl<'d> Spi<'d, Async> {
707 let rx_src = regs.rx_ptr(); 687 let rx_src = regs.rx_ptr();
708 688
709 for mut chunk in data.chunks_mut(u16::max_value().into()) { 689 for mut chunk in data.chunks_mut(u16::max_value().into()) {
710 self.set_word_size(W::CONFIG);
711 set_rxdmaen(regs, true); 690 set_rxdmaen(regs, true);
712 691
713 let tsize = chunk.len(); 692 let tsize = chunk.len();
@@ -765,12 +744,12 @@ impl<'d> Spi<'d, Async> {
765 return Ok(()); 744 return Ok(());
766 } 745 }
767 746
768 self.set_word_size(W::CONFIG);
769
770 self.info.regs.cr1().modify(|w| { 747 self.info.regs.cr1().modify(|w| {
771 w.set_spe(false); 748 w.set_spe(false);
772 }); 749 });
773 750
751 self.set_word_size(W::CONFIG);
752
774 // SPIv3 clears rxfifo on SPE=0 753 // SPIv3 clears rxfifo on SPE=0
775 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 754 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
776 flush_rx_fifo(self.info.regs); 755 flush_rx_fifo(self.info.regs);
@@ -813,11 +792,12 @@ impl<'d> Spi<'d, Async> {
813 return Ok(()); 792 return Ok(());
814 } 793 }
815 794
816 self.set_word_size(W::CONFIG);
817 self.info.regs.cr1().modify(|w| { 795 self.info.regs.cr1().modify(|w| {
818 w.set_spe(false); 796 w.set_spe(false);
819 }); 797 });
820 798
799 self.set_word_size(W::CONFIG);
800
821 // SPIv3 clears rxfifo on SPE=0 801 // SPIv3 clears rxfifo on SPE=0
822 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 802 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
823 flush_rx_fifo(self.info.regs); 803 flush_rx_fifo(self.info.regs);
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index 53d44a94a..9712a8c5a 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -7,7 +7,8 @@ use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::spi::{self, Spi}; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::spi::{self, Spi, Word};
11use embassy_stm32::time::Hertz; 12use embassy_stm32::time::Hertz;
12 13
13#[embassy_executor::main] 14#[embassy_executor::main]
@@ -31,11 +32,58 @@ async fn main(_spawner: Spawner) {
31 spi_config, 32 spi_config,
32 ); 33 );
33 34
34 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 35 test_txrx::<u8>(&mut spi);
36 test_txrx::<u16>(&mut spi);
37
38 // Assert the RCC bit gets disabled on drop.
39 #[cfg(feature = "stm32f429zi")]
40 defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en());
41 drop(spi);
42 #[cfg(feature = "stm32f429zi")]
43 defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en());
44
45 // test rx-only configuration
46 let mut spi = Spi::new_blocking_rxonly(&mut spi_peri, &mut sck, &mut miso, spi_config);
47 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
48
49 test_rx::<u8>(&mut spi, &mut mosi_out);
50 test_rx::<u16>(&mut spi, &mut mosi_out);
51 drop(spi);
52 drop(mosi_out);
53
54 let mut spi = Spi::new_blocking_txonly(&mut spi_peri, &mut sck, &mut mosi, spi_config);
55 test_tx::<u8>(&mut spi);
56 test_tx::<u16>(&mut spi);
57 drop(spi);
58
59 let mut spi = Spi::new_blocking_txonly_nosck(&mut spi_peri, &mut mosi, spi_config);
60 test_tx::<u8>(&mut spi);
61 test_tx::<u16>(&mut spi);
62 drop(spi);
63
64 info!("Test OK");
65 cortex_m::asm::bkpt();
66}
67
68fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>)
69where
70 W: core::ops::Not<Output = W>,
71{
72 let data: [W; 9] = [
73 0x00u8.into(),
74 0xFFu8.into(),
75 0xAAu8.into(),
76 0x55u8.into(),
77 0xC0u8.into(),
78 0xFFu8.into(),
79 0xEEu8.into(),
80 0xC0u8.into(),
81 0xDEu8.into(),
82 ];
35 83
36 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. 84 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor.
37 // so we should get the data we sent back. 85 // so we should get the data we sent back.
38 let mut buf = [0; 9]; 86 let mut buf = [W::default(); 9];
39 spi.blocking_transfer(&mut buf, &data).unwrap(); 87 spi.blocking_transfer(&mut buf, &data).unwrap();
40 assert_eq!(buf, data); 88 assert_eq!(buf, data);
41 89
@@ -59,47 +107,33 @@ async fn main(_spawner: Spawner) {
59 spi.blocking_transfer_in_place::<u8>(&mut []).unwrap(); 107 spi.blocking_transfer_in_place::<u8>(&mut []).unwrap();
60 spi.blocking_read::<u8>(&mut []).unwrap(); 108 spi.blocking_read::<u8>(&mut []).unwrap();
61 spi.blocking_write::<u8>(&[]).unwrap(); 109 spi.blocking_write::<u8>(&[]).unwrap();
110}
62 111
63 // Assert the RCC bit gets disabled on drop. 112fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>, mosi_out: &mut Output<'_>)
64 #[cfg(feature = "stm32f429zi")] 113where
65 defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en()); 114 W: core::ops::Not<Output = W>,
66 drop(spi); 115{
67 #[cfg(feature = "stm32f429zi")] 116 let mut buf = [W::default(); 9];
68 defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en());
69 117
70 // test rx-only configuration
71 let mut spi = Spi::new_blocking_rxonly(&mut spi_peri, &mut sck, &mut miso, spi_config);
72 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
73 mosi_out.set_high(); 118 mosi_out.set_high();
74 spi.blocking_read(&mut buf).unwrap(); 119 spi.blocking_read(&mut buf).unwrap();
75 assert_eq!(buf, [0xff; 9]); 120 assert_eq!(buf, [!W::default(); 9]);
76 mosi_out.set_low(); 121 mosi_out.set_low();
77 spi.blocking_read(&mut buf).unwrap(); 122 spi.blocking_read(&mut buf).unwrap();
78 assert_eq!(buf, [0x00; 9]); 123 assert_eq!(buf, [W::default(); 9]);
79 spi.blocking_read::<u8>(&mut []).unwrap(); 124 spi.blocking_read::<u8>(&mut []).unwrap();
80 spi.blocking_read::<u8>(&mut []).unwrap(); 125 spi.blocking_read::<u8>(&mut []).unwrap();
81 drop(mosi_out); 126}
82 drop(spi); 127
128fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>)
129where
130 W: core::ops::Not<Output = W>,
131{
132 let buf = [W::default(); 9];
83 133
84 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave. 134 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave.
85 let mut spi = Spi::new_blocking_txonly(&mut spi_peri, &mut sck, &mut mosi, spi_config);
86 spi.blocking_transfer(&mut buf, &data).unwrap();
87 spi.blocking_transfer_in_place(&mut buf).unwrap();
88 spi.blocking_write(&buf).unwrap(); 135 spi.blocking_write(&buf).unwrap();
89 spi.blocking_read(&mut buf).unwrap();
90 spi.blocking_transfer::<u8>(&mut [], &[]).unwrap();
91 spi.blocking_transfer_in_place::<u8>(&mut []).unwrap();
92 spi.blocking_read::<u8>(&mut []).unwrap();
93 spi.blocking_write::<u8>(&[]).unwrap(); 136 spi.blocking_write::<u8>(&[]).unwrap();
94 drop(spi);
95
96 // Test tx-only nosck.
97 let mut spi = Spi::new_blocking_txonly_nosck(&mut spi_peri, &mut mosi, spi_config);
98 spi.blocking_write(&buf).unwrap(); 137 spi.blocking_write(&buf).unwrap();
99 spi.blocking_write::<u8>(&[]).unwrap(); 138 spi.blocking_write::<u8>(&[]).unwrap();
100 spi.blocking_write(&buf).unwrap();
101 drop(spi);
102
103 info!("Test OK");
104 cortex_m::asm::bkpt();
105} 139}
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index a1cbc0ed1..307409a16 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -7,7 +7,8 @@ use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::spi::{self, Spi}; 10use embassy_stm32::mode::Async;
11use embassy_stm32::spi::{self, Spi, Word};
11use embassy_stm32::time::Hertz; 12use embassy_stm32::time::Hertz;
12 13
13#[embassy_executor::main] 14#[embassy_executor::main]
@@ -35,11 +36,61 @@ async fn main(_spawner: Spawner) {
35 spi_config, 36 spi_config,
36 ); 37 );
37 38
38 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 39 test_txrx::<u8>(&mut spi).await;
40 test_txrx::<u16>(&mut spi).await;
41 drop(spi);
42
43 // test rx-only configuration
44 let mut spi = Spi::new_rxonly(
45 &mut spi_peri,
46 &mut sck,
47 &mut miso,
48 // SPIv1/f1 requires txdma even if rxonly.
49 #[cfg(not(feature = "spi-v345"))]
50 &mut tx_dma,
51 &mut rx_dma,
52 spi_config,
53 );
54 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
55
56 test_rx::<u8>(&mut spi, &mut mosi_out).await;
57 test_rx::<u16>(&mut spi, &mut mosi_out).await;
58 drop(spi);
59 drop(mosi_out);
60
61 let mut spi = Spi::new_txonly(&mut spi_peri, &mut sck, &mut mosi, &mut tx_dma, spi_config);
62 test_tx::<u8>(&mut spi).await;
63 test_tx::<u16>(&mut spi).await;
64 drop(spi);
65
66 let mut spi = Spi::new_txonly_nosck(&mut spi_peri, &mut mosi, &mut tx_dma, spi_config);
67 test_tx::<u8>(&mut spi).await;
68 test_tx::<u16>(&mut spi).await;
69 drop(spi);
70
71 info!("Test OK");
72 cortex_m::asm::bkpt();
73}
74
75async fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>)
76where
77 W: core::ops::Not<Output = W>,
78{
79 let data: [W; 9] = [
80 0x00u8.into(),
81 0xFFu8.into(),
82 0xAAu8.into(),
83 0x55u8.into(),
84 0xC0u8.into(),
85 0xFFu8.into(),
86 0xEEu8.into(),
87 0xC0u8.into(),
88 0xDEu8.into(),
89 ];
39 90
40 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. 91 // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor.
41 // so we should get the data we sent back. 92 // so we should get the data we sent back.
42 let mut buf = [0; 9]; 93 let mut buf = [W::default(); 9];
43 spi.transfer(&mut buf, &data).await.unwrap(); 94 spi.transfer(&mut buf, &data).await.unwrap();
44 assert_eq!(buf, data); 95 assert_eq!(buf, data);
45 96
@@ -83,56 +134,41 @@ async fn main(_spawner: Spawner) {
83 spi.blocking_write(&buf).unwrap(); 134 spi.blocking_write(&buf).unwrap();
84 spi.blocking_read(&mut buf).unwrap(); 135 spi.blocking_read(&mut buf).unwrap();
85 spi.write(&buf).await.unwrap(); 136 spi.write(&buf).await.unwrap();
137}
86 138
87 core::mem::drop(spi); 139async fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>, mosi_out: &mut Output<'_>)
140where
141 W: core::ops::Not<Output = W>,
142{
143 let mut buf = [W::default(); 9];
88 144
89 // test rx-only configuration
90 let mut spi = Spi::new_rxonly(
91 &mut spi_peri,
92 &mut sck,
93 &mut miso,
94 // SPIv1/f1 requires txdma even if rxonly.
95 #[cfg(not(feature = "spi-v345"))]
96 &mut tx_dma,
97 &mut rx_dma,
98 spi_config,
99 );
100 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
101 mosi_out.set_high(); 145 mosi_out.set_high();
102 spi.read(&mut buf).await.unwrap(); 146 spi.read(&mut buf).await.unwrap();
103 assert_eq!(buf, [0xff; 9]); 147 assert_eq!(buf, [!W::default(); 9]);
104 spi.blocking_read(&mut buf).unwrap(); 148 spi.blocking_read(&mut buf).unwrap();
105 assert_eq!(buf, [0xff; 9]); 149 assert_eq!(buf, [!W::default(); 9]);
106 spi.read(&mut buf).await.unwrap(); 150 spi.read(&mut buf).await.unwrap();
107 assert_eq!(buf, [0xff; 9]); 151 assert_eq!(buf, [!W::default(); 9]);
108 spi.read(&mut buf).await.unwrap(); 152 spi.read(&mut buf).await.unwrap();
109 assert_eq!(buf, [0xff; 9]); 153 assert_eq!(buf, [!W::default(); 9]);
110 spi.blocking_read(&mut buf).unwrap(); 154 spi.blocking_read(&mut buf).unwrap();
111 assert_eq!(buf, [0xff; 9]); 155 assert_eq!(buf, [!W::default(); 9]);
112 spi.blocking_read(&mut buf).unwrap(); 156 spi.blocking_read(&mut buf).unwrap();
113 assert_eq!(buf, [0xff; 9]); 157 assert_eq!(buf, [!W::default(); 9]);
114 mosi_out.set_low(); 158 mosi_out.set_low();
115 spi.read(&mut buf).await.unwrap(); 159 spi.read(&mut buf).await.unwrap();
116 assert_eq!(buf, [0x00; 9]); 160 assert_eq!(buf, [W::default(); 9]);
117 spi.read::<u8>(&mut []).await.unwrap(); 161 spi.read::<u8>(&mut []).await.unwrap();
118 spi.blocking_read::<u8>(&mut []).unwrap(); 162 spi.blocking_read::<u8>(&mut []).unwrap();
119 drop(mosi_out); 163}
120 drop(spi);
121 164
122 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave. 165async fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>)
123 let mut spi = Spi::new_txonly(&mut spi_peri, &mut sck, &mut mosi, &mut tx_dma, spi_config); 166where
124 spi.blocking_write(&buf).unwrap(); 167 W: core::ops::Not<Output = W>,
125 spi.write(&buf).await.unwrap(); 168{
126 spi.blocking_write(&buf).unwrap(); 169 let buf = [W::default(); 9];
127 spi.blocking_write(&buf).unwrap();
128 spi.write(&buf).await.unwrap();
129 spi.write(&buf).await.unwrap();
130 spi.write::<u8>(&[]).await.unwrap();
131 spi.blocking_write::<u8>(&[]).unwrap();
132 drop(spi);
133 170
134 // Test tx-only nosck. 171 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave.
135 let mut spi = Spi::new_txonly_nosck(&mut spi_peri, &mut mosi, &mut tx_dma, spi_config);
136 spi.blocking_write(&buf).unwrap(); 172 spi.blocking_write(&buf).unwrap();
137 spi.write(&buf).await.unwrap(); 173 spi.write(&buf).await.unwrap();
138 spi.blocking_write(&buf).unwrap(); 174 spi.blocking_write(&buf).unwrap();
@@ -141,8 +177,4 @@ async fn main(_spawner: Spawner) {
141 spi.write(&buf).await.unwrap(); 177 spi.write(&buf).await.unwrap();
142 spi.write::<u8>(&[]).await.unwrap(); 178 spi.write::<u8>(&[]).await.unwrap();
143 spi.blocking_write::<u8>(&[]).unwrap(); 179 spi.blocking_write::<u8>(&[]).unwrap();
144 drop(spi);
145
146 info!("Test OK");
147 cortex_m::asm::bkpt();
148} 180}