1 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
2 | |
3 | use crate::pac::crc::vals; |
4 | use crate::pac::CRC as PAC_CRC; |
5 | use crate::peripherals::CRC; |
6 | use crate::{rcc, Peripheral}; |
7 | |
8 | /// CRC driver. |
9 | pub 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))] |
17 | pub enum ConfigError { |
18 | /// The selected polynomial is invalid. |
19 | InvalidPolynomial, |
20 | } |
21 | |
22 | /// CRC configuration |
23 | pub 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. |
34 | pub 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 | |
45 | impl 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)] |
74 | pub enum PolySize { |
75 | Width7, |
76 | Width8, |
77 | Width16, |
78 | Width32, |
79 | } |
80 | |
81 | impl<'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 | } |
175 | |