From 30606f9782247b7f0e485b39042100ec3286aaa2 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 27 Feb 2024 14:59:02 +0000 Subject: [PATCH 1/5] stm32: can: fd: allow TX buffers in FIFO mode --- embassy-stm32/src/can/fd/config.rs | 21 +++++++++++++++++++++ embassy-stm32/src/can/fd/peripheral.rs | 6 ++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index f2401d92f..e959913e4 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -287,6 +287,24 @@ impl Default for GlobalFilter { } } +/// TX buffer operation mode +#[derive(Clone, Copy, Debug)] +pub enum TxBufferMode { + /// TX FIFO operation + Fifo, + /// TX queue operation + Queue, +} + +impl From for crate::pac::can::vals::Tfqm { + fn from(value: TxBufferMode) -> Self { + match value { + TxBufferMode::Queue => Self::QUEUE, + TxBufferMode::Fifo => Self::FIFO, + } + } +} + /// FdCan Config Struct #[derive(Clone, Copy, Debug)] pub struct FdCanConfig { @@ -327,6 +345,8 @@ pub struct FdCanConfig { pub timestamp_source: TimestampSource, /// Configures the Global Filter pub global_filter: GlobalFilter, + /// TX buffer mode (FIFO or queue) + pub tx_buffer_mode: TxBufferMode, } impl FdCanConfig { @@ -433,6 +453,7 @@ impl Default for FdCanConfig { clock_divider: ClockDivider::_1, timestamp_source: TimestampSource::None, global_filter: GlobalFilter::default(), + tx_buffer_mode: TxBufferMode::Queue, } } } diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index e87a3c213..0ebbdb3b7 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -302,10 +302,8 @@ impl Registers { // Framework specific settings are set here - // set TxBuffer to Queue Mode - self.regs - .txbc() - .write(|w| w.set_tfqm(crate::pac::can::vals::Tfqm::QUEUE)); + // set TxBuffer Mode + self.regs.txbc().write(|w| w.set_tfqm(_config.tx_buffer_mode.into())); // set standard filters list size to 28 // set extended filters list size to 8 From befbb2845aebde5aa879bbe6dd0bdb08c277e492 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Wed, 28 Feb 2024 10:10:15 +0000 Subject: [PATCH 2/5] stm32: can: fd: write: if in TX FIFO mode & bufs full, then abort --- embassy-stm32/src/can/fd/config.rs | 11 ++++++++++- embassy-stm32/src/can/fd/peripheral.rs | 21 ++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index e959913e4..338e4979d 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -288,7 +288,7 @@ impl Default for GlobalFilter { } /// TX buffer operation mode -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum TxBufferMode { /// TX FIFO operation Fifo, @@ -305,6 +305,15 @@ impl From for crate::pac::can::vals::Tfqm { } } +impl From for TxBufferMode { + fn from(value: crate::pac::can::vals::Tfqm) -> Self { + match value { + crate::pac::can::vals::Tfqm::QUEUE => Self::Queue, + crate::pac::can::vals::Tfqm::FIFO => Self::Fifo, + } + } +} + /// FdCan Config Struct #[derive(Clone, Copy, Debug)] pub struct FdCanConfig { diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 0ebbdb3b7..2a183d2e8 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -114,6 +114,12 @@ impl Registers { self.regs.txfqs().read().tfqf() } + /// Returns the current TX buffer operation mode (queue or FIFO) + #[inline] + pub fn tx_queue_mode(&self) -> TxBufferMode { + self.regs.txbc().read().tfqm().into() + } + #[inline] pub fn has_pending_frame(&self, idx: usize) -> bool { self.regs.txbrp().read().trp(idx) @@ -197,13 +203,14 @@ impl Registers { } pub fn write(&self, frame: &F) -> nb::Result, Infallible> { - let queue_is_full = self.tx_queue_is_full(); - - let id = frame.header().id(); - - // If the queue is full, - // Discard the first slot with a lower priority message - let (idx, pending_frame) = if queue_is_full { + let (idx, pending_frame) = if self.tx_queue_is_full() { + if self.tx_queue_mode() == TxBufferMode::Fifo { + // Does not make sense to cancel a pending frame when using FIFO + return Err(nb::Error::WouldBlock); + } + // If the queue is full, + // Discard the first slot with a lower priority message + let id = frame.header().id(); if self.is_available(0, id) { (0, self.abort_pending_mailbox_generic(0)) } else if self.is_available(1, id) { From 9e403fa89aae1d13948fcc15d1cc1f3c709dca88 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Wed, 28 Feb 2024 10:12:22 +0000 Subject: [PATCH 3/5] stm32: can: fd: rename abort_pending_mailbox, rm pub qualifier --- embassy-stm32/src/can/fd/peripheral.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 2a183d2e8..3a95b2659 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -170,7 +170,7 @@ impl Registers { } #[inline] - pub fn abort_pending_mailbox_generic(&self, bufidx: usize) -> Option { + fn abort_pending_mailbox(&self, bufidx: usize) -> Option { if self.abort(bufidx) { let mailbox = self.tx_buffer_element(bufidx); @@ -212,11 +212,11 @@ impl Registers { // Discard the first slot with a lower priority message let id = frame.header().id(); if self.is_available(0, id) { - (0, self.abort_pending_mailbox_generic(0)) + (0, self.abort_pending_mailbox(0)) } else if self.is_available(1, id) { - (1, self.abort_pending_mailbox_generic(1)) + (1, self.abort_pending_mailbox(1)) } else if self.is_available(2, id) { - (2, self.abort_pending_mailbox_generic(2)) + (2, self.abort_pending_mailbox(2)) } else { // For now we bail when there is no lower priority slot available // Can this lead to priority inversion? From bf06d10534fcf6e6f2fd34c1517500a59ed4b626 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 2 Mar 2024 09:45:30 +1000 Subject: [PATCH 4/5] Delay setting TX buffer mode until user had a chance to configure it. --- embassy-stm32/src/can/fd/config.rs | 4 ++-- embassy-stm32/src/can/fd/peripheral.rs | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index 338e4979d..adaffe9cc 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -290,9 +290,9 @@ impl Default for GlobalFilter { /// TX buffer operation mode #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum TxBufferMode { - /// TX FIFO operation + /// TX FIFO operation - In this mode CAN frames are trasmitted strictly in write order. Fifo, - /// TX queue operation + /// TX queue operation - In this mode CAN frames are transmitted according to CAN priority. Queue, } diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 3a95b2659..f0aab132b 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -307,11 +307,6 @@ impl Registers { "Error reading endianness test value from FDCAN core" ); - // Framework specific settings are set here - - // set TxBuffer Mode - self.regs.txbc().write(|w| w.set_tfqm(_config.tx_buffer_mode.into())); - // 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 @@ -357,6 +352,7 @@ impl Registers { /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] #[inline] pub fn apply_config(&mut self, config: FdCanConfig) { + self.set_tx_buffer_mode(config.tx_buffer_mode); self.set_data_bit_timing(config.dbtr); self.set_nominal_bit_timing(config.nbtr); self.set_automatic_retransmit(config.automatic_retransmit); @@ -504,6 +500,12 @@ impl Registers { self.regs.cccr().modify(|w| w.set_efbi(enabled)); } + /// Configures TX Buffer Mode + #[inline] + pub fn set_tx_buffer_mode(&mut self, tbm: TxBufferMode) { + self.regs.txbc().write(|w| w.set_tfqm(tbm.into())); + } + /// Configures frame transmission mode. See /// [`FdCanConfig::set_frame_transmit`] #[inline] From b693ab9b34fad5844401bc80b9968940e750680e Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 2 Mar 2024 12:57:03 +1000 Subject: [PATCH 5/5] Restore init order to restore H7. Previous commit broke H7 support in HIL farm. Restore previous order by moving a bunch of config from new and into_config_mode to apply_config. This is a cleanup that I had considered to move more register access into peripheral.rs. --- embassy-stm32/src/can/fd/peripheral.rs | 133 +++++++++++++++++++++---- embassy-stm32/src/can/fdcan.rs | 92 +---------------- 2 files changed, 113 insertions(+), 112 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index f0aab132b..8ec09ac12 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -22,6 +22,7 @@ enum LoopbackMode { pub struct Registers { pub regs: &'static crate::pac::can::Fdcan, pub msgram: &'static crate::pac::fdcanram::Fdcanram, + pub msg_ram_offset: usize, } impl Registers { @@ -294,7 +295,6 @@ impl Registers { pub fn into_config_mode(mut self, _config: FdCanConfig) { self.set_power_down_mode(false); self.enter_init_mode(); - self.reset_msg_ram(); // check the FDCAN core matches our expections @@ -307,27 +307,6 @@ impl Registers { "Error reading endianness test value from FDCAN core" ); - // 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. - #[cfg(not(stm32h7))] - { - self.regs.rxgfc().modify(|w| { - w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX); - w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX); - }); - } - #[cfg(stm32h7)] - { - self.regs - .sidfc() - .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX)); - self.regs - .xidfc() - .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX)); - } - /* for fid in 0..crate::can::message_ram::STANDARD_FILTER_MAX { self.set_standard_filter((fid as u8).into(), StandardFilter::disable()); @@ -353,6 +332,51 @@ impl Registers { #[inline] pub fn apply_config(&mut self, config: FdCanConfig) { self.set_tx_buffer_mode(config.tx_buffer_mode); + + // 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. + #[cfg(not(stm32h7))] + { + self.regs.rxgfc().modify(|w| { + w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX); + w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX); + }); + } + #[cfg(stm32h7)] + { + self.regs + .sidfc() + .modify(|w| w.set_lss(crate::can::fd::message_ram::STANDARD_FILTER_MAX)); + self.regs + .xidfc() + .modify(|w| w.set_lse(crate::can::fd::message_ram::EXTENDED_FILTER_MAX)); + } + + self.configure_msg_ram(); + + // Enable timestamping + #[cfg(not(stm32h7))] + self.regs + .tscc() + .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); + #[cfg(stm32h7)] + self.regs.tscc().write(|w| w.set_tss(0x01)); + + // this isn't really documented in the reference manual + // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire + self.regs.txbtie().write(|w| w.0 = 0xffff_ffff); + self.regs.ie().modify(|w| { + w.set_rfne(0, true); // Rx Fifo 0 New Msg + w.set_rfne(1, true); // Rx Fifo 1 New Msg + w.set_tce(true); // Tx Complete + }); + self.regs.ile().modify(|w| { + w.set_eint0(true); // Interrupt Line 0 + w.set_eint1(true); // Interrupt Line 1 + }); + self.set_data_bit_timing(config.dbtr); self.set_nominal_bit_timing(config.nbtr); self.set_automatic_retransmit(config.automatic_retransmit); @@ -600,6 +624,71 @@ impl Registers { w.set_rrfe(filter.reject_remote_extended_frames); }); } + + #[cfg(not(stm32h7))] + fn configure_msg_ram(&mut self) {} + + #[cfg(stm32h7)] + fn configure_msg_ram(&mut self) { + let r = self.regs; + + use crate::can::fd::message_ram::*; + //use fdcan::message_ram::*; + let mut offset_words = self.msg_ram_offset as u16; + + // 11-bit filter + r.sidfc().modify(|w| w.set_flssa(offset_words)); + offset_words += STANDARD_FILTER_MAX as u16; + + // 29-bit filter + r.xidfc().modify(|w| w.set_flesa(offset_words)); + offset_words += 2 * EXTENDED_FILTER_MAX as u16; + + // Rx FIFO 0 and 1 + for i in 0..=1 { + r.rxfc(i).modify(|w| { + w.set_fsa(offset_words); + w.set_fs(RX_FIFO_MAX); + w.set_fwm(RX_FIFO_MAX); + }); + offset_words += 18 * RX_FIFO_MAX as u16; + } + + // Rx buffer - see below + // Tx event FIFO + r.txefc().modify(|w| { + w.set_efsa(offset_words); + w.set_efs(TX_EVENT_MAX); + w.set_efwm(TX_EVENT_MAX); + }); + offset_words += 2 * TX_EVENT_MAX as u16; + + // Tx buffers + r.txbc().modify(|w| { + w.set_tbsa(offset_words); + w.set_tfqs(TX_FIFO_MAX); + }); + offset_words += 18 * TX_FIFO_MAX as u16; + + // Rx Buffer - not used + r.rxbc().modify(|w| { + w.set_rbsa(offset_words); + }); + + // TX event FIFO? + // Trigger memory? + + // Set the element sizes to 16 bytes + r.rxesc().modify(|w| { + w.set_rbds(0b111); + for i in 0..=1 { + w.set_fds(i, 0b111); + } + }); + r.txesc().modify(|w| { + w.set_tbds(0b111); + }) + } } fn make_id(id: u32, extended: bool) -> embedded_can::Id { diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 77db774fc..20d00ccb5 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -184,43 +184,20 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { T::enable_and_reset(); let mut config = crate::can::fd::config::FdCanConfig::default(); + config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); T::registers().into_config_mode(config); rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - T::configure_msg_ram(); unsafe { - // Enable timestamping - #[cfg(not(stm32h7))] - T::regs() - .tscc() - .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT)); - #[cfg(stm32h7)] - T::regs().tscc().write(|w| w.set_tss(0x01)); - config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); - T::IT0Interrupt::unpend(); // Not unsafe T::IT0Interrupt::enable(); T::IT1Interrupt::unpend(); // Not unsafe T::IT1Interrupt::enable(); - - // this isn't really documented in the reference manual - // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire - T::regs().txbtie().write(|w| w.0 = 0xffff_ffff); } - T::regs().ie().modify(|w| { - w.set_rfne(0, true); // Rx Fifo 0 New Msg - w.set_rfne(1, true); // Rx Fifo 1 New Msg - w.set_tce(true); // Tx Complete - }); - T::regs().ile().modify(|w| { - w.set_eint0(true); // Interrupt Line 0 - w.set_eint1(true); // Interrupt Line 1 - }); - Self { config, instance: FdcanInstance(peri), @@ -869,71 +846,6 @@ pub(crate) mod sealed { fn state() -> &'static State; unsafe fn mut_state() -> &'static mut State; fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; - - #[cfg(not(stm32h7))] - fn configure_msg_ram() {} - - #[cfg(stm32h7)] - fn configure_msg_ram() { - let r = Self::regs(); - - use crate::can::fd::message_ram::*; - //use fdcan::message_ram::*; - let mut offset_words = Self::MSG_RAM_OFFSET as u16; - - // 11-bit filter - r.sidfc().modify(|w| w.set_flssa(offset_words)); - offset_words += STANDARD_FILTER_MAX as u16; - - // 29-bit filter - r.xidfc().modify(|w| w.set_flesa(offset_words)); - offset_words += 2 * EXTENDED_FILTER_MAX as u16; - - // Rx FIFO 0 and 1 - for i in 0..=1 { - r.rxfc(i).modify(|w| { - w.set_fsa(offset_words); - w.set_fs(RX_FIFO_MAX); - w.set_fwm(RX_FIFO_MAX); - }); - offset_words += 18 * RX_FIFO_MAX as u16; - } - - // Rx buffer - see below - // Tx event FIFO - r.txefc().modify(|w| { - w.set_efsa(offset_words); - w.set_efs(TX_EVENT_MAX); - w.set_efwm(TX_EVENT_MAX); - }); - offset_words += 2 * TX_EVENT_MAX as u16; - - // Tx buffers - r.txbc().modify(|w| { - w.set_tbsa(offset_words); - w.set_tfqs(TX_FIFO_MAX); - }); - offset_words += 18 * TX_FIFO_MAX as u16; - - // Rx Buffer - not used - r.rxbc().modify(|w| { - w.set_rbsa(offset_words); - }); - - // TX event FIFO? - // Trigger memory? - - // Set the element sizes to 16 bytes - r.rxesc().modify(|w| { - w.set_rbds(0b111); - for i in 0..=1 { - w.set_fds(i, 0b111); - } - }); - r.txesc().modify(|w| { - w.set_tbds(0b111); - }) - } } } @@ -957,7 +869,7 @@ macro_rules! impl_fdcan { &crate::pac::$inst } fn registers() -> Registers { - Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst} + Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} } fn ram() -> &'static crate::pac::fdcanram::Fdcanram { &crate::pac::$msg_ram_inst