From f13d78f7c3f5b109752e958ab30ddfd7a198102f Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 6 Dec 2024 18:01:33 +0100 Subject: [PATCH 1/3] Export pac as pac (#156) --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 93c12d07..d274d5ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,8 @@ pub use stm32g4::stm32g491 as stm32; #[cfg(feature = "stm32g4a1")] pub use stm32g4::stm32g4a1 as stm32; +pub use stm32 as pac; + #[cfg(feature = "rt")] pub use crate::stm32::interrupt; From 0cd4131394e3fc076276459c9bd039129fa8c03c Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 28 Dec 2024 11:55:48 +0100 Subject: [PATCH 2/3] rm remaining fdcan files (#160) --- src/fdcan.rs | 1783 --------------------- src/fdcan/filter.rs | 401 ----- src/fdcan/id.rs | 311 ---- src/fdcan/interrupt.rs | 205 --- src/fdcan/message_ram/txbuffer_element.rs | 407 ----- 5 files changed, 3107 deletions(-) delete mode 100644 src/fdcan.rs delete mode 100644 src/fdcan/filter.rs delete mode 100644 src/fdcan/id.rs delete mode 100644 src/fdcan/interrupt.rs delete mode 100644 src/fdcan/message_ram/txbuffer_element.rs diff --git a/src/fdcan.rs b/src/fdcan.rs deleted file mode 100644 index 24e42088..00000000 --- a/src/fdcan.rs +++ /dev/null @@ -1,1783 +0,0 @@ -#![deny(missing_docs)] - -//! FdCAN Operations - -/// Configuration of an FdCAN instance -pub mod config; -/// Filtering of CAN Messages -pub mod filter; -/// Header and info of transmitted and receiving frames -pub mod frame; -/// Standard and Extended Id -pub mod id; -/// Interrupt Line Information -pub mod interrupt; -mod message_ram; - -use id::{Id, IdReg}; - -use crate::rcc::Rcc; -use crate::stm32::fdcan::RegisterBlock; -use config::{ - ClockDivider, DataBitTiming, FdCanConfig, FrameTransmissionConfig, GlobalFilter, - NominalBitTiming, TimestampSource, -}; -use filter::{ - ActivateFilter as _, ExtendedFilter, ExtendedFilterSlot, StandardFilter, StandardFilterSlot, - EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX, -}; -use frame::MergeTxFrameHeader; -use frame::{RxFrameInfo, TxFrameHeader}; -use interrupt::{Interrupt, InterruptLine, Interrupts}; - -use message_ram::MsgRamExt; -use message_ram::RxFifoElement; - -use core::cmp::Ord; -use core::convert::Infallible; -use core::convert::TryFrom; -use core::marker::PhantomData; -use core::ptr::NonNull; - -mod sealed { - /// A TX pin configured for CAN communication - pub trait Tx {} - /// An RX pin configured for CAN communication - pub trait Rx {} -} - -/// An FdCAN 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: MsgRamExt + crate::rcc::Instance { - /// Pointer to the instance's register block. - const REGISTERS: *mut RegisterBlock; -} - -/// Indicates if an Receive Overflow has occurred -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum ReceiveErrorOverflow { - /// No overflow has occurred - Normal(u8), - /// An overflow has occurred - Overflow(u8), -} - -///Error Counters -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -#[allow(dead_code)] -pub struct ErrorCounters { - /// General CAN error counter - can_errors: u8, - /// Receive CAN error counter - receive_err: ReceiveErrorOverflow, - /// Transmit CAN error counter - transmit_err: u8, -} - -/// Loopback Mode -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -enum LoopbackMode { - None, - Internal, - External, -} - -/// Bus Activity -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum Activity { - /// Node is Synchronizing - Synchronizing = 0b00, - /// Node is Idle - Idle = 0b01, - /// Node is receiver only - Receiver = 0b10, - /// Node is transmitter only - Transmitter = 0b11, -} -impl TryFrom for Activity { - type Error = (); - fn try_from(value: u8) -> Result { - match value { - 0b000 => Ok(Self::Synchronizing), - 0b001 => Ok(Self::Idle), - 0b010 => Ok(Self::Receiver), - 0b011 => Ok(Self::Transmitter), - _ => Err(()), - } - } -} - -/// Indicates the type of the last error which occurred on the CAN bus -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum LastErrorCode { - /// There has been no error since last read - NoError = 0b000, - /// More than 5 equal bits in sequence are not allowed - StuffError = 0b001, - /// a fixed format part of ta received frame had the wrong format - FormError = 0b010, - /// message tramsitted by this node was not acknowledged by another - AckError = 0b011, - /// During transmit, the node wanted to send a 1 but monitored a 0 - Bit1Error = 0b100, - /// During transmit, the node wanted to send a 0 but monitored a 1 - Bit0Error = 0b101, - /// CRC checksum of a received message was incorrect - CRCError = 0b110, - /// No CAN bus event detected since last read - NoChange = 0b111, -} -impl TryFrom for LastErrorCode { - type Error = (); - fn try_from(value: u8) -> Result { - match value { - 0b000 => Ok(Self::NoError), - 0b001 => Ok(Self::StuffError), - 0b010 => Ok(Self::FormError), - 0b011 => Ok(Self::AckError), - 0b100 => Ok(Self::Bit1Error), - 0b101 => Ok(Self::Bit0Error), - 0b110 => Ok(Self::CRCError), - 0b111 => Ok(Self::NoChange), - _ => Err(()), - } - } -} - -/// Some status indications regarding the FDCAN protocl -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub struct ProtocolStatus { - /// Type of current activity - activity: Activity, - /// Transmitter delay companstation - transmitter_delay_comp: u8, - /// But Off Status - bus_off_status: bool, - /// Shows if Error counters are aat their limit of 96 - error_warning: bool, - /// Shows if the node send and active error flag (false) or stays silent (true). - error_passive_state: bool, - /// Indicates te last type of error which occurred on the CAN bus. - last_error: LastErrorCode, -} - -/// Allows for Transmit Operations -pub trait Transmit {} -/// Allows for Receive Operations -pub trait Receive {} - -/// Allows for the FdCan Instance to be released or to enter ConfigMode -pub struct PoweredDownMode; -/// Allows for the configuration for the Instance -pub struct ConfigMode; -/// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without -/// affecting a running CAN system connected to the FDCAN_TX and FDCAN_RX pins. In this -/// mode, FDCAN_RX pin is disconnected from the FDCAN and FDCAN_TX pin is held -/// recessive. -pub struct InternalLoopbackMode; -impl Transmit for InternalLoopbackMode {} -impl Receive for InternalLoopbackMode {} -/// This mode is provided for hardware self-test. To be independent from external stimulation, -/// the FDCAN ignores acknowledge errors (recessive bit sampled in the acknowledge slot of a -/// data / remote frame) in Loop Back mode. In this mode the FDCAN performs an internal -/// feedback from its transmit output to its receive input. The actual value of the FDCAN_RX -/// input pin is disregarded by the FDCAN. The transmitted messages can be monitored at the -/// FDCAN_TX transmit pin. -pub struct ExternalLoopbackMode; -impl Transmit for ExternalLoopbackMode {} -impl Receive for ExternalLoopbackMode {} -/// The normal use of the FdCan instance after configurations -pub struct NormalOperationMode; -impl Transmit for NormalOperationMode {} -impl Receive for NormalOperationMode {} -/// In Restricted operation mode the node is able to receive data and remote frames and to give -/// acknowledge to valid frames, but it does not send data frames, remote frames, active error -/// frames, or overload frames. In case of an error condition or overload condition, it does not -/// send dominant bits, instead it waits for the occurrence of bus idle condition to resynchronize -/// itself to the CAN communication. The error counters for transmit and receive are frozen while -/// error logging (can_errors) is active. TODO: automatically enter in this mode? -pub struct RestrictedOperationMode; -impl Receive for RestrictedOperationMode {} -/// In Bus monitoring mode (for more details refer to ISO11898-1, 10.12 Bus monitoring), -/// the FDCAN is able to receive valid data frames and valid remote frames, but cannot start a -/// transmission. In this mode, it sends only recessive bits on the CAN bus. If the FDCAN is -/// required to send a dominant bit (ACK bit, overload flag, active error flag), the bit is -/// rerouted internally so that the FDCAN can monitor it, even if the CAN bus remains in recessive -/// state. In Bus monitoring mode the TXBRP register is held in reset state. The Bus monitoring -/// mode can be used to analyze the traffic on a CAN bus without affecting it by the transmission -/// of dominant bits. -pub struct BusMonitoringMode; -impl Receive for BusMonitoringMode {} -/// Test mode must be used for production tests or self test only. The software control for -/// FDCAN_TX pin interferes with all CAN protocol functions. It is not recommended to use test -/// modes for application. -pub struct TestMode; - -/// Interface to a FdCAN peripheral. -pub struct FdCan { - control: FdCanControl, -} - -impl FdCan -where - I: Instance, -{ - fn create_can(config: FdCanConfig, instance: I) -> FdCan { - FdCan { - control: FdCanControl { - config, - instance, - _mode: core::marker::PhantomData, - }, - } - } - - fn into_can_mode(self) -> FdCan { - FdCan { - control: FdCanControl { - config: self.control.config, - instance: self.control.instance, - _mode: core::marker::PhantomData, - }, - } - } - - /// Returns a reference to the peripheral instance. - /// - /// This allows accessing HAL-specific data stored in the instance type. - #[inline] - pub fn instance(&mut self) -> &mut I { - &mut self.control.instance - } - - #[inline] - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } - } - - #[inline] - fn msg_ram_mut(&mut self) -> &mut message_ram::RegisterBlock { - self.instance().msg_ram_mut() - } - - #[inline] - fn reset_msg_ram(&mut self) { - self.msg_ram_mut().reset(); - } - - #[inline] - fn enter_init_mode(&mut self) { - let can = self.registers(); - - can.cccr.modify(|_, w| w.init().set_bit()); - while can.cccr.read().init().bit_is_clear() {} - can.cccr.modify(|_, w| w.cce().set_bit()); - } - - /// Returns the current FDCAN config settings - #[inline] - pub fn get_config(&self) -> FdCanConfig { - self.control.config - } - - /// Enables or disables loopback mode: Internally connects the TX and RX - /// signals together. - #[inline] - fn set_loopback_mode(&mut self, mode: LoopbackMode) { - let (test, mon, lbck) = match mode { - LoopbackMode::None => (false, false, false), - LoopbackMode::Internal => (true, true, true), - LoopbackMode::External => (true, false, true), - }; - - self.set_test_mode(test); - self.set_bus_monitoring_mode(mon); - - let can = self.registers(); - can.test.modify(|_, w| w.lbck().bit(lbck)); - } - - /// Enables or disables silent mode: Disconnects the TX signal from the pin. - #[inline] - fn set_bus_monitoring_mode(&mut self, enabled: bool) { - let can = self.registers(); - can.cccr.modify(|_, w| w.mon().bit(enabled)); - } - - #[inline] - fn set_restricted_operations(&mut self, enabled: bool) { - let can = self.registers(); - can.cccr.modify(|_, w| w.asm().bit(enabled)); - } - - #[inline] - fn set_normal_operations(&mut self, _enabled: bool) { - self.set_loopback_mode(LoopbackMode::None); - } - - #[inline] - fn set_test_mode(&mut self, enabled: bool) { - let can = self.registers(); - can.cccr.modify(|_, w| w.test().bit(enabled)); - } - - #[inline] - fn set_power_down_mode(&mut self, enabled: bool) { - let can = self.registers(); - can.cccr.modify(|_, w| w.csr().bit(enabled)); - while can.cccr.read().csa().bit() != enabled {} - } - - /// Enable/Disable the specific Interrupt Line - #[inline] - pub fn enable_interrupt_line(&mut self, line: InterruptLine, enabled: bool) { - let can = self.registers(); - match line { - InterruptLine::_0 => can.ile.modify(|_, w| w.eint1().bit(enabled)), - InterruptLine::_1 => can.ile.modify(|_, w| w.eint0().bit(enabled)), - } - } - - /// Starts listening for a CAN interrupt. - #[inline] - pub fn enable_interrupt(&mut self, interrupt: Interrupt) { - self.enable_interrupts(Interrupts::from_bits_truncate(interrupt as u32)) - } - - /// Starts listening for a set of CAN interrupts. - #[inline] - pub fn enable_interrupts(&mut self, interrupts: Interrupts) { - self.registers() - .ie - .modify(|r, w| unsafe { w.bits(r.bits() | interrupts.bits()) }) - } - - /// Stops listening for a CAN interrupt. - pub fn disable_interrupt(&mut self, interrupt: Interrupt) { - self.disable_interrupts(Interrupts::from_bits_truncate(interrupt as u32)) - } - - /// Stops listening for a set of CAN interrupts. - #[inline] - pub fn disable_interrupts(&mut self, interrupts: Interrupts) { - self.registers() - .ie - .modify(|r, w| unsafe { w.bits(r.bits() & !interrupts.bits()) }) - } - - /// Retrieve the CAN error counters - #[inline] - pub fn error_counters(&self) -> ErrorCounters { - self.control.error_counters() - } - - /// Set an Standard Address CAN filter into slot 'id' - #[inline] - pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) { - self.msg_ram_mut().filters.flssa[slot as usize].activate(filter); - } - - /// Set an array of Standard Address CAN filters and overwrite the current set - pub fn set_standard_filters( - &mut self, - filters: &[StandardFilter; STANDARD_FILTER_MAX as usize], - ) { - for (i, f) in filters.iter().enumerate() { - self.msg_ram_mut().filters.flssa[i].activate(*f); - } - } - - /// Set an Extended Address CAN filter into slot 'id' - #[inline] - pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { - self.msg_ram_mut().filters.flesa[slot as usize].activate(filter); - } - - /// Set an array of Extended Address CAN filters and overwrite the current set - pub fn set_extended_filters( - &mut self, - filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize], - ) { - for (i, f) in filters.iter().enumerate() { - self.msg_ram_mut().filters.flesa[i].activate(*f); - } - } - - /// Retrieve the current protocol status - pub fn get_protocol_status(&self) -> ProtocolStatus { - let psr = self.registers().psr.read(); - ProtocolStatus { - activity: Activity::try_from(0 /*psr.act().bits()*/).unwrap(), //TODO: stm32g4 does not allow reading from this register - transmitter_delay_comp: psr.tdcv().bits(), - bus_off_status: psr.bo().bit_is_set(), - error_warning: psr.ew().bit_is_set(), - error_passive_state: psr.ep().bit_is_set(), - last_error: LastErrorCode::try_from(psr.lec().bits()).unwrap(), - } - } - - /// Check if the interrupt is triggered - #[inline] - pub fn has_interrupt(&mut self, interrupt: Interrupt) -> bool { - self.control.has_interrupt(interrupt) - } - - /// Clear specified interrupt - #[inline] - pub fn clear_interrupt(&mut self, interrupt: Interrupt) { - self.control.clear_interrupt(interrupt) - } - - /// Clear specified interrupts - #[inline] - pub fn clear_interrupts(&mut self, interrupts: Interrupts) { - self.control.clear_interrupts(interrupts) - } - - /// Splits this `FdCan` instance into transmitting and receiving halves, by reference. - #[inline] - #[allow(clippy::type_complexity)] - fn split_by_ref_generic( - &mut self, - ) -> ( - &mut FdCanControl, - &mut Tx, - &mut Rx, - &mut Rx, - ) { - // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. - let tx = unsafe { Tx::conjure_by_ref() }; - let rx0 = unsafe { Rx::conjure_by_ref() }; - let rx1 = unsafe { Rx::conjure_by_ref() }; - (&mut self.control, tx, rx0, rx1) - } - - /// Consumes this `FdCan` instance and splits it into transmitting and receiving halves. - #[inline] - #[allow(clippy::type_complexity)] - fn split_generic( - self, - ) -> ( - FdCanControl, - Tx, - Rx, - Rx, - ) { - // Safety: We must be carefull to not let them use each others registers - unsafe { (self.control, Tx::conjure(), Rx::conjure(), Rx::conjure()) } - } - - /// Combines an FdCanControl, Tx and the two Rx instances back into an FdCan instance - #[inline] - #[allow(clippy::type_complexity)] - pub fn combine( - t: ( - FdCanControl, - Tx, - Rx, - Rx, - ), - ) -> Self { - Self::create_can(t.0.config, t.0.instance) - } -} - -/// Select an FDCAN Clock Source -pub enum FdCanClockSource { - /// Select HSE as the FDCAN clock source - HSE = 0b00, - /// Select PLL "Q" clock as the FDCAN clock source - PLLQ = 0b01, - /// Select "P" clock as the FDCAN clock source - PCLK = 0b10, - //Reserved = 0b10, -} - -impl FdCan -where - I: Instance, -{ - /// Creates a CAN interface. - /// - /// Sets the FDCAN clock to the P clock if no FDCAN clock has been configured - /// If one has been configured, it will leave it as is. - #[inline] - pub fn new(can_instance: I, _tx: TX, _rx: RX, rcc: &Rcc) -> Self - where - TX: sealed::Tx, - RX: sealed::Rx, - { - I::enable(&rcc.rb); - - if rcc.rb.ccipr.read().fdcansel().is_hse() { - // Select P clock as FDCAN clock source - rcc.rb.ccipr.modify(|_, w| { - // This is sound, as `FdCanClockSource` only contains valid values for this field. - unsafe { - w.fdcansel().bits(FdCanClockSource::PCLK as u8); - } - - w - }); - } - //TODO: Set Speed to VeryHigh? - - let can = Self::create_can(FdCanConfig::default(), can_instance); - let reg = can.registers(); - assert!(reg.endn.read().bits() == 0x87654321_u32); - can - } - - /// Creates a CAN interface. - /// - /// Sets the FDCAN clock to the selected clock source - /// Note that this is shared across all instances. - /// Do not call this if there is allready an active FDCAN instance. - #[inline] - pub fn new_with_clock_source( - can_instance: I, - _tx: TX, - _rx: RX, - rcc: &Rcc, - clock_source: FdCanClockSource, - ) -> Self - where - TX: sealed::Tx, - RX: sealed::Rx, - { - rcc.rb.ccipr.modify(|_, w| { - // This is sound, as `FdCanClockSource` only contains valid values for this field. - unsafe { - w.fdcansel().bits(clock_source as u8); - } - - w - }); - - Self::new(can_instance, _tx, _rx, rcc) - } - - /// Moves out of PoweredDownMode and into ConfigMode - #[inline] - pub fn into_config_mode(mut self) -> FdCan { - self.set_power_down_mode(false); - self.enter_init_mode(); - - self.reset_msg_ram(); - - let can = self.registers(); - - // Framework specific settings are set here. // - - // set TxBuffer to Queue Mode; - // TODO: don't require this. - // can.txbc.write(|w| w.tfqm().set_bit()); - //FIXME: stm32g4 has the wrong layout here! - //We should be able to use the above, - //But right now, we just set the 24th bit. - can.txbc.write(|w| unsafe { w.bits(1_u32 << 24) }); - - // set standard filters list size to 28 - // set extended filters list size to 8 - // REQUIRED: we use the memory map as if these settings are set - // instead of re-calculating them. - can.rxgfc.modify(|_, w| unsafe { - w.lse() - .bits(EXTENDED_FILTER_MAX) - .lss() - .bits(STANDARD_FILTER_MAX) - }); - for fid in 0..STANDARD_FILTER_MAX { - self.set_standard_filter((fid as u8).into(), StandardFilter::disable()); - } - for fid in 0..EXTENDED_FILTER_MAX { - self.set_extended_filter(fid.into(), ExtendedFilter::disable()); - } - - self.into_can_mode() - } - - /// Disables the CAN interface and returns back the raw peripheral it was created from. - #[inline] - pub fn free(mut self) -> I { - self.disable_interrupts(Interrupts::all()); - - //TODO check this! - self.enter_init_mode(); - self.set_power_down_mode(true); - self.control.instance - } -} - -impl FdCan -where - I: Instance, -{ - #[inline] - fn leave_init_mode(&mut self) { - self.apply_config(self.control.config); - - let can = self.registers(); - can.cccr.modify(|_, w| w.cce().clear_bit()); - can.cccr.modify(|_, w| w.init().clear_bit()); - while can.cccr.read().init().bit_is_set() {} - } - - /// Moves out of ConfigMode and into InternalLoopbackMode - #[inline] - pub fn into_internal_loopback(mut self) -> FdCan { - self.set_loopback_mode(LoopbackMode::Internal); - self.leave_init_mode(); - - self.into_can_mode() - } - - /// Moves out of ConfigMode and into ExternalLoopbackMode - #[inline] - pub fn into_external_loopback(mut self) -> FdCan { - self.set_loopback_mode(LoopbackMode::External); - self.leave_init_mode(); - - self.into_can_mode() - } - - /// Moves out of ConfigMode and into RestrictedOperationMode - #[inline] - pub fn into_restricted(mut self) -> FdCan { - self.set_restricted_operations(true); - self.leave_init_mode(); - - self.into_can_mode() - } - - /// Moves out of ConfigMode and into NormalOperationMode - #[inline] - pub fn into_normal(mut self) -> FdCan { - self.set_normal_operations(true); - self.leave_init_mode(); - - self.into_can_mode() - } - - /// Moves out of ConfigMode and into BusMonitoringMode - #[inline] - pub fn into_bus_monitoring(mut self) -> FdCan { - self.set_bus_monitoring_mode(true); - self.leave_init_mode(); - - self.into_can_mode() - } - - /// Moves out of ConfigMode and into Testmode - #[inline] - pub fn into_test_mode(mut self) -> FdCan { - self.set_test_mode(true); - self.leave_init_mode(); - - self.into_can_mode() - } - - /// Moves out of ConfigMode and into PoweredDownmode - #[inline] - pub fn into_powered_down(mut self) -> FdCan { - self.set_power_down_mode(true); - self.leave_init_mode(); - - self.into_can_mode() - } - - /// Applies the settings of a new FdCanConfig - /// See `[FdCanConfig]` for more information - #[inline] - pub fn apply_config(&mut self, config: FdCanConfig) { - self.set_data_bit_timing(config.dbtr); - self.set_nominal_bit_timing(config.nbtr); - self.set_automatic_retransmit(config.automatic_retransmit); - self.set_transmit_pause(config.transmit_pause); - self.set_frame_transmit(config.frame_transmit); - self.set_interrupt_line_config(config.interrupt_line_config); - self.set_non_iso_mode(config.non_iso_mode); - self.set_edge_filtering(config.edge_filtering); - self.set_protocol_exception_handling(config.protocol_exception_handling); - self.set_global_filter(config.global_filter); - } - - /// 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. - #[inline] - pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) { - self.control.config.nbtr = btr; - - let can = self.registers(); - can.nbtp.write(|w| unsafe { - w.nbrp() - .bits(btr.nbrp() - 1) - .ntseg1() - .bits(btr.ntseg1() - 1) - .ntseg2() - .bits(btr.ntseg2() - 1) - .nsjw() - .bits(btr.nsjw() - 1) - }); - } - - /// Configures the data bit timings for the FdCan Variable Bitrates. - /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. - #[inline] - pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) { - self.control.config.dbtr = btr; - - let can = self.registers(); - can.dbtp.write(|w| unsafe { - w.dbrp() - .bits(btr.dbrp() - 1) - .dtseg1() - .bits(btr.dtseg1() - 1) - .dtseg2() - .bits(btr.dtseg2() - 1) - .dsjw() - .bits(btr.dsjw() - 1) - }); - } - - /// Enables or disables automatic retransmission of messages - /// - /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame - /// util it can be sent. Otherwise, it will try only once to send each frame. - /// - /// Automatic retransmission is enabled by default. - #[inline] - pub fn set_automatic_retransmit(&mut self, enabled: bool) { - let can = self.registers(); - can.cccr.modify(|_, w| w.dar().bit(!enabled)); - self.control.config.automatic_retransmit = enabled; - } - - /// Configures the transmit pause feature - /// See `[FdCanConfig]` for more information - #[inline] - pub fn set_transmit_pause(&mut self, enabled: bool) { - let can = self.registers(); - can.cccr.modify(|_, w| w.dar().bit(!enabled)); - self.control.config.transmit_pause = enabled; - } - - /// Configures non-iso mode - /// See `[FdCanConfig]` for more information - #[inline] - pub fn set_non_iso_mode(&mut self, enabled: bool) { - let can = self.registers(); - can.cccr.modify(|_, w| w.niso().bit(enabled)); - self.control.config.non_iso_mode = enabled; - } - - /// Configures edge filtering - /// See `[FdCanConfig]` for more information - #[inline] - pub fn set_edge_filtering(&mut self, enabled: bool) { - let can = self.registers(); - can.cccr.modify(|_, w| w.efbi().bit(enabled)); - self.control.config.edge_filtering = enabled; - } - - /// Configures frame transmission mode - /// See `[FdCanConfig]` for more information - #[inline] - pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) { - let (fdoe, brse) = match fts { - FrameTransmissionConfig::ClassicCanOnly => (false, false), - FrameTransmissionConfig::AllowFdCan => (true, false), - FrameTransmissionConfig::AllowFdCanAndBRS => (true, true), - }; - - let can = self.registers(); - can.cccr.modify(|_, w| w.fdoe().bit(fdoe).brse().bit(brse)); - - self.control.config.frame_transmit = fts; - } - - /// Configures the interrupt lines - /// See `[FdCanConfig]` for more information - #[inline] - pub fn set_interrupt_line_config(&mut self, l0int: Interrupts) { - let can = self.registers(); - - can.ils.modify(|_, w| unsafe { w.bits(l0int.bits()) }); - - self.control.config.interrupt_line_config = l0int; - } - - /// Sets the protocol exception handling on/off - #[inline] - pub fn set_protocol_exception_handling(&mut self, enabled: bool) { - let can = self.registers(); - - can.cccr.modify(|_, w| w.pxhd().bit(!enabled)); - - self.control.config.protocol_exception_handling = enabled; - } - - /// Sets the General FdCAN clock divider for this instance - //TODO: ?clock divider is a shared register? - #[inline] - pub fn set_clock_divider(&mut self, div: ClockDivider) { - let can = self.registers(); - - can.ckdiv.write(|w| unsafe { w.pdiv().bits(div as u8) }); - - self.control.config.clock_divider = div; - } - - /// Configures and resets the timestamp counter - #[inline] - pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { - let (tcp, tss) = match select { - TimestampSource::None => (0, 0b00), - TimestampSource::Prescaler(p) => (p as u8, 0b01), - TimestampSource::FromTIM3 => (0, 0b10), - }; - self.registers() - .tscc - .write(|w| unsafe { w.tcp().bits(tcp).tss().bits(tss) }); - - self.control.config.timestamp_source = select; - } - - /// Configures the global filter settings - #[inline] - pub fn set_global_filter(&mut self, filter: GlobalFilter) { - self.registers().rxgfc.modify(|_, w| { - unsafe { - w.anfs() - .bits(filter.handle_standard_frames as u8) - .anfe() - .bits(filter.handle_extended_frames as u8) - } - .rrfs() - .bit(filter.reject_remote_standard_frames) - .rrfe() - .bit(filter.reject_remote_extended_frames) - }); - } - - /// Returns the current FdCan timestamp counter - #[inline] - pub fn timestamp(&self) -> u16 { - self.control.timestamp() - } -} - -impl FdCan -where - I: Instance, -{ - /// Returns out of InternalLoopbackMode and back into ConfigMode - #[inline] - pub fn into_config_mode(mut self) -> FdCan { - self.set_loopback_mode(LoopbackMode::None); - self.enter_init_mode(); - - self.into_can_mode() - } -} - -impl FdCan -where - I: Instance, -{ - /// Returns out of ExternalLoopbackMode and back into ConfigMode - #[inline] - pub fn into_config_mode(mut self) -> FdCan { - self.set_loopback_mode(LoopbackMode::None); - self.enter_init_mode(); - - self.into_can_mode() - } -} - -impl FdCan -where - I: Instance, -{ - /// Returns out of NormalOperationMode and back into ConfigMode - #[inline] - pub fn into_config_mode(mut self) -> FdCan { - self.set_normal_operations(false); - self.enter_init_mode(); - - self.into_can_mode() - } -} - -impl FdCan -where - I: Instance, -{ - /// Returns out of RestrictedOperationMode and back into ConfigMode - #[inline] - pub fn into_config_mode(mut self) -> FdCan { - self.set_restricted_operations(false); - self.enter_init_mode(); - - self.into_can_mode() - } -} - -impl FdCan -where - I: Instance, -{ - /// Returns out of BusMonitoringMode and back into ConfigMode - #[inline] - pub fn into_config_mode(mut self) -> FdCan { - self.set_bus_monitoring_mode(false); - self.enter_init_mode(); - - self.into_can_mode() - } -} - -/// states of the test.tx register -pub enum TestTransmitPinState { - /// CAN core has control (default) - CoreHasControl = 0b00, - /// Sample point can be monitored - ShowSamplePoint = 0b01, - /// Set to Dominant (0) Level - SetDominant = 0b10, - /// Set to Recessive (1) Level - SetRecessive = 0b11, -} - -impl FdCan -where - I: Instance, -{ - /// Returns out of TestMode and back into ConfigMode - #[inline] - pub fn into_config_mode(mut self) -> FdCan { - self.set_test_mode(false); - self.enter_init_mode(); - - self.into_can_mode() - } - - /// Gets the state of the receive pin to either Dominant (false), or Recessive (true) - pub fn get_receive_pin(&mut self) -> bool { - let can = self.registers(); - - can.test.read().rx().bit_is_set() - } - - /// Sets the state of the transmit pin according to TestTransmitPinState - pub fn set_transmit_pin(&mut self, state: TestTransmitPinState) { - let can = self.registers(); - - //SAFE: state has all possible values, and this can only occur in TestMode - can.test.modify(|_, w| unsafe { w.tx().bits(state as u8) }); - } -} - -impl FdCan -where - I: Instance, - M: Transmit + Receive, -{ - /// Splits this `FdCan` instance into transmitting and receiving halves, by reference. - #[inline] - #[allow(clippy::type_complexity)] - pub fn split_by_ref( - &mut self, - ) -> ( - &mut FdCanControl, - &mut Tx, - &mut Rx, - &mut Rx, - ) { - self.split_by_ref_generic() - } - - /// Consumes this `FdCan` instance and splits it into transmitting and receiving halves. - #[allow(clippy::type_complexity)] - pub fn split( - self, - ) -> ( - FdCanControl, - Tx, - Rx, - Rx, - ) { - self.split_generic() - } -} - -impl FdCan -where - I: Instance, - M: Transmit, -{ - /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. - /// - /// Frames are transmitted to the bus based on their priority (identifier). - /// Transmit order is preserved for frames with identical identifiers. - /// If all transmit mailboxes are full, this overwrites the mailbox with - /// the lowest priority. - #[inline] - pub fn transmit( - &mut self, - frame: TxFrameHeader, - write: &mut WTX, - ) -> nb::Result, Infallible> - where - WTX: FnMut(&mut [u32]), - { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure().transmit(frame, write) } - } - - /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. - /// - /// Frames are transmitted to the bus based on their priority (identifier). - /// Transmit order is preserved for frames with identical identifiers. - /// If all transmit mailboxes are full, `pending` is called with the mailbox, - /// header and data of the to-be-replaced frame. - pub fn transmit_preserve( - &mut self, - frame: TxFrameHeader, - write: &mut WTX, - pending: &mut PTX, - ) -> nb::Result, Infallible> - where - PTX: FnMut(Mailbox, TxFrameHeader, &[u32]) -> P, - WTX: FnMut(&mut [u32]), - { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure().transmit_preserve(frame, write, pending) } - } - - /// Returns `true` if no frame is pending for transmission. - #[inline] - pub fn is_transmitter_idle(&self) -> bool { - // Safety: Read-only operation. - unsafe { Tx::::conjure().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`. - #[inline] - pub fn abort(&mut self, mailbox: Mailbox) -> bool { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Tx::::conjure().abort(mailbox) } - } -} - -impl FdCan -where - I: Instance, - M: Receive, -{ - /// Returns a received frame from FIFO_0 if available. - #[inline] - pub fn receive0( - &mut self, - receive: &mut RECV, - ) -> nb::Result, Infallible> - where - RECV: FnMut(RxFrameInfo, &[u32]) -> R, - { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Rx::::conjure().receive(receive) } - } - - /// Returns a received frame from FIFO_1 if available. - #[inline] - pub fn receive1( - &mut self, - receive: &mut RECV, - ) -> nb::Result, Infallible> - where - RECV: FnMut(RxFrameInfo, &[u32]) -> R, - { - // Safety: We have a `&mut self` and have unique access to the peripheral. - unsafe { Rx::::conjure().receive(receive) } - } -} - -/// FdCanControl Struct -/// Used to house some information during an FdCan split. -/// and can be used for some generic information retrieval during operation. -pub struct FdCanControl -where - I: Instance, -{ - config: FdCanConfig, - instance: I, - _mode: PhantomData, -} -impl FdCanControl -where - I: Instance, -{ - #[inline] - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } - } - - /// Returns the current error counters - #[inline] - pub fn error_counters(&self) -> ErrorCounters { - let can = self.registers(); - let cel: u8 = can.ecr.read().cel().bits(); - let rp: bool = can.ecr.read().rp().bit(); - let rec: u8 = can.ecr.read().rec().bits(); - let tec: u8 = can.ecr.read().tec().bits(); - - ErrorCounters { - can_errors: cel, - transmit_err: tec, - receive_err: match rp { - false => ReceiveErrorOverflow::Normal(rec), - true => ReceiveErrorOverflow::Overflow(rec), - }, - } - } - - /// Returns the current FdCan Timestamp counter - #[inline] - pub fn timestamp(&self) -> u16 { - self.registers().tscv.read().tsc().bits() - } - - /// Check if the interrupt is triggered - #[inline] - pub fn has_interrupt(&mut self, interrupt: Interrupt) -> bool { - let can = self.registers(); - can.ir.read().bits() & (interrupt as u32) > 0 - } - - /// Clear specified interrupt - #[inline] - pub fn clear_interrupt(&mut self, interrupt: Interrupt) { - let can = self.registers(); - can.ir.write(|w| unsafe { w.bits(interrupt as u32) }); - } - - /// Clear specified interrupts - #[inline] - pub fn clear_interrupts(&mut self, interrupts: Interrupts) { - let can = self.registers(); - can.ir.write(|w| unsafe { w.bits(interrupts.bits()) }); - } -} - -/// Interface to the CAN transmitter part. -pub struct Tx { - _can: PhantomData, - _mode: PhantomData, -} - -impl Tx -where - I: Instance, -{ - #[inline] - unsafe fn conjure() -> Self { - Self { - _can: PhantomData, - _mode: PhantomData, - } - } - - /// Creates a `&mut Self` out of thin air. - /// - /// This is only safe if it is the only way to access a `Tx`. - #[inline] - unsafe fn conjure_by_ref<'a>() -> &'a mut Self { - // Cause out of bounds access when `Self` is not zero-sized. - #[allow(clippy::unnecessary_operation)] - [()][core::mem::size_of::()]; - - // Any aligned pointer is valid for ZSTs. - &mut *NonNull::dangling().as_ptr() - } - - #[inline] - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } - } - - #[inline] - fn tx_msg_ram(&self) -> &message_ram::Transmit { - unsafe { &(*I::MSG_RAM).transmit } - } - - #[inline] - fn tx_msg_ram_mut(&mut self) -> &mut message_ram::Transmit { - unsafe { &mut (*I::MSG_RAM).transmit } - } - - /// Puts a CAN frame in a transmit mailbox for transmission on the bus. - /// - /// Frames are transmitted to the bus based on their priority (identifier). Transmit order is - /// preserved for frames with identical identifiers. - /// - /// If all transmit mailboxes are full, a higher priority frame can replace a lower-priority - /// frame, which is returned via the closure 'pending'. If 'pending' is called; it's return value - /// is returned via Option

, if it is not, None is returned. - /// If there are only higher priority frames in the queue, this returns Err::WouldBlock - pub fn transmit( - &mut self, - frame: TxFrameHeader, - write: &mut WTX, - ) -> nb::Result, Infallible> - where - WTX: FnMut(&mut [u32]), - { - self.transmit_preserve(frame, write, &mut |_, _, _| ()) - } - - /// As Transmit, but if there is a pending frame, `pending` will be called so that the frame can - /// be preserved. - pub fn transmit_preserve( - &mut self, - frame: TxFrameHeader, - write: &mut WTX, - pending: &mut PTX, - ) -> nb::Result, Infallible> - where - PTX: FnMut(Mailbox, TxFrameHeader, &[u32]) -> P, - WTX: FnMut(&mut [u32]), - { - let can = self.registers(); - let queue_is_full = self.tx_queue_is_full(); - - let id = frame.into(); - - // If the queue is full, - // Discard the first slot with a lower priority message - let (idx, pending_frame) = if queue_is_full { - if self.is_available(Mailbox::_0, id) { - ( - Mailbox::_0, - self.abort_pending_mailbox(Mailbox::_0, pending), - ) - } else if self.is_available(Mailbox::_1, id) { - ( - Mailbox::_1, - self.abort_pending_mailbox(Mailbox::_1, pending), - ) - } else if self.is_available(Mailbox::_2, id) { - ( - Mailbox::_2, - self.abort_pending_mailbox(Mailbox::_2, pending), - ) - } else { - // For now we bail when there is no lower priority slot available - // Can this lead to priority inversion? - return Err(nb::Error::WouldBlock); - } - } else { - // Read the Write Pointer - let idx = can.txfqs.read().tfqpi().bits(); - - (Mailbox::new(idx), None) - }; - - self.write_mailbox(idx, frame, write); - - Ok(pending_frame) - } - - /// Returns if the tx queue is able to accept new messages without having to cancel an existing one - #[inline] - pub fn tx_queue_is_full(&self) -> bool { - self.registers().txfqs.read().tfqf().bit() - } - - /// Returns `Ok` when the mailbox is free or if it contains pending frame with a - /// lower priority (higher ID) than the identifier `id`. - #[inline] - fn is_available(&self, idx: Mailbox, id: IdReg) -> bool { - if self.has_pending_frame(idx) { - //read back header section - let header: TxFrameHeader = (&self.tx_msg_ram().tbsa[idx as usize].header).into(); - let old_id: IdReg = header.into(); - - id > old_id - } else { - true - } - } - - #[inline] - fn write_mailbox(&mut self, idx: Mailbox, tx_header: TxFrameHeader, transmit: TX) -> R - where - TX: FnOnce(&mut [u32]) -> R, - { - let tx_ram = self.tx_msg_ram_mut(); - - // Clear mail slot; mainly for debugging purposes. - tx_ram.tbsa[idx as usize].reset(); - - // Calculate length of data in words - let data_len = ((tx_header.len as usize) + 3) / 4; - - //set header section - tx_ram.tbsa[idx as usize].header.merge(tx_header); - - //set data - let result = transmit(&mut tx_ram.tbsa[idx as usize].data[0..data_len]); - - // Set as ready to transmit - self.registers() - .txbar - .modify(|r, w| unsafe { w.ar().bits(r.ar().bits() | 1 << (idx as u32)) }); - - result - } - - #[inline] - fn abort_pending_mailbox(&mut self, idx: Mailbox, pending: PTX) -> Option - where - PTX: FnOnce(Mailbox, TxFrameHeader, &[u32]) -> R, - { - if self.abort(idx) { - let tx_ram = self.tx_msg_ram(); - - //read back header section - let header = (&tx_ram.tbsa[idx as usize].header).into(); - Some(pending(idx, header, &tx_ram.tbsa[idx as usize].data)) - } 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 - } - } - - /// 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`. - #[inline] - fn abort(&mut self, idx: Mailbox) -> bool { - let can = self.registers(); - - // Check if there is a request pending to abort - if self.has_pending_frame(idx) { - let idx: u8 = idx.into(); - let idx = 1u8 << idx; - - // Abort Request - can.txbcr.write(|w| unsafe { w.cr().bits(idx) }); - - // Wait for the abort request to be finished. - loop { - if can.txbcf.read().cf().bits() & idx != 0 { - // Return false when a transmission has occured - break can.txbto.read().to().bits() & idx == 0; - } - } - } else { - false - } - } - - #[inline] - fn has_pending_frame(&self, idx: Mailbox) -> bool { - let can = self.registers(); - let idx: u8 = idx.into(); - let idx = 1u8 << idx; - - can.txbrp.read().trp().bits() & idx != 0 - } - - /// Returns `true` if no frame is pending for transmission. - #[inline] - pub fn is_idle(&self) -> bool { - let can = self.registers(); - can.txbrp.read().trp().bits() == 0x0 - } - - /// Clears the transmission complete flag. - #[inline] - pub fn clear_transmission_completed_flag(&mut self) { - let can = self.registers(); - can.ir.write(|w| w.tc().set_bit()); - } - - /// Clears the transmission cancelled flag. - #[inline] - pub fn clear_transmission_cancelled_flag(&mut self) { - let can = self.registers(); - can.ir.write(|w| w.tcf().set_bit()); - } -} - -#[doc(hidden)] -pub trait FifoNr: crate::sealed::Sealed { - const NR: usize; -} -#[doc(hidden)] -pub struct Fifo0; -impl crate::sealed::Sealed for Fifo0 {} -impl FifoNr for Fifo0 { - const NR: usize = 0; -} -#[doc(hidden)] -pub struct Fifo1; -impl crate::sealed::Sealed for Fifo1 {} -impl FifoNr for Fifo1 { - const NR: usize = 1; -} - -/// Notes whether an overrun has occurred. -/// Since both arms contain T, this can be 'unwrap'ed without causing a panic. -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum ReceiveOverrun { - /// No overrun has occured - NoOverrun(T), - /// an overrun has occurered - Overrun(T), -} -impl ReceiveOverrun { - /// unwraps itself and returns T - /// in contradiction to Option::unwrap, this does not panic - /// since both elements contain T. - #[inline] - pub fn unwrap(self) -> T { - match self { - ReceiveOverrun::NoOverrun(t) | ReceiveOverrun::Overrun(t) => t, - } - } -} - -/// Interface to the CAN receiver part. -pub struct Rx -where - FIFONR: FifoNr, -{ - _can: PhantomData, - _mode: PhantomData, - _nr: PhantomData, -} - -impl Rx -where - FIFONR: FifoNr, - I: Instance, -{ - #[inline] - unsafe fn conjure() -> Self { - Self { - _can: PhantomData, - _mode: PhantomData, - _nr: PhantomData, - } - } - - /// Creates a `&mut Self` out of thin air. - /// - /// This is only safe if it is the only way to access an `Rx`. - #[inline] - unsafe fn conjure_by_ref<'a>() -> &'a mut Self { - // Cause out of bounds access when `Self` is not zero-sized. - #[allow(clippy::unnecessary_operation)] - [()][core::mem::size_of::()]; - - // Any aligned pointer is valid for ZSTs. - &mut *NonNull::dangling().as_ptr() - } - - /// Returns a received frame if available. - /// - /// Returns `Err` when a frame was lost due to buffer overrun. - pub fn receive( - &mut self, - receive: &mut RECV, - ) -> nb::Result, Infallible> - where - RECV: FnMut(RxFrameInfo, &[u32]) -> R, - { - if !self.rx_fifo_is_empty() { - let mbox = self.get_rx_mailbox(); - let idx: usize = mbox.into(); - let mailbox: &RxFifoElement = &self.rx_msg_ram().fxsa[idx]; - - let header: RxFrameInfo = (&mailbox.header).into(); - let word_len = (header.len + 3) / 4; - let result = Ok(receive(header, &mailbox.data[0..word_len as usize])); - self.release_mailbox(mbox); - - if self.has_overrun() { - result.map(ReceiveOverrun::Overrun) - } else { - result.map(ReceiveOverrun::NoOverrun) - } - } else { - Err(nb::Error::WouldBlock) - } - } - - #[inline] - fn registers(&self) -> &RegisterBlock { - unsafe { &*I::REGISTERS } - } - - #[inline] - fn rx_msg_ram(&self) -> &message_ram::Receive { - unsafe { &(&(*I::MSG_RAM).receive)[FIFONR::NR] } - } - - #[inline] - fn has_overrun(&self) -> bool { - let can = self.registers(); - match FIFONR::NR { - 0 => can.rxf0s.read().rf0l().bit(), - 1 => can.rxf1s.read().rf1l().bit(), - _ => unreachable!(), - } - } - - /// Returns if the fifo contains any new messages. - #[inline] - pub fn rx_fifo_is_empty(&self) -> bool { - let can = self.registers(); - match FIFONR::NR { - 0 => can.rxf0s.read().f0fl().bits() == 0, - 1 => can.rxf1s.read().f1fl().bits() == 0, - _ => unreachable!(), - } - } - - #[inline] - fn release_mailbox(&mut self, idx: Mailbox) { - unsafe { - (*I::MSG_RAM).receive[FIFONR::NR].fxsa[idx as u8 as usize].reset(); - } - - let can = self.registers(); - match FIFONR::NR { - 0 => can.rxf0a.write(|w| unsafe { w.f0ai().bits(idx.into()) }), - 1 => can.rxf1a.write(|w| unsafe { w.f1ai().bits(idx.into()) }), - _ => unreachable!(), - } - } - - #[inline] - fn get_rx_mailbox(&self) -> Mailbox { - let can = self.registers(); - let idx = match FIFONR::NR { - 0 => can.rxf0s.read().f0gi().bits(), - 1 => can.rxf1s.read().f1gi().bits(), - _ => unreachable!(), - }; - Mailbox::new(idx) - } -} - -/// The three mailboxes. -/// These are used for the transmit queue -/// and the two Receive FIFOs -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum Mailbox { - /// Transmit mailbox 0 - _0 = 0, - /// Transmit mailbox 1 - _1 = 1, - /// Transmit mailbox 2 - _2 = 2, -} -impl Mailbox { - #[inline] - fn new(idx: u8) -> Self { - match idx & 0b11 { - 0 => Mailbox::_0, - 1 => Mailbox::_1, - 2 => Mailbox::_2, - _ => unreachable!(), - } - } -} -impl From for u8 { - #[inline] - fn from(m: Mailbox) -> Self { - m as u8 - } -} -impl From for usize { - #[inline] - fn from(m: Mailbox) -> Self { - m as u8 as usize - } -} - -mod impls { - use super::sealed; - - /// Implements sealed::{Tx,Rx} for pins associated with a CAN peripheral - macro_rules! pins { - ($PER:ident => - (tx: [ $($( #[ $pmetatx:meta ] )* $tx:ident<$txaf:ident>),+ $(,)? ], - rx: [ $($( #[ $pmetarx:meta ] )* $rx:ident<$rxaf:ident>),+ $(,)? ])) => { - $( - $( #[ $pmetatx ] )* - impl super::sealed::Tx<$PER> for $tx> {} - )+ - $( - $( #[ $pmetarx ] )* - impl super::sealed::Rx<$PER> for $rx> {} - )+ - }; - } - - mod fdcan1 { - use crate::fdcan; - use crate::fdcan::message_ram; - use crate::gpio::{ - gpioa::{PA11, PA12}, - gpiob::{PB8, PB9}, - gpiod::{PD0, PD1}, - AF9, - }; - use crate::stm32; - use crate::stm32::FDCAN1; - - // All STM32G4 models with CAN support these pins - pins! { - FDCAN1 => ( - tx: [ - PA12, - PB9, - PD1, - ], - rx: [ - PA11, - PB8, - PD0, - ] - ) - } - - unsafe impl message_ram::MsgRamExt for FDCAN1 { - const MSG_RAM: *mut message_ram::RegisterBlock = (0x4000_a400 as *mut _); - } - unsafe impl fdcan::Instance for FDCAN1 { - const REGISTERS: *mut stm32::fdcan::RegisterBlock = FDCAN1::ptr() as *mut _; - } - } - - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484", - feature = "stm32g491", - feature = "stm32g4A1", - ))] - mod fdcan2 { - use crate::fdcan; - use crate::fdcan::message_ram; - use crate::gpio::{ - gpiob::{PB12, PB13, PB5, PB6}, - AF9, - }; - use crate::stm32::{self, FDCAN2}; - - pins! { - FDCAN2 => ( - tx: [ - PB6, - PB13, - ], - rx: [ - PB5, - PB12, - ]) - } - - unsafe impl fdcan::Instance for FDCAN2 { - const REGISTERS: *mut stm32::fdcan::RegisterBlock = FDCAN2::ptr() as *mut _; - } - - unsafe impl message_ram::MsgRamExt for FDCAN2 { - const MSG_RAM: *mut message_ram::RegisterBlock = (0x4000_a750 as *mut _); - } - } - - #[cfg(any( - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484", - ))] - mod fdcan3 { - use crate::fdcan; - use crate::fdcan::message_ram; - use crate::gpio::{ - gpioa::{PA15, PA8}, - gpiob::{PB3, PB4}, - AF11, - }; - use crate::stm32::{self, FDCAN3}; - - pins! { - FDCAN3 => ( - tx: [ - PA15, - PB4, - ], - rx: [ - PA8, - PB3, - ]) - } - - unsafe impl fdcan::Instance for FDCAN3 { - const REGISTERS: *mut stm32::fdcan::RegisterBlock = FDCAN3::ptr() as *mut _; - } - - unsafe impl message_ram::MsgRamExt for FDCAN3 { - const MSG_RAM: *mut message_ram::RegisterBlock = (0x4000_aaa0 as *mut _); - } - } -} diff --git a/src/fdcan/filter.rs b/src/fdcan/filter.rs deleted file mode 100644 index a770ab23..00000000 --- a/src/fdcan/filter.rs +++ /dev/null @@ -1,401 +0,0 @@ -use super::id::{ExtendedId, StandardId}; - -pub use message_ram::{EXTENDED_FILTER_MAX, STANDARD_FILTER_MAX}; - -/// A Standard Filter -pub type StandardFilter = Filter; -/// An Extended Filter -pub type ExtendedFilter = Filter; - -impl Default for StandardFilter { - fn default() -> Self { - StandardFilter::disable() - } -} -impl Default for ExtendedFilter { - fn default() -> Self { - ExtendedFilter::disable() - } -} - -impl StandardFilter { - /// Accept all messages in FIFO 0 - pub fn accept_all_into_fifo0() -> StandardFilter { - StandardFilter { - filter: FilterType::BitMask { - filter: 0x0, - mask: 0x0, - }, - action: Action::StoreInFifo0, - } - } - - /// Accept all messages in FIFO 1 - pub fn accept_all_into_fifo1() -> StandardFilter { - StandardFilter { - filter: FilterType::BitMask { - filter: 0x0, - mask: 0x0, - }, - action: Action::StoreInFifo1, - } - } - - /// Reject all messages - pub fn reject_all() -> StandardFilter { - StandardFilter { - filter: FilterType::BitMask { - filter: 0x0, - mask: 0x0, - }, - action: Action::Reject, - } - } - - /// Disable the filter - pub fn disable() -> StandardFilter { - StandardFilter { - filter: FilterType::Disabled, - action: Action::Disable, - } - } -} - -impl ExtendedFilter { - /// Accept all messages in FIFO 0 - pub fn accept_all_into_fifo0() -> ExtendedFilter { - ExtendedFilter { - filter: FilterType::BitMask { - filter: 0x0, - mask: 0x0, - }, - action: Action::StoreInFifo0, - } - } - - /// Accept all messages in FIFO 1 - pub fn accept_all_into_fifo1() -> ExtendedFilter { - ExtendedFilter { - filter: FilterType::BitMask { - filter: 0x0, - mask: 0x0, - }, - action: Action::StoreInFifo1, - } - } - - /// Reject all messages - pub fn reject_all() -> ExtendedFilter { - ExtendedFilter { - filter: FilterType::BitMask { - filter: 0x0, - mask: 0x0, - }, - action: Action::Reject, - } - } - - /// Disable the filter - pub fn disable() -> ExtendedFilter { - ExtendedFilter { - filter: FilterType::Disabled, - action: Action::Disable, - } - } -} - -/// Filter Type -//#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -#[derive(Clone, Copy, Debug)] -pub enum FilterType -where - ID: Copy + Clone + core::fmt::Debug, - UNIT: Copy + Clone + core::fmt::Debug, -{ - /// Match with a range between two messages - Range { - /// First Id of the range - from: ID, - /// Last Id of the range - to: ID, - }, - /// Match with a bitmask - BitMask { - /// Filter of the bitmask - filter: UNIT, - /// Mask of the bitmask - mask: UNIT, - }, - /// Match with a single ID - DedicatedSingle(ID), - /// Match with one of two ID's - DedicatedDual(ID, ID), - /// Filter is disabled - Disabled, -} -impl From> for super::message_ram::enums::FilterType -where - ID: Copy + Clone + core::fmt::Debug, - UNIT: Copy + Clone + core::fmt::Debug, -{ - fn from(f: FilterType) -> Self { - match f { - FilterType::Range { to: _, from: _ } => Self::RangeFilter, - FilterType::BitMask { filter: _, mask: _ } => Self::ClassicFilter, - FilterType::DedicatedSingle(_) => Self::DualIdFilter, - FilterType::DedicatedDual(_, _) => Self::DualIdFilter, - FilterType::Disabled => Self::FilterDisabled, - } - } -} - -/// Filter Action -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum Action { - /// No Action - Disable = 0b000, - /// Store an matching message in FIFO 0 - StoreInFifo0 = 0b001, - /// Store an matching message in FIFO 1 - StoreInFifo1 = 0b010, - /// Reject an matching message - Reject = 0b011, - /// Flag a matching message (But not store?!?) - FlagHighPrio = 0b100, - /// Flag a matching message as a High Priority message and store it in FIFO 0 - FlagHighPrioAndStoreInFifo0 = 0b101, - /// Flag a matching message as a High Priority message and store it in FIFO 1 - FlagHighPrioAndStoreInFifo1 = 0b110, -} -impl From for super::message_ram::enums::FilterElementConfig { - fn from(a: Action) -> Self { - match a { - Action::Disable => Self::DisableFilterElement, - Action::StoreInFifo0 => Self::StoreInFifo0, - Action::StoreInFifo1 => Self::StoreInFifo1, - Action::Reject => Self::Reject, - Action::FlagHighPrio => Self::SetPriority, - Action::FlagHighPrioAndStoreInFifo0 => Self::SetPriorityAndStoreInFifo0, - Action::FlagHighPrioAndStoreInFifo1 => Self::SetPriorityAndStoreInFifo1, - } - } -} - -/// Filter -#[derive(Clone, Copy, Debug)] -//#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub struct Filter -where - ID: Copy + Clone + core::fmt::Debug, - UNIT: Copy + Clone + core::fmt::Debug, -{ - /// How to match an incoming message - pub filter: FilterType, - /// What to do with a matching message - pub action: Action, -} - -/// Standard Filter Slot -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum StandardFilterSlot { - /// 0 - _0 = 0, - /// 1 - _1 = 1, - /// 2 - _2 = 2, - /// 3 - _3 = 3, - /// 4 - _4 = 4, - /// 5 - _5 = 5, - /// 6 - _6 = 6, - /// 7 - _7 = 7, - /// 8 - _8 = 8, - /// 9 - _9 = 9, - /// 10 - _10 = 10, - /// 11 - _11 = 11, - /// 12 - _12 = 12, - /// 13 - _13 = 13, - /// 14 - _14 = 14, - /// 15 - _15 = 15, - /// 16 - _16 = 16, - /// 17 - _17 = 17, - /// 18 - _18 = 18, - /// 19 - _19 = 19, - /// 20 - _20 = 20, - /// 21 - _21 = 21, - /// 22 - _22 = 22, - /// 23 - _23 = 23, - /// 24 - _24 = 24, - /// 25 - _25 = 25, - /// 26 - _26 = 26, - /// 27 - _27 = 27, -} -impl From for StandardFilterSlot { - fn from(u: u8) -> Self { - match u { - 0 => StandardFilterSlot::_0, - 1 => StandardFilterSlot::_1, - 2 => StandardFilterSlot::_2, - 3 => StandardFilterSlot::_3, - 4 => StandardFilterSlot::_4, - 5 => StandardFilterSlot::_5, - 6 => StandardFilterSlot::_6, - 7 => StandardFilterSlot::_7, - 8 => StandardFilterSlot::_8, - 9 => StandardFilterSlot::_9, - 10 => StandardFilterSlot::_10, - 11 => StandardFilterSlot::_11, - 12 => StandardFilterSlot::_12, - 13 => StandardFilterSlot::_13, - 14 => StandardFilterSlot::_14, - 15 => StandardFilterSlot::_15, - 16 => StandardFilterSlot::_16, - 17 => StandardFilterSlot::_17, - 18 => StandardFilterSlot::_18, - 19 => StandardFilterSlot::_19, - 20 => StandardFilterSlot::_20, - 21 => StandardFilterSlot::_21, - 22 => StandardFilterSlot::_22, - 23 => StandardFilterSlot::_23, - 24 => StandardFilterSlot::_24, - 25 => StandardFilterSlot::_25, - 26 => StandardFilterSlot::_26, - 27 => StandardFilterSlot::_27, - _ => panic!("Standard Filter Slot Too High!"), - } - } -} - -/// Extended Filter Slot -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum ExtendedFilterSlot { - /// 0 - _0 = 0, - /// 1 - _1 = 1, - /// 2 - _2 = 2, - /// 3 - _3 = 3, - /// 4 - _4 = 4, - /// 5 - _5 = 5, - /// 6 - _6 = 6, - /// 7 - _7 = 7, -} -impl From for ExtendedFilterSlot { - fn from(u: u8) -> Self { - match u { - 0 => ExtendedFilterSlot::_0, - 1 => ExtendedFilterSlot::_1, - 2 => ExtendedFilterSlot::_2, - 3 => ExtendedFilterSlot::_3, - 4 => ExtendedFilterSlot::_4, - 5 => ExtendedFilterSlot::_5, - 6 => ExtendedFilterSlot::_6, - 7 => ExtendedFilterSlot::_7, - _ => panic!("Extended Filter Slot Too High!"), // Should be unreachable - } - } -} - -/// Enum over both Standard and Extended Filter ID's -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum FilterId { - /// Standard Filter Slots - Standard(StandardFilterSlot), - /// Extended Filter Slots - Extended(ExtendedFilterSlot), -} - -pub(crate) trait ActivateFilter -where - ID: Copy + Clone + core::fmt::Debug, - UNIT: Copy + Clone + core::fmt::Debug, -{ - fn activate(&mut self, f: Filter); - // fn read(&self) -> Filter; -} - -use super::message_ram; - -impl ActivateFilter for message_ram::StandardFilter { - fn activate(&mut self, f: Filter) { - let sft = f.filter.into(); - - let (sfid1, sfid2) = match f.filter { - FilterType::Range { to, from } => (to.as_raw(), from.as_raw()), - FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()), - FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()), - FilterType::BitMask { filter, mask } => (filter, mask), - FilterType::Disabled => (0x0, 0x0), - }; - let sfec = f.action.into(); - self.write(|w| { - unsafe { w.sfid1().bits(sfid1).sfid2().bits(sfid2) } - .sft() - .set_filter_type(sft) - .sfec() - .set_filter_element_config(sfec) - }); - } - // fn read(&self) -> Filter { - // todo!() - // } -} -impl ActivateFilter for message_ram::ExtendedFilter { - fn activate(&mut self, f: Filter) { - let eft = f.filter.into(); - - let (efid1, efid2) = match f.filter { - FilterType::Range { to, from } => (to.as_raw(), from.as_raw()), - FilterType::DedicatedSingle(id) => (id.as_raw(), id.as_raw()), - FilterType::DedicatedDual(id1, id2) => (id1.as_raw(), id2.as_raw()), - FilterType::BitMask { filter, mask } => (filter, mask), - FilterType::Disabled => (0x0, 0x0), - }; - let efec = f.action.into(); - self.write(|w| { - unsafe { w.efid1().bits(efid1).efid2().bits(efid2) } - .eft() - .set_filter_type(eft) - .efec() - .set_filter_element_config(efec) - }); - } - // fn read(&self) -> Filter { - // todo!() - // } -} diff --git a/src/fdcan/id.rs b/src/fdcan/id.rs deleted file mode 100644 index 20f77598..00000000 --- a/src/fdcan/id.rs +++ /dev/null @@ -1,311 +0,0 @@ -//! CAN Identifiers. - -use core::cmp::{Ord, Ordering}; - -use super::message_ram::enums::{IdType, RemoteTransmissionRequest}; - -/// Standard 11-bit CAN Identifier (`0..=0x7FF`). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub struct StandardId(u16); - -impl StandardId { - /// CAN ID `0`, the highest priority. - pub const ZERO: Self = Self(0); - - /// CAN ID `0x7FF`, the lowest priority. - pub const MAX: Self = Self(0x7FF); - - /// Tries to create a `StandardId` from a raw 16-bit integer. - /// - /// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`). - #[inline] - pub const fn new(raw: u16) -> Option { - if raw <= 0x7FF { - Some(Self(raw)) - } else { - None - } - } - - /// Creates a new `StandardId` without checking if it is inside the valid range. - /// - /// # Safety - /// - /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is - /// undefined. - #[inline] - pub const unsafe fn new_unchecked(raw: u16) -> Self { - Self(raw) - } - - /// Returns this CAN Identifier as a raw 16-bit integer. - #[inline] - pub fn as_raw(&self) -> u16 { - self.0 - } -} -impl From for IdType { - fn from(_id: StandardId) -> Self { - IdType::StandardId - } -} - -/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub struct ExtendedId(u32); - -impl ExtendedId { - /// CAN ID `0`, the highest priority. - pub const ZERO: Self = Self(0); - - /// CAN ID `0x1FFFFFFF`, the lowest priority. - pub const MAX: Self = Self(0x1FFF_FFFF); - - /// Tries to create a `ExtendedId` from a raw 32-bit integer. - /// - /// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`). - #[inline] - pub const fn new(raw: u32) -> Option { - if raw <= 0x1FFF_FFFF { - Some(Self(raw)) - } else { - None - } - } - - /// Creates a new `ExtendedId` without checking if it is inside the valid range. - /// - /// # Safety - /// - /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is - /// undefined. - #[inline] - pub const unsafe fn new_unchecked(raw: u32) -> Self { - Self(raw) - } - - /// Returns this CAN Identifier as a raw 32-bit integer. - #[inline] - pub fn as_raw(&self) -> u32 { - self.0 - } - - /// Returns the Base ID part of this extended identifier. - pub fn standard_id(&self) -> StandardId { - // ID-28 to ID-18 - StandardId((self.0 >> 18) as u16) - } -} - -impl From for IdType { - fn from(_id: ExtendedId) -> Self { - IdType::ExtendedId - } -} - -/// A CAN Identifier (standard or extended). -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum Id { - /// Standard 11-bit Identifier (`0..=0x7FF`). - Standard(StandardId), - - /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`). - Extended(ExtendedId), -} - -impl From for Id { - #[inline] - fn from(id: StandardId) -> Self { - Id::Standard(id) - } -} - -impl From for Id { - #[inline] - fn from(id: ExtendedId) -> Self { - Id::Extended(id) - } -} - -impl From for IdType { - #[inline] - fn from(id: Id) -> Self { - match id { - Id::Standard(id) => id.into(), - Id::Extended(id) => id.into(), - } - } -} - -/// Identifier of a CAN message. -/// -/// FdCan 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 = "unstable-defmt", derive(defmt::Format))] -pub(crate) struct IdReg(u32); - -impl IdReg { - const STANDARD_SHIFT: u32 = 18; - #[allow(dead_code)] - const STANDARD_MASK: u32 = 0x1FFC0000; - - const EXTENDED_SHIFT: u32 = 0; - const EXTENDED_MASK: u32 = 0x1FFFFFFF; - - const XTD_SHIFT: u32 = 30; - const XTD_MASK: u32 = 1 << Self::XTD_SHIFT; - - const RTR_SHIFT: u32 = 29; - const RTR_MASK: u32 = 1 << Self::RTR_SHIFT; - - /// 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) -> Self { - Self(id.as_raw() << Self::EXTENDED_SHIFT | (1 << Self::XTD_SHIFT)) - } - - pub(crate) fn as_raw_id(&self) -> u32 { - self.0 & Self::EXTENDED_MASK - } - - pub(crate) fn from_register(id: u32, rtr: RemoteTransmissionRequest, xtd: IdType) -> Self { - let rtr: u32 = match rtr { - RemoteTransmissionRequest::TransmitDataFrame => 0, - RemoteTransmissionRequest::TransmitRemoteFrame => 1 << Self::RTR_SHIFT, - }; - let xtd: u32 = match xtd { - IdType::StandardId => 0, - IdType::ExtendedId => 1 << Self::XTD_SHIFT, - }; - Self(id | rtr | xtd) - } - - /// Sets the remote transmission (RTR) flag. This marks the identifier as - /// being part of a remote frame. - #[must_use = "returns a new IdReg without modifying `self`"] - pub(crate) fn with_rtr(self, rtr: bool) -> Self { - if rtr { - Self(self.0 | (1 << Self::RTR_SHIFT)) - } else { - Self(self.0 & !Self::RTR_MASK) - } - } - - /// Returns the identifier. - pub fn to_id(self) -> Id { - if self.is_extended() { - Id::Extended(unsafe { - ExtendedId::new_unchecked((self.0 >> Self::EXTENDED_SHIFT) & Self::EXTENDED_MASK) - }) - } else { - Id::Standard(unsafe { - StandardId::new_unchecked( - ((self.0 >> Self::STANDARD_SHIFT) & Self::STANDARD_MASK) as u16, - ) - }) - } - } - - /// Returns `true` if the identifier is an extended identifier. - pub fn is_extended(self) -> bool { - (self.0 & Self::XTD_MASK) != 0 - } - - /// Returns `true` if the identifier is a standard identifier. - pub fn is_standard(self) -> bool { - !self.is_extended() - } - - /// Returns `true` if the identifer is part of a remote frame (RTR bit set). - pub(crate) fn rtr(self) -> bool { - self.0 & Self::RTR_MASK != 0 - } -} -impl From for IdReg { - fn from(id: Id) -> Self { - match id { - Id::Standard(s) => IdReg::new_standard(s), - Id::Extended(e) => IdReg::new_extended(e), - } - } -} -impl From for Id { - fn from(idr: IdReg) -> Self { - idr.to_id() - } -} -impl From for IdType { - #[inline] - fn from(id: IdReg) -> Self { - if id.is_standard() { - IdType::StandardId - } else { - IdType::ExtendedId - } - } -} -impl From for RemoteTransmissionRequest { - #[inline] - fn from(id: IdReg) -> Self { - if id.rtr() { - RemoteTransmissionRequest::TransmitRemoteFrame - } else { - RemoteTransmissionRequest::TransmitDataFrame - } - } -} - -/// `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)) - } -} diff --git a/src/fdcan/interrupt.rs b/src/fdcan/interrupt.rs deleted file mode 100644 index a9525e8e..00000000 --- a/src/fdcan/interrupt.rs +++ /dev/null @@ -1,205 +0,0 @@ -//! Interrupt types. - -use core::ops; - -#[allow(unused_imports)] // for intra-doc links only -use crate::fdcan::{FdCan, Rx}; - -/// FdCAN interrupt sources. -/// -/// These can be individually enabled and disabled in the FdCAN peripheral. Note that each FdCAN -/// peripheral only exposes 2 interrupts to the microcontroller: -/// -/// FDCANx_INTR0, -/// FDCANx_INTR1, -/// -/// The interrupts available on each line can be configured using the [`config::FdCanConfig`] struct. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Interrupt { - /// Rx FIFO 0 has a new message - RxFifo0NewMsg = 1 << 0, - /// Rx FIFO 0 is full - RxFifo0Full = 1 << 1, - /// Rx FIFO 0 has lost a message - RxFifo0MsgLost = 1 << 2, - /// Rx FIFO 1 has a new message - RxFifo1NewMsg = 1 << 3, - /// Rx FIFO 1 is full - RxFifo1Full = 1 << 4, - /// Rx FIFO 1 has lost a message - RxFifo1MsgLost = 1 << 5, - /// A High Priority Message has been flagged by a filter - RxHighPrio = 1 << 6, - /// Transmit has been completed - TxComplete = 1 << 7, - /// Tx message has been cancelled - TxCancel = 1 << 8, - /// Tx Fifo is empty - TxEmpty = 1 << 9, - /// An new Event has been received in the Tx Event Fifo - TxEventNew = 1 << 10, - /// The TxEvent Fifo is full - TxEventFull = 1 << 11, - /// An Tx Event has been lost - TxEventLost = 1 << 12, - /// Timestamp wrap around has occurred - TsWrapAround = 1 << 13, - /// Message RAM access failure - /// - /// The flag is set when the Rx handler: - /// has not completed acceptance filtering or storage of an accepted message until the - /// arbitration field of the following message has been received. In this case acceptance - /// filtering or message storage is aborted and the Rx handler starts processing of the - /// following message. was unable to write a message to the message RAM. In this case - /// message storage is aborted. - /// In both cases the FIFO put index is not updated. The partly stored message is overwritten - /// when the next message is stored to this location. - /// The flag is also set when the Tx Handler was not able to read a message from the Message - /// RAM in time. In this case message transmission is aborted. In case of a Tx Handler access - /// failure the FDCAN is switched into Restricted operation Mode (see Restricted operation - /// mode). - MsgRamAccessFailure = 1 << 14, - /// Timeout Occurred - TimeoutOccurred = 1 << 15, - /// Overflow of CAN error logging counter occurred - ErrLogOverflow = 1 << 16, - /// Errr Passive - ErrPassive = 1 << 17, - /// Warning Status - WarningStatus = 1 << 18, - /// Bus_Off status - BusOff = 1 << 19, - /// Watchdog interrupt - WatchdogInt = 1 << 20, - /// Protocol error in arbitration phase (nominal bit time is used) - ProtErrArbritation = 1 << 21, - /// Protocol error in data phase (data bit time is used) - ProtErrData = 1 << 22, - /// Access to reserved address - ReservedAccess = 1 << 23, -} - -bitflags::bitflags! { - /// A set of FdCAN interrupts. - #[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] - pub struct Interrupts: u32 { - /// Rx FIFO 0 has a new message - const RX_FIFO_0_NEW_MESSAGE = 1 << 0; - /// Rx FIFO 0 is full - const RX_FIFO_0_FULL = 1 << 1; - /// Rx FIFO 0 has lost a message - const RX_FIFO_0_MSG_LOST = 1 << 2; - /// Rx FIFO 1 has a new message - const RX_FIFO_1_NEW_MESSAGE = 1 << 3; - /// Rx FIFO 1 is full - const RX_FIFO_1_FULL = 1 << 4; - /// Rx FIFO 1 has lost a message - const RX_FIFO_1_MSG_LOST = 1 << 5; - /// A High Priority Message has been flagged by a filter - const RX_HIGH_PRIO_MSG = 1<<6; - /// Transmit has been completed - const TX_COMPLETE = 1<<7; - /// Tx message has been cancelled - const TX_CANCEL = 1<<8; - /// Tx Fifo is empty - const TX_EMPTY = 1<<9; - /// An new Event has been received in the Tx Event Fifo - const TX_EVENT_NEW = 1<<10; - /// The TxEvent Fifo is full - const TX_EVENT_FULL = 1<<11; - /// An Tx Event has been lost - const TX_EVENT_LOST = 1<<12; - /// Timestamp wrap around has occurred - const TS_WRAP_AROUND = 1<<13; - /// Message RAM access failure - /// - /// The flag is set when the Rx handler: - /// has not completed acceptance filtering or storage of an accepted message until the - /// arbitration field of the following message has been received. In this case acceptance - /// filtering or message storage is aborted and the Rx handler starts processing of the - /// following message. was unable to write a message to the message RAM. In this case - /// message storage is aborted. - /// In both cases the FIFO put index is not updated. The partly stored message is overwritten - /// when the next message is stored to this location. - /// The flag is also set when the Tx Handler was not able to read a message from the Message - /// RAM in time. In this case message transmission is aborted. In case of a Tx Handler access - /// failure the FDCAN is switched into Restricted operation Mode (see Restricted operation - /// mode). - const MSG_RAM_ACCESS_FAILURE = 1<<14; - /// Timeout Occurred - const TIMEOUT_OCCURRED = 1<<15; - /// Overflow of CAN error logging counter occurred - const ERR_LOG_OVERFLOW = 1<<16; - /// Err Passive - const ERR_PASSIVE = 1<<17; - /// Warning Status - const WARNING_STATUS = 1<<18; - /// Bus_Off status - const BUS_OFF = 1<<19; - /// Watchdog interrupt - const WATCHDOG_INT = 1<<20; - /// Protocol error in arbitration phase (nominal bit time is used) - const PROT_ERR_ARBRITATION = 1<<21; - /// Protocol error in data phase (data bit time is used) - const PROT_ERR_DATA = 1<<22; - /// Access to reserved address - const RESERVED_ACCESS = 1<<23; - } -} - -impl Interrupts { - /// No Interrupt masks selected - pub fn none() -> Self { - Self::from_bits_truncate(0) - } -} - -impl From for Interrupts { - #[inline] - fn from(i: Interrupt) -> Self { - Self::from_bits_truncate(i as u32) - } -} - -/// Adds an interrupt to the interrupt set. -impl ops::BitOrAssign for Interrupts { - #[inline] - fn bitor_assign(&mut self, rhs: Interrupt) { - *self |= Self::from(rhs); - } -} - -/// There are two interrupt lines for the FdCan -/// The events linked to these can be configured -/// see `[config::FdCanConfig]` -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum InterruptLine { - /// Interrupt Line 0 - _0 = 0, - /// Interrupt Line 1 - _1 = 1, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn interrupt_flags() { - assert_eq!( - Interrupts::from(Interrupt::TxComplete), - Interrupts::TX_COMPLETE - ); - assert_eq!(Interrupts::from(Interrupt::TxEmpty), Interrupts::TX_EMPTY); - - let mut ints = Interrupts::RX_FIFO_0_FULL; - ints |= Interrupt::RxFifo1Full; - assert_eq!( - ints, - Interrupts::RX_FIFO_0_FULL | Interrupts::RX_FIFO_1_FULL - ); - } -} diff --git a/src/fdcan/message_ram/txbuffer_element.rs b/src/fdcan/message_ram/txbuffer_element.rs deleted file mode 100644 index 7afc74e2..00000000 --- a/src/fdcan/message_ram/txbuffer_element.rs +++ /dev/null @@ -1,407 +0,0 @@ -use super::common::{BRS_R, DLC_R, ESI_R, FDF_R, ID_R, RTR_R, XTD_R}; -use super::enums::{ - BitRateSwitching, DataLength, ErrorStateIndicator, Event, EventControl, FrameFormat, IdType, - RemoteTransmissionRequest, -}; -use super::generic; - -#[doc = "Reader of register TxBufferElement"] -pub(crate) type R = generic::R; -#[doc = "Writer for register TxBufferElement"] -pub(crate) type W = generic::W; -impl generic::ResetValue for super::TxBufferElementHeader { - type Type = super::TxBufferElementHeaderType; - - #[allow(dead_code)] - #[inline(always)] - fn reset_value() -> Self::Type { - [0; 2] - } -} - -#[doc = "Write proxy for field `ESI`"] -pub(crate) struct ESI_W<'a> { - w: &'a mut W, -} -impl<'a> ESI_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_error_indicator(self, esi: ErrorStateIndicator) -> &'a mut W { - self.bit(esi as u8 != 0) - } - - #[doc = r"Sets the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits[0] = (self.w.bits[0] & !(0x01 << 31)) | (((value as u32) & 0x01) << 31); - self.w - } -} - -#[doc = "Write proxy for field `XTD`"] -pub(crate) struct XTD_W<'a> { - w: &'a mut W, -} -impl<'a> XTD_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_id_type(self, idt: IdType) -> &'a mut W { - self.bit(idt as u8 != 0) - } - - #[doc = r"Sets the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits[0] = (self.w.bits[0] & !(0x01 << 30)) | (((value as u32) & 0x01) << 30); - self.w - } -} - -#[doc = "Write proxy for field `RTR`"] -pub(crate) struct RTR_W<'a> { - w: &'a mut W, -} -impl<'a> RTR_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_rtr(self, rtr: RemoteTransmissionRequest) -> &'a mut W { - self.bit(rtr as u8 != 0) - } - - #[doc = r"Sets the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits[0] = (self.w.bits[0] & !(0x01 << 29)) | (((value as u32) & 0x01) << 29); - self.w - } -} - -#[doc = "Write proxy for field `ID`"] -pub(crate) struct ID_W<'a> { - w: &'a mut W, -} -impl<'a> ID_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - #[allow(dead_code)] - pub unsafe fn bits(self, value: u32) -> &'a mut W { - self.w.bits[0] = (self.w.bits[0] & !(0x1FFFFFFF)) | ((value as u32) & 0x1FFFFFFF); - self.w - } -} - -#[doc = "Write proxy for field `DLC`"] -pub(crate) struct DLC_W<'a> { - w: &'a mut W, -} -impl<'a> DLC_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - #[allow(dead_code)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits[1] = (self.w.bits[1] & !(0x0F << 16)) | (((value as u32) & 0x0F) << 16); - self.w - } -} - -#[doc = "Write proxy for field `BRS`"] -pub(crate) struct BRS_W<'a> { - w: &'a mut W, -} -impl<'a> BRS_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_brs(self, brs: BitRateSwitching) -> &'a mut W { - self.bit(brs as u8 != 0) - } - - #[doc = r"Sets the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits[1] = (self.w.bits[1] & !(0x01 << 20)) | (((value as u32) & 0x01) << 20); - self.w - } -} - -#[doc = "Write proxy for field `FDF`"] -pub(crate) struct FDF_W<'a> { - w: &'a mut W, -} -impl<'a> FDF_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_format(self, fdf: FrameFormat) -> &'a mut W { - self.bit(fdf as u8 != 0) - } - - #[doc = r"Sets the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits[1] = (self.w.bits[1] & !(0x01 << 21)) | (((value as u32) & 0x01) << 21); - self.w - } -} - -#[doc = "Reader of field `EFC`"] -pub(crate) type EFC_R = generic::R; -impl EFC_R { - pub fn to_event_control(&self) -> EventControl { - match self.bit() { - false => EventControl::DoNotStore, - true => EventControl::Store, - } - } -} -#[doc = "Write proxy for field `EFC`"] -pub(crate) struct EFC_W<'a> { - w: &'a mut W, -} -impl<'a> EFC_W<'a> { - #[doc = r"Writes `variant` to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_event_control(self, efc: EventControl) -> &'a mut W { - self.bit(match efc { - EventControl::DoNotStore => false, - EventControl::Store => true, - }) - } - - #[doc = r"Sets the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn set_bit(self) -> &'a mut W { - self.bit(true) - } - #[doc = r"Clears the field bit"] - #[inline(always)] - #[allow(dead_code)] - pub fn clear_bit(self) -> &'a mut W { - self.bit(false) - } - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - #[allow(dead_code)] - pub fn bit(self, value: bool) -> &'a mut W { - self.w.bits[1] = (self.w.bits[1] & !(0x01 << 23)) | (((value as u32) & 0x01) << 23); - self.w - } -} - -struct Marker(u8); -impl From for Marker { - fn from(e: Event) -> Marker { - match e { - Event::NoEvent => Marker(0), - Event::Event(mm) => Marker(mm), - } - } -} - -#[doc = "Reader of field `MM`"] -pub(crate) type MM_R = generic::R; -#[doc = "Write proxy for field `MM`"] -pub(crate) struct MM_W<'a> { - w: &'a mut W, -} -impl<'a> MM_W<'a> { - #[doc = r"Writes raw bits to the field"] - #[inline(always)] - pub unsafe fn bits(self, value: u8) -> &'a mut W { - self.w.bits[1] = (self.w.bits[1] & !(0x7F << 24)) | (((value as u32) & 0x7F) << 24); - self.w - } - - fn set_message_marker(self, mm: Marker) -> &'a mut W { - unsafe { self.bits(mm.0) } - } -} - -impl R { - #[doc = "Byte 0 - Bits 0:28 - ID"] - #[inline(always)] - pub fn id(&self) -> ID_R { - ID_R::new(((self.bits[0]) & 0x1FFFFFFF) as u32) - } - #[doc = "Byte 0 - Bit 29 - RTR"] - #[inline(always)] - pub fn rtr(&self) -> RTR_R { - RTR_R::new(((self.bits[0] >> 29) & 0x01) != 0) - } - #[doc = "Byte 0 - Bit 30 - XTD"] - #[inline(always)] - pub fn xtd(&self) -> XTD_R { - XTD_R::new(((self.bits[0] >> 30) & 0x01) != 0) - } - #[doc = "Byte 0 - Bit 30 - ESI"] - #[inline(always)] - pub fn esi(&self) -> ESI_R { - ESI_R::new(((self.bits[0] >> 31) & 0x01) != 0) - } - #[doc = "Byte 1 - Bits 16:19 - DLC"] - #[inline(always)] - pub fn dlc(&self) -> DLC_R { - DLC_R::new(((self.bits[1] >> 16) & 0x0F) as u8) - } - #[doc = "Byte 1 - Bits 20 - BRS"] - #[inline(always)] - pub fn brs(&self) -> BRS_R { - BRS_R::new(((self.bits[1] >> 20) & 0x01) != 0) - } - #[doc = "Byte 1 - Bits 20 - FDF"] - #[inline(always)] - pub fn fdf(&self) -> FDF_R { - FDF_R::new(((self.bits[1] >> 21) & 0x01) != 0) - } - #[doc = "Byte 1 - Bits 23 - EFC"] - #[inline(always)] - pub fn efc(&self) -> EFC_R { - EFC_R::new(((self.bits[1] >> 23) & 0x01) != 0) - } - #[doc = "Byte 1 - Bits 24:31 - MM"] - #[inline(always)] - pub fn mm(&self) -> MM_R { - MM_R::new(((self.bits[1] >> 24) & 0xFF) as u8) - } - pub fn to_data_length(&self) -> DataLength { - let dlc = self.dlc().bits(); - let ff = self.fdf().frame_format(); - DataLength::new(dlc, ff) - } - pub fn to_event(&self) -> Event { - let mm = self.mm().bits(); - let efc = self.efc().to_event_control(); - match efc { - EventControl::DoNotStore => Event::NoEvent, - EventControl::Store => Event::Event(mm), - } - } -} -impl W { - #[doc = "Byte 0 - Bits 0:28 - ID"] - #[inline(always)] - pub fn id(&mut self) -> ID_W { - ID_W { w: self } - } - #[doc = "Byte 0 - Bit 29 - RTR"] - #[inline(always)] - pub fn rtr(&mut self) -> RTR_W { - RTR_W { w: self } - } - #[doc = "Byte 0 - Bit 30 - XTD"] - #[inline(always)] - pub fn xtd(&mut self) -> XTD_W { - XTD_W { w: self } - } - #[doc = "Byte 0 - Bit 31 - ESI"] - #[inline(always)] - pub fn esi(&mut self) -> ESI_W { - ESI_W { w: self } - } - #[doc = "Byte 1 - Bit 16:19 - DLC"] - #[inline(always)] - pub fn dlc(&mut self) -> DLC_W { - DLC_W { w: self } - } - #[doc = "Byte 1 - Bit 20 - BRS"] - #[inline(always)] - pub fn brs(&mut self) -> BRS_W { - BRS_W { w: self } - } - #[doc = "Byte 1 - Bit 21 - FDF"] - #[inline(always)] - pub fn fdf(&mut self) -> FDF_W { - FDF_W { w: self } - } - #[doc = "Byte 1 - Bit 23 - EFC"] - #[inline(always)] - pub fn efc(&mut self) -> EFC_W { - EFC_W { w: self } - } - #[doc = "Byte 1 - Bit 24:31 - MM"] - #[inline(always)] - pub fn mm(&mut self) -> MM_W { - MM_W { w: self } - } - #[doc = "Convenience function for setting the data length and frame format"] - #[inline(always)] - pub fn set_len(&mut self, dl: impl Into) -> &mut Self { - let dl: DataLength = dl.into(); - self.fdf().set_format(dl.into()); - unsafe { self.dlc().bits(dl.dlc()) } - } - pub fn set_event(&mut self, event: Event) -> &mut Self { - self.mm().set_message_marker(event.into()); - self.efc().set_event_control(event.into()) - } -} From 6c83185d957d90e00b42504b2bc33e0dabefcd71 Mon Sep 17 00:00:00 2001 From: AdinAck Date: Wed, 8 Jan 2025 10:50:22 -0800 Subject: [PATCH 3/3] defmt format for rcc clocks (#163) --- Cargo.toml | 4 ++-- src/rcc/mod.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b78d4e2b..eb55bbfa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ paste = "1.0" bitflags = "1.2" vcell = "0.1" static_assertions = "1.1" -fugit = "0.3.5" +fugit = "0.3.7" stm32-usbd = { version = "0.7.0", optional = true } fixed = { version = "1.28.0", optional = true } @@ -93,7 +93,7 @@ stm32g4a1 = ["stm32g4/stm32g4a1"] log-itm = ["cortex-m-log/itm"] log-rtt = [] log-semihost = ["cortex-m-log/semihosting"] -defmt-logging = ["defmt"] +defmt = ["dep:defmt", "fugit/defmt"] cordic = ["dep:fixed"] [profile.dev] diff --git a/src/rcc/mod.rs b/src/rcc/mod.rs index 80447e7e..368130b1 100644 --- a/src/rcc/mod.rs +++ b/src/rcc/mod.rs @@ -16,6 +16,7 @@ pub const HSI_FREQ: u32 = 16_000_000; /// Clock frequencies #[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Clocks { /// System frequency pub sys_clk: Hertz, @@ -37,6 +38,7 @@ pub struct Clocks { /// PLL Clock frequencies #[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PLLClocks { /// R frequency pub r: Option,