added RTR example

This commit is contained in:
Robin Müller 2025-05-13 14:45:49 +02:00
parent 37ec9114b3
commit d661c940fe
Signed by: muellerr
GPG Key ID: A649FB78196E3849
4 changed files with 110 additions and 56 deletions

View File

@ -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]

View File

@ -1,7 +1,6 @@
use core::{
future::Future,
sync::atomic::{AtomicU8, Ordering},
usize,
};
use crate::can::regs::BufferState;

View File

@ -90,10 +90,7 @@ impl CanChannelLowLevel {
});
}
pub fn configure_for_transmission(
&mut self,
tx_priority: Option<u4>,
) -> Result<(), InvalidBufferIndexError> {
pub fn configure_for_transmission(&mut self, tx_priority: Option<u4>) {
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()
}
}
}

View File

@ -486,16 +486,23 @@ pub struct CanTx {
impl CanTx {
pub fn new(mut ll: CanChannelLowLevel, tx_priority: Option<u4>) -> 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<CanRx, InvalidTxStateError> {
/// 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<CanRx, InvalidTxStateError> {
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,