added RTR example
This commit is contained in:
parent
37ec9114b3
commit
d661c940fe
@ -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]
|
||||
|
@ -1,7 +1,6 @@
|
||||
use core::{
|
||||
future::Future,
|
||||
sync::atomic::{AtomicU8, Ordering},
|
||||
usize,
|
||||
};
|
||||
|
||||
use crate::can::regs::BufferState;
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user