forked from stm32-rs/stm32l0xx-hal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request stm32-rs#169 from allexoll/crc
adding support for crc engine, shamelessly taken from stm32l4xx-hal.
- Loading branch information
Showing
5 changed files
with
257 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#![deny(unsafe_code)] | ||
#![no_std] | ||
#![no_main] | ||
|
||
extern crate panic_halt; | ||
|
||
use cortex_m_rt::entry; | ||
use stm32l0xx_hal::{crc::*, pac, prelude::*, rcc::Config}; | ||
|
||
#[entry] | ||
fn main() -> ! { | ||
let dp = pac::Peripherals::take().unwrap(); | ||
let mut rcc = dp.RCC.freeze(Config::hsi16()); | ||
|
||
let crc = dp.CRC.constrain(&mut rcc); | ||
|
||
// Lets use the Ethernet CRC. The polynomial is there by default | ||
// but we need reflected in (by byte) and reflected out. | ||
let mut crc = crc | ||
.input_bit_reversal(BitReversal::ByByte) | ||
.output_bit_reversal(true) | ||
.freeze(); | ||
|
||
let data = [ | ||
0x21, 0x10, 0x00, 0x00, 0x63, 0x30, 0x42, 0x20, 0xa5, 0x50, 0x84, 0x40, 0xe7, 0x70, 0xc6, | ||
0x60, 0x4a, 0xa1, 0x29, 0x91, 0x8c, 0xc1, 0x6b, 0xb1, 0xce, 0xe1, 0xad, 0xd1, 0x31, 0x12, | ||
0xef, 0xf1, 0x52, 0x22, 0x73, 0x32, 0xa1, 0xb2, 0xc3, | ||
]; | ||
|
||
crc.feed(&data); | ||
|
||
// CRC32 has final XOR value of 0xFFFFFFFF | ||
let result = crc.result() ^ 0xffff_ffff; | ||
|
||
// check against https://crccalc.com/ | ||
// with 2110000063304220a5508440e770c6604aa129918cc16bb1cee1add13112eff152227332a1b2c3 | ||
// as hex input | ||
assert!(result == 0x5C45_81C0); | ||
|
||
loop {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
//! CRC calculation unit | ||
//! | ||
//! This unit is modeled after the [corresponding unit in the stm32l4xx-hal](https://github.com/stm32-rs/stm32l4xx-hal/blob/master/src/crc.rs). | ||
//! | ||
//! 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::pac::CRC; | ||
use crate::rcc::Rcc; | ||
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, rcc: &mut Rcc) -> Config; | ||
} | ||
|
||
impl CrcExt for CRC { | ||
fn constrain(self, rcc: &mut Rcc) -> Config { | ||
// Enable power to CRC unit | ||
rcc.rb.ahbenr.modify(|_, w| w.crcen().set_bit()); | ||
|
||
// 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| unsafe { w.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| unsafe { w.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| unsafe { w.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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters