aboutsummaryrefslogtreecommitdiff
path: root/embassy-mcxa
diff options
context:
space:
mode:
authorFelipe Balbi <[email protected]>2025-12-08 08:44:50 -0800
committerFelipe Balbi <[email protected]>2025-12-08 09:33:47 -0800
commitcc34871ebef2513f69ce52f8f8f717473e701ec2 (patch)
tree811b25cd8152f8c928588b293ef68d0f8d925d0f /embassy-mcxa
parentc48aa4c1a9820d3875995ca707c3aa133f17d19e (diff)
review comments
Diffstat (limited to 'embassy-mcxa')
-rw-r--r--embassy-mcxa/src/crc.rs202
1 files changed, 77 insertions, 125 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)]