CAN: Unify API's between BXCAN and FDCAN. Use Envelope for all read methods instead of a tuple sometimes.

This commit is contained in:
Corey Schuhen 2024-03-24 15:13:55 +10:00
parent f5daa50a7b
commit 2217b80278
12 changed files with 294 additions and 151 deletions

View File

@ -40,12 +40,11 @@ pub type Header = crate::can::frame::Header;
/// Data for a CAN Frame
pub type Data = crate::can::frame::ClassicData;
/// CAN Frame
pub type Frame = crate::can::frame::ClassicFrame;
use crate::can::_version::Envelope;
use crate::can::bx::filter::MasterFilters;
use crate::can::enums::BusError;
/// CAN Frame
pub use crate::can::frame::Frame;
use crate::pac::can::vals::Lec;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]

View File

@ -19,22 +19,10 @@ use crate::{interrupt, peripherals, Peripheral};
pub mod enums;
pub mod frame;
pub mod util;
pub use frame::Envelope;
mod common;
pub use self::common::{BufferedCanReceiver, BufferedCanSender, Timestamp};
/// Contains CAN frame and additional metadata.
///
/// Timestamp is available if `time` feature is enabled.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Envelope {
/// Reception time.
#[cfg(feature = "time")]
pub ts: embassy_time::Instant,
/// The actual CAN frame.
pub frame: Frame,
}
pub use self::common::{BufferedCanReceiver, BufferedCanSender};
/// Interrupt handler.
pub struct TxInterruptHandler<T: Instance> {
@ -276,7 +264,7 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<Envelope, BusError> {
self.rx.read().await
}
@ -482,8 +470,7 @@ impl<'d, T: Instance> CanRx<'d, T> {
}
/// User supplied buffer for RX Buffering
pub type RxBuf<const BUF_SIZE: usize> =
Channel<CriticalSectionRawMutex, Result<(Frame, Timestamp), BusError>, BUF_SIZE>;
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
/// CAN driver, receive half in Buffered mode.
pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> {
@ -508,7 +495,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<Envelope, BusError> {
self.rx_buf.receive().await
}
@ -520,7 +507,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
RxMode::Buffered(_) => {
if let Ok(result) = self.rx_buf.try_receive() {
match result {
Ok((frame, ts)) => Ok(Envelope { ts, frame }),
Ok(envelope) => Ok(envelope),
Err(e) => Err(TryReadError::BusError(e)),
}
} else {
@ -610,7 +597,7 @@ impl RxMode {
match regsisters.receive_fifo(fifo) {
Some(envelope) => {
// NOTE: consensus was reached that if rx_queue is full, packets should be dropped
let _ = buf.rx_sender.try_send(Ok((envelope.frame, envelope.ts)));
let _ = buf.rx_sender.try_send(Ok(envelope));
}
None => return,
};

View File

@ -3,25 +3,17 @@ use embassy_sync::channel::{DynamicReceiver, DynamicSender};
use crate::can::_version::enums::*;
use crate::can::_version::frame::*;
/// Timestamp for incoming packets. Use Embassy time when enabled.
#[cfg(feature = "time")]
pub type Timestamp = embassy_time::Instant;
/// Timestamp for incoming packets.
#[cfg(not(feature = "time"))]
pub type Timestamp = u16;
pub(crate) struct ClassicBufferedRxInner {
pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>,
pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>,
}
pub(crate) struct ClassicBufferedTxInner {
pub tx_receiver: DynamicReceiver<'static, ClassicFrame>,
pub tx_receiver: DynamicReceiver<'static, Frame>,
}
#[cfg(any(can_fdcan_v1, can_fdcan_h7))]
pub(crate) struct FdBufferedRxInner {
pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>,
pub rx_sender: DynamicSender<'static, Result<FdEnvelope, BusError>>,
}
#[cfg(any(can_fdcan_v1, can_fdcan_h7))]
@ -32,20 +24,20 @@ pub(crate) struct FdBufferedTxInner {
/// Sender that can be used for sending CAN frames.
#[derive(Copy, Clone)]
pub struct BufferedCanSender {
pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>,
pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>,
pub(crate) waker: fn(),
}
impl BufferedCanSender {
/// Async write frame to TX buffer.
pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError<ClassicFrame>> {
pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError<Frame>> {
self.tx_buf.try_send(frame)?;
(self.waker)();
Ok(())
}
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: ClassicFrame) {
pub async fn write(&mut self, frame: Frame) {
self.tx_buf.send(frame).await;
(self.waker)();
}
@ -57,5 +49,4 @@ impl BufferedCanSender {
}
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
pub type BufferedCanReceiver =
embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>;
pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result<Envelope, BusError>>;

View File

@ -397,13 +397,13 @@ impl Registers {
/// Moves out of ConfigMode and into specified mode
#[inline]
pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) {
pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) {
match mode {
crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true),
crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true),
crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true),
crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
crate::can::OperatingMode::NormalOperationMode => self.set_normal_operations(true),
crate::can::OperatingMode::RestrictedOperationMode => self.set_restricted_operations(true),
crate::can::OperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true),
}
self.leave_init_mode(config);
}

View File

@ -110,7 +110,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Different operating modes
pub enum FdcanOperatingMode {
pub enum OperatingMode {
//PoweredDownMode,
//ConfigMode,
/// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without
@ -148,7 +148,7 @@ pub enum FdcanOperatingMode {
/// FDCAN Configuration instance instance
/// Create instance of this first
pub struct FdcanConfigurator<'d, T: Instance> {
pub struct CanConfigurator<'d, T: Instance> {
config: crate::can::fd::config::FdCanConfig,
/// Reference to internals.
instance: FdcanInstance<'d, T>,
@ -169,7 +169,7 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransm
}
}
impl<'d, T: Instance> FdcanConfigurator<'d, T> {
impl<'d, T: Instance> CanConfigurator<'d, T> {
/// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
/// You must call [Fdcan::enable_non_blocking] to use the peripheral.
pub fn new(
@ -179,7 +179,7 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
_irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
+ interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
+ 'd,
) -> FdcanConfigurator<'d, T> {
) -> CanConfigurator<'d, T> {
into_ref!(peri, rx, tx);
rx.set_as_af(rx.af_num(), AFType::Input);
@ -273,13 +273,13 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
}
/// Start in mode.
pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> {
pub fn start(self, mode: OperatingMode) -> Can<'d, T> {
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
critical_section::with(|_| unsafe {
T::mut_state().ns_per_timer_tick = ns_per_timer_tick;
});
T::registers().into_mode(self.config, mode);
let ret = Fdcan {
let ret = Can {
config: self.config,
instance: self.instance,
_mode: mode,
@ -288,30 +288,30 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
}
/// Start, entering mode. Does same as start(mode)
pub fn into_normal_mode(self) -> Fdcan<'d, T> {
self.start(FdcanOperatingMode::NormalOperationMode)
pub fn into_normal_mode(self) -> Can<'d, T> {
self.start(OperatingMode::NormalOperationMode)
}
/// Start, entering mode. Does same as start(mode)
pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> {
self.start(FdcanOperatingMode::InternalLoopbackMode)
pub fn into_internal_loopback_mode(self) -> Can<'d, T> {
self.start(OperatingMode::InternalLoopbackMode)
}
/// Start, entering mode. Does same as start(mode)
pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> {
self.start(FdcanOperatingMode::ExternalLoopbackMode)
pub fn into_external_loopback_mode(self) -> Can<'d, T> {
self.start(OperatingMode::ExternalLoopbackMode)
}
}
/// FDCAN Instance
pub struct Fdcan<'d, T: Instance> {
pub struct Can<'d, T: Instance> {
config: crate::can::fd::config::FdCanConfig,
/// Reference to internals.
instance: FdcanInstance<'d, T>,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
}
impl<'d, T: Instance> Fdcan<'d, T> {
impl<'d, T: Instance> Can<'d, T> {
/// Flush one of the TX mailboxes.
pub async fn flush(&self, idx: usize) {
poll_fn(|cx| {
@ -334,12 +334,12 @@ impl<'d, T: Instance> Fdcan<'d, T> {
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
T::state().tx_mode.write::<T>(frame).await
}
/// Returns the next received message frame
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<Envelope, BusError> {
T::state().rx_mode.read_classic::<T>().await
}
@ -352,19 +352,19 @@ impl<'d, T: Instance> Fdcan<'d, T> {
}
/// Returns the next received message frame
pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
T::state().rx_mode.read_fd::<T>().await
}
/// Split instance into separate Tx(write) and Rx(read) portions
pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) {
pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) {
(
FdcanTx {
CanTx {
config: self.config,
_instance: self.instance,
_mode: self._mode,
},
FdcanRx {
CanRx {
_instance1: PhantomData::<T>,
_instance2: T::regs(),
_mode: self._mode,
@ -373,8 +373,8 @@ impl<'d, T: Instance> Fdcan<'d, T> {
}
/// Join split rx and tx portions back together
pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self {
Fdcan {
pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self {
Can {
config: tx.config,
//_instance2: T::regs(),
instance: tx._instance,
@ -402,17 +402,16 @@ impl<'d, T: Instance> Fdcan<'d, T> {
}
/// User supplied buffer for RX Buffering
pub type RxBuf<const BUF_SIZE: usize> =
Channel<CriticalSectionRawMutex, Result<(ClassicFrame, Timestamp), BusError>, BUF_SIZE>;
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
/// User supplied buffer for TX buffering
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>;
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
/// Buffered FDCAN Instance
pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
}
@ -423,7 +422,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
fn new(
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
) -> Self {
@ -453,13 +452,13 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
}
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: ClassicFrame) {
pub async fn write(&mut self, frame: Frame) {
self.tx_buf.send(frame).await;
T::IT0Interrupt::pend(); // Wake for Tx
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<Envelope, BusError> {
self.rx_buf.receive().await
}
@ -489,8 +488,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr
}
/// User supplied buffer for RX Buffering
pub type RxFdBuf<const BUF_SIZE: usize> =
Channel<CriticalSectionRawMutex, Result<(FdFrame, Timestamp), BusError>, BUF_SIZE>;
pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>;
/// User supplied buffer for TX buffering
pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
@ -499,7 +497,7 @@ pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFra
pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
}
@ -532,7 +530,7 @@ impl BufferedFdCanSender {
}
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>;
pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>;
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
@ -540,7 +538,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
fn new(
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
) -> Self {
@ -576,7 +574,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<FdEnvelope, BusError> {
self.rx_buf.receive().await
}
@ -606,25 +604,25 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr
}
/// FDCAN Rx only Instance
pub struct FdcanRx<'d, T: Instance> {
pub struct CanRx<'d, T: Instance> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
}
/// FDCAN Tx only Instance
pub struct FdcanTx<'d, T: Instance> {
pub struct CanTx<'d, T: Instance> {
config: crate::can::fd::config::FdCanConfig,
_instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
_mode: FdcanOperatingMode,
_mode: OperatingMode,
}
impl<'c, 'd, T: Instance> FdcanTx<'d, T> {
impl<'c, 'd, T: Instance> CanTx<'d, T> {
/// Queues the message to be sent but exerts backpressure. If a lower-priority
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
T::state().tx_mode.write::<T>(frame).await
}
@ -637,14 +635,14 @@ impl<'c, 'd, T: Instance> FdcanTx<'d, T> {
}
}
impl<'c, 'd, T: Instance> FdcanRx<'d, T> {
impl<'c, 'd, T: Instance> CanRx<'d, T> {
/// Returns the next received message frame
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<Envelope, BusError> {
T::state().rx_mode.read_classic::<T>().await
}
/// Returns the next received message frame
pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
T::state().rx_mode.read_fd::<T>().await
}
}
@ -672,18 +670,50 @@ impl RxMode {
waker.wake();
}
RxMode::ClassicBuffered(buf) => {
if let Some(result) = self.read::<T, _>() {
if let Some(result) = self.try_read::<T>() {
let _ = buf.rx_sender.try_send(result);
}
}
RxMode::FdBuffered(buf) => {
if let Some(result) = self.read::<T, _>() {
if let Some(result) = self.try_read_fd::<T>() {
let _ = buf.rx_sender.try_send(result);
}
}
}
}
//async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
fn try_read<T: Instance>(&self) -> Option<Result<Envelope, BusError>> {
if let Some((frame, ts)) = T::registers().read(0) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
Some(Ok(Envelope { ts, frame }))
} else if let Some((frame, ts)) = T::registers().read(1) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
Some(Ok(Envelope { ts, frame }))
} else if let Some(err) = T::registers().curr_error() {
// TODO: this is probably wrong
Some(Err(err))
} else {
None
}
}
//async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> {
if let Some((frame, ts)) = T::registers().read(0) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
Some(Ok(FdEnvelope { ts, frame }))
} else if let Some((frame, ts)) = T::registers().read(1) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
Some(Ok(FdEnvelope { ts, frame }))
} else if let Some(err) = T::registers().curr_error() {
// TODO: this is probably wrong
Some(Err(err))
} else {
None
}
}
fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> {
if let Some((msg, ts)) = T::registers().read(0) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
@ -711,12 +741,18 @@ impl RxMode {
.await
}
async fn read_classic<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> {
self.read_async::<T, _>().await
async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
match self.read_async::<T, _>().await {
Ok((frame, ts)) => Ok(Envelope { ts, frame }),
Err(e) => Err(e),
}
}
async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> {
self.read_async::<T, _>().await
async fn read_fd<T: Instance>(&self) -> Result<FdEnvelope, BusError> {
match self.read_async::<T, _>().await {
Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
Err(e) => Err(e),
}
}
}
@ -761,7 +797,7 @@ impl TxMode {
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> {
async fn write<T: Instance>(&self, frame: &Frame) -> Option<Frame> {
self.write_generic::<T, _>(frame).await
}

View File

@ -136,19 +136,20 @@ impl ClassicData {
}
}
/// Frame with up to 8 bytes of data payload as per Classic CAN
/// Frame with up to 8 bytes of data payload as per Classic(non-FD) CAN
/// For CAN-FD support use FdFrame
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClassicFrame {
pub struct Frame {
can_header: Header,
data: ClassicData,
}
impl ClassicFrame {
impl Frame {
/// Create a new CAN classic Frame
pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
let data = ClassicData::new(raw_data)?;
Ok(ClassicFrame { can_header, data: data })
Ok(Frame { can_header, data: data })
}
/// Creates a new data frame.
@ -206,9 +207,9 @@ impl ClassicFrame {
}
}
impl embedded_can::Frame for ClassicFrame {
impl embedded_can::Frame for Frame {
fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
match frameopt {
Ok(frame) => Some(frame),
Err(_) => None,
@ -216,7 +217,7 @@ impl embedded_can::Frame for ClassicFrame {
}
fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 {
let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
match frameopt {
Ok(frame) => Some(frame),
Err(_) => None,
@ -245,7 +246,7 @@ impl embedded_can::Frame for ClassicFrame {
}
}
impl CanHeader for ClassicFrame {
impl CanHeader for Frame {
fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
Self::new(header, data)
}
@ -255,10 +256,32 @@ impl CanHeader for ClassicFrame {
}
}
/// Contains CAN frame and additional metadata.
///
/// Timestamp is available if `time` feature is enabled.
/// For CAN-FD support use FdEnvelope
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Envelope {
/// Reception time.
#[cfg(feature = "time")]
pub ts: embassy_time::Instant,
/// The actual CAN frame.
pub frame: Frame,
}
impl Envelope {
/// Convert into a tuple
pub fn parts(self) -> (Frame, embassy_time::Instant) {
(self.frame, self.ts)
}
}
/// Payload of a (FD)CAN data frame.
///
/// Contains 0 to 64 Bytes of data.
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdData {
pub(crate) bytes: [u8; 64],
}
@ -308,6 +331,7 @@ impl FdData {
/// Frame with up to 8 bytes of data payload as per Fd CAN
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdFrame {
can_header: Header,
data: FdData,
@ -410,3 +434,23 @@ impl CanHeader for FdFrame {
self.header()
}
}
/// Contains CAN FD frame and additional metadata.
///
/// Timestamp is available if `time` feature is enabled.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdEnvelope {
/// Reception time.
#[cfg(feature = "time")]
pub ts: embassy_time::Instant,
/// The actual CAN frame.
pub frame: FdFrame,
}
impl FdEnvelope {
/// Convert into a tuple
pub fn parts(self) -> (FdFrame, embassy_time::Instant) {
(self.frame, self.ts)
}
}

View File

@ -23,6 +23,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.8", default-features = false }
nb = "1.0.0"
static_cell = "2.0.0"
[profile.dev]
opt-level = "s"

View File

@ -4,11 +4,12 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::can::{
filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
filter, Can, Envelope, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
TxInterruptHandler,
};
use embassy_stm32::peripherals::CAN;
use embassy_stm32::{bind_interrupts, Config};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@ -21,6 +22,27 @@ bind_interrupts!(struct Irqs {
// This example is configured to work with real CAN transceivers on B8/B9.
// See other examples for loopback.
fn handle_frame(env: Envelope, read_mode: &str) {
match env.frame.id() {
Id::Extended(id) => {
defmt::println!(
"{} Extended Frame id={:x} {:02x}",
read_mode,
id.as_raw(),
env.frame.data()
);
}
Id::Standard(id) => {
defmt::println!(
"{} Standard Frame id={:x} {:02x}",
read_mode,
id.as_raw(),
env.frame.data()
);
}
}
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Config::default());
@ -28,6 +50,9 @@ async fn main(_spawner: Spawner) {
// Set alternate pin mapping to B8/B9
embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2));
static RX_BUF: StaticCell<embassy_stm32::can::RxBuf<10>> = StaticCell::new();
static TX_BUF: StaticCell<embassy_stm32::can::TxBuf<10>> = StaticCell::new();
let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs);
can.as_mut()
@ -43,21 +68,72 @@ async fn main(_spawner: Spawner) {
can.set_bitrate(250_000);
can.enable().await;
let mut i: u8 = 0;
/*
// Example for using buffered Tx and Rx without needing to
// split first as is done below.
let mut can = can.buffered(
TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()),
RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
loop {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
can.write(&tx_frame).await;
match can.read().await {
Ok(env) => match env.frame.id() {
Id::Extended(id) => {
defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
Ok((frame, ts)) => {
handle_frame(Envelope { ts, frame }, "Buf");
}
Id::Standard(id) => {
defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
Err(err) => {
defmt::println!("Error {}", err);
}
}
i += 1;
}
*/
let (mut tx, mut rx) = can.split();
// This example shows using the wait_not_empty API before try read
while i < 3 {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
tx.write(&tx_frame).await;
rx.wait_not_empty().await;
let env = rx.try_read().unwrap();
handle_frame(env, "Wait");
i += 1;
}
// This example shows using the full async non-buffered API
while i < 6 {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
tx.write(&tx_frame).await;
match rx.read().await {
Ok(env) => {
handle_frame(env, "NoBuf");
}
Err(err) => {
defmt::println!("Error {}", err);
}
}
i += 1;
}
// This example shows using buffered RX and TX. User passes in desired buffer (size)
// It's possible this way to have just RX or TX buffered.
let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()));
loop {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
tx.write(&tx_frame).await;
match rx.read().await {
Ok(envelope) => {
handle_frame(envelope, "Buf");
}
},
Err(err) => {
defmt::println!("Error {}", err);
}

View File

@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) {
}
let peripherals = embassy_stm32::init(config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
can.set_extended_filter(
can::filter::ExtendedFilterSlot::_0,
@ -56,21 +56,22 @@ async fn main(_spawner: Spawner) {
info!("Configured");
let mut can = can.start(match use_fd {
true => can::FdcanOperatingMode::InternalLoopbackMode,
false => can::FdcanOperatingMode::NormalOperationMode,
true => can::OperatingMode::InternalLoopbackMode,
false => can::OperatingMode::NormalOperationMode,
});
let mut i = 0;
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -105,7 +106,8 @@ async fn main(_spawner: Spawner) {
}
match can.read_fd().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -129,12 +131,13 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -156,7 +159,7 @@ async fn main(_spawner: Spawner) {
}
}
let can = can::Fdcan::join(tx, rx);
let can = can::Can::join(tx, rx);
info!("\n\n\nBuffered\n");
if use_fd {
@ -173,7 +176,8 @@ async fn main(_spawner: Spawner) {
_ = can.write(frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -198,7 +202,7 @@ async fn main(_spawner: Spawner) {
RX_BUF.init(can::RxBuf::<10>::new()),
);
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
// You can use any of these approaches to send. The writer makes it
@ -208,7 +212,8 @@ async fn main(_spawner: Spawner) {
can.writer().write(frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(

View File

@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
let peripherals = embassy_stm32::init(config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
// 250k bps
can.set_bitrate(250_000);
@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) {
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (rx_frame, ts) = envelope.parts();
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (rx_frame, ts) = envelope.parts();
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(

View File

@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
let peripherals = embassy_stm32::init(config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
// 250k bps
can.set_bitrate(250_000);
@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) {
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (rx_frame, ts) = envelope.parts();
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (rx_frame, ts) = envelope.parts();
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(

View File

@ -79,8 +79,8 @@ async fn main(_spawner: Spawner) {
let options = options();
let peripherals = embassy_stm32::init(options.config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
let mut can2 = can::FdcanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
// 250k bps
can.set_bitrate(250_000);
@ -102,13 +102,13 @@ async fn main(_spawner: Spawner) {
let mut i: u8 = 0;
loop {
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame...");
let tx_ts = Instant::now();
can.write(&tx_frame).await;
let (frame, timestamp) = can.read().await.unwrap();
let (frame, timestamp) = can.read().await.unwrap().parts();
info!("Frame received!");
// Check data.
@ -139,13 +139,13 @@ async fn main(_spawner: Spawner) {
let mut i: u8 = 0;
loop {
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame...");
let tx_ts = Instant::now();
can2.write(&tx_frame).await;
let (frame, timestamp) = can2.read().await.unwrap();
let (frame, timestamp) = can2.read().await.unwrap().parts();
info!("Frame received!");
//print_regs().await;
@ -182,20 +182,20 @@ async fn main(_spawner: Spawner) {
// in each FIFO so make sure we write enough to fill them both up before reading.
for i in 0..3 {
// Try filling up the RX FIFO0 buffers with standard packets
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
can.write(&tx_frame).await;
}
for i in 3..max_buffered {
// Try filling up the RX FIFO0 buffers with extended packets
let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
can.write(&tx_frame).await;
}
// Try and receive all 6 packets
for i in 0..max_buffered {
let (frame, _ts) = can.read().await.unwrap();
let (frame, _ts) = can.read().await.unwrap().parts();
match frame.id() {
embedded_can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
@ -210,20 +210,20 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx) = can.split();
for i in 0..3 {
// Try filling up the RX FIFO0 buffers with standard packets
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
tx.write(&tx_frame).await;
}
for i in 3..max_buffered {
// Try filling up the RX FIFO0 buffers with extended packets
let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
tx.write(&tx_frame).await;
}
// Try and receive all 6 packets
for i in 0..max_buffered {
let (frame, _ts) = rx.read().await.unwrap();
let (frame, _ts) = rx.read().await.unwrap().parts();
match frame.id() {
embedded_can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);