Skip to content

Commit 3d157d5

Browse files
authored
Merge pull request #92 from korken89/add_crc
Added CRC peripheral
2 parents a006967 + 166bd76 commit 3d157d5

File tree

3 files changed

+209
-0
lines changed

3 files changed

+209
-0
lines changed

src/crc.rs

+200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
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+
}

src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ pub mod datetime;
6666
feature = "stm32l4x5",
6767
feature = "stm32l4x6"
6868
))]
69+
pub mod crc;
70+
#[cfg(any(
71+
feature = "stm32l4x1",
72+
feature = "stm32l4x2",
73+
feature = "stm32l4x3",
74+
feature = "stm32l4x5",
75+
feature = "stm32l4x6"
76+
))]
6977
pub mod delay;
7078
#[cfg(any(
7179
feature = "stm32l4x1",

src/prelude.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pub use crate::hal::prelude::*; // embedded hal traits
44
pub use crate::hal::digital::v2::*; // for some reason v2 is not exported in the ehal prelude
55

6+
pub use crate::crc::CrcExt as _stm32l4_hal_CrcExt;
67
pub use crate::rcc::RccExt as _stm32l4_hal_RccExt;
78
pub use crate::flash::FlashExt as _stm32l4_hal_FlashExt;
89
pub use crate::gpio::GpioExt as _stm32l4_hal_GpioExt;

0 commit comments

Comments
 (0)