diff --git a/examples/embassy/src/bin/can.rs b/examples/embassy/src/bin/can.rs index 4234931..30650b0 100644 --- a/examples/embassy/src/bin/can.rs +++ b/examples/embassy/src/bin/can.rs @@ -9,12 +9,17 @@ use defmt_rtt as _; use embassy_example::EXTCLK_FREQ; use embassy_executor::Spawner; use va416xx_hal::can::asynch::on_interrupt_can; -use va416xx_hal::can::{Can, CanFrame, CanFrameNormal, CanId, CanRx, CanTx, ClockConfig}; +use va416xx_hal::can::{ + Can, CanFrame, CanFrameNormal, CanFrameRtr, CanId, CanRx, CanTx, ClockConfig, +}; use va416xx_hal::clock::ClockConfigurator; use va416xx_hal::pac::{self, interrupt}; use va416xx_hal::time::Hertz; use va416xx_hal::{can, prelude::*}; +const STANDARD_ID_0: can::StandardId = can::StandardId::new(0x42).unwrap(); +const STANDARD_ID_1: can::StandardId = can::StandardId::new(0x5).unwrap(); + #[embassy_executor::main] async fn main(_spawner: Spawner) { defmt::println!("-- VA416xx CAN Demo --"); @@ -42,6 +47,7 @@ async fn main(_spawner: Spawner) { val.set_diag_enable(true); val }); + can.set_global_mask_for_exact_id_match_with_rtr_masked(); can.set_base_mask_for_all_match(); can.enable(); let err_counter = can.read_error_counters(); @@ -57,17 +63,72 @@ async fn main(_spawner: Spawner) { 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_data = &[1, 2, 3, 4]; - let send_frame = - CanFrame::Normal(CanFrameNormal::new(can::Id::Standard(standard_id), send_data).unwrap()); - rx_dedicated - .configure_for_reception_with_standard_id(standard_id, false) - .unwrap(); rx_base.configure_for_reception(); - defmt::info!("sending CAN frame with ID 0x42 and data {}", send_data); + + send_and_receive_on_dedicated_channel(&mut can, &mut tx, &mut rx_dedicated); + send_and_receive_rtr_on_dedicated_channel(&mut can, &mut tx, &mut rx_dedicated); + loop { + cortex_m::asm::nop(); + } +} + +fn send_and_receive_on_dedicated_channel(can: &mut Can, tx: &mut CanTx, rx_dedicated: &mut CanRx) { + let send_data = &[1, 2, 3, 4]; + defmt::info!( + "sending CAN frame with ID {:#X} and data {}", + STANDARD_ID_0.as_raw(), + send_data + ); + rx_dedicated.configure_for_reception_with_standard_id(STANDARD_ID_0, false); + let send_frame = + CanFrame::Normal(CanFrameNormal::new(can::Id::Standard(STANDARD_ID_0), send_data).unwrap()); tx.transmit_frame(send_frame).unwrap(); + // Await frame transmission completion. + nb::block!(tx.transfer_done()).unwrap(); + check_and_handle_errors(can); let frame = nb::block!(rx_dedicated.receive(true)).expect("invalid CAN rx state"); + check_and_handle_errors(can); + if let CanFrame::Normal(can_frame_normal) = frame { + if let can::Id::Standard(standard_id) = can_frame_normal.id() { + defmt::info!( + "received CAN frame with ID {:#X} and data {}", + standard_id.as_raw(), + can_frame_normal.data() + ); + } else { + panic!("unexpected CAN extended frame ID"); + } + } else { + defmt::error!("received unexpected CAN remote frame"); + } +} + +fn send_and_receive_rtr_on_dedicated_channel( + can: &mut Can, + tx: &mut CanTx, + rx_dedicated: &mut CanRx, +) { + let rtr_frame = CanFrame::Rtr(CanFrameRtr::new(can::Id::Standard(STANDARD_ID_1), 0)); + // RTR bit is masked, so the setting should not matter. + rx_dedicated.configure_for_reception_with_standard_id(STANDARD_ID_1, false); + tx.transmit_frame(rtr_frame).unwrap(); + // Await frame transmission completion. + nb::block!(tx.remote_transfer_done()).unwrap(); + check_and_handle_errors(can); + let frame = nb::block!(rx_dedicated.receive(true)).expect("invalid CAN rx state"); + check_and_handle_errors(can); + if let CanFrame::Rtr(can_frame_rtr) = frame { + if let can::Id::Standard(standard_id) = can_frame_rtr.id() { + defmt::info!("received CAN RTR frame with ID {:#X}", standard_id.as_raw(),); + } else { + panic!("unexpected CAN extended frame ID"); + } + } else { + defmt::error!("received unexpected CAN data frame"); + } +} + +fn check_and_handle_errors(can: &mut Can) { let err_counter = can.read_error_counters(); if err_counter.transmit() > 0 || err_counter.receive() > 0 { defmt::warn!( @@ -78,24 +139,6 @@ async fn main(_spawner: Spawner) { let diag = can.read_error_diagnostics(); defmt::warn!("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 {:#X} and data {}", - standard_id.as_raw(), - can_frame_normal.data() - ); - } - can::Id::Extended(_) => (), - }, - _ => { - defmt::error!("received unexpected CAN remote frame"); - } - } - loop { - cortex_m::asm::nop(); - } } #[interrupt] diff --git a/va416xx-hal/src/can/asynch.rs b/va416xx-hal/src/can/asynch.rs index ee941de..8207099 100644 --- a/va416xx-hal/src/can/asynch.rs +++ b/va416xx-hal/src/can/asynch.rs @@ -1,7 +1,6 @@ use core::{ future::Future, sync::atomic::{AtomicU8, Ordering}, - usize, }; use crate::can::regs::BufferState; diff --git a/va416xx-hal/src/can/ll.rs b/va416xx-hal/src/can/ll.rs index a048355..c67f864 100644 --- a/va416xx-hal/src/can/ll.rs +++ b/va416xx-hal/src/can/ll.rs @@ -90,10 +90,7 @@ impl CanChannelLowLevel { }); } - pub fn configure_for_transmission( - &mut self, - tx_priority: Option, - ) -> Result<(), InvalidBufferIndexError> { + pub fn configure_for_transmission(&mut self, tx_priority: Option) { self.msg_buf.modify_stat_ctrl(|mut val| { val.set_dlc(u4::new(0)); if let Some(tx_priority) = tx_priority { @@ -102,28 +99,18 @@ impl CanChannelLowLevel { val.set_state(BufferState::TxNotActive); val }); - Ok(()) } - pub fn set_standard_id( - &mut self, - standard_id: embedded_can::StandardId, - set_rtr: bool, - ) -> Result<(), InvalidBufferIndexError> { + pub fn set_standard_id(&mut self, standard_id: embedded_can::StandardId, set_rtr: bool) { let mut id1_reg = standard_id.as_raw() << 5; if set_rtr { id1_reg |= 1 << 4; } self.msg_buf .write_id1(BaseId::new_with_raw_value(id1_reg as u32)); - Ok(()) } - pub fn set_extended_id( - &mut self, - extended_id: embedded_can::ExtendedId, - set_rtr: bool, - ) -> Result<(), InvalidBufferIndexError> { + pub fn set_extended_id(&mut self, extended_id: embedded_can::ExtendedId, set_rtr: bool) { let id_raw = extended_id.as_raw(); let id1_reg = (((id_raw >> 18) & 0x7FF) << 4) as u16 | ((id_raw >> 15) & 0b111) as u16; self.msg_buf @@ -131,7 +118,6 @@ impl CanChannelLowLevel { let id0_reg = ((id_raw & 0x7FFF) << 1) as u16 | set_rtr as u16; self.msg_buf .write_id0(ExtendedId::new_with_raw_value(id0_reg as u32)); - Ok(()) } pub fn configure_for_reception(&mut self) { @@ -313,7 +299,9 @@ impl CanChannelLowLevel { } else { let dlc = self.msg_buf.read_stat_ctrl().dlc(); read_data(dlc); - CanFrameNormal::new(id, &data[0..dlc.as_usize()]).unwrap().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 5a8921f..3d97338 100644 --- a/va416xx-hal/src/can/mod.rs +++ b/va416xx-hal/src/can/mod.rs @@ -486,16 +486,23 @@ pub struct CanTx { impl CanTx { pub fn new(mut ll: CanChannelLowLevel, tx_priority: Option) -> Self { - ll.configure_for_transmission(tx_priority).unwrap(); + ll.configure_for_transmission(tx_priority); Self { ll, mode: TxState::Idle, } } + /// Start transmitting a frame. + /// + /// The frame transmission can be polled/awaited to completion using the [Self::transfer_done] + /// method. + /// + /// This function will return a [state error][InvalidTxStateError] if a transmission is already + /// active and/or the transmit buffer has an invalid state. pub fn transmit_frame(&mut self, frame: CanFrame) -> Result<(), InvalidTxStateError> { if self.mode == TxState::AwaitingRemoteFrameReply { - self.ll.configure_for_transmission(None).unwrap(); + self.ll.configure_for_transmission(None); self.mode = TxState::Idle; } if self.mode != TxState::Idle { @@ -515,7 +522,10 @@ impl CanTx { Ok(()) } - pub fn data_frame_transfer_done(&mut self) -> nb::Result<(), InvalidTxStateError> { + /// Poll whether an active data frame transmission is done. + /// + /// Returns a [state error][InvalidTxStateError] if no transmission is active. + pub fn transfer_done(&mut self) -> nb::Result<(), InvalidTxStateError> { if self.mode != TxState::TransmittingDataFrame { return Err(nb::Error::Other(InvalidTxStateError(self.mode.into()))); } @@ -531,7 +541,10 @@ impl CanTx { Err(nb::Error::WouldBlock) } - pub fn remote_frame_transfer_done(&mut self) -> nb::Result { + /// Poll whether an active remote frame transmission is done. + /// + /// Returns a [state error][InvalidTxStateError] if no transmission is active. + pub fn remote_transfer_done(&mut self) -> nb::Result { if self.mode != TxState::TransmittingRemoteFrame { return Err(nb::Error::Other(InvalidTxStateError(self.mode.into()))); } @@ -549,6 +562,11 @@ impl CanTx { } Err(nb::Error::WouldBlock) } + + pub fn reset(&mut self) { + self.ll.reset(); + self.mode = TxState::Idle; + } } pub struct CanRx { @@ -567,20 +585,18 @@ impl CanRx { &mut self, standard_id: embedded_can::StandardId, set_rtr: bool, - ) -> Result<(), InvalidBufferIndexError> { - self.ll.set_standard_id(standard_id, set_rtr)?; + ) { + self.ll.set_standard_id(standard_id, set_rtr); self.configure_for_reception(); - Ok(()) } pub fn configure_for_reception_with_extended_id( &mut self, extended_id: embedded_can::ExtendedId, set_rtr: bool, - ) -> Result<(), InvalidBufferIndexError> { - self.ll.set_extended_id(extended_id, set_rtr)?; + ) { + self.ll.set_extended_id(extended_id, set_rtr); self.configure_for_reception(); - Ok(()) } pub fn configure_for_reception(&mut self) { @@ -588,6 +604,14 @@ impl CanRx { self.mode = RxState::Receiving; } + #[inline] + pub fn frame_available(&self) -> bool { + self.ll + .read_state() + .is_ok_and(|state| state == BufferState::RxFull || state == BufferState::RxOverrun) + } + + /// Poll for frame reception. Returns the frame if one is available. pub fn receive( &mut self, reconfigure_for_reception: bool,