aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-mcxa/src/crc.rs234
1 files changed, 134 insertions, 100 deletions
diff --git a/embassy-mcxa/src/crc.rs b/embassy-mcxa/src/crc.rs
index f01a671c4..0db36273f 100644
--- a/embassy-mcxa/src/crc.rs
+++ b/embassy-mcxa/src/crc.rs
@@ -55,19 +55,65 @@ impl<'d, M: Mode> Crc<'d, M> {
55 unsafe { &*crate::pac::Crc0::ptr() } 55 unsafe { &*crate::pac::Crc0::ptr() }
56 } 56 }
57 57
58 /// Feeds a byte into the CRC peripheral. 58 /// Read the computed CRC value
59 fn feed_byte(&mut self, byte: u8) { 59 fn read_crc<W: Word>(&mut self) -> W {
60 Self::regs().data8().write(|w| unsafe { w.bits(byte) }); 60 // Reference manual states:
61 //
62 // "After writing all the data, you must wait for at least two
63 // clock cycles to read the data from CRC Data (DATA)
64 // register."
65 cortex_m::asm::delay(2);
66
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 }
61 } 79 }
62 80
63 /// Feeds a halfword into the CRC peripheral. 81 fn feed_word<W: Word>(&mut self, word: W) {
64 fn feed_halfword(&mut self, halfword: u16) { 82 if W::is_32bit() {
65 Self::regs().data16().write(|w| unsafe { w.bits(halfword) }); 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 }
66 } 89 }
67 90
68 /// Feeds a word into the CRC peripheral. 91 /// Feeds a slice of `Word`s into the CRC peripheral. Returns the
69 fn feed_word(&mut self, word: u32) { 92 /// computed checksum.
70 Self::regs().data32().write(|w| unsafe { w.bits(word) }); 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 ///
99 /// This allows efficient 32‑bit writes where possible, falling
100 /// back to `Word` writes for the remainder.
101 fn feed_inner<W: Word, R: Word>(&mut self, data: &[W]) -> R {
102 let (prefix, aligned, suffix) = unsafe { data.align_to::<u32>() };
103
104 for w in prefix {
105 self.feed_word(*w);
106 }
107
108 for w in aligned {
109 self.feed_word(*w);
110 }
111
112 for w in suffix {
113 self.feed_word(*w);
114 }
115
116 self.read_crc::<R>()
71 } 117 }
72} 118}
73 119
@@ -203,60 +249,17 @@ impl<'d> Crc<'d, Crc16> {
203 Self::new_algorithm16(peri, Algorithm16::Xmodem) 249 Self::new_algorithm16(peri, Algorithm16::Xmodem)
204 } 250 }
205 251
206 fn read_crc(&mut self) -> u16 {
207 // Reference manual states:
208 //
209 // "After writing all the data, you must wait for at least two
210 // clock cycles to read the data from CRC Data (DATA)
211 // register."
212 cortex_m::asm::delay(2);
213
214 let ctrl = Self::regs().ctrl().read();
215
216 // if transposition is enabled, result sits in the upper 16 bits
217 if ctrl.totr().is_byts_trnps() || ctrl.totr().is_byts_bts_trnps() {
218 (Self::regs().data32().read().bits() >> 16) as u16
219 } else {
220 Self::regs().data16().read().bits()
221 }
222 }
223
224 /// Feeds a slice of bytes into the CRC peripheral. Returns the computed checksum. 252 /// Feeds a slice of bytes into the CRC peripheral. Returns the computed checksum.
225 /// 253 ///
226 /// The input is split using [`align_to::<u32>`] into: 254 /// The input is split using `align_to::<u32>` into:
227 /// - `prefix`: unaligned leading bytes, 255 /// - `prefix`: unaligned leading bytes,
228 /// - `data`: aligned `u32` words, 256 /// - `data`: aligned `u32` words,
229 /// - `suffix`: trailing bytes. 257 /// - `suffix`: trailing bytes.
230 /// 258 ///
231 /// This allows efficient 32‑bit writes where possible, falling back to byte writes 259 /// This allows efficient 32‑bit writes where possible, falling back to byte writes
232 /// for the remainder. 260 /// for the remainder.
233 pub fn feed(&mut self, bytes: &[u8]) -> u16 { 261 pub fn feed<W: Word>(&mut self, data: &[W]) -> u16 {
234 let (prefix, data, suffix) = unsafe { bytes.align_to::<u32>() }; 262 self.feed_inner(data)
235
236 for b in prefix {
237 self.feed_byte(*b);
238 }
239
240 // use 32-bit writes as long as possible
241 for w in data {
242 self.feed_word(*w);
243 }
244
245 for b in suffix {
246 self.feed_byte(*b);
247 }
248
249 // read back result.
250 self.read_crc()
251 }
252
253 /// Feeds a slice of halfwords into the CRC peripheral. Returns the computed checksum.
254 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u16 {
255 for halfword in halfwords {
256 self.feed_halfword(*halfword);
257 }
258
259 self.read_crc()
260 } 263 }
261} 264}
262 265
@@ -322,68 +325,51 @@ impl<'d> Crc<'d, Crc32> {
322 Self::new_algorithm32(peri, Algorithm32::Xfer) 325 Self::new_algorithm32(peri, Algorithm32::Xfer)
323 } 326 }
324 327
325 fn read_crc(&mut self) -> u32 { 328 /// Feeds a slice of `Word`s into the CRC peripheral. Returns the
326 // Reference manual states: 329 /// computed checksum.
327 //
328 // "After writing all the data, you must wait for at least two
329 // clock cycles to read the data from CRC Data (DATA)
330 // register."
331 cortex_m::asm::delay(2);
332 Self::regs().data32().read().bits()
333 }
334
335 /// Feeds a slice of bytes into the CRC peripheral. Returns the computed checksum.
336 /// 330 ///
337 /// The input is split using [`align_to::<u32>`] into: 331 /// The input is split using `align_to::<u32>` into:
338 /// - `prefix`: unaligned leading bytes, 332 /// - `prefix`: unaligned leading bytes,
339 /// - `data`: aligned `u32` words, 333 /// - `data`: aligned `u32` words,
340 /// - `suffix`: trailing bytes. 334 /// - `suffix`: trailing bytes.
341 /// 335 ///
342 /// This allows efficient 32‑bit writes where possible, falling back to byte writes 336 /// This allows efficient 32‑bit writes where possible, falling
343 /// for the remainder. 337 /// back to `Word` writes for the remainder.
344 pub fn feed(&mut self, bytes: &[u8]) -> u32 { 338 pub fn feed<W: Word>(&mut self, data: &[W]) -> u32 {
345 let (prefix, data, suffix) = unsafe { bytes.align_to::<u32>() }; 339 self.feed_inner(data)
340 }
341}
346 342
347 for b in prefix { 343mod sealed {
348 self.feed_byte(*b); 344 pub trait SealedMode {}
349 }
350 345
351 // use 32-bit writes as long as possible 346 pub trait SealedWord: Copy {
352 for w in data { 347 const WIDTH: u8;
353 self.feed_word(*w);
354 }
355 348
356 for b in suffix { 349 #[inline]
357 self.feed_byte(*b); 350 fn is_8bit() -> bool {
351 Self::WIDTH == 8
358 } 352 }
359 353
360 // read back result. 354 #[inline]
361 self.read_crc() 355 fn is_16bit() -> bool {
362 } 356 Self::WIDTH == 16
363
364 /// Feeds a slice of halfwords into the CRC peripheral. Returns the computed checksum.
365 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
366 for halfword in halfwords {
367 self.feed_halfword(*halfword);
368 } 357 }
369 358
370 self.read_crc() 359 #[inline]
371 } 360 fn is_32bit() -> bool {
372 361 Self::WIDTH == 32
373 /// Feeds a slice of words into the CRC peripheral. Returns the computed checksum.
374 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
375 for word in words {
376 self.feed_word(*word);
377 } 362 }
378 363
379 self.read_crc() 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;
380 } 370 }
381} 371}
382 372
383mod sealed {
384 pub trait SealedMode {}
385}
386
387/// Mode of operation: 32 or 16-bit CRC. 373/// Mode of operation: 32 or 16-bit CRC.
388#[allow(private_bounds)] 374#[allow(private_bounds)]
389pub trait Mode: sealed::SealedMode {} 375pub trait Mode: sealed::SealedMode {}
@@ -398,6 +384,54 @@ pub struct Crc32;
398impl sealed::SealedMode for Crc32 {} 384impl sealed::SealedMode for Crc32 {}
399impl Mode for Crc32 {} 385impl Mode for Crc32 {}
400 386
387/// Word size for the CRC.
388#[allow(private_bounds)]
389pub trait Word: sealed::SealedWord {}
390
391macro_rules! impl_word {
392 ($t:ty, $width:literal) => {
393 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]
412 fn to_u8(self) -> u8 {
413 self as u8
414 }
415
416 #[inline]
417 fn to_u16(self) -> u16 {
418 self as u16
419 }
420
421 #[inline]
422 fn to_u32(self) -> u32 {
423 self as u32
424 }
425 }
426
427 impl Word for $t {}
428 };
429}
430
431impl_word!(u8, 8);
432impl_word!(u16, 16);
433impl_word!(u32, 32);
434
401/// CRC configuration. 435/// CRC configuration.
402#[derive(Copy, Clone, Debug)] 436#[derive(Copy, Clone, Debug)]
403#[non_exhaustive] 437#[non_exhaustive]