diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 9b6ebf5a4..c508ef2fe 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs @@ -406,7 +406,7 @@ impl Registers { } } } - + pub fn curr_error(&self) -> Option { let err = { self.canregs.esr().read() }; if err.boff() { @@ -585,6 +585,16 @@ impl Registers { }); } + pub fn receive_frame_available(&self) -> bool { + if self.canregs.rfr(0).read().fmp() != 0 { + true + } else if self.canregs.rfr(1).read().fmp() != 0 { + true + } else { + false + } + } + pub fn receive_fifo(&self, fifo: crate::can::_version::bx::RxFifo) -> Option { // Generate timestamp as early as possible #[cfg(feature = "time")] diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index d865bbe7d..66f6e7067 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -10,7 +10,6 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; -use futures::FutureExt; use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; @@ -22,6 +21,9 @@ use enums::*; pub mod frame; pub mod util; +mod common; +pub use self::common::{BufferedCanReceiver, BufferedCanSender, Timestamp}; + /// Contains CAN frame and additional metadata. /// /// Timestamp is available if `time` feature is enabled. @@ -59,8 +61,7 @@ pub struct Rx0InterruptHandler { impl interrupt::typelevel::Handler for Rx0InterruptHandler { unsafe fn on_interrupt() { - // info!("rx0 irq"); - Can::::receive_fifo(RxFifo::Fifo0); + T::state().rx_mode.on_interrupt::(RxFifo::Fifo0); } } @@ -71,8 +72,7 @@ pub struct Rx1InterruptHandler { impl interrupt::typelevel::Handler for Rx1InterruptHandler { unsafe fn on_interrupt() { - // info!("rx1 irq"); - Can::::receive_fifo(RxFifo::Fifo1); + T::state().rx_mode.on_interrupt::(RxFifo::Fifo1); } } @@ -99,16 +99,6 @@ pub struct Can<'d, T: Instance> { can: crate::can::bx::Can>, } -/// Error returned by `try_read` -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum TryReadError { - /// Bus error - BusError(BusError), - /// Receive buffer is empty - Empty, -} - /// Error returned by `try_write` #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -226,34 +216,19 @@ impl<'d, T: Instance> Can<'d, T> { /// /// Returns a tuple of the time the message was received and the message frame pub async fn read(&mut self) -> Result { - self.split().1.read().await + T::state().rx_mode.read::().await } /// Attempts to read a CAN frame without blocking. /// /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. pub fn try_read(&mut self) -> Result { - self.split().1.try_read() + T::state().rx_mode.try_read::() } /// Waits while receive queue is empty. pub async fn wait_not_empty(&mut self) { - self.split().1.wait_not_empty().await - } - - unsafe fn receive_fifo(fifo: RxFifo) { - let state = T::state(); - let regsisters = crate::can::bx::Registers { canregs: T::regs() }; - - loop { - match regsisters.receive_fifo(fifo) { - Some(envelope) => { - // NOTE: consensus was reached that if rx_queue is full, packets should be dropped - let _ = state.rx_queue.try_send(envelope); - } - None => return, - }; - } + T::state().rx_mode.wait_not_empty::().await } /// Split the CAN driver into transmit and receive halves. @@ -375,51 +350,95 @@ impl<'d, T: Instance> CanRx<'d, T> { /// /// Returns a tuple of the time the message was received and the message frame pub async fn read(&mut self) -> Result { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) { - return Poll::Ready(Ok(envelope)); - } else if let Some(err) = self.curr_error() { - return Poll::Ready(Err(err)); - } - - Poll::Pending - }) - .await + T::state().rx_mode.read::().await } /// Attempts to read a CAN frame without blocking. /// /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. pub fn try_read(&mut self) -> Result { - if let Ok(envelope) = T::state().rx_queue.try_receive() { - return Ok(envelope); - } - - if let Some(err) = self.curr_error() { - return Err(TryReadError::BusError(err)); - } - - Err(TryReadError::Empty) + T::state().rx_mode.try_read::() } /// Waits while receive queue is empty. pub async fn wait_not_empty(&mut self) { - poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await + T::state().rx_mode.wait_not_empty::().await } - fn curr_error(&self) -> Option { - let err = { T::regs().esr().read() }; - if err.boff() { - return Some(BusError::BusOff); - } else if err.epvf() { - return Some(BusError::BusPassive); - } else if err.ewgf() { - return Some(BusError::BusWarning); - } else if let Some(err) = err.lec().into_bus_err() { - return Some(err); + /// Return a buffered instance of driver without CAN FD support. User must supply Buffers + pub fn buffered( + self, + rxb: &'static mut RxBuf, + ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { + BufferedCanRx::new(self.rx, rxb) + } +} + +/// User supplied buffer for RX Buffering +pub type RxBuf = + Channel, BUF_SIZE>; + +/// CAN driver, receive half in Buffered mode. +pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { + _rx: crate::can::bx::Rx>, + rx_buf: &'static RxBuf, +} + +impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { + fn new(_rx: crate::can::bx::Rx>, rx_buf: &'static RxBuf) -> Self { + BufferedCanRx { _rx, rx_buf }.setup() + } + + fn setup(self) -> Self { + // We don't want interrupts being processed while we change modes. + critical_section::with(|_| unsafe { + let rx_inner = self::common::ClassicBufferedRxInner { + rx_sender: self.rx_buf.sender().into(), + }; + T::mut_state().rx_mode = RxMode::Buffered(rx_inner); + }); + self + } + + /// Async read frame from RX buffer. + pub async fn read(&mut self) -> Result<(Frame, Timestamp), BusError> { + self.rx_buf.receive().await + } + + /// Attempts to read a CAN frame without blocking. + /// + /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. + pub fn try_read(&mut self) -> Result { + match &T::state().rx_mode { + RxMode::Buffered(_) => { + if let Ok(result) = self.rx_buf.try_receive() { + match result { + Ok((frame, ts)) => Ok(Envelope { ts, frame }), + Err(e) => Err(TryReadError::BusError(e)), + } + } else { + let registers = crate::can::bx::Registers { canregs: T::regs() }; + if let Some(err) = registers.curr_error() { + return Err(TryReadError::BusError(err)); + } else { + Err(TryReadError::Empty) + } + } + } + _ => { + panic!("Bad Mode") + } } - None + } + + /// Waits while receive queue is empty. + pub async fn wait_not_empty(&mut self) { + poll_fn(|cx| self.rx_buf.poll_ready_to_receive(cx)).await + } + + /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. + pub fn reader(&self) -> BufferedCanReceiver { + self.rx_buf.receiver().into() } } @@ -448,10 +467,111 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> { } } +use crate::can::enums::{BusError, TryReadError}; + +pub(crate) enum RxMode { + NonBuffered(AtomicWaker), + Buffered(crate::can::_version::common::ClassicBufferedRxInner), +} + +impl RxMode { + pub fn on_interrupt(&self, fifo: crate::can::_version::bx::RxFifo) { + match self { + Self::NonBuffered(waker) => { + // Disable interrupts until read + let fifo_idx = match fifo { + crate::can::_version::bx::RxFifo::Fifo0 => 0usize, + crate::can::_version::bx::RxFifo::Fifo1 => 1usize, + }; + T::regs().ier().write(|w| { + w.set_fmpie(fifo_idx, false); + }); + waker.wake(); + } + Self::Buffered(buf) => { + let regsisters = crate::can::bx::Registers { canregs: T::regs() }; + + loop { + 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))); + } + None => return, + }; + } + } + } + } + + pub async fn read(&self) -> Result { + match self { + Self::NonBuffered(waker) => { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + waker.register(cx.waker()); + match self.try_read::() { + Ok(result) => Poll::Ready(Ok(result)), + Err(TryReadError::Empty) => Poll::Pending, + Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), + } + }) + .await + } + _ => { + panic!("Bad Mode") + } + } + } + pub fn try_read(&self) -> Result { + match self { + Self::NonBuffered(_) => { + let registers = crate::can::bx::Registers { canregs: T::regs() }; + if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo0) { + T::regs().ier().write(|w| { + w.set_fmpie(0, true); + }); + Ok(msg) + } else if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo1) { + T::regs().ier().write(|w| { + w.set_fmpie(1, true); + }); + Ok(msg) + } else if let Some(err) = registers.curr_error() { + Err(TryReadError::BusError(err)) + } else { + Err(TryReadError::Empty) + } + } + _ => { + panic!("Bad Mode") + } + } + } + pub async fn wait_not_empty(&self) { + match &T::state().rx_mode { + Self::NonBuffered(waker) => { + poll_fn(|cx| { + waker.register(cx.waker()); + let registers = crate::can::bx::Registers { canregs: T::regs() }; + if registers.receive_frame_available() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await + } + _ => { + panic!("Bad Mode") + } + } + } +} struct State { pub tx_waker: AtomicWaker, pub err_waker: AtomicWaker, - pub rx_queue: Channel, + pub(crate) rx_mode: RxMode, } impl State { @@ -459,7 +579,7 @@ impl State { Self { tx_waker: AtomicWaker::new(), err_waker: AtomicWaker::new(), - rx_queue: Channel::new(), + rx_mode: RxMode::NonBuffered(AtomicWaker::new()), } } } @@ -467,6 +587,7 @@ impl State { trait SealedInstance { fn regs() -> crate::pac::can::Can; fn state() -> &'static State; + unsafe fn mut_state() -> &'static mut State; } /// CAN instance trait. @@ -495,9 +616,12 @@ foreach_peripheral!( crate::pac::$inst } + unsafe fn mut_state() -> & 'static mut State { + static mut STATE: State = State::new(); + &mut *core::ptr::addr_of_mut!(STATE) + } fn state() -> &'static State { - static STATE: State = State::new(); - &STATE + unsafe { peripherals::$inst::mut_state() } } } @@ -561,5 +685,3 @@ impl Index for crate::can::bx::Mailbox { } } } - - diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 8c9990798..b0d177a6d 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -18,9 +18,13 @@ pub(crate) struct ClassicBufferedTxInner { pub tx_receiver: DynamicReceiver<'static, ClassicFrame>, } +#[cfg(any(can_fdcan_v1, can_fdcan_h7))] + pub(crate) struct FdBufferedRxInner { pub rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, } + +#[cfg(any(can_fdcan_v1, can_fdcan_h7))] pub(crate) struct FdBufferedTxInner { pub tx_receiver: DynamicReceiver<'static, FdFrame>, } diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 651de9194..4d89c84d1 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs @@ -40,3 +40,13 @@ pub enum FrameCreateError { /// Invalid ID. InvalidCanId, } + +/// Error returned by `try_read` +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TryReadError { + /// Bus error + BusError(BusError), + /// Receive buffer is empty + Empty, +}