Skip to content

Commit 0f1d6a3

Browse files
committed
serial: Enable DMA only when we actually use it
Instead of always enabling DMA on the USART peripherals, we want to enable it only when we actually do a transfer. To this end, this commit renames the `Target` trait mapping DMA targets to their channels to `OnChannel`. The new `Target` trait now provides methods to start and stop DMA on the implementing target, which are called when a `Transfer` starts or stops DMA.
1 parent 20d4b19 commit 0f1d6a3

File tree

2 files changed

+71
-22
lines changed

2 files changed

+71
-22
lines changed

src/dma.rs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,21 @@ pub trait DmaExt {
2727
fn split(self, ahb: &mut AHB) -> Self::Channels;
2828
}
2929

30+
/// Trait implemented by DMA targets.
31+
pub trait Target {
32+
/// Enable DMA on the target
33+
fn enable_dma(&mut self) {}
34+
/// Disable DMA on the target
35+
fn disable_dma(&mut self) {}
36+
}
37+
3038
/// An in-progress one-shot DMA transfer
31-
pub struct Transfer<B, C: Channel, T> {
39+
pub struct Transfer<B, C: Channel, T: Target> {
3240
// This is always a `Some` outside of `drop`.
3341
inner: Option<TransferInner<B, C, T>>,
3442
}
3543

36-
impl<B, C: Channel, T> Transfer<B, C, T> {
44+
impl<B, C: Channel, T: Target> Transfer<B, C, T> {
3745
/// Start a DMA write transfer.
3846
///
3947
/// # Panics
@@ -42,7 +50,7 @@ impl<B, C: Channel, T> Transfer<B, C, T> {
4250
pub fn start_write(mut buffer: B, mut channel: C, target: T) -> Self
4351
where
4452
B: WriteBuffer + 'static,
45-
T: Target<C>,
53+
T: OnChannel<C>,
4654
{
4755
// NOTE(unsafe) cannot call `&mut self` methods on `buffer` because its
4856
// concrete type is unknown here
@@ -65,7 +73,7 @@ impl<B, C: Channel, T> Transfer<B, C, T> {
6573
pub fn start_read(buffer: B, mut channel: C, target: T) -> Self
6674
where
6775
B: ReadBuffer + 'static,
68-
T: Target<C>,
76+
T: OnChannel<C>,
6977
{
7078
// NOTE(unsafe) cannot call `&mut self` methods on `buffer` because its
7179
// concrete type is unknown here
@@ -86,14 +94,15 @@ impl<B, C: Channel, T> Transfer<B, C, T> {
8694
///
8795
/// - the given buffer will be valid for the duration of the transfer
8896
/// - the DMA channel is configured correctly for the given target and buffer
89-
unsafe fn start(buffer: B, mut channel: C, target: T) -> Self
97+
unsafe fn start(buffer: B, mut channel: C, mut target: T) -> Self
9098
where
91-
T: Target<C>,
99+
T: OnChannel<C>,
92100
{
93101
assert!(!channel.is_enabled());
94102

95103
atomic::compiler_fence(Ordering::Release);
96104

105+
target.enable_dma();
97106
channel.enable();
98107

99108
Self {
@@ -127,7 +136,7 @@ impl<B, C: Channel, T> Transfer<B, C, T> {
127136
}
128137
}
129138

130-
impl<B, C: Channel, T> Drop for Transfer<B, C, T> {
139+
impl<B, C: Channel, T: Target> Drop for Transfer<B, C, T> {
131140
fn drop(&mut self) {
132141
if let Some(inner) = self.inner.as_mut() {
133142
inner.stop();
@@ -142,10 +151,12 @@ struct TransferInner<B, C, T> {
142151
target: T,
143152
}
144153

145-
impl<B, C: Channel, T> TransferInner<B, C, T> {
154+
impl<B, C: Channel, T: Target> TransferInner<B, C, T> {
146155
/// Stop this transfer
147156
fn stop(&mut self) {
148157
self.channel.disable();
158+
self.target.disable_dma();
159+
149160
atomic::compiler_fence(Ordering::SeqCst);
150161
}
151162
}
@@ -674,7 +685,6 @@ macro_rules! dma {
674685
};
675686
}
676687

677-
#[cfg(feature = "stm32f303")]
678688
dma!(
679689
DMA1, dma1, dma1en,
680690
channels: {
@@ -705,20 +715,25 @@ dma!(
705715
},
706716
);
707717

708-
/// Marker trait for DMA targets and their channels
709-
pub unsafe trait Target<C: Channel> {}
718+
/// Marker trait mapping DMA targets to their channels
719+
///
720+
/// # Safety
721+
///
722+
/// `C` must be the correct DMA channel for the peripheral implementing
723+
/// this trait.
724+
pub unsafe trait OnChannel<C: Channel>: Target {}
710725

711-
macro_rules! targets {
726+
macro_rules! on_channel {
712727
(
713728
$dma:ident,
714729
$( $target:ty => $C:ident, )+
715730
) => {
716-
$( unsafe impl Target<$dma::$C> for $target {} )+
731+
$( unsafe impl OnChannel<$dma::$C> for $target {} )+
717732
};
718733
}
719734

720735
#[cfg(feature = "stm32f303")]
721-
targets!(dma1,
736+
on_channel!(dma1,
722737
serial::Rx<pac::USART1> => C5,
723738
serial::Tx<pac::USART1> => C4,
724739
serial::Rx<pac::USART2> => C6,

src/serial.rs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::{
88
time::Bps,
99
};
1010
use core::{convert::Infallible, marker::PhantomData, ptr};
11+
use cortex_m::interrupt;
1112
use nb;
1213

1314
#[cfg(any(
@@ -39,7 +40,7 @@ use crate::gpio::gpiod;
3940
use crate::gpio::gpioe;
4041

4142
#[cfg(feature = "stm32f303")]
42-
pub use crate::dma;
43+
use crate::dma;
4344

4445
/// Interrupt event
4546
pub enum Event {
@@ -242,11 +243,6 @@ macro_rules! hal {
242243
// NOTE(write): uses all bits of this register.
243244
usart.brr.write(|w| unsafe { w.bits(brr) });
244245

245-
usart.cr3.modify(|_, w| {
246-
w.dmar().enabled(); // enable DMA for reception
247-
w.dmat().enabled() // enable DMA for transmission
248-
});
249-
250246
usart.cr1.modify(|_, w| {
251247
w.ue().enabled(); // enable USART
252248
w.re().enabled(); // enable receiver
@@ -377,7 +373,7 @@ macro_rules! hal {
377373
mut channel: C
378374
) -> dma::Transfer<B, C, Self>
379375
where
380-
Self: dma::Target<C>,
376+
Self: dma::OnChannel<C>,
381377
B: dma::WriteBuffer<Word = u8> + 'static,
382378
C: dma::Channel,
383379
{
@@ -398,7 +394,7 @@ macro_rules! hal {
398394
mut channel: C
399395
) -> dma::Transfer<B, C, Self>
400396
where
401-
Self: dma::Target<C>,
397+
Self: dma::OnChannel<C>,
402398
B: dma::ReadBuffer<Word = u8> + 'static,
403399
C: dma::Channel,
404400
{
@@ -409,6 +405,44 @@ macro_rules! hal {
409405
dma::Transfer::start_read(buffer, channel, self)
410406
}
411407
}
408+
409+
#[cfg(feature = "stm32f303")]
410+
impl dma::Target for Rx<$USARTX> {
411+
fn enable_dma(&mut self) {
412+
// NOTE(unsafe) critical section prevents races
413+
interrupt::free(|_| unsafe {
414+
let cr3 = &(*$USARTX::ptr()).cr3;
415+
cr3.modify(|_, w| w.dmar().enabled());
416+
});
417+
}
418+
419+
fn disable_dma(&mut self) {
420+
// NOTE(unsafe) critical section prevents races
421+
interrupt::free(|_| unsafe {
422+
let cr3 = &(*$USARTX::ptr()).cr3;
423+
cr3.modify(|_, w| w.dmar().disabled());
424+
});
425+
}
426+
}
427+
428+
#[cfg(feature = "stm32f303")]
429+
impl dma::Target for Tx<$USARTX> {
430+
fn enable_dma(&mut self) {
431+
// NOTE(unsafe) critical section prevents races
432+
interrupt::free(|_| unsafe {
433+
let cr3 = &(*$USARTX::ptr()).cr3;
434+
cr3.modify(|_, w| w.dmat().enabled());
435+
});
436+
}
437+
438+
fn disable_dma(&mut self) {
439+
// NOTE(unsafe) critical section prevents races
440+
interrupt::free(|_| unsafe {
441+
let cr3 = &(*$USARTX::ptr()).cr3;
442+
cr3.modify(|_, w| w.dmat().disabled());
443+
});
444+
}
445+
}
412446
)+
413447
}
414448
}

0 commit comments

Comments
 (0)