aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-04-23 13:46:09 +0000
committerGitHub <[email protected]>2024-04-23 13:46:09 +0000
commit1de44e7086e05b148dec5cbe38a3971c08dea742 (patch)
treea3a6e2cde912be3ed60bf5f947c0d80683b2ef68
parent511bee7230d319abfef02b1ac8bfb21e1d2e83d8 (diff)
parente15fd5895fc375c85880cf7fb846b2652df50c01 (diff)
Merge pull request #2840 from MaxiluxSystems/feature/fdcan-runtime-cfg
stm32: can: fd: Properties for common runtime get/set operations
-rw-r--r--embassy-stm32/src/can/enums.rs18
-rw-r--r--embassy-stm32/src/can/fdcan.rs125
-rw-r--r--examples/stm32g4/src/bin/can.rs4
-rw-r--r--examples/stm32h5/src/bin/can.rs2
-rw-r--r--examples/stm32h7/src/bin/can.rs2
-rw-r--r--tests/stm32/Cargo.toml2
-rw-r--r--tests/stm32/src/bin/fdcan.rs22
7 files changed, 137 insertions, 38 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 {
29 BusWarning, 29 BusWarning,
30} 30}
31 31
32/// Bus error modes.
33///
34/// Contrary to the `BusError` enum which also includes last-seen acute protocol
35/// errors, this enum includes only the mutually exclusive bus error modes.
36#[derive(Debug)]
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38pub enum BusErrorMode {
39 /// Error active mode (default). Controller will transmit an active error
40 /// frame upon protocol error.
41 ErrorActive,
42 /// Error passive mode. An error counter exceeded 127. Controller will
43 /// transmit a passive error frame upon protocol error.
44 ErrorPassive,
45 /// Bus off mode. The transmit error counter exceeded 255. Controller is not
46 /// participating in bus traffic.
47 BusOff,
48}
49
32/// Frame Create Errors 50/// Frame Create Errors
33#[derive(Debug)] 51#[derive(Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))] 52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 563f542d4..6144ba520 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> {
146 config: crate::can::fd::config::FdCanConfig, 146 config: crate::can::fd::config::FdCanConfig,
147 /// Reference to internals. 147 /// Reference to internals.
148 instance: FdcanInstance<'d, T>, 148 instance: FdcanInstance<'d, T>,
149 properties: Properties<T>,
149} 150}
150 151
151fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 { 152fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
@@ -199,9 +200,15 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
199 Self { 200 Self {
200 config, 201 config,
201 instance: FdcanInstance(peri), 202 instance: FdcanInstance(peri),
203 properties: Properties::new(),
202 } 204 }
203 } 205 }
204 206
207 /// Get driver properties
208 pub fn properties(&self) -> &Properties<T> {
209 &self.properties
210 }
211
205 /// Get configuration 212 /// Get configuration
206 pub fn config(&self) -> crate::can::fd::config::FdCanConfig { 213 pub fn config(&self) -> crate::can::fd::config::FdCanConfig {
207 return self.config; 214 return self.config;
@@ -240,32 +247,6 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
240 self.config = self.config.set_data_bit_timing(nbtr); 247 self.config = self.config.set_data_bit_timing(nbtr);
241 } 248 }
242 249
243 /// Set an Standard Address CAN filter into slot 'id'
244 #[inline]
245 pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) {
246 T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
247 }
248
249 /// Set an array of Standard Address CAN filters and overwrite the current set
250 pub fn set_standard_filters(&mut self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
251 for (i, f) in filters.iter().enumerate() {
252 T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
253 }
254 }
255
256 /// Set an Extended Address CAN filter into slot 'id'
257 #[inline]
258 pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
259 T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
260 }
261
262 /// Set an array of Extended Address CAN filters and overwrite the current set
263 pub fn set_extended_filters(&mut self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
264 for (i, f) in filters.iter().enumerate() {
265 T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
266 }
267 }
268
269 /// Start in mode. 250 /// Start in mode.
270 pub fn start(self, mode: OperatingMode) -> Can<'d, T> { 251 pub fn start(self, mode: OperatingMode) -> Can<'d, T> {
271 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); 252 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
@@ -277,6 +258,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
277 config: self.config, 258 config: self.config,
278 instance: self.instance, 259 instance: self.instance,
279 _mode: mode, 260 _mode: mode,
261 properties: self.properties,
280 }; 262 };
281 ret 263 ret
282 } 264 }
@@ -303,9 +285,15 @@ pub struct Can<'d, T: Instance> {
303 /// Reference to internals. 285 /// Reference to internals.
304 instance: FdcanInstance<'d, T>, 286 instance: FdcanInstance<'d, T>,
305 _mode: OperatingMode, 287 _mode: OperatingMode,
288 properties: Properties<T>,
306} 289}
307 290
308impl<'d, T: Instance> Can<'d, T> { 291impl<'d, T: Instance> Can<'d, T> {
292 /// Get driver properties
293 pub fn properties(&self) -> &Properties<T> {
294 &self.properties
295 }
296
309 /// Flush one of the TX mailboxes. 297 /// Flush one of the TX mailboxes.
310 pub async fn flush(&self, idx: usize) { 298 pub async fn flush(&self, idx: usize) {
311 poll_fn(|cx| { 299 poll_fn(|cx| {
@@ -350,8 +338,8 @@ impl<'d, T: Instance> Can<'d, T> {
350 T::state().rx_mode.read_fd::<T>().await 338 T::state().rx_mode.read_fd::<T>().await
351 } 339 }
352 340
353 /// Split instance into separate Tx(write) and Rx(read) portions 341 /// Split instance into separate portions: Tx(write), Rx(read), common properties
354 pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) { 342 pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>, Properties<T>) {
355 ( 343 (
356 CanTx { 344 CanTx {
357 config: self.config, 345 config: self.config,
@@ -363,6 +351,7 @@ impl<'d, T: Instance> Can<'d, T> {
363 _instance2: T::regs(), 351 _instance2: T::regs(),
364 _mode: self._mode, 352 _mode: self._mode,
365 }, 353 },
354 self.properties,
366 ) 355 )
367 } 356 }
368 357
@@ -373,6 +362,7 @@ impl<'d, T: Instance> Can<'d, T> {
373 //_instance2: T::regs(), 362 //_instance2: T::regs(),
374 instance: tx._instance, 363 instance: tx._instance,
375 _mode: rx._mode, 364 _mode: rx._mode,
365 properties: Properties::new(),
376 } 366 }
377 } 367 }
378 368
@@ -408,6 +398,7 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S
408 _mode: OperatingMode, 398 _mode: OperatingMode,
409 tx_buf: &'static TxBuf<TX_BUF_SIZE>, 399 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
410 rx_buf: &'static RxBuf<RX_BUF_SIZE>, 400 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
401 properties: Properties<T>,
411} 402}
412 403
413impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> 404impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
@@ -426,10 +417,16 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
426 _mode, 417 _mode,
427 tx_buf, 418 tx_buf,
428 rx_buf, 419 rx_buf,
420 properties: Properties::new(),
429 } 421 }
430 .setup() 422 .setup()
431 } 423 }
432 424
425 /// Get driver properties
426 pub fn properties(&self) -> &Properties<T> {
427 &self.properties
428 }
429
433 fn setup(self) -> Self { 430 fn setup(self) -> Self {
434 // We don't want interrupts being processed while we change modes. 431 // We don't want interrupts being processed while we change modes.
435 critical_section::with(|_| unsafe { 432 critical_section::with(|_| unsafe {
@@ -494,6 +491,7 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF
494 _mode: OperatingMode, 491 _mode: OperatingMode,
495 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, 492 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
496 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, 493 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
494 properties: Properties<T>,
497} 495}
498 496
499/// Sender that can be used for sending CAN frames. 497/// Sender that can be used for sending CAN frames.
@@ -542,10 +540,16 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
542 _mode, 540 _mode,
543 tx_buf, 541 tx_buf,
544 rx_buf, 542 rx_buf,
543 properties: Properties::new(),
545 } 544 }
546 .setup() 545 .setup()
547 } 546 }
548 547
548 /// Get driver properties
549 pub fn properties(&self) -> &Properties<T> {
550 &self.properties
551 }
552
549 fn setup(self) -> Self { 553 fn setup(self) -> Self {
550 // We don't want interrupts being processed while we change modes. 554 // We don't want interrupts being processed while we change modes.
551 critical_section::with(|_| unsafe { 555 critical_section::with(|_| unsafe {
@@ -804,6 +808,71 @@ impl TxMode {
804 } 808 }
805} 809}
806 810
811/// Common driver properties, including filters and error counters
812pub struct Properties<T> {
813 // phantom pointer to ensure !Sync
814 instance: PhantomData<*const T>,
815}
816
817impl<T: Instance> Properties<T> {
818 fn new() -> Self {
819 Self {
820 instance: Default::default(),
821 }
822 }
823
824 /// Set a standard address CAN filter in the specified slot in FDCAN memory.
825 #[inline]
826 pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) {
827 T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
828 }
829
830 /// Set the full array of standard address CAN filters in FDCAN memory.
831 /// Overwrites all standard address filters in memory.
832 pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
833 for (i, f) in filters.iter().enumerate() {
834 T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
835 }
836 }
837
838 /// Set an extended address CAN filter in the specified slot in FDCAN memory.
839 #[inline]
840 pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
841 T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
842 }
843
844 /// Set the full array of extended address CAN filters in FDCAN memory.
845 /// Overwrites all extended address filters in memory.
846 pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
847 for (i, f) in filters.iter().enumerate() {
848 T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
849 }
850 }
851
852 /// Get the CAN RX error counter
853 pub fn rx_error_count(&self) -> u8 {
854 T::regs().ecr().read().rec()
855 }
856
857 /// Get the CAN TX error counter
858 pub fn tx_error_count(&self) -> u8 {
859 T::regs().ecr().read().tec()
860 }
861
862 /// Get the current bus error mode
863 pub fn bus_error_mode(&self) -> BusErrorMode {
864 // This read will clear LEC and DLEC. This is not ideal, but protocol
865 // error reporting in this driver should have a big ol' FIXME on it
866 // anyway!
867 let psr = T::regs().psr().read();
868 match (psr.bo(), psr.ep()) {
869 (false, false) => BusErrorMode::ErrorActive,
870 (false, true) => BusErrorMode::ErrorPassive,
871 (true, _) => BusErrorMode::BusOff,
872 }
873 }
874}
875
807struct State { 876struct State {
808 pub rx_mode: RxMode, 877 pub rx_mode: RxMode,
809 pub tx_mode: TxMode, 878 pub tx_mode: TxMode,
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) {
38 38
39 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); 39 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
40 40
41 can.set_extended_filter( 41 can.properties().set_extended_filter(
42 can::filter::ExtendedFilterSlot::_0, 42 can::filter::ExtendedFilterSlot::_0,
43 can::filter::ExtendedFilter::accept_all_into_fifo1(), 43 can::filter::ExtendedFilter::accept_all_into_fifo1(),
44 ); 44 );
@@ -128,7 +128,7 @@ async fn main(_spawner: Spawner) {
128 } 128 }
129 } 129 }
130 i = 0; 130 i = 0;
131 let (mut tx, mut rx) = can.split(); 131 let (mut tx, mut rx, _props) = can.split();
132 // With split 132 // With split
133 loop { 133 loop {
134 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); 134 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) {
67 } 67 }
68 } 68 }
69 69
70 let (mut tx, mut rx) = can.split(); 70 let (mut tx, mut rx, _props) = can.split();
71 // With split 71 // With split
72 loop { 72 loop {
73 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); 73 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) {
67 } 67 }
68 } 68 }
69 69
70 let (mut tx, mut rx) = can.split(); 70 let (mut tx, mut rx, _props) = can.split();
71 // With split 71 // With split
72 loop { 72 loop {
73 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); 73 let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
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"
15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] 15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] 16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"]
17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"] 17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"]
18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash", "cordic"] 18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan", "hash", "cordic"]
19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] 19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] 20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] 21stm32h7a3zi = ["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 {
24 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; 24 FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
25}); 25});
26 26
27#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] 27#[cfg(feature = "stm32h563zi")]
28fn options() -> (Config, TestOptions) {
29 info!("H563 config");
30 (
31 config(),
32 TestOptions {
33 max_latency: Duration::from_micros(1200),
34 max_buffered: 3,
35 },
36 )
37}
38
39#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))]
28fn options() -> (Config, TestOptions) { 40fn options() -> (Config, TestOptions) {
29 use embassy_stm32::rcc; 41 use embassy_stm32::rcc;
30 info!("H75 config"); 42 info!("H75 config");
@@ -88,11 +100,11 @@ async fn main(_spawner: Spawner) {
88 can.set_bitrate(250_000); 100 can.set_bitrate(250_000);
89 can2.set_bitrate(250_000); 101 can2.set_bitrate(250_000);
90 102
91 can.set_extended_filter( 103 can.properties().set_extended_filter(
92 can::filter::ExtendedFilterSlot::_0, 104 can::filter::ExtendedFilterSlot::_0,
93 can::filter::ExtendedFilter::accept_all_into_fifo1(), 105 can::filter::ExtendedFilter::accept_all_into_fifo1(),
94 ); 106 );
95 can2.set_extended_filter( 107 can2.properties().set_extended_filter(
96 can::filter::ExtendedFilterSlot::_0, 108 can::filter::ExtendedFilterSlot::_0,
97 can::filter::ExtendedFilter::accept_all_into_fifo1(), 109 can::filter::ExtendedFilter::accept_all_into_fifo1(),
98 ); 110 );
@@ -106,8 +118,8 @@ async fn main(_spawner: Spawner) {
106 info!("CAN Configured"); 118 info!("CAN Configured");
107 119
108 // Test again with a split 120 // Test again with a split
109 let (mut tx, mut rx) = can.split(); 121 let (mut tx, mut rx, _props) = can.split();
110 let (mut tx2, mut rx2) = can2.split(); 122 let (mut tx2, mut rx2, _props) = can2.split();
111 run_split_can_tests(&mut tx, &mut rx, &options).await; 123 run_split_can_tests(&mut tx, &mut rx, &options).await;
112 run_split_can_tests(&mut tx2, &mut rx2, &options).await; 124 run_split_can_tests(&mut tx2, &mut rx2, &options).await;
113 125