|
| 1 | +//! CRC calculation unit |
| 2 | +//! |
| 3 | +//! Usage example: |
| 4 | +//! ``` |
| 5 | +//! let crc = dp.CRC.constrain(&mut rcc.ahb1); |
| 6 | +//! |
| 7 | +//! // Lets use the CRC-16-CCITT polynomial |
| 8 | +//! let mut crc = crc.polynomial(crc::Polynomial::L16(0x1021)).freeze(); |
| 9 | +//! |
| 10 | +//! let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]; |
| 11 | +//! crc.feed(&data); |
| 12 | +//! |
| 13 | +//! let result = crc.result(); |
| 14 | +//! assert!(result == 0x78cb); |
| 15 | +//! ``` |
| 16 | +
|
| 17 | +#![deny(missing_docs)] |
| 18 | + |
| 19 | +use crate::rcc; |
| 20 | +use crate::stm32::CRC; |
| 21 | +use core::ptr; |
| 22 | + |
| 23 | +/// Extension trait to constrain the FLASH peripheral. |
| 24 | +pub trait CrcExt { |
| 25 | + /// Constrains the CRC peripheral to play nicely with the other abstractions |
| 26 | + fn constrain(self, ahb1: &mut rcc::AHB1) -> Config; |
| 27 | +} |
| 28 | + |
| 29 | +impl CrcExt for CRC { |
| 30 | + fn constrain(self, ahb1: &mut rcc::AHB1) -> Config { |
| 31 | + // Enable power to CRC unit |
| 32 | + ahb1.enr().modify(|_, w| w.crcen().set_bit()); |
| 33 | + |
| 34 | + // Default values |
| 35 | + Config { |
| 36 | + initial_value: 0xffff_ffff, |
| 37 | + polynomial: Polynomial::L32(0x04c1_1db7), |
| 38 | + input_bit_reversal: None, |
| 39 | + output_bit_reversal: false, |
| 40 | + } |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +/// Polynomial settings. |
| 45 | +pub enum Polynomial { |
| 46 | + /// 7-bit polynomial, only the lowest 7 bits are valid |
| 47 | + L7(u8), |
| 48 | + /// 8-bit polynomial |
| 49 | + L8(u8), |
| 50 | + /// 16-bit polynomial |
| 51 | + L16(u16), |
| 52 | + /// 32-bit polynomial |
| 53 | + L32(u32), |
| 54 | +} |
| 55 | + |
| 56 | +/// Bit reversal settings. |
| 57 | +pub enum BitReversal { |
| 58 | + /// Reverse bits by byte |
| 59 | + ByByte, |
| 60 | + /// Reverse bits by half-word |
| 61 | + ByHalfWord, |
| 62 | + /// Reverse bits by word |
| 63 | + ByWord, |
| 64 | +} |
| 65 | + |
| 66 | +/// CRC configuration structure, uses builder pattern. |
| 67 | +pub struct Config { |
| 68 | + initial_value: u32, |
| 69 | + polynomial: Polynomial, |
| 70 | + input_bit_reversal: Option<BitReversal>, |
| 71 | + output_bit_reversal: bool, |
| 72 | +} |
| 73 | + |
| 74 | +impl Config { |
| 75 | + /// Sets the initial value of the CRC. |
| 76 | + pub fn initial_value(mut self, init: u32) -> Self { |
| 77 | + self.initial_value = init; |
| 78 | + |
| 79 | + self |
| 80 | + } |
| 81 | + |
| 82 | + /// Sets the polynomial of the CRC. |
| 83 | + pub fn polynomial(mut self, polynomial: Polynomial) -> Self { |
| 84 | + self.polynomial = polynomial; |
| 85 | + |
| 86 | + self |
| 87 | + } |
| 88 | + |
| 89 | + /// Enables bit reversal of the inputs. |
| 90 | + pub fn input_bit_reversal(mut self, rev: BitReversal) -> Self { |
| 91 | + self.input_bit_reversal = Some(rev); |
| 92 | + |
| 93 | + self |
| 94 | + } |
| 95 | + |
| 96 | + /// Enables bit reversal of the outputs. |
| 97 | + pub fn output_bit_reversal(mut self, rev: bool) -> Self { |
| 98 | + self.output_bit_reversal = rev; |
| 99 | + |
| 100 | + self |
| 101 | + } |
| 102 | + |
| 103 | + /// Freezes the peripheral, making the configuration take effect. |
| 104 | + pub fn freeze(self) -> Crc { |
| 105 | + let crc = unsafe { &(*CRC::ptr()) }; |
| 106 | + |
| 107 | + let (poly, poly_bits, init) = match self.polynomial { |
| 108 | + Polynomial::L7(val) => ((val & 0x7f) as u32, 0b11, self.initial_value & 0x7f), |
| 109 | + Polynomial::L8(val) => (val as u32, 0b10, self.initial_value & 0xff), |
| 110 | + Polynomial::L16(val) => (val as u32, 0b01, self.initial_value & 0xffff), |
| 111 | + Polynomial::L32(val) => (val, 0b00, self.initial_value), |
| 112 | + }; |
| 113 | + |
| 114 | + let in_rev_bits = match self.input_bit_reversal { |
| 115 | + None => 0b00, |
| 116 | + Some(BitReversal::ByByte) => 0b01, |
| 117 | + Some(BitReversal::ByHalfWord) => 0b10, |
| 118 | + Some(BitReversal::ByWord) => 0b11, |
| 119 | + }; |
| 120 | + |
| 121 | + crc.init.write(|w| unsafe { w.crc_init().bits(init) }); |
| 122 | + crc.pol.write(|w| unsafe { w.bits(poly) }); |
| 123 | + crc.cr.write(|w| { |
| 124 | + unsafe { |
| 125 | + w.rev_in() |
| 126 | + .bits(in_rev_bits) |
| 127 | + .polysize() |
| 128 | + .bits(poly_bits) |
| 129 | + .reset() |
| 130 | + .set_bit(); |
| 131 | + } |
| 132 | + |
| 133 | + if self.output_bit_reversal { |
| 134 | + w.rev_out().set_bit() |
| 135 | + } else { |
| 136 | + w.rev_out().clear_bit() |
| 137 | + } |
| 138 | + }); |
| 139 | + |
| 140 | + Crc {} |
| 141 | + } |
| 142 | +} |
| 143 | + |
| 144 | +/// Constrained CRC peripheral. |
| 145 | +pub struct Crc {} |
| 146 | + |
| 147 | +impl Crc { |
| 148 | + /// This will reset the CRC to its initial condition. |
| 149 | + #[inline] |
| 150 | + pub fn reset(&mut self) { |
| 151 | + let crc = unsafe { &(*CRC::ptr()) }; |
| 152 | + |
| 153 | + crc.cr.modify(|_, w| w.reset().set_bit()); |
| 154 | + } |
| 155 | + |
| 156 | + /// This will reset the CRC to its initial condition, however with a specific initial value. |
| 157 | + /// This is very useful if many task are sharing the CRC peripheral, as one can read out the |
| 158 | + /// intermediate result, store it until the next time a task runs, and initialize with the |
| 159 | + /// intermediate result to continue where the task left off. |
| 160 | + #[inline] |
| 161 | + pub fn reset_with_inital_value(&mut self, initial_value: u32) { |
| 162 | + let crc = unsafe { &(*CRC::ptr()) }; |
| 163 | + |
| 164 | + crc.init.write(|w| unsafe { w.crc_init().bits(initial_value) }); |
| 165 | + crc.cr.modify(|_, w| w.reset().set_bit()); |
| 166 | + } |
| 167 | + |
| 168 | + /// Feed the CRC with data, this will internally optimize for word writes. |
| 169 | + #[inline] |
| 170 | + pub fn feed(&mut self, data: &[u8]) { |
| 171 | + let crc = unsafe { &(*CRC::ptr()) }; |
| 172 | + for byte in data { |
| 173 | + unsafe { |
| 174 | + // Workaround with svd2rust, it does not generate the byte interface to the DR |
| 175 | + // register |
| 176 | + ptr::write_volatile(&crc.dr as *const _ as *mut u8, *byte); |
| 177 | + } |
| 178 | + } |
| 179 | + } |
| 180 | + |
| 181 | + /// Get the result of the CRC, depending on the polynomial chosen only a certain amount of the |
| 182 | + /// bits are the result. This will reset the CRC peripheral after use. |
| 183 | + #[inline] |
| 184 | + pub fn result(&mut self) -> u32 { |
| 185 | + let ret = self.peek_result(); |
| 186 | + |
| 187 | + self.reset(); |
| 188 | + |
| 189 | + ret |
| 190 | + } |
| 191 | + |
| 192 | + /// Get a peed at the result of the CRC, depending on the polynomial chosen only a certain |
| 193 | + /// amount of the bits are the result. |
| 194 | + #[inline] |
| 195 | + pub fn peek_result(&self) -> u32 { |
| 196 | + let crc = unsafe { &(*CRC::ptr()) }; |
| 197 | + |
| 198 | + crc.dr.read().bits() |
| 199 | + } |
| 200 | +} |
0 commit comments