From 245c895d090b93582e23fc1573b244bdc5087d72 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 30 May 2024 21:23:12 +1000 Subject: [PATCH 1/3] Remove generics for BXCAN. --- embassy-stm32/src/can/bxcan/mod.rs | 296 +++++++++++++++-------- embassy-stm32/src/can/bxcan/registers.rs | 12 +- tests/stm32/src/bin/can.rs | 4 +- 3 files changed, 200 insertions(+), 112 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 0ac4cdab6..4f516c917 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -5,6 +5,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; +use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; @@ -154,7 +155,10 @@ impl Drop for CanConfig<'_, T> { /// CAN driver 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` @@ -179,6 +183,8 @@ impl<'d, T: Instance> Can<'d, T> { + 'd, ) -> Self { into_ref!(peri, rx, tx); + let info = T::info(); + let regs = &T::info().regs; rx.set_as_af(rx.af_num(), AFType::Input); 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::regs().ier().write(|w| { + regs.0.ier().write(|w| { w.set_errie(true); w.set_fmpie(0, true); w.set_fmpie(1, true); @@ -197,7 +203,7 @@ impl<'d, T: Instance> Can<'d, T> { w.set_lecie(true); }); - T::regs().mcr().write(|w| { + regs.0.mcr().write(|w| { // Enable timestamps on rx messages w.set_ttcm(true); @@ -205,17 +211,14 @@ impl<'d, T: Instance> Can<'d, T> { } unsafe { - T::TXInterrupt::unpend(); - T::TXInterrupt::enable(); - - T::RX0Interrupt::unpend(); - T::RX0Interrupt::enable(); - - T::RX1Interrupt::unpend(); - T::RX1Interrupt::enable(); - - T::SCEInterrupt::unpend(); - T::SCEInterrupt::enable(); + info.tx_interrupt.unpend(); + info.tx_interrupt.enable(); + info.rx0_interrupt.unpend(); + info.rx0_interrupt.enable(); + info.rx1_interrupt.unpend(); + info.rx1_interrupt.enable(); + info.sce_interrupt.unpend(); + info.sce_interrupt.enable(); } 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(); - Self { peri } + Self { + _peri: peri, + instance: &T::info().regs.0, + info: T::info(), + state: T::state(), + } } /// 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. /// This will wait until the peripheral has acknowledged it has awoken from sleep mode pub fn wakeup(&mut self) { - Registers(T::regs()).wakeup() + self.info.regs.wakeup() } /// Check if the peripheral is currently in sleep mode pub fn is_sleeping(&self) -> bool { - T::regs().msr().read().slak() + self.info.regs.0.msr().read().slak() } /// 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 /// the peripheral will automatically wake and receive the incoming message. pub async fn sleep(&mut self) { - T::regs().ier().modify(|i| i.set_slkie(true)); - T::regs().mcr().modify(|m| m.set_sleep(true)); + self.info.regs.0.ier().modify(|i| i.set_slkie(true)); + self.info.regs.0.mcr().modify(|m| m.set_sleep(true)); poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); + self.state.err_waker.register(cx.waker()); if self.is_sleeping() { Poll::Ready(()) } else { @@ -295,7 +303,7 @@ impl<'d, T: Instance> Can<'d, T> { }) .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. @@ -337,7 +345,13 @@ impl<'d, T: Instance> Can<'d, T> { /// Waits for a specific transmit mailbox to become empty pub async fn flush(&self, mb: Mailbox) { - CanTx::::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 @@ -347,12 +361,24 @@ impl<'d, T: Instance> Can<'d, T> { /// This will happen if FIFO scheduling of outgoing frames is not enabled, /// and a frame with equal priority is already queued for transmission. pub async fn flush_any(&self) { - CanTx::::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 pub async fn flush_all(&self) { - CanTx::::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. @@ -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 /// returns `true`. 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. pub fn is_transmitter_idle(&self) -> bool { - Registers(T::regs()).is_idle() + self.info.regs.is_idle() } /// 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 pub async fn read(&mut self) -> Result { - T::state().rx_mode.read::().await + self.state.rx_mode.read(self.info, self.state).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 { - T::state().rx_mode.try_read::() + self.state.rx_mode.try_read(self.info) } /// Waits while receive queue is empty. pub async fn wait_not_empty(&mut self) { - T::state().rx_mode.wait_not_empty::().await + self.state.rx_mode.wait_not_empty(self.info, self.state).await } /// Split the CAN driver into transmit and receive halves. /// /// 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 { - _peri: unsafe { self.peri.clone_unchecked() }, + _instance: &self.instance, + info: self.info, + state: self.state, }, 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, txb: &'static mut TxBuf, rxb: &'static mut RxBuf, - ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { + ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { let (tx, rx) = self.split(); BufferedCan { 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 /// peripheral instead. pub fn modify_filters(&mut self) -> MasterFilters<'_, T> { - unsafe { MasterFilters::new(T::regs()) } + unsafe { MasterFilters::new(self.info.regs.0) } } } /// Buffered CAN driver. -pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { - tx: BufferedCanTx<'d, T, TX_BUF_SIZE>, - rx: BufferedCanRx<'d, T, RX_BUF_SIZE>, +pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { + tx: BufferedCanTx<'d, TX_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. pub async fn write(&mut self, frame: &Frame) { 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. -pub struct CanTx<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, +pub struct CanTx<'d> { + _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. /// /// 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 { poll_fn(|cx| { - T::state().tx_mode.register(cx.waker()); - if let Ok(status) = Registers(T::regs()).transmit(frame) { + self.state.tx_mode.register(cx.waker()); + if let Ok(status) = self.info.regs.transmit(frame) { 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 /// of frames with the same priority. pub fn try_write(&mut self, frame: &Frame) -> Result { - 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| { - T::state().tx_mode.register(cx.waker()); - if T::regs().tsr().read().tme(mb.index()) { + self.state.tx_mode.register(cx.waker()); + if self.info.regs.0.tsr().read().tme(mb.index()) { return Poll::Ready(()); } @@ -518,14 +550,14 @@ impl<'d, T: Instance> CanTx<'d, T> { /// Waits for a specific transmit mailbox to become empty 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| { - 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()) || tsr.tme(Mailbox::Mailbox1.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, /// and a frame with equal priority is already queued for transmission. 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| { - 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()) && tsr.tme(Mailbox::Mailbox1.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 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. @@ -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 /// returns `true`. 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. 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 pub fn buffered( self, txb: &'static mut TxBuf, - ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { - BufferedCanTx::new(self, txb) + ) -> BufferedCanTx<'d, TX_BUF_SIZE> { + BufferedCanTx::new(self.info, self.state, self, txb) } } @@ -599,23 +631,35 @@ impl<'d, T: Instance> CanTx<'d, T> { pub type TxBuf = Channel; /// Buffered CAN driver, transmit half. -pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { - _tx: CanTx<'d, T>, +pub struct BufferedCanTx<'d, const TX_BUF_SIZE: usize> { + info: &'static Info, + state: &'static State, + _tx: CanTx<'d>, tx_buf: &'static TxBuf, } -impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { - fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf) -> Self { - Self { _tx, tx_buf }.setup() +impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> { + fn new(info: &'static Info, state: &'static State, _tx: CanTx<'d>, tx_buf: &'static TxBuf) -> Self { + Self { + info, + state, + _tx, + tx_buf, + } + .setup() } fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. - critical_section::with(|_| unsafe { + critical_section::with(|_| { let tx_inner = super::common::ClassicBufferedTxInner { 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 } @@ -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. pub async fn write(&mut self, frame: &Frame) { 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. pub fn writer(&self) -> BufferedCanSender { BufferedCanSender { 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) { - critical_section::with(|_| unsafe { - T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + critical_section::with(|_| { + 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. #[allow(dead_code)] -pub struct CanRx<'d, T: Instance> { - peri: PeripheralRef<'d, T>, +pub struct CanRx<'d> { + 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. /// /// 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 pub async fn read(&mut self) -> Result { - T::state().rx_mode.read::().await + self.state.rx_mode.read(self.info, self.state).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 { - T::state().rx_mode.try_read::() + self.state.rx_mode.try_read(self.info) } /// Waits while receive queue is empty. pub async fn wait_not_empty(&mut self) { - T::state().rx_mode.wait_not_empty::().await + self.state.rx_mode.wait_not_empty(self.info, self.state).await } /// Return a buffered instance of driver. User must supply Buffers pub fn buffered( self, rxb: &'static mut RxBuf, - ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { - BufferedCanRx::new(self, rxb) + ) -> BufferedCanRx<'d, RX_BUF_SIZE> { + BufferedCanRx::new(self.info, self.state, self, rxb) } } @@ -684,23 +735,35 @@ impl<'d, T: Instance> CanRx<'d, T> { 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: CanRx<'d, T>, +pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> { + info: &'static Info, + state: &'static State, + _rx: CanRx<'d>, rx_buf: &'static RxBuf, } -impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { - fn new(_rx: CanRx<'d, T>, rx_buf: &'static RxBuf) -> Self { - BufferedCanRx { _rx, rx_buf }.setup() +impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { + fn new(info: &'static Info, state: &'static State, _rx: CanRx<'d>, rx_buf: &'static RxBuf) -> Self { + BufferedCanRx { + info, + state, + _rx, + rx_buf, + } + .setup() } fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. - critical_section::with(|_| unsafe { + critical_section::with(|_| { let rx_inner = super::common::ClassicBufferedRxInner { 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 } @@ -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. pub fn try_read(&mut self) -> Result { - match &T::state().rx_mode { + match &self.state.rx_mode { RxMode::Buffered(_) => { if let Ok(result) = self.rx_buf.try_receive() { 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)), } } else { - if let Some(err) = Registers(T::regs()).curr_error() { + if let Some(err) = self.info.regs.curr_error() { return Err(TryReadError::BusError(err)); } else { 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) { - critical_section::with(|_| unsafe { - T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + critical_section::with(|_| { + 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(&self) -> Result { + pub(crate) async fn read(&self, info: &Info, state: &State) -> Result { match self { Self::NonBuffered(waker) => { poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); + state.err_waker.register(cx.waker()); waker.register(cx.waker()); - match self.try_read::() { + match self.try_read(info) { Ok(result) => Poll::Ready(Ok(result)), Err(TryReadError::Empty) => Poll::Pending, Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), @@ -858,17 +925,17 @@ impl RxMode { } } } - pub fn try_read(&self) -> Result { + pub(crate) fn try_read(&self, info: &Info) -> Result { match self { Self::NonBuffered(_) => { - let registers = Registers(T::regs()); + let registers = &info.regs; if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { - T::regs().ier().write(|w| { + registers.0.ier().write(|w| { w.set_fmpie(0, true); }); Ok(msg) } 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); }); Ok(msg) @@ -883,12 +950,12 @@ impl RxMode { } } } - pub async fn wait_not_empty(&self) { - match &T::state().rx_mode { + pub(crate) async fn wait_not_empty(&self, info: &Info, state: &State) { + match &state.rx_mode { Self::NonBuffered(waker) => { poll_fn(|cx| { waker.register(cx.waker()); - if Registers(T::regs()).receive_frame_available() { + if info.regs.receive_frame_available() { Poll::Ready(()) } else { Poll::Pending @@ -903,7 +970,7 @@ impl RxMode { } } -enum TxMode { +pub(crate) enum TxMode { NonBuffered(AtomicWaker), Buffered(super::common::ClassicBufferedTxInner), } @@ -943,7 +1010,7 @@ impl TxMode { } } -struct State { +pub(crate) struct State { pub(crate) rx_mode: RxMode, pub(crate) tx_mode: TxMode, 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 { + fn info() -> &'static Info; fn regs() -> crate::pac::can::Can; fn state() -> &'static State; unsafe fn mut_state() -> &'static mut State; @@ -1012,6 +1089,17 @@ foreach_peripheral!( (can, $inst:ident) => { 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 { crate::pac::$inst } diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs index ad27e0744..e7c7525d8 100644 --- a/embassy-stm32/src/can/bxcan/registers.rs +++ b/embassy-stm32/src/can/bxcan/registers.rs @@ -131,7 +131,7 @@ impl Registers { /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN /// frame will cause that interrupt. #[allow(dead_code)] - pub fn wakeup(&mut self) { + pub fn wakeup(&self) { self.0.mcr().modify(|reg| { reg.set_sleep(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 all transmit mailboxes are full, this function returns [`nb::Error::WouldBlock`]. - pub fn transmit(&mut self, frame: &Frame) -> nb::Result { + pub fn transmit(&self, frame: &Frame) -> nb::Result { // Check if FIFO scheduling is enabled. let fifo_scheduling = self.0.mcr().read().txfp(); @@ -292,7 +292,7 @@ impl Registers { Ok(()) } - fn write_mailbox(&mut self, idx: usize, frame: &Frame) { + fn write_mailbox(&self, idx: usize, frame: &Frame) { debug_assert!(idx < 3); let mb = self.0.tx(idx); @@ -309,7 +309,7 @@ impl Registers { }); } - fn read_pending_mailbox(&mut self, idx: usize) -> Option { + fn read_pending_mailbox(&self, idx: usize) -> Option { if self.abort_by_index(idx) { debug_assert!(idx < 3); @@ -332,7 +332,7 @@ impl Registers { } /// 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)); // 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 /// 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 // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. let tsr = self.0.tsr().read(); diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index 004b1a729..f63076512 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -19,8 +19,8 @@ mod can_common; use can_common::*; 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 CanRx<'d> = embassy_stm32::can::CanRx<'d, embassy_stm32::peripherals::CAN1>; +type CanTx<'d> = embassy_stm32::can::CanTx<'d>; +type CanRx<'d> = embassy_stm32::can::CanRx<'d>; bind_interrupts!(struct Irqs { CAN1_RX0 => Rx0InterruptHandler; From 7fd79857c339ccc55a4df606e25b432ada8f43a1 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 30 May 2024 22:00:02 +1000 Subject: [PATCH 2/3] Fix example. --- examples/stm32f7/src/bin/can.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index e32b4d3df..f4d6d8c19 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -24,7 +24,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { +pub async fn send_can_message(tx: &'static mut CanTx<'static>) { loop { let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap(); tx.write(&frame).await; @@ -62,7 +62,7 @@ async fn main(spawner: Spawner) { let (tx, mut rx) = can.split(); - static CAN_TX: StaticCell> = StaticCell::new(); + static CAN_TX: StaticCell> = StaticCell::new(); let tx = CAN_TX.init(tx); spawner.spawn(send_can_message(tx)).unwrap(); From b4a2f7fb70ac3f0b0d9226ab5ff5aab7a5bf8649 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 30 May 2024 22:10:46 +1000 Subject: [PATCH 3/3] Use phantom for lifetime holder instead of not used pointer to pointer. --- embassy-stm32/src/can/bxcan/mod.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 4f516c917..c242aea2b 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -156,7 +156,6 @@ impl Drop for CanConfig<'_, T> { /// CAN driver pub struct Can<'d, T: Instance> { _peri: PeripheralRef<'d, T>, - instance: &'d crate::pac::can::Can, info: &'static Info, state: &'static State, } @@ -228,7 +227,6 @@ impl<'d, T: Instance> Can<'d, T> { Self { _peri: peri, - instance: &T::info().regs.0, info: T::info(), state: T::state(), } @@ -346,7 +344,7 @@ impl<'d, T: Instance> Can<'d, T> { /// Waits for a specific transmit mailbox to become empty pub async fn flush(&self, mb: Mailbox) { CanTx { - _instance: &self.instance, + _phantom: PhantomData, info: self.info, state: self.state, } @@ -362,7 +360,7 @@ impl<'d, T: Instance> Can<'d, T> { /// and a frame with equal priority is already queued for transmission. pub async fn flush_any(&self) { CanTx { - _instance: &self.instance, + _phantom: PhantomData, info: self.info, state: self.state, } @@ -373,7 +371,7 @@ impl<'d, T: Instance> Can<'d, T> { /// Waits until all of the transmit mailboxes become empty pub async fn flush_all(&self) { CanTx { - _instance: &self.instance, + _phantom: PhantomData, info: self.info, state: self.state, } @@ -424,12 +422,12 @@ impl<'d, T: Instance> Can<'d, T> { pub fn split<'c>(&'c mut self) -> (CanTx<'d>, CanRx<'d>) { ( CanTx { - _instance: &self.instance, + _phantom: PhantomData, info: self.info, state: self.state, }, CanRx { - instance: &self.instance, + _phantom: PhantomData, info: self.info, state: self.state, }, @@ -502,7 +500,7 @@ impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_ /// CAN driver, transmit half. pub struct CanTx<'d> { - _instance: &'d crate::pac::can::Can, + _phantom: PhantomData<&'d ()>, info: &'static Info, state: &'static State, } @@ -695,7 +693,7 @@ impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> { /// CAN driver, receive half. #[allow(dead_code)] pub struct CanRx<'d> { - instance: &'d crate::pac::can::Can, + _phantom: PhantomData<&'d ()>, info: &'static Info, state: &'static State, }