1use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
14
15use super::super::dma_controller::ChId;
16use core::marker::PhantomData;
17use paste::paste;
18
19use crate::pac::{
20 self, Dmac, Peripherals,
21 dmac::{Busych, Intstatus, Pendch, Swtrigctrl},
22 dmac::{
23 busych::BusychSpec, intstatus::IntstatusSpec, pendch::PendchSpec,
24 swtrigctrl::SwtrigctrlSpec,
25 },
26};
27
28#[hal_cfg(any("dmac-d11", "dmac-d21"))]
29use pac::dmac as channel_regs;
30
31#[hal_cfg("dmac-d5x")]
32use pac::dmac::channel as channel_regs;
33
34use channel_regs::{
35 Chctrla, Chctrlb, Chintenclr, Chintenset, Chintflag, Chstatus, chctrla::ChctrlaSpec,
36 chctrlb::ChctrlbSpec, chintenclr::ChintenclrSpec, chintenset::ChintensetSpec,
37 chintflag::ChintflagSpec, chstatus::ChstatusSpec,
38};
39
40#[hal_cfg("dmac-d5x")]
41use pac::dmac::channel::{Chprilvl, chprilvl::ChprilvlSpec};
42
43pub(super) trait Register<Id: ChId> {
48 fn dmac(&self) -> &Dmac;
50
51 #[hal_cfg(any("dmac-d11", "dmac-d21"))]
58 #[inline]
59 fn with_chid<F: FnOnce(&Dmac) -> R, R>(&mut self, fun: F) -> R {
60 let dmac = self.dmac();
69
70 let mut old_id = 0;
71
72 dmac.chid().modify(|r, w| {
73 old_id = r.id().bits();
75 unsafe { w.id().bits(Id::U8) }
77 });
78
79 let ret = fun(dmac);
81 unsafe { dmac.chid().write(|w| w.id().bits(old_id)) };
85
86 ret
87 }
88
89 #[hal_cfg("dmac-d5x")]
94 #[inline]
95 fn with_chid<F: FnOnce(&pac::dmac::Channel) -> R, R>(&mut self, fun: F) -> R {
96 let ch = &self.dmac().channel(Id::USIZE);
104 fun(ch)
105 }
106}
107
108macro_rules! reg_proxy {
109 (@new $reg:ident) => {
110 paste! {
111 pub(super) struct [< $reg:camel Proxy >]<Id: ChId, REG> {
113 #[allow(unused)]
114 dmac: Dmac,
115 _id: PhantomData<Id>,
116 _reg: PhantomData<REG>,
117 }
118
119 impl<Id: ChId> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
120 #[inline]
122 pub fn new() -> Self {
123 Self {
124 dmac: unsafe { Peripherals::steal().dmac },
128 _id: PhantomData,
129 _reg: PhantomData,
130 }
131 }
132 }
133 }
134 };
135
136 (@read_reg $reg:ident) => {
138 paste! {
139 impl<Id: ChId> Register<Id> for [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
140 fn dmac(&self) -> &Dmac {
141 &self.dmac
142 }
143 }
144
145 impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec>]: pac::generic::Readable {
146 #[inline]
147 #[allow(dead_code)]
148 pub fn read(&mut self) -> channel_regs::[< $reg:lower >]::R {
149 self.with_chid(|d| d.[< $reg:lower >]().read())
150 }
151 }
152 }
153 };
154
155 ($reg:ident, register, r) => {
157 paste! {
158
159 reg_proxy!(@new $reg);
160 reg_proxy!(@read_reg $reg);
161 }
162 };
163
164 ($reg:ident, register, rw) => {
166 paste! {
167 reg_proxy!(@new $reg);
168 reg_proxy!(@read_reg $reg);
169
170 impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec >]: pac::generic::Writable {
171 #[inline]
172 #[allow(dead_code)]
173 pub fn write<F>(&mut self, func: F)
174 where
175 for<'w> F: FnOnce(&'w mut channel_regs::[< $reg:lower >]::W) -> &'w mut channel_regs::[< $reg:lower >]::W,
176 {
177 self.with_chid(|d| d.[< $reg:lower >]().write(|w| func(w)));
178 }
179 }
180
181 impl<Id>[< $reg:camel Proxy >]<Id, [< $reg:camel >]> where
182 Id: ChId,
183 [< $reg:camel Spec >]: pac::generic::Writable + pac::generic::Readable
184 {
185 #[inline]
186 #[allow(dead_code)]
187 pub fn modify<F>(&mut self, func: F)
188 where
189 for<'w> F: FnOnce(
190 &channel_regs::[< $reg:lower >]::R,
191 &'w mut channel_regs::[< $reg:lower >]::W
192 ) -> &'w mut channel_regs::[< $reg:lower >]::W,
193 {
194 self.with_chid(|d| d.[< $reg:lower >]().modify(|r, w| func(r, w)));
195 }
196 }
197 }
198 };
199
200 (@read_bit $reg:ident) => {
202 paste! {
203 impl<Id: ChId> Register<Id> for [< $reg:camel Proxy >]<Id, [< $reg:camel >]> {
204 fn dmac(&self) -> &Dmac {
205 &self.dmac
206 }
207 }
208
209 impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where Id: ChId, [< $reg:camel Spec >]: pac::generic::Readable {
210 #[inline]
211 #[allow(dead_code)]
212 pub fn read_bit(&self) -> bool {
213 self.dmac.[< $reg:lower >]().read().bits() & (1 << Id::U8) != 0
214 }
215 }
216 }
217 };
218
219 ($reg:ident, bit, r) => {
221 paste! {
222 reg_proxy!(@new $reg);
223 reg_proxy!(@read_bit $reg);
224 }
225 };
226
227 ($reg:ident, bit, rw) => {
229 paste! {
230 reg_proxy!(@new $reg);
231 reg_proxy!(@read_bit $reg);
232
233 impl<Id> [< $reg:camel Proxy >]<Id, [< $reg:camel >]> where
234 Id: ChId,
235 [< $reg:camel Spec >]: pac::generic::Readable + pac::generic::Writable
236 {
237 #[inline]
238 #[allow(dead_code)]
239 pub fn set_bit(&mut self) {
240 unsafe {
243 self.dmac.[< $reg:lower >]().modify(|r, w| w.bits(r.bits() | (1 << Id::U8)));
244 }
245 }
246
247 #[inline]
248 #[allow(dead_code)]
249 pub fn clear_bit(&mut self) {
250 unsafe {
253 self.dmac.[< $reg:lower >]().modify(|r, w| w.bits(r.bits() & !(1 << Id::U8)));
254 }
255 }
256 }
257 }
258 };
259}
260
261reg_proxy!(chctrla, register, rw);
262reg_proxy!(chctrlb, register, rw);
263reg_proxy!(chintenclr, register, rw);
264reg_proxy!(chintenset, register, rw);
265reg_proxy!(chintflag, register, rw);
266reg_proxy!(chstatus, register, r);
267#[hal_cfg("dmac-d5x")]
268reg_proxy!(chprilvl, register, rw);
269
270reg_proxy!(intstatus, bit, r);
271reg_proxy!(busych, bit, r);
272reg_proxy!(pendch, bit, r);
273reg_proxy!(swtrigctrl, bit, rw);
274
275#[allow(dead_code)]
282#[hal_macro_helper]
283pub(super) struct RegisterBlock<Id: ChId> {
284 pub chctrla: ChctrlaProxy<Id, Chctrla>,
285 pub chctrlb: ChctrlbProxy<Id, Chctrlb>,
286 pub chintenclr: ChintenclrProxy<Id, Chintenclr>,
287 pub chintenset: ChintensetProxy<Id, Chintenset>,
288 pub chintflag: ChintflagProxy<Id, Chintflag>,
289 pub chstatus: ChstatusProxy<Id, Chstatus>,
290 pub intstatus: IntstatusProxy<Id, Intstatus>,
291 pub busych: BusychProxy<Id, Busych>,
292 pub pendch: PendchProxy<Id, Pendch>,
293 pub swtrigctrl: SwtrigctrlProxy<Id, Swtrigctrl>,
294 #[hal_cfg("dmac-d5x")]
295 pub chprilvl: ChprilvlProxy<Id, Chprilvl>,
296}
297
298impl<Id: ChId> RegisterBlock<Id> {
299 #[hal_macro_helper]
300 pub(super) fn new(_id: PhantomData<Id>) -> Self {
301 Self {
302 chctrla: ChctrlaProxy::new(),
303 chctrlb: ChctrlbProxy::new(),
304 chintenclr: ChintenclrProxy::new(),
305 chintenset: ChintensetProxy::new(),
306 chintflag: ChintflagProxy::new(),
307 chstatus: ChstatusProxy::new(),
308 intstatus: IntstatusProxy::new(),
309 busych: BusychProxy::new(),
310 pendch: PendchProxy::new(),
311 swtrigctrl: SwtrigctrlProxy::new(),
312 #[hal_cfg("dmac-d5x")]
313 chprilvl: ChprilvlProxy::new(),
314 }
315 }
316}
317
318impl<Id: ChId> Drop for RegisterBlock<Id> {
319 fn drop(&mut self) {
320 self.chctrla.modify(|_, w| w.enable().clear_bit());
322
323 while self.chctrla.read().enable().bit_is_set() {
324 core::hint::spin_loop();
325 }
326
327 core::sync::atomic::fence(core::sync::atomic::Ordering::Acquire); }
332}