Skip to content

Commit 6792867

Browse files
committed
require static lifetimes on spi-dma buffers
1 parent 9779052 commit 6792867

File tree

2 files changed

+82
-152
lines changed

2 files changed

+82
-152
lines changed

examples/spi-async-rtic.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
mod utilities;
55

6-
use embedded_hal_async::spi::SpiBus;
76
use rtic::app;
87
use stm32h5xx_hal::{
98
gpdma::{periph::DmaDuplex, DmaChannel0, DmaChannel1},
@@ -19,6 +18,8 @@ systick_monotonic!(Mono, 1000);
1918
#[app(device = pac, dispatchers = [USART1, USART2], peripherals = true)]
2019
mod app {
2120

21+
use cortex_m::singleton;
22+
use embedded_dma::{ReadBuffer, WriteBuffer};
2223
use stm32h5::stm32h503::{GPDMA1, NVIC};
2324

2425
use super::*;
@@ -33,8 +34,8 @@ mod app {
3334
pac::SPI2,
3435
DmaDuplex<pac::SPI2, u8, DmaChannel0<GPDMA1>, DmaChannel1<GPDMA1>>,
3536
>,
36-
source: [u8; 40],
37-
dest: [u8; 40],
37+
source: &'static mut [u8; 40],
38+
dest: &'static mut [u8; 40],
3839
}
3940

4041
#[init]
@@ -92,8 +93,8 @@ mod app {
9293
Local {
9394
led,
9495
spi,
95-
source: [0; 40],
96-
dest: [0; 40],
96+
source: singleton!(: [u8; 40] = [0; 40]).unwrap(),
97+
dest: singleton!(: [u8; 40] = [0; 40]).unwrap(),
9798
},
9899
)
99100
}
@@ -114,14 +115,17 @@ mod app {
114115
log::info!("Starting SPI transfer");
115116
ctx.local.source.fill(*ctx.local.count as u8);
116117
ctx.local.dest.fill(0);
118+
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) };
124+
117125
*ctx.local.count += 1;
118-
ctx.local
119-
.spi
120-
.transfer(ctx.local.dest, ctx.local.source)
121-
.await
122-
.unwrap();
126+
ctx.local.spi.transfer_dma(src, dest).await.unwrap();
123127

124-
assert_eq!(ctx.local.source, ctx.local.dest);
128+
assert_eq!(*ctx.local.source, *ctx.local.dest);
125129
log::info!("Success!");
126130
Mono::delay(1000.millis()).await;
127131
}

src/spi/dma.rs

Lines changed: 67 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use core::{
55
task::{Context, Poll},
66
};
77

8+
use embedded_dma::{ReadBuffer, WriteBuffer};
89
use embedded_hal::spi::ErrorType;
9-
use embedded_hal_async::spi::SpiBus;
1010
use futures_util::join;
1111
use futures_util::task::AtomicWaker;
1212

@@ -228,18 +228,22 @@ where
228228
W: Word + DmaWord,
229229
MODE: Rx<W>,
230230
{
231-
pub fn start_dma_read<'a>(
231+
pub fn start_dma_read<'a, D>(
232232
&'a mut self,
233-
words: &'a mut [W],
234-
) -> Result<DmaTransfer<'a, <MODE as Rx<W>>::CH>, Error> {
233+
mut destination: D,
234+
) -> Result<DmaTransfer<'a, <MODE as Rx<W>>::CH>, Error>
235+
where
236+
D: WriteBuffer<Word = W>,
237+
{
235238
let config = DmaConfig::new().with_request(SPI::rx_dma_request());
239+
let (_, len) = unsafe { destination.write_buffer() };
236240

237-
self.spi.inner.set_transfer_word_count(words.len() as u16);
241+
self.spi.inner.set_transfer_word_count(len as u16);
238242
// Make sure to handle any errors before initializing a transfer
239243
self.setup_read_mode()?;
240244

241245
let spi = &mut self.spi;
242-
let transfer = self.mode.init_rx_transfer(config, words);
246+
let transfer = self.mode.init_rx_transfer(config, destination);
243247

244248
spi.inner.enable_rx_dma();
245249

@@ -250,8 +254,11 @@ where
250254
Ok(transfer)
251255
}
252256

253-
async fn read_dma(&mut self, words: &mut [W]) -> Result<(), Error> {
254-
let result = self.start_dma_read(words)?.await;
257+
pub async fn read_dma<D>(&mut self, destination: D) -> Result<(), Error>
258+
where
259+
D: WriteBuffer<Word = W>,
260+
{
261+
let result = self.start_dma_read(destination)?.await;
255262
self.finish_transfer_async(result).await
256263
}
257264
}
@@ -263,19 +270,24 @@ where
263270
W: Word + DmaWord,
264271
MODE: Tx<W>,
265272
{
266-
pub fn start_dma_write<'a>(
273+
pub fn start_dma_write<'a, S>(
267274
&'a mut self,
268-
words: &'a [W],
269-
) -> Result<DmaTransfer<'a, <MODE as Tx<W>>::CH>, Error> {
275+
source: S,
276+
) -> Result<DmaTransfer<'a, <MODE as Tx<W>>::CH>, Error>
277+
where
278+
S: ReadBuffer<Word = W>,
279+
{
270280
let config = DmaConfig::new().with_request(SPI::tx_dma_request());
271281

272-
self.inner.set_transfer_word_count(words.len() as u16);
282+
let (_, len) = unsafe { source.read_buffer() };
283+
284+
self.inner.set_transfer_word_count(len as u16);
273285

274286
// Make sure to handle any errors before initializing a transfer
275287
self.setup_write_mode()?;
276288

277289
let spi = &mut self.spi;
278-
let transfer = self.mode.init_tx_transfer(config, words);
290+
let transfer = self.mode.init_tx_transfer(config, source);
279291

280292
transfer.start_nonblocking();
281293
spi.inner.enable_tx_dma();
@@ -284,8 +296,11 @@ where
284296
Ok(transfer)
285297
}
286298

287-
async fn write_dma(&mut self, words: &[W]) -> Result<(), Error> {
288-
let result = self.start_dma_write(words)?.await;
299+
pub async fn write_dma<S>(&mut self, source: S) -> Result<(), Error>
300+
where
301+
S: ReadBuffer<Word = W>,
302+
{
303+
let result = self.start_dma_write(source)?.await;
289304
self.finish_transfer_async(result).await
290305
}
291306
}
@@ -298,27 +313,33 @@ where
298313
TX: DmaChannel,
299314
RX: DmaChannel,
300315
{
301-
pub fn start_dma_duplex_transfer<'a>(
316+
pub fn start_dma_duplex_transfer<'a, S, D>(
302317
&'a mut self,
303-
read: &'a mut [W],
304-
write: &'a [W],
305-
) -> Result<(DmaTransfer<'a, TX>, DmaTransfer<'a, RX>), Error> {
318+
source: S,
319+
mut destination: D,
320+
) -> Result<(DmaTransfer<'a, TX>, DmaTransfer<'a, RX>), Error>
321+
where
322+
S: ReadBuffer<Word = W>,
323+
D: WriteBuffer<Word = W>,
324+
{
325+
let (_, read_len) = unsafe { source.read_buffer() };
326+
let (_, write_len) = unsafe { destination.write_buffer() };
327+
306328
assert_eq!(
307-
read.len(),
308-
write.len(),
329+
read_len, write_len,
309330
"Read and write buffers must have the same length"
310331
);
311332

312333
let tx_config = DmaConfig::new().with_request(SPI::tx_dma_request());
313334
let rx_config = DmaConfig::new().with_request(SPI::rx_dma_request());
314335

315-
self.inner.set_transfer_word_count(read.len() as u16);
336+
self.inner.set_transfer_word_count(read_len as u16);
316337

317338
self.check_transfer_mode()?;
318339

319340
let spi = &mut self.spi;
320-
let tx_transfer = self.mode.init_tx_transfer(tx_config, write);
321-
let rx_transfer = self.mode.init_rx_transfer(rx_config, read);
341+
let tx_transfer = self.mode.init_tx_transfer(tx_config, source);
342+
let rx_transfer = self.mode.init_rx_transfer(rx_config, destination);
322343

323344
spi.inner.enable_rx_dma();
324345
rx_transfer.start_nonblocking();
@@ -329,27 +350,38 @@ where
329350
Ok((tx_transfer, rx_transfer))
330351
}
331352

332-
async fn transfer_dma(
353+
pub async fn transfer_dma<S, D>(
333354
&mut self,
334-
read: &mut [W],
335-
write: &[W],
336-
) -> Result<(), Error> {
337-
let (tx, rx) = self.start_dma_duplex_transfer(read, write)?;
355+
source: S,
356+
destination: D,
357+
) -> Result<(), Error>
358+
where
359+
S: ReadBuffer<Word = W>,
360+
D: WriteBuffer<Word = W>,
361+
{
362+
let (tx, rx) = self.start_dma_duplex_transfer(source, destination)?;
338363
let (tx, rx) = (tx.into_future(), rx.into_future());
339364
let results = join!(tx, rx);
340365
let result = results.0.and(results.1);
341366

342367
self.finish_transfer_async(result).await
343368
}
344369

345-
async fn transfer_inplace_dma(
370+
pub async fn transfer_inplace_dma<B>(
346371
&mut self,
347-
words: &mut [W],
348-
) -> Result<(), Error> {
372+
mut buffer: B,
373+
) -> Result<(), Error>
374+
where
375+
B: WriteBuffer<Word = W>,
376+
{
377+
let (ptr, len) = unsafe { buffer.write_buffer() };
378+
349379
// Note (unsafe): Data will be read from the start of the buffer before data is written
350-
// to those locations just like for blocking non-DMA in-place transfers
351-
let write: &[W] = unsafe { *(words.as_ptr() as *const &[W]) };
352-
self.transfer_dma(words, write).await
380+
// to those locations just like for blocking non-DMA in-place transfers, and the location
381+
// is already guaranteed to be 'static
382+
let source = unsafe { core::slice::from_raw_parts(ptr, len) };
383+
384+
self.transfer_dma(source, buffer).await
353385
}
354386
}
355387

@@ -361,112 +393,6 @@ where
361393
type Error = Error;
362394
}
363395

364-
impl<SPI, CH, W> SpiBus<W> for SpiDma<SPI, DmaTx<SPI, W, CH>, W>
365-
where
366-
SPI: Instance + Waker,
367-
W: Word + DmaWord,
368-
CH: DmaChannel,
369-
{
370-
async fn read(&mut self, _words: &mut [W]) -> Result<(), Self::Error> {
371-
unimplemented!("Not supported for simplex transmitter")
372-
}
373-
374-
async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
375-
self.write_dma(words).await
376-
}
377-
378-
async fn transfer(
379-
&mut self,
380-
_read: &mut [W],
381-
_write: &[W],
382-
) -> Result<(), Self::Error> {
383-
unimplemented!("Not supported for simplex transmitter")
384-
}
385-
386-
async fn transfer_in_place(
387-
&mut self,
388-
_words: &mut [W],
389-
) -> Result<(), Self::Error> {
390-
unimplemented!("Not supported for simplex transmitter")
391-
}
392-
393-
async fn flush(&mut self) -> Result<(), Self::Error> {
394-
// This is handled within each of the above functions
395-
Ok(())
396-
}
397-
}
398-
399-
impl<SPI, CH, W> SpiBus<W> for SpiDma<SPI, DmaRx<SPI, W, CH>, W>
400-
where
401-
SPI: Instance + Waker,
402-
W: Word + DmaWord,
403-
CH: DmaChannel,
404-
{
405-
async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
406-
self.read_dma(words).await
407-
}
408-
409-
async fn write(&mut self, _words: &[W]) -> Result<(), Self::Error> {
410-
unimplemented!("Not supported for simplex receiver")
411-
}
412-
413-
async fn transfer(
414-
&mut self,
415-
_read: &mut [W],
416-
_write: &[W],
417-
) -> Result<(), Self::Error> {
418-
unimplemented!("Not supported for simplex receiver")
419-
}
420-
421-
async fn transfer_in_place(
422-
&mut self,
423-
_words: &mut [W],
424-
) -> Result<(), Self::Error> {
425-
unimplemented!("Not supported for simplex receiver")
426-
}
427-
428-
async fn flush(&mut self) -> Result<(), Self::Error> {
429-
// This is handled within each of the above functions
430-
Ok(())
431-
}
432-
}
433-
434-
impl<SPI, TX, RX, W> SpiBus<W> for SpiDma<SPI, DmaDuplex<SPI, W, TX, RX>, W>
435-
where
436-
SPI: Instance + Waker,
437-
W: Word + DmaWord,
438-
TX: DmaChannel,
439-
RX: DmaChannel,
440-
{
441-
async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
442-
self.read_dma(words).await
443-
}
444-
445-
async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
446-
self.write_dma(words).await
447-
}
448-
449-
async fn transfer(
450-
&mut self,
451-
read: &mut [W],
452-
write: &[W],
453-
) -> Result<(), Self::Error> {
454-
self.transfer_dma(read, write).await
455-
}
456-
457-
async fn transfer_in_place(
458-
&mut self,
459-
words: &mut [W],
460-
) -> Result<(), Self::Error> {
461-
self.transfer_inplace_dma(words).await
462-
}
463-
464-
async fn flush(&mut self) -> Result<(), Self::Error> {
465-
// This is handled within each of the above functions
466-
Ok(())
467-
}
468-
}
469-
470396
struct SpiDmaFuture<'a, SPI: Instance, MODE, W: Word> {
471397
spi: &'a mut SpiDma<SPI, MODE, W>,
472398
}

0 commit comments

Comments
 (0)