embassy_stm32/crc/
v2v3.rs

1use embassy_hal_internal::{into_ref, PeripheralRef};
2
3use crate::pac::crc::vals;
4use crate::pac::CRC as PAC_CRC;
5use crate::peripherals::CRC;
6use crate::{rcc, Peripheral};
7
8/// CRC driver.
9pub struct Crc<'d> {
10    _peripheral: PeripheralRef<'d, CRC>,
11    _config: Config,
12}
13
14/// CRC configuration errlr
15#[derive(Debug)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum ConfigError {
18    /// The selected polynomial is invalid.
19    InvalidPolynomial,
20}
21
22/// CRC configuration
23pub struct Config {
24    reverse_in: InputReverseConfig,
25    reverse_out: bool,
26    #[cfg(crc_v3)]
27    poly_size: PolySize,
28    crc_init_value: u32,
29    #[cfg(crc_v3)]
30    crc_poly: u32,
31}
32
33/// Input reverse configuration.
34pub enum InputReverseConfig {
35    /// Don't reverse anything
36    None,
37    /// Reverse bytes
38    Byte,
39    /// Reverse 16-bit halfwords.
40    Halfword,
41    /// Reverse 32-bit words.
42    Word,
43}
44
45impl Config {
46    /// Create a new CRC config.
47    pub fn new(
48        reverse_in: InputReverseConfig,
49        reverse_out: bool,
50        #[cfg(crc_v3)] poly_size: PolySize,
51        crc_init_value: u32,
52        #[cfg(crc_v3)] crc_poly: u32,
53    ) -> Result<Self, ConfigError> {
54        // As Per RM0091 (DocID018940 Rev 9), Even polynomials are not supported.
55        #[cfg(crc_v3)]
56        if crc_poly % 2 == 0 {
57            return Err(ConfigError::InvalidPolynomial);
58        }
59        Ok(Config {
60            reverse_in,
61            reverse_out,
62            #[cfg(crc_v3)]
63            poly_size,
64            crc_init_value,
65            #[cfg(crc_v3)]
66            crc_poly,
67        })
68    }
69}
70
71/// Polynomial size
72#[cfg(crc_v3)]
73#[allow(missing_docs)]
74pub enum PolySize {
75    Width7,
76    Width8,
77    Width16,
78    Width32,
79}
80
81impl<'d> Crc<'d> {
82    /// Instantiates the CRC32 peripheral and initializes it to default values.
83    pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self {
84        // Note: enable and reset come from RccPeripheral.
85        // reset to default values and enable CRC clock in RCC.
86        rcc::enable_and_reset::<CRC>();
87        into_ref!(peripheral);
88        let mut instance = Self {
89            _peripheral: peripheral,
90            _config: config,
91        };
92        instance.reconfigure();
93        instance.reset();
94        instance
95    }
96
97    /// Reset the CRC engine.
98    pub fn reset(&mut self) {
99        PAC_CRC.cr().modify(|w| w.set_reset(true));
100    }
101
102    /// Reconfigures the CRC peripheral. Doesn't reset.
103    fn reconfigure(&mut self) {
104        // Init CRC value
105        PAC_CRC.init().write_value(self._config.crc_init_value);
106        #[cfg(crc_v3)]
107        PAC_CRC.pol().write_value(self._config.crc_poly);
108
109        // configure CR components
110        // (reverse I/O, polysize, poly)
111        PAC_CRC.cr().write(|w| {
112            // configure reverse output
113            w.set_rev_out(match self._config.reverse_out {
114                true => vals::RevOut::REVERSED,
115                false => vals::RevOut::NORMAL,
116            });
117            // configure reverse input
118            w.set_rev_in(match self._config.reverse_in {
119                InputReverseConfig::None => vals::RevIn::NORMAL,
120                InputReverseConfig::Byte => vals::RevIn::BYTE,
121                InputReverseConfig::Halfword => vals::RevIn::HALF_WORD,
122                InputReverseConfig::Word => vals::RevIn::WORD,
123            });
124            // configure the polynomial.
125            #[cfg(crc_v3)]
126            w.set_polysize(match self._config.poly_size {
127                PolySize::Width7 => vals::Polysize::POLYSIZE7,
128                PolySize::Width8 => vals::Polysize::POLYSIZE8,
129                PolySize::Width16 => vals::Polysize::POLYSIZE16,
130                PolySize::Width32 => vals::Polysize::POLYSIZE32,
131            });
132        });
133
134        self.reset();
135    }
136
137    /// Feeds a byte into the CRC peripheral. Returns the computed checksum.
138    pub fn feed_byte(&mut self, byte: u8) -> u32 {
139        PAC_CRC.dr8().write_value(byte);
140        PAC_CRC.dr32().read()
141    }
142
143    /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
144    pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
145        for byte in bytes {
146            PAC_CRC.dr8().write_value(*byte);
147        }
148        PAC_CRC.dr32().read()
149    }
150    /// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
151    pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
152        PAC_CRC.dr16().write_value(halfword);
153        PAC_CRC.dr32().read()
154    }
155    /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
156    pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
157        for halfword in halfwords {
158            PAC_CRC.dr16().write_value(*halfword);
159        }
160        PAC_CRC.dr32().read()
161    }
162    /// Feeds a words into the CRC peripheral. Returns the computed checksum.
163    pub fn feed_word(&mut self, word: u32) -> u32 {
164        PAC_CRC.dr32().write_value(word as u32);
165        PAC_CRC.dr32().read()
166    }
167    /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
168    pub fn feed_words(&mut self, words: &[u32]) -> u32 {
169        for word in words {
170            PAC_CRC.dr32().write_value(*word as u32);
171        }
172        PAC_CRC.dr32().read()
173    }
174}