From 191efb47293bfa29dcce785987cb333efbb0fc48 Mon Sep 17 00:00:00 2001 From: Paval-from-Belarus Date: Tue, 24 Dec 2024 12:27:34 +0300 Subject: [PATCH] add register definition for can filter --- examples/ch32v203/src/bin/can.rs | 10 +++- src/can/can.rs | 5 +- src/can/enums.rs | 72 ++----------------------- src/can/filter/bit16.rs | 90 ++++++++++++++++++++++++++++++++ src/can/filter/bit32.rs | 88 +++++++++++++++++++++++++++++++ src/can/filter/mod.rs | 73 ++++++++++++++++++++++++++ src/can/mod.rs | 4 +- src/can/registers.rs | 10 +++- src/can/util.rs | 2 +- 9 files changed, 278 insertions(+), 76 deletions(-) create mode 100644 src/can/filter/bit16.rs create mode 100644 src/can/filter/bit32.rs create mode 100644 src/can/filter/mod.rs diff --git a/examples/ch32v203/src/bin/can.rs b/examples/ch32v203/src/bin/can.rs index 0ed125b..b0a0c2d 100644 --- a/examples/ch32v203/src/bin/can.rs +++ b/examples/ch32v203/src/bin/can.rs @@ -4,9 +4,8 @@ #![feature(impl_trait_in_assoc_type)] use ch32_hal::can::{Can, CanFifo, CanFilter, CanFrame, CanMode, StandardId}; -use embassy_time::{Duration, Ticker}; use embassy_executor::Spawner; - +use embassy_time::{Duration, Ticker}; use {ch32_hal as hal, panic_halt as _}; #[embassy_executor::main(entry = "ch32_hal::entry")] @@ -14,6 +13,13 @@ async fn main(_spawner: Spawner) { let p = hal::init(Default::default()); let can = Can::new(p.CAN1, p.PA11, p.PA12, CanFifo::Fifo1, CanMode::Normal, 500_000).expect("Valid"); + let mut filter = CanFilter::new_id_list(); + + filter + .get(0) + .unwrap() + .set(StandardId::new(0x580 | 0x42).unwrap().into(), Default::default()); + can.add_filter(CanFilter::accept_all()); let mut ticker = Ticker::every(Duration::from_millis(200)); diff --git a/src/can/can.rs b/src/can/can.rs index ec26cf6..93653e3 100644 --- a/src/can/can.rs +++ b/src/can/can.rs @@ -1,5 +1,6 @@ use super::enums::*; -use super::CanFrame; +use super::filter::{BitMode, FilterMode}; +use super::{CanFilter, CanFrame}; use crate as hal; use crate::can::registers::Registers; use crate::can::util; @@ -64,7 +65,7 @@ impl<'d, T: Instance> Can<'d, T> { Ok(this) } - pub fn add_filter(&self, filter: CanFilter) { + pub fn add_filter(&self, filter: CanFilter) { Registers(T::regs()).add_filter(filter, &self.fifo); } diff --git a/src/can/enums.rs b/src/can/enums.rs index 9a3a1b5..78d8129 100644 --- a/src/can/enums.rs +++ b/src/can/enums.rs @@ -27,23 +27,14 @@ impl core::fmt::Display for CanError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Overrun => write!(f, "The peripheral receive buffer was overrun"), - Self::Bit => write!( - f, - "Bit value that is monitored differs from the bit value sent" - ), + Self::Bit => write!(f, "Bit value that is monitored differs from the bit value sent"), Self::Stuff => write!(f, "Sixth consecutive equal bits detected"), Self::Crc => write!(f, "Calculated CRC sequence does not equal the received one"), - Self::Form => write!( - f, - "A fixed-form bit field contains one or more illegal bits" - ), + Self::Form => write!(f, "A fixed-form bit field contains one or more illegal bits"), Self::Acknowledge => write!(f, "Transmitted frame was not acknowledged"), Self::BusOff => write!(f, "The peripheral is in Bus Off mode"), Self::BusPassive => write!(f, "The peripheral is in Bus Passive mode"), - Self::BusWarning => write!( - f, - "A peripheral error counter has reached the Warning threshold" - ), + Self::BusWarning => write!(f, "A peripheral error counter has reached the Warning threshold"), } } } @@ -100,10 +91,7 @@ impl CanMode { lbkm: true, silm: false, }, - CanMode::SilentLoopback => CanModeRegs { - lbkm: true, - silm: true, - }, + CanMode::SilentLoopback => CanModeRegs { lbkm: true, silm: true }, } } } @@ -129,58 +117,6 @@ impl CanFifo { } } -pub enum CanFilterMode { - /// Matches the incoming ID to a predefined value after applying a predefined bit mask. - IdMask, - /// Matches the incoming ID to a predefined set of values. - IdList, -} - -impl CanFilterMode { - pub(crate) fn val_bool(&self) -> bool { - match self { - CanFilterMode::IdMask => false, - CanFilterMode::IdList => true, - } - } -} - -/// See table 24-1 of the reference manual for more details on filtering and modes. -pub struct CanFilter { - /// Filter bank number, 0-27 - pub bank: usize, - /// Filter mode, either identifier mask or identifier list - pub mode: CanFilterMode, - /// Values for `STID:EXID:IDE:RTR:0` from msb to lsb to be matched with an incoming message's values. - /// In IdList mode, value should be a 32-bit id or two 16-bit ids. - pub id_value: u32, - /// Bit mask to be applied to incoming message before comparing it to a predefined value. - /// In IdList mode, this is used in the same way as `id_value` is. - pub id_mask: u32, -} - -impl CanFilter { - /// Creates a filter that accepts all frames - pub fn accept_all() -> Self { - Self { - bank: 0, - mode: CanFilterMode::IdMask, - id_value: 0, - id_mask: 0, - } - } - - /// Offset in `usize` for bank `n` filter register 1 - pub(crate) fn fr_id_value_reg(&self) -> usize { - self.bank * 2 + 0 - } - - /// Offset in `usize` for bank `n` filter register 2 - pub(crate) fn fr_id_mask_reg(&self) -> usize { - self.bank * 2 + 1 - } -} - #[derive(Debug)] pub enum TxStatus { /// Message was sent correctly diff --git a/src/can/filter/bit16.rs b/src/can/filter/bit16.rs new file mode 100644 index 0000000..a13827a --- /dev/null +++ b/src/can/filter/bit16.rs @@ -0,0 +1,90 @@ +use embedded_can::StandardId; + +use super::{Bit16Mode, CanFilter, FilterOptions, ListMode, MaskMode}; + +pub struct Bit16IdReg<'a>(&'a mut u16); + +pub struct Bit16MaskReg<'a> { + mask: &'a mut u16, + id: &'a mut u16, +} + +impl Bit16IdReg<'_> { + pub fn set(&mut self, id: StandardId, opts: FilterOptions) { + let bits = (id.as_raw() << 3) | ((opts.rtr_enabled as u16) << 2); + *self.0 &= 0x0000; + *self.0 |= bits; + } +} + +impl Bit16MaskReg<'_> { + pub fn set(&mut self, id: u16, mask: u16, opts: FilterOptions) { + *self.mask &= 0xFFFF; + *self.id &= 0xFFFF; + + *self.mask |= (id << 3) | ((opts.rtr_enabled as u16) << 2); + *self.id |= (mask << 3) | ((opts.rtr_enabled as u16) << 2); + } +} + +impl CanFilter { + pub fn get(&mut self, index: usize) -> Option { + use core::mem; + + match index { + 0 => { + let bytes = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_value) }; + Some(Bit16IdReg(&mut bytes[0])) + } + + 1 => { + let bytes = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_value) }; + Some(Bit16IdReg(&mut bytes[1])) + } + + 2 => { + let bytes = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_mask) }; + Some(Bit16IdReg(&mut bytes[0])) + } + + 3 => { + let bytes = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_mask) }; + Some(Bit16IdReg(&mut bytes[0])) + } + + _ => None, + } + } +} + +impl From<[(StandardId, FilterOptions); 4]> for CanFilter { + fn from(value: [(StandardId, FilterOptions); 4]) -> Self { + let mut filter = CanFilter::new_id_list().use_16bit(); + + for (index, (id, opts)) in value.into_iter().enumerate() { + filter.get(index).expect("index less 4").set(id, opts); + } + + filter + } +} + +impl CanFilter { + pub fn get(&mut self, index: usize) -> Option { + use core::mem; + + match index { + 0 => { + let [id, mask] = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_value) }; + + Some(Bit16MaskReg { id, mask }) + } + 1 => { + let [id, mask] = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_mask) }; + + Some(Bit16MaskReg { id, mask }) + } + _ => None, + } + } +} diff --git a/src/can/filter/bit32.rs b/src/can/filter/bit32.rs new file mode 100644 index 0000000..c84fb84 --- /dev/null +++ b/src/can/filter/bit32.rs @@ -0,0 +1,88 @@ +use core::marker::PhantomData; + +use embedded_can::Id; + +use super::{Bit16Mode, Bit32Mode, CanFilter, FilterMode, FilterOptions, ListMode, MaskMode}; + +impl CanFilter { + pub fn use_16bit(self) -> CanFilter { + CanFilter { + id_mask: self.id_mask, + id_value: self.id_value, + mode: self.mode, + bank: self.bank, + bit_mode: PhantomData, + } + } +} + +impl CanFilter { + /// Creates a filter that accepts all frames + pub fn accept_all() -> Self { + CanFilter { + bank: 0, + mode: ListMode, + id_value: 0, + id_mask: 0, + bit_mode: PhantomData, + } + } + + pub fn new_id_list() -> Self { + Self { + bank: 0, + bit_mode: PhantomData, + mode: ListMode, + + id_mask: 0, + id_value: 0, + } + } +} + +impl CanFilter { + pub fn new_id_mask() -> Self { + Self { + bank: 0, + bit_mode: PhantomData, + mode: MaskMode, + + id_mask: 0, + id_value: 0, + } + } +} + +pub struct Bit32IdReg<'a>(&'a mut u32); + +impl Bit32IdReg<'_> { + pub fn set(&mut self, id: Id, opts: FilterOptions) { + *self.0 = 0; + *self.0 |= (opts.rtr_enabled as u32) << 1; + + match id { + Id::Standard(id) => { + let id_bits = id.as_raw() as u32; + + *self.0 |= ((id_bits << 3) << 24) | ((id_bits & 0x7) << 20); + } + + Id::Extended(id) => { + let std_id = (id.as_raw() as u16) as u32; + let ext_id = id.as_raw() >> 11; + + *self.0 |= ((std_id << 3) << 24) | ((std_id & 0x7) << 20) | (ext_id << 3); + } + } + } +} + +impl CanFilter { + pub fn get(&mut self, index: usize) -> Option { + match index { + 0 => Some(Bit32IdReg(&mut self.id_value)), + 1 => Some(Bit32IdReg(&mut self.id_mask)), + _ => None, + } + } +} diff --git a/src/can/filter/mod.rs b/src/can/filter/mod.rs new file mode 100644 index 0000000..16722d2 --- /dev/null +++ b/src/can/filter/mod.rs @@ -0,0 +1,73 @@ +mod bit16; +mod bit32; + +use core::marker::PhantomData; + +/// Filter mode, either identifier mask or identifier list +pub trait FilterMode { + fn val_bool(&self) -> bool; +} + +/// Matches the incoming ID to a predefined value after applying a predefined bit mask. +pub struct MaskMode; +pub struct ListMode; + +impl FilterMode for MaskMode { + fn val_bool(&self) -> bool { + false + } +} + +impl FilterMode for ListMode { + fn val_bool(&self) -> bool { + true + } +} + +pub trait BitMode {} + +pub struct Bit16Mode; +pub struct Bit32Mode; + +impl BitMode for Bit16Mode {} +impl BitMode for Bit32Mode {} + +/// See table 24-1 of the reference manual for more details on filtering and modes. +/// Each filter is applied for only one bank and for one register on it bank +pub struct CanFilter { + /// Filter bank number, 0-27 + pub bank: usize, + /// Values for `STID:EXID:IDE:RTR:0` from msb to lsb to be matched with an incoming message's values. + /// In IdList mode, value should be a 32-bit id or two 16-bit ids. + pub id_value: u32, + /// Bit mask to be applied to incoming message before comparing it to a predefined value. + /// In IdList mode, this is used in the same way as `id_value` is. + pub id_mask: u32, + pub bit_mode: PhantomData, + pub mode: MODE, +} + +impl CanFilter { + pub fn set_bank(&mut self, bank: usize) -> &mut Self { + self.bank = bank; + + self + } + + /// Offset in `usize` for bank `n` filter register 1 + pub(crate) fn fr_id_value_reg(&self) -> usize { + self.bank * 2 + 0 + } + + /// Offset in `usize` for bank `n` filter register 2 + pub(crate) fn fr_id_mask_reg(&self) -> usize { + self.bank * 2 + 1 + } +} + +/// By default rtr is disabled +#[derive(Default)] +pub struct FilterOptions { + pub rtr_enabled: bool, + //todo: add ide? +} diff --git a/src/can/mod.rs b/src/can/mod.rs index 96c4427..7a32f56 100644 --- a/src/can/mod.rs +++ b/src/can/mod.rs @@ -1,10 +1,12 @@ mod can; mod enums; +mod filter; mod frame; mod registers; mod util; pub use can::Can; pub use embedded_can::{ExtendedId, Id, StandardId}; -pub use enums::{CanError, CanFifo, CanFilter, CanFilterMode, CanMode, TxStatus}; +pub use enums::{CanError, CanFifo, CanMode, TxStatus}; +pub use filter::{Bit16Mode, Bit32Mode, CanFilter, ListMode, MaskMode}; pub use frame::CanFrame; diff --git a/src/can/registers.rs b/src/can/registers.rs index 0c7c63f..bfa3d23 100644 --- a/src/can/registers.rs +++ b/src/can/registers.rs @@ -1,3 +1,5 @@ +use super::filter::{BitMode, FilterMode}; + const CAN_TX_TIMEOUT: u32 = 0xFFF; pub(crate) struct Registers(pub crate::pac::can::Can); @@ -43,7 +45,12 @@ impl Registers { }); } - pub fn add_filter(&self, filter: super::CanFilter, associate_fifo: &super::CanFifo) { + /// Each filter bank consists of 2 32-bit registers CAN_FxR0 and CAN_FxR1 + pub fn add_filter( + &self, + filter: super::CanFilter, + associate_fifo: &super::CanFifo, + ) { self.0.fctlr().modify(|w| w.set_finit(true)); // Enable filter init mode self.0.fwr().modify(|w| w.set_fact(filter.bank, true)); // Activate new filter in filter bank self.0.fscfgr().modify(|w| w.set_fsc(filter.bank, true)); // Set filter scale config to single 32-bit (16-bit not implemented) @@ -146,7 +153,6 @@ impl Registers { v.set_fmp(0); }); - frame } } diff --git a/src/can/util.rs b/src/can/util.rs index 6448116..2c6b8fd 100644 --- a/src/can/util.rs +++ b/src/can/util.rs @@ -81,7 +81,7 @@ pub fn calc_can_timings(periph_clock: u32, can_bitrate: u32) -> Option bs1);