diff options
| author | xoviat <[email protected]> | 2025-11-02 15:42:10 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-02 15:42:10 +0000 |
| commit | 3ff0b2c5971e72a93bd37d7f8fecbc8e64421360 (patch) | |
| tree | 179ff4398ec7ea475ed48047565aaa46b1b1f7e0 | |
| parent | cf231d461ff4b16cf7d16e4dbc5db909212c2c89 (diff) | |
| parent | 758ea62859d6e93be573f700425fb0cdde957292 (diff) | |
Merge pull request #4821 from RichardWGNR/issue-4816
embassy-stm32: Automatic FDCAN bus off recovery
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/can/fd/config.rs | 13 | ||||
| -rw-r--r-- | embassy-stm32/src/can/fdcan.rs | 15 |
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 | ||
| 365 | impl FdCanConfig { | 367 | impl 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 | ||
| 461 | impl Default for FdCanConfig { | 473 | impl 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 | } |
