stm32l4xx_hal/
crc.rs

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
19use crate::rcc::{self, Enable};
20use crate::stm32::CRC;
21use core::hash::Hasher;
22
23/// Extension trait to constrain the CRC peripheral.
24pub 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
29impl CrcExt for CRC {
30    fn constrain(self, ahb1: &mut rcc::AHB1) -> Config {
31        // Enable power to CRC unit
32        CRC::enable(ahb1);
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.
45pub 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.
57pub 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.
67pub struct Config {
68    initial_value: u32,
69    polynomial: Polynomial,
70    input_bit_reversal: Option<BitReversal>,
71    output_bit_reversal: bool,
72}
73
74impl 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| w.init().bits(init));
122        crc.pol.write(|w| unsafe { w.bits(poly) });
123        crc.cr.write(|w| {
124            w.rev_in()
125                .bits(in_rev_bits)
126                .polysize()
127                .bits(poly_bits)
128                .reset()
129                .set_bit();
130
131            if self.output_bit_reversal {
132                w.rev_out().set_bit()
133            } else {
134                w.rev_out().clear_bit()
135            }
136        });
137
138        Crc {}
139    }
140}
141
142/// Constrained CRC peripheral.
143pub struct Crc {}
144
145impl Crc {
146    /// This will reset the CRC to its initial condition.
147    #[inline]
148    pub fn reset(&mut self) {
149        let crc = unsafe { &(*CRC::ptr()) };
150
151        crc.cr.modify(|_, w| w.reset().set_bit());
152    }
153
154    /// This will reset the CRC to its initial condition, however with a specific initial value.
155    /// This is very useful if many task are sharing the CRC peripheral, as one can read out the
156    /// intermediate result, store it until the next time a task runs, and initialize with the
157    /// intermediate result to continue where the task left off.
158    #[inline]
159    pub fn reset_with_inital_value(&mut self, initial_value: u32) {
160        let crc = unsafe { &(*CRC::ptr()) };
161
162        crc.init.write(|w| w.init().bits(initial_value));
163        crc.cr.modify(|_, w| w.reset().set_bit());
164    }
165
166    /// Feed the CRC with data
167    #[inline]
168    pub fn feed(&mut self, data: &[u8]) {
169        let crc = unsafe { &(*CRC::ptr()) };
170        for &byte in data {
171            crc.dr8().write(|w| w.dr8().bits(byte));
172        }
173    }
174
175    /// Get the result of the CRC, depending on the polynomial chosen only a certain amount of the
176    /// bits are the result. This will reset the CRC peripheral after use.
177    #[inline]
178    pub fn result(&mut self) -> u32 {
179        let ret = self.peek_result();
180
181        self.reset();
182
183        ret
184    }
185
186    /// Get a peed at the result of the CRC, depending on the polynomial chosen only a certain
187    /// amount of the bits are the result.
188    #[inline]
189    pub fn peek_result(&self) -> u32 {
190        let crc = unsafe { &(*CRC::ptr()) };
191
192        crc.dr().read().bits()
193    }
194}
195
196impl Hasher for Crc {
197    #[inline]
198    fn finish(&self) -> u64 {
199        // `peek_result` as `core::hash::Hasher` required that the `finish` method does not reset
200        // the hasher.
201        self.peek_result() as u64
202    }
203
204    #[inline]
205    fn write(&mut self, data: &[u8]) {
206        self.feed(data);
207    }
208}