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