diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-05-13 22:28:15 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-05-13 22:28:15 +0200 |
| commit | aa85293457039a336eec1f10bcd32d47d7223f95 (patch) | |
| tree | 901056384a10854e3b054fcc0603cb9669a6cf9b | |
| parent | 575eab3c60c0d2098f9e9d2a22429aa174b6b968 (diff) | |
| parent | d4c378e059443dbaaaece02a0f5148db62bd4484 (diff) | |
Merge pull request #4181 from felipebalbi/add-crc
Add Embassy-iMXRT CRC driver
| -rw-r--r-- | docs/pages/imxrt.adoc | 2 | ||||
| -rw-r--r-- | embassy-imxrt/src/crc.rs | 190 | ||||
| -rw-r--r-- | embassy-imxrt/src/lib.rs | 1 | ||||
| -rw-r--r-- | examples/mimxrt6/src/bin/crc.rs | 175 |
4 files changed, 367 insertions, 1 deletions
diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc index adf5218e8..a84fbae03 100644 --- a/docs/pages/imxrt.adoc +++ b/docs/pages/imxrt.adoc | |||
| @@ -9,5 +9,5 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb | |||
| 9 | 9 | ||
| 10 | The following peripherals have a HAL implementation at present | 10 | The following peripherals have a HAL implementation at present |
| 11 | 11 | ||
| 12 | * CRC | ||
| 12 | * GPIO | 13 | * GPIO |
| 13 | |||
diff --git a/embassy-imxrt/src/crc.rs b/embassy-imxrt/src/crc.rs new file mode 100644 index 000000000..24d6ba5bd --- /dev/null +++ b/embassy-imxrt/src/crc.rs | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | //! Cyclic Redundancy Check (CRC) | ||
| 2 | |||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 5 | use crate::clocks::{enable_and_reset, SysconPeripheral}; | ||
| 6 | pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial; | ||
| 7 | use crate::{peripherals, Peri, PeripheralType}; | ||
| 8 | |||
| 9 | /// CRC driver. | ||
| 10 | pub struct Crc<'d> { | ||
| 11 | info: Info, | ||
| 12 | _config: Config, | ||
| 13 | _lifetime: PhantomData<&'d ()>, | ||
| 14 | } | ||
| 15 | |||
| 16 | /// CRC configuration | ||
| 17 | pub struct Config { | ||
| 18 | /// Polynomial to be used | ||
| 19 | pub polynomial: Polynomial, | ||
| 20 | |||
| 21 | /// Reverse bit order of input? | ||
| 22 | pub reverse_in: bool, | ||
| 23 | |||
| 24 | /// 1's complement input? | ||
| 25 | pub complement_in: bool, | ||
| 26 | |||
| 27 | /// Reverse CRC bit order? | ||
| 28 | pub reverse_out: bool, | ||
| 29 | |||
| 30 | /// 1's complement CRC? | ||
| 31 | pub complement_out: bool, | ||
| 32 | |||
| 33 | /// CRC Seed | ||
| 34 | pub seed: u32, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl Config { | ||
| 38 | /// Create a new CRC config. | ||
| 39 | #[must_use] | ||
| 40 | pub fn new( | ||
| 41 | polynomial: Polynomial, | ||
| 42 | reverse_in: bool, | ||
| 43 | complement_in: bool, | ||
| 44 | reverse_out: bool, | ||
| 45 | complement_out: bool, | ||
| 46 | seed: u32, | ||
| 47 | ) -> Self { | ||
| 48 | Config { | ||
| 49 | polynomial, | ||
| 50 | reverse_in, | ||
| 51 | complement_in, | ||
| 52 | reverse_out, | ||
| 53 | complement_out, | ||
| 54 | seed, | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | impl Default for Config { | ||
| 60 | fn default() -> Self { | ||
| 61 | Self { | ||
| 62 | polynomial: Polynomial::CrcCcitt, | ||
| 63 | reverse_in: false, | ||
| 64 | complement_in: false, | ||
| 65 | reverse_out: false, | ||
| 66 | complement_out: false, | ||
| 67 | seed: 0xffff, | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | impl<'d> Crc<'d> { | ||
| 73 | /// Instantiates new CRC peripheral and initializes to default values. | ||
| 74 | pub fn new<T: Instance>(_peripheral: Peri<'d, T>, config: Config) -> Self { | ||
| 75 | // enable CRC clock | ||
| 76 | enable_and_reset::<T>(); | ||
| 77 | |||
| 78 | let mut instance = Self { | ||
| 79 | info: T::info(), | ||
| 80 | _config: config, | ||
| 81 | _lifetime: PhantomData, | ||
| 82 | }; | ||
| 83 | |||
| 84 | instance.reconfigure(); | ||
| 85 | instance | ||
| 86 | } | ||
| 87 | |||
| 88 | /// Reconfigured the CRC peripheral. | ||
| 89 | fn reconfigure(&mut self) { | ||
| 90 | self.info.regs.mode().write(|w| { | ||
| 91 | w.crc_poly() | ||
| 92 | .variant(self._config.polynomial) | ||
| 93 | .bit_rvs_wr() | ||
| 94 | .variant(self._config.reverse_in) | ||
| 95 | .cmpl_wr() | ||
| 96 | .variant(self._config.complement_in) | ||
| 97 | .bit_rvs_sum() | ||
| 98 | .variant(self._config.reverse_out) | ||
| 99 | .cmpl_sum() | ||
| 100 | .variant(self._config.complement_out) | ||
| 101 | }); | ||
| 102 | |||
| 103 | // Init CRC value | ||
| 104 | self.info | ||
| 105 | .regs | ||
| 106 | .seed() | ||
| 107 | .write(|w| unsafe { w.crc_seed().bits(self._config.seed) }); | ||
| 108 | } | ||
| 109 | |||
| 110 | /// Feeds a byte into the CRC peripheral. Returns the computed checksum. | ||
| 111 | pub fn feed_byte(&mut self, byte: u8) -> u32 { | ||
| 112 | self.info.regs.wr_data8().write(|w| unsafe { w.bits(byte) }); | ||
| 113 | |||
| 114 | self.info.regs.sum().read().bits() | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. | ||
| 118 | pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { | ||
| 119 | let (prefix, data, suffix) = unsafe { bytes.align_to::<u32>() }; | ||
| 120 | |||
| 121 | for b in prefix { | ||
| 122 | self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) }); | ||
| 123 | } | ||
| 124 | |||
| 125 | for d in data { | ||
| 126 | self.info.regs.wr_data32().write(|w| unsafe { w.bits(*d) }); | ||
| 127 | } | ||
| 128 | |||
| 129 | for b in suffix { | ||
| 130 | self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) }); | ||
| 131 | } | ||
| 132 | |||
| 133 | self.info.regs.sum().read().bits() | ||
| 134 | } | ||
| 135 | |||
| 136 | /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. | ||
| 137 | pub fn feed_halfword(&mut self, halfword: u16) -> u32 { | ||
| 138 | self.info.regs.wr_data16().write(|w| unsafe { w.bits(halfword) }); | ||
| 139 | |||
| 140 | self.info.regs.sum().read().bits() | ||
| 141 | } | ||
| 142 | |||
| 143 | /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. | ||
| 144 | pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { | ||
| 145 | for halfword in halfwords { | ||
| 146 | self.info.regs.wr_data16().write(|w| unsafe { w.bits(*halfword) }); | ||
| 147 | } | ||
| 148 | |||
| 149 | self.info.regs.sum().read().bits() | ||
| 150 | } | ||
| 151 | |||
| 152 | /// Feeds a words into the CRC peripheral. Returns the computed checksum. | ||
| 153 | pub fn feed_word(&mut self, word: u32) -> u32 { | ||
| 154 | self.info.regs.wr_data32().write(|w| unsafe { w.bits(word) }); | ||
| 155 | |||
| 156 | self.info.regs.sum().read().bits() | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. | ||
| 160 | pub fn feed_words(&mut self, words: &[u32]) -> u32 { | ||
| 161 | for word in words { | ||
| 162 | self.info.regs.wr_data32().write(|w| unsafe { w.bits(*word) }); | ||
| 163 | } | ||
| 164 | |||
| 165 | self.info.regs.sum().read().bits() | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | struct Info { | ||
| 170 | regs: crate::pac::CrcEngine, | ||
| 171 | } | ||
| 172 | |||
| 173 | trait SealedInstance { | ||
| 174 | fn info() -> Info; | ||
| 175 | } | ||
| 176 | |||
| 177 | /// CRC instance trait. | ||
| 178 | #[allow(private_bounds)] | ||
| 179 | pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {} | ||
| 180 | |||
| 181 | impl Instance for peripherals::CRC {} | ||
| 182 | |||
| 183 | impl SealedInstance for peripherals::CRC { | ||
| 184 | fn info() -> Info { | ||
| 185 | // SAFETY: safe from single executor | ||
| 186 | Info { | ||
| 187 | regs: unsafe { crate::pac::CrcEngine::steal() }, | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index ad9f81e88..d8ce97f76 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs | |||
| @@ -18,6 +18,7 @@ compile_error!( | |||
| 18 | pub(crate) mod fmt; | 18 | pub(crate) mod fmt; |
| 19 | 19 | ||
| 20 | pub mod clocks; | 20 | pub mod clocks; |
| 21 | pub mod crc; | ||
| 21 | pub mod gpio; | 22 | pub mod gpio; |
| 22 | pub mod iopctl; | 23 | pub mod iopctl; |
| 23 | 24 | ||
diff --git a/examples/mimxrt6/src/bin/crc.rs b/examples/mimxrt6/src/bin/crc.rs new file mode 100644 index 000000000..005a250e5 --- /dev/null +++ b/examples/mimxrt6/src/bin/crc.rs | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | extern crate embassy_imxrt_examples; | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_imxrt::crc::{Config, Crc, Polynomial}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(_spawner: Spawner) { | ||
| 13 | let mut p = embassy_imxrt::init(Default::default()); | ||
| 14 | let data = b"123456789"; | ||
| 15 | |||
| 16 | info!("Initializing CRC"); | ||
| 17 | |||
| 18 | // CRC-CCITT | ||
| 19 | let mut crc = Crc::new(p.CRC.reborrow(), Default::default()); | ||
| 20 | let output = crc.feed_bytes(data); | ||
| 21 | defmt::assert_eq!(output, 0x29b1); | ||
| 22 | |||
| 23 | // CRC16-ARC | ||
| 24 | let mut crc = Crc::new( | ||
| 25 | p.CRC.reborrow(), | ||
| 26 | Config { | ||
| 27 | polynomial: Polynomial::Crc16, | ||
| 28 | reverse_in: true, | ||
| 29 | reverse_out: true, | ||
| 30 | complement_out: false, | ||
| 31 | seed: 0, | ||
| 32 | ..Default::default() | ||
| 33 | }, | ||
| 34 | ); | ||
| 35 | let output = crc.feed_bytes(data); | ||
| 36 | defmt::assert_eq!(output, 0xbb3d); | ||
| 37 | |||
| 38 | // CRC16-CMS | ||
| 39 | let mut crc = Crc::new( | ||
| 40 | p.CRC.reborrow(), | ||
| 41 | Config { | ||
| 42 | polynomial: Polynomial::Crc16, | ||
| 43 | reverse_in: false, | ||
| 44 | reverse_out: false, | ||
| 45 | complement_out: false, | ||
| 46 | seed: 0xffff, | ||
| 47 | ..Default::default() | ||
| 48 | }, | ||
| 49 | ); | ||
| 50 | let output = crc.feed_bytes(data); | ||
| 51 | defmt::assert_eq!(output, 0xaee7); | ||
| 52 | |||
| 53 | // CRC16-DDS-110 | ||
| 54 | let mut crc = Crc::new( | ||
| 55 | p.CRC.reborrow(), | ||
| 56 | Config { | ||
| 57 | polynomial: Polynomial::Crc16, | ||
| 58 | reverse_in: false, | ||
| 59 | reverse_out: false, | ||
| 60 | complement_out: false, | ||
| 61 | seed: 0x800d, | ||
| 62 | ..Default::default() | ||
| 63 | }, | ||
| 64 | ); | ||
| 65 | let output = crc.feed_bytes(data); | ||
| 66 | defmt::assert_eq!(output, 0x9ecf); | ||
| 67 | |||
| 68 | // CRC16-MAXIM-DOW | ||
| 69 | let mut crc = Crc::new( | ||
| 70 | p.CRC.reborrow(), | ||
| 71 | Config { | ||
| 72 | polynomial: Polynomial::Crc16, | ||
| 73 | reverse_in: true, | ||
| 74 | reverse_out: true, | ||
| 75 | complement_out: true, | ||
| 76 | seed: 0, | ||
| 77 | ..Default::default() | ||
| 78 | }, | ||
| 79 | ); | ||
| 80 | let output = crc.feed_bytes(data); | ||
| 81 | defmt::assert_eq!(output, 0x44c2); | ||
| 82 | |||
| 83 | // CRC16-MODBUS | ||
| 84 | let mut crc = Crc::new( | ||
| 85 | p.CRC.reborrow(), | ||
| 86 | Config { | ||
| 87 | polynomial: Polynomial::Crc16, | ||
| 88 | reverse_in: true, | ||
| 89 | reverse_out: true, | ||
| 90 | complement_out: false, | ||
| 91 | seed: 0xffff, | ||
| 92 | ..Default::default() | ||
| 93 | }, | ||
| 94 | ); | ||
| 95 | let output = crc.feed_bytes(data); | ||
| 96 | defmt::assert_eq!(output, 0x4b37); | ||
| 97 | |||
| 98 | // CRC32-BZIP2 | ||
| 99 | let mut crc = Crc::new( | ||
| 100 | p.CRC.reborrow(), | ||
| 101 | Config { | ||
| 102 | polynomial: Polynomial::Crc32, | ||
| 103 | reverse_in: false, | ||
| 104 | reverse_out: false, | ||
| 105 | complement_out: true, | ||
| 106 | seed: 0xffff_ffff, | ||
| 107 | ..Default::default() | ||
| 108 | }, | ||
| 109 | ); | ||
| 110 | let output = crc.feed_bytes(data); | ||
| 111 | defmt::assert_eq!(output, 0xfc89_1918); | ||
| 112 | |||
| 113 | // CRC32-CKSUM | ||
| 114 | let mut crc = Crc::new( | ||
| 115 | p.CRC.reborrow(), | ||
| 116 | Config { | ||
| 117 | polynomial: Polynomial::Crc32, | ||
| 118 | reverse_in: false, | ||
| 119 | reverse_out: false, | ||
| 120 | complement_out: true, | ||
| 121 | seed: 0, | ||
| 122 | ..Default::default() | ||
| 123 | }, | ||
| 124 | ); | ||
| 125 | let output = crc.feed_bytes(data); | ||
| 126 | defmt::assert_eq!(output, 0x765e_7680); | ||
| 127 | |||
| 128 | // CRC32-ISO-HDLC | ||
| 129 | let mut crc = Crc::new( | ||
| 130 | p.CRC.reborrow(), | ||
| 131 | Config { | ||
| 132 | polynomial: Polynomial::Crc32, | ||
| 133 | reverse_in: true, | ||
| 134 | reverse_out: true, | ||
| 135 | complement_out: true, | ||
| 136 | seed: 0xffff_ffff, | ||
| 137 | ..Default::default() | ||
| 138 | }, | ||
| 139 | ); | ||
| 140 | let output = crc.feed_bytes(data); | ||
| 141 | defmt::assert_eq!(output, 0xcbf4_3926); | ||
| 142 | |||
| 143 | // CRC32-JAMCRC | ||
| 144 | let mut crc = Crc::new( | ||
| 145 | p.CRC.reborrow(), | ||
| 146 | Config { | ||
| 147 | polynomial: Polynomial::Crc32, | ||
| 148 | reverse_in: true, | ||
| 149 | reverse_out: true, | ||
| 150 | complement_out: false, | ||
| 151 | seed: 0xffff_ffff, | ||
| 152 | ..Default::default() | ||
| 153 | }, | ||
| 154 | ); | ||
| 155 | let output = crc.feed_bytes(data); | ||
| 156 | defmt::assert_eq!(output, 0x340b_c6d9); | ||
| 157 | |||
| 158 | // CRC32-MPEG-2 | ||
| 159 | let mut crc = Crc::new( | ||
| 160 | p.CRC.reborrow(), | ||
| 161 | Config { | ||
| 162 | polynomial: Polynomial::Crc32, | ||
| 163 | reverse_in: false, | ||
| 164 | reverse_out: false, | ||
| 165 | complement_out: false, | ||
| 166 | seed: 0xffff_ffff, | ||
| 167 | ..Default::default() | ||
| 168 | }, | ||
| 169 | ); | ||
| 170 | let output = crc.feed_bytes(data); | ||
| 171 | defmt::assert_eq!(output, 0x0376_e6e7); | ||
| 172 | |||
| 173 | info!("end program"); | ||
| 174 | cortex_m::asm::bkpt(); | ||
| 175 | } | ||
