aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/can/fd/config.rs13
-rw-r--r--embassy-stm32/src/can/fdcan.rs15
3 files changed, 25 insertions, 4 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 99808c233..4e55e1034 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
38- change: timer: added output compare values 38- change: timer: added output compare values
39- feat: timer: add ability to set master mode 39- feat: timer: add ability to set master mode
40- fix: usart: fix race condition in ringbuffered usart 40- fix: usart: fix race condition in ringbuffered usart
41- feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821))
41 42
42## 0.4.0 - 2025-08-26 43## 0.4.0 - 2025-08-26
43 44
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
index e08349f02..4fe634ce4 100644
--- a/embassy-stm32/src/can/fd/config.rs
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -360,6 +360,8 @@ pub struct FdCanConfig {
360 pub global_filter: GlobalFilter, 360 pub global_filter: GlobalFilter,
361 /// TX buffer mode (FIFO or priority queue) 361 /// TX buffer mode (FIFO or priority queue)
362 pub tx_buffer_mode: TxBufferMode, 362 pub tx_buffer_mode: TxBufferMode,
363 /// Automatic recovery from bus off state
364 pub automatic_bus_off_recovery: bool,
363} 365}
364 366
365impl FdCanConfig { 367impl FdCanConfig {
@@ -456,6 +458,16 @@ impl FdCanConfig {
456 self.tx_buffer_mode = txbm; 458 self.tx_buffer_mode = txbm;
457 self 459 self
458 } 460 }
461
462 /// Enables or disables automatic recovery from bus off state
463 ///
464 /// Automatic recovery is performed by clearing the INIT bit in the CCCR register if
465 /// the BO bit is active in the IR register in the IT0 interrupt.
466 #[inline]
467 pub const fn set_automatic_bus_off_recovery(mut self, enabled: bool) -> Self {
468 self.automatic_bus_off_recovery = enabled;
469 self
470 }
459} 471}
460 472
461impl Default for FdCanConfig { 473impl Default for FdCanConfig {
@@ -474,6 +486,7 @@ impl Default for FdCanConfig {
474 timestamp_source: TimestampSource::None, 486 timestamp_source: TimestampSource::None,
475 global_filter: GlobalFilter::default(), 487 global_filter: GlobalFilter::default(),
476 tx_buffer_mode: TxBufferMode::Priority, 488 tx_buffer_mode: TxBufferMode::Priority,
489 automatic_bus_off_recovery: true,
477 } 490 }
478 } 491 }
479} 492}
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index a142a6d63..9883aff57 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -53,7 +53,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
53 regs.ir().write(|w| w.set_tefn(true)); 53 regs.ir().write(|w| w.set_tefn(true));
54 } 54 }
55 55
56 T::info().state.lock(|s| { 56 let recover_from_bo = T::info().state.lock(|s| {
57 let state = s.borrow_mut(); 57 let state = s.borrow_mut();
58 match &state.tx_mode { 58 match &state.tx_mode {
59 TxMode::NonBuffered(waker) => waker.wake(), 59 TxMode::NonBuffered(waker) => waker.wake(),
@@ -85,11 +85,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
85 if ir.rfn(1) { 85 if ir.rfn(1) {
86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick); 86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick);
87 } 87 }
88
89 state.automatic_bus_off_recovery
88 }); 90 });
89 91
90 if ir.bo() { 92 if ir.bo() {
91 regs.ir().write(|w| w.set_bo(true)); 93 regs.ir().write(|w| w.set_bo(true));
92 if regs.psr().read().bo() { 94 if let Some(true) = recover_from_bo
95 && regs.psr().read().bo()
96 {
93 // Initiate bus-off recovery sequence by resetting CCCR.INIT 97 // Initiate bus-off recovery sequence by resetting CCCR.INIT
94 regs.cccr().modify(|w| w.set_init(false)); 98 regs.cccr().modify(|w| w.set_init(false));
95 } 99 }
@@ -263,7 +267,9 @@ impl<'d> CanConfigurator<'d> {
263 pub fn start(self, mode: OperatingMode) -> Can<'d> { 267 pub fn start(self, mode: OperatingMode) -> Can<'d> {
264 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit); 268 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit);
265 self.info.state.lock(|s| { 269 self.info.state.lock(|s| {
266 s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; 270 let mut state = s.borrow_mut();
271 state.ns_per_timer_tick = ns_per_timer_tick;
272 state.automatic_bus_off_recovery = Some(self.config.automatic_bus_off_recovery);
267 }); 273 });
268 self.info.regs.into_mode(self.config, mode); 274 self.info.regs.into_mode(self.config, mode);
269 Can { 275 Can {
@@ -861,7 +867,7 @@ struct State {
861 sender_instance_count: usize, 867 sender_instance_count: usize,
862 tx_pin_port: Option<u8>, 868 tx_pin_port: Option<u8>,
863 rx_pin_port: Option<u8>, 869 rx_pin_port: Option<u8>,
864 870 automatic_bus_off_recovery: Option<bool>, // controlled by CanConfigurator::start()
865 pub err_waker: AtomicWaker, 871 pub err_waker: AtomicWaker,
866} 872}
867 873
@@ -876,6 +882,7 @@ impl State {
876 sender_instance_count: 0, 882 sender_instance_count: 0,
877 tx_pin_port: None, 883 tx_pin_port: None,
878 rx_pin_port: None, 884 rx_pin_port: None,
885 automatic_bus_off_recovery: None,
879 } 886 }
880 } 887 }
881} 888}