1use core::{marker::PhantomData, task::Poll};
11
12use embassy_hal_internal::{Peri, PeripheralType, interrupt::InterruptExt as _};
13use embassy_sync::waitqueue::AtomicWaker;
14
15use crate::{
16 event_link::{IcuInterrupt as _, InterruptEvent},
17 interrupt::typelevel::{Handler as InterruptHandler, Interrupt as InterruptType},
18 pac::{
19 self,
20 dmac::vals::{Dctg, Dm, Dts, Md, Sm, Sz},
21 },
22};
23
24pub struct DmacInterruptHandler<C: Instance> {
26 phantom: PhantomData<C>,
27}
28
29#[allow(private_bounds)]
31pub trait Instance: SealedInstance + Into<AnyChannel> {}
32
33pub(crate) trait SealedInstance: PeripheralType {
34 const INTERRUPT_EVENT: InterruptEvent;
35 const DMAC_INDEX: u8;
36 fn regs() -> pac::dmac::Dmac;
37}
38
39#[allow(private_bounds)]
43pub trait Word: SealedWord {}
44trait SealedWord: Copy {
45 const DMA_WIDTH: Sz;
46}
47
48#[derive(Debug, Clone, Copy)]
50pub struct AnyChannel {
51 pub(crate) dmac_index: u8,
52 pub(crate) interrupt_event: InterruptEvent,
53}
54
55impl<C: Instance, Int: InterruptType> InterruptHandler<Int> for DmacInterruptHandler<C> {
56 unsafe fn on_interrupt() {
57 Int::IRQ.icu_unpend();
58 DMAC_WAKERS[usize::from(C::DMAC_INDEX)].wake();
59 }
60}
61
62impl PeripheralType for AnyChannel {}
63
64const DMAC_COUNT: usize = 4;
65static DMAC_WAKERS: [AtomicWaker; DMAC_COUNT] = [const { AtomicWaker::new() }; DMAC_COUNT];
66
67pub struct Channel<'d> {
69 pub(crate) channel: Peri<'d, AnyChannel>,
70}
71
72impl AnyChannel {
73 #[inline(always)]
74 fn regs(&self) -> pac::dmac::Dmac {
75 let dmac_ptr = pac::DMAC0.as_ptr() as usize;
76 let offset = 0x40 * usize::from(self.dmac_index);
77 unsafe { crate::pac::dmac::Dmac::from_ptr(dmac_ptr.wrapping_add(offset) as _) }
78 }
79}
80
81pub struct Transfer<'d> {
83 channel: Channel<'d>,
84}
85
86impl<'d> Channel<'d> {
87 pub fn new<C: Instance, Int: InterruptType>(
89 channel: Peri<'d, C>,
90 irq: impl crate::interrupt::typelevel::Binding<Int, DmacInterruptHandler<C>> + 'd,
91 ) -> Self {
92 let _ = irq;
93
94 unsafe {
96 Int::IRQ.enable();
97 Int::IRQ.icu_enable(C::INTERRUPT_EVENT);
98 }
99
100 trace!("DMAC{}, enable={}", C::DMAC_INDEX, C::INTERRUPT_EVENT);
101
102 let dmac = C::regs();
103 dmac.dmint().modify(|r| {
104 r.set_rptie(true);
105 r.set_dtie(true);
106 });
107
108 Self {
109 channel: channel.into(),
110 }
111 }
112
113 #[inline]
115 pub fn reborrow(&mut self) -> Channel<'_> {
116 Channel {
117 channel: self.channel.reborrow(),
118 }
119 }
120
121 pub(crate) fn configure_peripheral_read<W: Word>(
126 &mut self,
127 src: *const W,
128 event: InterruptEvent,
129 ) {
130 let dmac = self.channel.regs();
131 let ctrl_block = cfg_select! {
132 ra8m1 => pac::DMA,
133 _ => pac::ICU,
134 };
135
136 dmac.dmamd().write(|r| {
137 r.set_sm(Sm::Fixed);
138 r.set_dm(Dm::Increment);
139 });
140 dmac.dmtmd().write(|r| {
141 r.set_sz(W::DMA_WIDTH);
142 r.set_md(Md::Normal);
143 r.set_dts(Dts::RepeatDestination);
144 r.set_dctg(Dctg::Interrupts);
145 });
146
147 ctrl_block.delsr(self.channel.dmac_index as _).write(|r| {
148 r.set_dels(event as u16);
149 });
150
151 dmac.dmsar().write_value(src as u32);
152 }
153
154 pub(crate) fn rearm<W: Word>(&mut self, dest: *mut W, len: usize) {
159 let dmac = self.channel.regs();
160 dmac.dmdar().write_value(dest as u32);
161 assert!(len <= usize::from(u16::MAX));
162 dmac.dmcra().write(|r| {
163 r.set_dmcrah(len as u16);
164 r.set_dmcral(len as u16);
165 });
166 dmac.dmcnt().write(|r| r.set_dte(true));
167 }
168
169 pub(crate) fn disable_dte(&mut self) {
171 self.channel.regs().dmcnt().write(|r| r.set_dte(false));
172 }
173
174 pub(crate) fn register_waker(&self, waker: &core::task::Waker) {
176 DMAC_WAKERS[usize::from(self.channel.dmac_index)].register(waker);
177 }
178
179 pub(crate) fn take_dtif(&self) -> bool {
181 let dmac = self.channel.regs();
182 if dmac.dmsts().read().dtif() {
183 dmac.dmsts().modify(|r| r.set_dtif(false));
184 true
185 } else {
186 false
187 }
188 }
189
190 pub fn write<W: Word>(
201 &mut self,
202 src: &[W],
203 dest: *mut W,
204 event: InterruptEvent,
205 ) -> Transfer<'_> {
206 let dmac = self.channel.regs();
207
208 let ctrl_block = cfg_select! {
209 ra8m1 => pac::DMA,
210 _ => pac::ICU,
211 };
212
213 dmac.dmamd().write(|r| {
214 r.set_sm(Sm::Increment);
215 r.set_dm(Dm::Fixed);
216 });
217 dmac.dmtmd().write(|r| {
218 r.set_sz(W::DMA_WIDTH);
219 r.set_md(Md::Normal);
220 r.set_dts(Dts::RepeatSource);
221 r.set_dctg(Dctg::Interrupts);
222 });
223
224 ctrl_block.delsr(self.channel.dmac_index as _).write(|r| {
225 r.set_dels(event as u16);
226 });
227
228 dmac.dmsar().write_value(src.as_ptr() as u32);
229 dmac.dmdar().write_value(dest as u32);
230 assert!(src.len() < usize::from(u16::MAX));
231 dmac.dmcra().write(|r| {
232 r.set_dmcrah(src.len() as u16);
233 r.set_dmcral(src.len() as u16);
234 });
235
236 dmac.dmcnt().modify(|r| r.set_dte(true));
237
238 Transfer {
239 channel: self.reborrow(),
240 }
241 }
242
243 pub fn read<W: Word>(
254 &mut self,
255 src: *const W,
256 dest: &mut [W],
257 event: InterruptEvent,
258 ) -> Transfer<'_> {
259 let dmac = self.channel.regs();
260 let ctrl_block = cfg_select! {
261 ra8m1 => pac::DMA,
262 _ => pac::ICU,
263 };
264
265 dmac.dmamd().write(|r| {
266 r.set_sm(Sm::Fixed);
267 r.set_dm(Dm::Increment);
268 });
269 dmac.dmtmd().write(|r| {
270 r.set_sz(W::DMA_WIDTH);
271 r.set_md(Md::Normal);
272 r.set_dts(Dts::RepeatDestination);
273 r.set_dctg(Dctg::Interrupts);
274 });
275
276 ctrl_block.delsr(self.channel.dmac_index as _).write(|r| {
277 r.set_dels(event as u16);
278 });
279
280 dmac.dmsar().write_value(src as u32);
281 dmac.dmdar().write_value(dest.as_mut_ptr() as u32);
282 assert!(dest.len() < usize::from(u16::MAX));
283 dmac.dmcra().write(|r| {
284 r.set_dmcrah(dest.len() as u16);
285 r.set_dmcral(dest.len() as u16);
286 });
287 dmac.dmcnt().write(|r| r.set_dte(true));
288
289 Transfer {
290 channel: self.reborrow(),
291 }
292 }
293}
294
295impl<'d> Future for Transfer<'d> {
296 type Output = ();
297
298 fn poll(
299 self: core::pin::Pin<&mut Self>,
300 ctx: &mut core::task::Context<'_>,
301 ) -> Poll<Self::Output> {
302 DMAC_WAKERS[usize::from(self.channel.channel.dmac_index)].register(ctx.waker());
303 let dmac = self.channel.channel.regs();
304 if dmac.dmsts().read().dtif() {
305 dmac.dmcnt().write(|r| r.set_dte(false));
306
307 #[cfg(feature = "cache")]
308 {
309 let fcache = pac::FCACHE;
310 fcache.fcacheiv().write(|r| r.set_fcacheiv(true));
311
312 while fcache.fcacheiv().read().fcacheiv() {}
313 }
314
315 Poll::Ready(())
316 } else {
317 Poll::Pending
318 }
319 }
320}
321
322impl<'d> Drop for Channel<'d> {
323 fn drop(&mut self) {
324 #[cfg(not(ra8m1))]
325 let block = pac::ICU;
326 #[cfg(ra8m1)]
327 let block = pac::DMA;
328
329 let index = self.channel.dmac_index;
330
331 block.delsr(index as _).write(|r| r.set_dels(0));
332 }
333}
334
335pub(crate) fn init() {
336 let dma = pac::DMA;
337 dma.dmast().write(|r| r.set_dmst(true));
338}
339
340macro_rules! dmac_chan {
341 ($index:literal) => {
342 paste::paste! {
343 impl crate::dmac::Instance for crate::peripherals::[< DMAC $index >] {}
344
345 impl crate::dmac::SealedInstance for crate::peripherals::[< DMAC $index >] {
346 const INTERRUPT_EVENT: InterruptEvent = crate::event_link::InterruptEvent::[< Dmac $index Int >];
347 const DMAC_INDEX: u8 = $index;
348
349 #[inline(always)]
350 fn regs() -> crate::pac::dmac::Dmac {
351 crate::pac::[< DMAC $index >]
352 }
353 }
354
355 impl From<crate::peripherals::[< DMAC $index >]> for AnyChannel {
356 fn from(_: crate::peripherals::[< DMAC $index >]) -> Self {
357 AnyChannel {
358 dmac_index: $index,
359 interrupt_event: crate::event_link::InterruptEvent::[< Dmac $index Int >],
360 }
361 }
362 }
363
364 }
365 };
366}
367
368dmac_chan!(0);
369dmac_chan!(1);
370dmac_chan!(2);
371dmac_chan!(3);
372
373impl Word for u8 {}
374impl SealedWord for u8 {
375 const DMA_WIDTH: Sz = Sz::_8bits;
376}
377
378impl Word for u16 {}
379impl SealedWord for u16 {
380 const DMA_WIDTH: Sz = Sz::_16bits;
381}
382
383impl Word for u32 {}
384impl SealedWord for u32 {
385 const DMA_WIDTH: Sz = Sz::_32bits;
386}