From c8936edb6c13eb099dfb31a4a51be2dd3bb4661e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 2 Apr 2024 01:29:52 +0200 Subject: 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/filter.rs | 475 -------------- embassy-stm32/src/can/bx/mod.rs | 1010 ------------------------------ embassy-stm32/src/can/bxcan.rs | 833 ------------------------ embassy-stm32/src/can/bxcan/filter.rs | 475 ++++++++++++++ embassy-stm32/src/can/bxcan/mod.rs | 989 +++++++++++++++++++++++++++++ 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 +- 13 files changed, 2021 insertions(+), 2373 deletions(-) delete mode 100644 embassy-stm32/src/can/bx/filter.rs delete mode 100644 embassy-stm32/src/can/bx/mod.rs delete mode 100644 embassy-stm32/src/can/bxcan.rs create mode 100644 embassy-stm32/src/can/bxcan/filter.rs create mode 100644 embassy-stm32/src/can/bxcan/mod.rs create mode 100644 embassy-stm32/src/can/bxcan/registers.rs diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bx/filter.rs deleted file mode 100644 index 51766aa31..000000000 --- a/embassy-stm32/src/can/bx/filter.rs +++ /dev/null @@ -1,475 +0,0 @@ -//! Filter bank API. - -use core::marker::PhantomData; - -use crate::can::bx::{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 -const F16_RTR: u16 = 0b10000; -const F16_IDE: u16 = 0b01000; - -/// A 16-bit filter list entry. -/// -/// This can match data and remote frames using standard IDs. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ListEntry16(u16); - -/// A 32-bit filter list entry. -/// -/// This can match data and remote frames using extended or standard IDs. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ListEntry32(u32); - -/// A 16-bit identifier mask. -#[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Mask16 { - id: u16, - mask: u16, -} - -/// A 32-bit identifier mask. -#[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Mask32 { - id: u32, - mask: u32, -} - -impl ListEntry16 { - /// Creates a filter list entry that accepts data frames with the given standard ID. - /// - /// This entry will *not* accept remote frames with the same ID. - pub fn data_frames_with_id(id: StandardId) -> Self { - Self(id.as_raw() << 5) - } - - /// Creates a filter list entry that accepts remote frames with the given standard ID. - pub fn remote_frames_with_id(id: StandardId) -> Self { - Self(id.as_raw() << 5 | F16_RTR) - } -} - -impl ListEntry32 { - /// Creates a filter list entry that accepts data frames with the given ID. - /// - /// This entry will *not* accept remote frames with the same ID. - /// - /// The filter will only accept *either* standard *or* extended frames, depending on `id`. - pub fn data_frames_with_id(id: impl Into) -> Self { - match id.into() { - Id::Standard(id) => Self(u32::from(id.as_raw()) << 21), - Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE), - } - } - - /// Creates a filter list entry that accepts remote frames with the given ID. - pub fn remote_frames_with_id(id: impl Into) -> Self { - match id.into() { - Id::Standard(id) => Self(u32::from(id.as_raw()) << 21 | F32_RTR), - Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE | F32_RTR), - } - } -} - -impl Mask16 { - /// Creates a 16-bit identifier mask that accepts all frames. - /// - /// This will accept both standard and extended data and remote frames with any ID. - pub fn accept_all() -> Self { - Self { id: 0, mask: 0 } - } - - /// Creates a 16-bit identifier mask that accepts all frames with the given standard - /// ID and mask combination. - /// - /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` - /// - /// A mask of all all ones (`0x7FF`) matches an exact ID, a mask of 0 matches all IDs. - /// - /// Both data and remote frames with `id` will be accepted. Any extended frames will be - /// rejected. - pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self { - Self { - id: id.as_raw() << 5, - mask: mask.as_raw() << 5 | F16_IDE, // also require IDE = 0 - } - } - - /// Make the filter accept data frames only. - pub fn data_frames_only(&mut self) -> &mut Self { - self.id &= !F16_RTR; // RTR = 0 - self.mask |= F16_RTR; - self - } - - /// Make the filter accept remote frames only. - pub fn remote_frames_only(&mut self) -> &mut Self { - self.id |= F16_RTR; // RTR = 1 - self.mask |= F16_RTR; - self - } -} - -impl Mask32 { - /// Creates a 32-bit identifier mask that accepts all frames. - /// - /// This will accept both standard and extended data and remote frames with any ID. - pub fn accept_all() -> Self { - Self { id: 0, mask: 0 } - } - - /// Creates a 32-bit identifier mask that accepts all frames with the given extended - /// ID and mask combination. - /// - /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` - /// - /// A mask of all all ones (`0x1FFF_FFFF`) matches an exact ID, a mask of 0 matches all IDs. - /// - /// Both data and remote frames with `id` will be accepted. Standard frames will be rejected. - pub fn frames_with_ext_id(id: ExtendedId, mask: ExtendedId) -> Self { - Self { - id: id.as_raw() << 3 | F32_IDE, - mask: mask.as_raw() << 3 | F32_IDE, // also require IDE = 1 - } - } - - /// Creates a 32-bit identifier mask that accepts all frames with the given standard - /// ID and mask combination. - /// - /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` - /// - /// A mask of all all ones (`0x7FF`) matches the exact ID, a mask of 0 matches all IDs. - /// - /// Both data and remote frames with `id` will be accepted. Extended frames will be rejected. - pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self { - Self { - id: u32::from(id.as_raw()) << 21, - mask: u32::from(mask.as_raw()) << 21 | F32_IDE, // also require IDE = 0 - } - } - - /// Make the filter accept data frames only. - pub fn data_frames_only(&mut self) -> &mut Self { - self.id &= !F32_RTR; // RTR = 0 - self.mask |= F32_RTR; - self - } - - /// Make the filter accept remote frames only. - pub fn remote_frames_only(&mut self) -> &mut Self { - self.id |= F32_RTR; // RTR = 1 - self.mask |= F32_RTR; - self - } -} - -/// The configuration of a filter bank. -#[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum BankConfig { - /// Specify up to 4 exact standard CAN ID's. - List16([ListEntry16; 4]), - /// Specify up to 2 exact standard or extended CAN ID's. - List32([ListEntry32; 2]), - /// Specify up to 2 standard ID's with masks. - Mask16([Mask16; 2]), - /// Specify a single extended ID with mask. - Mask32(Mask32), -} - -impl From<[ListEntry16; 4]> for BankConfig { - #[inline] - fn from(entries: [ListEntry16; 4]) -> Self { - Self::List16(entries) - } -} - -impl From<[ListEntry32; 2]> for BankConfig { - #[inline] - fn from(entries: [ListEntry32; 2]) -> Self { - Self::List32(entries) - } -} - -impl From<[Mask16; 2]> for BankConfig { - #[inline] - fn from(entries: [Mask16; 2]) -> Self { - Self::Mask16(entries) - } -} - -impl From for BankConfig { - #[inline] - fn from(filter: Mask32) -> Self { - Self::Mask32(filter) - } -} - -/// Interface to the filter banks of a CAN peripheral. -pub struct MasterFilters<'a, I: FilterOwner> { - /// Number of assigned filter banks. - /// - /// On chips with splittable filter banks, this value can be dynamic. - bank_count: u8, - _can: PhantomData<&'a mut I>, - canregs: crate::pac::can::Can, -} - -// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it -// exists. -impl MasterFilters<'_, I> { - pub(crate) unsafe fn new(canregs: crate::pac::can::Can) -> Self { - // Enable initialization mode. - canregs.fmr().modify(|reg| reg.set_finit(true)); - - // Read the filter split value. - let bank_count = canregs.fmr().read().can2sb(); - - // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all - // of them to the master peripheral, and in devices with 28, assigns them 50/50 to - // master/slave instances) - - Self { - bank_count, - _can: PhantomData, - canregs, - } - } - - fn banks_imm(&self) -> FilterBanks { - FilterBanks { - start_idx: 0, - bank_count: self.bank_count, - canregs: self.canregs, - } - } - - /// Returns the number of filter banks currently assigned to this instance. - /// - /// Chips with splittable filter banks may start out with some banks assigned to the master - /// instance and some assigned to the slave instance. - pub fn num_banks(&self) -> u8 { - self.bank_count - } - - /// Disables all enabled filter banks. - /// - /// This causes all incoming frames to be disposed. - pub fn clear(&mut self) -> &mut Self { - self.banks_imm().clear(); - self - } - - /// Disables a filter bank. - /// - /// If `index` is out of bounds, this will panic. - pub fn disable_bank(&mut self, index: u8) -> &mut Self { - self.banks_imm().disable(index); - self - } - - /// Configures a filter bank according to `config` and enables it. - /// - /// Each filter bank is associated with one of the two RX FIFOs, configured by the [`Fifo`] - /// passed to this function. In the event that both FIFOs are configured to accept an incoming - /// frame, the accepting filter bank with the lowest index wins. The FIFO state is ignored, so - /// if the FIFO is full, it will overflow, even if the other FIFO is also configured to accept - /// the frame. - /// - /// # Parameters - /// - /// - `index`: the filter index. - /// - `fifo`: the receive FIFO the filter should pass accepted messages to. - /// - `config`: the filter configuration. - pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into) -> &mut Self { - self.banks_imm().enable(index, fifo, config.into()); - self - } -} - -impl MasterFilters<'_, I> { - /// Sets the index at which the filter banks owned by the slave peripheral start. - pub fn set_split(&mut self, split_index: u8) -> &mut Self { - assert!(split_index <= I::NUM_FILTER_BANKS); - self.canregs.fmr().modify(|reg| reg.set_can2sb(split_index)); - self.bank_count = split_index; - self - } - - /// Accesses the filters assigned to the slave peripheral. - pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> { - // NB: This mutably borrows `self`, so it has full access to the filter bank registers. - SlaveFilters { - start_idx: self.bank_count, - bank_count: I::NUM_FILTER_BANKS - self.bank_count, - _can: PhantomData, - canregs: self.canregs, - } - } -} - -impl Drop for MasterFilters<'_, I> { - #[inline] - fn drop(&mut self) { - // Leave initialization mode. - self.canregs.fmr().modify(|regs| regs.set_finit(false)); - } -} - -/// Interface to the filter banks assigned to a slave peripheral. -pub struct SlaveFilters<'a, I: Instance> { - start_idx: u8, - bank_count: u8, - _can: PhantomData<&'a mut I>, - canregs: crate::pac::can::Can, -} - -impl SlaveFilters<'_, I> { - fn banks_imm(&self) -> FilterBanks { - FilterBanks { - start_idx: self.start_idx, - bank_count: self.bank_count, - canregs: self.canregs, - } - } - - /// Returns the number of filter banks currently assigned to this instance. - /// - /// Chips with splittable filter banks may start out with some banks assigned to the master - /// instance and some assigned to the slave instance. - pub fn num_banks(&self) -> u8 { - self.bank_count - } - - /// Disables all enabled filter banks. - /// - /// This causes all incoming frames to be disposed. - pub fn clear(&mut self) -> &mut Self { - self.banks_imm().clear(); - self - } - - /// Disables a filter bank. - /// - /// If `index` is out of bounds, this will panic. - pub fn disable_bank(&mut self, index: u8) -> &mut Self { - self.banks_imm().disable(index); - self - } - - /// Configures a filter bank according to `config` and enables it. - /// - /// # Parameters - /// - /// - `index`: the filter index. - /// - `fifo`: the receive FIFO the filter should pass accepted messages to. - /// - `config`: the filter configuration. - pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into) -> &mut Self { - self.banks_imm().enable(index, fifo, config.into()); - self - } -} - -struct FilterBanks { - start_idx: u8, - bank_count: u8, - canregs: crate::pac::can::Can, -} - -impl FilterBanks { - fn clear(&mut self) { - let mask = filter_bitmask(self.start_idx, self.bank_count); - - self.canregs.fa1r().modify(|reg| { - for i in 0..28usize { - if (0x01u32 << i) & mask != 0 { - reg.set_fact(i, false); - } - } - }); - } - - fn assert_bank_index(&self, index: u8) { - assert!((self.start_idx..self.start_idx + self.bank_count).contains(&index)); - } - - fn disable(&mut self, index: u8) { - self.assert_bank_index(index); - self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, false)) - } - - fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) { - self.assert_bank_index(index); - - // Configure mode. - let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_)); - self.canregs.fm1r().modify(|reg| reg.set_fbm(index as usize, mode)); - - // Configure scale. - let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_)); - self.canregs.fs1r().modify(|reg| reg.set_fsc(index as usize, scale)); - - // Configure filter register. - let (fxr1, fxr2); - match config { - BankConfig::List16([a, b, c, d]) => { - fxr1 = (u32::from(b.0) << 16) | u32::from(a.0); - fxr2 = (u32::from(d.0) << 16) | u32::from(c.0); - } - BankConfig::List32([a, b]) => { - fxr1 = a.0; - fxr2 = b.0; - } - BankConfig::Mask16([a, b]) => { - fxr1 = (u32::from(a.mask) << 16) | u32::from(a.id); - fxr2 = (u32::from(b.mask) << 16) | u32::from(b.id); - } - BankConfig::Mask32(a) => { - fxr1 = a.id; - fxr2 = a.mask; - } - }; - let bank = self.canregs.fb(index as usize); - bank.fr1().write(|w| w.0 = fxr1); - bank.fr2().write(|w| w.0 = fxr2); - - // Assign to the right FIFO - self.canregs.ffa1r().modify(|reg| { - reg.set_ffa( - index as usize, - match fifo { - Fifo::Fifo0 => false, - Fifo::Fifo1 => true, - }, - ) - }); - - // Set active. - self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, true)) - } -} - -/// Computes a bitmask for per-filter-bank registers that only includes filters in the given range. -fn filter_bitmask(start_idx: u8, bank_count: u8) -> u32 { - let count_mask = (1 << bank_count) - 1; // `bank_count` 1-bits - count_mask << start_idx -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_filter_bitmask() { - assert_eq!(filter_bitmask(0, 1), 0x1); - assert_eq!(filter_bitmask(1, 1), 0b10); - assert_eq!(filter_bitmask(0, 4), 0xf); - assert_eq!(filter_bitmask(1, 3), 0xe); - assert_eq!(filter_bitmask(8, 1), 0x100); - assert_eq!(filter_bitmask(8, 4), 0xf00); - } -} 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/bxcan.rs b/embassy-stm32/src/can/bxcan.rs deleted file mode 100644 index fd6a79092..000000000 --- a/embassy-stm32/src/can/bxcan.rs +++ /dev/null @@ -1,833 +0,0 @@ -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; - -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, -} - -impl interrupt::typelevel::Handler for TxInterruptHandler { - unsafe fn on_interrupt() { - T::regs().tsr().write(|v| { - v.set_rqcp(0, true); - v.set_rqcp(1, true); - v.set_rqcp(2, true); - }); - T::state().tx_mode.on_interrupt::(); - } -} - -/// RX0 interrupt handler. -pub struct Rx0InterruptHandler { - _phantom: PhantomData, -} - -impl interrupt::typelevel::Handler for Rx0InterruptHandler { - unsafe fn on_interrupt() { - T::state().rx_mode.on_interrupt::(RxFifo::Fifo0); - } -} - -/// RX1 interrupt handler. -pub struct Rx1InterruptHandler { - _phantom: PhantomData, -} - -impl interrupt::typelevel::Handler for Rx1InterruptHandler { - unsafe fn on_interrupt() { - T::state().rx_mode.on_interrupt::(RxFifo::Fifo1); - } -} - -/// SCE interrupt handler. -pub struct SceInterruptHandler { - _phantom: PhantomData, -} - -impl interrupt::typelevel::Handler for SceInterruptHandler { - unsafe fn on_interrupt() { - // info!("sce irq"); - let msr = T::regs().msr(); - let msr_val = msr.read(); - - if msr_val.erri() { - msr.modify(|v| v.set_erri(true)); - T::state().err_waker.wake(); - } - } -} - -/// CAN driver -pub struct Can<'d, T: Instance> { - can: crate::can::bx::Can>, -} - -/// Error returned by `try_write` -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum TryWriteError { - /// All transmit mailboxes are full - Full, -} - -impl<'d, T: Instance> Can<'d, T> { - /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. - /// You must call [Can::enable_non_blocking] to use the peripheral. - pub fn new( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, - _irqs: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, - ) -> Self { - into_ref!(peri, rx, tx); - - rx.set_as_af(rx.af_num(), AFType::Input); - tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - - T::enable_and_reset(); - - { - T::regs().ier().write(|w| { - w.set_errie(true); - w.set_fmpie(0, true); - w.set_fmpie(1, true); - w.set_tmeie(true); - }); - - T::regs().mcr().write(|w| { - // Enable timestamps on rx messages - - w.set_ttcm(true); - }); - } - - unsafe { - T::TXInterrupt::unpend(); - T::TXInterrupt::enable(); - - T::RX0Interrupt::unpend(); - T::RX0Interrupt::enable(); - - T::RX1Interrupt::unpend(); - T::RX1Interrupt::enable(); - - T::SCEInterrupt::unpend(); - T::SCEInterrupt::enable(); - } - - 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 } - } - - /// 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(); - } - - /// Enables the peripheral and synchronizes with the bus. - /// - /// 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() { - // 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; - } - } - - /// 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 { - 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 { - 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) { - CanTx::::flush_inner(mb).await - } - - /// Waits until any of the transmit mailboxes become empty - pub async fn flush_any(&self) { - CanTx::::flush_any_inner().await - } - - /// Waits until all of the transmit mailboxes become empty - pub async fn flush_all(&self) { - CanTx::::flush_all_inner().await - } - - /// Read a CAN frame. - /// - /// If no CAN frame is in the RX buffer, this will wait until there is one. - /// - /// Returns a tuple of the time the message was received and the message frame - pub async fn read(&mut self) -> Result { - T::state().rx_mode.read::().await - } - - /// Attempts to read a CAN frame without blocking. - /// - /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. - pub fn try_read(&mut self) -> Result { - T::state().rx_mode.try_read::() - } - - /// Waits while receive queue is empty. - pub async fn wait_not_empty(&mut self) { - T::state().rx_mode.wait_not_empty::().await - } - - /// Split the CAN driver into transmit and receive halves. - /// - /// Useful for doing separate transmit/receive tasks. - pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { - let (tx, rx) = self.can.split_by_ref(); - (CanTx { tx }, CanRx { rx }) - } - - /// Return a buffered instance of driver. User must supply Buffers - pub fn buffered<'c, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( - &'c mut self, - txb: &'static mut TxBuf, - rxb: &'static mut RxBuf, - ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { - let (tx, rx) = self.split(); - BufferedCan { - tx: tx.buffered(txb), - rx: rx.buffered(rxb), - } - } -} - -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 - } -} - -/// Buffered CAN driver. -pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { - tx: BufferedCanTx<'d, T, TX_BUF_SIZE>, - rx: BufferedCanRx<'d, T, RX_BUF_SIZE>, -} - -impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { - /// Async write frame to TX buffer. - pub async fn write(&mut self, frame: &Frame) { - self.tx.write(frame).await - } - - /// Returns a sender that can be used for sending CAN frames. - pub fn writer(&self) -> BufferedCanSender { - self.tx.writer() - } - - /// Async read frame from RX buffer. - pub async fn read(&mut self) -> Result { - self.rx.read().await - } - - /// Attempts to read a CAN frame without blocking. - /// - /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. - pub fn try_read(&mut self) -> Result { - self.rx.try_read() - } - - /// Waits while receive queue is empty. - pub async fn wait_not_empty(&mut self) { - self.rx.wait_not_empty().await - } - - /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. - pub fn reader(&self) -> BufferedCanReceiver { - self.rx.reader() - } -} - -/// CAN driver, transmit half. -pub struct CanTx<'d, T: Instance> { - tx: crate::can::bx::Tx>, -} - -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 { - poll_fn(|cx| { - T::state().tx_mode.register(cx.waker()); - if let Ok(status) = self.tx.transmit(frame) { - return Poll::Ready(status); - } - - Poll::Pending - }) - .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 { - self.tx.transmit(frame).map_err(|_| TryWriteError::Full) - } - - async fn flush_inner(mb: crate::can::bx::Mailbox) { - poll_fn(|cx| { - T::state().tx_mode.register(cx.waker()); - if T::regs().tsr().read().tme(mb.index()) { - return Poll::Ready(()); - } - - Poll::Pending - }) - .await; - } - - /// Waits for a specific transmit mailbox to become empty - pub async fn flush(&self, mb: crate::can::bx::Mailbox) { - Self::flush_inner(mb).await - } - - async fn flush_any_inner() { - poll_fn(|cx| { - 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()) - { - return Poll::Ready(()); - } - - Poll::Pending - }) - .await; - } - - /// Waits until any of the transmit mailboxes become empty - pub async fn flush_any(&self) { - Self::flush_any_inner().await - } - - async fn flush_all_inner() { - poll_fn(|cx| { - 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()) - { - return Poll::Ready(()); - } - - Poll::Pending - }) - .await; - } - - /// Waits until all of the transmit mailboxes become empty - pub async fn flush_all(&self) { - Self::flush_all_inner().await - } - - /// 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) - } -} - -/// User supplied buffer for TX buffering -pub type TxBuf = Channel; - -/// Buffered CAN driver, transmit half. -pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { - _tx: crate::can::bx::Tx>, - 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 { - 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 { - tx_receiver: self.tx_buf.receiver().into(), - }; - T::mut_state().tx_mode = TxMode::Buffered(tx_inner); - }); - self - } - - /// Async write frame to TX buffer. - pub async fn write(&mut self, frame: &Frame) { - self.tx_buf.send(*frame).await; - T::TXInterrupt::pend(); // Wake for Tx - } - - /// Returns a sender that can be used for sending CAN frames. - pub fn writer(&self) -> BufferedCanSender { - BufferedCanSender { - tx_buf: self.tx_buf.sender().into(), - waker: T::TXInterrupt::pend, - } - } -} - -impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { - fn drop(&mut self) { - critical_section::with(|_| unsafe { - T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - }); - } -} - -/// CAN driver, receive half. -#[allow(dead_code)] -pub struct CanRx<'d, T: Instance> { - rx: crate::can::bx::Rx>, -} - -impl<'d, T: Instance> CanRx<'d, T> { - /// Read a CAN frame. - /// - /// If no CAN frame is in the RX buffer, this will wait until there is one. - /// - /// Returns a tuple of the time the message was received and the message frame - pub async fn read(&mut self) -> Result { - T::state().rx_mode.read::().await - } - - /// Attempts to read a CAN frame without blocking. - /// - /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. - pub fn try_read(&mut self) -> Result { - T::state().rx_mode.try_read::() - } - - /// Waits while receive queue is empty. - pub async fn wait_not_empty(&mut self) { - T::state().rx_mode.wait_not_empty::().await - } - - /// Return a buffered instance of driver. User must supply Buffers - pub fn buffered( - self, - rxb: &'static mut RxBuf, - ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { - BufferedCanRx::new(self.rx, rxb) - } -} - -/// User supplied buffer for RX Buffering -pub type RxBuf = Channel, BUF_SIZE>; - -/// CAN driver, receive half in Buffered mode. -pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { - _rx: crate::can::bx::Rx>, - rx_buf: &'static RxBuf, -} - -impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { - fn new(_rx: crate::can::bx::Rx>, rx_buf: &'static RxBuf) -> Self { - BufferedCanRx { _rx, rx_buf }.setup() - } - - fn setup(self) -> Self { - // We don't want interrupts being processed while we change modes. - critical_section::with(|_| unsafe { - let rx_inner = self::common::ClassicBufferedRxInner { - rx_sender: self.rx_buf.sender().into(), - }; - T::mut_state().rx_mode = RxMode::Buffered(rx_inner); - }); - self - } - - /// Async read frame from RX buffer. - pub async fn read(&mut self) -> Result { - self.rx_buf.receive().await - } - - /// Attempts to read a CAN frame without blocking. - /// - /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. - pub fn try_read(&mut self) -> Result { - match &T::state().rx_mode { - RxMode::Buffered(_) => { - if let Ok(result) = self.rx_buf.try_receive() { - match result { - Ok(envelope) => Ok(envelope), - Err(e) => Err(TryReadError::BusError(e)), - } - } else { - let registers = crate::can::bx::Registers { canregs: T::regs() }; - if let Some(err) = registers.curr_error() { - return Err(TryReadError::BusError(err)); - } else { - Err(TryReadError::Empty) - } - } - } - _ => { - panic!("Bad Mode") - } - } - } - - /// Waits while receive queue is empty. - pub async fn wait_not_empty(&mut self) { - poll_fn(|cx| self.rx_buf.poll_ready_to_receive(cx)).await - } - - /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. - pub fn reader(&self) -> BufferedCanReceiver { - self.rx_buf.receiver().into() - } -} - -impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { - fn drop(&mut self) { - critical_section::with(|_| unsafe { - T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - }); - } -} - -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. - // Manually reset the peripheral. - T::regs().mcr().write(|w| w.set_reset(true)); - T::disable(); - } -} - -impl<'d, T: Instance> Deref for Can<'d, T> { - type Target = crate::can::bx::Can>; - - fn deref(&self) -> &Self::Target { - &self.can - } -} - -impl<'d, T: Instance> DerefMut for Can<'d, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.can - } -} - -use crate::can::enums::{BusError, TryReadError}; - -pub(crate) enum RxMode { - NonBuffered(AtomicWaker), - Buffered(crate::can::_version::common::ClassicBufferedRxInner), -} - -impl RxMode { - pub fn on_interrupt(&self, fifo: crate::can::_version::bx::RxFifo) { - match self { - Self::NonBuffered(waker) => { - // Disable interrupts until read - let fifo_idx = match fifo { - crate::can::_version::bx::RxFifo::Fifo0 => 0usize, - crate::can::_version::bx::RxFifo::Fifo1 => 1usize, - }; - T::regs().ier().write(|w| { - w.set_fmpie(fifo_idx, false); - }); - waker.wake(); - } - Self::Buffered(buf) => { - let regsisters = crate::can::bx::Registers { canregs: T::regs() }; - - loop { - match regsisters.receive_fifo(fifo) { - Some(envelope) => { - // NOTE: consensus was reached that if rx_queue is full, packets should be dropped - let _ = buf.rx_sender.try_send(Ok(envelope)); - } - None => return, - }; - } - } - } - } - - pub async fn read(&self) -> Result { - match self { - Self::NonBuffered(waker) => { - poll_fn(|cx| { - T::state().err_waker.register(cx.waker()); - waker.register(cx.waker()); - match self.try_read::() { - Ok(result) => Poll::Ready(Ok(result)), - Err(TryReadError::Empty) => Poll::Pending, - Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), - } - }) - .await - } - _ => { - panic!("Bad Mode") - } - } - } - pub fn try_read(&self) -> Result { - match self { - Self::NonBuffered(_) => { - let registers = crate::can::bx::Registers { canregs: T::regs() }; - if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo0) { - T::regs().ier().write(|w| { - w.set_fmpie(0, true); - }); - Ok(msg) - } else if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo1) { - T::regs().ier().write(|w| { - w.set_fmpie(1, true); - }); - Ok(msg) - } else if let Some(err) = registers.curr_error() { - Err(TryReadError::BusError(err)) - } else { - Err(TryReadError::Empty) - } - } - _ => { - panic!("Bad Mode") - } - } - } - pub async fn wait_not_empty(&self) { - match &T::state().rx_mode { - Self::NonBuffered(waker) => { - poll_fn(|cx| { - waker.register(cx.waker()); - let registers = crate::can::bx::Registers { canregs: T::regs() }; - if registers.receive_frame_available() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await - } - _ => { - panic!("Bad Mode") - } - } - } -} - -enum TxMode { - NonBuffered(AtomicWaker), - Buffered(self::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()) - } - pub fn on_interrupt(&self) { - match &T::state().tx_mode { - TxMode::NonBuffered(waker) => waker.wake(), - TxMode::Buffered(buf) => { - 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); - } - Err(_) => { - break; - } - } - } - } - } - } - - fn register(&self, arg: &core::task::Waker) { - match self { - TxMode::NonBuffered(waker) => { - waker.register(arg); - } - _ => { - panic!("Bad mode"); - } - } - } -} - -struct State { - pub(crate) rx_mode: RxMode, - pub(crate) tx_mode: TxMode, - pub err_waker: AtomicWaker, -} - -impl State { - pub const fn new() -> Self { - Self { - rx_mode: RxMode::NonBuffered(AtomicWaker::new()), - tx_mode: TxMode::NonBuffered(AtomicWaker::new()), - err_waker: AtomicWaker::new(), - } - } -} - -trait SealedInstance { - fn regs() -> crate::pac::can::Can; - fn state() -> &'static State; - unsafe fn mut_state() -> &'static mut State; -} - -/// CAN instance trait. -#[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + 'static { - /// TX interrupt for this instance. - type TXInterrupt: crate::interrupt::typelevel::Interrupt; - /// RX0 interrupt for this instance. - type RX0Interrupt: crate::interrupt::typelevel::Interrupt; - /// RX1 interrupt for this instance. - type RX1Interrupt: crate::interrupt::typelevel::Interrupt; - /// SCE interrupt for this instance. - type SCEInterrupt: crate::interrupt::typelevel::Interrupt; -} - -/// BXCAN instance newtype. -pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); - -unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> {} - -foreach_peripheral!( - (can, $inst:ident) => { - impl SealedInstance for peripherals::$inst { - - fn regs() -> crate::pac::can::Can { - crate::pac::$inst - } - - unsafe fn mut_state() -> & 'static mut State { - static mut STATE: State = State::new(); - &mut *core::ptr::addr_of_mut!(STATE) - } - fn state() -> &'static State { - unsafe { peripherals::$inst::mut_state() } - } - } - - impl Instance for peripherals::$inst { - type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX; - type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0; - type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1; - type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE; - } - }; -); - -foreach_peripheral!( - (can, CAN) => { - unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN> { - const NUM_FILTER_BANKS: u8 = 14; - } - }; - // CAN1 and CAN2 is a combination of master and slave instance. - // CAN1 owns the filter bank and needs to be enabled in order - // for CAN2 to receive messages. - (can, CAN1) => { - cfg_if::cfg_if! { - if #[cfg(all( - any(stm32l4, stm32f72, stm32f73), - not(any(stm32l49, stm32l4a)) - ))] { - // 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> { - const NUM_FILTER_BANKS: u8 = 14; - } - } else { - unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { - const NUM_FILTER_BANKS: u8 = 28; - } - unsafe impl<'d> crate::can::bx::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {} - } - } - }; - (can, CAN3) => { - unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN3> { - const NUM_FILTER_BANKS: u8 = 14; - } - }; -); - -pin_trait!(RxPin, Instance); -pin_trait!(TxPin, Instance); - -trait Index { - fn index(&self) -> usize; -} - -impl Index for crate::can::bx::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, - } - } -} diff --git a/embassy-stm32/src/can/bxcan/filter.rs b/embassy-stm32/src/can/bxcan/filter.rs new file mode 100644 index 000000000..9940c7f50 --- /dev/null +++ b/embassy-stm32/src/can/bxcan/filter.rs @@ -0,0 +1,475 @@ +//! Filter bank API. + +use core::marker::PhantomData; + +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 +const F16_RTR: u16 = 0b10000; +const F16_IDE: u16 = 0b01000; + +/// A 16-bit filter list entry. +/// +/// This can match data and remote frames using standard IDs. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ListEntry16(u16); + +/// A 32-bit filter list entry. +/// +/// This can match data and remote frames using extended or standard IDs. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ListEntry32(u32); + +/// A 16-bit identifier mask. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Mask16 { + id: u16, + mask: u16, +} + +/// A 32-bit identifier mask. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Mask32 { + id: u32, + mask: u32, +} + +impl ListEntry16 { + /// Creates a filter list entry that accepts data frames with the given standard ID. + /// + /// This entry will *not* accept remote frames with the same ID. + pub fn data_frames_with_id(id: StandardId) -> Self { + Self(id.as_raw() << 5) + } + + /// Creates a filter list entry that accepts remote frames with the given standard ID. + pub fn remote_frames_with_id(id: StandardId) -> Self { + Self(id.as_raw() << 5 | F16_RTR) + } +} + +impl ListEntry32 { + /// Creates a filter list entry that accepts data frames with the given ID. + /// + /// This entry will *not* accept remote frames with the same ID. + /// + /// The filter will only accept *either* standard *or* extended frames, depending on `id`. + pub fn data_frames_with_id(id: impl Into) -> Self { + match id.into() { + Id::Standard(id) => Self(u32::from(id.as_raw()) << 21), + Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE), + } + } + + /// Creates a filter list entry that accepts remote frames with the given ID. + pub fn remote_frames_with_id(id: impl Into) -> Self { + match id.into() { + Id::Standard(id) => Self(u32::from(id.as_raw()) << 21 | F32_RTR), + Id::Extended(id) => Self(id.as_raw() << 3 | F32_IDE | F32_RTR), + } + } +} + +impl Mask16 { + /// Creates a 16-bit identifier mask that accepts all frames. + /// + /// This will accept both standard and extended data and remote frames with any ID. + pub fn accept_all() -> Self { + Self { id: 0, mask: 0 } + } + + /// Creates a 16-bit identifier mask that accepts all frames with the given standard + /// ID and mask combination. + /// + /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` + /// + /// A mask of all all ones (`0x7FF`) matches an exact ID, a mask of 0 matches all IDs. + /// + /// Both data and remote frames with `id` will be accepted. Any extended frames will be + /// rejected. + pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self { + Self { + id: id.as_raw() << 5, + mask: mask.as_raw() << 5 | F16_IDE, // also require IDE = 0 + } + } + + /// Make the filter accept data frames only. + pub fn data_frames_only(&mut self) -> &mut Self { + self.id &= !F16_RTR; // RTR = 0 + self.mask |= F16_RTR; + self + } + + /// Make the filter accept remote frames only. + pub fn remote_frames_only(&mut self) -> &mut Self { + self.id |= F16_RTR; // RTR = 1 + self.mask |= F16_RTR; + self + } +} + +impl Mask32 { + /// Creates a 32-bit identifier mask that accepts all frames. + /// + /// This will accept both standard and extended data and remote frames with any ID. + pub fn accept_all() -> Self { + Self { id: 0, mask: 0 } + } + + /// Creates a 32-bit identifier mask that accepts all frames with the given extended + /// ID and mask combination. + /// + /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` + /// + /// A mask of all all ones (`0x1FFF_FFFF`) matches an exact ID, a mask of 0 matches all IDs. + /// + /// Both data and remote frames with `id` will be accepted. Standard frames will be rejected. + pub fn frames_with_ext_id(id: ExtendedId, mask: ExtendedId) -> Self { + Self { + id: id.as_raw() << 3 | F32_IDE, + mask: mask.as_raw() << 3 | F32_IDE, // also require IDE = 1 + } + } + + /// Creates a 32-bit identifier mask that accepts all frames with the given standard + /// ID and mask combination. + /// + /// Filter logic: `frame_accepted = (incoming_id & mask) == (id & mask)` + /// + /// A mask of all all ones (`0x7FF`) matches the exact ID, a mask of 0 matches all IDs. + /// + /// Both data and remote frames with `id` will be accepted. Extended frames will be rejected. + pub fn frames_with_std_id(id: StandardId, mask: StandardId) -> Self { + Self { + id: u32::from(id.as_raw()) << 21, + mask: u32::from(mask.as_raw()) << 21 | F32_IDE, // also require IDE = 0 + } + } + + /// Make the filter accept data frames only. + pub fn data_frames_only(&mut self) -> &mut Self { + self.id &= !F32_RTR; // RTR = 0 + self.mask |= F32_RTR; + self + } + + /// Make the filter accept remote frames only. + pub fn remote_frames_only(&mut self) -> &mut Self { + self.id |= F32_RTR; // RTR = 1 + self.mask |= F32_RTR; + self + } +} + +/// The configuration of a filter bank. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum BankConfig { + /// Specify up to 4 exact standard CAN ID's. + List16([ListEntry16; 4]), + /// Specify up to 2 exact standard or extended CAN ID's. + List32([ListEntry32; 2]), + /// Specify up to 2 standard ID's with masks. + Mask16([Mask16; 2]), + /// Specify a single extended ID with mask. + Mask32(Mask32), +} + +impl From<[ListEntry16; 4]> for BankConfig { + #[inline] + fn from(entries: [ListEntry16; 4]) -> Self { + Self::List16(entries) + } +} + +impl From<[ListEntry32; 2]> for BankConfig { + #[inline] + fn from(entries: [ListEntry32; 2]) -> Self { + Self::List32(entries) + } +} + +impl From<[Mask16; 2]> for BankConfig { + #[inline] + fn from(entries: [Mask16; 2]) -> Self { + Self::Mask16(entries) + } +} + +impl From for BankConfig { + #[inline] + fn from(filter: Mask32) -> Self { + Self::Mask32(filter) + } +} + +/// Interface to the filter banks of a CAN peripheral. +pub struct MasterFilters<'a, I: FilterOwner> { + /// Number of assigned filter banks. + /// + /// On chips with splittable filter banks, this value can be dynamic. + bank_count: u8, + _can: PhantomData<&'a mut I>, + canregs: crate::pac::can::Can, +} + +// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it +// exists. +impl MasterFilters<'_, I> { + pub(crate) unsafe fn new(canregs: crate::pac::can::Can) -> Self { + // Enable initialization mode. + canregs.fmr().modify(|reg| reg.set_finit(true)); + + // Read the filter split value. + let bank_count = canregs.fmr().read().can2sb(); + + // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all + // of them to the master peripheral, and in devices with 28, assigns them 50/50 to + // master/slave instances) + + Self { + bank_count, + _can: PhantomData, + canregs, + } + } + + fn banks_imm(&self) -> FilterBanks { + FilterBanks { + start_idx: 0, + bank_count: self.bank_count, + canregs: self.canregs, + } + } + + /// Returns the number of filter banks currently assigned to this instance. + /// + /// Chips with splittable filter banks may start out with some banks assigned to the master + /// instance and some assigned to the slave instance. + pub fn num_banks(&self) -> u8 { + self.bank_count + } + + /// Disables all enabled filter banks. + /// + /// This causes all incoming frames to be disposed. + pub fn clear(&mut self) -> &mut Self { + self.banks_imm().clear(); + self + } + + /// Disables a filter bank. + /// + /// If `index` is out of bounds, this will panic. + pub fn disable_bank(&mut self, index: u8) -> &mut Self { + self.banks_imm().disable(index); + self + } + + /// Configures a filter bank according to `config` and enables it. + /// + /// Each filter bank is associated with one of the two RX FIFOs, configured by the [`Fifo`] + /// passed to this function. In the event that both FIFOs are configured to accept an incoming + /// frame, the accepting filter bank with the lowest index wins. The FIFO state is ignored, so + /// if the FIFO is full, it will overflow, even if the other FIFO is also configured to accept + /// the frame. + /// + /// # Parameters + /// + /// - `index`: the filter index. + /// - `fifo`: the receive FIFO the filter should pass accepted messages to. + /// - `config`: the filter configuration. + pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into) -> &mut Self { + self.banks_imm().enable(index, fifo, config.into()); + self + } +} + +impl MasterFilters<'_, I> { + /// Sets the index at which the filter banks owned by the slave peripheral start. + pub fn set_split(&mut self, split_index: u8) -> &mut Self { + assert!(split_index <= I::NUM_FILTER_BANKS); + self.canregs.fmr().modify(|reg| reg.set_can2sb(split_index)); + self.bank_count = split_index; + self + } + + /// Accesses the filters assigned to the slave peripheral. + pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> { + // NB: This mutably borrows `self`, so it has full access to the filter bank registers. + SlaveFilters { + start_idx: self.bank_count, + bank_count: I::NUM_FILTER_BANKS - self.bank_count, + _can: PhantomData, + canregs: self.canregs, + } + } +} + +impl Drop for MasterFilters<'_, I> { + #[inline] + fn drop(&mut self) { + // Leave initialization mode. + self.canregs.fmr().modify(|regs| regs.set_finit(false)); + } +} + +/// Interface to the filter banks assigned to a slave peripheral. +pub struct SlaveFilters<'a, I: Instance> { + start_idx: u8, + bank_count: u8, + _can: PhantomData<&'a mut I>, + canregs: crate::pac::can::Can, +} + +impl SlaveFilters<'_, I> { + fn banks_imm(&self) -> FilterBanks { + FilterBanks { + start_idx: self.start_idx, + bank_count: self.bank_count, + canregs: self.canregs, + } + } + + /// Returns the number of filter banks currently assigned to this instance. + /// + /// Chips with splittable filter banks may start out with some banks assigned to the master + /// instance and some assigned to the slave instance. + pub fn num_banks(&self) -> u8 { + self.bank_count + } + + /// Disables all enabled filter banks. + /// + /// This causes all incoming frames to be disposed. + pub fn clear(&mut self) -> &mut Self { + self.banks_imm().clear(); + self + } + + /// Disables a filter bank. + /// + /// If `index` is out of bounds, this will panic. + pub fn disable_bank(&mut self, index: u8) -> &mut Self { + self.banks_imm().disable(index); + self + } + + /// Configures a filter bank according to `config` and enables it. + /// + /// # Parameters + /// + /// - `index`: the filter index. + /// - `fifo`: the receive FIFO the filter should pass accepted messages to. + /// - `config`: the filter configuration. + pub fn enable_bank(&mut self, index: u8, fifo: Fifo, config: impl Into) -> &mut Self { + self.banks_imm().enable(index, fifo, config.into()); + self + } +} + +struct FilterBanks { + start_idx: u8, + bank_count: u8, + canregs: crate::pac::can::Can, +} + +impl FilterBanks { + fn clear(&mut self) { + let mask = filter_bitmask(self.start_idx, self.bank_count); + + self.canregs.fa1r().modify(|reg| { + for i in 0..28usize { + if (0x01u32 << i) & mask != 0 { + reg.set_fact(i, false); + } + } + }); + } + + fn assert_bank_index(&self, index: u8) { + assert!((self.start_idx..self.start_idx + self.bank_count).contains(&index)); + } + + fn disable(&mut self, index: u8) { + self.assert_bank_index(index); + self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, false)) + } + + fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) { + self.assert_bank_index(index); + + // Configure mode. + let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_)); + self.canregs.fm1r().modify(|reg| reg.set_fbm(index as usize, mode)); + + // Configure scale. + let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_)); + self.canregs.fs1r().modify(|reg| reg.set_fsc(index as usize, scale)); + + // Configure filter register. + let (fxr1, fxr2); + match config { + BankConfig::List16([a, b, c, d]) => { + fxr1 = (u32::from(b.0) << 16) | u32::from(a.0); + fxr2 = (u32::from(d.0) << 16) | u32::from(c.0); + } + BankConfig::List32([a, b]) => { + fxr1 = a.0; + fxr2 = b.0; + } + BankConfig::Mask16([a, b]) => { + fxr1 = (u32::from(a.mask) << 16) | u32::from(a.id); + fxr2 = (u32::from(b.mask) << 16) | u32::from(b.id); + } + BankConfig::Mask32(a) => { + fxr1 = a.id; + fxr2 = a.mask; + } + }; + let bank = self.canregs.fb(index as usize); + bank.fr1().write(|w| w.0 = fxr1); + bank.fr2().write(|w| w.0 = fxr2); + + // Assign to the right FIFO + self.canregs.ffa1r().modify(|reg| { + reg.set_ffa( + index as usize, + match fifo { + Fifo::Fifo0 => false, + Fifo::Fifo1 => true, + }, + ) + }); + + // Set active. + self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, true)) + } +} + +/// Computes a bitmask for per-filter-bank registers that only includes filters in the given range. +fn filter_bitmask(start_idx: u8, bank_count: u8) -> u32 { + let count_mask = (1 << bank_count) - 1; // `bank_count` 1-bits + count_mask << start_idx +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_filter_bitmask() { + assert_eq!(filter_bitmask(0, 1), 0x1); + assert_eq!(filter_bitmask(1, 1), 0b10); + assert_eq!(filter_bitmask(0, 4), 0xf); + assert_eq!(filter_bitmask(1, 3), 0xe); + assert_eq!(filter_bitmask(8, 1), 0x100); + assert_eq!(filter_bitmask(8, 4), 0xf00); + } +} diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs new file mode 100644 index 000000000..65fd0e9c2 --- /dev/null +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -0,0 +1,989 @@ +pub mod filter; +mod registers; + +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + +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}; + +/// Interrupt handler. +pub struct TxInterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for TxInterruptHandler { + unsafe fn on_interrupt() { + T::regs().tsr().write(|v| { + v.set_rqcp(0, true); + v.set_rqcp(1, true); + v.set_rqcp(2, true); + }); + T::state().tx_mode.on_interrupt::(); + } +} + +/// RX0 interrupt handler. +pub struct Rx0InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for Rx0InterruptHandler { + unsafe fn on_interrupt() { + T::state().rx_mode.on_interrupt::(RxFifo::Fifo0); + } +} + +/// RX1 interrupt handler. +pub struct Rx1InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for Rx1InterruptHandler { + unsafe fn on_interrupt() { + T::state().rx_mode.on_interrupt::(RxFifo::Fifo1); + } +} + +/// SCE interrupt handler. +pub struct SceInterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for SceInterruptHandler { + unsafe fn on_interrupt() { + // info!("sce irq"); + let msr = T::regs().msr(); + let msr_val = msr.read(); + + if msr_val.erri() { + msr.modify(|v| v.set_erri(true)); + T::state().err_waker.wake(); + } + } +} + +/// 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> { + peri: PeripheralRef<'d, T>, +} + +/// Error returned by `try_write` +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TryWriteError { + /// All transmit mailboxes are full + Full, +} + +impl<'d, T: Instance> Can<'d, T> { + /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. + /// You must call [Can::enable_non_blocking] to use the peripheral. + pub fn new( + peri: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + tx: impl Peripheral

> + 'd, + _irqs: impl interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + 'd, + ) -> Self { + into_ref!(peri, rx, tx); + + rx.set_as_af(rx.af_num(), AFType::Input); + tx.set_as_af(tx.af_num(), AFType::OutputPushPull); + + T::enable_and_reset(); + + { + T::regs().ier().write(|w| { + w.set_errie(true); + w.set_fmpie(0, true); + w.set_fmpie(1, true); + w.set_tmeie(true); + }); + + T::regs().mcr().write(|w| { + // Enable timestamps on rx messages + + w.set_ttcm(true); + }); + } + + unsafe { + T::TXInterrupt::unpend(); + T::TXInterrupt::enable(); + + T::RX0Interrupt::unpend(); + T::RX0Interrupt::enable(); + + T::RX1Interrupt::unpend(); + T::RX1Interrupt::enable(); + + T::SCEInterrupt::unpend(); + T::SCEInterrupt::enable(); + } + + rx.set_as_af(rx.af_num(), AFType::Input); + tx.set_as_af(tx.af_num(), AFType::OutputPushPull); + + 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.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. + /// + /// 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 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; + } + } + + /// Queues the message to be sent. + /// + /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. + pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { + 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 { + self.split().0.try_write(frame) + } + + /// Waits for a specific transmit mailbox to become empty + pub async fn flush(&self, mb: Mailbox) { + CanTx::::flush_inner(mb).await + } + + /// Waits until any of the transmit mailboxes become empty + pub async fn flush_any(&self) { + CanTx::::flush_any_inner().await + } + + /// Waits until all of the transmit mailboxes become empty + pub async fn flush_all(&self) { + 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. + /// + /// Returns a tuple of the time the message was received and the message frame + pub async fn read(&mut self) -> Result { + T::state().rx_mode.read::().await + } + + /// Attempts to read a CAN frame without blocking. + /// + /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. + pub fn try_read(&mut self) -> Result { + T::state().rx_mode.try_read::() + } + + /// Waits while receive queue is empty. + pub async fn wait_not_empty(&mut self) { + T::state().rx_mode.wait_not_empty::().await + } + + /// Split the CAN driver into transmit and receive halves. + /// + /// Useful for doing separate transmit/receive tasks. + pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { + ( + CanTx { + _peri: unsafe { self.peri.clone_unchecked() }, + }, + CanRx { + peri: unsafe { self.peri.clone_unchecked() }, + }, + ) + } + + /// Return a buffered instance of driver. User must supply Buffers + pub fn buffered<'c, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( + &'c mut self, + txb: &'static mut TxBuf, + rxb: &'static mut RxBuf, + ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { + let (tx, rx) = self.split(); + BufferedCan { + tx: tx.buffered(txb), + rx: rx.buffered(rxb), + } + } +} + +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()) } + } +} + +/// Buffered CAN driver. +pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { + tx: BufferedCanTx<'d, T, TX_BUF_SIZE>, + rx: BufferedCanRx<'d, T, RX_BUF_SIZE>, +} + +impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: &Frame) { + self.tx.write(frame).await + } + + /// Returns a sender that can be used for sending CAN frames. + pub fn writer(&self) -> BufferedCanSender { + self.tx.writer() + } + + /// Async read frame from RX buffer. + pub async fn read(&mut self) -> Result { + self.rx.read().await + } + + /// Attempts to read a CAN frame without blocking. + /// + /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. + pub fn try_read(&mut self) -> Result { + self.rx.try_read() + } + + /// Waits while receive queue is empty. + pub async fn wait_not_empty(&mut self) { + self.rx.wait_not_empty().await + } + + /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. + pub fn reader(&self) -> BufferedCanReceiver { + self.rx.reader() + } +} + +/// CAN driver, transmit half. +pub struct CanTx<'d, T: Instance> { + _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) -> TransmitStatus { + poll_fn(|cx| { + T::state().tx_mode.register(cx.waker()); + if let Ok(status) = Registers(T::regs()).transmit(frame) { + return Poll::Ready(status); + } + + Poll::Pending + }) + .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 { + Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) + } + + async fn flush_inner(mb: Mailbox) { + poll_fn(|cx| { + T::state().tx_mode.register(cx.waker()); + if T::regs().tsr().read().tme(mb.index()) { + return Poll::Ready(()); + } + + Poll::Pending + }) + .await; + } + + /// Waits for a specific transmit mailbox to become empty + pub async fn flush(&self, mb: Mailbox) { + Self::flush_inner(mb).await + } + + async fn flush_any_inner() { + poll_fn(|cx| { + T::state().tx_mode.register(cx.waker()); + + let tsr = T::regs().tsr().read(); + if tsr.tme(Mailbox::Mailbox0.index()) + || tsr.tme(Mailbox::Mailbox1.index()) + || tsr.tme(Mailbox::Mailbox2.index()) + { + return Poll::Ready(()); + } + + Poll::Pending + }) + .await; + } + + /// Waits until any of the transmit mailboxes become empty + pub async fn flush_any(&self) { + Self::flush_any_inner().await + } + + async fn flush_all_inner() { + poll_fn(|cx| { + T::state().tx_mode.register(cx.waker()); + + let tsr = T::regs().tsr().read(); + if tsr.tme(Mailbox::Mailbox0.index()) + && tsr.tme(Mailbox::Mailbox1.index()) + && tsr.tme(Mailbox::Mailbox2.index()) + { + return Poll::Ready(()); + } + + Poll::Pending + }) + .await; + } + + /// Waits until all of the transmit mailboxes become empty + pub async fn flush_all(&self) { + 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, txb) + } +} + +/// User supplied buffer for TX buffering +pub type TxBuf = Channel; + +/// Buffered CAN driver, transmit half. +pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { + _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: 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 = super::common::ClassicBufferedTxInner { + tx_receiver: self.tx_buf.receiver().into(), + }; + T::mut_state().tx_mode = TxMode::Buffered(tx_inner); + }); + self + } + + /// Async write frame to TX buffer. + pub async fn write(&mut self, frame: &Frame) { + self.tx_buf.send(*frame).await; + T::TXInterrupt::pend(); // Wake for Tx + } + + /// Returns a sender that can be used for sending CAN frames. + pub fn writer(&self) -> BufferedCanSender { + BufferedCanSender { + tx_buf: self.tx_buf.sender().into(), + waker: T::TXInterrupt::pend, + } + } +} + +impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { + fn drop(&mut self) { + critical_section::with(|_| unsafe { + T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + }); + } +} + +/// CAN driver, receive half. +#[allow(dead_code)] +pub struct CanRx<'d, T: Instance> { + peri: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> CanRx<'d, T> { + /// Read a CAN frame. + /// + /// If no CAN frame is in the RX buffer, this will wait until there is one. + /// + /// Returns a tuple of the time the message was received and the message frame + pub async fn read(&mut self) -> Result { + T::state().rx_mode.read::().await + } + + /// Attempts to read a CAN frame without blocking. + /// + /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. + pub fn try_read(&mut self) -> Result { + T::state().rx_mode.try_read::() + } + + /// Waits while receive queue is empty. + pub async fn wait_not_empty(&mut self) { + T::state().rx_mode.wait_not_empty::().await + } + + /// Return a buffered instance of driver. User must supply Buffers + pub fn buffered( + self, + rxb: &'static mut RxBuf, + ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { + BufferedCanRx::new(self, rxb) + } +} + +/// User supplied buffer for RX Buffering +pub type RxBuf = Channel, BUF_SIZE>; + +/// CAN driver, receive half in Buffered mode. +pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { + _rx: 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: 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 = super::common::ClassicBufferedRxInner { + rx_sender: self.rx_buf.sender().into(), + }; + T::mut_state().rx_mode = RxMode::Buffered(rx_inner); + }); + self + } + + /// Async read frame from RX buffer. + pub async fn read(&mut self) -> Result { + self.rx_buf.receive().await + } + + /// Attempts to read a CAN frame without blocking. + /// + /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. + pub fn try_read(&mut self) -> Result { + match &T::state().rx_mode { + RxMode::Buffered(_) => { + if let Ok(result) = self.rx_buf.try_receive() { + match result { + Ok(envelope) => Ok(envelope), + Err(e) => Err(TryReadError::BusError(e)), + } + } else { + if let Some(err) = Registers(T::regs()).curr_error() { + return Err(TryReadError::BusError(err)); + } else { + Err(TryReadError::Empty) + } + } + } + _ => { + panic!("Bad Mode") + } + } + } + + /// Waits while receive queue is empty. + pub async fn wait_not_empty(&mut self) { + poll_fn(|cx| self.rx_buf.poll_ready_to_receive(cx)).await + } + + /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. + pub fn reader(&self) -> BufferedCanReceiver { + self.rx_buf.receiver().into() + } +} + +impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { + fn drop(&mut self) { + critical_section::with(|_| unsafe { + T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + }); + } +} + +impl<'d, T: Instance> Drop for Can<'d, T> { + fn drop(&mut self) { + // Cannot call `free()` because it moves the instance. + // Manually reset the peripheral. + T::regs().mcr().write(|w| w.set_reset(true)); + T::disable(); + } +} + +/// 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 + } +} + +pub(crate) enum RxMode { + NonBuffered(AtomicWaker), + Buffered(super::common::ClassicBufferedRxInner), +} + +impl RxMode { + pub fn on_interrupt(&self, fifo: RxFifo) { + match self { + Self::NonBuffered(waker) => { + // Disable interrupts until read + let fifo_idx = match fifo { + RxFifo::Fifo0 => 0usize, + RxFifo::Fifo1 => 1usize, + }; + T::regs().ier().write(|w| { + w.set_fmpie(fifo_idx, false); + }); + waker.wake(); + } + Self::Buffered(buf) => { + loop { + 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)); + } + None => return, + }; + } + } + } + } + + pub async fn read(&self) -> Result { + match self { + Self::NonBuffered(waker) => { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + waker.register(cx.waker()); + match self.try_read::() { + Ok(result) => Poll::Ready(Ok(result)), + Err(TryReadError::Empty) => Poll::Pending, + Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), + } + }) + .await + } + _ => { + panic!("Bad Mode") + } + } + } + pub fn try_read(&self) -> Result { + match self { + Self::NonBuffered(_) => { + let registers = 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(RxFifo::Fifo1) { + T::regs().ier().write(|w| { + w.set_fmpie(1, true); + }); + Ok(msg) + } else if let Some(err) = registers.curr_error() { + Err(TryReadError::BusError(err)) + } else { + Err(TryReadError::Empty) + } + } + _ => { + panic!("Bad Mode") + } + } + } + pub async fn wait_not_empty(&self) { + match &T::state().rx_mode { + Self::NonBuffered(waker) => { + poll_fn(|cx| { + waker.register(cx.waker()); + if Registers(T::regs()).receive_frame_available() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await + } + _ => { + panic!("Bad Mode") + } + } + } +} + +enum TxMode { + NonBuffered(AtomicWaker), + Buffered(super::common::ClassicBufferedTxInner), +} + +impl TxMode { + pub fn buffer_free(&self) -> bool { + let tsr = T::regs().tsr().read(); + 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 { + TxMode::NonBuffered(waker) => waker.wake(), + TxMode::Buffered(buf) => { + while self.buffer_free::() { + match buf.tx_receiver.try_receive() { + Ok(frame) => { + _ = Registers(T::regs()).transmit(&frame); + } + Err(_) => { + break; + } + } + } + } + } + } + + fn register(&self, arg: &core::task::Waker) { + match self { + TxMode::NonBuffered(waker) => { + waker.register(arg); + } + _ => { + panic!("Bad mode"); + } + } + } +} + +struct State { + pub(crate) rx_mode: RxMode, + pub(crate) tx_mode: TxMode, + pub err_waker: AtomicWaker, +} + +impl State { + pub const fn new() -> Self { + Self { + rx_mode: RxMode::NonBuffered(AtomicWaker::new()), + tx_mode: TxMode::NonBuffered(AtomicWaker::new()), + err_waker: AtomicWaker::new(), + } + } +} + +trait SealedInstance { + fn regs() -> crate::pac::can::Can; + fn state() -> &'static State; + unsafe fn mut_state() -> &'static mut State; +} + +/// CAN instance trait. +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral + 'static { + /// TX interrupt for this instance. + type TXInterrupt: crate::interrupt::typelevel::Interrupt; + /// RX0 interrupt for this instance. + type RX0Interrupt: crate::interrupt::typelevel::Interrupt; + /// RX1 interrupt for this instance. + type RX1Interrupt: crate::interrupt::typelevel::Interrupt; + /// SCE interrupt for this instance. + type SCEInterrupt: crate::interrupt::typelevel::Interrupt; +} + +/// 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 {} + +foreach_peripheral!( + (can, $inst:ident) => { + impl SealedInstance for peripherals::$inst { + + fn regs() -> crate::pac::can::Can { + crate::pac::$inst + } + + unsafe fn mut_state() -> & 'static mut State { + static mut STATE: State = State::new(); + &mut *core::ptr::addr_of_mut!(STATE) + } + fn state() -> &'static State { + unsafe { peripherals::$inst::mut_state() } + } + } + + impl Instance for peripherals::$inst { + type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX; + type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0; + type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1; + type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE; + } + }; +); + +foreach_peripheral!( + (can, CAN) => { + unsafe impl FilterOwner for peripherals::CAN { + const NUM_FILTER_BANKS: u8 = 14; + } + }; + // CAN1 and CAN2 is a combination of master and slave instance. + // CAN1 owns the filter bank and needs to be enabled in order + // for CAN2 to receive messages. + (can, CAN1) => { + cfg_if::cfg_if! { + if #[cfg(all( + any(stm32l4, stm32f72, stm32f73), + not(any(stm32l49, stm32l4a)) + ))] { + // Most L4 devices and some F7 devices use the name "CAN1" + // even if there is no "CAN2" peripheral. + unsafe impl FilterOwner for peripherals::CAN1 { + const NUM_FILTER_BANKS: u8 = 14; + } + } else { + unsafe impl FilterOwner for peripherals::CAN1 { + const NUM_FILTER_BANKS: u8 = 28; + } + unsafe impl MasterInstance for peripherals::CAN1 {} + } + } + }; + (can, CAN3) => { + unsafe impl FilterOwner for peripherals::CAN3 { + const NUM_FILTER_BANKS: u8 = 14; + } + }; +); + +pin_trait!(RxPin, Instance); +pin_trait!(TxPin, Instance); + +trait Index { + fn index(&self) -> usize; +} + +impl Index for Mailbox { + fn index(&self) -> usize { + match self { + 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"); -- cgit