From 172e319720bf9a8dd7e7e31f97b818fd900e08d6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 13 May 2025 12:30:20 +0200 Subject: [PATCH] first CAN test works --- examples/embassy/Cargo.toml | 1 + examples/embassy/src/bin/can.rs | 60 +++++++++++++++++++++++----- va416xx-hal/Cargo.toml | 1 + va416xx-hal/src/can/frame.rs | 21 +++++++--- va416xx-hal/src/can/ll.rs | 56 ++++++++++++++------------ va416xx-hal/src/can/mod.rs | 70 +++++++++++++++++++++++---------- va416xx-hal/src/can/regs.rs | 16 +++++--- 7 files changed, 157 insertions(+), 68 deletions(-) diff --git a/examples/embassy/Cargo.toml b/examples/embassy/Cargo.toml index 2ac9a67..300a7d7 100644 --- a/examples/embassy/Cargo.toml +++ b/examples/embassy/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" cortex-m-rt = "0.7" cfg-if = "1" embedded-io = "0.6" +embedded-can = "0.4" embedded-hal-async = "1" embedded-io-async = "0.6" diff --git a/examples/embassy/src/bin/can.rs b/examples/embassy/src/bin/can.rs index 1e0f039..588d5a0 100644 --- a/examples/embassy/src/bin/can.rs +++ b/examples/embassy/src/bin/can.rs @@ -31,26 +31,66 @@ async fn main(_spawner: Spawner) { va416xx_embassy::init(dp.tim15, dp.tim14, &clocks); defmt::info!("creating CAN peripheral driver"); defmt::info!("clocks: {}", clocks); - let clk_config = ClockConfig::from_bitrate_and_segments(&clocks, 250.kHz(), 4, 14, 5) + let clk_config = ClockConfig::from_bitrate_and_segments(&clocks, 250.kHz(), 14, 5, 4) .expect("CAN clock config error"); let mut can = Can::new(dp.can0, clk_config); - can.set_loopback(true); - can.set_bufflock(true); + can.modify_control(|mut val| { + val.set_loopback(true); + val.set_ignore_ack(true); + val.set_internal(true); + val.set_bufflock(true); + val.set_diag_enable(true); + val + }); can.set_base_mask_for_all_match(); can.enable(); + let err_counter = can.read_error_counters(); + defmt::info!( + "error count tx {}, error count rx {}", + err_counter.transmit(), + err_counter.receive() + ); let mut channels = can.take_channels().unwrap(); // Transmit channel. let mut tx = CanTx::new(channels.take(0).unwrap(), None); // Base channel which has dedicated mask. - let mut rx = CanRx::new(channels.take(14).unwrap()); - let send_frame = CanFrame::Normal(CanFrameNormal::new( - can::Id::Standard(can::StandardId::new(0x1).unwrap()), - &[1, 2, 3, 4], - )); + let mut rx_dedicated = CanRx::new(channels.take(1).unwrap()); + // Base channel which has dedicated mask. + let mut rx_base = CanRx::new(channels.take(14).unwrap()); + let standard_id = can::StandardId::new(0x42).unwrap(); + let send_frame = CanFrame::Normal( + CanFrameNormal::new(can::Id::Standard(standard_id), &[1, 2, 3, 4]).unwrap(), + ); + rx_dedicated + .configure_for_reception_with_standard_id(standard_id, false) + .unwrap(); + rx_base.configure_for_reception(); defmt::info!("sending CAN frame"); tx.transmit_frame(send_frame).unwrap(); - let _frame = nb::block!(rx.receive(true)).expect("invalid CAN rx state"); - defmt::info!("received CAN frame with data"); + let frame = nb::block!(rx_dedicated.receive(true)).expect("invalid CAN rx state"); + let err_counter = can.read_error_counters(); + defmt::info!( + "error count tx {}, error count rx {}", + err_counter.transmit(), + err_counter.receive() + ); + let diag = can.read_error_diagnostics(); + defmt::info!("EFID: {}, EBID: {}", diag.efid(), diag.ebid()); + match frame { + CanFrame::Normal(can_frame_normal) => match can_frame_normal.id() { + can::Id::Standard(standard_id) => { + defmt::info!( + "received CAN frame with ID {} and data {}", + standard_id.as_raw(), + can_frame_normal.data() + ); + } + can::Id::Extended(_) => (), + }, + _ => { + defmt::error!("received unexpected CAN remote frame"); + } + } loop {} } diff --git a/va416xx-hal/Cargo.toml b/va416xx-hal/Cargo.toml index 7f081bf..24ba437 100644 --- a/va416xx-hal/Cargo.toml +++ b/va416xx-hal/Cargo.toml @@ -14,6 +14,7 @@ categories = ["embedded", "no-std", "hardware-support"] cortex-m = { version = "0.7", features = ["critical-section-single-core"] } va416xx = { version = "0.4", features = ["critical-section"], default-features = false } derive-mmio = { version = "0.4", git = "https://github.com/knurling-rs/derive-mmio.git" } +static_assertions = "1.1" vorago-shared-periphs = { git = "https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs.git", features = ["vor4x"] } libm = "0.2" diff --git a/va416xx-hal/src/can/frame.rs b/va416xx-hal/src/can/frame.rs index f4bef5e..838740a 100644 --- a/va416xx-hal/src/can/frame.rs +++ b/va416xx-hal/src/can/frame.rs @@ -12,25 +12,31 @@ pub struct CanFrameNormal { } impl CanFrameNormal { - pub fn new(id: embedded_can::Id, data: &[u8]) -> Self { + pub fn new(id: embedded_can::Id, data: &[u8]) -> Result { + if data.len() > 8 { + return Err(InvalidDataSizeError(data.len())); + } let size = data.len(); let mut data_array = [0; 8]; - data_array[..size].copy_from_slice(data); - Self { + data_array[0..size].copy_from_slice(data); + Ok(Self { id, size, data: data_array, - } + }) } + #[inline] pub fn id(&self) -> embedded_can::Id { self.id } + #[inline] pub fn data(&self) -> &[u8] { - &self.data[..self.size] + &self.data[0..self.dlc()] } + #[inline] pub fn dlc(&self) -> usize { self.size } @@ -76,8 +82,11 @@ impl From for CanFrame { impl embedded_can::Frame for CanFrame { fn new(id: impl Into, data: &[u8]) -> Option { + if data.len() > 8 { + return None; + } let id: embedded_can::Id = id.into(); - Some(Self::Normal(CanFrameNormal::new(id, data))) + Some(Self::Normal(CanFrameNormal::new(id, data).unwrap())) } fn new_remote(id: impl Into, dlc: usize) -> Option { diff --git a/va416xx-hal/src/can/ll.rs b/va416xx-hal/src/can/ll.rs index 41b35e0..a048355 100644 --- a/va416xx-hal/src/can/ll.rs +++ b/va416xx-hal/src/can/ll.rs @@ -73,15 +73,19 @@ impl CanChannelLowLevel { } } + pub fn reset(&mut self) { + self.msg_buf.reset(); + } + #[inline] pub fn read_state(&self) -> Result { - self.msg_buf.read_stat_ctrl().status() + self.msg_buf.read_stat_ctrl().state() } #[inline] pub fn write_state(&mut self, buffer_state: BufferState) { self.msg_buf.modify_stat_ctrl(|mut val| { - val.set_status(buffer_state); + val.set_state(buffer_state); val }); } @@ -95,7 +99,7 @@ impl CanChannelLowLevel { if let Some(tx_priority) = tx_priority { val.set_priority(tx_priority); } - val.set_status(BufferState::TxNotActive); + val.set_state(BufferState::TxNotActive); val }); Ok(()) @@ -135,7 +139,7 @@ impl CanChannelLowLevel { BufStatusAndControl::builder() .with_dlc(u4::new(0)) .with_priority(u4::new(0)) - .with_status(BufferState::RxReady) + .with_state(BufferState::RxReady) .build(), ); } @@ -144,6 +148,10 @@ impl CanChannelLowLevel { let is_remote = frame.is_remote_frame(); self.write_id(frame.id(), is_remote); let dlc = frame.dlc(); + self.msg_buf.modify_stat_ctrl(|mut ctrl| { + ctrl.set_dlc(u4::new(dlc as u8)); + ctrl + }); if !is_remote { self.msg_buf .write_data0(TwoBytesData::new_with_raw_value(0)); @@ -155,35 +163,35 @@ impl CanChannelLowLevel { .write_data3(TwoBytesData::new_with_raw_value(0)); for idx in 0..dlc { match idx { - 0 => self.msg_buf.modify_data3(|mut val| { + 0 => self.msg_buf.modify_data0(|mut val| { val.set_data_upper_byte(frame.data()[idx]); val }), - 1 => self.msg_buf.modify_data3(|mut val| { + 1 => self.msg_buf.modify_data0(|mut val| { val.set_data_lower_byte(frame.data()[idx]); val }), - 2 => self.msg_buf.modify_data2(|mut val| { + 2 => self.msg_buf.modify_data1(|mut val| { val.set_data_upper_byte(frame.data()[idx]); val }), - 3 => self.msg_buf.modify_data2(|mut val| { + 3 => self.msg_buf.modify_data1(|mut val| { val.set_data_lower_byte(frame.data()[idx]); val }), - 4 => self.msg_buf.modify_data1(|mut val| { + 4 => self.msg_buf.modify_data2(|mut val| { val.set_data_upper_byte(frame.data()[idx]); val }), - 5 => self.msg_buf.modify_data1(|mut val| { + 5 => self.msg_buf.modify_data2(|mut val| { val.set_data_lower_byte(frame.data()[idx]); val }), - 6 => self.msg_buf.modify_data0(|mut val| { + 6 => self.msg_buf.modify_data3(|mut val| { val.set_data_upper_byte(frame.data()[idx]); val }), - 7 => self.msg_buf.modify_data0(|mut val| { + 7 => self.msg_buf.modify_data3(|mut val| { val.set_data_lower_byte(frame.data()[idx]); val }), @@ -191,11 +199,7 @@ impl CanChannelLowLevel { } } } - self.msg_buf.modify_stat_ctrl(|mut ctrl| { - ctrl.set_dlc(u4::new(dlc as u8)); - ctrl.set_status(BufferState::TxOnce); - ctrl - }); + self.write_state(BufferState::TxOnce); } pub fn enable_error_interrupt(&mut self, enable_translation: bool) { @@ -273,14 +277,14 @@ impl CanChannelLowLevel { let mut data: [u8; 8] = [0; 8]; let mut read_data = |dlc: u4| { (0..dlc.as_usize()).for_each(|i| match i { - 0 => data[i] = data3.data_upper_byte().as_u8(), - 1 => data[i] = data3.data_lower_byte().as_u8(), - 2 => data[i] = data2.data_upper_byte().as_u8(), - 3 => data[i] = data2.data_lower_byte().as_u8(), - 4 => data[i] = data1.data_upper_byte().as_u8(), - 5 => data[i] = data1.data_lower_byte().as_u8(), - 6 => data[i] = data0.data_upper_byte().as_u8(), - 7 => data[i] = data0.data_lower_byte().as_u8(), + 0 => data[i] = data0.data_upper_byte().as_u8(), + 1 => data[i] = data0.data_lower_byte().as_u8(), + 2 => data[i] = data1.data_upper_byte().as_u8(), + 3 => data[i] = data1.data_lower_byte().as_u8(), + 4 => data[i] = data2.data_upper_byte().as_u8(), + 5 => data[i] = data2.data_lower_byte().as_u8(), + 6 => data[i] = data3.data_upper_byte().as_u8(), + 7 => data[i] = data3.data_lower_byte().as_u8(), _ => unreachable!(), }); }; @@ -309,7 +313,7 @@ impl CanChannelLowLevel { } else { let dlc = self.msg_buf.read_stat_ctrl().dlc(); read_data(dlc); - CanFrameNormal::new(id, &data[0..dlc.as_usize()]).into() + CanFrameNormal::new(id, &data[0..dlc.as_usize()]).unwrap().into() } } } diff --git a/va416xx-hal/src/can/mod.rs b/va416xx-hal/src/can/mod.rs index 8395914..5a8921f 100644 --- a/va416xx-hal/src/can/mod.rs +++ b/va416xx-hal/src/can/mod.rs @@ -125,20 +125,16 @@ impl ClockConfig { if bitrate.raw() == 0 { return Err(ClockConfigError::BitrateIsZero); } - let mut prescaler = roundf( - clocks.apb1().raw() as f32 - / (bitrate.raw() as f32 * (1.0 + tseg1.as_u32() as f32 + tseg2.as_u32() as f32)), - ) as u32; - // defmt::info!("calc prescaler: {}", prescaler); + let nominal_bit_time = 1 + tseg1 as u32 + tseg2 as u32; + let prescaler = + roundf(clocks.apb1().raw() as f32 / (bitrate.raw() as f32 * nominal_bit_time as f32)) + as u32; if !(PRESCALER_MIN as u32..=PRESCALER_MAX as u32).contains(&prescaler) { return Err(ClockConfigError::CanNotFindPrescaler); } - let actual_bitrate = (clocks.apb1().raw() as f32) - / (prescaler * (1 + tseg1.as_u32() + tseg2.as_u32())) as f32; - let bitrate_deviation = - ((actual_bitrate as i32 - bitrate.raw() as i32).abs() as f32) / bitrate.raw() as f32; - //defmt::info!("actual bitrate: {}, target {}", actual_bitrate, bitrate); + let actual_bitrate = (clocks.apb1().raw() as f32) / (prescaler * nominal_bit_time) as f32; + let bitrate_deviation = calculate_bitrate_deviation(actual_bitrate, bitrate); if bitrate_deviation > MAX_BITRATE_DEVIATION { return Err(ClockConfigError::BitrateErrorTooLarge); } @@ -392,6 +388,16 @@ impl Can { &mut self.regs } + #[inline] + pub fn read_error_counters(&self) -> regs::ErrorCounter { + self.regs.read_error_counter() + } + + #[inline] + pub fn read_error_diagnostics(&self) -> regs::DiagnosticRegister { + self.regs.read_diag() + } + #[inline] pub fn id(&self) -> CanId { self.id @@ -403,11 +409,11 @@ impl Can { } #[inline] - pub fn set_loopback(&mut self, enable: bool) { - self.regs.modify_control(|mut val| { - val.set_loopback(enable); - val - }); + pub fn modify_control(&mut self, f: F) + where + F: FnOnce(Control) -> Control, + { + self.regs.modify_control(f); } #[inline] @@ -436,10 +442,29 @@ pub enum TxState { AwaitingRemoteFrameReply, } +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum InvalidTxState { + State(TxState), + BufferState(BufferState), +} + +impl From for InvalidTxState { + fn from(state: TxState) -> Self { + InvalidTxState::State(state) + } +} + +impl From for InvalidTxState { + fn from(state: BufferState) -> Self { + InvalidTxState::BufferState(state) + } +} + #[derive(Debug, thiserror::Error)] #[error("invalid tx state {0:?}")] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct InvalidTxStateError(pub TxState); +pub struct InvalidTxStateError(pub InvalidTxState); #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -474,20 +499,25 @@ impl CanTx { self.mode = TxState::Idle; } if self.mode != TxState::Idle { - return Err(InvalidTxStateError(self.mode)); + return Err(InvalidTxStateError(self.mode.into())); } if !frame.is_remote_frame() { self.mode = TxState::TransmittingDataFrame; } else { self.mode = TxState::TransmittingRemoteFrame; } + if let Ok(state) = self.ll.read_state() { + if state != BufferState::TxNotActive { + return Err(InvalidTxStateError(state.into())); + } + } self.ll.transmit_frame_unchecked(frame); Ok(()) } pub fn data_frame_transfer_done(&mut self) -> nb::Result<(), InvalidTxStateError> { if self.mode != TxState::TransmittingDataFrame { - return Err(nb::Error::Other(InvalidTxStateError(self.mode))); + return Err(nb::Error::Other(InvalidTxStateError(self.mode.into()))); } let status = self.ll.read_state(); if status.is_err() { @@ -503,7 +533,7 @@ impl CanTx { pub fn remote_frame_transfer_done(&mut self) -> nb::Result { if self.mode != TxState::TransmittingRemoteFrame { - return Err(nb::Error::Other(InvalidTxStateError(self.mode))); + return Err(nb::Error::Other(InvalidTxStateError(self.mode.into()))); } let status = self.ll.read_state(); if status.is_err() { @@ -570,7 +600,7 @@ impl CanRx { return Err(nb::Error::WouldBlock); } let status = status.unwrap(); - if status == BufferState::RxReady || status == BufferState::RxOverrun { + if status == BufferState::RxFull || status == BufferState::RxOverrun { self.mode = RxState::Idle; if reconfigure_for_reception { self.ll.write_state(BufferState::RxReady); diff --git a/va416xx-hal/src/can/regs.rs b/va416xx-hal/src/can/regs.rs index bf7a35b..5bdc1d9 100644 --- a/va416xx-hal/src/can/regs.rs +++ b/va416xx-hal/src/can/regs.rs @@ -46,7 +46,7 @@ pub struct BufStatusAndControl { #[bits(4..=7, rw)] priority: u4, #[bits(0..=3, rw)] - status: Option, + state: Option, } #[derive(Debug)] @@ -68,10 +68,10 @@ impl Timestamp { #[bitbybit::bitfield(u32, default = 0x0)] #[derive(Debug)] pub struct TwoBytesData { + #[bits(0..=7, rw)] + data_lower_byte: u8, #[bits(8..=15, rw)] data_upper_byte: u8, - #[bits(8..=15, rw)] - data_lower_byte: u8, } #[derive(derive_mmio::Mmio)] @@ -87,14 +87,16 @@ pub struct CanMsgBuf { id1: BaseId, } +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x20); + impl MmioCanMsgBuf<'_> { pub fn reset(&mut self) { self.write_stat_ctrl(BufStatusAndControl::new_with_raw_value(0)); self.write_timestamp(Timestamp::new(0)); - self.write_data3(TwoBytesData::new_with_raw_value(0)); - self.write_data2(TwoBytesData::new_with_raw_value(0)); - self.write_data1(TwoBytesData::new_with_raw_value(0)); self.write_data0(TwoBytesData::new_with_raw_value(0)); + self.write_data1(TwoBytesData::new_with_raw_value(0)); + self.write_data2(TwoBytesData::new_with_raw_value(0)); + self.write_data3(TwoBytesData::new_with_raw_value(0)); self.write_id1(BaseId::new_with_raw_value(0)); self.write_id0(ExtendedId::new_with_raw_value(0)); } @@ -387,6 +389,8 @@ pub struct Can { timer: u32, } +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x238); + impl Can { /// Create a new CAN MMIO instance for peripheral 0. ///