aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-03-26 15:55:58 +0000
committerGitHub <[email protected]>2023-03-26 15:55:58 +0000
commit9c7b9b7848da853028902829245887277279b53c (patch)
tree1d8ab7ce5dd0c53829281cc9ae4c4304442bb145
parent299689dfa2a5e160dbd6aa474772a9317a219084 (diff)
parent7be63b3468f72fc684267c90093a00e77cff1bdc (diff)
Merge #1288
1288: fix(rp): spi transfer r=elpiel a=elpiel Fixes #1181 Co-authored-by: Lachezar Lechev <[email protected]>
-rw-r--r--embassy-rp/src/dma.rs1
-rw-r--r--embassy-rp/src/spi.rs45
-rw-r--r--tests/rp/src/bin/spi_async.rs64
3 files changed, 98 insertions, 12 deletions
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 05adcecdd..ba07a88df 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -1,3 +1,4 @@
1//! Direct Memory Access (DMA)
1use core::future::Future; 2use core::future::Future;
2use core::pin::Pin; 3use core::pin::Pin;
3use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 584370d56..ebd621ecf 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -1,3 +1,4 @@
1//! Serial Peripheral Interface
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2 3
3use embassy_embedded_hal::SetConfig; 4use embassy_embedded_hal::SetConfig;
@@ -383,21 +384,33 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
383 } 384 }
384 385
385 async fn transfer_inner(&mut self, rx_ptr: *mut [u8], tx_ptr: *const [u8]) -> Result<(), Error> { 386 async fn transfer_inner(&mut self, rx_ptr: *mut [u8], tx_ptr: *const [u8]) -> Result<(), Error> {
386 let (_, from_len) = crate::dma::slice_ptr_parts(tx_ptr); 387 let (_, tx_len) = crate::dma::slice_ptr_parts(tx_ptr);
387 let (_, to_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); 388 let (_, rx_len) = crate::dma::slice_ptr_parts_mut(rx_ptr);
388 assert_eq!(from_len, to_len); 389
389 unsafe { 390 unsafe {
390 self.inner.regs().dmacr().write(|reg| { 391 self.inner.regs().dmacr().write(|reg| {
391 reg.set_rxdmae(true); 392 reg.set_rxdmae(true);
392 reg.set_txdmae(true); 393 reg.set_txdmae(true);
393 }) 394 })
394 }; 395 };
395 let tx_ch = self.tx_dma.as_mut().unwrap(); 396
396 let tx_transfer = unsafe { 397 let mut tx_ch = self.tx_dma.as_mut().unwrap();
397 // If we don't assign future to a variable, the data register pointer 398 // If we don't assign future to a variable, the data register pointer
398 // is held across an await and makes the future non-Send. 399 // is held across an await and makes the future non-Send.
399 crate::dma::write(tx_ch, tx_ptr, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) 400 let tx_transfer = async {
401 let p = self.inner.regs();
402 unsafe {
403 crate::dma::write(&mut tx_ch, tx_ptr, p.dr().ptr() as *mut _, T::TX_DREQ).await;
404
405 if rx_len > tx_len {
406 let write_bytes_len = rx_len - tx_len;
407 // write dummy data
408 // this will disable incrementation of the buffers
409 crate::dma::write_repeated(tx_ch, p.dr().ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
410 }
411 }
400 }; 412 };
413
401 let rx_ch = self.rx_dma.as_mut().unwrap(); 414 let rx_ch = self.rx_dma.as_mut().unwrap();
402 let rx_transfer = unsafe { 415 let rx_transfer = unsafe {
403 // If we don't assign future to a variable, the data register pointer 416 // If we don't assign future to a variable, the data register pointer
@@ -405,6 +418,22 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
405 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) 418 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ)
406 }; 419 };
407 join(tx_transfer, rx_transfer).await; 420 join(tx_transfer, rx_transfer).await;
421
422 // if tx > rx we should clear any overflow of the FIFO SPI buffer
423 if tx_len > rx_len {
424 let p = self.inner.regs();
425 unsafe {
426 while p.sr().read().bsy() {}
427
428 // clear RX FIFO contents to prevent stale reads
429 while p.sr().read().rne() {
430 let _: u16 = p.dr().read().data();
431 }
432 // clear RX overrun interrupt
433 p.icr().write(|w| w.set_roric(true));
434 }
435 }
436
408 Ok(()) 437 Ok(())
409 } 438 }
410} 439}
diff --git a/tests/rp/src/bin/spi_async.rs b/tests/rp/src/bin/spi_async.rs
index 6c85ef60a..2e22c9de7 100644
--- a/tests/rp/src/bin/spi_async.rs
+++ b/tests/rp/src/bin/spi_async.rs
@@ -1,3 +1,6 @@
1//! Make sure to connect GPIO pins 3 (`PIN_3`) and 4 (`PIN_4`) together
2//! to run this test.
3//!
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
@@ -18,10 +21,63 @@ async fn main(_spawner: Spawner) {
18 21
19 let mut spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default()); 22 let mut spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
20 23
21 let tx_buf = [1_u8, 2, 3, 4, 5, 6]; 24 // equal rx & tx buffers
22 let mut rx_buf = [0_u8; 6]; 25 {
23 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); 26 let tx_buf = [1_u8, 2, 3, 4, 5, 6];
24 assert_eq!(rx_buf, tx_buf); 27 let mut rx_buf = [0_u8; 6];
28 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
29 assert_eq!(rx_buf, tx_buf);
30 }
31
32 // tx > rx buffer
33 {
34 let tx_buf = [7_u8, 8, 9, 10, 11, 12];
35
36 let mut rx_buf = [0_u8; 3];
37 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
38 assert_eq!(rx_buf, tx_buf[..3]);
39
40 defmt::info!("tx > rx buffer - OK");
41 }
42
43 // we make sure to that clearing FIFO works after the uneven buffers
44
45 // equal rx & tx buffers
46 {
47 let tx_buf = [13_u8, 14, 15, 16, 17, 18];
48 let mut rx_buf = [0_u8; 6];
49 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
50 assert_eq!(rx_buf, tx_buf);
51
52 defmt::info!("buffer rx length == tx length - OK");
53 }
54
55 // rx > tx buffer
56 {
57 let tx_buf = [19_u8, 20, 21];
58 let mut rx_buf = [0_u8; 6];
59
60 // we should have written dummy data to tx buffer to sync clock.
61 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
62
63 assert_eq!(
64 rx_buf[..3],
65 tx_buf,
66 "only the first 3 TX bytes should have been received in the RX buffer"
67 );
68 assert_eq!(rx_buf[3..], [0, 0, 0], "the rest of the RX bytes should be empty");
69 defmt::info!("buffer rx length > tx length - OK");
70 }
71
72 // equal rx & tx buffers
73 {
74 let tx_buf = [22_u8, 23, 24, 25, 26, 27];
75 let mut rx_buf = [0_u8; 6];
76 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
77
78 assert_eq!(rx_buf, tx_buf);
79 defmt::info!("buffer rx length = tx length - OK");
80 }
25 81
26 info!("Test OK"); 82 info!("Test OK");
27 cortex_m::asm::bkpt(); 83 cortex_m::asm::bkpt();