Remove generics for BXCAN.

This commit is contained in:
Corey Schuhen 2024-05-30 21:23:12 +10:00
parent 62f4b4ee1e
commit 245c895d09
3 changed files with 200 additions and 112 deletions

View file

@ -5,6 +5,7 @@ use core::future::poll_fn;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::task::Poll; use core::task::Poll;
use embassy_hal_internal::interrupt::InterruptExt;
use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel; use embassy_sync::channel::Channel;
@ -154,7 +155,10 @@ impl<T: Instance> Drop for CanConfig<'_, T> {
/// CAN driver /// CAN driver
pub struct Can<'d, T: Instance> { pub struct Can<'d, T: Instance> {
peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
instance: &'d crate::pac::can::Can,
info: &'static Info,
state: &'static State,
} }
/// Error returned by `try_write` /// Error returned by `try_write`
@ -179,6 +183,8 @@ impl<'d, T: Instance> Can<'d, T> {
+ 'd, + 'd,
) -> Self { ) -> Self {
into_ref!(peri, rx, tx); into_ref!(peri, rx, tx);
let info = T::info();
let regs = &T::info().regs;
rx.set_as_af(rx.af_num(), AFType::Input); rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull); tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
@ -186,7 +192,7 @@ impl<'d, T: Instance> Can<'d, T> {
T::enable_and_reset(); T::enable_and_reset();
{ {
T::regs().ier().write(|w| { regs.0.ier().write(|w| {
w.set_errie(true); w.set_errie(true);
w.set_fmpie(0, true); w.set_fmpie(0, true);
w.set_fmpie(1, true); w.set_fmpie(1, true);
@ -197,7 +203,7 @@ impl<'d, T: Instance> Can<'d, T> {
w.set_lecie(true); w.set_lecie(true);
}); });
T::regs().mcr().write(|w| { regs.0.mcr().write(|w| {
// Enable timestamps on rx messages // Enable timestamps on rx messages
w.set_ttcm(true); w.set_ttcm(true);
@ -205,17 +211,14 @@ impl<'d, T: Instance> Can<'d, T> {
} }
unsafe { unsafe {
T::TXInterrupt::unpend(); info.tx_interrupt.unpend();
T::TXInterrupt::enable(); info.tx_interrupt.enable();
info.rx0_interrupt.unpend();
T::RX0Interrupt::unpend(); info.rx0_interrupt.enable();
T::RX0Interrupt::enable(); info.rx1_interrupt.unpend();
info.rx1_interrupt.enable();
T::RX1Interrupt::unpend(); info.sce_interrupt.unpend();
T::RX1Interrupt::enable(); info.sce_interrupt.enable();
T::SCEInterrupt::unpend();
T::SCEInterrupt::enable();
} }
rx.set_as_af(rx.af_num(), AFType::Input); rx.set_as_af(rx.af_num(), AFType::Input);
@ -223,7 +226,12 @@ impl<'d, T: Instance> Can<'d, T> {
Registers(T::regs()).leave_init_mode(); Registers(T::regs()).leave_init_mode();
Self { peri } Self {
_peri: peri,
instance: &T::info().regs.0,
info: T::info(),
state: T::state(),
}
} }
/// Set CAN bit rate. /// Set CAN bit rate.
@ -265,12 +273,12 @@ impl<'d, T: Instance> Can<'d, T> {
/// Waking the peripheral manually does not trigger a wake-up interrupt. /// Waking the peripheral manually does not trigger a wake-up interrupt.
/// This will wait until the peripheral has acknowledged it has awoken from sleep mode /// This will wait until the peripheral has acknowledged it has awoken from sleep mode
pub fn wakeup(&mut self) { pub fn wakeup(&mut self) {
Registers(T::regs()).wakeup() self.info.regs.wakeup()
} }
/// Check if the peripheral is currently in sleep mode /// Check if the peripheral is currently in sleep mode
pub fn is_sleeping(&self) -> bool { pub fn is_sleeping(&self) -> bool {
T::regs().msr().read().slak() self.info.regs.0.msr().read().slak()
} }
/// Put the peripheral in sleep mode /// Put the peripheral in sleep mode
@ -282,11 +290,11 @@ impl<'d, T: Instance> Can<'d, T> {
/// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected /// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected
/// the peripheral will automatically wake and receive the incoming message. /// the peripheral will automatically wake and receive the incoming message.
pub async fn sleep(&mut self) { pub async fn sleep(&mut self) {
T::regs().ier().modify(|i| i.set_slkie(true)); self.info.regs.0.ier().modify(|i| i.set_slkie(true));
T::regs().mcr().modify(|m| m.set_sleep(true)); self.info.regs.0.mcr().modify(|m| m.set_sleep(true));
poll_fn(|cx| { poll_fn(|cx| {
T::state().err_waker.register(cx.waker()); self.state.err_waker.register(cx.waker());
if self.is_sleeping() { if self.is_sleeping() {
Poll::Ready(()) Poll::Ready(())
} else { } else {
@ -295,7 +303,7 @@ impl<'d, T: Instance> Can<'d, T> {
}) })
.await; .await;
T::regs().ier().modify(|i| i.set_slkie(false)); self.info.regs.0.ier().modify(|i| i.set_slkie(false));
} }
/// Enable FIFO scheduling of outgoing frames. /// Enable FIFO scheduling of outgoing frames.
@ -337,7 +345,13 @@ impl<'d, T: Instance> Can<'d, T> {
/// Waits for a specific transmit mailbox to become empty /// Waits for a specific transmit mailbox to become empty
pub async fn flush(&self, mb: Mailbox) { pub async fn flush(&self, mb: Mailbox) {
CanTx::<T>::flush_inner(mb).await CanTx {
_instance: &self.instance,
info: self.info,
state: self.state,
}
.flush_inner(mb)
.await;
} }
/// Waits until any of the transmit mailboxes become empty /// Waits until any of the transmit mailboxes become empty
@ -347,12 +361,24 @@ impl<'d, T: Instance> Can<'d, T> {
/// This will happen if FIFO scheduling of outgoing frames is not enabled, /// This will happen if FIFO scheduling of outgoing frames is not enabled,
/// and a frame with equal priority is already queued for transmission. /// and a frame with equal priority is already queued for transmission.
pub async fn flush_any(&self) { pub async fn flush_any(&self) {
CanTx::<T>::flush_any_inner().await CanTx {
_instance: &self.instance,
info: self.info,
state: self.state,
}
.flush_any_inner()
.await
} }
/// Waits until all of the transmit mailboxes become empty /// Waits until all of the transmit mailboxes become empty
pub async fn flush_all(&self) { pub async fn flush_all(&self) {
CanTx::<T>::flush_all_inner().await CanTx {
_instance: &self.instance,
info: self.info,
state: self.state,
}
.flush_all_inner()
.await
} }
/// Attempts to abort the sending of a frame that is pending in a mailbox. /// Attempts to abort the sending of a frame that is pending in a mailbox.
@ -363,12 +389,12 @@ impl<'d, T: Instance> Can<'d, T> {
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
/// returns `true`. /// returns `true`.
pub fn abort(&mut self, mailbox: Mailbox) -> bool { pub fn abort(&mut self, mailbox: Mailbox) -> bool {
Registers(T::regs()).abort(mailbox) self.info.regs.abort(mailbox)
} }
/// Returns `true` if no frame is pending for transmission. /// Returns `true` if no frame is pending for transmission.
pub fn is_transmitter_idle(&self) -> bool { pub fn is_transmitter_idle(&self) -> bool {
Registers(T::regs()).is_idle() self.info.regs.is_idle()
} }
/// Read a CAN frame. /// Read a CAN frame.
@ -377,31 +403,35 @@ impl<'d, T: Instance> Can<'d, T> {
/// ///
/// Returns a tuple of the time the message was received and the message frame /// Returns a tuple of the time the message was received and the message frame
pub async fn read(&mut self) -> Result<Envelope, BusError> { pub async fn read(&mut self) -> Result<Envelope, BusError> {
T::state().rx_mode.read::<T>().await self.state.rx_mode.read(self.info, self.state).await
} }
/// Attempts to read a CAN frame without blocking. /// Attempts to read a CAN frame without blocking.
/// ///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
T::state().rx_mode.try_read::<T>() self.state.rx_mode.try_read(self.info)
} }
/// Waits while receive queue is empty. /// Waits while receive queue is empty.
pub async fn wait_not_empty(&mut self) { pub async fn wait_not_empty(&mut self) {
T::state().rx_mode.wait_not_empty::<T>().await self.state.rx_mode.wait_not_empty(self.info, self.state).await
} }
/// Split the CAN driver into transmit and receive halves. /// Split the CAN driver into transmit and receive halves.
/// ///
/// Useful for doing separate transmit/receive tasks. /// Useful for doing separate transmit/receive tasks.
pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { pub fn split<'c>(&'c mut self) -> (CanTx<'d>, CanRx<'d>) {
( (
CanTx { CanTx {
_peri: unsafe { self.peri.clone_unchecked() }, _instance: &self.instance,
info: self.info,
state: self.state,
}, },
CanRx { CanRx {
peri: unsafe { self.peri.clone_unchecked() }, instance: &self.instance,
info: self.info,
state: self.state,
}, },
) )
} }
@ -411,7 +441,7 @@ impl<'d, T: Instance> Can<'d, T> {
&'c mut self, &'c mut self,
txb: &'static mut TxBuf<TX_BUF_SIZE>, txb: &'static mut TxBuf<TX_BUF_SIZE>,
rxb: &'static mut RxBuf<RX_BUF_SIZE>, rxb: &'static mut RxBuf<RX_BUF_SIZE>,
) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
let (tx, rx) = self.split(); let (tx, rx) = self.split();
BufferedCan { BufferedCan {
tx: tx.buffered(txb), tx: tx.buffered(txb),
@ -426,17 +456,17 @@ impl<'d, T: FilterOwner> Can<'d, T> {
/// To modify filters of a slave peripheral, `modify_filters` has to be called on the master /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
/// peripheral instead. /// peripheral instead.
pub fn modify_filters(&mut self) -> MasterFilters<'_, T> { pub fn modify_filters(&mut self) -> MasterFilters<'_, T> {
unsafe { MasterFilters::new(T::regs()) } unsafe { MasterFilters::new(self.info.regs.0) }
} }
} }
/// Buffered CAN driver. /// Buffered CAN driver.
pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
tx: BufferedCanTx<'d, T, TX_BUF_SIZE>, tx: BufferedCanTx<'d, TX_BUF_SIZE>,
rx: BufferedCanRx<'d, T, RX_BUF_SIZE>, rx: BufferedCanRx<'d, RX_BUF_SIZE>,
} }
impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
/// Async write frame to TX buffer. /// Async write frame to TX buffer.
pub async fn write(&mut self, frame: &Frame) { pub async fn write(&mut self, frame: &Frame) {
self.tx.write(frame).await self.tx.write(frame).await
@ -471,18 +501,20 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer
} }
/// CAN driver, transmit half. /// CAN driver, transmit half.
pub struct CanTx<'d, T: Instance> { pub struct CanTx<'d> {
_peri: PeripheralRef<'d, T>, _instance: &'d crate::pac::can::Can,
info: &'static Info,
state: &'static State,
} }
impl<'d, T: Instance> CanTx<'d, T> { impl<'d> CanTx<'d> {
/// Queues the message to be sent. /// Queues the message to be sent.
/// ///
/// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { pub async fn write(&mut self, frame: &Frame) -> TransmitStatus {
poll_fn(|cx| { poll_fn(|cx| {
T::state().tx_mode.register(cx.waker()); self.state.tx_mode.register(cx.waker());
if let Ok(status) = Registers(T::regs()).transmit(frame) { if let Ok(status) = self.info.regs.transmit(frame) {
return Poll::Ready(status); return Poll::Ready(status);
} }
@ -501,13 +533,13 @@ impl<'d, T: Instance> CanTx<'d, T> {
/// This is done to work around a hardware limitation that could lead to out-of-order delivery /// This is done to work around a hardware limitation that could lead to out-of-order delivery
/// of frames with the same priority. /// of frames with the same priority.
pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> {
Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) self.info.regs.transmit(frame).map_err(|_| TryWriteError::Full)
} }
async fn flush_inner(mb: Mailbox) { async fn flush_inner(&self, mb: Mailbox) {
poll_fn(|cx| { poll_fn(|cx| {
T::state().tx_mode.register(cx.waker()); self.state.tx_mode.register(cx.waker());
if T::regs().tsr().read().tme(mb.index()) { if self.info.regs.0.tsr().read().tme(mb.index()) {
return Poll::Ready(()); return Poll::Ready(());
} }
@ -518,14 +550,14 @@ impl<'d, T: Instance> CanTx<'d, T> {
/// Waits for a specific transmit mailbox to become empty /// Waits for a specific transmit mailbox to become empty
pub async fn flush(&self, mb: Mailbox) { pub async fn flush(&self, mb: Mailbox) {
Self::flush_inner(mb).await self.flush_inner(mb).await
} }
async fn flush_any_inner() { async fn flush_any_inner(&self) {
poll_fn(|cx| { poll_fn(|cx| {
T::state().tx_mode.register(cx.waker()); self.state.tx_mode.register(cx.waker());
let tsr = T::regs().tsr().read(); let tsr = self.info.regs.0.tsr().read();
if tsr.tme(Mailbox::Mailbox0.index()) if tsr.tme(Mailbox::Mailbox0.index())
|| tsr.tme(Mailbox::Mailbox1.index()) || tsr.tme(Mailbox::Mailbox1.index())
|| tsr.tme(Mailbox::Mailbox2.index()) || tsr.tme(Mailbox::Mailbox2.index())
@ -545,14 +577,14 @@ impl<'d, T: Instance> CanTx<'d, T> {
/// This will happen if FIFO scheduling of outgoing frames is not enabled, /// This will happen if FIFO scheduling of outgoing frames is not enabled,
/// and a frame with equal priority is already queued for transmission. /// and a frame with equal priority is already queued for transmission.
pub async fn flush_any(&self) { pub async fn flush_any(&self) {
Self::flush_any_inner().await self.flush_any_inner().await
} }
async fn flush_all_inner() { async fn flush_all_inner(&self) {
poll_fn(|cx| { poll_fn(|cx| {
T::state().tx_mode.register(cx.waker()); self.state.tx_mode.register(cx.waker());
let tsr = T::regs().tsr().read(); let tsr = self.info.regs.0.tsr().read();
if tsr.tme(Mailbox::Mailbox0.index()) if tsr.tme(Mailbox::Mailbox0.index())
&& tsr.tme(Mailbox::Mailbox1.index()) && tsr.tme(Mailbox::Mailbox1.index())
&& tsr.tme(Mailbox::Mailbox2.index()) && tsr.tme(Mailbox::Mailbox2.index())
@ -567,7 +599,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
/// Waits until all of the transmit mailboxes become empty /// Waits until all of the transmit mailboxes become empty
pub async fn flush_all(&self) { pub async fn flush_all(&self) {
Self::flush_all_inner().await self.flush_all_inner().await
} }
/// Attempts to abort the sending of a frame that is pending in a mailbox. /// Attempts to abort the sending of a frame that is pending in a mailbox.
@ -578,20 +610,20 @@ impl<'d, T: Instance> CanTx<'d, T> {
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
/// returns `true`. /// returns `true`.
pub fn abort(&mut self, mailbox: Mailbox) -> bool { pub fn abort(&mut self, mailbox: Mailbox) -> bool {
Registers(T::regs()).abort(mailbox) self.info.regs.abort(mailbox)
} }
/// Returns `true` if no frame is pending for transmission. /// Returns `true` if no frame is pending for transmission.
pub fn is_idle(&self) -> bool { pub fn is_idle(&self) -> bool {
Registers(T::regs()).is_idle() self.info.regs.is_idle()
} }
/// Return a buffered instance of driver. User must supply Buffers /// Return a buffered instance of driver. User must supply Buffers
pub fn buffered<const TX_BUF_SIZE: usize>( pub fn buffered<const TX_BUF_SIZE: usize>(
self, self,
txb: &'static mut TxBuf<TX_BUF_SIZE>, txb: &'static mut TxBuf<TX_BUF_SIZE>,
) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { ) -> BufferedCanTx<'d, TX_BUF_SIZE> {
BufferedCanTx::new(self, txb) BufferedCanTx::new(self.info, self.state, self, txb)
} }
} }
@ -599,23 +631,35 @@ impl<'d, T: Instance> CanTx<'d, T> {
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
/// Buffered CAN driver, transmit half. /// Buffered CAN driver, transmit half.
pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { pub struct BufferedCanTx<'d, const TX_BUF_SIZE: usize> {
_tx: CanTx<'d, T>, info: &'static Info,
state: &'static State,
_tx: CanTx<'d>,
tx_buf: &'static TxBuf<TX_BUF_SIZE>, tx_buf: &'static TxBuf<TX_BUF_SIZE>,
} }
impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> {
fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self { fn new(info: &'static Info, state: &'static State, _tx: CanTx<'d>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
Self { _tx, tx_buf }.setup() Self {
info,
state,
_tx,
tx_buf,
}
.setup()
} }
fn setup(self) -> Self { fn setup(self) -> Self {
// We don't want interrupts being processed while we change modes. // We don't want interrupts being processed while we change modes.
critical_section::with(|_| unsafe { critical_section::with(|_| {
let tx_inner = super::common::ClassicBufferedTxInner { let tx_inner = super::common::ClassicBufferedTxInner {
tx_receiver: self.tx_buf.receiver().into(), tx_receiver: self.tx_buf.receiver().into(),
}; };
T::mut_state().tx_mode = TxMode::Buffered(tx_inner); let state = self.state as *const State;
unsafe {
let mut_state = state as *mut State;
(*mut_state).tx_mode = TxMode::Buffered(tx_inner);
}
}); });
self self
} }
@ -623,60 +667,67 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE
/// Async write frame to TX buffer. /// Async write frame to TX buffer.
pub async fn write(&mut self, frame: &Frame) { pub async fn write(&mut self, frame: &Frame) {
self.tx_buf.send(*frame).await; self.tx_buf.send(*frame).await;
T::TXInterrupt::pend(); // Wake for Tx let waker = self.info.tx_waker;
waker(); // Wake for Tx
} }
/// Returns a sender that can be used for sending CAN frames. /// Returns a sender that can be used for sending CAN frames.
pub fn writer(&self) -> BufferedCanSender { pub fn writer(&self) -> BufferedCanSender {
BufferedCanSender { BufferedCanSender {
tx_buf: self.tx_buf.sender().into(), tx_buf: self.tx_buf.sender().into(),
waker: T::TXInterrupt::pend, waker: self.info.tx_waker,
} }
} }
} }
impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> {
fn drop(&mut self) { fn drop(&mut self) {
critical_section::with(|_| unsafe { critical_section::with(|_| {
T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); let state = self.state as *const State;
unsafe {
let mut_state = state as *mut State;
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
}
}); });
} }
} }
/// CAN driver, receive half. /// CAN driver, receive half.
#[allow(dead_code)] #[allow(dead_code)]
pub struct CanRx<'d, T: Instance> { pub struct CanRx<'d> {
peri: PeripheralRef<'d, T>, instance: &'d crate::pac::can::Can,
info: &'static Info,
state: &'static State,
} }
impl<'d, T: Instance> CanRx<'d, T> { impl<'d> CanRx<'d> {
/// Read a CAN frame. /// Read a CAN frame.
/// ///
/// If no CAN frame is in the RX buffer, this will wait until there is one. /// If no CAN frame is in the RX buffer, this will wait until there is one.
/// ///
/// Returns a tuple of the time the message was received and the message frame /// Returns a tuple of the time the message was received and the message frame
pub async fn read(&mut self) -> Result<Envelope, BusError> { pub async fn read(&mut self) -> Result<Envelope, BusError> {
T::state().rx_mode.read::<T>().await self.state.rx_mode.read(self.info, self.state).await
} }
/// Attempts to read a CAN frame without blocking. /// Attempts to read a CAN frame without blocking.
/// ///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
T::state().rx_mode.try_read::<T>() self.state.rx_mode.try_read(self.info)
} }
/// Waits while receive queue is empty. /// Waits while receive queue is empty.
pub async fn wait_not_empty(&mut self) { pub async fn wait_not_empty(&mut self) {
T::state().rx_mode.wait_not_empty::<T>().await self.state.rx_mode.wait_not_empty(self.info, self.state).await
} }
/// Return a buffered instance of driver. User must supply Buffers /// Return a buffered instance of driver. User must supply Buffers
pub fn buffered<const RX_BUF_SIZE: usize>( pub fn buffered<const RX_BUF_SIZE: usize>(
self, self,
rxb: &'static mut RxBuf<RX_BUF_SIZE>, rxb: &'static mut RxBuf<RX_BUF_SIZE>,
) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { ) -> BufferedCanRx<'d, RX_BUF_SIZE> {
BufferedCanRx::new(self, rxb) BufferedCanRx::new(self.info, self.state, self, rxb)
} }
} }
@ -684,23 +735,35 @@ impl<'d, T: Instance> CanRx<'d, T> {
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>; pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
/// CAN driver, receive half in Buffered mode. /// CAN driver, receive half in Buffered mode.
pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> {
_rx: CanRx<'d, T>, info: &'static Info,
state: &'static State,
_rx: CanRx<'d>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>, rx_buf: &'static RxBuf<RX_BUF_SIZE>,
} }
impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
fn new(_rx: CanRx<'d, T>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self { fn new(info: &'static Info, state: &'static State, _rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
BufferedCanRx { _rx, rx_buf }.setup() BufferedCanRx {
info,
state,
_rx,
rx_buf,
}
.setup()
} }
fn setup(self) -> Self { fn setup(self) -> Self {
// We don't want interrupts being processed while we change modes. // We don't want interrupts being processed while we change modes.
critical_section::with(|_| unsafe { critical_section::with(|_| {
let rx_inner = super::common::ClassicBufferedRxInner { let rx_inner = super::common::ClassicBufferedRxInner {
rx_sender: self.rx_buf.sender().into(), rx_sender: self.rx_buf.sender().into(),
}; };
T::mut_state().rx_mode = RxMode::Buffered(rx_inner); let state = self.state as *const State;
unsafe {
let mut_state = state as *mut State;
(*mut_state).rx_mode = RxMode::Buffered(rx_inner);
}
}); });
self self
} }
@ -714,7 +777,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
/// ///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
match &T::state().rx_mode { match &self.state.rx_mode {
RxMode::Buffered(_) => { RxMode::Buffered(_) => {
if let Ok(result) = self.rx_buf.try_receive() { if let Ok(result) = self.rx_buf.try_receive() {
match result { match result {
@ -722,7 +785,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
Err(e) => Err(TryReadError::BusError(e)), Err(e) => Err(TryReadError::BusError(e)),
} }
} else { } else {
if let Some(err) = Registers(T::regs()).curr_error() { if let Some(err) = self.info.regs.curr_error() {
return Err(TryReadError::BusError(err)); return Err(TryReadError::BusError(err));
} else { } else {
Err(TryReadError::Empty) Err(TryReadError::Empty)
@ -746,10 +809,14 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
} }
} }
impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> {
fn drop(&mut self) { fn drop(&mut self) {
critical_section::with(|_| unsafe { critical_section::with(|_| {
T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); let state = self.state as *const State;
unsafe {
let mut_state = state as *mut State;
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
}
}); });
} }
} }
@ -839,13 +906,13 @@ impl RxMode {
} }
} }
pub async fn read<T: Instance>(&self) -> Result<Envelope, BusError> { pub(crate) async fn read(&self, info: &Info, state: &State) -> Result<Envelope, BusError> {
match self { match self {
Self::NonBuffered(waker) => { Self::NonBuffered(waker) => {
poll_fn(|cx| { poll_fn(|cx| {
T::state().err_waker.register(cx.waker()); state.err_waker.register(cx.waker());
waker.register(cx.waker()); waker.register(cx.waker());
match self.try_read::<T>() { match self.try_read(info) {
Ok(result) => Poll::Ready(Ok(result)), Ok(result) => Poll::Ready(Ok(result)),
Err(TryReadError::Empty) => Poll::Pending, Err(TryReadError::Empty) => Poll::Pending,
Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)),
@ -858,17 +925,17 @@ impl RxMode {
} }
} }
} }
pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> { pub(crate) fn try_read(&self, info: &Info) -> Result<Envelope, TryReadError> {
match self { match self {
Self::NonBuffered(_) => { Self::NonBuffered(_) => {
let registers = Registers(T::regs()); let registers = &info.regs;
if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) {
T::regs().ier().write(|w| { registers.0.ier().write(|w| {
w.set_fmpie(0, true); w.set_fmpie(0, true);
}); });
Ok(msg) Ok(msg)
} else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) { } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) {
T::regs().ier().write(|w| { registers.0.ier().write(|w| {
w.set_fmpie(1, true); w.set_fmpie(1, true);
}); });
Ok(msg) Ok(msg)
@ -883,12 +950,12 @@ impl RxMode {
} }
} }
} }
pub async fn wait_not_empty<T: Instance>(&self) { pub(crate) async fn wait_not_empty(&self, info: &Info, state: &State) {
match &T::state().rx_mode { match &state.rx_mode {
Self::NonBuffered(waker) => { Self::NonBuffered(waker) => {
poll_fn(|cx| { poll_fn(|cx| {
waker.register(cx.waker()); waker.register(cx.waker());
if Registers(T::regs()).receive_frame_available() { if info.regs.receive_frame_available() {
Poll::Ready(()) Poll::Ready(())
} else { } else {
Poll::Pending Poll::Pending
@ -903,7 +970,7 @@ impl RxMode {
} }
} }
enum TxMode { pub(crate) enum TxMode {
NonBuffered(AtomicWaker), NonBuffered(AtomicWaker),
Buffered(super::common::ClassicBufferedTxInner), Buffered(super::common::ClassicBufferedTxInner),
} }
@ -943,7 +1010,7 @@ impl TxMode {
} }
} }
struct State { pub(crate) struct State {
pub(crate) rx_mode: RxMode, pub(crate) rx_mode: RxMode,
pub(crate) tx_mode: TxMode, pub(crate) tx_mode: TxMode,
pub err_waker: AtomicWaker, pub err_waker: AtomicWaker,
@ -959,7 +1026,17 @@ impl State {
} }
} }
pub(crate) struct Info {
regs: Registers,
tx_interrupt: crate::interrupt::Interrupt,
rx0_interrupt: crate::interrupt::Interrupt,
rx1_interrupt: crate::interrupt::Interrupt,
sce_interrupt: crate::interrupt::Interrupt,
tx_waker: fn(),
}
trait SealedInstance { trait SealedInstance {
fn info() -> &'static Info;
fn regs() -> crate::pac::can::Can; fn regs() -> crate::pac::can::Can;
fn state() -> &'static State; fn state() -> &'static State;
unsafe fn mut_state() -> &'static mut State; unsafe fn mut_state() -> &'static mut State;
@ -1012,6 +1089,17 @@ foreach_peripheral!(
(can, $inst:ident) => { (can, $inst:ident) => {
impl SealedInstance for peripherals::$inst { impl SealedInstance for peripherals::$inst {
fn info() -> &'static Info {
static INFO: Info = Info {
regs: Registers(crate::pac::$inst),
tx_interrupt: crate::_generated::peripheral_interrupts::$inst::TX::IRQ,
rx0_interrupt: crate::_generated::peripheral_interrupts::$inst::RX0::IRQ,
rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ,
sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ,
tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend,
};
&INFO
}
fn regs() -> crate::pac::can::Can { fn regs() -> crate::pac::can::Can {
crate::pac::$inst crate::pac::$inst
} }

View file

@ -131,7 +131,7 @@ impl Registers {
/// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN
/// frame will cause that interrupt. /// frame will cause that interrupt.
#[allow(dead_code)] #[allow(dead_code)]
pub fn wakeup(&mut self) { pub fn wakeup(&self) {
self.0.mcr().modify(|reg| { self.0.mcr().modify(|reg| {
reg.set_sleep(false); reg.set_sleep(false);
reg.set_inrq(false); reg.set_inrq(false);
@ -216,7 +216,7 @@ impl Registers {
/// If FIFO scheduling is enabled, frames are transmitted in the order that they are passed to this function. /// If FIFO scheduling is enabled, frames are transmitted in the order that they are passed to this function.
/// ///
/// If all transmit mailboxes are full, this function returns [`nb::Error::WouldBlock`]. /// If all transmit mailboxes are full, this function returns [`nb::Error::WouldBlock`].
pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { pub fn transmit(&self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
// Check if FIFO scheduling is enabled. // Check if FIFO scheduling is enabled.
let fifo_scheduling = self.0.mcr().read().txfp(); let fifo_scheduling = self.0.mcr().read().txfp();
@ -292,7 +292,7 @@ impl Registers {
Ok(()) Ok(())
} }
fn write_mailbox(&mut self, idx: usize, frame: &Frame) { fn write_mailbox(&self, idx: usize, frame: &Frame) {
debug_assert!(idx < 3); debug_assert!(idx < 3);
let mb = self.0.tx(idx); let mb = self.0.tx(idx);
@ -309,7 +309,7 @@ impl Registers {
}); });
} }
fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> { fn read_pending_mailbox(&self, idx: usize) -> Option<Frame> {
if self.abort_by_index(idx) { if self.abort_by_index(idx) {
debug_assert!(idx < 3); debug_assert!(idx < 3);
@ -332,7 +332,7 @@ impl Registers {
} }
/// Tries to abort a pending frame. Returns `true` when aborted. /// Tries to abort a pending frame. Returns `true` when aborted.
fn abort_by_index(&mut self, idx: usize) -> bool { fn abort_by_index(&self, idx: usize) -> bool {
self.0.tsr().write(|reg| reg.set_abrq(idx, true)); self.0.tsr().write(|reg| reg.set_abrq(idx, true));
// Wait for the abort request to be finished. // Wait for the abort request to be finished.
@ -351,7 +351,7 @@ impl Registers {
/// ///
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
/// returns `true`. /// returns `true`.
pub fn abort(&mut self, mailbox: Mailbox) -> bool { pub fn abort(&self, mailbox: Mailbox) -> bool {
// If the mailbox is empty, the value of TXOKx depends on what happened with the previous // If the mailbox is empty, the value of TXOKx depends on what happened with the previous
// frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty.
let tsr = self.0.tsr().read(); let tsr = self.0.tsr().read();

View file

@ -19,8 +19,8 @@ mod can_common;
use can_common::*; use can_common::*;
type Can<'d> = embassy_stm32::can::Can<'d, embassy_stm32::peripherals::CAN1>; type Can<'d> = embassy_stm32::can::Can<'d, embassy_stm32::peripherals::CAN1>;
type CanTx<'d> = embassy_stm32::can::CanTx<'d, embassy_stm32::peripherals::CAN1>; type CanTx<'d> = embassy_stm32::can::CanTx<'d>;
type CanRx<'d> = embassy_stm32::can::CanRx<'d, embassy_stm32::peripherals::CAN1>; type CanRx<'d> = embassy_stm32::can::CanRx<'d>;
bind_interrupts!(struct Irqs { bind_interrupts!(struct Irqs {
CAN1_RX0 => Rx0InterruptHandler<CAN1>; CAN1_RX0 => Rx0InterruptHandler<CAN1>;