From e0c5e93e78d48a2077578ac01d532066a638115a Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Sun, 18 May 2025 22:09:00 +0200 Subject: [PATCH] Count all users of a given CAN instance and cleanup pins and RCC when the last user gets dropped --- embassy-stm32/src/can/fdcan.rs | 71 +++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 5467a40f1..a7815f79b 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -10,7 +10,7 @@ use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; use crate::can::fd::peripheral::Registers; -use crate::gpio::{AfType, OutputType, Pull, Speed}; +use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; use crate::{interrupt, peripherals, Peri}; @@ -187,13 +187,17 @@ impl<'d> CanConfigurator<'d> { rcc::enable_and_reset::(); + let info = T::info(); + let state = unsafe { T::mut_state() }; + state.tx_pin_port = Some(tx.pin_port()); + state.rx_pin_port = Some(rx.pin_port()); + (info.internal_operation)(InternalOperation::NotifySenderCreated); + (info.internal_operation)(InternalOperation::NotifyReceiverCreated); + 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(Pull::None)); - tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); - unsafe { T::IT0Interrupt::unpend(); // Not unsafe T::IT0Interrupt::enable(); @@ -204,8 +208,8 @@ impl<'d> CanConfigurator<'d> { Self { _phantom: PhantomData, config, - info: T::info(), - state: T::state(), + info, + state, properties: Properties::new(T::info()), periph_clock: T::frequency(), } @@ -265,6 +269,8 @@ impl<'d> CanConfigurator<'d> { } }); self.info.regs.into_mode(self.config, mode); + (self.info.internal_operation)(InternalOperation::NotifySenderCreated); + (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); Can { _phantom: PhantomData, config: self.config, @@ -291,6 +297,13 @@ impl<'d> CanConfigurator<'d> { } } +impl<'d> Drop for CanConfigurator<'d> { + fn drop(&mut self) { + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + } +} + /// FDCAN Instance pub struct Can<'d> { _phantom: PhantomData<&'d ()>, @@ -353,6 +366,8 @@ impl<'d> Can<'d> { /// Split instance into separate portions: Tx(write), Rx(read), common properties pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) { + (self.info.internal_operation)(InternalOperation::NotifySenderCreated); + (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); ( CanTx { _phantom: PhantomData, @@ -367,11 +382,15 @@ impl<'d> Can<'d> { state: self.state, _mode: self._mode, }, - self.properties, + Properties { + info: self.properties.info, + }, ) } /// Join split rx and tx portions back together pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self { + (tx.info.internal_operation)(InternalOperation::NotifySenderCreated); + (tx.info.internal_operation)(InternalOperation::NotifyReceiverCreated); Can { _phantom: PhantomData, config: tx.config, @@ -401,6 +420,13 @@ impl<'d> Can<'d> { } } +impl<'d> Drop for Can<'d> { + fn drop(&mut self) { + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + } +} + /// User supplied buffer for RX Buffering pub type RxBuf = Channel, BUF_SIZE>; @@ -426,6 +452,8 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, ) -> Self { + (info.internal_operation)(InternalOperation::NotifySenderCreated); + (info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedCan { _phantom: PhantomData, info, @@ -532,6 +560,8 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, ) -> Self { + (info.internal_operation)(InternalOperation::NotifySenderCreated); + (info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedCanFd { _phantom: PhantomData, info, @@ -627,6 +657,12 @@ impl<'d> CanRx<'d> { } } +impl<'d> Drop for CanRx<'d> { + fn drop(&mut self) { + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + } +} + /// FDCAN Tx only Instance pub struct CanTx<'d> { _phantom: PhantomData<&'d ()>, @@ -654,6 +690,12 @@ impl<'c, 'd> CanTx<'d> { } } +impl<'d> Drop for CanTx<'d> { + fn drop(&mut self) { + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); + } +} + enum RxMode { NonBuffered(AtomicWaker), ClassicBuffered(super::common::ClassicBufferedRxInner), @@ -898,6 +940,8 @@ struct State { pub ns_per_timer_tick: u64, receiver_instance_count: usize, sender_instance_count: usize, + tx_pin_port: Option, + rx_pin_port: Option, pub err_waker: AtomicWaker, } @@ -909,8 +953,10 @@ impl State { tx_mode: TxMode::NonBuffered(AtomicWaker::new()), ns_per_timer_tick: 0, err_waker: AtomicWaker::new(), - receiver_instance_count: 1, - sender_instance_count: 1, + receiver_instance_count: 0, + sender_instance_count: 0, + tx_pin_port: None, + rx_pin_port: None, } } } @@ -998,6 +1044,13 @@ macro_rules! impl_fdcan { } } } + if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 { + let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap()); + tx_pin.set_as_disconnected(); + let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap()); + rx_pin.set_as_disconnected(); + rcc::disable::(); + } } }); }