Skip to content

Commit 2f7c45e

Browse files
Change DMA API to use embedded-dma traits (#274)
* Change DMA API to use embedded-dma traits * Fix dma::Transfer::peek * Update docs on DMA code
1 parent f88137a commit 2f7c45e

File tree

6 files changed

+176
-143
lines changed

6 files changed

+176
-143
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1313
- SPI objects now have a `FrameSize` type field
1414
- Bit banding functions (`bb::*`) are now correctly marked as unsafe
1515
- Add missing remap to `spi3` constructor. Requires a new `mapr` argument.
16+
- Change DMA API to use embedded-dma traits.
1617

1718
### Added
1819

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ cortex-m = "0.6.0"
2020
nb = "0.1.2"
2121
cortex-m-rt = "0.6.8"
2222
stm32f1 = "0.11.0"
23-
as-slice = "0.1"
23+
embedded-dma = "0.1.2"
2424

2525
[dependencies.void]
2626
default-features = false

src/adc.rs

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::gpio::{gpioa, gpiob, gpioc};
99
use crate::rcc::{Clocks, Enable, Reset, APB2};
1010
use core::sync::atomic::{self, Ordering};
1111
use cortex_m::asm::delay;
12+
use embedded_dma::StaticWriteBuffer;
1213

1314
use crate::pac::ADC1;
1415
#[cfg(feature = "stm32f103")]
@@ -701,34 +702,34 @@ where
701702
impl<B, PINS, MODE> crate::dma::CircReadDma<B, u16> for AdcDma<PINS, MODE>
702703
where
703704
Self: TransferPayload,
704-
B: as_slice::AsMutSlice<Element = u16>,
705+
&'static mut [B; 2]: StaticWriteBuffer<Word = u16>,
706+
B: 'static,
705707
{
706-
fn circ_read(mut self, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self> {
707-
{
708-
let buffer = buffer[0].as_mut_slice();
709-
self.channel
710-
.set_peripheral_address(unsafe { &(*ADC1::ptr()).dr as *const _ as u32 }, false);
711-
self.channel
712-
.set_memory_address(buffer.as_ptr() as u32, true);
713-
self.channel.set_transfer_length(buffer.len() * 2);
714-
715-
atomic::compiler_fence(Ordering::Release);
716-
717-
self.channel.ch().cr.modify(|_, w| {
718-
w.mem2mem()
719-
.clear_bit()
720-
.pl()
721-
.medium()
722-
.msize()
723-
.bits16()
724-
.psize()
725-
.bits16()
726-
.circ()
727-
.set_bit()
728-
.dir()
729-
.clear_bit()
730-
});
731-
}
708+
fn circ_read(mut self, mut buffer: &'static mut [B; 2]) -> CircBuffer<B, Self> {
709+
// NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
710+
// until the end of the transfer.
711+
let (ptr, len) = unsafe { buffer.static_write_buffer() };
712+
self.channel
713+
.set_peripheral_address(unsafe { &(*ADC1::ptr()).dr as *const _ as u32 }, false);
714+
self.channel.set_memory_address(ptr as u32, true);
715+
self.channel.set_transfer_length(len);
716+
717+
atomic::compiler_fence(Ordering::Release);
718+
719+
self.channel.ch().cr.modify(|_, w| {
720+
w.mem2mem()
721+
.clear_bit()
722+
.pl()
723+
.medium()
724+
.msize()
725+
.bits16()
726+
.psize()
727+
.bits16()
728+
.circ()
729+
.set_bit()
730+
.dir()
731+
.clear_bit()
732+
});
732733

733734
self.start();
734735

@@ -739,17 +740,17 @@ where
739740
impl<B, PINS, MODE> crate::dma::ReadDma<B, u16> for AdcDma<PINS, MODE>
740741
where
741742
Self: TransferPayload,
742-
B: as_slice::AsMutSlice<Element = u16>,
743+
B: StaticWriteBuffer<Word = u16>,
743744
{
744-
fn read(mut self, buffer: &'static mut B) -> Transfer<W, &'static mut B, Self> {
745-
{
746-
let buffer = buffer.as_mut_slice();
747-
self.channel
748-
.set_peripheral_address(unsafe { &(*ADC1::ptr()).dr as *const _ as u32 }, false);
749-
self.channel
750-
.set_memory_address(buffer.as_ptr() as u32, true);
751-
self.channel.set_transfer_length(buffer.len());
752-
}
745+
fn read(mut self, mut buffer: B) -> Transfer<W, B, Self> {
746+
// NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
747+
// until the end of the transfer.
748+
let (ptr, len) = unsafe { buffer.static_write_buffer() };
749+
self.channel
750+
.set_peripheral_address(unsafe { &(*ADC1::ptr()).dr as *const _ as u32 }, false);
751+
self.channel.set_memory_address(ptr as u32, true);
752+
self.channel.set_transfer_length(len);
753+
753754
atomic::compiler_fence(Ordering::Release);
754755
self.channel.ch().cr.modify(|_, w| {
755756
w.mem2mem()

src/dma.rs

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
//! # Direct Memory Access
22
#![allow(dead_code)]
33

4-
use core::marker::PhantomData;
5-
use core::ops;
4+
use core::{
5+
marker::PhantomData,
6+
sync::atomic::{compiler_fence, Ordering},
7+
};
8+
use embedded_dma::{StaticReadBuffer, StaticWriteBuffer};
69

710
use crate::rcc::AHB;
811

912
#[derive(Debug)]
13+
#[non_exhaustive]
1014
pub enum Error {
1115
Overrun,
12-
#[doc(hidden)]
13-
_Extensible,
1416
}
1517

1618
pub enum Event {
@@ -33,7 +35,11 @@ where
3335
readable_half: Half,
3436
}
3537

36-
impl<BUFFER, PAYLOAD> CircBuffer<BUFFER, PAYLOAD> {
38+
impl<BUFFER, PAYLOAD> CircBuffer<BUFFER, PAYLOAD>
39+
where
40+
&'static mut [BUFFER; 2]: StaticWriteBuffer,
41+
BUFFER: 'static,
42+
{
3743
pub(crate) fn new(buf: &'static mut [BUFFER; 2], payload: PAYLOAD) -> Self {
3844
CircBuffer {
3945
buffer: buf,
@@ -43,22 +49,6 @@ impl<BUFFER, PAYLOAD> CircBuffer<BUFFER, PAYLOAD> {
4349
}
4450
}
4551

46-
pub trait Static<B> {
47-
fn borrow(&self) -> &B;
48-
}
49-
50-
impl<B> Static<B> for &'static B {
51-
fn borrow(&self) -> &B {
52-
*self
53-
}
54-
}
55-
56-
impl<B> Static<B> for &'static mut B {
57-
fn borrow(&self) -> &B {
58-
*self
59-
}
60-
}
61-
6252
pub trait DmaExt {
6353
type Channels;
6454

@@ -70,13 +60,19 @@ pub trait TransferPayload {
7060
fn stop(&mut self);
7161
}
7262

73-
pub struct Transfer<MODE, BUFFER, PAYLOAD> {
63+
pub struct Transfer<MODE, BUFFER, PAYLOAD>
64+
where
65+
PAYLOAD: TransferPayload,
66+
{
7467
_mode: PhantomData<MODE>,
7568
buffer: BUFFER,
7669
payload: PAYLOAD,
7770
}
7871

79-
impl<BUFFER, PAYLOAD> Transfer<R, BUFFER, PAYLOAD> {
72+
impl<BUFFER, PAYLOAD> Transfer<R, BUFFER, PAYLOAD>
73+
where
74+
PAYLOAD: TransferPayload,
75+
{
8076
pub(crate) fn r(buffer: BUFFER, payload: PAYLOAD) -> Self {
8177
Transfer {
8278
_mode: PhantomData,
@@ -86,7 +82,10 @@ impl<BUFFER, PAYLOAD> Transfer<R, BUFFER, PAYLOAD> {
8682
}
8783
}
8884

89-
impl<BUFFER, PAYLOAD> Transfer<W, BUFFER, PAYLOAD> {
85+
impl<BUFFER, PAYLOAD> Transfer<W, BUFFER, PAYLOAD>
86+
where
87+
PAYLOAD: TransferPayload,
88+
{
9089
pub(crate) fn w(buffer: BUFFER, payload: PAYLOAD) -> Self {
9190
Transfer {
9291
_mode: PhantomData,
@@ -96,11 +95,13 @@ impl<BUFFER, PAYLOAD> Transfer<W, BUFFER, PAYLOAD> {
9695
}
9796
}
9897

99-
impl<BUFFER, PAYLOAD> ops::Deref for Transfer<R, BUFFER, PAYLOAD> {
100-
type Target = BUFFER;
101-
102-
fn deref(&self) -> &BUFFER {
103-
&self.buffer
98+
impl<MODE, BUFFER, PAYLOAD> Drop for Transfer<MODE, BUFFER, PAYLOAD>
99+
where
100+
PAYLOAD: TransferPayload,
101+
{
102+
fn drop(&mut self) {
103+
self.payload.stop();
104+
compiler_fence(Ordering::SeqCst);
104105
}
105106
}
106107

@@ -123,14 +124,14 @@ macro_rules! dma {
123124
}),)+) => {
124125
$(
125126
pub mod $dmaX {
126-
use core::sync::atomic::{self, Ordering};
127-
use core::ptr;
127+
use core::{sync::atomic::{self, Ordering}, ptr, mem};
128128

129129
use crate::pac::{$DMAX, dma1};
130130

131131
use crate::dma::{CircBuffer, DmaExt, Error, Event, Half, Transfer, W, RxDma, TxDma, TransferPayload};
132132
use crate::rcc::{AHB, Enable};
133133

134+
#[allow(clippy::manual_non_exhaustive)]
134135
pub struct Channels((), $(pub $CX),+);
135136

136137
$(
@@ -316,7 +317,19 @@ macro_rules! dma {
316317
// we need a fence here for the same reason we need one in `Transfer.wait`
317318
atomic::compiler_fence(Ordering::Acquire);
318319

319-
(self.buffer, self.payload)
320+
// `Transfer` needs to have a `Drop` implementation, because we accept
321+
// managed buffers that can free their memory on drop. Because of that
322+
// we can't move out of the `Transfer`'s fields, so we use `ptr::read`
323+
// and `mem::forget`.
324+
//
325+
// NOTE(unsafe) There is no panic branch between getting the resources
326+
// and forgetting `self`.
327+
unsafe {
328+
let buffer = ptr::read(&self.buffer);
329+
let payload = ptr::read(&self.payload);
330+
mem::forget(self);
331+
(buffer, payload)
332+
}
320333
}
321334
}
322335

@@ -342,11 +355,23 @@ macro_rules! dma {
342355
// we need a fence here for the same reason we need one in `Transfer.wait`
343356
atomic::compiler_fence(Ordering::Acquire);
344357

345-
(self.buffer, self.payload)
358+
// `Transfer` needs to have a `Drop` implementation, because we accept
359+
// managed buffers that can free their memory on drop. Because of that
360+
// we can't move out of the `Transfer`'s fields, so we use `ptr::read`
361+
// and `mem::forget`.
362+
//
363+
// NOTE(unsafe) There is no panic branch between getting the resources
364+
// and forgetting `self`.
365+
unsafe {
366+
let buffer = ptr::read(&self.buffer);
367+
let payload = ptr::read(&self.payload);
368+
mem::forget(self);
369+
(buffer, payload)
370+
}
346371
}
347372
}
348373

349-
impl<BUFFER, PAYLOAD> Transfer<W, &'static mut BUFFER, RxDma<PAYLOAD, $CX>>
374+
impl<BUFFER, PAYLOAD> Transfer<W, BUFFER, RxDma<PAYLOAD, $CX>>
350375
where
351376
RxDma<PAYLOAD, $CX>: TransferPayload,
352377
{
@@ -480,27 +505,30 @@ pub trait Transmit {
480505
type ReceivedWord;
481506
}
482507

508+
/// Trait for circular DMA readings from peripheral to memory.
483509
pub trait CircReadDma<B, RS>: Receive
484510
where
485-
B: as_slice::AsMutSlice<Element = RS>,
511+
&'static mut [B; 2]: StaticWriteBuffer<Word = RS>,
512+
B: 'static,
486513
Self: core::marker::Sized,
487514
{
488515
fn circ_read(self, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self>;
489516
}
490517

518+
/// Trait for DMA readings from peripheral to memory.
491519
pub trait ReadDma<B, RS>: Receive
492520
where
493-
B: as_slice::AsMutSlice<Element = RS>,
494-
Self: core::marker::Sized,
521+
B: StaticWriteBuffer<Word = RS>,
522+
Self: core::marker::Sized + TransferPayload,
495523
{
496-
fn read(self, buffer: &'static mut B) -> Transfer<W, &'static mut B, Self>;
524+
fn read(self, buffer: B) -> Transfer<W, B, Self>;
497525
}
498526

499-
pub trait WriteDma<A, B, TS>: Transmit
527+
/// Trait for DMA writing from memory to peripheral.
528+
pub trait WriteDma<B, TS>: Transmit
500529
where
501-
A: as_slice::AsSlice<Element = TS>,
502-
B: Static<A>,
503-
Self: core::marker::Sized,
530+
B: StaticReadBuffer<Word = TS>,
531+
Self: core::marker::Sized + TransferPayload,
504532
{
505533
fn write(self, buffer: B) -> Transfer<R, B, Self>;
506534
}

0 commit comments

Comments
 (0)