1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
|
#![macro_use]
use core::cell::RefCell;
use core::future::Future;
use core::pin::Pin;
use core::sync::atomic::{Ordering, compiler_fence};
use core::task::{Context, Poll};
use critical_section::Mutex;
use embassy_hal_internal::interrupt::InterruptExt;
use embassy_hal_internal::{PeripheralType, impl_peripheral};
use embassy_sync::waitqueue::AtomicWaker;
use crate::Peri;
#[cfg(feature = "rt")]
use crate::pac::interrupt;
use crate::pac::{SYSCON, *};
#[cfg(feature = "rt")]
#[interrupt]
fn DMA0() {
let inta = DMA0.inta0().read().ia();
for channel in 0..CHANNEL_COUNT {
if (DMA0.errint0().read().err() & (1 << channel)) != 0 {
panic!("DMA: error on DMA_0 channel {}", channel);
}
if (inta & (1 << channel)) != 0 {
CHANNEL_WAKERS[channel].wake();
DMA0.inta0().modify(|w| w.set_ia(1 << channel));
}
}
}
pub(crate) fn init() {
assert_eq!(core::mem::size_of::<DmaDescriptor>(), 16, "Descriptor must be 16 bytes");
assert_eq!(
core::mem::align_of::<DmaDescriptor>(),
16,
"Descriptor must be 16-byte aligned"
);
assert_eq!(
core::mem::align_of::<DmaDescriptorTable>(),
512,
"Table must be 512-byte aligned"
);
// Start clock for DMA
SYSCON.ahbclkctrl0().modify(|w| w.set_dma0(true));
// Reset DMA
SYSCON
.presetctrl0()
.modify(|w| w.set_dma0_rst(syscon::vals::Dma0Rst::ASSERTED));
SYSCON
.presetctrl0()
.modify(|w| w.set_dma0_rst(syscon::vals::Dma0Rst::RELEASED));
// Address bits 31:9 of the beginning of the DMA descriptor table
critical_section::with(|cs| {
DMA0.srambase()
.write(|w| w.set_offset((DMA_DESCRIPTORS.borrow(cs).as_ptr() as u32) >> 9));
});
// Enable DMA controller
DMA0.ctrl().modify(|w| w.set_enable(true));
unsafe {
crate::pac::interrupt::DMA0.enable();
}
info!("DMA initialized");
}
/// DMA read.
///
/// SAFETY: Slice must point to a valid location reachable by DMA.
pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> {
copy_inner(
ch,
from as *const u32,
to as *mut W as *mut u32,
to.len(),
W::size(),
false,
true,
)
}
/// DMA write.
///
/// SAFETY: Slice must point to a valid location reachable by DMA.
pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> {
copy_inner(
ch,
from as *const W as *const u32,
to as *mut u32,
from.len(),
W::size(),
true,
false,
)
}
/// DMA copy between slices.
///
/// SAFETY: Slices must point to locations reachable by DMA.
pub unsafe fn copy<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: &[W], to: &mut [W]) -> Transfer<'a, C> {
let from_len = from.len();
let to_len = to.len();
assert_eq!(from_len, to_len);
copy_inner(
ch,
from.as_ptr() as *const u32,
to.as_mut_ptr() as *mut u32,
from_len,
W::size(),
true,
true,
)
}
fn copy_inner<'a, C: Channel>(
ch: Peri<'a, C>,
from: *const u32,
to: *mut u32,
len: usize,
data_size: crate::pac::dma::vals::Width,
incr_src: bool,
incr_dest: bool,
) -> Transfer<'a, C> {
let p = ch.regs();
// Buffer ending address = buffer starting address + (XFERCOUNT * the transfer increment)
// XREFCOUNT = the number of transfers performed - 1.
// The 1st transfer is included in the starting address.
let source_end_addr = if incr_src {
from as u32 + len as u32 - 1
} else {
from as u32
};
let dest_end_addr = if incr_dest {
to as u32 + len as u32 - 1
} else {
to as u32
};
compiler_fence(Ordering::SeqCst);
critical_section::with(|cs| {
DMA_DESCRIPTORS.borrow(cs).borrow_mut().descriptors[ch.number() as usize] = DmaDescriptor {
reserved: 0,
source_end_addr,
dest_end_addr,
next_desc: 0, // Since only single transfers are made, there is no need for reload descriptor address.
}
});
compiler_fence(Ordering::SeqCst);
p.cfg().modify(|w| {
// Peripheral DMA requests are enabled.
// DMA requests that pace transfers can be interpreted then.
w.set_periphreqen(true);
// There is no need to have them on.
// No complex transfers are performed for now.
w.set_hwtrigen(false);
w.set_chpriority(0);
});
p.xfercfg().modify(|w| {
// This bit indicates whether the current channel descriptor is
// valid and can potentially be acted upon,
// if all other activation criteria are fulfilled.
w.set_cfgvalid(true);
// Indicates whether the channel’s control structure will be reloaded
// when the current descriptor is exhausted.
// Reloading allows ping-pong and linked transfers.
w.set_reload(false);
// There is no hardware distinction between interrupt A and B.
// They can be used by software to assist with more complex descriptor usage.
// By convention, interrupt A may be used when only one interrupt flag is needed.
w.set_setinta(true);
w.set_setintb(false);
w.set_width(data_size);
w.set_srcinc(if incr_src {
dma::vals::Srcinc::WIDTH_X_1
} else {
dma::vals::Srcinc::NO_INCREMENT
});
w.set_dstinc(if incr_dest {
dma::vals::Dstinc::WIDTH_X_1
} else {
dma::vals::Dstinc::NO_INCREMENT
});
// Total number of transfers to be performed, minus 1 encoded.
w.set_xfercount((len as u16) - 1);
// Before triggering the channel, it has to be enabled.
w.set_swtrig(false);
});
compiler_fence(Ordering::SeqCst);
DMA0.enableset0().write(|w| w.set_ena(1 << ch.number()));
DMA0.intenset0().write(|w| w.set_inten(1 << ch.number()));
compiler_fence(Ordering::SeqCst);
// Start transfer.
DMA0.settrig0().write(|w| w.set_trig(1 << ch.number()));
compiler_fence(Ordering::SeqCst);
Transfer::new(ch)
}
/// DMA transfer driver.
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Transfer<'a, C: Channel> {
channel: Peri<'a, C>,
}
impl<'a, C: Channel> Transfer<'a, C> {
pub(crate) fn new(channel: Peri<'a, C>) -> Self {
Self { channel }
}
}
impl<'a, C: Channel> Drop for Transfer<'a, C> {
fn drop(&mut self) {
DMA0.enableclr0().write(|w| w.set_clr(1 << self.channel.number()));
while (DMA0.busy0().read().bsy() & (1 << self.channel.number())) != 0 {}
DMA0.abort0().write(|w| w.set_abortctrl(1 << self.channel.number()));
}
}
impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
impl<'a, C: Channel> Future for Transfer<'a, C> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// We need to register/re-register the waker for each poll because any
// calls to wake will deregister the waker.
CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
// Check if it is busy or not.
if (DMA0.busy0().read().bsy() & (1 << self.channel.number())) != 0 {
Poll::Pending
} else {
Poll::Ready(())
}
}
}
// Total number of channles including both DMA0 and DMA1.
// In spite of using only DMA0 channels, the descriptor table
// should be of this size.
pub(crate) const CHANNEL_COUNT: usize = 32;
static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
// See section 22.5.2 (table 450)
// UM11126, Rev. 2.8
// The size of a descriptor must be aligned to a multiple of 16 bytes.
#[repr(C, align(16))]
#[derive(Clone, Copy)]
struct DmaDescriptor {
/// 0x0 Reserved.
reserved: u32,
/// 0x4 Source data end address.
source_end_addr: u32,
/// 0x8 Destination end address.
dest_end_addr: u32,
/// 0xC Link to next descriptor.
next_desc: u32,
}
// See section 22.6.3
// UM11126, Rev. 2.8
// The table must begin on a 512 byte boundary.
#[repr(C, align(512))]
struct DmaDescriptorTable {
descriptors: [DmaDescriptor; CHANNEL_COUNT],
}
// DMA descriptors are stored in on-chip SRAM.
static DMA_DESCRIPTORS: Mutex<RefCell<DmaDescriptorTable>> = Mutex::new(RefCell::new(DmaDescriptorTable {
descriptors: [DmaDescriptor {
reserved: 0,
source_end_addr: 0,
dest_end_addr: 0,
next_desc: 0,
}; CHANNEL_COUNT],
}));
pub(crate) trait SealedChannel {}
trait SealedWord {}
/// DMA channel interface.
#[allow(private_bounds)]
pub trait Channel: PeripheralType + SealedChannel + Into<AnyChannel> + Sized + 'static {
/// Channel number.
fn number(&self) -> u8;
/// Channel registry block.
fn regs(&self) -> crate::pac::dma::Channel {
crate::pac::DMA0.channel(self.number() as _)
}
}
/// DMA word.
#[allow(private_bounds)]
pub trait Word: SealedWord {
/// Word size.
fn size() -> crate::pac::dma::vals::Width;
}
impl SealedWord for u8 {}
impl Word for u8 {
fn size() -> crate::pac::dma::vals::Width {
crate::pac::dma::vals::Width::BIT_8
}
}
impl SealedWord for u16 {}
impl Word for u16 {
fn size() -> crate::pac::dma::vals::Width {
crate::pac::dma::vals::Width::BIT_16
}
}
impl SealedWord for u32 {}
impl Word for u32 {
fn size() -> crate::pac::dma::vals::Width {
crate::pac::dma::vals::Width::BIT_32
}
}
/// Type erased DMA channel.
pub struct AnyChannel {
pub(crate) number: u8,
}
impl_peripheral!(AnyChannel);
impl SealedChannel for AnyChannel {}
impl Channel for AnyChannel {
fn number(&self) -> u8 {
self.number
}
}
macro_rules! impl_dma_channel {
($instance:ident, $name:ident, $num:expr) => {
impl crate::dma::SealedChannel for crate::peripherals::$name {}
impl crate::dma::Channel for crate::peripherals::$name {
fn number(&self) -> u8 {
$num
}
}
impl From<peripherals::$name> for crate::dma::AnyChannel {
fn from(val: peripherals::$name) -> Self {
use crate::dma::Channel;
Self { number: val.number() }
}
}
};
}
|