aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-mcxa/src/crc.rs202
-rw-r--r--examples/mcxa/Cargo.toml1
-rw-r--r--examples/mcxa/src/bin/crc.rs103
3 files changed, 161 insertions, 145 deletions
diff --git a/embassy-mcxa/src/crc.rs b/embassy-mcxa/src/crc.rs
index 0db36273f..8f3b6b5de 100644
--- a/embassy-mcxa/src/crc.rs
+++ b/embassy-mcxa/src/crc.rs
@@ -1,9 +1,9 @@
1//! Cyclic Redundandy Check (CRC) 1//! Cyclic Redundancy Check (CRC)
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
6use mcxa_pac::crc0::ctrl::{Fxor, Tot, Totr}; 6use mcxa_pac::crc0::ctrl::{Fxor, Tcrc, Tot, Totr};
7 7
8use crate::clocks::enable_and_reset; 8use crate::clocks::enable_and_reset;
9use crate::clocks::periph_helpers::NoConfig; 9use crate::clocks::periph_helpers::NoConfig;
@@ -27,12 +27,7 @@ impl<'d, M: Mode> Crc<'d, M> {
27 27
28 // Configure the underlying peripheral. `f` is expected to set the 28 // Configure the underlying peripheral. `f` is expected to set the
29 // operating mode to either 16- or 32-bits. 29 // operating mode to either 16- or 32-bits.
30 fn configure<F>(config: Config, f: F) 30 fn configure(config: Config, width: Tcrc) {
31 where
32 F: FnOnce(),
33 {
34 f();
35
36 Self::regs().ctrl().modify(|_, w| { 31 Self::regs().ctrl().modify(|_, w| {
37 w.fxor() 32 w.fxor()
38 .variant(config.complement_out.into()) 33 .variant(config.complement_out.into())
@@ -42,6 +37,8 @@ impl<'d, M: Mode> Crc<'d, M> {
42 .variant(config.reflect_in.into()) 37 .variant(config.reflect_in.into())
43 .was() 38 .was()
44 .data() 39 .data()
40 .tcrc()
41 .variant(width)
45 }); 42 });
46 43
47 Self::regs().gpoly32().write(|w| unsafe { w.bits(config.polynomial) }); 44 Self::regs().gpoly32().write(|w| unsafe { w.bits(config.polynomial) });
@@ -56,49 +53,26 @@ impl<'d, M: Mode> Crc<'d, M> {
56 } 53 }
57 54
58 /// Read the computed CRC value 55 /// Read the computed CRC value
59 fn read_crc<W: Word>(&mut self) -> W { 56 fn finalize_inner<W: Word>(self) -> W {
60 // Reference manual states: 57 // Reference manual states:
61 // 58 //
62 // "After writing all the data, you must wait for at least two 59 // "After writing all the data, you must wait for at least two
63 // clock cycles to read the data from CRC Data (DATA) 60 // clock cycles to read the data from CRC Data (DATA)
64 // register." 61 // register."
65 cortex_m::asm::delay(2); 62 cortex_m::asm::delay(2);
66 63 W::read(Self::regs())
67 let ctrl = Self::regs().ctrl().read();
68
69 if W::is_16bit() {
70 // if transposition is enabled, result sits in the upper 16 bits
71 if ctrl.totr().is_byts_trnps() || ctrl.totr().is_byts_bts_trnps() {
72 W::from_u32(Self::regs().data32().read().bits() >> 16)
73 } else {
74 W::from_u16(Self::regs().data16().read().bits())
75 }
76 } else {
77 W::from_u32(Self::regs().data32().read().bits())
78 }
79 } 64 }
80 65
81 fn feed_word<W: Word>(&mut self, word: W) { 66 fn feed_word<W: Word>(&mut self, word: W) {
82 if W::is_32bit() { 67 W::write(Self::regs(), word);
83 Self::regs().data32().write(|w| unsafe { w.bits(word.to_u32()) });
84 } else if W::is_16bit() {
85 Self::regs().data16().write(|w| unsafe { w.bits(word.to_u16()) });
86 } else {
87 Self::regs().data8().write(|w| unsafe { w.bits(word.to_u8()) });
88 }
89 } 68 }
90 69
91 /// Feeds a slice of `Word`s into the CRC peripheral. Returns the 70 /// Feeds a slice of `Word`s into the CRC peripheral. Returns the computed
92 /// computed checksum. 71 /// checksum.
93 ///
94 /// The input is split using [`align_to::<u32>`] into:
95 /// - `prefix`: unaligned leading data,
96 /// - `data`: aligned `u32` words,
97 /// - `suffix`: trailing data.
98 /// 72 ///
99 /// This allows efficient 32‑bit writes where possible, falling 73 /// The input is strided efficiently into as many `u32`s as possible,
100 /// back to `Word` writes for the remainder. 74 /// falling back to smaller writes for the remainder.
101 fn feed_inner<W: Word, R: Word>(&mut self, data: &[W]) -> R { 75 fn feed_inner<W: Word>(&mut self, data: &[W]) {
102 let (prefix, aligned, suffix) = unsafe { data.align_to::<u32>() }; 76 let (prefix, aligned, suffix) = unsafe { data.align_to::<u32>() };
103 77
104 for w in prefix { 78 for w in prefix {
@@ -112,8 +86,6 @@ impl<'d, M: Mode> Crc<'d, M> {
112 for w in suffix { 86 for w in suffix {
113 self.feed_word(*w); 87 self.feed_word(*w);
114 } 88 }
115
116 self.read_crc::<R>()
117 } 89 }
118} 90}
119 91
@@ -121,11 +93,7 @@ impl<'d> Crc<'d, Crc16> {
121 /// Instantiates a new CRC peripheral driver in 16-bit mode 93 /// Instantiates a new CRC peripheral driver in 16-bit mode
122 pub fn new_crc16(peri: Peri<'d, CRC0>, config: Config) -> Self { 94 pub fn new_crc16(peri: Peri<'d, CRC0>, config: Config) -> Self {
123 let inst = Self::new_inner(peri); 95 let inst = Self::new_inner(peri);
124 96 Self::configure(config, Tcrc::B16);
125 Self::configure(config, || {
126 Self::regs().ctrl().modify(|_, w| w.tcrc().b16());
127 });
128
129 inst 97 inst
130 } 98 }
131 99
@@ -249,17 +217,18 @@ impl<'d> Crc<'d, Crc16> {
249 Self::new_algorithm16(peri, Algorithm16::Xmodem) 217 Self::new_algorithm16(peri, Algorithm16::Xmodem)
250 } 218 }
251 219
252 /// Feeds a slice of bytes into the CRC peripheral. Returns the computed checksum. 220 /// Feeds a slice of `Word`s into the CRC peripheral.
253 ///
254 /// The input is split using `align_to::<u32>` into:
255 /// - `prefix`: unaligned leading bytes,
256 /// - `data`: aligned `u32` words,
257 /// - `suffix`: trailing bytes.
258 /// 221 ///
259 /// This allows efficient 32‑bit writes where possible, falling back to byte writes 222 /// The input is strided efficiently into as many `u32`s as possible,
260 /// for the remainder. 223 /// falling back to smaller writes for the remainder.
261 pub fn feed<W: Word>(&mut self, data: &[W]) -> u16 { 224 pub fn feed<W: Word>(&mut self, data: &[W]) {
262 self.feed_inner(data) 225 self.feed_inner(data);
226 }
227
228 /// Finalizes the CRC calculation and reads the resulting CRC from the
229 /// hardware consuming `self`.
230 pub fn finalize(self) -> u16 {
231 self.finalize_inner()
263 } 232 }
264} 233}
265 234
@@ -267,11 +236,7 @@ impl<'d> Crc<'d, Crc32> {
267 /// Instantiates a new CRC peripheral driver in 32-bit mode 236 /// Instantiates a new CRC peripheral driver in 32-bit mode
268 pub fn new_crc32(peri: Peri<'d, CRC0>, config: Config) -> Self { 237 pub fn new_crc32(peri: Peri<'d, CRC0>, config: Config) -> Self {
269 let inst = Self::new_inner(peri); 238 let inst = Self::new_inner(peri);
270 239 Self::configure(config, Tcrc::B32);
271 Self::configure(config, || {
272 Self::regs().ctrl().modify(|_, w| w.tcrc().b32());
273 });
274
275 inst 240 inst
276 } 241 }
277 242
@@ -325,18 +290,18 @@ impl<'d> Crc<'d, Crc32> {
325 Self::new_algorithm32(peri, Algorithm32::Xfer) 290 Self::new_algorithm32(peri, Algorithm32::Xfer)
326 } 291 }
327 292
328 /// Feeds a slice of `Word`s into the CRC peripheral. Returns the 293 /// Feeds a slice of `Word`s into the CRC peripheral.
329 /// computed checksum.
330 ///
331 /// The input is split using `align_to::<u32>` into:
332 /// - `prefix`: unaligned leading bytes,
333 /// - `data`: aligned `u32` words,
334 /// - `suffix`: trailing bytes.
335 /// 294 ///
336 /// This allows efficient 32‑bit writes where possible, falling 295 /// The input is strided efficiently into as many `u32`s as possible,
337 /// back to `Word` writes for the remainder. 296 /// falling back to smaller writes for the remainder.
338 pub fn feed<W: Word>(&mut self, data: &[W]) -> u32 { 297 pub fn feed<W: Word>(&mut self, data: &[W]) {
339 self.feed_inner(data) 298 self.feed_inner(data);
299 }
300
301 /// Finalizes the CRC calculation and reads the resulting CRC from the
302 /// hardware consuming `self`.
303 pub fn finalize(self) -> u32 {
304 self.finalize_inner()
340 } 305 }
341} 306}
342 307
@@ -344,29 +309,8 @@ mod sealed {
344 pub trait SealedMode {} 309 pub trait SealedMode {}
345 310
346 pub trait SealedWord: Copy { 311 pub trait SealedWord: Copy {
347 const WIDTH: u8; 312 fn write(regs: &'static crate::pac::crc0::RegisterBlock, word: Self);
348 313 fn read(regs: &'static crate::pac::crc0::RegisterBlock) -> Self;
349 #[inline]
350 fn is_8bit() -> bool {
351 Self::WIDTH == 8
352 }
353
354 #[inline]
355 fn is_16bit() -> bool {
356 Self::WIDTH == 16
357 }
358
359 #[inline]
360 fn is_32bit() -> bool {
361 Self::WIDTH == 32
362 }
363
364 fn from_u8(x: u8) -> Self;
365 fn from_u16(x: u16) -> Self;
366 fn from_u32(x: u32) -> Self;
367 fn to_u8(self) -> u8;
368 fn to_u16(self) -> u16;
369 fn to_u32(self) -> u32;
370 } 314 }
371} 315}
372 316
@@ -389,38 +333,16 @@ impl Mode for Crc32 {}
389pub trait Word: sealed::SealedWord {} 333pub trait Word: sealed::SealedWord {}
390 334
391macro_rules! impl_word { 335macro_rules! impl_word {
392 ($t:ty, $width:literal) => { 336 ($t:ty, $width:literal, $write:expr, $read:expr) => {
393 impl sealed::SealedWord for $t { 337 impl sealed::SealedWord for $t {
394 const WIDTH: u8 = $width;
395
396 #[inline]
397 fn from_u8(x: u8) -> Self {
398 x as $t
399 }
400
401 #[inline]
402 fn from_u16(x: u16) -> Self {
403 x as $t
404 }
405
406 #[inline]
407 fn from_u32(x: u32) -> Self {
408 x as $t
409 }
410
411 #[inline] 338 #[inline]
412 fn to_u8(self) -> u8 { 339 fn write(regs: &'static crate::pac::crc0::RegisterBlock, word: Self) {
413 self as u8 340 $write(regs, word)
414 } 341 }
415 342
416 #[inline] 343 #[inline]
417 fn to_u16(self) -> u16 { 344 fn read(regs: &'static crate::pac::crc0::RegisterBlock) -> Self {
418 self as u16 345 $read(regs)
419 }
420
421 #[inline]
422 fn to_u32(self) -> u32 {
423 self as u32
424 } 346 }
425 } 347 }
426 348
@@ -428,9 +350,39 @@ macro_rules! impl_word {
428 }; 350 };
429} 351}
430 352
431impl_word!(u8, 8); 353impl_word!(
432impl_word!(u16, 16); 354 u8,
433impl_word!(u32, 32); 355 8,
356 |regs: &'static crate::pac::crc0::RegisterBlock, word| {
357 regs.data8().write(|w| unsafe { w.bits(word) });
358 },
359 |regs: &'static crate::pac::crc0::RegisterBlock| { regs.data8().read().bits() }
360);
361impl_word!(
362 u16,
363 16,
364 |regs: &'static crate::pac::crc0::RegisterBlock, word| {
365 regs.data16().write(|w| unsafe { w.bits(word) });
366 },
367 |regs: &'static crate::pac::crc0::RegisterBlock| {
368 let ctrl = regs.ctrl().read();
369
370 // if transposition is enabled, result sits in the upper 16 bits
371 if ctrl.totr().is_byts_trnps() || ctrl.totr().is_byts_bts_trnps() {
372 (regs.data32().read().bits() >> 16) as u16
373 } else {
374 regs.data16().read().bits()
375 }
376 }
377);
378impl_word!(
379 u32,
380 32,
381 |regs: &'static crate::pac::crc0::RegisterBlock, word| {
382 regs.data32().write(|w| unsafe { w.bits(word) });
383 },
384 |regs: &'static crate::pac::crc0::RegisterBlock| { regs.data32().read().bits() }
385);
434 386
435/// CRC configuration. 387/// CRC configuration.
436#[derive(Copy, Clone, Debug)] 388#[derive(Copy, Clone, Debug)]
diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml
index 4d0459f41..19d8d8657 100644
--- a/examples/mcxa/Cargo.toml
+++ b/examples/mcxa/Cargo.toml
@@ -8,6 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9cortex-m = { version = "0.7", features = ["critical-section-single-core"] } 9cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
10cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] } 10cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] }
11crc = "3.4.0"
11critical-section = "1.2.0" 12critical-section = "1.2.0"
12defmt = "1.0" 13defmt = "1.0"
13defmt-rtt = "1.0" 14defmt-rtt = "1.0"
diff --git a/examples/mcxa/src/bin/crc.rs b/examples/mcxa/src/bin/crc.rs
index 12c423980..0125e625c 100644
--- a/examples/mcxa/src/bin/crc.rs
+++ b/examples/mcxa/src/bin/crc.rs
@@ -6,6 +6,28 @@ use hal::config::Config;
6use hal::crc::Crc; 6use hal::crc::Crc;
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8 8
9const CCITT_FALSE: crc::Algorithm<u16> = crc::Algorithm {
10 width: 16,
11 poly: 0x1021,
12 init: 0xffff,
13 refin: false,
14 refout: false,
15 xorout: 0,
16 check: 0x29b1,
17 residue: 0x0000,
18};
19
20const POSIX: crc::Algorithm<u32> = crc::Algorithm {
21 width: 32,
22 poly: 0x04c1_1db7,
23 init: 0,
24 refin: false,
25 refout: false,
26 xorout: 0xffff_ffff,
27 check: 0x765e_7680,
28 residue: 0x0000,
29};
30
9#[embassy_executor::main] 31#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 32async fn main(_spawner: Spawner) {
11 let config = Config::default(); 33 let config = Config::default();
@@ -19,72 +41,113 @@ async fn main(_spawner: Spawner) {
19 41
20 // CCITT False 42 // CCITT False
21 43
44 let sw_crc = crc::Crc::<u16>::new(&CCITT_FALSE);
45 let mut digest = sw_crc.digest();
46 digest.update(&buf_u8);
47 let sw_sum = digest.finalize();
48
22 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); 49 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow());
23 let sum = crc.feed(&buf_u8); 50 crc.feed(&buf_u8);
24 assert_eq!(sum, 0x9627); 51 let sum = crc.finalize();
52 assert_eq!(sum, sw_sum);
25 53
26 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); 54 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow());
27 let sum = crc.feed(&buf_u16); 55 crc.feed(&buf_u16);
56 let sum = crc.finalize();
28 assert_eq!(sum, 0xa467); 57 assert_eq!(sum, 0xa467);
29 58
30 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); 59 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow());
31 let sum = crc.feed(&buf_u32); 60 crc.feed(&buf_u32);
61 let sum = crc.finalize();
32 assert_eq!(sum, 0xe5c7); 62 assert_eq!(sum, 0xe5c7);
33 63
34 // Maxim 64 // Maxim
35 65
66 let sw_crc = crc::Crc::<u16>::new(&crc::CRC_16_MAXIM_DOW);
67 let mut digest = sw_crc.digest();
68 digest.update(&buf_u8);
69 let sw_sum = digest.finalize();
70
36 let mut crc = Crc::new_maxim(p.CRC0.reborrow()); 71 let mut crc = Crc::new_maxim(p.CRC0.reborrow());
37 let sum = crc.feed(&buf_u8); 72 crc.feed(&buf_u8);
38 assert_eq!(sum, 0x4ff7); 73 let sum = crc.finalize();
74 assert_eq!(sum, sw_sum);
39 75
40 let mut crc = Crc::new_maxim(p.CRC0.reborrow()); 76 let mut crc = Crc::new_maxim(p.CRC0.reborrow());
41 let sum = crc.feed(&buf_u16); 77 crc.feed(&buf_u16);
78 let sum = crc.finalize();
42 assert_eq!(sum, 0x2afe); 79 assert_eq!(sum, 0x2afe);
43 80
44 let mut crc = Crc::new_maxim(p.CRC0.reborrow()); 81 let mut crc = Crc::new_maxim(p.CRC0.reborrow());
45 let sum = crc.feed(&buf_u32); 82 crc.feed(&buf_u32);
83 let sum = crc.finalize();
46 assert_eq!(sum, 0x17d7); 84 assert_eq!(sum, 0x17d7);
47 85
48 // Kermit 86 // Kermit
49 87
88 let sw_crc = crc::Crc::<u16>::new(&crc::CRC_16_KERMIT);
89 let mut digest = sw_crc.digest();
90 digest.update(&buf_u8);
91 let sw_sum = digest.finalize();
92
50 let mut crc = Crc::new_kermit(p.CRC0.reborrow()); 93 let mut crc = Crc::new_kermit(p.CRC0.reborrow());
51 let sum = crc.feed(&buf_u8); 94 crc.feed(&buf_u8);
52 assert_eq!(sum, 0xccd2); 95 let sum = crc.finalize();
96 assert_eq!(sum, sw_sum);
53 97
54 let mut crc = Crc::new_kermit(p.CRC0.reborrow()); 98 let mut crc = Crc::new_kermit(p.CRC0.reborrow());
55 let sum = crc.feed(&buf_u16); 99 crc.feed(&buf_u16);
100 let sum = crc.finalize();
56 assert_eq!(sum, 0x66eb); 101 assert_eq!(sum, 0x66eb);
57 102
58 let mut crc = Crc::new_kermit(p.CRC0.reborrow()); 103 let mut crc = Crc::new_kermit(p.CRC0.reborrow());
59 let sum = crc.feed(&buf_u32); 104 crc.feed(&buf_u32);
105 let sum = crc.finalize();
60 assert_eq!(sum, 0x75ea); 106 assert_eq!(sum, 0x75ea);
61 107
62 // ISO HDLC 108 // ISO HDLC
63 109
110 let sw_crc = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
111 let mut digest = sw_crc.digest();
112 digest.update(&buf_u8);
113 let sw_sum = digest.finalize();
114
64 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); 115 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow());
65 let sum = crc.feed(&buf_u8); 116 crc.feed(&buf_u8);
66 assert_eq!(sum, 0x24c2_316d); 117 let sum = crc.finalize();
118 assert_eq!(sum, sw_sum);
67 119
68 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); 120 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow());
69 let sum = crc.feed(&buf_u16); 121 crc.feed(&buf_u16);
122 let sum = crc.finalize();
70 assert_eq!(sum, 0x8a61_4178); 123 assert_eq!(sum, 0x8a61_4178);
71 124
72 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); 125 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow());
73 let sum = crc.feed(&buf_u32); 126 crc.feed(&buf_u32);
127 let sum = crc.finalize();
74 assert_eq!(sum, 0xfab5_d04e); 128 assert_eq!(sum, 0xfab5_d04e);
75 129
76 // POSIX 130 // POSIX
77 131
132 let sw_crc = crc::Crc::<u32>::new(&POSIX);
133 let mut digest = sw_crc.digest();
134 digest.update(&buf_u8);
135 let sw_sum = digest.finalize();
136
78 let mut crc = Crc::new_posix(p.CRC0.reborrow()); 137 let mut crc = Crc::new_posix(p.CRC0.reborrow());
79 let sum = crc.feed(&buf_u8); 138 crc.feed(&buf_u8);
80 assert_eq!(sum, 0xba8d_7868); 139 let sum = crc.finalize();
140
141 assert_eq!(sum, sw_sum);
81 142
82 let mut crc = Crc::new_posix(p.CRC0.reborrow()); 143 let mut crc = Crc::new_posix(p.CRC0.reborrow());
83 let sum = crc.feed(&buf_u16); 144 crc.feed(&buf_u16);
145 let sum = crc.finalize();
84 assert_eq!(sum, 0x6d76_4f58); 146 assert_eq!(sum, 0x6d76_4f58);
85 147
86 let mut crc = Crc::new_posix(p.CRC0.reborrow()); 148 let mut crc = Crc::new_posix(p.CRC0.reborrow());
87 let sum = crc.feed(&buf_u32); 149 crc.feed(&buf_u32);
150 let sum = crc.finalize();
88 assert_eq!(sum, 0x2a5b_cb90); 151 assert_eq!(sum, 0x2a5b_cb90);
89 152
90 defmt::info!("CRC successful"); 153 defmt::info!("CRC successful");