diff --git a/embassy-stm32/src/crc/mod.rs b/embassy-stm32/src/crc/mod.rs new file mode 100644 index 00000000..63f7ad9b --- /dev/null +++ b/embassy-stm32/src/crc/mod.rs @@ -0,0 +1,6 @@ +#[cfg_attr(crc_v1, path = "v1.rs")] +#[cfg_attr(crc_v2, path = "v2v3.rs")] +#[cfg_attr(crc_v3, path = "v2v3.rs")] +mod _version; + +pub use _version::*; diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs new file mode 100644 index 00000000..c33eea31 --- /dev/null +++ b/embassy-stm32/src/crc/v1.rs @@ -0,0 +1,52 @@ +use crate::pac::CRC as PAC_CRC; +use crate::peripherals::CRC; +use crate::rcc::sealed::RccPeripheral; +use embassy::util::Unborrow; +use embassy_hal_common::unborrow; + +pub struct Crc { + _peripheral: CRC, +} + +impl Crc { + /// Instantiates the CRC32 peripheral and initializes it to default values. + pub fn new(peripheral: impl Unborrow) -> Self { + // Note: enable and reset come from RccPeripheral. + // enable CRC clock in RCC. + CRC::enable(); + // Reset CRC to default values. + CRC::reset(); + // Unborrow the peripheral + unborrow!(peripheral); + let mut instance = Self { + _peripheral: peripheral, + }; + instance.reset(); + instance + } + + /// Resets the CRC unit to default value (0xFFFF_FFFF) + pub fn reset(&mut self) { + unsafe { PAC_CRC.cr().write(|w| w.set_reset(true)) }; + } + + /// Feeds a word to the peripheral and returns the current CRC value + pub fn feed_word(&mut self, word: u32) -> u32 { + // write a single byte to the device, and return the result + unsafe { + PAC_CRC.dr().write_value(word); + } + self.read() + } + /// Feed a slice of words to the peripheral and return the result. + pub fn feed_words(&mut self, words: &[u32]) -> u32 { + for word in words { + unsafe { PAC_CRC.dr().write_value(*word) } + } + + self.read() + } + pub fn read(&self) -> u32 { + unsafe { PAC_CRC.dr().read() } + } +} diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs new file mode 100644 index 00000000..1ca52956 --- /dev/null +++ b/embassy-stm32/src/crc/v2v3.rs @@ -0,0 +1,178 @@ +use crate::pac::crc::vals; +use crate::pac::CRC as PAC_CRC; +use crate::peripherals::CRC; +use crate::rcc::sealed::RccPeripheral; +use embassy::util::Unborrow; +use embassy_hal_common::unborrow; + +pub struct Crc { + _peripheral: CRC, + _config: Config, +} + +pub enum ConfigError { + InvalidPolynomial, +} + +pub struct Config { + reverse_in: InputReverseConfig, + reverse_out: bool, + #[cfg(crc_v3)] + poly_size: PolySize, + crc_init_value: u32, + #[cfg(crc_v3)] + crc_poly: u32, +} + +pub enum InputReverseConfig { + None, + Byte, + Halfword, + Word, +} + +impl Config { + pub fn new( + reverse_in: InputReverseConfig, + reverse_out: bool, + #[cfg(crc_v3)] poly_size: PolySize, + crc_init_value: u32, + #[cfg(crc_v3)] crc_poly: u32, + ) -> Result { + // As Per RM0091 (DocID018940 Rev 9), Even polynomials are not supported. + #[cfg(crc_v3)] + if crc_poly % 2 == 0 { + return Err(ConfigError::InvalidPolynomial); + } + Ok(Config { + reverse_in, + reverse_out, + #[cfg(crc_v3)] + poly_size, + crc_init_value, + #[cfg(crc_v3)] + crc_poly, + }) + } +} + +#[cfg(crc_v3)] +pub enum PolySize { + Width7, + Width8, + Width16, + Width32, +} + +impl Crc { + /// Instantiates the CRC32 peripheral and initializes it to default values. + pub fn new(peripheral: impl Unborrow, config: Config) -> Self { + // Note: enable and reset come from RccPeripheral. + // enable CRC clock in RCC. + CRC::enable(); + // Reset CRC to default values. + CRC::reset(); + unborrow!(peripheral); + let mut instance = Self { + _peripheral: peripheral, + _config: config, + }; + CRC::reset(); + instance.reconfigure(); + instance.reset(); + instance + } + + pub fn reset(&mut self) { + unsafe { + PAC_CRC.cr().modify(|w| w.set_reset(true)); + } + } + + /// Reconfigures the CRC peripheral. Doesn't reset. + fn reconfigure(&mut self) { + unsafe { + // Init CRC value + PAC_CRC.init().write_value(self._config.crc_init_value); + #[cfg(crc_v3)] + PAC_CRC.pol().write_value(self._config.crc_poly); + + // configure CR components + // (reverse I/O, polysize, poly) + PAC_CRC.cr().write(|w| { + // configure reverse output + w.set_rev_out(match self._config.reverse_out { + true => vals::RevOut::REVERSED, + false => vals::RevOut::NORMAL, + }); + // configure reverse input + w.set_rev_in(match self._config.reverse_in { + InputReverseConfig::None => vals::RevIn::NORMAL, + InputReverseConfig::Byte => vals::RevIn::BYTE, + InputReverseConfig::Halfword => vals::RevIn::HALFWORD, + InputReverseConfig::Word => vals::RevIn::WORD, + }); + // configure the polynomial. + #[cfg(crc_v3)] + w.set_polysize(match self._config.poly_size { + PolySize::Width7 => vals::Polysize::POLYSIZE7, + PolySize::Width8 => vals::Polysize::POLYSIZE8, + PolySize::Width16 => vals::Polysize::POLYSIZE16, + PolySize::Width32 => vals::Polysize::POLYSIZE32, + }); + }) + } + + self.reset(); + } + + /// Feeds a byte into the CRC peripheral. Returns the computed checksum. + pub fn feed_byte(&mut self, byte: u8) -> u32 { + unsafe { + PAC_CRC.dr8().write_value(byte as u32); + PAC_CRC.dr().read() + } + } + + /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. + pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { + for byte in bytes { + unsafe { + PAC_CRC.dr8().write_value(*byte as u32); + } + } + unsafe { PAC_CRC.dr().read() } + } + /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. + pub fn feed_halfword(&mut self, halfword: u16) -> u32 { + unsafe { + PAC_CRC.dr16().write_value(halfword as u32); + PAC_CRC.dr().read() + } + } + /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. + pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { + for halfword in halfwords { + unsafe { + PAC_CRC.dr16().write_value(*halfword as u32); + } + } + unsafe { PAC_CRC.dr().read() } + } + /// Feeds a words into the CRC peripheral. Returns the computed checksum. + pub fn feed_word(&mut self, word: u32) -> u32 { + unsafe { + PAC_CRC.dr().write_value(word as u32); + PAC_CRC.dr().read() + } + } + /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. + pub fn feed_words(&mut self, words: &[u32]) -> u32 { + for word in words { + unsafe { + PAC_CRC.dr().write_value(*word as u32); + } + } + unsafe { PAC_CRC.dr().read() } + } +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 073e79f2..424b1c99 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -39,6 +39,8 @@ pub mod exti; #[cfg(i2c)] pub mod i2c; +#[cfg(crc)] +pub mod crc; #[cfg(pwr)] pub mod pwr; #[cfg(rng)] diff --git a/stm32-data b/stm32-data index 8cdca8ad..9e8e3478 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 8cdca8ad5b65d9a63c5198370ea337ddd03f32b1 +Subproject commit 9e8e34786222b76a7d1bbbc1baf14cd3b33cd2d7