aboutsummaryrefslogtreecommitdiff
path: root/examples/mcxa
diff options
context:
space:
mode:
Diffstat (limited to 'examples/mcxa')
-rw-r--r--examples/mcxa/.cargo/config.toml17
-rw-r--r--examples/mcxa/.gitignore1
-rw-r--r--examples/mcxa/Cargo.lock1555
-rw-r--r--examples/mcxa/Cargo.toml26
-rw-r--r--examples/mcxa/build.rs20
-rw-r--r--examples/mcxa/memory.x5
-rw-r--r--examples/mcxa/src/bin/adc_interrupt.rs84
-rw-r--r--examples/mcxa/src/bin/adc_polling.rs68
-rw-r--r--examples/mcxa/src/bin/blinky.rs36
-rw-r--r--examples/mcxa/src/bin/button.rs23
-rw-r--r--examples/mcxa/src/bin/button_async.rs29
-rw-r--r--examples/mcxa/src/bin/clkout.rs69
-rw-r--r--examples/mcxa/src/bin/dma_channel_link.rs372
-rw-r--r--examples/mcxa/src/bin/dma_interleave_transfer.rs215
-rw-r--r--examples/mcxa/src/bin/dma_mem_to_mem.rs229
-rw-r--r--examples/mcxa/src/bin/dma_memset.rs218
-rw-r--r--examples/mcxa/src/bin/dma_ping_pong_transfer.rs376
-rw-r--r--examples/mcxa/src/bin/dma_scatter_gather.rs262
-rw-r--r--examples/mcxa/src/bin/dma_scatter_gather_builder.rs231
-rw-r--r--examples/mcxa/src/bin/dma_wrap_transfer.rs222
-rw-r--r--examples/mcxa/src/bin/hello.rs119
-rw-r--r--examples/mcxa/src/bin/i2c-blocking.rs31
-rw-r--r--examples/mcxa/src/bin/i2c-scan-blocking.rs41
-rw-r--r--examples/mcxa/src/bin/lpuart_buffered.rs62
-rw-r--r--examples/mcxa/src/bin/lpuart_dma.rs81
-rw-r--r--examples/mcxa/src/bin/lpuart_polling.rs47
-rw-r--r--examples/mcxa/src/bin/lpuart_ring_buffer.rs130
-rw-r--r--examples/mcxa/src/bin/rtc_alarm.rs74
-rw-r--r--examples/mcxa/src/lib.rs16
29 files changed, 4659 insertions, 0 deletions
diff --git a/examples/mcxa/.cargo/config.toml b/examples/mcxa/.cargo/config.toml
new file mode 100644
index 000000000..aedc55b06
--- /dev/null
+++ b/examples/mcxa/.cargo/config.toml
@@ -0,0 +1,17 @@
1[target.thumbv8m.main-none-eabihf]
2runner = 'probe-rs run --chip MCXA276 --preverify --verify --protocol swd --speed 12000'
3
4rustflags = [
5 "-C", "linker=flip-link",
6 "-C", "link-arg=-Tlink.x",
7 "-C", "link-arg=-Tdefmt.x",
8 # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
9 # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
10 "-C", "link-arg=--nmagic",
11]
12
13[build]
14target = "thumbv8m.main-none-eabihf" # Cortex-M33
15
16[env]
17DEFMT_LOG = "trace"
diff --git a/examples/mcxa/.gitignore b/examples/mcxa/.gitignore
new file mode 100644
index 000000000..2f7896d1d
--- /dev/null
+++ b/examples/mcxa/.gitignore
@@ -0,0 +1 @@
target/
diff --git a/examples/mcxa/Cargo.lock b/examples/mcxa/Cargo.lock
new file mode 100644
index 000000000..c6e864df2
--- /dev/null
+++ b/examples/mcxa/Cargo.lock
@@ -0,0 +1,1555 @@
1# This file is automatically @generated by Cargo.
2# It is not intended for manual editing.
3version = 4
4
5[[package]]
6name = "aho-corasick"
7version = "1.1.4"
8source = "registry+https://github.com/rust-lang/crates.io-index"
9checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
10dependencies = [
11 "memchr",
12]
13
14[[package]]
15name = "anyhow"
16version = "1.0.100"
17source = "registry+https://github.com/rust-lang/crates.io-index"
18checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
19
20[[package]]
21name = "askama"
22version = "0.14.0"
23source = "registry+https://github.com/rust-lang/crates.io-index"
24checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
25dependencies = [
26 "askama_derive",
27 "itoa",
28 "percent-encoding",
29 "serde",
30 "serde_json",
31]
32
33[[package]]
34name = "askama_derive"
35version = "0.14.0"
36source = "registry+https://github.com/rust-lang/crates.io-index"
37checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
38dependencies = [
39 "askama_parser",
40 "memchr",
41 "proc-macro2",
42 "quote",
43 "rustc-hash",
44 "syn 2.0.110",
45]
46
47[[package]]
48name = "askama_parser"
49version = "0.14.0"
50source = "registry+https://github.com/rust-lang/crates.io-index"
51checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
52dependencies = [
53 "memchr",
54 "winnow 0.7.13",
55]
56
57[[package]]
58name = "autocfg"
59version = "1.5.0"
60source = "registry+https://github.com/rust-lang/crates.io-index"
61checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
62
63[[package]]
64name = "bare-metal"
65version = "0.2.5"
66source = "registry+https://github.com/rust-lang/crates.io-index"
67checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
68dependencies = [
69 "rustc_version",
70]
71
72[[package]]
73name = "bitfield"
74version = "0.13.2"
75source = "registry+https://github.com/rust-lang/crates.io-index"
76checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
77
78[[package]]
79name = "bitflags"
80version = "1.3.2"
81source = "registry+https://github.com/rust-lang/crates.io-index"
82checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
83
84[[package]]
85name = "bitflags"
86version = "2.10.0"
87source = "registry+https://github.com/rust-lang/crates.io-index"
88checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
89
90[[package]]
91name = "bitvec"
92version = "1.0.1"
93source = "registry+https://github.com/rust-lang/crates.io-index"
94checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
95dependencies = [
96 "funty",
97 "radium",
98 "tap",
99 "wyz",
100]
101
102[[package]]
103name = "byteorder"
104version = "1.5.0"
105source = "registry+https://github.com/rust-lang/crates.io-index"
106checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
107
108[[package]]
109name = "cc"
110version = "1.2.47"
111source = "registry+https://github.com/rust-lang/crates.io-index"
112checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
113dependencies = [
114 "find-msvc-tools",
115 "shlex",
116]
117
118[[package]]
119name = "cfg-if"
120version = "1.0.4"
121source = "registry+https://github.com/rust-lang/crates.io-index"
122checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
123
124[[package]]
125name = "convert_case"
126version = "0.6.0"
127source = "registry+https://github.com/rust-lang/crates.io-index"
128checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
129dependencies = [
130 "unicode-segmentation",
131]
132
133[[package]]
134name = "cordyceps"
135version = "0.3.4"
136source = "registry+https://github.com/rust-lang/crates.io-index"
137checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a"
138dependencies = [
139 "loom",
140 "tracing",
141]
142
143[[package]]
144name = "cortex-m"
145version = "0.7.7"
146source = "registry+https://github.com/rust-lang/crates.io-index"
147checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
148dependencies = [
149 "bare-metal",
150 "bitfield",
151 "critical-section",
152 "embedded-hal 0.2.7",
153 "volatile-register",
154]
155
156[[package]]
157name = "cortex-m-rt"
158version = "0.7.5"
159source = "registry+https://github.com/rust-lang/crates.io-index"
160checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6"
161dependencies = [
162 "cortex-m-rt-macros",
163]
164
165[[package]]
166name = "cortex-m-rt-macros"
167version = "0.7.5"
168source = "registry+https://github.com/rust-lang/crates.io-index"
169checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472"
170dependencies = [
171 "proc-macro2",
172 "quote",
173 "syn 2.0.110",
174]
175
176[[package]]
177name = "critical-section"
178version = "1.2.0"
179source = "registry+https://github.com/rust-lang/crates.io-index"
180checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
181
182[[package]]
183name = "darling"
184version = "0.20.11"
185source = "registry+https://github.com/rust-lang/crates.io-index"
186checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
187dependencies = [
188 "darling_core",
189 "darling_macro",
190]
191
192[[package]]
193name = "darling_core"
194version = "0.20.11"
195source = "registry+https://github.com/rust-lang/crates.io-index"
196checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
197dependencies = [
198 "fnv",
199 "ident_case",
200 "proc-macro2",
201 "quote",
202 "strsim",
203 "syn 2.0.110",
204]
205
206[[package]]
207name = "darling_macro"
208version = "0.20.11"
209source = "registry+https://github.com/rust-lang/crates.io-index"
210checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
211dependencies = [
212 "darling_core",
213 "quote",
214 "syn 2.0.110",
215]
216
217[[package]]
218name = "dd-manifest-tree"
219version = "1.0.0"
220source = "registry+https://github.com/rust-lang/crates.io-index"
221checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9"
222dependencies = [
223 "toml",
224]
225
226[[package]]
227name = "defmt"
228version = "1.0.1"
229source = "registry+https://github.com/rust-lang/crates.io-index"
230checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78"
231dependencies = [
232 "bitflags 1.3.2",
233 "defmt-macros",
234]
235
236[[package]]
237name = "defmt-macros"
238version = "1.0.1"
239source = "registry+https://github.com/rust-lang/crates.io-index"
240checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
241dependencies = [
242 "defmt-parser",
243 "proc-macro-error2",
244 "proc-macro2",
245 "quote",
246 "syn 2.0.110",
247]
248
249[[package]]
250name = "defmt-parser"
251version = "1.0.0"
252source = "registry+https://github.com/rust-lang/crates.io-index"
253checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
254dependencies = [
255 "thiserror",
256]
257
258[[package]]
259name = "defmt-rtt"
260version = "1.1.0"
261source = "registry+https://github.com/rust-lang/crates.io-index"
262checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e"
263dependencies = [
264 "critical-section",
265 "defmt",
266]
267
268[[package]]
269name = "device-driver"
270version = "1.0.7"
271source = "registry+https://github.com/rust-lang/crates.io-index"
272checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf"
273dependencies = [
274 "device-driver-macros",
275 "embedded-io",
276 "embedded-io-async",
277]
278
279[[package]]
280name = "device-driver-generation"
281version = "1.0.7"
282source = "registry+https://github.com/rust-lang/crates.io-index"
283checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0"
284dependencies = [
285 "anyhow",
286 "askama",
287 "bitvec",
288 "convert_case",
289 "dd-manifest-tree",
290 "itertools",
291 "kdl",
292 "proc-macro2",
293 "quote",
294 "syn 2.0.110",
295]
296
297[[package]]
298name = "device-driver-macros"
299version = "1.0.7"
300source = "registry+https://github.com/rust-lang/crates.io-index"
301checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17"
302dependencies = [
303 "device-driver-generation",
304 "proc-macro2",
305 "syn 2.0.110",
306]
307
308[[package]]
309name = "document-features"
310version = "0.2.12"
311source = "registry+https://github.com/rust-lang/crates.io-index"
312checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
313dependencies = [
314 "litrs",
315]
316
317[[package]]
318name = "either"
319version = "1.15.0"
320source = "registry+https://github.com/rust-lang/crates.io-index"
321checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
322
323[[package]]
324name = "embassy-embedded-hal"
325version = "0.5.0"
326source = "registry+https://github.com/rust-lang/crates.io-index"
327checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8"
328dependencies = [
329 "embassy-futures",
330 "embassy-hal-internal",
331 "embassy-sync",
332 "embedded-hal 0.2.7",
333 "embedded-hal 1.0.0",
334 "embedded-hal-async",
335 "embedded-storage",
336 "embedded-storage-async",
337 "nb 1.1.0",
338]
339
340[[package]]
341name = "embassy-executor"
342version = "0.9.1"
343source = "registry+https://github.com/rust-lang/crates.io-index"
344checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b"
345dependencies = [
346 "cortex-m",
347 "critical-section",
348 "document-features",
349 "embassy-executor-macros",
350 "embassy-executor-timer-queue",
351]
352
353[[package]]
354name = "embassy-executor-macros"
355version = "0.7.0"
356source = "registry+https://github.com/rust-lang/crates.io-index"
357checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472"
358dependencies = [
359 "darling",
360 "proc-macro2",
361 "quote",
362 "syn 2.0.110",
363]
364
365[[package]]
366name = "embassy-executor-timer-queue"
367version = "0.1.0"
368source = "registry+https://github.com/rust-lang/crates.io-index"
369checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c"
370
371[[package]]
372name = "embassy-futures"
373version = "0.1.2"
374source = "registry+https://github.com/rust-lang/crates.io-index"
375checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01"
376
377[[package]]
378name = "embassy-hal-internal"
379version = "0.3.0"
380source = "registry+https://github.com/rust-lang/crates.io-index"
381checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a"
382dependencies = [
383 "cortex-m",
384 "critical-section",
385 "num-traits",
386]
387
388[[package]]
389name = "embassy-mcxa"
390version = "0.1.0"
391dependencies = [
392 "cortex-m",
393 "cortex-m-rt",
394 "critical-section",
395 "defmt",
396 "embassy-embedded-hal",
397 "embassy-hal-internal",
398 "embassy-sync",
399 "embassy-time",
400 "embassy-time-driver",
401 "embedded-hal 0.2.7",
402 "embedded-hal 1.0.0",
403 "embedded-hal-async",
404 "embedded-hal-nb",
405 "embedded-io",
406 "embedded-io-async",
407 "heapless 0.8.0",
408 "maitake-sync",
409 "mcxa-pac",
410 "nb 1.1.0",
411 "paste",
412]
413
414[[package]]
415name = "embassy-mcxa-examples"
416version = "0.1.0"
417dependencies = [
418 "cortex-m",
419 "cortex-m-rt",
420 "critical-section",
421 "defmt",
422 "defmt-rtt",
423 "embassy-embedded-hal",
424 "embassy-executor",
425 "embassy-mcxa",
426 "embassy-sync",
427 "embassy-time",
428 "embassy-time-driver",
429 "embedded-io-async",
430 "heapless 0.9.2",
431 "panic-probe",
432 "tmp108",
433]
434
435[[package]]
436name = "embassy-sync"
437version = "0.7.2"
438source = "registry+https://github.com/rust-lang/crates.io-index"
439checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b"
440dependencies = [
441 "cfg-if",
442 "critical-section",
443 "embedded-io-async",
444 "futures-core",
445 "futures-sink",
446 "heapless 0.8.0",
447]
448
449[[package]]
450name = "embassy-time"
451version = "0.5.0"
452source = "registry+https://github.com/rust-lang/crates.io-index"
453checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65"
454dependencies = [
455 "cfg-if",
456 "critical-section",
457 "document-features",
458 "embassy-time-driver",
459 "embedded-hal 0.2.7",
460 "embedded-hal 1.0.0",
461 "embedded-hal-async",
462 "futures-core",
463]
464
465[[package]]
466name = "embassy-time-driver"
467version = "0.2.1"
468source = "registry+https://github.com/rust-lang/crates.io-index"
469checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6"
470dependencies = [
471 "document-features",
472]
473
474[[package]]
475name = "embedded-hal"
476version = "0.2.7"
477source = "registry+https://github.com/rust-lang/crates.io-index"
478checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
479dependencies = [
480 "nb 0.1.3",
481 "void",
482]
483
484[[package]]
485name = "embedded-hal"
486version = "1.0.0"
487source = "registry+https://github.com/rust-lang/crates.io-index"
488checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
489
490[[package]]
491name = "embedded-hal-async"
492version = "1.0.0"
493source = "registry+https://github.com/rust-lang/crates.io-index"
494checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884"
495dependencies = [
496 "embedded-hal 1.0.0",
497]
498
499[[package]]
500name = "embedded-hal-nb"
501version = "1.0.0"
502source = "registry+https://github.com/rust-lang/crates.io-index"
503checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605"
504dependencies = [
505 "embedded-hal 1.0.0",
506 "nb 1.1.0",
507]
508
509[[package]]
510name = "embedded-io"
511version = "0.6.1"
512source = "registry+https://github.com/rust-lang/crates.io-index"
513checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
514
515[[package]]
516name = "embedded-io-async"
517version = "0.6.1"
518source = "registry+https://github.com/rust-lang/crates.io-index"
519checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f"
520dependencies = [
521 "embedded-io",
522]
523
524[[package]]
525name = "embedded-storage"
526version = "0.3.1"
527source = "registry+https://github.com/rust-lang/crates.io-index"
528checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032"
529
530[[package]]
531name = "embedded-storage-async"
532version = "0.4.1"
533source = "registry+https://github.com/rust-lang/crates.io-index"
534checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc"
535dependencies = [
536 "embedded-storage",
537]
538
539[[package]]
540name = "equivalent"
541version = "1.0.2"
542source = "registry+https://github.com/rust-lang/crates.io-index"
543checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
544
545[[package]]
546name = "find-msvc-tools"
547version = "0.1.5"
548source = "registry+https://github.com/rust-lang/crates.io-index"
549checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
550
551[[package]]
552name = "fnv"
553version = "1.0.7"
554source = "registry+https://github.com/rust-lang/crates.io-index"
555checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
556
557[[package]]
558name = "funty"
559version = "2.0.0"
560source = "registry+https://github.com/rust-lang/crates.io-index"
561checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
562
563[[package]]
564name = "futures-core"
565version = "0.3.31"
566source = "registry+https://github.com/rust-lang/crates.io-index"
567checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
568
569[[package]]
570name = "futures-sink"
571version = "0.3.31"
572source = "registry+https://github.com/rust-lang/crates.io-index"
573checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
574
575[[package]]
576name = "generator"
577version = "0.8.7"
578source = "registry+https://github.com/rust-lang/crates.io-index"
579checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2"
580dependencies = [
581 "cc",
582 "cfg-if",
583 "libc",
584 "log",
585 "rustversion",
586 "windows",
587]
588
589[[package]]
590name = "hash32"
591version = "0.3.1"
592source = "registry+https://github.com/rust-lang/crates.io-index"
593checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
594dependencies = [
595 "byteorder",
596]
597
598[[package]]
599name = "hashbrown"
600version = "0.16.0"
601source = "registry+https://github.com/rust-lang/crates.io-index"
602checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
603
604[[package]]
605name = "heapless"
606version = "0.8.0"
607source = "registry+https://github.com/rust-lang/crates.io-index"
608checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
609dependencies = [
610 "hash32",
611 "stable_deref_trait",
612]
613
614[[package]]
615name = "heapless"
616version = "0.9.2"
617source = "registry+https://github.com/rust-lang/crates.io-index"
618checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed"
619dependencies = [
620 "hash32",
621 "stable_deref_trait",
622]
623
624[[package]]
625name = "ident_case"
626version = "1.0.1"
627source = "registry+https://github.com/rust-lang/crates.io-index"
628checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
629
630[[package]]
631name = "indexmap"
632version = "2.12.0"
633source = "registry+https://github.com/rust-lang/crates.io-index"
634checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
635dependencies = [
636 "equivalent",
637 "hashbrown",
638]
639
640[[package]]
641name = "itertools"
642version = "0.14.0"
643source = "registry+https://github.com/rust-lang/crates.io-index"
644checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
645dependencies = [
646 "either",
647]
648
649[[package]]
650name = "itoa"
651version = "1.0.15"
652source = "registry+https://github.com/rust-lang/crates.io-index"
653checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
654
655[[package]]
656name = "kdl"
657version = "6.5.0"
658source = "registry+https://github.com/rust-lang/crates.io-index"
659checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e"
660dependencies = [
661 "miette",
662 "num",
663 "winnow 0.6.24",
664]
665
666[[package]]
667name = "lazy_static"
668version = "1.5.0"
669source = "registry+https://github.com/rust-lang/crates.io-index"
670checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
671
672[[package]]
673name = "libc"
674version = "0.2.177"
675source = "registry+https://github.com/rust-lang/crates.io-index"
676checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
677
678[[package]]
679name = "litrs"
680version = "1.0.0"
681source = "registry+https://github.com/rust-lang/crates.io-index"
682checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
683
684[[package]]
685name = "log"
686version = "0.4.28"
687source = "registry+https://github.com/rust-lang/crates.io-index"
688checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
689
690[[package]]
691name = "loom"
692version = "0.7.2"
693source = "registry+https://github.com/rust-lang/crates.io-index"
694checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
695dependencies = [
696 "cfg-if",
697 "generator",
698 "scoped-tls",
699 "tracing",
700 "tracing-subscriber",
701]
702
703[[package]]
704name = "maitake-sync"
705version = "0.2.2"
706source = "registry+https://github.com/rust-lang/crates.io-index"
707checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f"
708dependencies = [
709 "cordyceps",
710 "critical-section",
711 "loom",
712 "mutex-traits",
713 "mycelium-bitfield",
714 "pin-project",
715 "portable-atomic",
716 "tracing",
717]
718
719[[package]]
720name = "manyhow"
721version = "0.11.4"
722source = "registry+https://github.com/rust-lang/crates.io-index"
723checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587"
724dependencies = [
725 "manyhow-macros",
726 "proc-macro2",
727 "quote",
728 "syn 1.0.109",
729 "syn 2.0.110",
730]
731
732[[package]]
733name = "manyhow-macros"
734version = "0.11.4"
735source = "registry+https://github.com/rust-lang/crates.io-index"
736checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495"
737dependencies = [
738 "proc-macro-utils",
739 "proc-macro2",
740 "quote",
741]
742
743[[package]]
744name = "matchers"
745version = "0.2.0"
746source = "registry+https://github.com/rust-lang/crates.io-index"
747checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
748dependencies = [
749 "regex-automata",
750]
751
752[[package]]
753name = "maybe-async-cfg"
754version = "0.2.5"
755source = "registry+https://github.com/rust-lang/crates.io-index"
756checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627"
757dependencies = [
758 "manyhow",
759 "proc-macro2",
760 "pulldown-cmark",
761 "quote",
762 "syn 1.0.109",
763]
764
765[[package]]
766name = "mcxa-pac"
767version = "0.1.0"
768source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca"
769dependencies = [
770 "cortex-m",
771 "cortex-m-rt",
772 "critical-section",
773 "defmt",
774 "vcell",
775]
776
777[[package]]
778name = "memchr"
779version = "2.7.6"
780source = "registry+https://github.com/rust-lang/crates.io-index"
781checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
782
783[[package]]
784name = "miette"
785version = "7.6.0"
786source = "registry+https://github.com/rust-lang/crates.io-index"
787checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7"
788dependencies = [
789 "cfg-if",
790 "unicode-width",
791]
792
793[[package]]
794name = "mutex-traits"
795version = "1.0.1"
796source = "registry+https://github.com/rust-lang/crates.io-index"
797checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f"
798
799[[package]]
800name = "mycelium-bitfield"
801version = "0.1.5"
802source = "registry+https://github.com/rust-lang/crates.io-index"
803checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc"
804
805[[package]]
806name = "nb"
807version = "0.1.3"
808source = "registry+https://github.com/rust-lang/crates.io-index"
809checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
810dependencies = [
811 "nb 1.1.0",
812]
813
814[[package]]
815name = "nb"
816version = "1.1.0"
817source = "registry+https://github.com/rust-lang/crates.io-index"
818checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
819
820[[package]]
821name = "nu-ansi-term"
822version = "0.50.3"
823source = "registry+https://github.com/rust-lang/crates.io-index"
824checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
825dependencies = [
826 "windows-sys",
827]
828
829[[package]]
830name = "num"
831version = "0.4.3"
832source = "registry+https://github.com/rust-lang/crates.io-index"
833checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
834dependencies = [
835 "num-bigint",
836 "num-complex",
837 "num-integer",
838 "num-iter",
839 "num-rational",
840 "num-traits",
841]
842
843[[package]]
844name = "num-bigint"
845version = "0.4.6"
846source = "registry+https://github.com/rust-lang/crates.io-index"
847checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
848dependencies = [
849 "num-integer",
850 "num-traits",
851]
852
853[[package]]
854name = "num-complex"
855version = "0.4.6"
856source = "registry+https://github.com/rust-lang/crates.io-index"
857checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
858dependencies = [
859 "num-traits",
860]
861
862[[package]]
863name = "num-integer"
864version = "0.1.46"
865source = "registry+https://github.com/rust-lang/crates.io-index"
866checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
867dependencies = [
868 "num-traits",
869]
870
871[[package]]
872name = "num-iter"
873version = "0.1.45"
874source = "registry+https://github.com/rust-lang/crates.io-index"
875checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
876dependencies = [
877 "autocfg",
878 "num-integer",
879 "num-traits",
880]
881
882[[package]]
883name = "num-rational"
884version = "0.4.2"
885source = "registry+https://github.com/rust-lang/crates.io-index"
886checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
887dependencies = [
888 "num-bigint",
889 "num-integer",
890 "num-traits",
891]
892
893[[package]]
894name = "num-traits"
895version = "0.2.19"
896source = "registry+https://github.com/rust-lang/crates.io-index"
897checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
898dependencies = [
899 "autocfg",
900]
901
902[[package]]
903name = "once_cell"
904version = "1.21.3"
905source = "registry+https://github.com/rust-lang/crates.io-index"
906checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
907
908[[package]]
909name = "panic-probe"
910version = "1.0.0"
911source = "registry+https://github.com/rust-lang/crates.io-index"
912checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a"
913dependencies = [
914 "cortex-m",
915 "defmt",
916]
917
918[[package]]
919name = "paste"
920version = "1.0.15"
921source = "registry+https://github.com/rust-lang/crates.io-index"
922checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
923
924[[package]]
925name = "percent-encoding"
926version = "2.3.2"
927source = "registry+https://github.com/rust-lang/crates.io-index"
928checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
929
930[[package]]
931name = "pin-project"
932version = "1.1.10"
933source = "registry+https://github.com/rust-lang/crates.io-index"
934checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
935dependencies = [
936 "pin-project-internal",
937]
938
939[[package]]
940name = "pin-project-internal"
941version = "1.1.10"
942source = "registry+https://github.com/rust-lang/crates.io-index"
943checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
944dependencies = [
945 "proc-macro2",
946 "quote",
947 "syn 2.0.110",
948]
949
950[[package]]
951name = "pin-project-lite"
952version = "0.2.16"
953source = "registry+https://github.com/rust-lang/crates.io-index"
954checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
955
956[[package]]
957name = "portable-atomic"
958version = "1.11.1"
959source = "registry+https://github.com/rust-lang/crates.io-index"
960checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
961dependencies = [
962 "critical-section",
963]
964
965[[package]]
966name = "proc-macro-error-attr2"
967version = "2.0.0"
968source = "registry+https://github.com/rust-lang/crates.io-index"
969checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
970dependencies = [
971 "proc-macro2",
972 "quote",
973]
974
975[[package]]
976name = "proc-macro-error2"
977version = "2.0.1"
978source = "registry+https://github.com/rust-lang/crates.io-index"
979checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
980dependencies = [
981 "proc-macro-error-attr2",
982 "proc-macro2",
983 "quote",
984 "syn 2.0.110",
985]
986
987[[package]]
988name = "proc-macro-utils"
989version = "0.10.0"
990source = "registry+https://github.com/rust-lang/crates.io-index"
991checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071"
992dependencies = [
993 "proc-macro2",
994 "quote",
995 "smallvec",
996]
997
998[[package]]
999name = "proc-macro2"
1000version = "1.0.103"
1001source = "registry+https://github.com/rust-lang/crates.io-index"
1002checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
1003dependencies = [
1004 "unicode-ident",
1005]
1006
1007[[package]]
1008name = "pulldown-cmark"
1009version = "0.11.3"
1010source = "registry+https://github.com/rust-lang/crates.io-index"
1011checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
1012dependencies = [
1013 "bitflags 2.10.0",
1014 "memchr",
1015 "unicase",
1016]
1017
1018[[package]]
1019name = "quote"
1020version = "1.0.42"
1021source = "registry+https://github.com/rust-lang/crates.io-index"
1022checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
1023dependencies = [
1024 "proc-macro2",
1025]
1026
1027[[package]]
1028name = "radium"
1029version = "0.7.0"
1030source = "registry+https://github.com/rust-lang/crates.io-index"
1031checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
1032
1033[[package]]
1034name = "regex-automata"
1035version = "0.4.13"
1036source = "registry+https://github.com/rust-lang/crates.io-index"
1037checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
1038dependencies = [
1039 "aho-corasick",
1040 "memchr",
1041 "regex-syntax",
1042]
1043
1044[[package]]
1045name = "regex-syntax"
1046version = "0.8.8"
1047source = "registry+https://github.com/rust-lang/crates.io-index"
1048checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
1049
1050[[package]]
1051name = "rustc-hash"
1052version = "2.1.1"
1053source = "registry+https://github.com/rust-lang/crates.io-index"
1054checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
1055
1056[[package]]
1057name = "rustc_version"
1058version = "0.2.3"
1059source = "registry+https://github.com/rust-lang/crates.io-index"
1060checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1061dependencies = [
1062 "semver",
1063]
1064
1065[[package]]
1066name = "rustversion"
1067version = "1.0.22"
1068source = "registry+https://github.com/rust-lang/crates.io-index"
1069checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
1070
1071[[package]]
1072name = "ryu"
1073version = "1.0.20"
1074source = "registry+https://github.com/rust-lang/crates.io-index"
1075checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
1076
1077[[package]]
1078name = "scoped-tls"
1079version = "1.0.1"
1080source = "registry+https://github.com/rust-lang/crates.io-index"
1081checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
1082
1083[[package]]
1084name = "semver"
1085version = "0.9.0"
1086source = "registry+https://github.com/rust-lang/crates.io-index"
1087checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
1088dependencies = [
1089 "semver-parser",
1090]
1091
1092[[package]]
1093name = "semver-parser"
1094version = "0.7.0"
1095source = "registry+https://github.com/rust-lang/crates.io-index"
1096checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1097
1098[[package]]
1099name = "serde"
1100version = "1.0.228"
1101source = "registry+https://github.com/rust-lang/crates.io-index"
1102checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
1103dependencies = [
1104 "serde_core",
1105]
1106
1107[[package]]
1108name = "serde_core"
1109version = "1.0.228"
1110source = "registry+https://github.com/rust-lang/crates.io-index"
1111checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
1112dependencies = [
1113 "serde_derive",
1114]
1115
1116[[package]]
1117name = "serde_derive"
1118version = "1.0.228"
1119source = "registry+https://github.com/rust-lang/crates.io-index"
1120checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
1121dependencies = [
1122 "proc-macro2",
1123 "quote",
1124 "syn 2.0.110",
1125]
1126
1127[[package]]
1128name = "serde_json"
1129version = "1.0.145"
1130source = "registry+https://github.com/rust-lang/crates.io-index"
1131checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
1132dependencies = [
1133 "itoa",
1134 "memchr",
1135 "ryu",
1136 "serde",
1137 "serde_core",
1138]
1139
1140[[package]]
1141name = "serde_spanned"
1142version = "0.6.9"
1143source = "registry+https://github.com/rust-lang/crates.io-index"
1144checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
1145dependencies = [
1146 "serde",
1147]
1148
1149[[package]]
1150name = "sharded-slab"
1151version = "0.1.7"
1152source = "registry+https://github.com/rust-lang/crates.io-index"
1153checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
1154dependencies = [
1155 "lazy_static",
1156]
1157
1158[[package]]
1159name = "shlex"
1160version = "1.3.0"
1161source = "registry+https://github.com/rust-lang/crates.io-index"
1162checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
1163
1164[[package]]
1165name = "smallvec"
1166version = "1.15.1"
1167source = "registry+https://github.com/rust-lang/crates.io-index"
1168checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
1169
1170[[package]]
1171name = "stable_deref_trait"
1172version = "1.2.1"
1173source = "registry+https://github.com/rust-lang/crates.io-index"
1174checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
1175
1176[[package]]
1177name = "strsim"
1178version = "0.11.1"
1179source = "registry+https://github.com/rust-lang/crates.io-index"
1180checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
1181
1182[[package]]
1183name = "syn"
1184version = "1.0.109"
1185source = "registry+https://github.com/rust-lang/crates.io-index"
1186checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
1187dependencies = [
1188 "proc-macro2",
1189 "quote",
1190 "unicode-ident",
1191]
1192
1193[[package]]
1194name = "syn"
1195version = "2.0.110"
1196source = "registry+https://github.com/rust-lang/crates.io-index"
1197checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
1198dependencies = [
1199 "proc-macro2",
1200 "quote",
1201 "unicode-ident",
1202]
1203
1204[[package]]
1205name = "tap"
1206version = "1.0.1"
1207source = "registry+https://github.com/rust-lang/crates.io-index"
1208checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
1209
1210[[package]]
1211name = "thiserror"
1212version = "2.0.17"
1213source = "registry+https://github.com/rust-lang/crates.io-index"
1214checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
1215dependencies = [
1216 "thiserror-impl",
1217]
1218
1219[[package]]
1220name = "thiserror-impl"
1221version = "2.0.17"
1222source = "registry+https://github.com/rust-lang/crates.io-index"
1223checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
1224dependencies = [
1225 "proc-macro2",
1226 "quote",
1227 "syn 2.0.110",
1228]
1229
1230[[package]]
1231name = "thread_local"
1232version = "1.1.9"
1233source = "registry+https://github.com/rust-lang/crates.io-index"
1234checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
1235dependencies = [
1236 "cfg-if",
1237]
1238
1239[[package]]
1240name = "tmp108"
1241version = "0.4.0"
1242source = "registry+https://github.com/rust-lang/crates.io-index"
1243checksum = "e0d644cc97d3cee96793f454b834881f78b5d4e89c90ecf26b3690f42004d111"
1244dependencies = [
1245 "device-driver",
1246 "embedded-hal 1.0.0",
1247 "maybe-async-cfg",
1248]
1249
1250[[package]]
1251name = "toml"
1252version = "0.8.23"
1253source = "registry+https://github.com/rust-lang/crates.io-index"
1254checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
1255dependencies = [
1256 "indexmap",
1257 "serde",
1258 "serde_spanned",
1259 "toml_datetime",
1260 "toml_edit",
1261]
1262
1263[[package]]
1264name = "toml_datetime"
1265version = "0.6.11"
1266source = "registry+https://github.com/rust-lang/crates.io-index"
1267checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
1268dependencies = [
1269 "serde",
1270]
1271
1272[[package]]
1273name = "toml_edit"
1274version = "0.22.27"
1275source = "registry+https://github.com/rust-lang/crates.io-index"
1276checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
1277dependencies = [
1278 "indexmap",
1279 "serde",
1280 "serde_spanned",
1281 "toml_datetime",
1282 "toml_write",
1283 "winnow 0.7.13",
1284]
1285
1286[[package]]
1287name = "toml_write"
1288version = "0.1.2"
1289source = "registry+https://github.com/rust-lang/crates.io-index"
1290checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
1291
1292[[package]]
1293name = "tracing"
1294version = "0.1.42"
1295source = "registry+https://github.com/rust-lang/crates.io-index"
1296checksum = "8eb41cbdb933e23b7929f47bb577710643157d7602ef3a2ebd3902b13ac5eda6"
1297dependencies = [
1298 "pin-project-lite",
1299 "tracing-attributes",
1300 "tracing-core",
1301]
1302
1303[[package]]
1304name = "tracing-attributes"
1305version = "0.1.31"
1306source = "registry+https://github.com/rust-lang/crates.io-index"
1307checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
1308dependencies = [
1309 "proc-macro2",
1310 "quote",
1311 "syn 2.0.110",
1312]
1313
1314[[package]]
1315name = "tracing-core"
1316version = "0.1.35"
1317source = "registry+https://github.com/rust-lang/crates.io-index"
1318checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
1319dependencies = [
1320 "once_cell",
1321 "valuable",
1322]
1323
1324[[package]]
1325name = "tracing-log"
1326version = "0.2.0"
1327source = "registry+https://github.com/rust-lang/crates.io-index"
1328checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
1329dependencies = [
1330 "log",
1331 "once_cell",
1332 "tracing-core",
1333]
1334
1335[[package]]
1336name = "tracing-subscriber"
1337version = "0.3.20"
1338source = "registry+https://github.com/rust-lang/crates.io-index"
1339checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
1340dependencies = [
1341 "matchers",
1342 "nu-ansi-term",
1343 "once_cell",
1344 "regex-automata",
1345 "sharded-slab",
1346 "smallvec",
1347 "thread_local",
1348 "tracing",
1349 "tracing-core",
1350 "tracing-log",
1351]
1352
1353[[package]]
1354name = "unicase"
1355version = "2.8.1"
1356source = "registry+https://github.com/rust-lang/crates.io-index"
1357checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
1358
1359[[package]]
1360name = "unicode-ident"
1361version = "1.0.22"
1362source = "registry+https://github.com/rust-lang/crates.io-index"
1363checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
1364
1365[[package]]
1366name = "unicode-segmentation"
1367version = "1.12.0"
1368source = "registry+https://github.com/rust-lang/crates.io-index"
1369checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
1370
1371[[package]]
1372name = "unicode-width"
1373version = "0.1.14"
1374source = "registry+https://github.com/rust-lang/crates.io-index"
1375checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
1376
1377[[package]]
1378name = "valuable"
1379version = "0.1.1"
1380source = "registry+https://github.com/rust-lang/crates.io-index"
1381checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
1382
1383[[package]]
1384name = "vcell"
1385version = "0.1.3"
1386source = "registry+https://github.com/rust-lang/crates.io-index"
1387checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
1388
1389[[package]]
1390name = "void"
1391version = "1.0.2"
1392source = "registry+https://github.com/rust-lang/crates.io-index"
1393checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
1394
1395[[package]]
1396name = "volatile-register"
1397version = "0.2.2"
1398source = "registry+https://github.com/rust-lang/crates.io-index"
1399checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
1400dependencies = [
1401 "vcell",
1402]
1403
1404[[package]]
1405name = "windows"
1406version = "0.61.3"
1407source = "registry+https://github.com/rust-lang/crates.io-index"
1408checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
1409dependencies = [
1410 "windows-collections",
1411 "windows-core",
1412 "windows-future",
1413 "windows-link 0.1.3",
1414 "windows-numerics",
1415]
1416
1417[[package]]
1418name = "windows-collections"
1419version = "0.2.0"
1420source = "registry+https://github.com/rust-lang/crates.io-index"
1421checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
1422dependencies = [
1423 "windows-core",
1424]
1425
1426[[package]]
1427name = "windows-core"
1428version = "0.61.2"
1429source = "registry+https://github.com/rust-lang/crates.io-index"
1430checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
1431dependencies = [
1432 "windows-implement",
1433 "windows-interface",
1434 "windows-link 0.1.3",
1435 "windows-result",
1436 "windows-strings",
1437]
1438
1439[[package]]
1440name = "windows-future"
1441version = "0.2.1"
1442source = "registry+https://github.com/rust-lang/crates.io-index"
1443checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
1444dependencies = [
1445 "windows-core",
1446 "windows-link 0.1.3",
1447 "windows-threading",
1448]
1449
1450[[package]]
1451name = "windows-implement"
1452version = "0.60.2"
1453source = "registry+https://github.com/rust-lang/crates.io-index"
1454checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
1455dependencies = [
1456 "proc-macro2",
1457 "quote",
1458 "syn 2.0.110",
1459]
1460
1461[[package]]
1462name = "windows-interface"
1463version = "0.59.3"
1464source = "registry+https://github.com/rust-lang/crates.io-index"
1465checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
1466dependencies = [
1467 "proc-macro2",
1468 "quote",
1469 "syn 2.0.110",
1470]
1471
1472[[package]]
1473name = "windows-link"
1474version = "0.1.3"
1475source = "registry+https://github.com/rust-lang/crates.io-index"
1476checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
1477
1478[[package]]
1479name = "windows-link"
1480version = "0.2.1"
1481source = "registry+https://github.com/rust-lang/crates.io-index"
1482checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
1483
1484[[package]]
1485name = "windows-numerics"
1486version = "0.2.0"
1487source = "registry+https://github.com/rust-lang/crates.io-index"
1488checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
1489dependencies = [
1490 "windows-core",
1491 "windows-link 0.1.3",
1492]
1493
1494[[package]]
1495name = "windows-result"
1496version = "0.3.4"
1497source = "registry+https://github.com/rust-lang/crates.io-index"
1498checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
1499dependencies = [
1500 "windows-link 0.1.3",
1501]
1502
1503[[package]]
1504name = "windows-strings"
1505version = "0.4.2"
1506source = "registry+https://github.com/rust-lang/crates.io-index"
1507checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
1508dependencies = [
1509 "windows-link 0.1.3",
1510]
1511
1512[[package]]
1513name = "windows-sys"
1514version = "0.61.2"
1515source = "registry+https://github.com/rust-lang/crates.io-index"
1516checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
1517dependencies = [
1518 "windows-link 0.2.1",
1519]
1520
1521[[package]]
1522name = "windows-threading"
1523version = "0.1.0"
1524source = "registry+https://github.com/rust-lang/crates.io-index"
1525checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
1526dependencies = [
1527 "windows-link 0.1.3",
1528]
1529
1530[[package]]
1531name = "winnow"
1532version = "0.6.24"
1533source = "registry+https://github.com/rust-lang/crates.io-index"
1534checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a"
1535dependencies = [
1536 "memchr",
1537]
1538
1539[[package]]
1540name = "winnow"
1541version = "0.7.13"
1542source = "registry+https://github.com/rust-lang/crates.io-index"
1543checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
1544dependencies = [
1545 "memchr",
1546]
1547
1548[[package]]
1549name = "wyz"
1550version = "0.5.1"
1551source = "registry+https://github.com/rust-lang/crates.io-index"
1552checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
1553dependencies = [
1554 "tap",
1555]
diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml
new file mode 100644
index 000000000..a1092c416
--- /dev/null
+++ b/examples/mcxa/Cargo.toml
@@ -0,0 +1,26 @@
1[package]
2name = "embassy-mcxa-examples"
3version = "0.1.0"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
9cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] }
10critical-section = "1.2.0"
11defmt = "1.0"
12defmt-rtt = "1.0"
13embassy-embedded-hal = "0.5.0"
14embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false }
15embassy-mcxa = { path = "../", features = ["defmt", "unstable-pac", "time"] }
16embassy-sync = "0.7.2"
17embassy-time = "0.5.0"
18embassy-time-driver = "0.2.1"
19embedded-io-async = "0.6.1"
20heapless = "0.9.2"
21panic-probe = { version = "1.0", features = ["print-defmt"] }
22tmp108 = "0.4.0"
23
24[profile.release]
25lto = true # better optimizations
26debug = 2 # enough information for defmt/rtt locations
diff --git a/examples/mcxa/build.rs b/examples/mcxa/build.rs
new file mode 100644
index 000000000..f076bba9f
--- /dev/null
+++ b/examples/mcxa/build.rs
@@ -0,0 +1,20 @@
1use std::env;
2use std::fs::File;
3use std::io::Write;
4use std::path::PathBuf;
5
6fn main() {
7 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
8
9 // Generate memory.x - put "FLASH" at start of RAM, RAM after "FLASH"
10 // cortex-m-rt expects FLASH for code, RAM for data/bss/stack
11 // Both are in RAM, but separated to satisfy cortex-m-rt's expectations
12 // MCXA256 has 128KB RAM total
13 File::create(out.join("memory.x"))
14 .unwrap()
15 .write_all(include_bytes!("memory.x"))
16 .unwrap();
17
18 println!("cargo:rustc-link-search={}", out.display());
19 println!("cargo:rerun-if-changed=memory.x");
20}
diff --git a/examples/mcxa/memory.x b/examples/mcxa/memory.x
new file mode 100644
index 000000000..315ced58a
--- /dev/null
+++ b/examples/mcxa/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 1M
4 RAM : ORIGIN = 0x20000000, LENGTH = 128K
5}
diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs
new file mode 100644
index 000000000..83d8046b3
--- /dev/null
+++ b/examples/mcxa/src/bin/adc_interrupt.rs
@@ -0,0 +1,84 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa_examples::init_adc_pins;
6use hal::adc::{LpadcConfig, TriggerPriorityPolicy};
7use hal::clocks::periph_helpers::{AdcClockSel, Div4};
8use hal::clocks::PoweredClock;
9use hal::pac::adc1::cfg::{Pwrsel, Refsel};
10use hal::pac::adc1::cmdl1::{Adch, Mode};
11use hal::pac::adc1::ctrl::CalAvgs;
12use hal::pac::adc1::tctrl::Tcmd;
13use hal::{bind_interrupts, InterruptExt};
14use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 ADC1 => hal::adc::AdcHandler;
18});
19
20#[used]
21#[no_mangle]
22static KEEP_ADC: unsafe extern "C" fn() = ADC1;
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let p = hal::init(hal::config::Config::default());
27
28 defmt::info!("ADC interrupt Example");
29
30 unsafe {
31 init_adc_pins();
32 }
33
34 let adc_config = LpadcConfig {
35 enable_in_doze_mode: true,
36 conversion_average_mode: CalAvgs::Average128,
37 enable_analog_preliminary: true,
38 power_up_delay: 0x80,
39 reference_voltage_source: Refsel::Option3,
40 power_level_mode: Pwrsel::Lowest,
41 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
42 enable_conv_pause: false,
43 conv_pause_delay: 0,
44 fifo_watermark: 0,
45 power: PoweredClock::NormalEnabledDeepSleepDisabled,
46 source: AdcClockSel::FroLfDiv,
47 div: Div4::no_div(),
48 };
49 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config);
50
51 adc.do_offset_calibration();
52 adc.do_auto_calibration();
53
54 let mut conv_command_config = adc.get_default_conv_command_config();
55 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8;
56 conv_command_config.conversion_resolution_mode = Mode::Data16Bits;
57 adc.set_conv_command_config(1, &conv_command_config);
58
59 let mut conv_trigger_config = adc.get_default_conv_trigger_config();
60 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1;
61 conv_trigger_config.enable_hardware_trigger = false;
62 adc.set_conv_trigger_config(0, &conv_trigger_config);
63
64 defmt::info!("ADC configuration done...");
65
66 adc.enable_interrupt(0x1);
67
68 unsafe {
69 hal::interrupt::ADC1.enable();
70 }
71
72 unsafe {
73 cortex_m::interrupt::enable();
74 }
75
76 loop {
77 adc.do_software_trigger(1);
78 while !adc.is_interrupt_triggered() {
79 // Wait until the interrupt is triggered
80 }
81 defmt::info!("*** ADC interrupt TRIGGERED! ***");
82 //TBD need to print the value
83 }
84}
diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs
new file mode 100644
index 000000000..ddf3f586b
--- /dev/null
+++ b/examples/mcxa/src/bin/adc_polling.rs
@@ -0,0 +1,68 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa_examples::init_adc_pins;
6use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy};
7use hal::clocks::periph_helpers::{AdcClockSel, Div4};
8use hal::clocks::PoweredClock;
9use hal::pac::adc1::cfg::{Pwrsel, Refsel};
10use hal::pac::adc1::cmdl1::{Adch, Mode};
11use hal::pac::adc1::ctrl::CalAvgs;
12use hal::pac::adc1::tctrl::Tcmd;
13use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
14
15const G_LPADC_RESULT_SHIFT: u32 = 0;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = hal::init(hal::config::Config::default());
20
21 unsafe {
22 init_adc_pins();
23 }
24
25 defmt::info!("=== ADC polling Example ===");
26
27 let adc_config = LpadcConfig {
28 enable_in_doze_mode: true,
29 conversion_average_mode: CalAvgs::Average128,
30 enable_analog_preliminary: true,
31 power_up_delay: 0x80,
32 reference_voltage_source: Refsel::Option3,
33 power_level_mode: Pwrsel::Lowest,
34 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
35 enable_conv_pause: false,
36 conv_pause_delay: 0,
37 fifo_watermark: 0,
38 power: PoweredClock::NormalEnabledDeepSleepDisabled,
39 source: AdcClockSel::FroLfDiv,
40 div: Div4::no_div(),
41 };
42 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config);
43
44 adc.do_offset_calibration();
45 adc.do_auto_calibration();
46
47 let mut conv_command_config = adc.get_default_conv_command_config();
48 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8;
49 conv_command_config.conversion_resolution_mode = Mode::Data16Bits;
50 adc.set_conv_command_config(1, &conv_command_config);
51
52 let mut conv_trigger_config = adc.get_default_conv_trigger_config();
53 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1;
54 conv_trigger_config.enable_hardware_trigger = false;
55 adc.set_conv_trigger_config(0, &conv_trigger_config);
56
57 defmt::info!("=== ADC configuration done... ===");
58
59 loop {
60 adc.do_software_trigger(1);
61 let mut result: Option<ConvResult> = None;
62 while result.is_none() {
63 result = hal::adc::get_conv_result();
64 }
65 let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT;
66 defmt::info!("value: {=u16}", value);
67 }
68}
diff --git a/examples/mcxa/src/bin/blinky.rs b/examples/mcxa/src/bin/blinky.rs
new file mode 100644
index 000000000..dd08ec0d9
--- /dev/null
+++ b/examples/mcxa/src/bin/blinky.rs
@@ -0,0 +1,36 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::gpio::{DriveStrength, Level, Output, SlewRate};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = hal::init(hal::config::Config::default());
12
13 defmt::info!("Blink example");
14
15 let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast);
16 let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast);
17 let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast);
18
19 loop {
20 defmt::info!("Toggle LEDs");
21
22 red.toggle();
23 Timer::after_millis(250).await;
24
25 red.toggle();
26 green.toggle();
27 Timer::after_millis(250).await;
28
29 green.toggle();
30 blue.toggle();
31 Timer::after_millis(250).await;
32 blue.toggle();
33
34 Timer::after_millis(250).await;
35 }
36}
diff --git a/examples/mcxa/src/bin/button.rs b/examples/mcxa/src/bin/button.rs
new file mode 100644
index 000000000..943edbb15
--- /dev/null
+++ b/examples/mcxa/src/bin/button.rs
@@ -0,0 +1,23 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::gpio::{Input, Pull};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = hal::init(hal::config::Config::default());
12
13 defmt::info!("Button example");
14
15 // This button is labeled "WAKEUP" on the FRDM-MCXA276
16 // The board already has a 10K pullup
17 let monitor = Input::new(p.P1_7, Pull::Disabled);
18
19 loop {
20 defmt::info!("Pin level is {:?}", monitor.get_level());
21 Timer::after_millis(1000).await;
22 }
23}
diff --git a/examples/mcxa/src/bin/button_async.rs b/examples/mcxa/src/bin/button_async.rs
new file mode 100644
index 000000000..6cc7b62cd
--- /dev/null
+++ b/examples/mcxa/src/bin/button_async.rs
@@ -0,0 +1,29 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::gpio::{Input, Pull};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = hal::init(hal::config::Config::default());
12
13 defmt::info!("GPIO interrupt example");
14
15 // This button is labeled "WAKEUP" on the FRDM-MCXA276
16 // The board already has a 10K pullup
17 let mut pin = Input::new(p.P1_7, Pull::Disabled);
18
19 let mut press_count = 0u32;
20
21 loop {
22 pin.wait_for_falling_edge().await;
23
24 press_count += 1;
25
26 defmt::info!("Button pressed! Count: {}", press_count);
27 Timer::after_millis(50).await;
28 }
29}
diff --git a/examples/mcxa/src/bin/clkout.rs b/examples/mcxa/src/bin/clkout.rs
new file mode 100644
index 000000000..bfd963540
--- /dev/null
+++ b/examples/mcxa/src/bin/clkout.rs
@@ -0,0 +1,69 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4};
6use embassy_mcxa::clocks::PoweredClock;
7use embassy_mcxa::gpio::{DriveStrength, SlewRate};
8use embassy_mcxa::{Level, Output};
9use embassy_time::Timer;
10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11
12/// Demonstrate CLKOUT, using Pin P4.2
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = hal::init(hal::config::Config::default());
16 let mut pin = p.P4_2;
17 let mut clkout = p.CLKOUT;
18
19 loop {
20 defmt::info!("Set Low...");
21 let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow);
22 Timer::after_millis(500).await;
23
24 defmt::info!("Set High...");
25 output.set_high();
26 Timer::after_millis(400).await;
27
28 defmt::info!("Set Low...");
29 output.set_low();
30 Timer::after_millis(500).await;
31
32 defmt::info!("16k...");
33 // Run Clock Out with the 16K clock
34 let _clock_out = ClockOut::new(
35 clkout.reborrow(),
36 pin.reborrow(),
37 Config {
38 sel: ClockOutSel::Clk16K,
39 div: Div4::no_div(),
40 level: PoweredClock::NormalEnabledDeepSleepDisabled,
41 },
42 )
43 .unwrap();
44
45 Timer::after_millis(3000).await;
46
47 defmt::info!("Set Low...");
48 drop(_clock_out);
49
50 let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow);
51 Timer::after_millis(500).await;
52
53 // Run Clock Out with the 12M clock, divided by 3
54 defmt::info!("4M...");
55 let _clock_out = ClockOut::new(
56 clkout.reborrow(),
57 pin.reborrow(),
58 Config {
59 sel: ClockOutSel::Fro12M,
60 div: const { Div4::from_divisor(3).unwrap() },
61 level: PoweredClock::NormalEnabledDeepSleepDisabled,
62 },
63 )
64 .unwrap();
65
66 // Let it run for 3 seconds...
67 Timer::after_millis(3000).await;
68 }
69}
diff --git a/examples/mcxa/src/bin/dma_channel_link.rs b/examples/mcxa/src/bin/dma_channel_link.rs
new file mode 100644
index 000000000..92c7a9681
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_channel_link.rs
@@ -0,0 +1,372 @@
1//! DMA channel linking example for MCXA276.
2//!
3//! This example demonstrates DMA channel linking (minor and major loop linking):
4//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with:
5//! - Minor Link to Channel 1 (triggers CH1 after each minor loop)
6//! - Major Link to Channel 2 (triggers CH2 after major loop completes)
7//! - Channel 1: Transfers SRC_BUFFER to DEST_BUFFER1 (triggered by CH0 minor link)
8//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link)
9//!
10//! # Embassy-style features demonstrated:
11//! - `DmaChannel::new()` for channel creation
12//! - `DmaChannel::is_done()` and `clear_done()` helper methods
13//! - Channel linking with `set_minor_link()` and `set_major_link()`
14//! - Standard `DmaCh*InterruptHandler` with `bind_interrupts!` macro
15
16#![no_std]
17#![no_main]
18
19use embassy_executor::Spawner;
20use embassy_mcxa::clocks::config::Div8;
21use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler, DmaChannel};
22use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
23use embassy_mcxa::{bind_interrupts, pac};
24use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
25
26// Buffers
27static mut SRC_BUFFER: [u32; 4] = [1, 2, 3, 4];
28static mut DEST_BUFFER0: [u32; 4] = [0; 4];
29static mut DEST_BUFFER1: [u32; 4] = [0; 4];
30static mut DEST_BUFFER2: [u32; 4] = [0; 4];
31
32// Bind DMA channel interrupts using Embassy-style macro
33// The standard handlers call on_interrupt() which wakes wakers and clears flags
34bind_interrupts!(struct Irqs {
35 DMA_CH0 => DmaCh0InterruptHandler;
36 DMA_CH1 => DmaCh1InterruptHandler;
37 DMA_CH2 => DmaCh2InterruptHandler;
38});
39
40/// Helper to write a u32 as decimal ASCII to UART
41fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
42 let mut buf = [0u8; 10];
43 let mut n = val;
44 let mut i = buf.len();
45
46 if n == 0 {
47 tx.blocking_write(b"0").ok();
48 return;
49 }
50
51 while n > 0 {
52 i -= 1;
53 buf[i] = b'0' + (n % 10) as u8;
54 n /= 10;
55 }
56
57 tx.blocking_write(&buf[i..]).ok();
58}
59
60/// Helper to print a buffer to UART
61fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
62 tx.blocking_write(b"[").ok();
63 unsafe {
64 for i in 0..len {
65 write_u32(tx, *buf_ptr.add(i));
66 if i < len - 1 {
67 tx.blocking_write(b", ").ok();
68 }
69 }
70 }
71 tx.blocking_write(b"]").ok();
72}
73
74#[embassy_executor::main]
75async fn main(_spawner: Spawner) {
76 // Small delay to allow probe-rs to attach after reset
77 for _ in 0..100_000 {
78 cortex_m::asm::nop();
79 }
80
81 let mut cfg = hal::config::Config::default();
82 cfg.clock_cfg.sirc.fro_12m_enabled = true;
83 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
84 let p = hal::init(cfg);
85
86 defmt::info!("DMA channel link example starting...");
87
88 // DMA is initialized during hal::init() - no need to call ensure_init()
89
90 let pac_periphs = unsafe { pac::Peripherals::steal() };
91 let dma0 = &pac_periphs.dma0;
92 let edma = unsafe { &*pac::Edma0Tcd0::ptr() };
93
94 // Clear any residual state
95 for i in 0..3 {
96 let t = edma.tcd(i);
97 t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one());
98 t.ch_int().write(|w| w.int().clear_bit_by_one());
99 t.ch_es().write(|w| w.err().clear_bit_by_one());
100 t.ch_mux().write(|w| unsafe { w.bits(0) });
101 }
102
103 // Clear Global Halt/Error state
104 dma0.mp_csr().modify(|_, w| {
105 w.halt()
106 .normal_operation()
107 .hae()
108 .normal_operation()
109 .ecx()
110 .normal_operation()
111 .cx()
112 .normal_operation()
113 });
114
115 unsafe {
116 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
117 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1);
118 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH2);
119 }
120
121 let config = Config {
122 baudrate_bps: 115_200,
123 ..Default::default()
124 };
125
126 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
127 let (mut tx, _rx) = lpuart.split();
128
129 tx.blocking_write(b"EDMA channel link example begin.\r\n\r\n").unwrap();
130
131 // Initialize buffers
132 unsafe {
133 SRC_BUFFER = [1, 2, 3, 4];
134 DEST_BUFFER0 = [0; 4];
135 DEST_BUFFER1 = [0; 4];
136 DEST_BUFFER2 = [0; 4];
137 }
138
139 tx.blocking_write(b"Source Buffer: ").unwrap();
140 print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, 4);
141 tx.blocking_write(b"\r\n").unwrap();
142
143 tx.blocking_write(b"DEST0 (before): ").unwrap();
144 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4);
145 tx.blocking_write(b"\r\n").unwrap();
146
147 tx.blocking_write(b"DEST1 (before): ").unwrap();
148 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4);
149 tx.blocking_write(b"\r\n").unwrap();
150
151 tx.blocking_write(b"DEST2 (before): ").unwrap();
152 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4);
153 tx.blocking_write(b"\r\n\r\n").unwrap();
154
155 tx.blocking_write(b"Configuring DMA channels with Embassy-style API...\r\n")
156 .unwrap();
157
158 let ch0 = DmaChannel::new(p.DMA_CH0);
159 let ch1 = DmaChannel::new(p.DMA_CH1);
160 let ch2 = DmaChannel::new(p.DMA_CH2);
161
162 // Configure channels using direct TCD access (advanced feature demo)
163 // This example demonstrates channel linking which requires direct TCD manipulation
164
165 // Helper to configure TCD for memory-to-memory transfer
166 // Parameters: channel, src, dst, width, nbytes (minor loop), count (major loop), interrupt
167 #[allow(clippy::too_many_arguments)]
168 unsafe fn configure_tcd(
169 edma: &embassy_mcxa::pac::edma_0_tcd0::RegisterBlock,
170 ch: usize,
171 src: u32,
172 dst: u32,
173 width: u8,
174 nbytes: u32,
175 count: u16,
176 enable_int: bool,
177 ) {
178 let t = edma.tcd(ch);
179
180 // Reset channel state
181 t.ch_csr().write(|w| {
182 w.erq()
183 .disable()
184 .earq()
185 .disable()
186 .eei()
187 .no_error()
188 .ebw()
189 .disable()
190 .done()
191 .clear_bit_by_one()
192 });
193 t.ch_es().write(|w| w.bits(0));
194 t.ch_int().write(|w| w.int().clear_bit_by_one());
195
196 // Source/destination addresses
197 t.tcd_saddr().write(|w| w.saddr().bits(src));
198 t.tcd_daddr().write(|w| w.daddr().bits(dst));
199
200 // Offsets: increment by width
201 t.tcd_soff().write(|w| w.soff().bits(width as u16));
202 t.tcd_doff().write(|w| w.doff().bits(width as u16));
203
204 // Attributes: size = log2(width)
205 let size = match width {
206 1 => 0,
207 2 => 1,
208 4 => 2,
209 _ => 0,
210 };
211 t.tcd_attr().write(|w| w.ssize().bits(size).dsize().bits(size));
212
213 // Number of bytes per minor loop
214 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
215
216 // Major loop: reset source address after major loop
217 let total_bytes = nbytes * count as u32;
218 t.tcd_slast_sda()
219 .write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32));
220 t.tcd_dlast_sga()
221 .write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32));
222
223 // Major loop count
224 t.tcd_biter_elinkno().write(|w| w.biter().bits(count));
225 t.tcd_citer_elinkno().write(|w| w.citer().bits(count));
226
227 // Control/status: enable interrupt if requested
228 if enable_int {
229 t.tcd_csr().write(|w| w.intmajor().set_bit());
230 } else {
231 t.tcd_csr().write(|w| w.intmajor().clear_bit());
232 }
233
234 cortex_m::asm::dsb();
235 }
236
237 unsafe {
238 // Channel 0: Transfer 16 bytes total (8 bytes per minor loop, 2 major iterations)
239 // Minor Link -> Channel 1
240 // Major Link -> Channel 2
241 configure_tcd(
242 edma,
243 0,
244 core::ptr::addr_of!(SRC_BUFFER) as u32,
245 core::ptr::addr_of_mut!(DEST_BUFFER0) as u32,
246 4, // src width
247 8, // nbytes (minor loop = 2 words)
248 2, // count (major loop = 2 iterations)
249 false, // no interrupt
250 );
251 ch0.set_minor_link(1); // Link to CH1 after each minor loop
252 ch0.set_major_link(2); // Link to CH2 after major loop
253
254 // Channel 1: Transfer 16 bytes (triggered by CH0 minor link)
255 configure_tcd(
256 edma,
257 1,
258 core::ptr::addr_of!(SRC_BUFFER) as u32,
259 core::ptr::addr_of_mut!(DEST_BUFFER1) as u32,
260 4,
261 16, // full buffer in one minor loop
262 1, // 1 major iteration
263 false,
264 );
265
266 // Channel 2: Transfer 16 bytes (triggered by CH0 major link)
267 configure_tcd(
268 edma,
269 2,
270 core::ptr::addr_of!(SRC_BUFFER) as u32,
271 core::ptr::addr_of_mut!(DEST_BUFFER2) as u32,
272 4,
273 16, // full buffer in one minor loop
274 1, // 1 major iteration
275 true, // enable interrupt
276 );
277 }
278
279 tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n")
280 .unwrap();
281
282 // Trigger first minor loop of CH0
283 unsafe {
284 ch0.trigger_start();
285 }
286
287 // Wait for CH1 to complete (triggered by CH0 minor link)
288 while !ch1.is_done() {
289 cortex_m::asm::nop();
290 }
291 unsafe {
292 ch1.clear_done();
293 }
294
295 tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap();
296 tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n")
297 .unwrap();
298
299 // Trigger second minor loop of CH0
300 unsafe {
301 ch0.trigger_start();
302 }
303
304 // Wait for CH0 major loop to complete
305 while !ch0.is_done() {
306 cortex_m::asm::nop();
307 }
308 unsafe {
309 ch0.clear_done();
310 }
311
312 tx.blocking_write(b"CH0 major loop done.\r\n").unwrap();
313
314 // Wait for CH2 to complete (triggered by CH0 major link)
315 // Using is_done() instead of AtomicBool - the standard interrupt handler
316 // clears the interrupt flag and wakes wakers, but DONE bit remains set
317 while !ch2.is_done() {
318 cortex_m::asm::nop();
319 }
320 unsafe {
321 ch2.clear_done();
322 }
323
324 tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap();
325
326 tx.blocking_write(b"EDMA channel link example finish.\r\n\r\n").unwrap();
327
328 tx.blocking_write(b"DEST0 (after): ").unwrap();
329 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4);
330 tx.blocking_write(b"\r\n").unwrap();
331
332 tx.blocking_write(b"DEST1 (after): ").unwrap();
333 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4);
334 tx.blocking_write(b"\r\n").unwrap();
335
336 tx.blocking_write(b"DEST2 (after): ").unwrap();
337 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4);
338 tx.blocking_write(b"\r\n\r\n").unwrap();
339
340 // Verify all buffers match source
341 let mut success = true;
342 unsafe {
343 let src_ptr = core::ptr::addr_of!(SRC_BUFFER) as *const u32;
344 let dst0_ptr = core::ptr::addr_of!(DEST_BUFFER0) as *const u32;
345 let dst1_ptr = core::ptr::addr_of!(DEST_BUFFER1) as *const u32;
346 let dst2_ptr = core::ptr::addr_of!(DEST_BUFFER2) as *const u32;
347
348 for i in 0..4 {
349 if *dst0_ptr.add(i) != *src_ptr.add(i) {
350 success = false;
351 }
352 if *dst1_ptr.add(i) != *src_ptr.add(i) {
353 success = false;
354 }
355 if *dst2_ptr.add(i) != *src_ptr.add(i) {
356 success = false;
357 }
358 }
359 }
360
361 if success {
362 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
363 defmt::info!("PASS: Data verified.");
364 } else {
365 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
366 defmt::error!("FAIL: Mismatch detected!");
367 }
368
369 loop {
370 cortex_m::asm::wfe();
371 }
372}
diff --git a/examples/mcxa/src/bin/dma_interleave_transfer.rs b/examples/mcxa/src/bin/dma_interleave_transfer.rs
new file mode 100644
index 000000000..7876e8978
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_interleave_transfer.rs
@@ -0,0 +1,215 @@
1//! DMA interleaved transfer example for MCXA276.
2//!
3//! This example demonstrates using DMA with custom source/destination offsets
4//! to interleave data during transfer.
5//!
6//! # Embassy-style features demonstrated:
7//! - `TransferOptions::default()` for configuration (used internally)
8//! - DMA channel with `DmaChannel::new()`
9
10#![no_std]
11#![no_main]
12
13use embassy_executor::Spawner;
14use embassy_mcxa::clocks::config::Div8;
15use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel};
16use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
17use embassy_mcxa::{bind_interrupts, pac};
18use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
19
20// Bind DMA channel 0 interrupt using Embassy-style macro
21bind_interrupts!(struct Irqs {
22 DMA_CH0 => DmaCh0InterruptHandler;
23});
24
25const BUFFER_LENGTH: usize = 16;
26const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2;
27
28// Buffers in RAM
29static mut SRC_BUFFER: [u32; HALF_BUFF_LENGTH] = [0; HALF_BUFF_LENGTH];
30static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH];
31
32/// Helper to write a u32 as decimal ASCII to UART
33fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
34 let mut buf = [0u8; 10];
35 let mut n = val;
36 let mut i = buf.len();
37
38 if n == 0 {
39 tx.blocking_write(b"0").ok();
40 return;
41 }
42
43 while n > 0 {
44 i -= 1;
45 buf[i] = b'0' + (n % 10) as u8;
46 n /= 10;
47 }
48
49 tx.blocking_write(&buf[i..]).ok();
50}
51
52/// Helper to print a buffer to UART
53fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
54 tx.blocking_write(b"[").ok();
55 unsafe {
56 for i in 0..len {
57 write_u32(tx, *buf_ptr.add(i));
58 if i < len - 1 {
59 tx.blocking_write(b", ").ok();
60 }
61 }
62 }
63 tx.blocking_write(b"]").ok();
64}
65
66#[embassy_executor::main]
67async fn main(_spawner: Spawner) {
68 // Small delay to allow probe-rs to attach after reset
69 for _ in 0..100_000 {
70 cortex_m::asm::nop();
71 }
72
73 let mut cfg = hal::config::Config::default();
74 cfg.clock_cfg.sirc.fro_12m_enabled = true;
75 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
76 let p = hal::init(cfg);
77
78 defmt::info!("DMA interleave transfer example starting...");
79
80 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
81 unsafe {
82 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
83 }
84
85 let config = Config {
86 baudrate_bps: 115_200,
87 ..Default::default()
88 };
89
90 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
91 let (mut tx, _rx) = lpuart.split();
92
93 tx.blocking_write(b"EDMA interleave transfer example begin.\r\n\r\n")
94 .unwrap();
95
96 // Initialize buffers
97 unsafe {
98 SRC_BUFFER = [1, 2, 3, 4, 5, 6, 7, 8];
99 DEST_BUFFER = [0; BUFFER_LENGTH];
100 }
101
102 tx.blocking_write(b"Source Buffer: ").unwrap();
103 print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, HALF_BUFF_LENGTH);
104 tx.blocking_write(b"\r\n").unwrap();
105
106 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
107 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH);
108 tx.blocking_write(b"\r\n").unwrap();
109
110 tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n")
111 .unwrap();
112
113 // Create DMA channel using Embassy-style API
114 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
115
116 // Configure interleaved transfer using direct TCD access:
117 // - src_offset = 4: advance source by 4 bytes after each read
118 // - dst_offset = 8: advance dest by 8 bytes after each write
119 // This spreads source data across every other word in destination
120 unsafe {
121 let t = dma_ch0.tcd();
122
123 // Reset channel state
124 t.ch_csr().write(|w| {
125 w.erq()
126 .disable()
127 .earq()
128 .disable()
129 .eei()
130 .no_error()
131 .ebw()
132 .disable()
133 .done()
134 .clear_bit_by_one()
135 });
136 t.ch_es().write(|w| w.bits(0));
137 t.ch_int().write(|w| w.int().clear_bit_by_one());
138
139 // Source/destination addresses
140 t.tcd_saddr()
141 .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(SRC_BUFFER) as u32));
142 t.tcd_daddr()
143 .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32));
144
145 // Custom offsets for interleaving
146 t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read
147 t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write
148
149 // Attributes: 32-bit transfers (size = 2)
150 t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2));
151
152 // Transfer entire source buffer in one minor loop
153 let nbytes = (HALF_BUFF_LENGTH * 4) as u32;
154 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
155
156 // Reset source address after major loop
157 t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32));
158 // Destination uses 2x offset, so adjust accordingly
159 let dst_total = (HALF_BUFF_LENGTH * 8) as u32;
160 t.tcd_dlast_sga()
161 .write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32));
162
163 // Major loop count = 1
164 t.tcd_biter_elinkno().write(|w| w.biter().bits(1));
165 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
166
167 // Enable interrupt on major loop completion
168 t.tcd_csr().write(|w| w.intmajor().set_bit());
169
170 cortex_m::asm::dsb();
171
172 tx.blocking_write(b"Triggering transfer...\r\n").unwrap();
173 dma_ch0.trigger_start();
174 }
175
176 // Wait for completion using channel helper method
177 while !dma_ch0.is_done() {
178 cortex_m::asm::nop();
179 }
180 unsafe {
181 dma_ch0.clear_done();
182 }
183
184 tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n")
185 .unwrap();
186 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
187 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH);
188 tx.blocking_write(b"\r\n\r\n").unwrap();
189
190 // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0
191 let mut mismatch = false;
192 unsafe {
193 for i in 0..BUFFER_LENGTH {
194 if i % 2 == 0 {
195 if DEST_BUFFER[i] != SRC_BUFFER[i / 2] {
196 mismatch = true;
197 }
198 } else if DEST_BUFFER[i] != 0 {
199 mismatch = true;
200 }
201 }
202 }
203
204 if mismatch {
205 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
206 defmt::error!("FAIL: Mismatch detected!");
207 } else {
208 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
209 defmt::info!("PASS: Data verified.");
210 }
211
212 loop {
213 cortex_m::asm::wfe();
214 }
215}
diff --git a/examples/mcxa/src/bin/dma_mem_to_mem.rs b/examples/mcxa/src/bin/dma_mem_to_mem.rs
new file mode 100644
index 000000000..68f70e742
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_mem_to_mem.rs
@@ -0,0 +1,229 @@
1//! DMA memory-to-memory transfer example for MCXA276.
2//!
3//! This example demonstrates using DMA to copy data between memory buffers
4//! using the Embassy-style async API with type-safe transfers.
5//!
6//! # Embassy-style features demonstrated:
7//! - `TransferOptions` for configuration
8//! - Type-safe `mem_to_mem<u32>()` method with async `.await`
9//! - `Transfer` Future that can be `.await`ed
10//! - `Word` trait for automatic transfer width detection
11//! - `memset()` method for filling memory with a pattern
12
13#![no_std]
14#![no_main]
15
16use embassy_executor::Spawner;
17use embassy_mcxa::clocks::config::Div8;
18use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, TransferOptions};
19use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
20use embassy_mcxa::{bind_interrupts, pac};
21use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
22
23// Bind DMA channel 0 interrupt using Embassy-style macro
24bind_interrupts!(struct Irqs {
25 DMA_CH0 => DmaCh0InterruptHandler;
26});
27
28const BUFFER_LENGTH: usize = 4;
29
30// Buffers in RAM (static mut is automatically placed in .bss/.data)
31static mut SRC_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH];
32static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH];
33static mut MEMSET_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH];
34
35/// Helper to write a u32 as decimal ASCII to UART
36fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
37 let mut buf = [0u8; 10]; // u32 max is 4294967295 (10 digits)
38 let mut n = val;
39 let mut i = buf.len();
40
41 if n == 0 {
42 tx.blocking_write(b"0").ok();
43 return;
44 }
45
46 while n > 0 {
47 i -= 1;
48 buf[i] = b'0' + (n % 10) as u8;
49 n /= 10;
50 }
51
52 tx.blocking_write(&buf[i..]).ok();
53}
54
55/// Helper to print a buffer as [v1, v2, v3, v4] to UART
56/// Takes a raw pointer to avoid warnings about shared references to mutable statics
57fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const [u32; BUFFER_LENGTH]) {
58 tx.blocking_write(b"[").ok();
59 unsafe {
60 let buf = &*buf_ptr;
61 for (i, val) in buf.iter().enumerate() {
62 write_u32(tx, *val);
63 if i < buf.len() - 1 {
64 tx.blocking_write(b", ").ok();
65 }
66 }
67 }
68 tx.blocking_write(b"]").ok();
69}
70
71#[embassy_executor::main]
72async fn main(_spawner: Spawner) {
73 // Small delay to allow probe-rs to attach after reset
74 for _ in 0..100_000 {
75 cortex_m::asm::nop();
76 }
77
78 let mut cfg = hal::config::Config::default();
79 cfg.clock_cfg.sirc.fro_12m_enabled = true;
80 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
81 let p = hal::init(cfg);
82
83 defmt::info!("DMA memory-to-memory example starting...");
84
85 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
86 unsafe {
87 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
88 }
89
90 // Create UART for debug output
91 let config = Config {
92 baudrate_bps: 115_200,
93 ..Default::default()
94 };
95
96 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
97 let (mut tx, _rx) = lpuart.split();
98
99 tx.blocking_write(b"EDMA memory to memory example begin.\r\n\r\n")
100 .unwrap();
101
102 // Initialize buffers
103 unsafe {
104 SRC_BUFFER = [1, 2, 3, 4];
105 DEST_BUFFER = [0; BUFFER_LENGTH];
106 }
107
108 tx.blocking_write(b"Source Buffer: ").unwrap();
109 print_buffer(&mut tx, &raw const SRC_BUFFER);
110 tx.blocking_write(b"\r\n").unwrap();
111
112 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
113 print_buffer(&mut tx, &raw const DEST_BUFFER);
114 tx.blocking_write(b"\r\n").unwrap();
115
116 tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n")
117 .unwrap();
118
119 // Create DMA channel
120 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
121
122 // Configure transfer options (Embassy-style)
123 // TransferOptions defaults to: complete_transfer_interrupt = true
124 let options = TransferOptions::default();
125
126 // =========================================================================
127 // Part 1: Embassy-style async API demonstration (mem_to_mem)
128 // =========================================================================
129 //
130 // Use the new type-safe `mem_to_mem<u32>()` method:
131 // - Automatically determines transfer width from buffer element type (u32)
132 // - Returns a `Transfer` future that can be `.await`ed
133 // - Uses TransferOptions for consistent configuration
134 //
135 // Using async `.await` - the executor can run other tasks while waiting!
136
137 // Perform type-safe memory-to-memory transfer using Embassy-style async API
138 unsafe {
139 let src = &*core::ptr::addr_of!(SRC_BUFFER);
140 let dst = &mut *core::ptr::addr_of_mut!(DEST_BUFFER);
141
142 // Using async `.await` - the executor can run other tasks while waiting!
143 let transfer = dma_ch0.mem_to_mem(src, dst, options);
144 transfer.await;
145 }
146
147 tx.blocking_write(b"DMA mem-to-mem transfer complete!\r\n\r\n").unwrap();
148 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
149 print_buffer(&mut tx, &raw const DEST_BUFFER);
150 tx.blocking_write(b"\r\n").unwrap();
151
152 // Verify data
153 let mut mismatch = false;
154 unsafe {
155 for i in 0..BUFFER_LENGTH {
156 if SRC_BUFFER[i] != DEST_BUFFER[i] {
157 mismatch = true;
158 break;
159 }
160 }
161 }
162
163 if mismatch {
164 tx.blocking_write(b"FAIL: mem_to_mem mismatch!\r\n").unwrap();
165 defmt::error!("FAIL: mem_to_mem mismatch!");
166 } else {
167 tx.blocking_write(b"PASS: mem_to_mem verified.\r\n\r\n").unwrap();
168 defmt::info!("PASS: mem_to_mem verified.");
169 }
170
171 // =========================================================================
172 // Part 2: memset() demonstration
173 // =========================================================================
174 //
175 // The `memset()` method fills a buffer with a pattern value:
176 // - Fixed source address (pattern is read repeatedly)
177 // - Incrementing destination address
178 // - Uses the same Transfer future pattern
179
180 tx.blocking_write(b"--- Demonstrating memset() feature ---\r\n\r\n")
181 .unwrap();
182
183 tx.blocking_write(b"Memset Buffer (before): ").unwrap();
184 print_buffer(&mut tx, &raw const MEMSET_BUFFER);
185 tx.blocking_write(b"\r\n").unwrap();
186
187 // Fill buffer with a pattern value using DMA memset
188 let pattern: u32 = 0xDEADBEEF;
189 tx.blocking_write(b"Filling with pattern 0xDEADBEEF...\r\n").unwrap();
190
191 unsafe {
192 let dst = &mut *core::ptr::addr_of_mut!(MEMSET_BUFFER);
193
194 // Using blocking_wait() for demonstration - also shows non-async usage
195 let transfer = dma_ch0.memset(&pattern, dst, options);
196 transfer.blocking_wait();
197 }
198
199 tx.blocking_write(b"DMA memset complete!\r\n\r\n").unwrap();
200 tx.blocking_write(b"Memset Buffer (after): ").unwrap();
201 print_buffer(&mut tx, &raw const MEMSET_BUFFER);
202 tx.blocking_write(b"\r\n").unwrap();
203
204 // Verify memset result
205 let mut memset_ok = true;
206 unsafe {
207 #[allow(clippy::needless_range_loop)]
208 for i in 0..BUFFER_LENGTH {
209 if MEMSET_BUFFER[i] != pattern {
210 memset_ok = false;
211 break;
212 }
213 }
214 }
215
216 if !memset_ok {
217 tx.blocking_write(b"FAIL: memset mismatch!\r\n").unwrap();
218 defmt::error!("FAIL: memset mismatch!");
219 } else {
220 tx.blocking_write(b"PASS: memset verified.\r\n\r\n").unwrap();
221 defmt::info!("PASS: memset verified.");
222 }
223
224 tx.blocking_write(b"=== All DMA tests complete ===\r\n").unwrap();
225
226 loop {
227 cortex_m::asm::wfe();
228 }
229}
diff --git a/examples/mcxa/src/bin/dma_memset.rs b/examples/mcxa/src/bin/dma_memset.rs
new file mode 100644
index 000000000..95e365e47
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_memset.rs
@@ -0,0 +1,218 @@
1//! DMA memset example for MCXA276.
2//!
3//! This example demonstrates using DMA to fill a buffer with a repeated pattern.
4//! The source address stays fixed while the destination increments.
5//!
6//! # Embassy-style features demonstrated:
7//! - `DmaChannel::is_done()` and `clear_done()` helper methods
8//! - No need to pass register block around
9
10#![no_std]
11#![no_main]
12
13use embassy_executor::Spawner;
14use embassy_mcxa::clocks::config::Div8;
15use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel};
16use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
17use embassy_mcxa::{bind_interrupts, pac};
18use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
19
20// Bind DMA channel 0 interrupt using Embassy-style macro
21bind_interrupts!(struct Irqs {
22 DMA_CH0 => DmaCh0InterruptHandler;
23});
24
25const BUFFER_LENGTH: usize = 4;
26
27// Buffers in RAM
28static mut PATTERN: u32 = 0;
29static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH];
30
31/// Helper to write a u32 as decimal ASCII to UART
32fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
33 let mut buf = [0u8; 10];
34 let mut n = val;
35 let mut i = buf.len();
36
37 if n == 0 {
38 tx.blocking_write(b"0").ok();
39 return;
40 }
41
42 while n > 0 {
43 i -= 1;
44 buf[i] = b'0' + (n % 10) as u8;
45 n /= 10;
46 }
47
48 tx.blocking_write(&buf[i..]).ok();
49}
50
51/// Helper to print a buffer to UART
52fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
53 tx.blocking_write(b"[").ok();
54 unsafe {
55 for i in 0..len {
56 write_u32(tx, *buf_ptr.add(i));
57 if i < len - 1 {
58 tx.blocking_write(b", ").ok();
59 }
60 }
61 }
62 tx.blocking_write(b"]").ok();
63}
64
65#[embassy_executor::main]
66async fn main(_spawner: Spawner) {
67 // Small delay to allow probe-rs to attach after reset
68 for _ in 0..100_000 {
69 cortex_m::asm::nop();
70 }
71
72 let mut cfg = hal::config::Config::default();
73 cfg.clock_cfg.sirc.fro_12m_enabled = true;
74 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
75 let p = hal::init(cfg);
76
77 defmt::info!("DMA memset example starting...");
78
79 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
80 unsafe {
81 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
82 }
83
84 let config = Config {
85 baudrate_bps: 115_200,
86 ..Default::default()
87 };
88
89 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
90 let (mut tx, _rx) = lpuart.split();
91
92 tx.blocking_write(b"EDMA memset example begin.\r\n\r\n").unwrap();
93
94 // Initialize buffers
95 unsafe {
96 PATTERN = 0xDEADBEEF;
97 DEST_BUFFER = [0; BUFFER_LENGTH];
98 }
99
100 tx.blocking_write(b"Pattern value: 0x").unwrap();
101 // Print pattern in hex
102 unsafe {
103 let hex_chars = b"0123456789ABCDEF";
104 let mut hex_buf = [0u8; 8];
105 let mut val = PATTERN;
106 for i in (0..8).rev() {
107 hex_buf[i] = hex_chars[(val & 0xF) as usize];
108 val >>= 4;
109 }
110 tx.blocking_write(&hex_buf).ok();
111 }
112 tx.blocking_write(b"\r\n").unwrap();
113
114 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
115 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH);
116 tx.blocking_write(b"\r\n").unwrap();
117
118 tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n")
119 .unwrap();
120
121 // Create DMA channel using Embassy-style API
122 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
123
124 // Configure memset transfer using direct TCD access:
125 // Source stays fixed (soff = 0, reads same pattern repeatedly)
126 // Destination increments (doff = 4)
127 unsafe {
128 let t = dma_ch0.tcd();
129
130 // Reset channel state
131 t.ch_csr().write(|w| {
132 w.erq()
133 .disable()
134 .earq()
135 .disable()
136 .eei()
137 .no_error()
138 .ebw()
139 .disable()
140 .done()
141 .clear_bit_by_one()
142 });
143 t.ch_es().write(|w| w.bits(0));
144 t.ch_int().write(|w| w.int().clear_bit_by_one());
145
146 // Source address (pattern) - fixed
147 t.tcd_saddr()
148 .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(PATTERN) as u32));
149 // Destination address - increments
150 t.tcd_daddr()
151 .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32));
152
153 // Source offset = 0 (stays fixed), Dest offset = 4 (increments)
154 t.tcd_soff().write(|w| w.soff().bits(0));
155 t.tcd_doff().write(|w| w.doff().bits(4));
156
157 // Attributes: 32-bit transfers (size = 2)
158 t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2));
159
160 // Transfer entire buffer in one minor loop
161 let nbytes = (BUFFER_LENGTH * 4) as u32;
162 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
163
164 // Source doesn't need adjustment (stays fixed)
165 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0));
166 // Reset dest address after major loop
167 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32));
168
169 // Major loop count = 1
170 t.tcd_biter_elinkno().write(|w| w.biter().bits(1));
171 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
172
173 // Enable interrupt on major loop completion
174 t.tcd_csr().write(|w| w.intmajor().set_bit());
175
176 cortex_m::asm::dsb();
177
178 tx.blocking_write(b"Triggering transfer...\r\n").unwrap();
179 dma_ch0.trigger_start();
180 }
181
182 // Wait for completion using channel helper method
183 while !dma_ch0.is_done() {
184 cortex_m::asm::nop();
185 }
186 unsafe {
187 dma_ch0.clear_done();
188 }
189
190 tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n").unwrap();
191 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
192 print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH);
193 tx.blocking_write(b"\r\n\r\n").unwrap();
194
195 // Verify: All elements should equal PATTERN
196 let mut mismatch = false;
197 unsafe {
198 #[allow(clippy::needless_range_loop)]
199 for i in 0..BUFFER_LENGTH {
200 if DEST_BUFFER[i] != PATTERN {
201 mismatch = true;
202 break;
203 }
204 }
205 }
206
207 if mismatch {
208 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
209 defmt::error!("FAIL: Mismatch detected!");
210 } else {
211 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
212 defmt::info!("PASS: Data verified.");
213 }
214
215 loop {
216 cortex_m::asm::wfe();
217 }
218}
diff --git a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs
new file mode 100644
index 000000000..f8f543382
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs
@@ -0,0 +1,376 @@
1//! DMA ping-pong/double-buffer transfer example for MCXA276.
2//!
3//! This example demonstrates two approaches for ping-pong/double-buffering:
4//!
5//! ## Approach 1: Scatter/Gather with linked TCDs (manual)
6//! - Two TCDs link to each other for alternating transfers
7//! - Uses custom handler that delegates to on_interrupt() then signals completion
8//! - Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
9//! so we need an AtomicBool to track completion
10//!
11//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!)
12//! - Single continuous transfer over entire buffer
13//! - Uses half-transfer interrupt to know when first half is ready
14//! - Application can process first half while second half is being filled
15//!
16//! # Embassy-style features demonstrated:
17//! - `DmaChannel::new()` for channel creation
18//! - Scatter/gather with linked TCDs
19//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice)
20//! - Standard `DmaCh1InterruptHandler` with `bind_interrupts!` macro
21//! - NEW: `wait_half()` for half-transfer interrupt handling
22
23#![no_std]
24#![no_main]
25
26use core::sync::atomic::{AtomicBool, Ordering};
27
28use embassy_executor::Spawner;
29use embassy_mcxa::clocks::config::Div8;
30use embassy_mcxa::dma::{self, DmaCh1InterruptHandler, DmaChannel, Tcd, TransferOptions};
31use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
32use embassy_mcxa::{bind_interrupts, pac};
33use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
34
35// Source and destination buffers for Approach 1 (scatter/gather)
36static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
37static mut DST: [u32; 8] = [0; 8];
38
39// Source and destination buffers for Approach 2 (wait_half)
40static mut SRC2: [u32; 8] = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4];
41static mut DST2: [u32; 8] = [0; 8];
42
43// TCD pool for scatter/gather - must be 32-byte aligned
44#[repr(C, align(32))]
45struct TcdPool([Tcd; 2]);
46
47static mut TCD_POOL: TcdPool = TcdPool(
48 [Tcd {
49 saddr: 0,
50 soff: 0,
51 attr: 0,
52 nbytes: 0,
53 slast: 0,
54 daddr: 0,
55 doff: 0,
56 citer: 0,
57 dlast_sga: 0,
58 csr: 0,
59 biter: 0,
60 }; 2],
61);
62
63// AtomicBool to track scatter/gather completion
64// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
65// so we need this flag to detect when each transfer completes
66static TRANSFER_DONE: AtomicBool = AtomicBool::new(false);
67
68// Custom handler for scatter/gather that delegates to HAL's on_interrupt()
69// This follows the "interrupts as threads" pattern - the handler does minimal work
70// (delegates to HAL + sets a flag) and the main task does the actual processing
71pub struct PingPongDmaHandler;
72
73impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH0> for PingPongDmaHandler {
74 unsafe fn on_interrupt() {
75 // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers
76 dma::on_interrupt(0);
77 // Signal completion for polling (needed because ESG clears DONE bit)
78 TRANSFER_DONE.store(true, Ordering::Release);
79 }
80}
81
82// Bind DMA channel interrupts
83// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag)
84// CH1: Standard handler for wait_half() demo
85bind_interrupts!(struct Irqs {
86 DMA_CH0 => PingPongDmaHandler;
87 DMA_CH1 => DmaCh1InterruptHandler;
88});
89
90/// Helper to write a u32 as decimal ASCII to UART
91fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
92 let mut buf = [0u8; 10];
93 let mut n = val;
94 let mut i = buf.len();
95
96 if n == 0 {
97 tx.blocking_write(b"0").ok();
98 return;
99 }
100
101 while n > 0 {
102 i -= 1;
103 buf[i] = b'0' + (n % 10) as u8;
104 n /= 10;
105 }
106
107 tx.blocking_write(&buf[i..]).ok();
108}
109
110/// Helper to print a buffer to UART
111fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
112 tx.blocking_write(b"[").ok();
113 unsafe {
114 for i in 0..len {
115 write_u32(tx, *buf_ptr.add(i));
116 if i < len - 1 {
117 tx.blocking_write(b", ").ok();
118 }
119 }
120 }
121 tx.blocking_write(b"]").ok();
122}
123
124#[embassy_executor::main]
125async fn main(_spawner: Spawner) {
126 // Small delay to allow probe-rs to attach after reset
127 for _ in 0..100_000 {
128 cortex_m::asm::nop();
129 }
130
131 let mut cfg = hal::config::Config::default();
132 cfg.clock_cfg.sirc.fro_12m_enabled = true;
133 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
134 let p = hal::init(cfg);
135
136 defmt::info!("DMA ping-pong transfer example starting...");
137
138 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
139 unsafe {
140 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
141 }
142
143 let config = Config {
144 baudrate_bps: 115_200,
145 ..Default::default()
146 };
147
148 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
149 let (mut tx, _rx) = lpuart.split();
150
151 tx.blocking_write(b"EDMA ping-pong transfer example begin.\r\n\r\n")
152 .unwrap();
153
154 // Initialize buffers
155 unsafe {
156 SRC = [1, 2, 3, 4, 5, 6, 7, 8];
157 DST = [0; 8];
158 }
159
160 tx.blocking_write(b"Source Buffer: ").unwrap();
161 print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8);
162 tx.blocking_write(b"\r\n").unwrap();
163
164 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
165 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
166 tx.blocking_write(b"\r\n").unwrap();
167
168 tx.blocking_write(b"Configuring ping-pong DMA with Embassy-style API...\r\n")
169 .unwrap();
170
171 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
172
173 // Configure ping-pong transfer using direct TCD access:
174 // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel.
175 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1.
176 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0.
177 unsafe {
178 let tcds = &mut *core::ptr::addr_of_mut!(TCD_POOL.0);
179 let src_ptr = core::ptr::addr_of!(SRC) as *const u32;
180 let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32;
181
182 let half_len = 4usize;
183 let half_bytes = (half_len * 4) as u32;
184
185 let tcd0_addr = &tcds[0] as *const _ as u32;
186 let tcd1_addr = &tcds[1] as *const _ as u32;
187
188 // TCD0: First half -> Links to TCD1
189 tcds[0] = Tcd {
190 saddr: src_ptr as u32,
191 soff: 4,
192 attr: 0x0202, // 32-bit src/dst
193 nbytes: half_bytes,
194 slast: 0,
195 daddr: dst_ptr as u32,
196 doff: 4,
197 citer: 1,
198 dlast_sga: tcd1_addr as i32,
199 csr: 0x0012, // ESG | INTMAJOR
200 biter: 1,
201 };
202
203 // TCD1: Second half -> Links to TCD0
204 tcds[1] = Tcd {
205 saddr: src_ptr.add(half_len) as u32,
206 soff: 4,
207 attr: 0x0202,
208 nbytes: half_bytes,
209 slast: 0,
210 daddr: dst_ptr.add(half_len) as u32,
211 doff: 4,
212 citer: 1,
213 dlast_sga: tcd0_addr as i32,
214 csr: 0x0012,
215 biter: 1,
216 };
217
218 // Load TCD0 into hardware registers
219 dma_ch0.load_tcd(&tcds[0]);
220 }
221
222 tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap();
223
224 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4])
225 unsafe {
226 dma_ch0.trigger_start();
227 }
228
229 // Wait for first half
230 while !TRANSFER_DONE.load(Ordering::Acquire) {
231 cortex_m::asm::nop();
232 }
233 TRANSFER_DONE.store(false, Ordering::Release);
234
235 tx.blocking_write(b"First half transferred.\r\n").unwrap();
236 tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap();
237
238 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8])
239 unsafe {
240 dma_ch0.trigger_start();
241 }
242
243 // Wait for second half
244 while !TRANSFER_DONE.load(Ordering::Acquire) {
245 cortex_m::asm::nop();
246 }
247 TRANSFER_DONE.store(false, Ordering::Release);
248
249 tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap();
250
251 tx.blocking_write(b"EDMA ping-pong transfer example finish.\r\n\r\n")
252 .unwrap();
253 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
254 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
255 tx.blocking_write(b"\r\n\r\n").unwrap();
256
257 // Verify: DST should match SRC
258 let mut mismatch = false;
259 unsafe {
260 let src_ptr = core::ptr::addr_of!(SRC) as *const u32;
261 let dst_ptr = core::ptr::addr_of!(DST) as *const u32;
262 for i in 0..8 {
263 if *src_ptr.add(i) != *dst_ptr.add(i) {
264 mismatch = true;
265 break;
266 }
267 }
268 }
269
270 if mismatch {
271 tx.blocking_write(b"FAIL: Approach 1 mismatch detected!\r\n").unwrap();
272 defmt::error!("FAIL: Approach 1 mismatch detected!");
273 } else {
274 tx.blocking_write(b"PASS: Approach 1 data verified.\r\n\r\n").unwrap();
275 defmt::info!("PASS: Approach 1 data verified.");
276 }
277
278 // =========================================================================
279 // Approach 2: Half-Transfer Interrupt with wait_half() (NEW!)
280 // =========================================================================
281 //
282 // This approach uses a single continuous DMA transfer with half-transfer
283 // interrupt enabled. The wait_half() method allows you to be notified
284 // when the first half of the buffer is complete, so you can process it
285 // while the second half is still being filled.
286 //
287 // Benefits:
288 // - Simpler setup (no TCD pool needed)
289 // - True async/await support
290 // - Good for streaming data processing
291
292 tx.blocking_write(b"--- Approach 2: wait_half() demo ---\r\n\r\n")
293 .unwrap();
294
295 // Enable DMA CH1 interrupt
296 unsafe {
297 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1);
298 }
299
300 // Initialize approach 2 buffers
301 unsafe {
302 SRC2 = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4];
303 DST2 = [0; 8];
304 }
305
306 tx.blocking_write(b"SRC2: ").unwrap();
307 print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 8);
308 tx.blocking_write(b"\r\n").unwrap();
309
310 let dma_ch1 = DmaChannel::new(p.DMA_CH1);
311
312 // Configure transfer with half-transfer interrupt enabled
313 let mut options = TransferOptions::default();
314 options.half_transfer_interrupt = true; // Enable half-transfer interrupt
315 options.complete_transfer_interrupt = true;
316
317 tx.blocking_write(b"Starting transfer with half_transfer_interrupt...\r\n")
318 .unwrap();
319
320 unsafe {
321 let src = &*core::ptr::addr_of!(SRC2);
322 let dst = &mut *core::ptr::addr_of_mut!(DST2);
323
324 // Create the transfer
325 let mut transfer = dma_ch1.mem_to_mem(src, dst, options);
326
327 // Wait for half-transfer (first 4 elements)
328 tx.blocking_write(b"Waiting for first half...\r\n").unwrap();
329 let half_ok = transfer.wait_half().await;
330
331 if half_ok {
332 tx.blocking_write(b"Half-transfer complete! First half of DST2: ")
333 .unwrap();
334 print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4);
335 tx.blocking_write(b"\r\n").unwrap();
336 tx.blocking_write(b"(Processing first half while second half transfers...)\r\n")
337 .unwrap();
338 }
339
340 // Wait for complete transfer
341 tx.blocking_write(b"Waiting for second half...\r\n").unwrap();
342 transfer.await;
343 }
344
345 tx.blocking_write(b"Transfer complete! Full DST2: ").unwrap();
346 print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 8);
347 tx.blocking_write(b"\r\n\r\n").unwrap();
348
349 // Verify approach 2
350 let mut mismatch2 = false;
351 unsafe {
352 let src_ptr = core::ptr::addr_of!(SRC2) as *const u32;
353 let dst_ptr = core::ptr::addr_of!(DST2) as *const u32;
354 for i in 0..8 {
355 if *src_ptr.add(i) != *dst_ptr.add(i) {
356 mismatch2 = true;
357 break;
358 }
359 }
360 }
361
362 if mismatch2 {
363 tx.blocking_write(b"FAIL: Approach 2 mismatch!\r\n").unwrap();
364 defmt::error!("FAIL: Approach 2 mismatch!");
365 } else {
366 tx.blocking_write(b"PASS: Approach 2 verified.\r\n").unwrap();
367 defmt::info!("PASS: Approach 2 verified.");
368 }
369
370 tx.blocking_write(b"\r\n=== All ping-pong demos complete ===\r\n")
371 .unwrap();
372
373 loop {
374 cortex_m::asm::wfe();
375 }
376}
diff --git a/examples/mcxa/src/bin/dma_scatter_gather.rs b/examples/mcxa/src/bin/dma_scatter_gather.rs
new file mode 100644
index 000000000..4b26bc2ed
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_scatter_gather.rs
@@ -0,0 +1,262 @@
1//! DMA scatter-gather transfer example for MCXA276.
2//!
3//! This example demonstrates using DMA with scatter/gather to chain multiple
4//! transfer descriptors. The first TCD transfers the first half of the buffer,
5//! then automatically loads the second TCD to transfer the second half.
6//!
7//! # Embassy-style features demonstrated:
8//! - `DmaChannel::new()` for channel creation
9//! - Scatter/gather with chained TCDs
10//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice)
11
12#![no_std]
13#![no_main]
14
15use core::sync::atomic::{AtomicBool, Ordering};
16
17use embassy_executor::Spawner;
18use embassy_mcxa::clocks::config::Div8;
19use embassy_mcxa::dma::{self, DmaChannel, Tcd};
20use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
21use embassy_mcxa::{bind_interrupts, pac};
22use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
23
24// Source and destination buffers
25static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
26static mut DST: [u32; 8] = [0; 8];
27
28// TCD pool for scatter/gather - must be 32-byte aligned
29#[repr(C, align(32))]
30struct TcdPool([Tcd; 2]);
31
32static mut TCD_POOL: TcdPool = TcdPool(
33 [Tcd {
34 saddr: 0,
35 soff: 0,
36 attr: 0,
37 nbytes: 0,
38 slast: 0,
39 daddr: 0,
40 doff: 0,
41 citer: 0,
42 dlast_sga: 0,
43 csr: 0,
44 biter: 0,
45 }; 2],
46);
47
48// AtomicBool to track scatter/gather completion
49// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
50// so we need this flag to detect when each transfer completes
51static TRANSFER_DONE: AtomicBool = AtomicBool::new(false);
52
53// Custom handler for scatter/gather that delegates to HAL's on_interrupt()
54// This follows the "interrupts as threads" pattern - the handler does minimal work
55// (delegates to HAL + sets a flag) and the main task does the actual processing
56pub struct ScatterGatherDmaHandler;
57
58impl embassy_mcxa::interrupt::typelevel::Handler<embassy_mcxa::interrupt::typelevel::DMA_CH0>
59 for ScatterGatherDmaHandler
60{
61 unsafe fn on_interrupt() {
62 // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers
63 dma::on_interrupt(0);
64 // Signal completion for polling (needed because ESG clears DONE bit)
65 TRANSFER_DONE.store(true, Ordering::Release);
66 }
67}
68
69// Bind DMA channel interrupt
70// Custom handler for scatter/gather (delegates to on_interrupt + sets flag)
71bind_interrupts!(struct Irqs {
72 DMA_CH0 => ScatterGatherDmaHandler;
73});
74
75/// Helper to write a u32 as decimal ASCII to UART
76fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
77 let mut buf = [0u8; 10];
78 let mut n = val;
79 let mut i = buf.len();
80
81 if n == 0 {
82 tx.blocking_write(b"0").ok();
83 return;
84 }
85
86 while n > 0 {
87 i -= 1;
88 buf[i] = b'0' + (n % 10) as u8;
89 n /= 10;
90 }
91
92 tx.blocking_write(&buf[i..]).ok();
93}
94
95/// Helper to print a buffer to UART
96fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
97 tx.blocking_write(b"[").ok();
98 unsafe {
99 for i in 0..len {
100 write_u32(tx, *buf_ptr.add(i));
101 if i < len - 1 {
102 tx.blocking_write(b", ").ok();
103 }
104 }
105 }
106 tx.blocking_write(b"]").ok();
107}
108
109#[embassy_executor::main]
110async fn main(_spawner: Spawner) {
111 // Small delay to allow probe-rs to attach after reset
112 for _ in 0..100_000 {
113 cortex_m::asm::nop();
114 }
115
116 let mut cfg = hal::config::Config::default();
117 cfg.clock_cfg.sirc.fro_12m_enabled = true;
118 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
119 let p = hal::init(cfg);
120
121 defmt::info!("DMA scatter-gather transfer example starting...");
122
123 // DMA is initialized during hal::init() - no need to call ensure_init()
124
125 // Enable DMA interrupt
126 unsafe {
127 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
128 }
129
130 let config = Config {
131 baudrate_bps: 115_200,
132 ..Default::default()
133 };
134
135 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
136 let (mut tx, _rx) = lpuart.split();
137
138 tx.blocking_write(b"EDMA scatter-gather transfer example begin.\r\n\r\n")
139 .unwrap();
140
141 // Initialize buffers
142 unsafe {
143 SRC = [1, 2, 3, 4, 5, 6, 7, 8];
144 DST = [0; 8];
145 }
146
147 tx.blocking_write(b"Source Buffer: ").unwrap();
148 print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8);
149 tx.blocking_write(b"\r\n").unwrap();
150
151 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
152 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
153 tx.blocking_write(b"\r\n").unwrap();
154
155 tx.blocking_write(b"Configuring scatter-gather DMA with Embassy-style API...\r\n")
156 .unwrap();
157
158 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
159
160 // Configure scatter-gather transfer using direct TCD access:
161 // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel.
162 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1.
163 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD.
164 unsafe {
165 let tcds = core::slice::from_raw_parts_mut(core::ptr::addr_of_mut!(TCD_POOL.0) as *mut Tcd, 2);
166 let src_ptr = core::ptr::addr_of!(SRC) as *const u32;
167 let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32;
168
169 let num_tcds = 2usize;
170 let chunk_len = 4usize; // 8 / 2
171 let chunk_bytes = (chunk_len * 4) as u32;
172
173 for i in 0..num_tcds {
174 let is_last = i == num_tcds - 1;
175 let next_tcd_addr = if is_last {
176 0 // No next TCD
177 } else {
178 &tcds[i + 1] as *const _ as u32
179 };
180
181 tcds[i] = Tcd {
182 saddr: src_ptr.add(i * chunk_len) as u32,
183 soff: 4,
184 attr: 0x0202, // 32-bit src/dst
185 nbytes: chunk_bytes,
186 slast: 0,
187 daddr: dst_ptr.add(i * chunk_len) as u32,
188 doff: 4,
189 citer: 1,
190 dlast_sga: next_tcd_addr as i32,
191 // ESG (scatter/gather) for non-last, INTMAJOR for all
192 csr: if is_last { 0x0002 } else { 0x0012 },
193 biter: 1,
194 };
195 }
196
197 // Load TCD0 into hardware registers
198 dma_ch0.load_tcd(&tcds[0]);
199 }
200
201 tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap();
202
203 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4])
204 // TCD0 is currently loaded.
205 unsafe {
206 dma_ch0.trigger_start();
207 }
208
209 // Wait for first half
210 while !TRANSFER_DONE.load(Ordering::Acquire) {
211 cortex_m::asm::nop();
212 }
213 TRANSFER_DONE.store(false, Ordering::Release);
214
215 tx.blocking_write(b"First half transferred.\r\n").unwrap();
216 tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap();
217
218 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8])
219 // TCD1 should have been loaded by the scatter/gather engine.
220 unsafe {
221 dma_ch0.trigger_start();
222 }
223
224 // Wait for second half
225 while !TRANSFER_DONE.load(Ordering::Acquire) {
226 cortex_m::asm::nop();
227 }
228 TRANSFER_DONE.store(false, Ordering::Release);
229
230 tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap();
231
232 tx.blocking_write(b"EDMA scatter-gather transfer example finish.\r\n\r\n")
233 .unwrap();
234 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
235 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
236 tx.blocking_write(b"\r\n\r\n").unwrap();
237
238 // Verify: DST should match SRC
239 let mut mismatch = false;
240 unsafe {
241 let src_ptr = core::ptr::addr_of!(SRC) as *const u32;
242 let dst_ptr = core::ptr::addr_of!(DST) as *const u32;
243 for i in 0..8 {
244 if *src_ptr.add(i) != *dst_ptr.add(i) {
245 mismatch = true;
246 break;
247 }
248 }
249 }
250
251 if mismatch {
252 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
253 defmt::error!("FAIL: Mismatch detected!");
254 } else {
255 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
256 defmt::info!("PASS: Data verified.");
257 }
258
259 loop {
260 cortex_m::asm::wfe();
261 }
262}
diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs
new file mode 100644
index 000000000..e483bb81f
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs
@@ -0,0 +1,231 @@
1//! DMA Scatter-Gather Builder example for MCXA276.
2//!
3//! This example demonstrates using the new `ScatterGatherBuilder` API for
4//! chaining multiple DMA transfers with a type-safe builder pattern.
5//!
6//! # Features demonstrated:
7//! - `ScatterGatherBuilder::new()` for creating a builder
8//! - `add_transfer()` for adding memory-to-memory segments
9//! - `build()` to start the chained transfer
10//! - Automatic TCD linking and ESG bit management
11//!
12//! # Comparison with manual scatter-gather:
13//! The manual approach (see `dma_scatter_gather.rs`) requires:
14//! - Manual TCD pool allocation and alignment
15//! - Manual CSR/ESG/INTMAJOR bit manipulation
16//! - Manual dlast_sga address calculations
17//!
18//! The builder approach handles all of this automatically!
19
20#![no_std]
21#![no_main]
22
23use embassy_executor::Spawner;
24use embassy_mcxa::clocks::config::Div8;
25use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, ScatterGatherBuilder};
26use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
27use embassy_mcxa::{bind_interrupts, pac};
28use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
29
30// Bind DMA channel 0 interrupt
31bind_interrupts!(struct Irqs {
32 DMA_CH0 => DmaCh0InterruptHandler;
33});
34
35// Source buffers (multiple segments)
36static mut SRC1: [u32; 4] = [0x11111111, 0x22222222, 0x33333333, 0x44444444];
37static mut SRC2: [u32; 4] = [0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD];
38static mut SRC3: [u32; 4] = [0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210];
39
40// Destination buffers (one per segment)
41static mut DST1: [u32; 4] = [0; 4];
42static mut DST2: [u32; 4] = [0; 4];
43static mut DST3: [u32; 4] = [0; 4];
44
45/// Helper to write a u32 as hex to UART
46fn write_hex(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
47 const HEX: &[u8; 16] = b"0123456789ABCDEF";
48 for i in (0..8).rev() {
49 let nibble = ((val >> (i * 4)) & 0xF) as usize;
50 tx.blocking_write(&[HEX[nibble]]).ok();
51 }
52}
53
54/// Helper to print a buffer to UART
55fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
56 tx.blocking_write(b"[").ok();
57 unsafe {
58 for i in 0..len {
59 write_hex(tx, *buf_ptr.add(i));
60 if i < len - 1 {
61 tx.blocking_write(b", ").ok();
62 }
63 }
64 }
65 tx.blocking_write(b"]").ok();
66}
67
68#[embassy_executor::main]
69async fn main(_spawner: Spawner) {
70 // Small delay to allow probe-rs to attach after reset
71 for _ in 0..100_000 {
72 cortex_m::asm::nop();
73 }
74
75 let mut cfg = hal::config::Config::default();
76 cfg.clock_cfg.sirc.fro_12m_enabled = true;
77 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
78 let p = hal::init(cfg);
79
80 defmt::info!("DMA Scatter-Gather Builder example starting...");
81
82 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
83 unsafe {
84 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
85 }
86
87 // Create UART for debug output
88 let config = Config {
89 baudrate_bps: 115_200,
90 ..Default::default()
91 };
92
93 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
94 let (mut tx, _rx) = lpuart.split();
95
96 tx.blocking_write(b"DMA Scatter-Gather Builder Example\r\n").unwrap();
97 tx.blocking_write(b"===================================\r\n\r\n")
98 .unwrap();
99
100 // Show source buffers
101 tx.blocking_write(b"Source buffers:\r\n").unwrap();
102 tx.blocking_write(b" SRC1: ").unwrap();
103 print_buffer(&mut tx, core::ptr::addr_of!(SRC1) as *const u32, 4);
104 tx.blocking_write(b"\r\n").unwrap();
105 tx.blocking_write(b" SRC2: ").unwrap();
106 print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 4);
107 tx.blocking_write(b"\r\n").unwrap();
108 tx.blocking_write(b" SRC3: ").unwrap();
109 print_buffer(&mut tx, core::ptr::addr_of!(SRC3) as *const u32, 4);
110 tx.blocking_write(b"\r\n\r\n").unwrap();
111
112 tx.blocking_write(b"Destination buffers (before):\r\n").unwrap();
113 tx.blocking_write(b" DST1: ").unwrap();
114 print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4);
115 tx.blocking_write(b"\r\n").unwrap();
116 tx.blocking_write(b" DST2: ").unwrap();
117 print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4);
118 tx.blocking_write(b"\r\n").unwrap();
119 tx.blocking_write(b" DST3: ").unwrap();
120 print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4);
121 tx.blocking_write(b"\r\n\r\n").unwrap();
122
123 // Create DMA channel
124 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
125
126 tx.blocking_write(b"Building scatter-gather chain with builder API...\r\n")
127 .unwrap();
128
129 // =========================================================================
130 // ScatterGatherBuilder API demonstration
131 // =========================================================================
132 //
133 // The builder pattern makes scatter-gather transfers much easier:
134 // 1. Create a builder
135 // 2. Add transfer segments with add_transfer()
136 // 3. Call build() to start the entire chain
137 // No manual TCD manipulation required!
138
139 let mut builder = ScatterGatherBuilder::<u32>::new();
140
141 // Add three transfer segments - the builder handles TCD linking automatically
142 unsafe {
143 let src1 = &*core::ptr::addr_of!(SRC1);
144 let dst1 = &mut *core::ptr::addr_of_mut!(DST1);
145 builder.add_transfer(src1, dst1);
146 }
147
148 unsafe {
149 let src2 = &*core::ptr::addr_of!(SRC2);
150 let dst2 = &mut *core::ptr::addr_of_mut!(DST2);
151 builder.add_transfer(src2, dst2);
152 }
153
154 unsafe {
155 let src3 = &*core::ptr::addr_of!(SRC3);
156 let dst3 = &mut *core::ptr::addr_of_mut!(DST3);
157 builder.add_transfer(src3, dst3);
158 }
159
160 tx.blocking_write(b"Added 3 transfer segments to chain.\r\n").unwrap();
161 tx.blocking_write(b"Starting scatter-gather transfer with .await...\r\n\r\n")
162 .unwrap();
163
164 // Build and execute the scatter-gather chain
165 // The build() method:
166 // - Links all TCDs together with ESG bit
167 // - Sets INTMAJOR on all TCDs
168 // - Loads the first TCD into hardware
169 // - Returns a Transfer future
170 unsafe {
171 let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather");
172 transfer.blocking_wait();
173 }
174
175 tx.blocking_write(b"Scatter-gather transfer complete!\r\n\r\n").unwrap();
176
177 // Show results
178 tx.blocking_write(b"Destination buffers (after):\r\n").unwrap();
179 tx.blocking_write(b" DST1: ").unwrap();
180 print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4);
181 tx.blocking_write(b"\r\n").unwrap();
182 tx.blocking_write(b" DST2: ").unwrap();
183 print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4);
184 tx.blocking_write(b"\r\n").unwrap();
185 tx.blocking_write(b" DST3: ").unwrap();
186 print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4);
187 tx.blocking_write(b"\r\n\r\n").unwrap();
188
189 // Verify all three segments
190 let mut all_ok = true;
191 unsafe {
192 let src1 = core::ptr::addr_of!(SRC1) as *const u32;
193 let dst1 = core::ptr::addr_of!(DST1) as *const u32;
194 for i in 0..4 {
195 if *src1.add(i) != *dst1.add(i) {
196 all_ok = false;
197 }
198 }
199
200 let src2 = core::ptr::addr_of!(SRC2) as *const u32;
201 let dst2 = core::ptr::addr_of!(DST2) as *const u32;
202 for i in 0..4 {
203 if *src2.add(i) != *dst2.add(i) {
204 all_ok = false;
205 }
206 }
207
208 let src3 = core::ptr::addr_of!(SRC3) as *const u32;
209 let dst3 = core::ptr::addr_of!(DST3) as *const u32;
210 for i in 0..4 {
211 if *src3.add(i) != *dst3.add(i) {
212 all_ok = false;
213 }
214 }
215 }
216
217 if all_ok {
218 tx.blocking_write(b"PASS: All segments verified!\r\n").unwrap();
219 defmt::info!("PASS: All segments verified!");
220 } else {
221 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
222 defmt::error!("FAIL: Mismatch detected!");
223 }
224
225 tx.blocking_write(b"\r\n=== Scatter-Gather Builder example complete ===\r\n")
226 .unwrap();
227
228 loop {
229 cortex_m::asm::wfe();
230 }
231}
diff --git a/examples/mcxa/src/bin/dma_wrap_transfer.rs b/examples/mcxa/src/bin/dma_wrap_transfer.rs
new file mode 100644
index 000000000..82936d9d0
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_wrap_transfer.rs
@@ -0,0 +1,222 @@
1//! DMA wrap transfer example for MCXA276.
2//!
3//! This example demonstrates using DMA with modulo addressing to wrap around
4//! a source buffer, effectively repeating the source data in the destination.
5//!
6//! # Embassy-style features demonstrated:
7//! - `DmaChannel::is_done()` and `clear_done()` helper methods
8//! - No need to pass register block around
9
10#![no_std]
11#![no_main]
12
13use embassy_executor::Spawner;
14use embassy_mcxa::clocks::config::Div8;
15use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel};
16use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
17use embassy_mcxa::{bind_interrupts, pac};
18use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
19
20// Bind DMA channel 0 interrupt using Embassy-style macro
21bind_interrupts!(struct Irqs {
22 DMA_CH0 => DmaCh0InterruptHandler;
23});
24
25// Source buffer: 4 words (16 bytes), aligned to 16 bytes for modulo
26#[repr(align(16))]
27struct AlignedSrc([u32; 4]);
28
29static mut SRC: AlignedSrc = AlignedSrc([0; 4]);
30static mut DST: [u32; 8] = [0; 8];
31
32/// Helper to write a u32 as decimal ASCII to UART
33fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) {
34 let mut buf = [0u8; 10];
35 let mut n = val;
36 let mut i = buf.len();
37
38 if n == 0 {
39 tx.blocking_write(b"0").ok();
40 return;
41 }
42
43 while n > 0 {
44 i -= 1;
45 buf[i] = b'0' + (n % 10) as u8;
46 n /= 10;
47 }
48
49 tx.blocking_write(&buf[i..]).ok();
50}
51
52/// Helper to print a buffer to UART
53fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
54 tx.blocking_write(b"[").ok();
55 unsafe {
56 for i in 0..len {
57 write_u32(tx, *buf_ptr.add(i));
58 if i < len - 1 {
59 tx.blocking_write(b", ").ok();
60 }
61 }
62 }
63 tx.blocking_write(b"]").ok();
64}
65
66#[embassy_executor::main]
67async fn main(_spawner: Spawner) {
68 // Small delay to allow probe-rs to attach after reset
69 for _ in 0..100_000 {
70 cortex_m::asm::nop();
71 }
72
73 let mut cfg = hal::config::Config::default();
74 cfg.clock_cfg.sirc.fro_12m_enabled = true;
75 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
76 let p = hal::init(cfg);
77
78 defmt::info!("DMA wrap transfer example starting...");
79
80 // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL)
81 unsafe {
82 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
83 }
84
85 let config = Config {
86 baudrate_bps: 115_200,
87 ..Default::default()
88 };
89
90 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
91 let (mut tx, _rx) = lpuart.split();
92
93 tx.blocking_write(b"EDMA wrap transfer example begin.\r\n\r\n").unwrap();
94
95 // Initialize buffers
96 unsafe {
97 SRC.0 = [1, 2, 3, 4];
98 DST = [0; 8];
99 }
100
101 tx.blocking_write(b"Source Buffer: ").unwrap();
102 print_buffer(&mut tx, unsafe { core::ptr::addr_of!(SRC.0) } as *const u32, 4);
103 tx.blocking_write(b"\r\n").unwrap();
104
105 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
106 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
107 tx.blocking_write(b"\r\n").unwrap();
108
109 tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n")
110 .unwrap();
111
112 // Create DMA channel using Embassy-style API
113 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
114
115 // Configure wrap transfer using direct TCD access:
116 // SRC is 16 bytes (4 * u32). We want to transfer 32 bytes (8 * u32).
117 // SRC modulo is 16 bytes (2^4 = 16) - wraps source address.
118 // DST modulo is 0 (disabled).
119 // This causes the source address to wrap around after 16 bytes,
120 // effectively repeating the source data.
121 unsafe {
122 let t = dma_ch0.tcd();
123
124 // Reset channel state
125 t.ch_csr().write(|w| {
126 w.erq()
127 .disable()
128 .earq()
129 .disable()
130 .eei()
131 .no_error()
132 .ebw()
133 .disable()
134 .done()
135 .clear_bit_by_one()
136 });
137 t.ch_es().write(|w| w.bits(0));
138 t.ch_int().write(|w| w.int().clear_bit_by_one());
139
140 // Source/destination addresses
141 t.tcd_saddr()
142 .write(|w| w.saddr().bits(core::ptr::addr_of!(SRC.0) as u32));
143 t.tcd_daddr()
144 .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DST) as u32));
145
146 // Offsets: both increment by 4 bytes
147 t.tcd_soff().write(|w| w.soff().bits(4));
148 t.tcd_doff().write(|w| w.doff().bits(4));
149
150 // Attributes: 32-bit transfers (size = 2)
151 // SMOD = 4 (2^4 = 16 byte modulo for source), DMOD = 0 (disabled)
152 t.tcd_attr().write(|w| {
153 w.ssize()
154 .bits(2)
155 .dsize()
156 .bits(2)
157 .smod()
158 .bits(4) // Source modulo: 2^4 = 16 bytes
159 .dmod()
160 .bits(0) // Dest modulo: disabled
161 });
162
163 // Transfer 32 bytes total in one minor loop
164 let nbytes = 32u32;
165 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
166
167 // Source wraps via modulo, no adjustment needed
168 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0));
169 // Reset dest address after major loop
170 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32));
171
172 // Major loop count = 1
173 t.tcd_biter_elinkno().write(|w| w.biter().bits(1));
174 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
175
176 // Enable interrupt on major loop completion
177 t.tcd_csr().write(|w| w.intmajor().set_bit());
178
179 cortex_m::asm::dsb();
180
181 tx.blocking_write(b"Triggering transfer...\r\n").unwrap();
182 dma_ch0.trigger_start();
183 }
184
185 // Wait for completion using channel helper method
186 while !dma_ch0.is_done() {
187 cortex_m::asm::nop();
188 }
189 unsafe {
190 dma_ch0.clear_done();
191 }
192
193 tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n")
194 .unwrap();
195 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
196 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
197 tx.blocking_write(b"\r\n\r\n").unwrap();
198
199 // Verify: DST should be [1, 2, 3, 4, 1, 2, 3, 4]
200 let expected = [1u32, 2, 3, 4, 1, 2, 3, 4];
201 let mut mismatch = false;
202 unsafe {
203 for i in 0..8 {
204 if DST[i] != expected[i] {
205 mismatch = true;
206 break;
207 }
208 }
209 }
210
211 if mismatch {
212 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
213 defmt::error!("FAIL: Mismatch detected!");
214 } else {
215 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
216 defmt::info!("PASS: Data verified.");
217 }
218
219 loop {
220 cortex_m::asm::wfe();
221 }
222}
diff --git a/examples/mcxa/src/bin/hello.rs b/examples/mcxa/src/bin/hello.rs
new file mode 100644
index 000000000..e371d9413
--- /dev/null
+++ b/examples/mcxa/src/bin/hello.rs
@@ -0,0 +1,119 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::clocks::config::Div8;
6use hal::lpuart::{Blocking, Config, Lpuart};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9/// Simple helper to write a byte as hex to UART
10fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) {
11 const HEX_DIGITS: &[u8] = b"0123456789ABCDEF";
12 let _ = uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]);
13 let _ = uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]);
14}
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut cfg = hal::config::Config::default();
19 cfg.clock_cfg.sirc.fro_12m_enabled = true;
20 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
21 let p = hal::init(cfg);
22
23 defmt::info!("boot");
24
25 // Create UART configuration
26 let config = Config {
27 baudrate_bps: 115_200,
28 ..Default::default()
29 };
30
31 // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX
32 let mut uart = Lpuart::new_blocking(
33 p.LPUART2, // Peripheral
34 p.P2_2, // TX pin
35 p.P2_3, // RX pin
36 config,
37 )
38 .unwrap();
39
40 // Print welcome message before any async delays to guarantee early console output
41 uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n");
42 uart.write_str_blocking("Available commands:\r\n");
43 uart.write_str_blocking(" help - Show this help\r\n");
44 uart.write_str_blocking(" echo <text> - Echo back the text\r\n");
45 uart.write_str_blocking(" hex <byte> - Display byte in hex (0-255)\r\n");
46 uart.write_str_blocking("Type a command: ");
47
48 let mut buffer = [0u8; 64];
49 let mut buf_idx = 0;
50
51 loop {
52 // Read a byte from UART
53 let byte = uart.read_byte_blocking();
54
55 // Echo the character back
56 if byte == b'\r' || byte == b'\n' {
57 // Enter pressed - process command
58 uart.write_str_blocking("\r\n");
59
60 if buf_idx > 0 {
61 let command = &buffer[0..buf_idx];
62
63 if command == b"help" {
64 uart.write_str_blocking("Available commands:\r\n");
65 uart.write_str_blocking(" help - Show this help\r\n");
66 uart.write_str_blocking(" echo <text> - Echo back the text\r\n");
67 uart.write_str_blocking(" hex <byte> - Display byte in hex (0-255)\r\n");
68 } else if command.starts_with(b"echo ") && command.len() > 5 {
69 uart.write_str_blocking("Echo: ");
70 uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or(""));
71 uart.write_str_blocking("\r\n");
72 } else if command.starts_with(b"hex ") && command.len() > 4 {
73 // Parse the byte value
74 let num_str = &command[4..];
75 if let Ok(num) = parse_u8(num_str) {
76 uart.write_str_blocking("Hex: 0x");
77 write_hex_byte(&mut uart, num);
78 uart.write_str_blocking("\r\n");
79 } else {
80 uart.write_str_blocking("Invalid number for hex command\r\n");
81 }
82 } else if !command.is_empty() {
83 uart.write_str_blocking("Unknown command: ");
84 uart.write_str_blocking(core::str::from_utf8(command).unwrap_or(""));
85 uart.write_str_blocking("\r\n");
86 }
87 }
88
89 // Reset buffer and prompt
90 buf_idx = 0;
91 uart.write_str_blocking("Type a command: ");
92 } else if byte == 8 || byte == 127 {
93 // Backspace
94 if buf_idx > 0 {
95 buf_idx -= 1;
96 uart.write_str_blocking("\x08 \x08"); // Erase character
97 }
98 } else if buf_idx < buffer.len() - 1 {
99 // Regular character
100 buffer[buf_idx] = byte;
101 buf_idx += 1;
102 let _ = uart.write_byte(byte);
103 }
104 }
105}
106
107/// Simple parser for u8 from ASCII bytes
108fn parse_u8(bytes: &[u8]) -> Result<u8, ()> {
109 let mut result = 0u8;
110 for &b in bytes {
111 if b.is_ascii_digit() {
112 result = result.checked_mul(10).ok_or(())?;
113 result = result.checked_add(b - b'0').ok_or(())?;
114 } else {
115 return Err(());
116 }
117 }
118 Ok(result)
119}
diff --git a/examples/mcxa/src/bin/i2c-blocking.rs b/examples/mcxa/src/bin/i2c-blocking.rs
new file mode 100644
index 000000000..0f6c8cbae
--- /dev/null
+++ b/examples/mcxa/src/bin/i2c-blocking.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::clocks::config::Div8;
7use hal::config::Config;
8use hal::i2c::controller::{self, I2c, Speed};
9use tmp108::Tmp108;
10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
16
17 let p = hal::init(config);
18
19 defmt::info!("I2C example");
20
21 let mut config = controller::Config::default();
22 config.speed = Speed::Standard;
23 let i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap();
24 let mut tmp = Tmp108::new_with_a0_gnd(i2c);
25
26 loop {
27 let temperature = tmp.temperature().unwrap();
28 defmt::info!("Temperature: {}C", temperature);
29 Timer::after_secs(1).await;
30 }
31}
diff --git a/examples/mcxa/src/bin/i2c-scan-blocking.rs b/examples/mcxa/src/bin/i2c-scan-blocking.rs
new file mode 100644
index 000000000..4e203597b
--- /dev/null
+++ b/examples/mcxa/src/bin/i2c-scan-blocking.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::gpio::Pull;
6use embassy_mcxa::Input;
7use embassy_time::Timer;
8use hal::clocks::config::Div8;
9use hal::config::Config;
10use hal::i2c::controller::{self, I2c, Speed};
11use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let mut config = Config::default();
16 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
17
18 let p = hal::init(config);
19
20 defmt::info!("I2C example");
21
22 let mut config = controller::Config::default();
23 config.speed = Speed::Standard;
24
25 // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and
26 // defaults to SWO on the debug peripheral. Explicitly make it a high-z
27 // input.
28 let _pin = Input::new(p.P0_2, Pull::Disabled);
29 let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap();
30
31 for addr in 0x01..=0x7f {
32 let result = i2c.blocking_write(addr, &[]);
33 if result.is_ok() {
34 defmt::info!("Device found at addr {:02x}", addr);
35 }
36 }
37
38 loop {
39 Timer::after_secs(10).await;
40 }
41}
diff --git a/examples/mcxa/src/bin/lpuart_buffered.rs b/examples/mcxa/src/bin/lpuart_buffered.rs
new file mode 100644
index 000000000..420589d00
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_buffered.rs
@@ -0,0 +1,62 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::clocks::config::Div8;
6use embassy_mcxa::lpuart::buffered::BufferedLpuart;
7use embassy_mcxa::lpuart::Config;
8use embassy_mcxa::{bind_interrupts, lpuart};
9use embedded_io_async::Write;
10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11
12// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver
13bind_interrupts!(struct Irqs {
14 LPUART2 => lpuart::buffered::BufferedInterruptHandler::<hal::peripherals::LPUART2>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let mut cfg = hal::config::Config::default();
20 cfg.clock_cfg.sirc.fro_12m_enabled = true;
21 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
22 let p = hal::init(cfg);
23
24 // Configure NVIC for LPUART2
25 hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3);
26
27 // UART configuration (enable both TX and RX)
28 let config = Config {
29 baudrate_bps: 115_200,
30 rx_fifo_watermark: 0,
31 tx_fifo_watermark: 0,
32 ..Default::default()
33 };
34
35 let mut tx_buf = [0u8; 256];
36 let mut rx_buf = [0u8; 256];
37
38 // Create a buffered LPUART2 instance with both TX and RX
39 let mut uart = BufferedLpuart::new(
40 p.LPUART2,
41 p.P2_2, // TX pin
42 p.P2_3, // RX pin
43 Irqs,
44 &mut tx_buf,
45 &mut rx_buf,
46 config,
47 )
48 .unwrap();
49
50 // Split into TX and RX parts
51 let (tx, rx) = uart.split_ref();
52
53 tx.write(b"Hello buffered LPUART.\r\n").await.unwrap();
54 tx.write(b"Type characters to echo them back.\r\n").await.unwrap();
55
56 // Echo loop
57 let mut buf = [0u8; 4];
58 loop {
59 let used = rx.read(&mut buf).await.unwrap();
60 tx.write_all(&buf[..used]).await.unwrap();
61 }
62}
diff --git a/examples/mcxa/src/bin/lpuart_dma.rs b/examples/mcxa/src/bin/lpuart_dma.rs
new file mode 100644
index 000000000..5497f8646
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_dma.rs
@@ -0,0 +1,81 @@
1//! LPUART DMA example for MCXA276.
2//!
3//! This example demonstrates using DMA for UART TX and RX operations.
4//! It sends a message using DMA, then waits for 16 characters to be received
5//! via DMA and echoes them back.
6//!
7//! The DMA request sources are automatically derived from the LPUART instance type.
8//! DMA clock/reset/init is handled automatically by the HAL.
9
10#![no_std]
11#![no_main]
12
13use embassy_executor::Spawner;
14use embassy_mcxa::clocks::config::Div8;
15use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler};
16use embassy_mcxa::lpuart::{Config, LpuartDma};
17use embassy_mcxa::{bind_interrupts, pac};
18use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
19
20// Bind DMA channel interrupts using Embassy-style macro
21bind_interrupts!(struct Irqs {
22 DMA_CH0 => DmaCh0InterruptHandler;
23 DMA_CH1 => DmaCh1InterruptHandler;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let mut cfg = hal::config::Config::default();
29 cfg.clock_cfg.sirc.fro_12m_enabled = true;
30 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
31 let p = hal::init(cfg);
32
33 defmt::info!("LPUART DMA example starting...");
34
35 // Enable DMA interrupts (per-channel, as needed)
36 unsafe {
37 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0);
38 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1);
39 }
40
41 // Create UART configuration
42 let config = Config {
43 baudrate_bps: 115_200,
44 ..Default::default()
45 };
46
47 // Create UART instance with DMA channels
48 let mut lpuart = LpuartDma::new(
49 p.LPUART2, p.P2_2, // TX pin
50 p.P2_3, // RX pin
51 p.DMA_CH0, // TX DMA channel
52 p.DMA_CH1, // RX DMA channel
53 config,
54 )
55 .unwrap();
56
57 // Send a message using DMA (DMA request source is automatically derived from LPUART2)
58 let tx_msg = b"Hello from LPUART2 DMA TX!\r\n";
59 lpuart.write_dma(tx_msg).await.unwrap();
60
61 defmt::info!("TX DMA complete");
62
63 // Send prompt
64 let prompt = b"Type 16 characters to echo via DMA:\r\n";
65 lpuart.write_dma(prompt).await.unwrap();
66
67 // Receive 16 characters using DMA
68 let mut rx_buf = [0u8; 16];
69 lpuart.read_dma(&mut rx_buf).await.unwrap();
70
71 defmt::info!("RX DMA complete");
72
73 // Echo back the received data
74 let echo_prefix = b"\r\nReceived: ";
75 lpuart.write_dma(echo_prefix).await.unwrap();
76 lpuart.write_dma(&rx_buf).await.unwrap();
77 let done_msg = b"\r\nDone!\r\n";
78 lpuart.write_dma(done_msg).await.unwrap();
79
80 defmt::info!("Example complete");
81}
diff --git a/examples/mcxa/src/bin/lpuart_polling.rs b/examples/mcxa/src/bin/lpuart_polling.rs
new file mode 100644
index 000000000..b80668834
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_polling.rs
@@ -0,0 +1,47 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::clocks::config::Div8;
6use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
7
8use crate::hal::lpuart::{Config, Lpuart};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let mut cfg = hal::config::Config::default();
13 cfg.clock_cfg.sirc.fro_12m_enabled = true;
14 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
15 let p = hal::init(cfg);
16
17 defmt::info!("boot");
18
19 // Create UART configuration
20 let config = Config {
21 baudrate_bps: 115_200,
22 ..Default::default()
23 };
24
25 // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX
26 let lpuart = Lpuart::new_blocking(
27 p.LPUART2, // Peripheral
28 p.P2_2, // TX pin
29 p.P2_3, // RX pin
30 config,
31 )
32 .unwrap();
33
34 // Split into separate TX and RX parts
35 let (mut tx, mut rx) = lpuart.split();
36
37 // Write hello messages
38 tx.blocking_write(b"Hello world.\r\n").unwrap();
39 tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap();
40
41 // Echo loop
42 loop {
43 let mut buf = [0u8; 1];
44 rx.blocking_read(&mut buf).unwrap();
45 tx.blocking_write(&buf).unwrap();
46 }
47}
diff --git a/examples/mcxa/src/bin/lpuart_ring_buffer.rs b/examples/mcxa/src/bin/lpuart_ring_buffer.rs
new file mode 100644
index 000000000..1d1a51970
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_ring_buffer.rs
@@ -0,0 +1,130 @@
1//! LPUART Ring Buffer DMA example for MCXA276.
2//!
3//! This example demonstrates using the high-level `LpuartRxDma::setup_ring_buffer()`
4//! API for continuous circular DMA reception from a UART peripheral.
5//!
6//! # Features demonstrated:
7//! - `LpuartRxDma::setup_ring_buffer()` for continuous peripheral-to-memory DMA
8//! - `RingBuffer` for async reading of received data
9//! - Handling of potential overrun conditions
10//! - Half-transfer and complete-transfer interrupts for timely wakeups
11//!
12//! # How it works:
13//! 1. Create an `LpuartRxDma` driver with a DMA channel
14//! 2. Call `setup_ring_buffer()` which handles all low-level DMA configuration
15//! 3. Application asynchronously reads data as it arrives via `ring_buf.read()`
16//! 4. Both half-transfer and complete-transfer interrupts wake the reader
17
18#![no_std]
19#![no_main]
20
21use embassy_executor::Spawner;
22use embassy_mcxa::bind_interrupts;
23use embassy_mcxa::clocks::config::Div8;
24use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler};
25use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma};
26use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
27
28// Bind DMA channel interrupts
29bind_interrupts!(struct Irqs {
30 DMA_CH0 => DmaCh0InterruptHandler;
31 DMA_CH1 => DmaCh1InterruptHandler;
32});
33
34// Ring buffer for RX - power of 2 is ideal for modulo efficiency
35static mut RX_RING_BUFFER: [u8; 64] = [0; 64];
36
37/// Helper to write a byte as hex to UART
38fn write_hex<T: embassy_mcxa::lpuart::Instance, C: embassy_mcxa::dma::Channel>(
39 tx: &mut LpuartTxDma<'_, T, C>,
40 byte: u8,
41) {
42 const HEX: &[u8; 16] = b"0123456789ABCDEF";
43 let buf = [HEX[(byte >> 4) as usize], HEX[(byte & 0x0F) as usize]];
44 tx.blocking_write(&buf).ok();
45}
46
47#[embassy_executor::main]
48async fn main(_spawner: Spawner) {
49 // Small delay to allow probe-rs to attach after reset
50 for _ in 0..100_000 {
51 cortex_m::asm::nop();
52 }
53
54 let mut cfg = hal::config::Config::default();
55 cfg.clock_cfg.sirc.fro_12m_enabled = true;
56 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
57 let p = hal::init(cfg);
58
59 defmt::info!("LPUART Ring Buffer DMA example starting...");
60
61 // Create UART configuration
62 let config = Config {
63 baudrate_bps: 115_200,
64 ..Default::default()
65 };
66
67 // Create LPUART with DMA support for both TX and RX, then split
68 // This is the proper Embassy pattern - create once, split into TX and RX
69 let lpuart = LpuartDma::new(p.LPUART2, p.P2_2, p.P2_3, p.DMA_CH1, p.DMA_CH0, config).unwrap();
70 let (mut tx, rx) = lpuart.split();
71
72 tx.blocking_write(b"LPUART Ring Buffer DMA Example\r\n").unwrap();
73 tx.blocking_write(b"==============================\r\n\r\n").unwrap();
74
75 tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n")
76 .unwrap();
77
78 // Set up the ring buffer with circular DMA
79 // The HAL handles: DMA request source, RDMAE enable, circular transfer config, NVIC enable
80 let ring_buf = unsafe {
81 let buf = &mut *core::ptr::addr_of_mut!(RX_RING_BUFFER);
82 rx.setup_ring_buffer(buf)
83 };
84
85 // Enable DMA requests to start continuous reception
86 unsafe {
87 rx.enable_dma_request();
88 }
89
90 tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n")
91 .unwrap();
92 tx.blocking_write(b"The DMA continuously receives in the background.\r\n\r\n")
93 .unwrap();
94
95 // Main loop: read from ring buffer and echo back
96 let mut read_buf = [0u8; 16];
97 let mut total_received: usize = 0;
98
99 loop {
100 // Async read - waits until data is available
101 match ring_buf.read(&mut read_buf).await {
102 Ok(n) if n > 0 => {
103 total_received += n;
104
105 // Echo back what we received
106 tx.blocking_write(b"RX[").unwrap();
107 for (i, &byte) in read_buf.iter().enumerate().take(n) {
108 write_hex(&mut tx, byte);
109 if i < n - 1 {
110 tx.blocking_write(b" ").unwrap();
111 }
112 }
113 tx.blocking_write(b"]: ").unwrap();
114 tx.blocking_write(&read_buf[..n]).unwrap();
115 tx.blocking_write(b"\r\n").unwrap();
116
117 defmt::info!("Received {} bytes, total: {}", n, total_received);
118 }
119 Ok(_) => {
120 // No data, shouldn't happen with async read
121 }
122 Err(_) => {
123 // Overrun detected
124 tx.blocking_write(b"ERROR: Ring buffer overrun!\r\n").unwrap();
125 defmt::error!("Ring buffer overrun!");
126 ring_buf.clear();
127 }
128 }
129 }
130}
diff --git a/examples/mcxa/src/bin/rtc_alarm.rs b/examples/mcxa/src/bin/rtc_alarm.rs
new file mode 100644
index 000000000..a7800a2d1
--- /dev/null
+++ b/examples/mcxa/src/bin/rtc_alarm.rs
@@ -0,0 +1,74 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa as hal;
6use hal::rtc::{RtcDateTime, RtcInterruptEnable};
7use hal::InterruptExt;
8
9type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>;
10
11use embassy_mcxa::bind_interrupts;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 RTC => hal::rtc::RtcHandler;
16});
17
18#[used]
19#[no_mangle]
20static KEEP_RTC: unsafe extern "C" fn() = RTC;
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = hal::init(hal::config::Config::default());
25
26 defmt::info!("=== RTC Alarm Example ===");
27
28 let rtc_config = hal::rtc::get_default_config();
29
30 let rtc = MyRtc::new(p.RTC0, rtc_config);
31
32 let now = RtcDateTime {
33 year: 2025,
34 month: 10,
35 day: 15,
36 hour: 14,
37 minute: 30,
38 second: 0,
39 };
40
41 rtc.stop();
42
43 defmt::info!("Time set to: 2025-10-15 14:30:00");
44 rtc.set_datetime(now);
45
46 let mut alarm = now;
47 alarm.second += 10;
48
49 rtc.set_alarm(alarm);
50 defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)");
51
52 rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE);
53
54 unsafe {
55 hal::interrupt::RTC.enable();
56 }
57
58 unsafe {
59 cortex_m::interrupt::enable();
60 }
61
62 rtc.start();
63
64 defmt::info!("RTC started, waiting for alarm...");
65
66 loop {
67 if rtc.is_alarm_triggered() {
68 defmt::info!("*** ALARM TRIGGERED! ***");
69 break;
70 }
71 }
72
73 defmt::info!("Example complete - Test PASSED!");
74}
diff --git a/examples/mcxa/src/lib.rs b/examples/mcxa/src/lib.rs
new file mode 100644
index 000000000..2573a6adc
--- /dev/null
+++ b/examples/mcxa/src/lib.rs
@@ -0,0 +1,16 @@
1#![no_std]
2#![allow(clippy::missing_safety_doc)]
3
4//! Shared board-specific helpers for the FRDM-MCXA276 examples.
5//! These live with the examples so the HAL stays generic.
6
7use hal::{clocks, pins};
8use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
9
10/// Initialize clocks and pin muxing for ADC.
11pub unsafe fn init_adc_pins() {
12 // NOTE: Lpuart has been updated to properly enable + reset its own clocks.
13 // GPIO has not.
14 _ = clocks::enable_and_reset::<hal::peripherals::PORT1>(&clocks::periph_helpers::NoConfig);
15 pins::configure_adc_pins();
16}