Skip to content

Commit 053fa02

Browse files
committed
gpdma: implement futures and IRQ handling for GPDMA
1 parent 95e3f78 commit 053fa02

File tree

4 files changed

+170
-1
lines changed

4 files changed

+170
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ embedded-hal = "1.0.0"
7171
defmt = { version = "1.0.0", optional = true }
7272
paste = "1.0.15"
7373
log = { version = "0.4.20", optional = true}
74+
futures-util = { version = "0.3", default-features = false, features = ["async-await-macro"]}
7475
stm32-usbd = "0.8.0"
7576

7677
[dev-dependencies]

src/gpdma.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ use embedded_dma::{ReadBuffer, Word as DmaWord, WriteBuffer};
8989

9090
mod ch;
9191
pub mod config;
92+
mod future;
9293
pub mod periph;
9394

9495
pub use ch::{

src/gpdma/ch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use super::{
1515
DmaConfig, Error, Instance, Word,
1616
};
1717

18-
trait ChannelRegs: Sealed {
18+
pub(super) trait ChannelRegs: Sealed {
1919
#[allow(unused)] // TODO: this will be used for linked-list transfers
2020
fn lbar(&self) -> &LBAR;
2121
fn fcr(&self) -> &FCR;

src/gpdma/future.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
use core::{
2+
future::{Future, IntoFuture},
3+
ops::{Deref, DerefMut},
4+
pin::Pin,
5+
task::{Context, Poll},
6+
};
7+
8+
use futures_util::task::AtomicWaker;
9+
10+
use crate::interrupt;
11+
use crate::stm32::{GPDMA1, GPDMA2};
12+
13+
use super::{
14+
ch::{
15+
ChannelRegs, DmaChannel, DmaChannel0, DmaChannel1, DmaChannel2,
16+
DmaChannel3, DmaChannel4, DmaChannel5, DmaChannel6, DmaChannel7,
17+
DmaChannelImpl, DmaChannelRef,
18+
},
19+
DmaTransfer, Error, Instance,
20+
};
21+
22+
#[allow(private_bounds)]
23+
impl<'a, CH: DmaChannel + ChannelWaker> IntoFuture for DmaTransfer<'a, CH> {
24+
type Output = Result<(), Error>;
25+
type IntoFuture = DmaTransferFuture<'a, CH>;
26+
27+
fn into_future(self) -> DmaTransferFuture<'a, CH> {
28+
DmaTransferFuture { transfer: self }
29+
}
30+
}
31+
32+
pub struct DmaTransferFuture<'a, CH: DmaChannel> {
33+
transfer: DmaTransfer<'a, CH>,
34+
}
35+
36+
impl<'a, CH> Deref for DmaTransferFuture<'a, CH>
37+
where
38+
CH: DmaChannel,
39+
{
40+
type Target = DmaTransfer<'a, CH>;
41+
42+
fn deref(&self) -> &Self::Target {
43+
&self.transfer
44+
}
45+
}
46+
47+
impl<'a, CH> DerefMut for DmaTransferFuture<'a, CH>
48+
where
49+
CH: DmaChannel,
50+
{
51+
fn deref_mut(&mut self) -> &mut Self::Target {
52+
&mut self.transfer
53+
}
54+
}
55+
56+
impl<'a, CH> Drop for DmaTransferFuture<'a, CH>
57+
where
58+
CH: DmaChannel,
59+
{
60+
fn drop(&mut self) {
61+
match self.abort() {
62+
Ok(()) => {}
63+
Err(_error) => {
64+
#[cfg(feature = "log")]
65+
log::error!("Error aborting DMA transfer: {_error:?}");
66+
}
67+
}
68+
self.disable_interrupts();
69+
}
70+
}
71+
72+
impl<'a, CH: DmaChannel> Unpin for DmaTransferFuture<'a, CH> {}
73+
74+
impl<'a, CH> Future for DmaTransferFuture<'a, CH>
75+
where
76+
CH: DmaChannel + ChannelWaker,
77+
{
78+
type Output = Result<(), Error>;
79+
80+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
81+
self.channel.waker().register(cx.waker());
82+
if self.is_transfer_complete()? {
83+
Poll::Ready(Ok(()))
84+
} else {
85+
Poll::Pending
86+
}
87+
}
88+
}
89+
90+
#[allow(private_bounds)]
91+
impl<DMA, CH, const N: usize> DmaChannelImpl<DmaChannelRef<DMA, CH, N>>
92+
where
93+
DMA: Instance,
94+
CH: ChannelRegs,
95+
Self: ChannelWaker,
96+
DmaChannelRef<DMA, CH, N>: ChannelRegs,
97+
{
98+
#[inline(always)]
99+
fn handle_interrupt() {
100+
let ch = Self::new();
101+
ch.waker().wake();
102+
ch.disable_transfer_interrupts();
103+
}
104+
}
105+
106+
macro_rules! gpdma_irq {
107+
($GPDMA:ident, $CH:literal) => {
108+
paste::item! {
109+
#[interrupt]
110+
fn [<$GPDMA _CH $CH>]() {
111+
[< DmaChannel $CH>]::<$GPDMA>::handle_interrupt();
112+
}
113+
}
114+
};
115+
}
116+
117+
trait ChannelWaker {
118+
fn waker(&self) -> &'static AtomicWaker;
119+
}
120+
121+
mod gpdma1 {
122+
use super::*;
123+
124+
static WAKERS_GPDMA1: [AtomicWaker; 8] = [const { AtomicWaker::new() }; 8];
125+
126+
#[allow(private_bounds)]
127+
impl<CH: ChannelRegs, const N: usize> ChannelWaker
128+
for DmaChannelImpl<DmaChannelRef<GPDMA1, CH, N>>
129+
{
130+
fn waker(&self) -> &'static AtomicWaker {
131+
&WAKERS_GPDMA1[N]
132+
}
133+
}
134+
135+
gpdma_irq!(GPDMA1, 0);
136+
gpdma_irq!(GPDMA1, 1);
137+
gpdma_irq!(GPDMA1, 2);
138+
gpdma_irq!(GPDMA1, 3);
139+
gpdma_irq!(GPDMA1, 4);
140+
gpdma_irq!(GPDMA1, 5);
141+
gpdma_irq!(GPDMA1, 6);
142+
gpdma_irq!(GPDMA1, 7);
143+
}
144+
145+
mod gpdma2 {
146+
use super::*;
147+
148+
static WAKERS_GPDMA2: [AtomicWaker; 8] = [const { AtomicWaker::new() }; 8];
149+
150+
#[allow(private_bounds)]
151+
impl<CH: ChannelRegs, const N: usize> ChannelWaker
152+
for DmaChannelImpl<DmaChannelRef<GPDMA2, CH, N>>
153+
{
154+
fn waker(&self) -> &'static AtomicWaker {
155+
&WAKERS_GPDMA2[N]
156+
}
157+
}
158+
159+
gpdma_irq!(GPDMA2, 0);
160+
gpdma_irq!(GPDMA2, 1);
161+
gpdma_irq!(GPDMA2, 2);
162+
gpdma_irq!(GPDMA2, 3);
163+
gpdma_irq!(GPDMA2, 4);
164+
gpdma_irq!(GPDMA2, 5);
165+
gpdma_irq!(GPDMA2, 6);
166+
gpdma_irq!(GPDMA2, 7);
167+
}

0 commit comments

Comments
 (0)