Skip to content

Commit a83cb46

Browse files
committed
make non-static requirement unsafe
1 parent 767fd5a commit a83cb46

File tree

1 file changed

+82
-9
lines changed

1 file changed

+82
-9
lines changed

src/dma/mod.rs

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,13 @@ use core::{
9393
ptr,
9494
sync::atomic::{fence, Ordering},
9595
};
96-
use embedded_dma::{ReadBuffer, StaticWriteBuffer, WriteBuffer};
96+
97+
use embedded_dma::{StaticReadBuffer, StaticWriteBuffer, WriteBuffer};
98+
99+
use traits::{
100+
sealed::Bits, Direction, DoubleBufferedConfig, DoubleBufferedStream,
101+
MasterStream, Stream, TargetAddress,
102+
};
97103

98104
#[macro_use]
99105
mod macros;
@@ -106,10 +112,6 @@ pub mod bdma;
106112
pub mod mdma;
107113

108114
pub mod traits;
109-
use traits::{
110-
sealed::Bits, Direction, DoubleBufferedConfig, DoubleBufferedStream,
111-
MasterStream, Stream, TargetAddress,
112-
};
113115

114116
/// Errors.
115117
#[derive(PartialEq, Debug, Copy, Clone)]
@@ -374,7 +376,7 @@ where
374376
}
375377

376378
macro_rules! db_transfer_def {
377-
($Marker:ident, $init:ident, $Buffer:tt, $rw_buffer:ident $(, $mut:tt)*;
379+
($([$prepend: ident],)?$Marker:ident, $init:ident, $Buffer:tt, $rw_buffer:ident $(, $mut:tt)*;
378380
$($constraint:stmt)*) => {
379381
impl<STREAM, CONFIG, PERIPHERAL, DIR, BUF>
380382
Transfer<STREAM, PERIPHERAL, DIR, BUF, $Marker>
@@ -415,7 +417,40 @@ macro_rules! db_transfer_def {
415417
/// * When double buffering is enabled but the `double_buf` argument is
416418
/// `None`.
417419
/// * When the transfer length is greater than (2^16 - 1)
418-
pub fn $init(
420+
///
421+
/// # Safety
422+
///
423+
/// * If using an unsafe variant of this function (i.e., [Transfer::init_unsafe]),
424+
/// the buffer must live as long as the
425+
/// hardware DMA transfer. A case where this **wouldn't be true** is demonstrated below:
426+
/// ```
427+
/// use stm32h7xx_hal::dma::{PeripheralToMemory, Transfer};
428+
///
429+
/// let spi = spi.disable();
430+
/// let mut short_buffer = [0u8; 1024];
431+
/// let streams = StreamsTuple::new(dp.DMA1, ccdr.peripheral.DMA1);
432+
/// let config = DmaConfig::default().memory_increment(true);
433+
/// let mut transfer: Transfer<_, _, PeripheralToMemory, _, _> = unsafe {
434+
/// Transfer::init_unsafe(streams.0, spi, &mut short_buffer[..], None, config)
435+
/// };
436+
///
437+
/// transfer.start(|spi| {
438+
/// spi.enable_dma_tx();
439+
/// spi.inner_mut()
440+
/// .cr1
441+
/// .write(|w| w.ssi().slave_not_selected().spe().enabled());
442+
/// spi.inner_mut().cr1.modify(|_, w| w.cstart().started());
443+
/// });
444+
///
445+
/// mem::forget(transfer); // <<<<<<<<
446+
///
447+
/// loop {
448+
/// // &ref to buffer while DMA transfer is still writing to buffer
449+
/// info!("short_buffer = {:?}", short_buffer);
450+
/// }
451+
/// ```
452+
#[allow(unused_unsafe)]
453+
pub $($prepend)? fn $init(
419454
mut stream: STREAM,
420455
peripheral: PERIPHERAL,
421456
$($mut)* memory: BUF,
@@ -743,8 +778,46 @@ macro_rules! db_transfer_def {
743778
};
744779
}
745780

746-
db_transfer_def!(DBTransfer, init, WriteBuffer, write_buffer, mut;);
747-
db_transfer_def!(ConstDBTransfer, init_const, ReadBuffer, read_buffer;
781+
impl<STREAM, CONFIG, PERIPHERAL, DIR, BUF>
782+
Transfer<STREAM, PERIPHERAL, DIR, BUF, DBTransfer>
783+
where
784+
STREAM: DoubleBufferedStream + Stream<Config = CONFIG>,
785+
CONFIG: DoubleBufferedConfig,
786+
DIR: Direction,
787+
PERIPHERAL: TargetAddress<DIR>,
788+
BUF: StaticWriteBuffer<Word = <PERIPHERAL as TargetAddress<DIR>>::MemSize>,
789+
BUF: WriteBuffer<Word = <PERIPHERAL as TargetAddress<DIR>>::MemSize>,
790+
{
791+
792+
/// Configures the DMA source and destination and applies supplied
793+
/// configuration. In a memory to memory transfer, the `double_buf` argument
794+
/// is the source of the data. If double buffering is enabled, the number of
795+
/// transfers will be the minimum length of `memory` and `double_buf`.
796+
///
797+
/// # Panics
798+
///
799+
/// * When the FIFO is disabled or double buffering is enabled in
800+
/// `DmaConfig` while initializing a memory to memory transfer.
801+
/// * When double buffering is enabled but the `double_buf` argument is
802+
/// `None`.
803+
/// * When the transfer length is greater than (2^16 - 1)
804+
pub fn init(
805+
stream: STREAM,
806+
peripheral: PERIPHERAL,
807+
memory: BUF,
808+
double_buf: Option<BUF>,
809+
config: CONFIG,
810+
) -> Self {
811+
unsafe {
812+
Transfer::init_unsafe(
813+
stream, peripheral, memory, double_buf, config,
814+
)
815+
}
816+
}
817+
}
818+
819+
db_transfer_def!([unsafe], DBTransfer, init_unsafe, WriteBuffer, write_buffer, mut;);
820+
db_transfer_def!(ConstDBTransfer, init_const, StaticReadBuffer, read_buffer;
748821
assert!(DIR::direction() != DmaDirection::PeripheralToMemory));
749822

750823
impl<STREAM, CONFIG, PERIPHERAL, DIR, BUF, TXFRT>

0 commit comments

Comments
 (0)