diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 81ceb06aa..b772a3ca0 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -3,6 +3,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, DynamicReceiver, DynamicSender}; @@ -40,7 +41,7 @@ pub struct IT0InterruptHandler { // We use IT0 for everything currently impl interrupt::typelevel::Handler for IT0InterruptHandler { unsafe fn on_interrupt() { - let regs = T::regs(); + let regs = T::registers().regs; let ir = regs.ir().read(); @@ -140,22 +141,13 @@ pub enum OperatingMode { //TestMode, } -/// FDCAN Configuration instance instance -/// Create instance of this first -pub struct CanConfigurator<'d, T: Instance> { - config: crate::can::fd::config::FdCanConfig, - /// Reference to internals. - instance: FdcanInstance<'d, T>, - properties: Properties, -} - fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { match mode { // Use timestamp from Rx FIFO to adjust timestamp reported to user crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => { let freq = T::frequency(); - let prescale: u64 = - ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64; + let prescale: u64 = ({ T::registers().regs.nbtp().read().nbrp() } + 1) as u64 + * ({ T::registers().regs.tscc().read().tcp() } + 1) as u64; 1_000_000_000 as u64 / (freq.0 as u64 * prescale) } // For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use @@ -164,6 +156,18 @@ fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransm } } +/// FDCAN Configuration instance instance +/// Create instance of this first +pub struct CanConfigurator<'d, T: Instance> { + config: crate::can::fd::config::FdCanConfig, + info: &'static Info, + state: &'static State, + /// Reference to internals. + _instance: FdcanInstance<'d, T>, + properties: Properties, + periph_clock: crate::time::Hertz, +} + 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. @@ -196,16 +200,18 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { T::IT1Interrupt::unpend(); // Not unsafe T::IT1Interrupt::enable(); } - Self { config, - instance: FdcanInstance(peri), - properties: Properties::new(), + info: T::info(), + state: T::state(), + _instance: FdcanInstance(peri), + properties: Properties::new(T::info()), + periph_clock: T::frequency(), } } /// Get driver properties - pub fn properties(&self) -> &Properties { + pub fn properties(&self) -> &Properties { &self.properties } @@ -221,7 +227,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { /// Configures the bit timings calculated from supplied bitrate. pub fn set_bitrate(&mut self, bitrate: u32) { - let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); + let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap(); let nbtr = crate::can::fd::config::NominalBitTiming { sync_jump_width: bit_timing.sync_jump_width, @@ -234,7 +240,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { /// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) { - let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); + let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap(); // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M let nbtr = crate::can::fd::config::DataBitTiming { transceiver_delay_compensation, @@ -248,62 +254,68 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { } /// Start in mode. - pub fn start(self, mode: OperatingMode) -> Can<'d, T> { + pub fn start(self, mode: OperatingMode) -> Can<'d> { let ns_per_timer_tick = calc_ns_per_timer_tick::(self.config.frame_transmit); - critical_section::with(|_| unsafe { - T::mut_state().ns_per_timer_tick = ns_per_timer_tick; + critical_section::with(|_| { + let state = self.state as *const State; + unsafe { + let mut_state = state as *mut State; + (*mut_state).ns_per_timer_tick = ns_per_timer_tick; + } }); T::registers().into_mode(self.config, mode); - let ret = Can { + Can { config: self.config, - instance: self.instance, + info: self.info, + state: self.state, + instance: T::info().regs.regs, _mode: mode, - properties: self.properties, - }; - ret + properties: Properties::new(T::info()), + } } /// Start, entering mode. Does same as start(mode) - pub fn into_normal_mode(self) -> Can<'d, T> { + pub fn into_normal_mode(self) -> Can<'d> { self.start(OperatingMode::NormalOperationMode) } /// Start, entering mode. Does same as start(mode) - pub fn into_internal_loopback_mode(self) -> Can<'d, T> { + pub fn into_internal_loopback_mode(self) -> Can<'d> { self.start(OperatingMode::InternalLoopbackMode) } /// Start, entering mode. Does same as start(mode) - pub fn into_external_loopback_mode(self) -> Can<'d, T> { + pub fn into_external_loopback_mode(self) -> Can<'d> { self.start(OperatingMode::ExternalLoopbackMode) } } /// FDCAN Instance -pub struct Can<'d, T: Instance> { +pub struct Can<'d> { config: crate::can::fd::config::FdCanConfig, - /// Reference to internals. - instance: FdcanInstance<'d, T>, + info: &'static Info, + state: &'static State, + instance: &'d crate::pac::can::Fdcan, _mode: OperatingMode, - properties: Properties, + properties: Properties, } -impl<'d, T: Instance> Can<'d, T> { +impl<'d> Can<'d> { /// Get driver properties - pub fn properties(&self) -> &Properties { + pub fn properties(&self) -> &Properties { &self.properties } /// Flush one of the TX mailboxes. pub async fn flush(&self, idx: usize) { poll_fn(|cx| { - T::state().tx_mode.register(cx.waker()); + self.state.tx_mode.register(cx.waker()); if idx > 3 { panic!("Bad mailbox"); } let idx = 1 << idx; - if !T::regs().txbrp().read().trp(idx) { + if !self.info.regs.regs.txbrp().read().trp(idx) { return Poll::Ready(()); } @@ -317,12 +329,12 @@ impl<'d, T: Instance> Can<'d, T> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write(&mut self, frame: &Frame) -> Option { - T::state().tx_mode.write::(frame).await + self.state.tx_mode.write(self.info, frame).await } /// Returns the next received message frame pub async fn read(&mut self) -> Result { - T::state().rx_mode.read_classic::().await + self.state.rx_mode.read_classic(self.info, self.state).await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -330,58 +342,61 @@ impl<'d, T: Instance> Can<'d, T> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { - T::state().tx_mode.write_fd::(frame).await + self.state.tx_mode.write_fd(self.info, frame).await } /// Returns the next received message frame pub async fn read_fd(&mut self) -> Result { - T::state().rx_mode.read_fd::().await + self.state.rx_mode.read_fd(self.info, self.state).await } /// Split instance into separate portions: Tx(write), Rx(read), common properties - pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>, Properties) { + pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) { ( CanTx { + info: self.info, + state: self.state, config: self.config, _instance: self.instance, _mode: self._mode, }, CanRx { - _instance1: PhantomData::, - _instance2: T::regs(), + info: self.info, + state: self.state, + _instance: self.instance, _mode: self._mode, }, self.properties, ) } - /// Join split rx and tx portions back together - pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self { + pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self { Can { config: tx.config, - //_instance2: T::regs(), + info: tx.info, + state: tx.state, instance: tx._instance, _mode: rx._mode, - properties: Properties::new(), + properties: Properties::new(tx.info), } } /// Return a buffered instance of driver without CAN FD support. User must supply Buffers pub fn buffered( - &self, + self, tx_buf: &'static mut TxBuf, rxb: &'static mut RxBuf, - ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { - BufferedCan::new(PhantomData::, T::regs(), self._mode, tx_buf, rxb) + ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { + BufferedCan::new(self.info, self.state, self.info.regs.regs, self._mode, tx_buf, rxb) } /// Return a buffered instance of driver with CAN FD support. User must supply Buffers pub fn buffered_fd( - &self, + self, tx_buf: &'static mut TxFdBuf, rxb: &'static mut RxFdBuf, - ) -> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { - BufferedCanFd::new(PhantomData::, T::regs(), self._mode, tx_buf, rxb) + ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { + BufferedCanFd::new(self.info, self.state, self.info.regs.regs, self._mode, tx_buf, rxb) } } @@ -392,52 +407,57 @@ pub type RxBuf = Channel = Channel; /// Buffered FDCAN Instance -pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { - _instance1: PhantomData, - _instance2: &'d crate::pac::can::Fdcan, +pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { + info: &'static Info, + state: &'static State, + _instance: &'d crate::pac::can::Fdcan, _mode: OperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, - properties: Properties, + properties: Properties, } -impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> - BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> -{ +impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { fn new( - _instance1: PhantomData, - _instance2: &'d crate::pac::can::Fdcan, + info: &'static Info, + state: &'static State, + _instance: &'d crate::pac::can::Fdcan, _mode: OperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, ) -> Self { BufferedCan { - _instance1, - _instance2, + info, + state, + _instance, _mode, tx_buf, rx_buf, - properties: Properties::new(), + properties: Properties::new(info), } .setup() } /// Get driver properties - pub fn properties(&self) -> &Properties { + pub fn properties(&self) -> &Properties { &self.properties } 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(), }; let tx_inner = super::common::ClassicBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; - T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); - T::mut_state().tx_mode = TxMode::ClassicBuffered(tx_inner); + let state = self.state as *const State; + unsafe { + let mut_state = state as *mut State; + (*mut_state).rx_mode = RxMode::ClassicBuffered(rx_inner); + (*mut_state).tx_mode = TxMode::ClassicBuffered(tx_inner); + } }); self } @@ -445,7 +465,8 @@ 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: Frame) { self.tx_buf.send(frame).await; - T::IT0Interrupt::pend(); // Wake for Tx + self.info.interrupt0.pend(); // Wake for Tx + //T::IT0Interrupt::pend(); // Wake for Tx } /// Async read frame from RX buffer. @@ -457,7 +478,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> pub fn writer(&self) -> BufferedCanSender { BufferedCanSender { tx_buf: self.tx_buf.sender().into(), - waker: T::IT0Interrupt::pend, + waker: self.info.tx_waker, } } @@ -467,13 +488,15 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> } } -impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop - for BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> -{ +impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { fn drop(&mut self) { - critical_section::with(|_| unsafe { - T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - 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).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } }); } } @@ -484,16 +507,6 @@ pub type RxFdBuf = Channel = Channel; -/// Buffered FDCAN Instance -pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { - _instance1: PhantomData, - _instance2: &'d crate::pac::can::Fdcan, - _mode: OperatingMode, - tx_buf: &'static TxFdBuf, - rx_buf: &'static RxFdBuf, - properties: Properties, -} - /// Sender that can be used for sending CAN frames. #[derive(Copy, Clone)] pub struct BufferedFdCanSender { @@ -524,43 +537,58 @@ 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>; -impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> - BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> -{ +/// Buffered FDCAN Instance +pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { + info: &'static Info, + state: &'static State, + _instance: &'d crate::pac::can::Fdcan, + _mode: OperatingMode, + tx_buf: &'static TxFdBuf, + rx_buf: &'static RxFdBuf, + properties: Properties, +} + +impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { fn new( - _instance1: PhantomData, - _instance2: &'d crate::pac::can::Fdcan, + info: &'static Info, + state: &'static State, + _instance: &'d crate::pac::can::Fdcan, _mode: OperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, ) -> Self { BufferedCanFd { - _instance1, - _instance2, + info, + state, + _instance, _mode, tx_buf, rx_buf, - properties: Properties::new(), + properties: Properties::new(info), } .setup() } /// Get driver properties - pub fn properties(&self) -> &Properties { + pub fn properties(&self) -> &Properties { &self.properties } 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::FdBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; let tx_inner = super::common::FdBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; - T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); - T::mut_state().tx_mode = TxMode::FdBuffered(tx_inner); + let state = self.state as *const State; + unsafe { + let mut_state = state as *mut State; + (*mut_state).rx_mode = RxMode::FdBuffered(rx_inner); + (*mut_state).tx_mode = TxMode::FdBuffered(tx_inner); + } }); self } @@ -568,7 +596,8 @@ 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: FdFrame) { self.tx_buf.send(frame).await; - T::IT0Interrupt::pend(); // Wake for Tx + self.info.interrupt0.pend(); // Wake for Tx + //T::IT0Interrupt::pend(); // Wake for Tx } /// Async read frame from RX buffer. @@ -580,7 +609,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> pub fn writer(&self) -> BufferedFdCanSender { BufferedFdCanSender { tx_buf: self.tx_buf.sender().into(), - waker: T::IT0Interrupt::pend, + waker: self.info.tx_waker, } } @@ -590,38 +619,55 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> } } -impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop - for BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> -{ +impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { fn drop(&mut self) { - critical_section::with(|_| unsafe { - T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - 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).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } }); } } /// FDCAN Rx only Instance -pub struct CanRx<'d, T: Instance> { - _instance1: PhantomData, - _instance2: &'d crate::pac::can::Fdcan, +pub struct CanRx<'d> { + info: &'static Info, + state: &'static State, + _instance: &'d crate::pac::can::Fdcan, _mode: OperatingMode, } +impl<'d> CanRx<'d> { + /// Returns the next received message frame + pub async fn read(&mut self) -> Result { + self.state.rx_mode.read_classic(&self.info, &self.state).await + } + + /// Returns the next received message frame + pub async fn read_fd(&mut self) -> Result { + self.state.rx_mode.read_fd(&self.info, &self.state).await + } +} + /// FDCAN Tx only Instance -pub struct CanTx<'d, T: Instance> { +pub struct CanTx<'d> { + info: &'static Info, + state: &'static State, config: crate::can::fd::config::FdCanConfig, - _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); + _instance: &'d crate::pac::can::Fdcan, _mode: OperatingMode, } -impl<'c, 'd, T: Instance> CanTx<'d, T> { +impl<'c, 'd> CanTx<'d> { /// 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: &Frame) -> Option { - T::state().tx_mode.write::(frame).await + self.state.tx_mode.write(self.info, frame).await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -629,19 +675,7 @@ impl<'c, 'd, T: Instance> CanTx<'d, T> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { - T::state().tx_mode.write_fd::(frame).await - } -} - -impl<'c, 'd, T: Instance> CanRx<'d, T> { - /// Returns the next received message frame - pub async fn read(&mut self) -> Result { - T::state().rx_mode.read_classic::().await - } - - /// Returns the next received message frame - pub async fn read_fd(&mut self) -> Result { - T::state().rx_mode.read_fd::().await + self.state.tx_mode.write_fd(self.info, frame).await } } @@ -662,7 +696,7 @@ impl RxMode { } fn on_interrupt(&self, fifonr: usize) { - T::regs().ir().write(|w| w.set_rfn(fifonr, true)); + T::registers().regs.ir().write(|w| w.set_rfn(fifonr, true)); match self { RxMode::NonBuffered(waker) => { waker.wake(); @@ -696,7 +730,6 @@ impl RxMode { } } - //async fn read_classic(&self) -> Result { fn try_read_fd(&self) -> Option> { if let Some((frame, ts)) = T::registers().read(0) { let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); @@ -712,14 +745,18 @@ impl RxMode { } } - fn read(&self) -> Option> { - if let Some((msg, ts)) = T::registers().read(0) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + fn read( + &self, + info: &'static Info, + state: &'static State, + ) -> Option> { + if let Some((msg, ts)) = info.regs.read(0) { + let ts = info.calc_timestamp(state.ns_per_timer_tick, ts); Some(Ok((msg, ts))) - } else if let Some((msg, ts)) = T::registers().read(1) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + } else if let Some((msg, ts)) = info.regs.read(1) { + let ts = info.calc_timestamp(state.ns_per_timer_tick, ts); Some(Ok((msg, ts))) - } else if let Some(err) = T::registers().curr_error() { + } else if let Some(err) = info.regs.curr_error() { // TODO: this is probably wrong Some(Err(err)) } else { @@ -727,11 +764,16 @@ impl RxMode { } } - async fn read_async(&self) -> Result<(F, Timestamp), BusError> { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); + async fn read_async( + &self, + info: &'static Info, + state: &'static State, + ) -> Result<(F, Timestamp), BusError> { + //let _ = self.read::(info, state); + poll_fn(move |cx| { + state.err_waker.register(cx.waker()); self.register(cx.waker()); - match self.read::() { + match self.read::<_>(info, state) { Some(result) => Poll::Ready(result), None => Poll::Pending, } @@ -739,15 +781,15 @@ impl RxMode { .await } - async fn read_classic(&self) -> Result { - match self.read_async::().await { + async fn read_classic(&self, info: &'static Info, state: &'static State) -> Result { + match self.read_async::<_>(info, state).await { Ok((frame, ts)) => Ok(Envelope { ts, frame }), Err(e) => Err(e), } } - async fn read_fd(&self) -> Result { - match self.read_async::().await { + async fn read_fd(&self, info: &'static Info, state: &'static State) -> Result { + match self.read_async::<_>(info, state).await { Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }), Err(e) => Err(e), } @@ -776,11 +818,11 @@ 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_generic(&self, frame: &F) -> Option { + async fn write_generic(&self, info: &'static Info, frame: &F) -> Option { poll_fn(|cx| { self.register(cx.waker()); - if let Ok(dropped) = T::registers().write(frame) { + if let Ok(dropped) = info.regs.write(frame) { return Poll::Ready(dropped); } @@ -795,68 +837,70 @@ 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(&self, frame: &Frame) -> Option { - self.write_generic::(frame).await + async fn write(&self, info: &'static Info, frame: &Frame) -> Option { + self.write_generic::<_>(info, frame).await } /// 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. - async fn write_fd(&self, frame: &FdFrame) -> Option { - self.write_generic::(frame).await + async fn write_fd(&self, info: &'static Info, frame: &FdFrame) -> Option { + self.write_generic::<_>(info, frame).await } } /// Common driver properties, including filters and error counters -pub struct Properties { +pub struct Properties { + info: &'static Info, // phantom pointer to ensure !Sync - instance: PhantomData<*const T>, + //instance: PhantomData<*const T>, } -impl Properties { - fn new() -> Self { +impl Properties { + fn new(info: &'static Info) -> Self { Self { - instance: Default::default(), + info, + //instance: Default::default(), } } /// Set a standard address CAN filter in the specified slot in FDCAN memory. #[inline] pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) { - T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter); + self.info.regs.msg_ram_mut().filters.flssa[slot as usize].activate(filter); } /// Set the full array of standard address CAN filters in FDCAN memory. /// Overwrites all standard address filters in memory. pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) { for (i, f) in filters.iter().enumerate() { - T::registers().msg_ram_mut().filters.flssa[i].activate(*f); + self.info.regs.msg_ram_mut().filters.flssa[i].activate(*f); } } /// Set an extended address CAN filter in the specified slot in FDCAN memory. #[inline] pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { - T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter); + self.info.regs.msg_ram_mut().filters.flesa[slot as usize].activate(filter); } /// Set the full array of extended address CAN filters in FDCAN memory. /// Overwrites all extended address filters in memory. pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) { for (i, f) in filters.iter().enumerate() { - T::registers().msg_ram_mut().filters.flesa[i].activate(*f); + self.info.regs.msg_ram_mut().filters.flesa[i].activate(*f); } } /// Get the CAN RX error counter pub fn rx_error_count(&self) -> u8 { - T::regs().ecr().read().rec() + self.info.regs.regs.ecr().read().rec() } /// Get the CAN TX error counter pub fn tx_error_count(&self) -> u8 { - T::regs().ecr().read().tec() + self.info.regs.regs.ecr().read().tec() } /// Get the current bus error mode @@ -864,7 +908,7 @@ impl Properties { // This read will clear LEC and DLEC. This is not ideal, but protocol // error reporting in this driver should have a big ol' FIXME on it // anyway! - let psr = T::regs().psr().read(); + let psr = self.info.regs.regs.psr().read(); match (psr.bo(), psr.ep()) { (false, false) => BusErrorMode::ErrorActive, (false, true) => BusErrorMode::ErrorPassive, @@ -892,10 +936,37 @@ impl State { } } +struct Info { + regs: Registers, + interrupt0: crate::interrupt::Interrupt, + _interrupt1: crate::interrupt::Interrupt, + tx_waker: fn(), +} + +impl Info { + #[cfg(feature = "time")] + fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + let now_embassy = embassy_time::Instant::now(); + if ns_per_timer_tick == 0 { + return now_embassy; + } + let cantime = { self.regs.regs.tscv().read().tsc() }; + let delta = cantime.overflowing_sub(ts_val).0 as u64; + let ns = ns_per_timer_tick * delta as u64; + now_embassy - embassy_time::Duration::from_nanos(ns) + } + + #[cfg(not(feature = "time"))] + fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + ts_val + } +} + trait SealedInstance { const MSG_RAM_OFFSET: usize; - fn regs() -> &'static crate::pac::can::Fdcan; + fn info() -> &'static Info; + //fn regs() -> &'static crate::pac::can::Fdcan; fn registers() -> crate::can::fd::peripheral::Registers; fn state() -> &'static State; unsafe fn mut_state() -> &'static mut State; @@ -915,12 +986,20 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static { pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); macro_rules! impl_fdcan { - ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { + ($inst:ident, + //$irq0:ident, $irq1:ident, + $msg_ram_inst:ident, $msg_ram_offset:literal) => { impl SealedInstance for peripherals::$inst { const MSG_RAM_OFFSET: usize = $msg_ram_offset; - fn regs() -> &'static crate::pac::can::Fdcan { - &crate::pac::$inst + fn info() -> &'static Info { + static INFO: Info = Info { + regs: Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset}, + interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ, + _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ, + tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend, + }; + &INFO } fn registers() -> Registers { Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} @@ -939,7 +1018,7 @@ macro_rules! impl_fdcan { if ns_per_timer_tick == 0 { return now_embassy; } - let cantime = { Self::regs().tscv().read().tsc() }; + let cantime = { Self::registers().regs.tscv().read().tsc() }; let delta = cantime.overflowing_sub(ts_val).0 as u64; let ns = ns_per_timer_tick * delta as u64; now_embassy - embassy_time::Duration::from_nanos(ns) diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index 551764458..004b1a729 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -9,9 +9,7 @@ use common::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::can::filter::Mask32; -use embassy_stm32::can::{ - Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, -}; +use embassy_stm32::can::{Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN1; use embassy_time::Duration; @@ -20,6 +18,10 @@ use {defmt_rtt as _, panic_probe as _}; 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>; + bind_interrupts!(struct Irqs { CAN1_RX0 => Rx0InterruptHandler; CAN1_RX1 => Rx1InterruptHandler; diff --git a/tests/stm32/src/bin/can_common.rs b/tests/stm32/src/bin/can_common.rs index 4b39269cc..fbfbcdc21 100644 --- a/tests/stm32/src/bin/can_common.rs +++ b/tests/stm32/src/bin/can_common.rs @@ -8,7 +8,8 @@ pub struct TestOptions { pub max_buffered: u8, } -pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) { +pub async fn run_can_tests<'d>(can: &mut crate::Can<'d>, options: &TestOptions) { + //pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) { let mut i: u8 = 0; loop { //let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap(); @@ -79,11 +80,7 @@ pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, opti } } -pub async fn run_split_can_tests<'d, T: can::Instance>( - tx: &mut can::CanTx<'d, T>, - rx: &mut can::CanRx<'d, T>, - options: &TestOptions, -) { +pub async fn run_split_can_tests<'d>(tx: &mut crate::CanTx<'d>, rx: &mut crate::CanRx<'d>, options: &TestOptions) { for i in 0..options.max_buffered { // Try filling up the RX FIFO0 buffers //let tx_frame = if 0 != (i & 0x01) { diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index 20bd3f7e3..8534f92e8 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -15,6 +15,10 @@ use {defmt_rtt as _, panic_probe as _}; mod can_common; use can_common::*; +type Can<'d> = can::Can<'d>; +type CanTx<'d> = can::CanTx<'d>; +type CanRx<'d> = can::CanRx<'d>; + bind_interrupts!(struct Irqs2 { FDCAN2_IT0 => can::IT0InterruptHandler; FDCAN2_IT1 => can::IT1InterruptHandler;