aboutsummaryrefslogtreecommitdiff
path: root/tests/mspm0/src/bin/dma.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/mspm0/src/bin/dma.rs')
-rw-r--r--tests/mspm0/src/bin/dma.rs503
1 files changed, 503 insertions, 0 deletions
diff --git a/tests/mspm0/src/bin/dma.rs b/tests/mspm0/src/bin/dma.rs
new file mode 100644
index 000000000..6fd973a18
--- /dev/null
+++ b/tests/mspm0/src/bin/dma.rs
@@ -0,0 +1,503 @@
1#![no_std]
2#![no_main]
3
4#[cfg(feature = "mspm0g3507")]
5teleprobe_meta::target!(b"lp-mspm0g3507");
6
7#[cfg(feature = "mspm0g3519")]
8teleprobe_meta::target!(b"lp-mspm0g3519");
9
10use core::slice;
11
12use defmt::{assert, assert_eq, *};
13use embassy_executor::Spawner;
14use embassy_mspm0::dma::{Channel, Transfer, TransferMode, TransferOptions, Word};
15use embassy_mspm0::Peri;
16use {defmt_rtt as _, panic_probe as _};
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let mut p = embassy_mspm0::init(Default::default());
21 info!("Hello World!");
22
23 {
24 info!("Single u8 read (blocking)");
25 single_read(p.DMA_CH0.reborrow(), 0x41_u8);
26
27 info!("Single u16 read (blocking)");
28 single_read(p.DMA_CH0.reborrow(), 0xFF41_u16);
29
30 info!("Single u32 read (blocking)");
31 single_read(p.DMA_CH0.reborrow(), 0xFFEE_FF41_u32);
32
33 info!("Single u64 read (blocking)");
34 single_read(p.DMA_CH0.reborrow(), 0x0011_2233_FFEE_FF41_u64);
35 }
36
37 // Widening transfers
38 {
39 info!("Single u8 read to u16");
40 widening_single_read::<u8, u16>(p.DMA_CH0.reborrow(), 0x41);
41
42 info!("Single u8 read to u32");
43 widening_single_read::<u8, u32>(p.DMA_CH0.reborrow(), 0x43);
44
45 info!("Single u8 read to u64");
46 widening_single_read::<u8, u64>(p.DMA_CH0.reborrow(), 0x47);
47
48 info!("Single u16 read to u32");
49 widening_single_read::<u16, u32>(p.DMA_CH0.reborrow(), 0xAE43);
50
51 info!("Single u16 read to u64");
52 widening_single_read::<u16, u64>(p.DMA_CH0.reborrow(), 0xAF47);
53
54 info!("Single u32 read to u64");
55 widening_single_read::<u32, u64>(p.DMA_CH0.reborrow(), 0xDEAD_AF47);
56 }
57
58 // Narrowing transfers.
59 {
60 info!("Single u16 read to u8");
61 narrowing_single_read::<u16, u8>(p.DMA_CH0.reborrow(), 0x4142);
62
63 info!("Single u32 read to u8");
64 narrowing_single_read::<u32, u8>(p.DMA_CH0.reborrow(), 0x4142_2414);
65
66 info!("Single u64 read to u8");
67 narrowing_single_read::<u64, u8>(p.DMA_CH0.reborrow(), 0x4142_2414_5153_7776);
68
69 info!("Single u32 read to u16");
70 narrowing_single_read::<u32, u16>(p.DMA_CH0.reborrow(), 0x4142_2414);
71
72 info!("Single u64 read to u16");
73 narrowing_single_read::<u64, u16>(p.DMA_CH0.reborrow(), 0x4142_2414_5153_7776);
74
75 info!("Single u64 read to u32");
76 narrowing_single_read::<u64, u32>(p.DMA_CH0.reborrow(), 0x4142_2414_5153_7776);
77 }
78
79 {
80 info!("Single u8 read (async)");
81 async_single_read(p.DMA_CH0.reborrow(), 0x42_u8).await;
82
83 info!("Single u16 read (async)");
84 async_single_read(p.DMA_CH0.reborrow(), 0xAE42_u16).await;
85
86 info!("Single u32 read (async)");
87 async_single_read(p.DMA_CH0.reborrow(), 0xFE44_1500_u32).await;
88
89 info!("Single u64 read (async)");
90 async_single_read(p.DMA_CH0.reborrow(), 0x8F7F_6F5F_4F3F_2F1F_u64).await;
91 }
92
93 {
94 info!("Multiple u8 reads (blocking)");
95 block_read::<_, 16>(p.DMA_CH0.reborrow(), 0x98_u8);
96
97 info!("Multiple u16 reads (blocking)");
98 block_read::<_, 2>(p.DMA_CH0.reborrow(), 0x9801_u16);
99
100 info!("Multiple u32 reads (blocking)");
101 block_read::<_, 4>(p.DMA_CH0.reborrow(), 0x9821_9801_u32);
102
103 info!("Multiple u64 reads (blocking)");
104 block_read::<_, 4>(p.DMA_CH0.reborrow(), 0xABCD_EF01_2345_6789_u64);
105 }
106
107 {
108 info!("Multiple u8 reads (async)");
109 async_block_read::<_, 8>(p.DMA_CH0.reborrow(), 0x86_u8).await;
110
111 info!("Multiple u16 reads (async)");
112 async_block_read::<_, 6>(p.DMA_CH0.reborrow(), 0x7777_u16).await;
113
114 info!("Multiple u32 reads (async)");
115 async_block_read::<_, 3>(p.DMA_CH0.reborrow(), 0xA5A5_A5A5_u32).await;
116
117 info!("Multiple u64 reads (async)");
118 async_block_read::<_, 14>(p.DMA_CH0.reborrow(), 0x5A5A_5A5A_A5A5_A5A5_u64).await;
119 }
120
121 // Intentionally skip testing multiple reads in single transfer mode.
122 //
123 // If the destination length is greater than 1 and single transfer mode is used then two transfers
124 // are performed in a trigger. Similarly with any other length of destination above 2, only 2 transfers
125 // are performed. Issuing another trigger (resume) results in no further progress. More than likely
126 // the test does not work due to some combination of a hardware bug and the datasheet being unclear
127 // regarding what ends a software trigger.
128 //
129 // However this case works fine with a hardware trigger (such as the ADC hardware trigger).
130
131 {
132 info!("Single u8 write (blocking)");
133 single_write(p.DMA_CH0.reborrow(), 0x41_u8);
134
135 info!("Single u16 write (blocking)");
136 single_write(p.DMA_CH0.reborrow(), 0x4142_u16);
137
138 info!("Single u32 write (blocking)");
139 single_write(p.DMA_CH0.reborrow(), 0x4142_4344_u32);
140
141 info!("Single u64 write (blocking)");
142 single_write(p.DMA_CH0.reborrow(), 0x4142_4344_4546_4748_u64);
143 }
144
145 {
146 info!("Single u8 write (async)");
147 async_single_write(p.DMA_CH0.reborrow(), 0xAA_u8).await;
148
149 info!("Single u16 write (async)");
150 async_single_write(p.DMA_CH0.reborrow(), 0xBBBB_u16).await;
151
152 info!("Single u32 write (async)");
153 async_single_write(p.DMA_CH0.reborrow(), 0xCCCC_CCCC_u32).await;
154
155 info!("Single u64 write (async)");
156 async_single_write(p.DMA_CH0.reborrow(), 0xDDDD_DDDD_DDDD_DDDD_u64).await;
157 }
158
159 {
160 info!("Multiple u8 writes (blocking)");
161 block_write(p.DMA_CH0.reborrow(), &[0xFF_u8, 0x7F, 0x3F, 0x1F]);
162
163 info!("Multiple u16 writes (blocking)");
164 block_write(p.DMA_CH0.reborrow(), &[0xFFFF_u16, 0xFF7F, 0xFF3F, 0xFF1F]);
165
166 info!("Multiple u32 writes (blocking)");
167 block_write(
168 p.DMA_CH0.reborrow(),
169 &[0xFF00_00FF_u32, 0xFF00_007F, 0x0000_FF3F, 0xFF1F_0000],
170 );
171
172 info!("Multiple u64 writes (blocking)");
173 block_write(
174 p.DMA_CH0.reborrow(),
175 &[
176 0xFF00_0000_0000_00FF_u64,
177 0x0000_FF00_007F_0000,
178 0x0000_FF3F_0000_0000,
179 0xFF1F_0000_1111_837A,
180 ],
181 );
182 }
183
184 {
185 info!("Multiple u8 writes (async)");
186 async_block_write(p.DMA_CH0.reborrow(), &[0u8, 1, 2, 3]).await;
187
188 info!("Multiple u16 writes (async)");
189 async_block_write(p.DMA_CH0.reborrow(), &[0x9801u16, 0x9802, 0x9803, 0x9800, 0x9000]).await;
190
191 info!("Multiple u32 writes (async)");
192 async_block_write(p.DMA_CH0.reborrow(), &[0x9801_ABCDu32, 0xFFAC_9802, 0xDEAD_9803]).await;
193
194 info!("Multiple u64 writes (async)");
195 async_block_write(
196 p.DMA_CH0.reborrow(),
197 &[
198 0xA55A_1111_3333_5555_u64,
199 0x1111_A55A_3333_5555,
200 0x5555_A55A_3333_1111,
201 0x01234_5678_89AB_CDEF,
202 ],
203 )
204 .await;
205 }
206
207 // TODO: Mixed byte and word transfers.
208
209 info!("Test OK");
210 cortex_m::asm::bkpt();
211}
212
213fn single_read<W: Word + Copy + Default + Eq + defmt::Format>(mut channel: Peri<'_, impl Channel>, mut src: W) {
214 let options = TransferOptions::default();
215 let mut dst = W::default();
216
217 // SAFETY: src and dst outlive the transfer.
218 let transfer = unsafe {
219 unwrap!(Transfer::new_read(
220 channel.reborrow(),
221 Transfer::SOFTWARE_TRIGGER,
222 &mut src,
223 slice::from_mut(&mut dst),
224 options,
225 ))
226 };
227 transfer.blocking_wait();
228
229 assert_eq!(src, dst);
230}
231
232async fn async_single_read<W: Word + Copy + Default + Eq + defmt::Format>(
233 mut channel: Peri<'_, impl Channel>,
234 mut src: W,
235) {
236 let options = TransferOptions::default();
237 let mut dst = W::default();
238
239 // SAFETY: src and dst outlive the transfer.
240 let transfer = unsafe {
241 unwrap!(Transfer::new_read(
242 channel.reborrow(),
243 Transfer::SOFTWARE_TRIGGER,
244 &mut src,
245 slice::from_mut(&mut dst),
246 options,
247 ))
248 };
249 transfer.await;
250
251 assert_eq!(src, dst);
252}
253
254fn block_read<W: Word + Copy + Default + Eq + defmt::Format, const N: usize>(
255 mut channel: Peri<'_, impl Channel>,
256 mut src: W,
257) {
258 let mut options = TransferOptions::default();
259 // Complete the entire transfer.
260 options.mode = TransferMode::Block;
261
262 let mut dst = [W::default(); N];
263
264 // SAFETY: src and dst outlive the transfer.
265 let transfer = unsafe {
266 unwrap!(Transfer::new_read(
267 channel.reborrow(),
268 Transfer::SOFTWARE_TRIGGER,
269 &mut src,
270 &mut dst[..],
271 options,
272 ))
273 };
274 transfer.blocking_wait();
275
276 assert_eq!(dst, [src; N]);
277}
278
279async fn async_block_read<W: Word + Copy + Default + Eq + defmt::Format, const N: usize>(
280 mut channel: Peri<'_, impl Channel>,
281 mut src: W,
282) {
283 let mut options = TransferOptions::default();
284 // Complete the entire transfer.
285 options.mode = TransferMode::Block;
286
287 let mut dst = [W::default(); N];
288
289 // SAFETY: src and dst outlive the transfer.
290 let transfer = unsafe {
291 unwrap!(Transfer::new_read(
292 channel.reborrow(),
293 Transfer::SOFTWARE_TRIGGER,
294 &mut src,
295 &mut dst[..],
296 options,
297 ))
298 };
299 transfer.await;
300
301 assert_eq!(dst, [src; N]);
302}
303
304fn single_write<W: Word + Default + Eq + defmt::Format>(mut channel: Peri<'_, impl Channel>, src: W) {
305 let options = TransferOptions::default();
306 let mut dst = W::default();
307
308 // SAFETY: src and dst outlive the transfer.
309 let transfer = unsafe {
310 unwrap!(Transfer::new_write(
311 channel.reborrow(),
312 Transfer::SOFTWARE_TRIGGER,
313 slice::from_ref(&src),
314 &mut dst,
315 options,
316 ))
317 };
318 transfer.blocking_wait();
319
320 assert_eq!(src, dst);
321}
322
323async fn async_single_write<W: Word + Default + Eq + defmt::Format>(mut channel: Peri<'_, impl Channel>, src: W) {
324 let options = TransferOptions::default();
325 let mut dst = W::default();
326
327 // SAFETY: src and dst outlive the transfer.
328 let transfer = unsafe {
329 unwrap!(Transfer::new_write(
330 channel.reborrow(),
331 Transfer::SOFTWARE_TRIGGER,
332 slice::from_ref(&src),
333 &mut dst,
334 options,
335 ))
336 };
337 transfer.await;
338
339 assert_eq!(src, dst);
340}
341
342fn block_write<W: Word + Default + Eq + defmt::Format>(mut channel: Peri<'_, impl Channel>, src: &[W]) {
343 let mut options = TransferOptions::default();
344 // Complete the entire transfer.
345 options.mode = TransferMode::Block;
346
347 let mut dst = W::default();
348
349 // Starting from 1 because a zero length transfer does nothing.
350 for i in 1..src.len() {
351 info!("-> {} write(s)", i);
352
353 // SAFETY: src and dst outlive the transfer.
354 let transfer = unsafe {
355 unwrap!(Transfer::new_write(
356 channel.reborrow(),
357 Transfer::SOFTWARE_TRIGGER,
358 &src[..i],
359 &mut dst,
360 options,
361 ))
362 };
363 transfer.blocking_wait();
364
365 // The result will be the last value written.
366 assert_eq!(dst, src[i - 1]);
367 }
368}
369
370async fn async_block_write<W: Word + Default + Eq + defmt::Format>(mut channel: Peri<'_, impl Channel>, src: &[W]) {
371 let mut options = TransferOptions::default();
372 // Complete the entire transfer.
373 options.mode = TransferMode::Block;
374
375 let mut dst = W::default();
376
377 // Starting from 1 because a zero length transfer does nothing.
378 for i in 1..src.len() {
379 info!("-> {} write(s)", i);
380 // SAFETY: src and dst outlive the transfer.
381 let transfer = unsafe {
382 unwrap!(Transfer::new_write(
383 channel.reborrow(),
384 Transfer::SOFTWARE_TRIGGER,
385 &src[..i],
386 &mut dst,
387 options,
388 ))
389 };
390 transfer.await;
391
392 // The result will be the last value written.
393 assert_eq!(dst, src[i - 1]);
394 }
395}
396
397/// [`single_read`], but testing when the destination is wider than the source.
398///
399/// The MSPM0 DMA states that the upper bytes when the destination is longer than the source are zeroed.
400/// This matches the behavior in Rust for all unsigned integer types.
401fn widening_single_read<SW, DW>(mut channel: Peri<'_, impl Channel>, mut src: SW)
402where
403 SW: Word + Copy + Default + Eq + defmt::Format,
404 DW: Word + Copy + Default + Eq + defmt::Format + From<SW>,
405{
406 assert!(
407 DW::size() > SW::size(),
408 "This test only works when the destination is larger than the source"
409 );
410
411 let options = TransferOptions::default();
412 let mut dst = DW::default();
413
414 // SAFETY: src and dst outlive the transfer.
415 let transfer = unsafe {
416 unwrap!(Transfer::new_read(
417 channel.reborrow(),
418 Transfer::SOFTWARE_TRIGGER,
419 &mut src,
420 slice::from_mut(&mut dst),
421 options,
422 ))
423 };
424 transfer.blocking_wait();
425
426 assert_eq!(DW::from(src), dst);
427}
428
429/// [`single_read`], but testing when the destination is narrower than the source.
430///
431/// The MSPM0 DMA states that the upper bytes when the source is longer than the destination are dropped.
432/// This matches the behavior in Rust for all unsigned integer types.
433fn narrowing_single_read<SW, DW>(mut channel: Peri<'_, impl Channel>, mut src: SW)
434where
435 SW: Word + Copy + Default + Eq + defmt::Format + From<DW>,
436 DW: Word + Copy + Default + Eq + defmt::Format + Narrow<SW>,
437{
438 assert!(
439 SW::size() > DW::size(),
440 "This test only works when the source is larger than the destination"
441 );
442
443 let options = TransferOptions::default();
444 let mut dst = DW::default();
445
446 // SAFETY: src and dst outlive the transfer.
447 let transfer = unsafe {
448 unwrap!(Transfer::new_read(
449 channel.reborrow(),
450 Transfer::SOFTWARE_TRIGGER,
451 &mut src,
452 slice::from_mut(&mut dst),
453 options,
454 ))
455 };
456 transfer.blocking_wait();
457
458 // The expected value is the source value masked by the maximum destination value.
459 // This is effectively `src as DW as SW` to drop the upper byte(s).
460 let expect = SW::from(DW::narrow(src));
461 assert_eq!(expect, dst.into());
462}
463
464/// A pseudo `as` trait to allow downcasting integer types (TryFrom could fail).
465trait Narrow<T> {
466 fn narrow(value: T) -> Self;
467}
468
469impl Narrow<u16> for u8 {
470 fn narrow(value: u16) -> Self {
471 value as u8
472 }
473}
474
475impl Narrow<u32> for u8 {
476 fn narrow(value: u32) -> Self {
477 value as u8
478 }
479}
480
481impl Narrow<u64> for u8 {
482 fn narrow(value: u64) -> Self {
483 value as u8
484 }
485}
486
487impl Narrow<u32> for u16 {
488 fn narrow(value: u32) -> Self {
489 value as u16
490 }
491}
492
493impl Narrow<u64> for u16 {
494 fn narrow(value: u64) -> Self {
495 value as u16
496 }
497}
498
499impl Narrow<u64> for u32 {
500 fn narrow(value: u64) -> Self {
501 value as u32
502 }
503}