atsamd_hal/dmac/
dma_controller.rs1#![allow(unused_braces)]
22
23use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
24use core::marker::PhantomData;
25
26use modular_bitfield::prelude::*;
27use seq_macro::seq;
28
29#[hal_cfg(any("dmac-d11", "dmac-d21"))]
30pub use crate::pac::dmac::chctrlb::{
31 Lvlselect as PriorityLevel, Trigactselect as TriggerAction, Trigsrcselect as TriggerSource,
32};
33
34#[hal_cfg("dmac-d5x")]
35pub use crate::pac::dmac::channel::{
36 chctrla::{
37 Burstlenselect as BurstLength, Thresholdselect as FifoThreshold,
38 Trigactselect as TriggerAction, Trigsrcselect as TriggerSource,
39 },
40 chprilvl::Prilvlselect as PriorityLevel,
41};
42
43use super::{
44 channel::{Channel, Uninitialized},
45 sram,
46};
47use crate::{
48 pac::{Dmac, Pm},
49 typelevel::NoneT,
50};
51
52pub trait ChId {
54 const U8: u8;
55 const USIZE: usize;
56}
57
58#[bitfield]
60#[repr(u16)]
61pub struct PriorityLevelMask {
62 #[skip]
63 _reserved: B8,
64 pub level0: bool,
66 pub level1: bool,
68 pub level2: bool,
70 pub level3: bool,
72 #[skip]
73 _reserved: B4,
74}
75
76impl Default for PriorityLevelMask {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82#[bitfield]
84#[repr(u32)]
85pub struct RoundRobinMask {
86 #[skip]
87 _reserved: B7,
88 pub level0: bool,
90 #[skip]
91 _reserved: B7,
92 pub level1: bool,
94 #[skip]
95 _reserved: B7,
96 pub level2: bool,
98 #[skip]
99 _reserved: B7,
100 pub level3: bool,
102}
103
104impl Default for RoundRobinMask {
105 fn default() -> Self {
106 Self::new()
107 }
108}
109
110macro_rules! define_channels_struct {
111 ($num_channels:literal) => {
112 seq!(N in 0..$num_channels {
113 #(
114 pub enum Ch~N {}
116
117 impl ChId for Ch~N {
118 const U8: u8 = N;
119 const USIZE: usize = N;
120 }
121 )*
122
123 pub struct Channels(
125 #(
126 pub Channel<Ch~N, Uninitialized>,
127 )*
128 );
129 });
130 };
131}
132
133with_num_channels!(define_channels_struct);
134
135#[cfg(feature = "async")]
136macro_rules! define_channels_struct_future {
137 ($num_channels:literal) => {
138 seq!(N in 0..$num_channels {
139 pub struct FutureChannels(
141 #(
142 pub Channel<Ch~N, super::channel::UninitializedFuture>,
143 )*
144 );
145 });
146 };
147}
148
149#[cfg(feature = "async")]
150with_num_channels!(define_channels_struct_future);
151
152pub struct DmaController<I = NoneT> {
154 dmac: Dmac,
155 _irqs: PhantomData<I>,
156}
157
158impl DmaController {
159 #[inline]
164 #[hal_macro_helper]
165 pub fn init(mut dmac: Dmac, _pm: &mut Pm) -> Self {
166 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
168 {
169 _pm.ahbmask().modify(|_, w| w.dmac_().set_bit());
171 _pm.apbbmask().modify(|_, w| w.dmac_().set_bit());
172 }
173
174 Self::swreset(&mut dmac);
175
176 unsafe {
183 dmac.baseaddr()
184 .write(|w| w.baseaddr().bits(sram::descriptor_section_addr() as u32));
185 dmac.wrbaddr()
186 .write(|w| w.wrbaddr().bits(sram::writeback_addr() as u32));
187 }
188
189 dmac.ctrl().modify(|_, w| {
191 w.lvlen3().set_bit();
192 w.lvlen2().set_bit();
193 w.lvlen1().set_bit();
194 w.lvlen0().set_bit()
195 });
196
197 dmac.ctrl().modify(|_, w| w.dmaenable().set_bit());
199
200 Self {
201 dmac,
202 _irqs: PhantomData,
203 }
204 }
205
206 #[inline]
213 #[hal_macro_helper]
214 pub fn free(mut self, _channels: Channels, _pm: &mut Pm) -> Dmac {
215 self.dmac.ctrl().modify(|_, w| w.dmaenable().clear_bit());
216
217 Self::swreset(&mut self.dmac);
218
219 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
220 {
221 _pm.apbbmask().modify(|_, w| w.dmac_().clear_bit());
223 _pm.ahbmask().modify(|_, w| w.dmac_().clear_bit());
224 }
225
226 self.dmac
228 }
229}
230
231impl<T> DmaController<T> {
232 #[inline]
234 pub fn enable_levels(&mut self, mask: PriorityLevelMask) {
235 let mask: u16 = mask.into();
239 unsafe {
240 self.dmac.ctrl().modify(|r, w| w.bits(r.bits() | mask));
241 }
242 }
243
244 #[inline]
246 pub fn disable_levels(&mut self, mask: PriorityLevelMask) {
247 let mask: u16 = mask.into();
251 unsafe {
252 self.dmac.ctrl().modify(|r, w| w.bits(r.bits() & !mask));
253 }
254 }
255
256 #[inline]
259 pub fn round_robin_arbitration(&mut self, mask: RoundRobinMask) {
260 let mask: u32 = mask.into();
264 unsafe {
265 self.dmac.prictrl0().modify(|r, w| w.bits(r.bits() | mask));
266 }
267 }
268
269 #[inline]
272 pub fn static_arbitration(&mut self, mask: RoundRobinMask) {
273 let mask: u32 = mask.into();
277 unsafe {
278 self.dmac.prictrl0().modify(|r, w| w.bits(r.bits() & !mask));
279 }
280 }
281
282 #[cfg(feature = "async")]
292 #[inline]
293 pub fn into_future<I>(self, _interrupts: I) -> DmaController<I>
294 where
295 I: crate::async_hal::interrupts::Binding<
296 crate::async_hal::interrupts::DMAC,
297 super::async_api::InterruptHandler,
298 >,
299 {
300 use crate::async_hal::interrupts::{DMAC, InterruptSource};
301
302 DMAC::unpend();
303 unsafe { DMAC::enable() };
304
305 DmaController {
306 dmac: self.dmac,
307 _irqs: PhantomData,
308 }
309 }
310
311 #[inline]
313 fn swreset(dmac: &mut Dmac) {
314 dmac.ctrl().modify(|_, w| w.swrst().set_bit());
315 while dmac.ctrl().read().swrst().bit_is_set() {}
316 }
317}
318
319#[cfg(feature = "async")]
320impl<I> DmaController<I>
321where
322 I: crate::async_hal::interrupts::Binding<
323 crate::async_hal::interrupts::DMAC,
324 super::async_api::InterruptHandler,
325 >,
326{
327 #[inline]
334 #[hal_macro_helper]
335 pub fn free(mut self, _channels: FutureChannels, _pm: &mut Pm) -> Dmac {
336 self.dmac.ctrl().modify(|_, w| w.dmaenable().clear_bit());
337
338 Self::swreset(&mut self.dmac);
339
340 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
341 {
342 _pm.apbbmask().modify(|_, w| w.dmac_().clear_bit());
344 _pm.ahbmask().modify(|_, w| w.dmac_().clear_bit());
345 }
346
347 self.dmac
349 }
350}
351
352macro_rules! define_split {
353 ($num_channels:literal) => {
354 seq!(N in 0..$num_channels {
355 #[inline]
357 pub fn split(&mut self) -> Channels {
358 Channels(
359 #(
360 crate::dmac::channel::new_chan(core::marker::PhantomData),
361 )*
362 )
363 }
364 });
365 };
366}
367
368impl DmaController {
369 with_num_channels!(define_split);
370}
371
372#[cfg(feature = "async")]
373macro_rules! define_split_future {
374 ($num_channels:literal) => {
375 seq!(N in 0..$num_channels {
376 #[inline]
378 pub fn split(&mut self) -> FutureChannels {
379 FutureChannels(
380 #(
381 crate::dmac::channel::new_chan_future(core::marker::PhantomData),
382 )*
383 )
384 }
385 });
386 };
387}
388
389#[cfg(feature = "async")]
390impl<I> DmaController<I>
391where
392 I: crate::async_hal::interrupts::Binding<
393 crate::async_hal::interrupts::DMAC,
394 super::async_api::InterruptHandler,
395 >,
396{
397 with_num_channels!(define_split_future);
398}