Skip to content

Commit c88387f

Browse files
committed
spi: Use new periph API, fix unsoundness in example
1 parent 209cb62 commit c88387f

File tree

2 files changed

+65
-18
lines changed

2 files changed

+65
-18
lines changed

examples/spi-async-rtic.rs

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33

44
mod utilities;
55

6+
use embedded_dma::{ReadBuffer, WriteBuffer};
67
use rtic::app;
78
use stm32h5xx_hal::{
8-
gpdma::{periph::DmaDuplex, DmaChannel0, DmaChannel1},
9+
gpdma::{periph::DmaDuplex, DmaChannel0, DmaChannel1, Word},
910
gpio::{Output, PA5},
1011
pac,
1112
prelude::*,
@@ -15,11 +16,51 @@ use stm32h5xx_hal::{
1516
use rtic_monotonics::systick::prelude::*;
1617
systick_monotonic!(Mono, 1000);
1718

19+
// Buffer is used to manage a reference to a static buffer returned by the cortex_m::singleton!
20+
// macro and which can be with the DmaTransfer API (which requires passing ReadBuffer and
21+
// WriteBuffer implementations by value) and then used to access the buffer after the transfer has
22+
// completed.
23+
struct Buffer<T: Word + 'static, const N: usize> {
24+
data: &'static mut [T; N],
25+
}
26+
27+
impl<T, const N: usize> Buffer<T, N>
28+
where
29+
T: Word + 'static,
30+
{
31+
fn new(data: &'static mut [T; N]) -> Self {
32+
Self { data }
33+
}
34+
}
35+
36+
unsafe impl<T, const N: usize> ReadBuffer for &mut Buffer<T, N>
37+
where
38+
T: Word + 'static,
39+
{
40+
type Word = T;
41+
42+
unsafe fn read_buffer(&self) -> (*const Self::Word, usize) {
43+
(self.data.as_ptr(), N)
44+
}
45+
}
46+
47+
unsafe impl<T, const N: usize> WriteBuffer for &mut Buffer<T, N>
48+
where
49+
T: Word + 'static,
50+
{
51+
type Word = T;
52+
53+
unsafe fn write_buffer(&mut self) -> (*mut Self::Word, usize) {
54+
(self.data.as_mut_ptr(), N)
55+
}
56+
}
57+
1858
#[app(device = pac, dispatchers = [USART1, USART2], peripherals = true)]
1959
mod app {
2060

61+
use core::cell::Cell;
62+
2163
use cortex_m::singleton;
22-
use embedded_dma::{ReadBuffer, WriteBuffer};
2364
use stm32h5::stm32h503::{GPDMA1, NVIC};
2465

2566
use super::*;
@@ -34,8 +75,8 @@ mod app {
3475
pac::SPI2,
3576
DmaDuplex<pac::SPI2, u8, DmaChannel0<GPDMA1>, DmaChannel1<GPDMA1>>,
3677
>,
37-
source: &'static mut [u8; 40],
38-
dest: &'static mut [u8; 40],
78+
source: Cell<Buffer<u8, 40>>,
79+
dest: Cell<Buffer<u8, 40>>,
3980
}
4081

4182
#[init]
@@ -86,15 +127,18 @@ mod app {
86127
NVIC::unmask(pac::interrupt::GPDMA1_CH1);
87128
};
88129

130+
let src = singleton!(: [u8; 40] = [0; 40]).unwrap();
131+
let dest = singleton!(: [u8; 40] = [0; 40]).unwrap();
132+
89133
tick::spawn().unwrap();
90134
spi_transfer::spawn().unwrap();
91135
(
92136
Shared {},
93137
Local {
94138
led,
95139
spi,
96-
source: singleton!(: [u8; 40] = [0; 40]).unwrap(),
97-
dest: singleton!(: [u8; 40] = [0; 40]).unwrap(),
140+
source: Cell::new(Buffer::new(src)),
141+
dest: Cell::new(Buffer::new(dest)),
98142
},
99143
)
100144
}
@@ -113,19 +157,19 @@ mod app {
113157
async fn spi_transfer(ctx: spi_transfer::Context) {
114158
loop {
115159
log::info!("Starting SPI transfer");
116-
ctx.local.source.fill(*ctx.local.count as u8);
117-
ctx.local.dest.fill(0);
118160

119-
let (src_ptr, src_len) = unsafe { ctx.local.source.read_buffer() };
120-
let src = unsafe { core::slice::from_raw_parts(src_ptr, src_len) };
121-
let (dest_ptr, dest_len) = unsafe { ctx.local.dest.write_buffer() };
122-
let dest =
123-
unsafe { core::slice::from_raw_parts_mut(dest_ptr, dest_len) };
161+
let src = ctx.local.source.get_mut();
162+
let dest = ctx.local.dest.get_mut();
163+
src.data.fill(*ctx.local.count as u8);
164+
dest.data.fill(0);
124165

125166
*ctx.local.count += 1;
126167
ctx.local.spi.transfer_dma(src, dest).await.unwrap();
127168

128-
assert_eq!(*ctx.local.source, *ctx.local.dest);
169+
assert_eq!(
170+
*ctx.local.source.get_mut().data,
171+
*ctx.local.dest.get_mut().data
172+
);
129173
log::info!("Success!");
130174
Mono::delay(1000.millis()).await;
131175
}

src/spi/dma.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use futures_util::task::AtomicWaker;
1313
use crate::{
1414
gpdma::{
1515
config::DmaConfig,
16-
periph::{DmaDuplex, DmaRx, DmaTx, RxAddr, TxAddr},
16+
periph::{DmaDuplex, DmaRx, DmaTx, PeriphRxBuffer, PeriphTxBuffer, RxAddr, TxAddr},
1717
DmaChannel, DmaTransfer, Error as DmaError, Word as DmaWord,
1818
},
1919
interrupt,
@@ -231,7 +231,7 @@ where
231231
pub fn start_dma_read<'a, D>(
232232
&'a mut self,
233233
mut destination: D,
234-
) -> Result<DmaTransfer<'a, CH>, Error>
234+
) -> Result<DmaTransfer<'a, CH, PeriphRxBuffer<SPI, W>, D>, Error>
235235
where
236236
D: WriteBuffer<Word = W>,
237237
{
@@ -273,7 +273,7 @@ where
273273
pub fn start_dma_write<'a, S>(
274274
&'a mut self,
275275
source: S,
276-
) -> Result<DmaTransfer<'a, CH>, Error>
276+
) -> Result<DmaTransfer<'a, CH, S, PeriphTxBuffer<SPI, W>>, Error>
277277
where
278278
S: ReadBuffer<Word = W>,
279279
{
@@ -313,11 +313,13 @@ where
313313
TX: DmaChannel,
314314
RX: DmaChannel,
315315
{
316+
#[allow(clippy::type_complexity)]
316317
pub fn start_dma_duplex_transfer<'a, S, D>(
317318
&'a mut self,
318319
source: S,
319320
mut destination: D,
320-
) -> Result<(DmaTransfer<'a, TX>, DmaTransfer<'a, RX>), Error>
321+
) -> Result<(DmaTransfer<'a, TX, S, PeriphTxBuffer<SPI, W>>,
322+
DmaTransfer<'a, RX, PeriphRxBuffer<SPI, W>, D>), Error>
321323
where
322324
S: ReadBuffer<Word = W>,
323325
D: WriteBuffer<Word = W>,
@@ -363,6 +365,7 @@ where
363365
let (tx, rx) = self.start_dma_duplex_transfer(source, destination)?;
364366
let (tx, rx) = (tx.into_future(), rx.into_future());
365367
let results = join!(tx, rx);
368+
366369
let result = results.0.and(results.1);
367370

368371
self.finish_transfer_async(result).await

0 commit comments

Comments
 (0)