From 7f55a28a50bf5ac8acbeac4e47ad4e2fc73895f4 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Thu, 18 Apr 2024 09:59:39 +0100 Subject: [PATCH 1/7] stm32: can: fd: Properties for common runtime get/set operations --- embassy-stm32/src/can/fdcan.rs | 132 ++++++++++++++++++++++++++------- 1 file changed, 105 insertions(+), 27 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 563f542d4..cec94e78a 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -146,6 +146,7 @@ pub struct CanConfigurator<'d, T: Instance> { config: crate::can::fd::config::FdCanConfig, /// Reference to internals. instance: FdcanInstance<'d, T>, + properties: Properties, } fn calc_ns_per_timer_tick(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { @@ -199,9 +200,20 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { Self { config, instance: FdcanInstance(peri), + properties: Properties::new(), } } + /// Get driver properties + pub fn properties(&self) -> &Properties { + &self.properties + } + + /// Get mutable driver properties + pub fn properties_mut(&mut self) -> &mut Properties { + &mut self.properties + } + /// Get configuration pub fn config(&self) -> crate::can::fd::config::FdCanConfig { return self.config; @@ -240,32 +252,6 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { self.config = self.config.set_data_bit_timing(nbtr); } - /// Set an Standard Address CAN filter into slot 'id' - #[inline] - pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) { - T::registers().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() { - T::registers().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) { - T::registers().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() { - T::registers().msg_ram_mut().filters.flesa[i].activate(*f); - } - } - /// Start in mode. pub fn start(self, mode: OperatingMode) -> Can<'d, T> { let ns_per_timer_tick = calc_ns_per_timer_tick::(self.config.frame_transmit); @@ -277,6 +263,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { config: self.config, instance: self.instance, _mode: mode, + properties: self.properties, }; ret } @@ -303,9 +290,20 @@ pub struct Can<'d, T: Instance> { /// Reference to internals. instance: FdcanInstance<'d, T>, _mode: OperatingMode, + properties: Properties, } impl<'d, T: Instance> Can<'d, T> { + /// Get properties + pub fn properties(&self) -> &Properties { + &self.properties + } + + /// Get mutable driver properties + pub fn properties_mut(&mut self) -> &mut Properties { + &mut self.properties + } + /// Flush one of the TX mailboxes. pub async fn flush(&self, idx: usize) { poll_fn(|cx| { @@ -351,7 +349,7 @@ impl<'d, T: Instance> Can<'d, T> { } /// Split instance into separate Tx(write) and Rx(read) portions - pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) { + pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>, Properties) { ( CanTx { config: self.config, @@ -363,6 +361,7 @@ impl<'d, T: Instance> Can<'d, T> { _instance2: T::regs(), _mode: self._mode, }, + self.properties, ) } @@ -373,6 +372,7 @@ impl<'d, T: Instance> Can<'d, T> { //_instance2: T::regs(), instance: tx._instance, _mode: rx._mode, + properties: Properties::new(), } } @@ -408,6 +408,7 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S _mode: OperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, + properties: Properties, } impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> @@ -426,10 +427,21 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> _mode, tx_buf, rx_buf, + properties: Properties::new(), } .setup() } + /// Get driver properties + pub fn properties(&self) -> &Properties { + &self.properties + } + + /// Get mutable driver properties + pub fn properties_mut(&mut self) -> &mut Properties { + &mut self.properties + } + fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { @@ -494,6 +506,7 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF _mode: OperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, + properties: Properties, } /// Sender that can be used for sending CAN frames. @@ -542,10 +555,21 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> _mode, tx_buf, rx_buf, + properties: Properties::new(), } .setup() } + /// Get driver properties + pub fn properties(&self) -> &Properties { + &self.properties + } + + /// Get mutable driver properties + pub fn properties_mut(&mut self) -> &mut Properties { + &mut self.properties + } + fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { @@ -804,6 +828,60 @@ impl TxMode { } } +/// Common driver properties, including filters and error counters +pub struct Properties { + instance: PhantomData, +} + +impl Properties { + fn new() -> Self { + Self { + instance: Default::default(), + } + } + + /// Set an Standard Address CAN filter into slot 'id' + #[inline] + pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) { + T::registers().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() { + T::registers().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) { + T::registers().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() { + T::registers().msg_ram_mut().filters.flesa[i].activate(*f); + } + } + + /// Get the CAN RX error counter + pub fn get_rx_error_count(&self) -> u8 { + T::registers().regs.ecr().read().rec() + } + + /// Get the CAN TX error counter + pub fn get_tx_error_count(&self) -> u8 { + T::registers().regs.ecr().read().tec() + } + + /// Get the current Bus-Off state + pub fn get_bus_off(&self) -> bool { + T::registers().regs.psr().read().bo() + } +} + struct State { pub rx_mode: RxMode, pub tx_mode: TxMode, From 263071d0169318ab24e0f6caac87a13d1c906769 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Fri, 19 Apr 2024 14:41:49 +0100 Subject: [PATCH 2/7] stm32: can: fd: Properties: rm &mut refs; make !Sync; rename getters --- embassy-stm32/src/can/fdcan.rs | 47 +++++++++++----------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index cec94e78a..0916f6ac6 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -209,11 +209,6 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { &self.properties } - /// Get mutable driver properties - pub fn properties_mut(&mut self) -> &mut Properties { - &mut self.properties - } - /// Get configuration pub fn config(&self) -> crate::can::fd::config::FdCanConfig { return self.config; @@ -299,11 +294,6 @@ impl<'d, T: Instance> Can<'d, T> { &self.properties } - /// Get mutable driver properties - pub fn properties_mut(&mut self) -> &mut Properties { - &mut self.properties - } - /// Flush one of the TX mailboxes. pub async fn flush(&self, idx: usize) { poll_fn(|cx| { @@ -437,11 +427,6 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> &self.properties } - /// Get mutable driver properties - pub fn properties_mut(&mut self) -> &mut Properties { - &mut self.properties - } - fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { @@ -565,11 +550,6 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> &self.properties } - /// Get mutable driver properties - pub fn properties_mut(&mut self) -> &mut Properties { - &mut self.properties - } - fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. critical_section::with(|_| unsafe { @@ -830,7 +810,8 @@ impl TxMode { /// Common driver properties, including filters and error counters pub struct Properties { - instance: PhantomData, + // phantom pointer to ensure !Sync + instance: PhantomData<*const T>, } impl Properties { @@ -840,44 +821,46 @@ impl Properties { } } - /// Set an Standard Address CAN filter into slot 'id' + /// Set a standard address CAN filter in the specified slot in FDCAN memory. #[inline] - pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) { + pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) { T::registers().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]) { + /// Set the full array of standard address CAN filters in FDCAN memory. + /// Overwrites all standard address filters in memory. + pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) { for (i, f) in filters.iter().enumerate() { T::registers().msg_ram_mut().filters.flssa[i].activate(*f); } } - /// Set an Extended Address CAN filter into slot 'id' + /// Set an extended address CAN filter in the specified slot in FDCAN memory. #[inline] - pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { + pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { T::registers().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]) { + /// Set the full array of extended address CAN filters in FDCAN memory. + /// Overwrites all extended address filters in memory. + pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) { for (i, f) in filters.iter().enumerate() { T::registers().msg_ram_mut().filters.flesa[i].activate(*f); } } /// Get the CAN RX error counter - pub fn get_rx_error_count(&self) -> u8 { + pub fn rx_error_count(&self) -> u8 { T::registers().regs.ecr().read().rec() } /// Get the CAN TX error counter - pub fn get_tx_error_count(&self) -> u8 { + pub fn tx_error_count(&self) -> u8 { T::registers().regs.ecr().read().tec() } /// Get the current Bus-Off state - pub fn get_bus_off(&self) -> bool { + pub fn bus_off(&self) -> bool { T::registers().regs.psr().read().bo() } } From 543c02e649ea8ec05597daca3816c05db2c6ab53 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Fri, 19 Apr 2024 15:09:01 +0100 Subject: [PATCH 3/7] stm32: can: fd: fix test build for all relevant chips --- tests/stm32/Cargo.toml | 2 +- tests/stm32/src/bin/fdcan.rs | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index e09083111..004846a9b 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -15,7 +15,7 @@ stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma" stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"] -stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash", "cordic"] +stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan", "hash", "cordic"] stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index 27bdd038a..b0c0cd82e 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -24,7 +24,19 @@ bind_interrupts!(struct Irqs1 { FDCAN1_IT1 => can::IT1InterruptHandler; }); -#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] +#[cfg(feature = "stm32h563zi")] +fn options() -> (Config, TestOptions) { + info!("H563 config"); + ( + config(), + TestOptions { + max_latency: Duration::from_micros(1200), + max_buffered: 3, + }, + ) +} + +#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))] fn options() -> (Config, TestOptions) { use embassy_stm32::rcc; info!("H75 config"); @@ -88,11 +100,11 @@ async fn main(_spawner: Spawner) { can.set_bitrate(250_000); can2.set_bitrate(250_000); - can.set_extended_filter( + can.properties().set_extended_filter( can::filter::ExtendedFilterSlot::_0, can::filter::ExtendedFilter::accept_all_into_fifo1(), ); - can2.set_extended_filter( + can2.properties().set_extended_filter( can::filter::ExtendedFilterSlot::_0, can::filter::ExtendedFilter::accept_all_into_fifo1(), ); @@ -106,8 +118,8 @@ async fn main(_spawner: Spawner) { info!("CAN Configured"); // Test again with a split - let (mut tx, mut rx) = can.split(); - let (mut tx2, mut rx2) = can2.split(); + let (mut tx, mut rx, _props) = can.split(); + let (mut tx2, mut rx2, _props) = can2.split(); run_split_can_tests(&mut tx, &mut rx, &options).await; run_split_can_tests(&mut tx2, &mut rx2, &options).await; From 846abfae2b8a24715542d57d4e6ea4386607d845 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Fri, 19 Apr 2024 15:20:04 +0100 Subject: [PATCH 4/7] examples: stm32: can: fix build --- examples/stm32g4/src/bin/can.rs | 4 ++-- examples/stm32h5/src/bin/can.rs | 2 +- examples/stm32h7/src/bin/can.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 2ed632a93..7836334af 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) { let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); - can.set_extended_filter( + can.properties().set_extended_filter( can::filter::ExtendedFilterSlot::_0, can::filter::ExtendedFilter::accept_all_into_fifo1(), ); @@ -128,7 +128,7 @@ async fn main(_spawner: Spawner) { } } i = 0; - let (mut tx, mut rx) = can.split(); + let (mut tx, mut rx, _props) = can.split(); // With split loop { let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index dd625c90a..dc77ec3bf 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) { } } - let (mut tx, mut rx) = can.split(); + let (mut tx, mut rx, _props) = can.split(); // With split loop { let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 22cb27481..a889d5860 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) { } } - let (mut tx, mut rx) = can.split(); + let (mut tx, mut rx, _props) = can.split(); // With split loop { let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); From 6ca7e0feab9eb16261adacc8c2327e4d018acb13 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 23 Apr 2024 12:33:20 +0100 Subject: [PATCH 5/7] stm32: can: fd: fix a couple doc comments --- embassy-stm32/src/can/fdcan.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 0916f6ac6..0df74a778 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -289,7 +289,7 @@ pub struct Can<'d, T: Instance> { } impl<'d, T: Instance> Can<'d, T> { - /// Get properties + /// Get driver properties pub fn properties(&self) -> &Properties { &self.properties } @@ -338,7 +338,7 @@ impl<'d, T: Instance> Can<'d, T> { T::state().rx_mode.read_fd::().await } - /// Split instance into separate Tx(write) and Rx(read) portions + /// Split instance into separate portions: Tx(write), Rx(read), common properties pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>, Properties) { ( CanTx { From 521c132e348054e6326e9c9387516b0e98743092 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 23 Apr 2024 12:33:27 +0100 Subject: [PATCH 6/7] stm32: can: fd: introduce BusErrorMode with docs and Properties getter --- embassy-stm32/src/can/enums.rs | 18 ++++++++++++++++++ embassy-stm32/src/can/fdcan.rs | 14 +++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 4d89c84d1..a5cca424d 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs @@ -29,6 +29,24 @@ pub enum BusError { BusWarning, } +/// Bus error modes. +/// +/// Contrary to the `BusError` enum which also includes last-seen acute protocol +/// errors, this enum includes only the mutually exclusive bus error modes. +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum BusErrorMode { + /// Error active mode (default). Controller will transmit an active error + /// frame upon protocol error. + ErrorActive, + /// Error passive mode. An error counter exceeded 127. Controller will + /// transmit a passive error frame upon protocol error. + ErrorPassive, + /// Bus off mode. The transmit error counter exceeded 255. Controller is not + /// participating in bus traffic. + BusOff, +} + /// Frame Create Errors #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 0df74a778..faf8a1176 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -859,9 +859,17 @@ impl Properties { T::registers().regs.ecr().read().tec() } - /// Get the current Bus-Off state - pub fn bus_off(&self) -> bool { - T::registers().regs.psr().read().bo() + /// Get the current bus error mode + pub fn bus_error_mode(&self) -> BusErrorMode { + // This read will clear LEC and DLEC. This is not ideal, but protocol + // error reporting in this driver should have a big ol' FIXME on it + // anyway! + let psr = T::regs().psr().read(); + match (psr.bo(), psr.ep()) { + (false, false) => BusErrorMode::ErrorActive, + (false, true) => BusErrorMode::ErrorPassive, + (true, _) => BusErrorMode::BusOff, + } } } From e15fd5895fc375c85880cf7fb846b2652df50c01 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Tue, 23 Apr 2024 12:46:42 +0100 Subject: [PATCH 7/7] stm32: can: fd: Properties: simplify reg accesses --- embassy-stm32/src/can/fdcan.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index faf8a1176..6144ba520 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -851,12 +851,12 @@ impl Properties { /// Get the CAN RX error counter pub fn rx_error_count(&self) -> u8 { - T::registers().regs.ecr().read().rec() + T::regs().ecr().read().rec() } /// Get the CAN TX error counter pub fn tx_error_count(&self) -> u8 { - T::registers().regs.ecr().read().tec() + T::regs().ecr().read().tec() } /// Get the current bus error mode