From c8936edb6c13eb099dfb31a4a51be2dd3bb4661e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 2 Apr 2024 01:29:52 +0200 Subject: [PATCH] stm32/can: simplify bxcan api, merging bx::* into the main structs. The bx::* separate structs (Can, Rx, Tx) and separate `Instance` trait are a relic from the `bxcan` crate. Remove them, move the functionality into the main structs. --- embassy-stm32/src/can/bx/mod.rs | 1010 ----------------- embassy-stm32/src/can/{bx => bxcan}/filter.rs | 2 +- .../src/can/{bxcan.rs => bxcan/mod.rs} | 344 ++++-- embassy-stm32/src/can/bxcan/registers.rs | 510 +++++++++ embassy-stm32/src/can/common.rs | 4 +- embassy-stm32/src/can/fdcan.rs | 34 +- embassy-stm32/src/can/mod.rs | 9 +- examples/stm32f1/src/bin/can.rs | 13 +- examples/stm32f4/src/bin/can.rs | 11 +- examples/stm32f7/src/bin/can.rs | 12 +- tests/stm32/src/bin/can.rs | 19 +- 11 files changed, 808 insertions(+), 1160 deletions(-) delete mode 100644 embassy-stm32/src/can/bx/mod.rs rename embassy-stm32/src/can/{bx => bxcan}/filter.rs (99%) rename embassy-stm32/src/can/{bxcan.rs => bxcan/mod.rs} (68%) create mode 100644 embassy-stm32/src/can/bxcan/registers.rs diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs deleted file mode 100644 index cd82148ba..000000000 --- a/embassy-stm32/src/can/bx/mod.rs +++ /dev/null @@ -1,1010 +0,0 @@ -//! Driver for the STM32 bxCAN peripheral. -//! -//! This crate provides a reusable driver for the bxCAN peripheral found in many low- to middle-end -//! STM32 microcontrollers. HALs for compatible chips can reexport this crate and implement its -//! traits to easily expose a featureful CAN driver. -//! -//! # Features -//! -//! - Supports both single- and dual-peripheral configurations (where one bxCAN instance manages the -//! filters of a secondary instance). -//! - Handles standard and extended frames, and data and remote frames. -//! - Support for interrupts emitted by the bxCAN peripheral. -//! - Transmission respects CAN IDs and protects against priority inversion (a lower-priority frame -//! may be dequeued when enqueueing a higher-priority one). -//! - Implements the [`embedded-hal`] traits for interoperability. -//! - Support for both RX FIFOs (as [`Rx0`] and [`Rx1`]). -//! -//! # Limitations -//! -//! - Support for querying error states and handling error interrupts is incomplete. -//! - -// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default -#![allow(clippy::unnecessary_operation)] // lint is bugged - -//mod embedded_hal; -pub mod filter; - -#[allow(clippy::all)] // generated code -use core::cmp::{Ord, Ordering}; -use core::convert::Infallible; -use core::marker::PhantomData; -use core::mem; - -pub use embedded_can::{ExtendedId, Id, StandardId}; - -/// CAN Header: includes ID and length -pub type Header = crate::can::frame::Header; - -/// Data for a CAN Frame -pub type Data = crate::can::frame::ClassicData; - -use crate::can::_version::Envelope; -use crate::can::bx::filter::MasterFilters; -use crate::can::enums::BusError; -/// CAN Frame -pub use crate::can::frame::Frame; -use crate::pac::can::vals::Lec; - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub(crate) enum RxFifo { - Fifo0, - Fifo1, -} - -trait IntoBusError { - fn into_bus_err(self) -> Option; -} - -impl IntoBusError for Lec { - fn into_bus_err(self) -> Option { - match self { - Lec::STUFF => Some(BusError::Stuff), - Lec::FORM => Some(BusError::Form), - Lec::ACK => Some(BusError::Acknowledge), - Lec::BITRECESSIVE => Some(BusError::BitRecessive), - Lec::BITDOMINANT => Some(BusError::BitDominant), - Lec::CRC => Some(BusError::Crc), - Lec::CUSTOM => Some(BusError::Software), - _ => None, - } - } -} - -/// A bxCAN peripheral instance. -/// -/// This trait is meant to be implemented for a HAL-specific type that represent ownership of -/// the CAN peripheral (and any pins required by it, although that is entirely up to the HAL). -/// -/// # Safety -/// -/// It is only safe to implement this trait, when: -/// -/// * The implementing type has ownership of the peripheral, preventing any other accesses to the -/// register block. -/// * `REGISTERS` is a pointer to that peripheral's register block and can be safely accessed for as -/// long as ownership or a borrow of the implementing type is present. -pub unsafe trait Instance {} - -/// A bxCAN instance that owns filter banks. -/// -/// In master-slave-instance setups, only the master instance owns the filter banks, and needs to -/// split some of them off for use by the slave instance. In that case, the master instance should -/// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement -/// [`Instance`]. -/// -/// In single-instance configurations, the instance owns all filter banks and they can not be split -/// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`]. -/// -/// # Safety -/// -/// This trait must only be implemented if the instance does, in fact, own its associated filter -/// banks, and `NUM_FILTER_BANKS` must be correct. -pub unsafe trait FilterOwner: Instance { - /// The total number of filter banks available to the instance. - /// - /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet. - const NUM_FILTER_BANKS: u8; -} - -/// A bxCAN master instance that shares filter banks with a slave instance. -/// -/// In master-slave-instance setups, this trait should be implemented for the master instance. -/// -/// # Safety -/// -/// This trait must only be implemented when there is actually an associated slave instance. -pub unsafe trait MasterInstance: FilterOwner {} - -// TODO: what to do with these? -/* -#[derive(Debug, Copy, Clone, Eq, PartialEq, Format)] -pub enum Error { - Stuff, - Form, - Acknowledgement, - BitRecessive, - BitDominant, - Crc, - Software, -}*/ - -/// Error that indicates that an incoming message has been lost due to buffer overrun. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OverrunError { - _priv: (), -} - -/// Identifier of a CAN message. -/// -/// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a -/// extendended identifier (29bit , Range: 0..0x1FFFFFFF). -/// -/// The `Ord` trait can be used to determine the frame’s priority this ID -/// belongs to. -/// Lower identifier values have a higher priority. Additionally standard frames -/// have a higher priority than extended frames and data frames have a higher -/// priority than remote frames. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub(crate) struct IdReg(u32); - -impl IdReg { - const STANDARD_SHIFT: u32 = 21; - - const EXTENDED_SHIFT: u32 = 3; - - const IDE_MASK: u32 = 0x0000_0004; - - const RTR_MASK: u32 = 0x0000_0002; - - /// Creates a new standard identifier (11bit, Range: 0..0x7FF) - /// - /// Panics for IDs outside the allowed range. - fn new_standard(id: StandardId) -> Self { - Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT) - } - - /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF). - /// - /// Panics for IDs outside the allowed range. - fn new_extended(id: ExtendedId) -> IdReg { - Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK) - } - - fn from_register(reg: u32) -> IdReg { - Self(reg & 0xFFFF_FFFE) - } - - /// Returns the identifier. - fn to_id(self) -> Id { - if self.is_extended() { - Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) - } else { - Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) }) - } - } - - /// Returns the identifier. - fn id(self) -> embedded_can::Id { - if self.is_extended() { - embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT) - .unwrap() - .into() - } else { - embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16) - .unwrap() - .into() - } - } - - /// Returns `true` if the identifier is an extended identifier. - fn is_extended(self) -> bool { - self.0 & Self::IDE_MASK != 0 - } - - /// Returns `true` if the identifer is part of a remote frame (RTR bit set). - fn rtr(self) -> bool { - self.0 & Self::RTR_MASK != 0 - } -} - -impl From<&embedded_can::Id> for IdReg { - fn from(eid: &embedded_can::Id) -> Self { - match eid { - embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()), - embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()), - } - } -} - -impl From for embedded_can::Id { - fn from(idr: IdReg) -> Self { - idr.id() - } -} - -/// `IdReg` is ordered by priority. -impl Ord for IdReg { - fn cmp(&self, other: &Self) -> Ordering { - // When the IDs match, data frames have priority over remote frames. - let rtr = self.rtr().cmp(&other.rtr()).reverse(); - - let id_a = self.to_id(); - let id_b = other.to_id(); - match (id_a, id_b) { - (Id::Standard(a), Id::Standard(b)) => { - // Lower IDs have priority over higher IDs. - a.as_raw().cmp(&b.as_raw()).reverse().then(rtr) - } - (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr), - (Id::Standard(a), Id::Extended(b)) => { - // Standard frames have priority over extended frames if their Base IDs match. - a.as_raw() - .cmp(&b.standard_id().as_raw()) - .reverse() - .then(Ordering::Greater) - } - (Id::Extended(a), Id::Standard(b)) => { - a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less) - } - } - } -} - -impl PartialOrd for IdReg { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -pub(crate) struct Registers { - pub canregs: crate::pac::can::Can, -} - -impl Registers { - fn enter_init_mode(&mut self) { - self.canregs.mcr().modify(|reg| { - reg.set_sleep(false); - reg.set_inrq(true); - }); - loop { - let msr = self.canregs.msr().read(); - if !msr.slak() && msr.inak() { - break; - } - } - } - - // Leaves initialization mode, enters sleep mode. - fn leave_init_mode(&mut self) { - self.canregs.mcr().modify(|reg| { - reg.set_sleep(true); - reg.set_inrq(false); - }); - loop { - let msr = self.canregs.msr().read(); - if msr.slak() && !msr.inak() { - break; - } - } - } - - fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { - let prescaler = u16::from(bt.prescaler) & 0x1FF; - let seg1 = u8::from(bt.seg1); - let seg2 = u8::from(bt.seg2) & 0x7F; - let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; - self.canregs.btr().modify(|reg| { - reg.set_brp(prescaler - 1); - reg.set_ts(0, seg1 - 1); - reg.set_ts(1, seg2 - 1); - reg.set_sjw(sync_jump_width - 1); - }); - } - - /// Enables or disables silent mode: Disconnects the TX signal from the pin. - pub fn set_silent(&self, enabled: bool) { - let mode = match enabled { - false => stm32_metapac::can::vals::Silm::NORMAL, - true => stm32_metapac::can::vals::Silm::SILENT, - }; - self.canregs.btr().modify(|reg| reg.set_silm(mode)); - } - - /// Enables or disables automatic retransmission of messages. - /// - /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame - /// until it can be sent. Otherwise, it will try only once to send each frame. - /// - /// Automatic retransmission is enabled by default. - pub fn set_automatic_retransmit(&self, enabled: bool) { - self.canregs.mcr().modify(|reg| reg.set_nart(enabled)); - } - - /// Enables or disables loopback mode: Internally connects the TX and RX - /// signals together. - pub fn set_loopback(&self, enabled: bool) { - self.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); - } - - /// Configures the automatic wake-up feature. - /// - /// This is turned off by default. - /// - /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and - /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming - /// frame. - #[allow(dead_code)] - pub fn set_automatic_wakeup(&mut self, enabled: bool) { - self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); - } - - /// Leaves initialization mode and enables the peripheral (non-blocking version). - /// - /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed - /// if you want non-blocking initialization. - /// - /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself - /// in the background. The peripheral is enabled and ready to use when this method returns - /// successfully. - pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { - let msr = self.canregs.msr().read(); - if msr.slak() { - self.canregs.mcr().modify(|reg| { - reg.set_abom(true); - reg.set_sleep(false); - }); - Err(nb::Error::WouldBlock) - } else { - Ok(()) - } - } - - /// Puts the peripheral in a sleep mode to save power. - /// - /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. - #[allow(dead_code)] - pub fn sleep(&mut self) { - self.canregs.mcr().modify(|reg| { - reg.set_sleep(true); - reg.set_inrq(false); - }); - loop { - let msr = self.canregs.msr().read(); - if msr.slak() && !msr.inak() { - break; - } - } - } - - /// Disables the CAN interface. - /// - /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to - /// enter sleep mode. - pub fn reset(&self) { - self.canregs.mcr().write(|reg| reg.set_reset(true)); - } - - /// Wakes up from sleep mode. - /// - /// 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) { - self.canregs.mcr().modify(|reg| { - reg.set_sleep(false); - reg.set_inrq(false); - }); - loop { - let msr = self.canregs.msr().read(); - if !msr.slak() && !msr.inak() { - break; - } - } - } - - pub fn curr_error(&self) -> Option { - let err = { self.canregs.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); - } - None - } - - /// Puts a CAN frame in a transmit mailbox for transmission on the bus. - /// - /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). - /// Transmit order is preserved for frames with identical priority. - /// - /// If all transmit mailboxes are full, and `frame` has a higher priority than the - /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is - /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as - /// [`TransmitStatus::dequeued_frame`]. - pub fn transmit(&mut self, frame: &Frame) -> nb::Result { - // Get the index of the next free mailbox or the one with the lowest priority. - let tsr = self.canregs.tsr().read(); - let idx = tsr.code() as usize; - - let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); - let pending_frame = if frame_is_pending { - // High priority frames are transmitted first by the mailbox system. - // Frames with identical identifier shall be transmitted in FIFO order. - // The controller schedules pending frames of same priority based on the - // mailbox index instead. As a workaround check all pending mailboxes - // and only accept higher priority frames. - self.check_priority(0, frame.id().into())?; - self.check_priority(1, frame.id().into())?; - self.check_priority(2, frame.id().into())?; - - let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); - if all_frames_are_pending { - // No free mailbox is available. This can only happen when three frames with - // ascending priority (descending IDs) were requested for transmission and all - // of them are blocked by bus traffic with even higher priority. - // To prevent a priority inversion abort and replace the lowest priority frame. - self.read_pending_mailbox(idx) - } else { - // There was a free mailbox. - None - } - } else { - // All mailboxes are available: Send frame without performing any checks. - None - }; - - self.write_mailbox(idx, frame); - - let mailbox = match idx { - 0 => Mailbox::Mailbox0, - 1 => Mailbox::Mailbox1, - 2 => Mailbox::Mailbox2, - _ => unreachable!(), - }; - Ok(TransmitStatus { - dequeued_frame: pending_frame, - mailbox, - }) - } - - /// Returns `Ok` when the mailbox is free or if it contains pending frame with a - /// lower priority (higher ID) than the identifier `id`. - fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { - // Read the pending frame's id to check its priority. - assert!(idx < 3); - let tir = &self.canregs.tx(idx).tir().read(); - //let tir = &can.tx[idx].tir.read(); - - // Check the priority by comparing the identifiers. But first make sure the - // frame has not finished the transmission (`TXRQ` == 0) in the meantime. - if tir.txrq() && id <= IdReg::from_register(tir.0) { - // There's a mailbox whose priority is higher or equal - // the priority of the new frame. - return Err(nb::Error::WouldBlock); - } - - Ok(()) - } - - fn write_mailbox(&mut self, idx: usize, frame: &Frame) { - debug_assert!(idx < 3); - - let mb = self.canregs.tx(idx); - mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); - - mb.tdlr() - .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); - mb.tdhr() - .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); - let id: IdReg = frame.id().into(); - mb.tir().write(|w| { - w.0 = id.0; - w.set_txrq(true); - }); - } - - fn read_pending_mailbox(&mut self, idx: usize) -> Option { - if self.abort_by_index(idx) { - debug_assert!(idx < 3); - - let mb = self.canregs.tx(idx); - - let id = IdReg(mb.tir().read().0); - let mut data = [0xff; 8]; - data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); - data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); - let len = mb.tdtr().read().dlc(); - - Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) - } else { - // Abort request failed because the frame was already sent (or being sent) on - // the bus. All mailboxes are now free. This can happen for small prescaler - // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR - // has preempted the execution. - None - } - } - - /// Tries to abort a pending frame. Returns `true` when aborted. - fn abort_by_index(&mut self, idx: usize) -> bool { - self.canregs.tsr().write(|reg| reg.set_abrq(idx, true)); - - // Wait for the abort request to be finished. - loop { - let tsr = self.canregs.tsr().read(); - if false == tsr.abrq(idx) { - break tsr.txok(idx) == false; - } - } - } - - /// Attempts to abort the sending of a frame that is pending in a mailbox. - /// - /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be - /// aborted, this function has no effect and returns `false`. - /// - /// 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 { - // 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.canregs.tsr().read(); - let mailbox_empty = match mailbox { - Mailbox::Mailbox0 => tsr.tme(0), - Mailbox::Mailbox1 => tsr.tme(1), - Mailbox::Mailbox2 => tsr.tme(2), - }; - if mailbox_empty { - false - } else { - self.abort_by_index(mailbox as usize) - } - } - - /// Returns `true` if no frame is pending for transmission. - pub fn is_idle(&self) -> bool { - let tsr = self.canregs.tsr().read(); - tsr.tme(0) && tsr.tme(1) && tsr.tme(2) - } - - /// Clears the request complete flag for all mailboxes. - pub fn clear_interrupt_flags(&mut self) { - self.canregs.tsr().write(|reg| { - reg.set_rqcp(0, true); - reg.set_rqcp(1, true); - reg.set_rqcp(2, true); - }); - } - - 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")] - let ts = embassy_time::Instant::now(); - - use crate::pac::can::vals::Ide; - - let fifo_idx = match fifo { - crate::can::_version::bx::RxFifo::Fifo0 => 0usize, - crate::can::_version::bx::RxFifo::Fifo1 => 1usize, - }; - let rfr = self.canregs.rfr(fifo_idx); - let fifo = self.canregs.rx(fifo_idx); - - // If there are no pending messages, there is nothing to do - if rfr.read().fmp() == 0 { - return None; - } - - let rir = fifo.rir().read(); - let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { - embedded_can::StandardId::new(rir.stid()).unwrap().into() - } else { - let stid = (rir.stid() & 0x7FF) as u32; - let exid = rir.exid() & 0x3FFFF; - let id = (stid << 18) | (exid); - embedded_can::ExtendedId::new(id).unwrap().into() - }; - let rdtr = fifo.rdtr().read(); - let data_len = rdtr.dlc(); - let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE; - - #[cfg(not(feature = "time"))] - let ts = rdtr.time(); - - let mut data: [u8; 8] = [0; 8]; - data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); - data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); - - let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap(); - let envelope = Envelope { ts, frame }; - - rfr.modify(|v| v.set_rfom(true)); - - Some(envelope) - } -} - -/// Configuration proxy returned by [`Can::modify_config`]. -#[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] -pub struct CanConfig<'a, I: Instance> { - can: &'a mut Can, -} - -impl CanConfig<'_, I> { - /// Configures the bit timings. - /// - /// You can use to calculate the `btr` parameter. Enter - /// parameters as follows: - /// - /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). - /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). - /// - *Sample Point*: Should normally be left at the default value of 87.5%. - /// - *SJW*: Should normally be left at the default value of 1. - /// - /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` - /// parameter to this method. - pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { - self.can.registers.set_bit_timing(bt); - self - } - - /// Enables or disables loopback mode: Internally connects the TX and RX - /// signals together. - pub fn set_loopback(self, enabled: bool) -> Self { - self.can.registers.set_loopback(enabled); - self - } - - /// Enables or disables silent mode: Disconnects the TX signal from the pin. - pub fn set_silent(self, enabled: bool) -> Self { - self.can.registers.set_silent(enabled); - self - } - - /// Enables or disables automatic retransmission of messages. - /// - /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame - /// until it can be sent. Otherwise, it will try only once to send each frame. - /// - /// Automatic retransmission is enabled by default. - pub fn set_automatic_retransmit(self, enabled: bool) -> Self { - self.can.registers.set_automatic_retransmit(enabled); - self - } - - /// Leaves initialization mode and enables the peripheral. - /// - /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected - /// on the bus. - /// - /// If you want to finish configuration without enabling the peripheral, you can call - /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. - pub fn enable(self) { - self.can.registers.leave_init_mode(); - - match nb::block!(self.can.registers.enable_non_blocking()) { - Ok(()) => {} - Err(void) => match void {}, - } - - // Don't run the destructor. - mem::forget(self); - } - - /// Leaves initialization mode, but keeps the peripheral in sleep mode. - /// - /// Before the [`Can`] instance can be used, you have to enable it by calling - /// [`Can::enable_non_blocking`]. - pub fn leave_disabled(self) { - self.can.registers.leave_init_mode(); - } -} - -impl Drop for CanConfig<'_, I> { - #[inline] - fn drop(&mut self) { - self.can.registers.leave_init_mode(); - } -} - -/// Builder returned by [`Can::builder`]. -#[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"] -pub struct CanBuilder { - can: Can, -} - -impl CanBuilder { - /// Configures the bit timings. - /// - /// You can use to calculate the `btr` parameter. Enter - /// parameters as follows: - /// - /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). - /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). - /// - *Sample Point*: Should normally be left at the default value of 87.5%. - /// - *SJW*: Should normally be left at the default value of 1. - /// - /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` - /// parameter to this method. - pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { - self.can.registers.set_bit_timing(bt); - self - } - /// Enables or disables loopback mode: Internally connects the TX and RX - /// signals together. - pub fn set_loopback(self, enabled: bool) -> Self { - self.can.registers.set_loopback(enabled); - self - } - - /// Enables or disables silent mode: Disconnects the TX signal from the pin. - pub fn set_silent(self, enabled: bool) -> Self { - self.can.registers.set_silent(enabled); - self - } - - /// Enables or disables automatic retransmission of messages. - /// - /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame - /// until it can be sent. Otherwise, it will try only once to send each frame. - /// - /// Automatic retransmission is enabled by default. - pub fn set_automatic_retransmit(self, enabled: bool) -> Self { - self.can.registers.set_automatic_retransmit(enabled); - self - } - - /// Leaves initialization mode and enables the peripheral. - /// - /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected - /// on the bus. - /// - /// If you want to finish configuration without enabling the peripheral, you can call - /// [`CanBuilder::leave_disabled`] instead. - pub fn enable(mut self) -> Can { - self.leave_init_mode(); - - match nb::block!(self.can.registers.enable_non_blocking()) { - Ok(()) => self.can, - Err(void) => match void {}, - } - } - - /// Returns the [`Can`] interface without enabling it. - /// - /// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling - /// it. - /// - /// Before the [`Can`] instance can be used, you have to enable it by calling - /// [`Can::enable_non_blocking`]. - pub fn leave_disabled(mut self) -> Can { - self.leave_init_mode(); - self.can - } - - /// Leaves initialization mode, enters sleep mode. - fn leave_init_mode(&mut self) { - self.can.registers.leave_init_mode(); - } -} - -/// Interface to a bxCAN peripheral. -pub struct Can { - instance: I, - canregs: crate::pac::can::Can, - pub(crate) registers: Registers, -} - -impl Can -where - I: Instance, -{ - /// Creates a [`CanBuilder`] for constructing a CAN interface. - pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder { - let mut can_builder = CanBuilder { - can: Can { - instance, - canregs, - registers: Registers { canregs }, - }, - }; - - can_builder.can.registers.enter_init_mode(); - - can_builder - } - - /// Disables the CAN interface and returns back the raw peripheral it was created from. - /// - /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to - /// enter sleep mode. - pub fn free(self) -> I { - self.registers.reset(); - self.instance - } - - /// Configure bit timings and silent/loop-back mode. - /// - /// Calling this method will enter initialization mode. - pub fn modify_config(&mut self) -> CanConfig<'_, I> { - self.registers.enter_init_mode(); - - CanConfig { can: self } - } - - /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. - /// - /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). - /// Transmit order is preserved for frames with identical priority. - /// - /// If all transmit mailboxes are full, and `frame` has a higher priority than the - /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is - /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as - /// [`TransmitStatus::dequeued_frame`]. - pub fn transmit(&mut self, frame: &Frame) -> nb::Result { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure(self.canregs).transmit(frame) } - } - - /// Returns `true` if no frame is pending for transmission. - pub fn is_transmitter_idle(&self) -> bool { - // Safety: Read-only operation. - unsafe { Tx::::conjure(self.canregs).is_idle() } - } - - /// Attempts to abort the sending of a frame that is pending in a mailbox. - /// - /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be - /// aborted, this function has no effect and returns `false`. - /// - /// 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 { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure(self.canregs).abort(mailbox) } - } - - pub(crate) fn split_by_ref(&mut self) -> (Tx, Rx) { - // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. - let tx = unsafe { Tx::conjure(self.canregs) }; - let rx0 = unsafe { Rx::conjure() }; - (tx, rx0) - } -} - -impl Can { - /// Accesses the filter banks owned by this CAN peripheral. - /// - /// 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<'_, I> { - unsafe { MasterFilters::new(self.canregs) } - } -} - -/// Marker for Tx half -pub struct Tx { - _can: PhantomData, - pub(crate) registers: Registers, -} - -impl Tx -where - I: Instance, -{ - unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { - Self { - _can: PhantomData, - registers: Registers { canregs }, //canregs, - } - } - - /// Puts a CAN frame in a transmit mailbox for transmission on the bus. - /// - /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). - /// Transmit order is preserved for frames with identical priority. - /// - /// If all transmit mailboxes are full, and `frame` has a higher priority than the - /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is - /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as - /// [`TransmitStatus::dequeued_frame`]. - pub fn transmit(&mut self, frame: &Frame) -> nb::Result { - self.registers.transmit(frame) - } - - /// Attempts to abort the sending of a frame that is pending in a mailbox. - /// - /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be - /// aborted, this function has no effect and returns `false`. - /// - /// 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 { - self.registers.abort(mailbox) - } - - /// Returns `true` if no frame is pending for transmission. - pub fn is_idle(&self) -> bool { - self.registers.is_idle() - } - - /// Clears the request complete flag for all mailboxes. - pub fn clear_interrupt_flags(&mut self) { - self.registers.clear_interrupt_flags() - } -} - -/// Marker for Rx half -pub struct Rx { - _can: PhantomData, -} - -impl Rx -where - I: Instance, -{ - unsafe fn conjure() -> Self { - Self { _can: PhantomData } - } -} - -/// Identifies one of the two receive FIFOs. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Fifo { - /// First receive FIFO - Fifo0 = 0, - /// Second receive FIFO - Fifo1 = 1, -} - -/// Identifies one of the three transmit mailboxes. -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Mailbox { - /// Transmit mailbox 0 - Mailbox0 = 0, - /// Transmit mailbox 1 - Mailbox1 = 1, - /// Transmit mailbox 2 - Mailbox2 = 2, -} - -/// Contains information about a frame enqueued for transmission via [`Can::transmit`] or -/// [`Tx::transmit`]. -pub struct TransmitStatus { - dequeued_frame: Option, - mailbox: Mailbox, -} - -impl TransmitStatus { - /// Returns the lower-priority frame that was dequeued to make space for the new frame. - #[inline] - pub fn dequeued_frame(&self) -> Option<&Frame> { - self.dequeued_frame.as_ref() - } - - /// Returns the [`Mailbox`] the frame was enqueued in. - #[inline] - pub fn mailbox(&self) -> Mailbox { - self.mailbox - } -} diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bxcan/filter.rs similarity index 99% rename from embassy-stm32/src/can/bx/filter.rs rename to embassy-stm32/src/can/bxcan/filter.rs index 51766aa31..9940c7f50 100644 --- a/embassy-stm32/src/can/bx/filter.rs +++ b/embassy-stm32/src/can/bxcan/filter.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; -use crate::can::bx::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; +use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan/mod.rs similarity index 68% rename from embassy-stm32/src/can/bxcan.rs rename to embassy-stm32/src/can/bxcan/mod.rs index fd6a79092..65fd0e9c2 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -1,29 +1,27 @@ +pub mod filter; +mod registers; + use core::future::poll_fn; use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; use core::task::Poll; -pub mod bx; - -pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId}; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; +pub use embedded_can::{ExtendedId, Id, StandardId}; +use self::filter::MasterFilters; +use self::registers::{Registers, RxFifo}; +pub use super::common::{BufferedCanReceiver, BufferedCanSender}; +use super::frame::{Envelope, Frame}; +use super::util; +use crate::can::enums::{BusError, TryReadError}; use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals, Peripheral}; -pub mod enums; -pub mod frame; -pub mod util; -pub use frame::Envelope; - -mod common; -pub use self::common::{BufferedCanReceiver, BufferedCanSender}; - /// Interrupt handler. pub struct TxInterruptHandler { _phantom: PhantomData, @@ -80,9 +78,72 @@ impl interrupt::typelevel::Handler for SceInterrup } } +/// Configuration proxy returned by [`Can::modify_config`]. +pub struct CanConfig<'a, T: Instance> { + can: PhantomData<&'a mut T>, +} + +impl CanConfig<'_, T> { + /// Configures the bit timings. + /// + /// You can use to calculate the `btr` parameter. Enter + /// parameters as follows: + /// + /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). + /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). + /// - *Sample Point*: Should normally be left at the default value of 87.5%. + /// - *SJW*: Should normally be left at the default value of 1. + /// + /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` + /// parameter to this method. + pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { + Registers(T::regs()).set_bit_timing(bt); + self + } + + /// Configure the CAN bit rate. + /// + /// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing]. + pub fn set_bitrate(self, bitrate: u32) -> Self { + let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); + self.set_bit_timing(bit_timing) + } + + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + pub fn set_loopback(self, enabled: bool) -> Self { + Registers(T::regs()).set_loopback(enabled); + self + } + + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + pub fn set_silent(self, enabled: bool) -> Self { + Registers(T::regs()).set_silent(enabled); + self + } + + /// Enables or disables automatic retransmission of messages. + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// until it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + pub fn set_automatic_retransmit(self, enabled: bool) -> Self { + Registers(T::regs()).set_automatic_retransmit(enabled); + self + } +} + +impl Drop for CanConfig<'_, T> { + #[inline] + fn drop(&mut self) { + Registers(T::regs()).leave_init_mode(); + } +} + /// CAN driver pub struct Can<'d, T: Instance> { - can: crate::can::bx::Can>, + peri: PeripheralRef<'d, T>, } /// Error returned by `try_write` @@ -145,14 +206,25 @@ impl<'d, T: Instance> Can<'d, T> { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - let can = crate::can::bx::Can::builder(BxcanInstance(peri), T::regs()).leave_disabled(); - Self { can } + Registers(T::regs()).leave_init_mode(); + + Self { peri } } /// Set CAN bit rate. pub fn set_bitrate(&mut self, bitrate: u32) { let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); - self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); + self.modify_config().set_bit_timing(bit_timing); + } + + /// Configure bit timings and silent/loop-back mode. + /// + /// Calling this method will enter initialization mode. You must enable the peripheral + /// again afterwards with [`enable`](Self::enable). + pub fn modify_config(&mut self) -> CanConfig<'_, T> { + Registers(T::regs()).enter_init_mode(); + + CanConfig { can: PhantomData } } /// Enables the peripheral and synchronizes with the bus. @@ -160,7 +232,7 @@ impl<'d, T: Instance> Can<'d, T> { /// This will wait for 11 consecutive recessive bits (bus idle state). /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. pub async fn enable(&mut self) { - while self.registers.enable_non_blocking().is_err() { + while Registers(T::regs()).enable_non_blocking().is_err() { // SCE interrupt is only generated for entering sleep mode, but not leaving. // Yield to allow other tasks to execute while can bus is initializing. embassy_futures::yield_now().await; @@ -170,19 +242,19 @@ impl<'d, T: Instance> Can<'d, T> { /// 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) -> crate::can::bx::TransmitStatus { + pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { self.split().0.write(frame).await } /// Attempts to transmit a frame without blocking. /// /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. - pub fn try_write(&mut self, frame: &Frame) -> Result { + pub fn try_write(&mut self, frame: &Frame) -> Result { self.split().0.try_write(frame) } /// Waits for a specific transmit mailbox to become empty - pub async fn flush(&self, mb: crate::can::bx::Mailbox) { + pub async fn flush(&self, mb: Mailbox) { CanTx::::flush_inner(mb).await } @@ -196,6 +268,22 @@ impl<'d, T: Instance> Can<'d, T> { CanTx::::flush_all_inner().await } + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// 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) + } + + /// Returns `true` if no frame is pending for transmission. + pub fn is_transmitter_idle(&self) -> bool { + Registers(T::regs()).is_idle() + } + /// Read a CAN frame. /// /// If no CAN frame is in the RX buffer, this will wait until there is one. @@ -221,8 +309,14 @@ impl<'d, T: Instance> Can<'d, T> { /// /// Useful for doing separate transmit/receive tasks. pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { - let (tx, rx) = self.can.split_by_ref(); - (CanTx { tx }, CanRx { rx }) + ( + CanTx { + _peri: unsafe { self.peri.clone_unchecked() }, + }, + CanRx { + peri: unsafe { self.peri.clone_unchecked() }, + }, + ) } /// Return a buffered instance of driver. User must supply Buffers @@ -239,10 +333,13 @@ impl<'d, T: Instance> Can<'d, T> { } } -impl<'d, T: Instance> AsMut>> for Can<'d, T> { - /// Get mutable access to the lower-level driver from the `bxcan` crate. - fn as_mut(&mut self) -> &mut crate::can::bx::Can> { - &mut self.can +impl<'d, T: FilterOwner> Can<'d, T> { + /// Accesses the filter banks owned by this CAN peripheral. + /// + /// 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()) } } } @@ -288,17 +385,17 @@ 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> { - tx: crate::can::bx::Tx>, + _peri: PeripheralRef<'d, T>, } impl<'d, T: Instance> CanTx<'d, T> { /// 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) -> crate::can::bx::TransmitStatus { + pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { poll_fn(|cx| { T::state().tx_mode.register(cx.waker()); - if let Ok(status) = self.tx.transmit(frame) { + if let Ok(status) = Registers(T::regs()).transmit(frame) { return Poll::Ready(status); } @@ -310,11 +407,11 @@ impl<'d, T: Instance> CanTx<'d, T> { /// Attempts to transmit a frame without blocking. /// /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. - pub fn try_write(&mut self, frame: &Frame) -> Result { - self.tx.transmit(frame).map_err(|_| TryWriteError::Full) + pub fn try_write(&mut self, frame: &Frame) -> Result { + Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) } - async fn flush_inner(mb: crate::can::bx::Mailbox) { + async fn flush_inner(mb: Mailbox) { poll_fn(|cx| { T::state().tx_mode.register(cx.waker()); if T::regs().tsr().read().tme(mb.index()) { @@ -327,7 +424,7 @@ impl<'d, T: Instance> CanTx<'d, T> { } /// Waits for a specific transmit mailbox to become empty - pub async fn flush(&self, mb: crate::can::bx::Mailbox) { + pub async fn flush(&self, mb: Mailbox) { Self::flush_inner(mb).await } @@ -336,9 +433,9 @@ impl<'d, T: Instance> CanTx<'d, T> { T::state().tx_mode.register(cx.waker()); let tsr = T::regs().tsr().read(); - if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) - || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) - || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) + if tsr.tme(Mailbox::Mailbox0.index()) + || tsr.tme(Mailbox::Mailbox1.index()) + || tsr.tme(Mailbox::Mailbox2.index()) { return Poll::Ready(()); } @@ -358,9 +455,9 @@ impl<'d, T: Instance> CanTx<'d, T> { T::state().tx_mode.register(cx.waker()); let tsr = T::regs().tsr().read(); - if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) - && tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) - && tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) + if tsr.tme(Mailbox::Mailbox0.index()) + && tsr.tme(Mailbox::Mailbox1.index()) + && tsr.tme(Mailbox::Mailbox2.index()) { return Poll::Ready(()); } @@ -375,12 +472,28 @@ impl<'d, T: Instance> CanTx<'d, T> { Self::flush_all_inner().await } + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// 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) + } + + /// Returns `true` if no frame is pending for transmission. + pub fn is_idle(&self) -> bool { + Registers(T::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.tx, txb) + BufferedCanTx::new(self, txb) } } @@ -389,19 +502,19 @@ pub type TxBuf = Channel { - _tx: crate::can::bx::Tx>, + _tx: CanTx<'d, T>, tx_buf: &'static TxBuf, } impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { - fn new(_tx: crate::can::bx::Tx>, tx_buf: &'static TxBuf) -> Self { + fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf) -> Self { Self { _tx, tx_buf }.setup() } fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { - let tx_inner = self::common::ClassicBufferedTxInner { + let tx_inner = super::common::ClassicBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; T::mut_state().tx_mode = TxMode::Buffered(tx_inner); @@ -435,7 +548,7 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX /// CAN driver, receive half. #[allow(dead_code)] pub struct CanRx<'d, T: Instance> { - rx: crate::can::bx::Rx>, + peri: PeripheralRef<'d, T>, } impl<'d, T: Instance> CanRx<'d, T> { @@ -465,7 +578,7 @@ impl<'d, T: Instance> CanRx<'d, T> { self, rxb: &'static mut RxBuf, ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { - BufferedCanRx::new(self.rx, rxb) + BufferedCanRx::new(self, rxb) } } @@ -474,19 +587,19 @@ pub type RxBuf = Channel { - _rx: crate::can::bx::Rx>, + _rx: CanRx<'d, T>, 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 { + fn new(_rx: CanRx<'d, T>, 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 { + let rx_inner = super::common::ClassicBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; T::mut_state().rx_mode = RxMode::Buffered(rx_inner); @@ -511,8 +624,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE Err(e) => Err(TryReadError::BusError(e)), } } else { - let registers = crate::can::bx::Registers { canregs: T::regs() }; - if let Some(err) = registers.curr_error() { + if let Some(err) = Registers(T::regs()).curr_error() { return Err(TryReadError::BusError(err)); } else { Err(TryReadError::Empty) @@ -544,8 +656,6 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX } } -use crate::can::bx::RxFifo; - impl<'d, T: Instance> Drop for Can<'d, T> { fn drop(&mut self) { // Cannot call `free()` because it moves the instance. @@ -555,35 +665,62 @@ impl<'d, T: Instance> Drop for Can<'d, T> { } } -impl<'d, T: Instance> Deref for Can<'d, T> { - type Target = crate::can::bx::Can>; - - fn deref(&self) -> &Self::Target { - &self.can - } +/// Identifies one of the two receive FIFOs. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Fifo { + /// First receive FIFO + Fifo0 = 0, + /// Second receive FIFO + Fifo1 = 1, } -impl<'d, T: Instance> DerefMut for Can<'d, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.can - } +/// Identifies one of the three transmit mailboxes. +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Mailbox { + /// Transmit mailbox 0 + Mailbox0 = 0, + /// Transmit mailbox 1 + Mailbox1 = 1, + /// Transmit mailbox 2 + Mailbox2 = 2, } -use crate::can::enums::{BusError, TryReadError}; +/// Contains information about a frame enqueued for transmission via [`Can::transmit`] or +/// [`Tx::transmit`]. +pub struct TransmitStatus { + dequeued_frame: Option, + mailbox: Mailbox, +} + +impl TransmitStatus { + /// Returns the lower-priority frame that was dequeued to make space for the new frame. + #[inline] + pub fn dequeued_frame(&self) -> Option<&Frame> { + self.dequeued_frame.as_ref() + } + + /// Returns the [`Mailbox`] the frame was enqueued in. + #[inline] + pub fn mailbox(&self) -> Mailbox { + self.mailbox + } +} pub(crate) enum RxMode { NonBuffered(AtomicWaker), - Buffered(crate::can::_version::common::ClassicBufferedRxInner), + Buffered(super::common::ClassicBufferedRxInner), } impl RxMode { - pub fn on_interrupt(&self, fifo: crate::can::_version::bx::RxFifo) { + pub fn on_interrupt(&self, fifo: 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, + RxFifo::Fifo0 => 0usize, + RxFifo::Fifo1 => 1usize, }; T::regs().ier().write(|w| { w.set_fmpie(fifo_idx, false); @@ -591,10 +728,8 @@ impl RxMode { waker.wake(); } Self::Buffered(buf) => { - let regsisters = crate::can::bx::Registers { canregs: T::regs() }; - loop { - match regsisters.receive_fifo(fifo) { + match Registers(T::regs()).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)); @@ -628,13 +763,13 @@ impl RxMode { 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) { + let registers = Registers(T::regs()); + if let Some(msg) = registers.receive_fifo(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) { + } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) { T::regs().ier().write(|w| { w.set_fmpie(1, true); }); @@ -655,8 +790,7 @@ impl RxMode { Self::NonBuffered(waker) => { poll_fn(|cx| { waker.register(cx.waker()); - let registers = crate::can::bx::Registers { canregs: T::regs() }; - if registers.receive_frame_available() { + if Registers(T::regs()).receive_frame_available() { Poll::Ready(()) } else { Poll::Pending @@ -673,15 +807,13 @@ impl RxMode { enum TxMode { NonBuffered(AtomicWaker), - Buffered(self::common::ClassicBufferedTxInner), + Buffered(super::common::ClassicBufferedTxInner), } impl TxMode { pub fn buffer_free(&self) -> bool { let tsr = T::regs().tsr().read(); - tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) - || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) - || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) + tsr.tme(Mailbox::Mailbox0.index()) || tsr.tme(Mailbox::Mailbox1.index()) || tsr.tme(Mailbox::Mailbox2.index()) } pub fn on_interrupt(&self) { match &T::state().tx_mode { @@ -690,8 +822,7 @@ impl TxMode { while self.buffer_free::() { match buf.tx_receiver.try_receive() { Ok(frame) => { - let mut registers = crate::can::bx::Registers { canregs: T::regs() }; - _ = registers.transmit(&frame); + _ = Registers(T::regs()).transmit(&frame); } Err(_) => { break; @@ -738,7 +869,7 @@ trait SealedInstance { /// CAN instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + 'static { +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral + 'static { /// TX interrupt for this instance. type TXInterrupt: crate::interrupt::typelevel::Interrupt; /// RX0 interrupt for this instance. @@ -749,10 +880,35 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static { type SCEInterrupt: crate::interrupt::typelevel::Interrupt; } -/// BXCAN instance newtype. -pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); +/// A bxCAN instance that owns filter banks. +/// +/// In master-slave-instance setups, only the master instance owns the filter banks, and needs to +/// split some of them off for use by the slave instance. In that case, the master instance should +/// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement +/// [`Instance`]. +/// +/// In single-instance configurations, the instance owns all filter banks and they can not be split +/// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`]. +/// +/// # Safety +/// +/// This trait must only be implemented if the instance does, in fact, own its associated filter +/// banks, and `NUM_FILTER_BANKS` must be correct. +pub unsafe trait FilterOwner: Instance { + /// The total number of filter banks available to the instance. + /// + /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet. + const NUM_FILTER_BANKS: u8; +} -unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> {} +/// A bxCAN master instance that shares filter banks with a slave instance. +/// +/// In master-slave-instance setups, this trait should be implemented for the master instance. +/// +/// # Safety +/// +/// This trait must only be implemented when there is actually an associated slave instance. +pub unsafe trait MasterInstance: FilterOwner {} foreach_peripheral!( (can, $inst:ident) => { @@ -782,7 +938,7 @@ foreach_peripheral!( foreach_peripheral!( (can, CAN) => { - unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN> { + unsafe impl FilterOwner for peripherals::CAN { const NUM_FILTER_BANKS: u8 = 14; } }; @@ -797,19 +953,19 @@ foreach_peripheral!( ))] { // Most L4 devices and some F7 devices use the name "CAN1" // even if there is no "CAN2" peripheral. - unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { + unsafe impl FilterOwner for peripherals::CAN1 { const NUM_FILTER_BANKS: u8 = 14; } } else { - unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { + unsafe impl FilterOwner for peripherals::CAN1 { const NUM_FILTER_BANKS: u8 = 28; } - unsafe impl<'d> crate::can::bx::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {} + unsafe impl MasterInstance for peripherals::CAN1 {} } } }; (can, CAN3) => { - unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN3> { + unsafe impl FilterOwner for peripherals::CAN3 { const NUM_FILTER_BANKS: u8 = 14; } }; @@ -822,12 +978,12 @@ trait Index { fn index(&self) -> usize; } -impl Index for crate::can::bx::Mailbox { +impl Index for Mailbox { fn index(&self) -> usize { match self { - crate::can::bx::Mailbox::Mailbox0 => 0, - crate::can::bx::Mailbox::Mailbox1 => 1, - crate::can::bx::Mailbox::Mailbox2 => 2, + Mailbox::Mailbox0 => 0, + Mailbox::Mailbox1 => 1, + Mailbox::Mailbox2 => 2, } } } diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs new file mode 100644 index 000000000..732567797 --- /dev/null +++ b/embassy-stm32/src/can/bxcan/registers.rs @@ -0,0 +1,510 @@ +use core::cmp::Ordering; +use core::convert::Infallible; + +pub use embedded_can::{ExtendedId, Id, StandardId}; +use stm32_metapac::can::vals::Lec; + +use super::{Mailbox, TransmitStatus}; +use crate::can::enums::BusError; +use crate::can::frame::{Envelope, Frame, Header}; + +pub(crate) struct Registers(pub crate::pac::can::Can); + +impl Registers { + pub fn enter_init_mode(&mut self) { + self.0.mcr().modify(|reg| { + reg.set_sleep(false); + reg.set_inrq(true); + }); + loop { + let msr = self.0.msr().read(); + if !msr.slak() && msr.inak() { + break; + } + } + } + + // Leaves initialization mode, enters sleep mode. + pub fn leave_init_mode(&mut self) { + self.0.mcr().modify(|reg| { + reg.set_sleep(true); + reg.set_inrq(false); + }); + loop { + let msr = self.0.msr().read(); + if msr.slak() && !msr.inak() { + break; + } + } + } + + pub fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { + let prescaler = u16::from(bt.prescaler) & 0x1FF; + let seg1 = u8::from(bt.seg1); + let seg2 = u8::from(bt.seg2) & 0x7F; + let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; + self.0.btr().modify(|reg| { + reg.set_brp(prescaler - 1); + reg.set_ts(0, seg1 - 1); + reg.set_ts(1, seg2 - 1); + reg.set_sjw(sync_jump_width - 1); + }); + } + + /// Enables or disables silent mode: Disconnects the TX signal from the pin. + pub fn set_silent(&self, enabled: bool) { + let mode = match enabled { + false => stm32_metapac::can::vals::Silm::NORMAL, + true => stm32_metapac::can::vals::Silm::SILENT, + }; + self.0.btr().modify(|reg| reg.set_silm(mode)); + } + + /// Enables or disables automatic retransmission of messages. + /// + /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame + /// until it can be sent. Otherwise, it will try only once to send each frame. + /// + /// Automatic retransmission is enabled by default. + pub fn set_automatic_retransmit(&self, enabled: bool) { + self.0.mcr().modify(|reg| reg.set_nart(enabled)); + } + + /// Enables or disables loopback mode: Internally connects the TX and RX + /// signals together. + pub fn set_loopback(&self, enabled: bool) { + self.0.btr().modify(|reg| reg.set_lbkm(enabled)); + } + + /// Configures the automatic wake-up feature. + /// + /// This is turned off by default. + /// + /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and + /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming + /// frame. + #[allow(dead_code)] + pub fn set_automatic_wakeup(&mut self, enabled: bool) { + self.0.mcr().modify(|reg| reg.set_awum(enabled)); + } + + /// Leaves initialization mode and enables the peripheral (non-blocking version). + /// + /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed + /// if you want non-blocking initialization. + /// + /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself + /// in the background. The peripheral is enabled and ready to use when this method returns + /// successfully. + pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { + let msr = self.0.msr().read(); + if msr.slak() { + self.0.mcr().modify(|reg| { + reg.set_abom(true); + reg.set_sleep(false); + }); + Err(nb::Error::WouldBlock) + } else { + Ok(()) + } + } + + /// Puts the peripheral in a sleep mode to save power. + /// + /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. + #[allow(dead_code)] + pub fn sleep(&mut self) { + self.0.mcr().modify(|reg| { + reg.set_sleep(true); + reg.set_inrq(false); + }); + loop { + let msr = self.0.msr().read(); + if msr.slak() && !msr.inak() { + break; + } + } + } + + /// Wakes up from sleep mode. + /// + /// 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) { + self.0.mcr().modify(|reg| { + reg.set_sleep(false); + reg.set_inrq(false); + }); + loop { + let msr = self.0.msr().read(); + if !msr.slak() && !msr.inak() { + break; + } + } + } + + pub fn curr_error(&self) -> Option { + let err = { self.0.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 err.lec() != Lec::NOERROR { + return Some(match err.lec() { + Lec::STUFF => BusError::Stuff, + Lec::FORM => BusError::Form, + Lec::ACK => BusError::Acknowledge, + Lec::BITRECESSIVE => BusError::BitRecessive, + Lec::BITDOMINANT => BusError::BitDominant, + Lec::CRC => BusError::Crc, + Lec::CUSTOM => BusError::Software, + Lec::NOERROR => unreachable!(), + }); + } + None + } + + /// Puts a CAN frame in a transmit mailbox for transmission on the bus. + /// + /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). + /// Transmit order is preserved for frames with identical priority. + /// + /// If all transmit mailboxes are full, and `frame` has a higher priority than the + /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is + /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as + /// [`TransmitStatus::dequeued_frame`]. + pub fn transmit(&mut self, frame: &Frame) -> nb::Result { + // Get the index of the next free mailbox or the one with the lowest priority. + let tsr = self.0.tsr().read(); + let idx = tsr.code() as usize; + + let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); + let pending_frame = if frame_is_pending { + // High priority frames are transmitted first by the mailbox system. + // Frames with identical identifier shall be transmitted in FIFO order. + // The controller schedules pending frames of same priority based on the + // mailbox index instead. As a workaround check all pending mailboxes + // and only accept higher priority frames. + self.check_priority(0, frame.id().into())?; + self.check_priority(1, frame.id().into())?; + self.check_priority(2, frame.id().into())?; + + let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); + if all_frames_are_pending { + // No free mailbox is available. This can only happen when three frames with + // ascending priority (descending IDs) were requested for transmission and all + // of them are blocked by bus traffic with even higher priority. + // To prevent a priority inversion abort and replace the lowest priority frame. + self.read_pending_mailbox(idx) + } else { + // There was a free mailbox. + None + } + } else { + // All mailboxes are available: Send frame without performing any checks. + None + }; + + self.write_mailbox(idx, frame); + + let mailbox = match idx { + 0 => Mailbox::Mailbox0, + 1 => Mailbox::Mailbox1, + 2 => Mailbox::Mailbox2, + _ => unreachable!(), + }; + Ok(TransmitStatus { + dequeued_frame: pending_frame, + mailbox, + }) + } + + /// Returns `Ok` when the mailbox is free or if it contains pending frame with a + /// lower priority (higher ID) than the identifier `id`. + fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { + // Read the pending frame's id to check its priority. + assert!(idx < 3); + let tir = &self.0.tx(idx).tir().read(); + //let tir = &can.tx[idx].tir.read(); + + // Check the priority by comparing the identifiers. But first make sure the + // frame has not finished the transmission (`TXRQ` == 0) in the meantime. + if tir.txrq() && id <= IdReg::from_register(tir.0) { + // There's a mailbox whose priority is higher or equal + // the priority of the new frame. + return Err(nb::Error::WouldBlock); + } + + Ok(()) + } + + fn write_mailbox(&mut self, idx: usize, frame: &Frame) { + debug_assert!(idx < 3); + + let mb = self.0.tx(idx); + mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); + + mb.tdlr() + .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); + mb.tdhr() + .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); + let id: IdReg = frame.id().into(); + mb.tir().write(|w| { + w.0 = id.0; + w.set_txrq(true); + }); + } + + fn read_pending_mailbox(&mut self, idx: usize) -> Option { + if self.abort_by_index(idx) { + debug_assert!(idx < 3); + + let mb = self.0.tx(idx); + + let id = IdReg(mb.tir().read().0); + let mut data = [0xff; 8]; + data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); + data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); + let len = mb.tdtr().read().dlc(); + + Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) + } else { + // Abort request failed because the frame was already sent (or being sent) on + // the bus. All mailboxes are now free. This can happen for small prescaler + // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR + // has preempted the execution. + None + } + } + + /// Tries to abort a pending frame. Returns `true` when aborted. + fn abort_by_index(&mut self, idx: usize) -> bool { + self.0.tsr().write(|reg| reg.set_abrq(idx, true)); + + // Wait for the abort request to be finished. + loop { + let tsr = self.0.tsr().read(); + if false == tsr.abrq(idx) { + break tsr.txok(idx) == false; + } + } + } + + /// Attempts to abort the sending of a frame that is pending in a mailbox. + /// + /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be + /// aborted, this function has no effect and returns `false`. + /// + /// 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 { + // 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(); + let mailbox_empty = match mailbox { + Mailbox::Mailbox0 => tsr.tme(0), + Mailbox::Mailbox1 => tsr.tme(1), + Mailbox::Mailbox2 => tsr.tme(2), + }; + if mailbox_empty { + false + } else { + self.abort_by_index(mailbox as usize) + } + } + + /// Returns `true` if no frame is pending for transmission. + pub fn is_idle(&self) -> bool { + let tsr = self.0.tsr().read(); + tsr.tme(0) && tsr.tme(1) && tsr.tme(2) + } + + pub fn receive_frame_available(&self) -> bool { + if self.0.rfr(0).read().fmp() != 0 { + true + } else if self.0.rfr(1).read().fmp() != 0 { + true + } else { + false + } + } + + pub fn receive_fifo(&self, fifo: RxFifo) -> Option { + // Generate timestamp as early as possible + #[cfg(feature = "time")] + let ts = embassy_time::Instant::now(); + + use crate::pac::can::vals::Ide; + + let fifo_idx = match fifo { + RxFifo::Fifo0 => 0usize, + RxFifo::Fifo1 => 1usize, + }; + let rfr = self.0.rfr(fifo_idx); + let fifo = self.0.rx(fifo_idx); + + // If there are no pending messages, there is nothing to do + if rfr.read().fmp() == 0 { + return None; + } + + let rir = fifo.rir().read(); + let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { + embedded_can::StandardId::new(rir.stid()).unwrap().into() + } else { + let stid = (rir.stid() & 0x7FF) as u32; + let exid = rir.exid() & 0x3FFFF; + let id = (stid << 18) | (exid); + embedded_can::ExtendedId::new(id).unwrap().into() + }; + let rdtr = fifo.rdtr().read(); + let data_len = rdtr.dlc(); + let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE; + + #[cfg(not(feature = "time"))] + let ts = rdtr.time(); + + let mut data: [u8; 8] = [0; 8]; + data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); + data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); + + let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap(); + let envelope = Envelope { ts, frame }; + + rfr.modify(|v| v.set_rfom(true)); + + Some(envelope) + } +} + +/// Identifier of a CAN message. +/// +/// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a +/// extendended identifier (29bit , Range: 0..0x1FFFFFFF). +/// +/// The `Ord` trait can be used to determine the frame’s priority this ID +/// belongs to. +/// Lower identifier values have a higher priority. Additionally standard frames +/// have a higher priority than extended frames and data frames have a higher +/// priority than remote frames. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub(crate) struct IdReg(u32); + +impl IdReg { + const STANDARD_SHIFT: u32 = 21; + + const EXTENDED_SHIFT: u32 = 3; + + const IDE_MASK: u32 = 0x0000_0004; + + const RTR_MASK: u32 = 0x0000_0002; + + /// Creates a new standard identifier (11bit, Range: 0..0x7FF) + /// + /// Panics for IDs outside the allowed range. + fn new_standard(id: StandardId) -> Self { + Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT) + } + + /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF). + /// + /// Panics for IDs outside the allowed range. + fn new_extended(id: ExtendedId) -> IdReg { + Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK) + } + + fn from_register(reg: u32) -> IdReg { + Self(reg & 0xFFFF_FFFE) + } + + /// Returns the identifier. + fn to_id(self) -> Id { + if self.is_extended() { + Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) + } else { + Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) }) + } + } + + /// Returns the identifier. + fn id(self) -> embedded_can::Id { + if self.is_extended() { + embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT) + .unwrap() + .into() + } else { + embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16) + .unwrap() + .into() + } + } + + /// Returns `true` if the identifier is an extended identifier. + fn is_extended(self) -> bool { + self.0 & Self::IDE_MASK != 0 + } + + /// Returns `true` if the identifer is part of a remote frame (RTR bit set). + fn rtr(self) -> bool { + self.0 & Self::RTR_MASK != 0 + } +} + +impl From<&embedded_can::Id> for IdReg { + fn from(eid: &embedded_can::Id) -> Self { + match eid { + embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()), + embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()), + } + } +} + +impl From for embedded_can::Id { + fn from(idr: IdReg) -> Self { + idr.id() + } +} + +/// `IdReg` is ordered by priority. +impl Ord for IdReg { + fn cmp(&self, other: &Self) -> Ordering { + // When the IDs match, data frames have priority over remote frames. + let rtr = self.rtr().cmp(&other.rtr()).reverse(); + + let id_a = self.to_id(); + let id_b = other.to_id(); + match (id_a, id_b) { + (Id::Standard(a), Id::Standard(b)) => { + // Lower IDs have priority over higher IDs. + a.as_raw().cmp(&b.as_raw()).reverse().then(rtr) + } + (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr), + (Id::Standard(a), Id::Extended(b)) => { + // Standard frames have priority over extended frames if their Base IDs match. + a.as_raw() + .cmp(&b.standard_id().as_raw()) + .reverse() + .then(Ordering::Greater) + } + (Id::Extended(a), Id::Standard(b)) => { + a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less) + } + } + } +} + +impl PartialOrd for IdReg { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub(crate) enum RxFifo { + Fifo0, + Fifo1, +} diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 570761b19..a54b54f6e 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -1,7 +1,7 @@ use embassy_sync::channel::{DynamicReceiver, DynamicSender}; -use crate::can::_version::enums::*; -use crate::can::_version::frame::*; +use super::enums::*; +use super::frame::*; pub(crate) struct ClassicBufferedRxInner { pub rx_sender: DynamicSender<'static, Result>, diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 2ccf4b093..e31821ca2 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -14,19 +14,15 @@ use crate::interrupt::typelevel::Interrupt; use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals, Peripheral}; -mod common; -pub mod enums; pub(crate) mod fd; -pub mod frame; -mod util; -use enums::*; -use fd::config::*; -use fd::filter::*; -pub use fd::{config, filter}; -use frame::*; - -pub use self::common::{BufferedCanReceiver, BufferedCanSender}; +use self::fd::config::*; +use self::fd::filter::*; +pub use self::fd::{config, filter}; +pub use super::common::{BufferedCanReceiver, BufferedCanSender}; +use super::enums::*; +use super::frame::*; +use super::util; /// Timestamp for incoming packets. Use Embassy time when enabled. #[cfg(feature = "time")] @@ -439,10 +435,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> 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 { + let rx_inner = super::common::ClassicBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; - let tx_inner = self::common::ClassicBufferedTxInner { + let tx_inner = super::common::ClassicBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); @@ -555,10 +551,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { - let rx_inner = self::common::FdBufferedRxInner { + let rx_inner = super::common::FdBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; - let tx_inner = self::common::FdBufferedTxInner { + let tx_inner = super::common::FdBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); @@ -649,8 +645,8 @@ impl<'c, 'd, T: Instance> CanRx<'d, T> { enum RxMode { NonBuffered(AtomicWaker), - ClassicBuffered(self::common::ClassicBufferedRxInner), - FdBuffered(self::common::FdBufferedRxInner), + ClassicBuffered(super::common::ClassicBufferedRxInner), + FdBuffered(super::common::FdBufferedRxInner), } impl RxMode { @@ -758,8 +754,8 @@ impl RxMode { enum TxMode { NonBuffered(AtomicWaker), - ClassicBuffered(self::common::ClassicBufferedTxInner), - FdBuffered(self::common::FdBufferedTxInner), + ClassicBuffered(super::common::ClassicBufferedTxInner), + FdBuffered(super::common::FdBufferedTxInner), } impl TxMode { diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs index 915edb3a6..410a6bfcb 100644 --- a/embassy-stm32/src/can/mod.rs +++ b/embassy-stm32/src/can/mod.rs @@ -1,7 +1,14 @@ //! Controller Area Network (CAN) #![macro_use] -#[cfg_attr(can_bxcan, path = "bxcan.rs")] +#[cfg_attr(can_bxcan, path = "bxcan/mod.rs")] #[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")] mod _version; pub use _version::*; + +mod common; +pub mod enums; +pub mod frame; +pub mod util; + +pub use frame::Frame; diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index 90cb9e46b..1c13d623d 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -3,8 +3,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::can::frame::Envelope; use embassy_stm32::can::{ - filter, Can, Envelope, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, + filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, TxInterruptHandler, }; use embassy_stm32::peripherals::CAN; @@ -55,17 +56,13 @@ async fn main(_spawner: Spawner) { let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); - can.as_mut() - .modify_filters() + can.modify_filters() .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all()); - can.as_mut() - .modify_config() + can.modify_config() .set_loopback(false) .set_silent(false) - .leave_disabled(); - - can.set_bitrate(250_000); + .set_bitrate(250_000); can.enable().await; let mut i: u8 = 0; diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index 71b9453eb..cedc057a7 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs @@ -35,17 +35,12 @@ async fn main(_spawner: Spawner) { let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); - can.as_mut() - .modify_filters() - .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); - can.as_mut() - .modify_config() + can.modify_config() .set_loopback(true) // Receive own frames .set_silent(true) - .leave_disabled(); - - can.set_bitrate(1_000_000); + .set_bitrate(1_000_000); can.enable().await; diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 221ac2a05..e32b4d3df 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -47,20 +47,18 @@ async fn main(spawner: Spawner) { static CAN: StaticCell> = StaticCell::new(); let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); - can.as_mut() - .modify_filters() - .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); - can.as_mut() - .modify_config() + can.modify_config() .set_bit_timing(can::util::NominalBitTiming { prescaler: NonZeroU16::new(2).unwrap(), seg1: NonZeroU8::new(13).unwrap(), seg2: NonZeroU8::new(2).unwrap(), sync_jump_width: NonZeroU8::new(1).unwrap(), }) // http://www.bittiming.can-wiki.info/ - .set_loopback(true) - .enable(); + .set_loopback(true); + + can.enable().await; let (tx, mut rx) = can.split(); diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index 74d84c42f..551764458 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -8,9 +8,10 @@ mod common; use common::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; -use embassy_stm32::can::bx::filter::Mask32; -use embassy_stm32::can::bx::Fifo; -use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; +use embassy_stm32::can::filter::Mask32; +use embassy_stm32::can::{ + Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, +}; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN1; use embassy_time::Duration; @@ -51,17 +52,15 @@ async fn main(_spawner: Spawner) { info!("Configuring can..."); - can.as_mut() - .modify_filters() - .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); - can.set_bitrate(1_000_000); - can.as_mut() - .modify_config() + can.modify_config() .set_loopback(true) // Receive own frames .set_silent(true) // .set_bit_timing(0x001c0003) - .enable(); + .set_bitrate(1_000_000); + + can.enable().await; info!("Can configured");