diff options
| -rw-r--r-- | embassy-mcxa/src/crc.rs | 234 |
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 { | 343 | mod 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 | ||
| 383 | mod 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)] |
| 389 | pub trait Mode: sealed::SealedMode {} | 375 | pub trait Mode: sealed::SealedMode {} |
| @@ -398,6 +384,54 @@ pub struct Crc32; | |||
| 398 | impl sealed::SealedMode for Crc32 {} | 384 | impl sealed::SealedMode for Crc32 {} |
| 399 | impl Mode for Crc32 {} | 385 | impl Mode for Crc32 {} |
| 400 | 386 | ||
| 387 | /// Word size for the CRC. | ||
| 388 | #[allow(private_bounds)] | ||
| 389 | pub trait Word: sealed::SealedWord {} | ||
| 390 | |||
| 391 | macro_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 | |||
| 431 | impl_word!(u8, 8); | ||
| 432 | impl_word!(u16, 16); | ||
| 433 | impl_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] |
