diff options
| author | Felipe Balbi <[email protected]> | 2025-12-08 08:44:50 -0800 |
|---|---|---|
| committer | Felipe Balbi <[email protected]> | 2025-12-08 09:33:47 -0800 |
| commit | cc34871ebef2513f69ce52f8f8f717473e701ec2 (patch) | |
| tree | 811b25cd8152f8c928588b293ef68d0f8d925d0f /embassy-mcxa | |
| parent | c48aa4c1a9820d3875995ca707c3aa133f17d19e (diff) | |
review comments
Diffstat (limited to 'embassy-mcxa')
| -rw-r--r-- | embassy-mcxa/src/crc.rs | 202 |
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 | ||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| 5 | use embassy_hal_internal::Peri; | 5 | use embassy_hal_internal::Peri; |
| 6 | use mcxa_pac::crc0::ctrl::{Fxor, Tot, Totr}; | 6 | use mcxa_pac::crc0::ctrl::{Fxor, Tcrc, Tot, Totr}; |
| 7 | 7 | ||
| 8 | use crate::clocks::enable_and_reset; | 8 | use crate::clocks::enable_and_reset; |
| 9 | use crate::clocks::periph_helpers::NoConfig; | 9 | use 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 {} | |||
| 389 | pub trait Word: sealed::SealedWord {} | 333 | pub trait Word: sealed::SealedWord {} |
| 390 | 334 | ||
| 391 | macro_rules! impl_word { | 335 | macro_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 | ||
| 431 | impl_word!(u8, 8); | 353 | impl_word!( |
| 432 | impl_word!(u16, 16); | 354 | u8, |
| 433 | impl_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 | ); | ||
| 361 | impl_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 | ); | ||
| 378 | impl_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)] |
