diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 0bf57ef8a..6d12af2cc 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -9,16 +9,16 @@ use core::future::Future; use core::iter; use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, Peripheral}; +use embassy_hal_internal::{Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; use crate::dma::ChannelAndRequest; -use crate::gpio::{AFType, Pull}; +use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::mode::{Async, Blocking, Mode}; -use crate::rcc::{self, RccInfo, SealedRccPeripheral}; +use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; use crate::{interrupt, peripherals}; @@ -72,11 +72,29 @@ impl Default for Config { } } +impl Config { + fn scl_pull_mode(&self) -> Pull { + match self.scl_pullup { + true => Pull::Up, + false => Pull::Down, + } + } + + fn sda_pull_mode(&self) -> Pull { + match self.sda_pullup { + true => Pull::Up, + false => Pull::Down, + } + } +} + /// I2C driver. pub struct I2c<'d, M: Mode> { info: &'static Info, state: &'static State, kernel_clock: Hertz, + scl: Option>, + sda: Option>, tx_dma: Option>, rx_dma: Option>, #[cfg(feature = "time")] @@ -98,7 +116,15 @@ impl<'d> I2c<'d, Async> { freq: Hertz, config: Config, ) -> Self { - Self::new_inner(peri, scl, sda, new_dma!(tx_dma), new_dma!(rx_dma), freq, config) + Self::new_inner( + peri, + new_pin!(scl, AFType::OutputOpenDrain, Speed::Medium, config.scl_pull_mode()), + new_pin!(sda, AFType::OutputOpenDrain, Speed::Medium, config.sda_pull_mode()), + new_dma!(tx_dma), + new_dma!(rx_dma), + freq, + config, + ) } } @@ -111,7 +137,15 @@ impl<'d> I2c<'d, Blocking> { freq: Hertz, config: Config, ) -> Self { - Self::new_inner(peri, scl, sda, None, None, freq, config) + Self::new_inner( + peri, + new_pin!(scl, AFType::OutputOpenDrain, Speed::Medium, config.scl_pull_mode()), + new_pin!(sda, AFType::OutputOpenDrain, Speed::Medium, config.sda_pull_mode()), + None, + None, + freq, + config, + ) } } @@ -119,34 +153,13 @@ impl<'d, M: Mode> I2c<'d, M> { /// Create a new I2C driver. fn new_inner( _peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, + scl: Option>, + sda: Option>, tx_dma: Option>, rx_dma: Option>, freq: Hertz, config: Config, ) -> Self { - into_ref!(scl, sda); - - rcc::enable_and_reset::(); - - scl.set_as_af_pull( - scl.af_num(), - AFType::OutputOpenDrain, - match config.scl_pullup { - true => Pull::Up, - false => Pull::None, - }, - ); - sda.set_as_af_pull( - sda.af_num(), - AFType::OutputOpenDrain, - match config.sda_pullup { - true => Pull::Up, - false => Pull::None, - }, - ); - unsafe { T::EventInterrupt::enable() }; unsafe { T::ErrorInterrupt::enable() }; @@ -154,18 +167,23 @@ impl<'d, M: Mode> I2c<'d, M> { info: T::info(), state: T::state(), kernel_clock: T::frequency(), + scl, + sda, tx_dma, rx_dma, #[cfg(feature = "time")] timeout: config.timeout, _phantom: PhantomData, }; - - this.init(freq, config); - + this.enable_and_init(freq, config); this } + fn enable_and_init(&mut self, freq: Hertz, config: Config) { + self.info.rcc.enable_and_reset(); + self.init(freq, config); + } + fn timeout(&self) -> Timeout { Timeout { #[cfg(feature = "time")] @@ -174,6 +192,15 @@ impl<'d, M: Mode> I2c<'d, M> { } } +impl<'d, M: Mode> Drop for I2c<'d, M> { + fn drop(&mut self) { + self.scl.as_ref().map(|x| x.set_as_disconnected()); + self.sda.as_ref().map(|x| x.set_as_disconnected()); + + self.info.rcc.disable() + } +} + #[derive(Copy, Clone)] struct Timeout { #[cfg(feature = "time")] diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 0e2bd2e40..28026f83c 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -700,12 +700,6 @@ impl<'d> I2c<'d, Async> { } } -impl<'d, M: PeriMode> Drop for I2c<'d, M> { - fn drop(&mut self) { - self.info.rcc.disable() - } -} - enum Mode { Fast, Standard, diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 193f29733..80163c287 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -671,12 +671,6 @@ impl<'d> I2c<'d, Async> { } } -impl<'d, M: Mode> Drop for I2c<'d, M> { - fn drop(&mut self) { - self.info.rcc.disable(); - } -} - /// I2C Stop Configuration /// /// Peripheral options for generating the STOP condition diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 720e80e0d..4eaf7777f 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -13,7 +13,7 @@ use crate::dma::{slice_ptr_parts, word, ChannelAndRequest}; use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::spi::{regs, vals, Spi as Regs}; -use crate::rcc::{self, RccInfo, SealedRccPeripheral}; +use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; use crate::Peripheral; @@ -120,17 +120,30 @@ impl<'d, M: PeriMode> Spi<'d, M> { rx_dma: Option>, config: Config, ) -> Self { - let regs = T::info().regs; - let kernel_clock = T::frequency(); - let br = compute_baud_rate(kernel_clock, config.frequency); + let mut this = Self { + info: T::info(), + kernel_clock: T::frequency(), + sck, + mosi, + miso, + tx_dma, + rx_dma, + current_word_size: ::CONFIG, + _phantom: PhantomData, + }; + this.enable_and_init(config); + this + } + fn enable_and_init(&mut self, config: Config) { + let br = compute_baud_rate(self.kernel_clock, config.frequency); let cpha = config.raw_phase(); let cpol = config.raw_polarity(); - let lsbfirst = config.raw_byte_order(); - rcc::enable_and_reset::(); + self.info.rcc.enable_and_reset(); + let regs = self.info.regs; #[cfg(any(spi_v1, spi_f1))] { regs.cr2().modify(|w| { @@ -209,18 +222,6 @@ impl<'d, M: PeriMode> Spi<'d, M> { w.set_spe(true); }); } - - Self { - info: T::info(), - kernel_clock, - sck, - mosi, - miso, - tx_dma, - rx_dma, - current_word_size: ::CONFIG, - _phantom: PhantomData, - } } /// Reconfigures it with the supplied config. @@ -611,7 +612,7 @@ impl<'d> Spi<'d, Async> { // see RM0453 rev 1 section 7.2.13 page 291 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz. - let pclk3_freq = ::frequency().0; + let pclk3_freq = ::frequency().0; let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000)); let mut config = Config::default(); config.mode = MODE_0; diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index eacf95002..fd79e035e 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -6,7 +6,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; -use embassy_hal_internal::{into_ref, Peripheral}; +use embassy_hal_internal::{Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(usart_v1, usart_v2)))] @@ -15,10 +15,8 @@ use super::{ clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance, Regs, RtsPin, RxPin, TxPin, }; -use crate::gpio::AFType; -use crate::interrupt::typelevel::Interrupt as _; +use crate::gpio::{AFType, AnyPin, SealedPin as _}; use crate::interrupt::{self, InterruptExt}; -use crate::rcc; use crate::time::Hertz; /// Interrupt handler. @@ -156,7 +154,9 @@ pub struct BufferedUartTx<'d> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - _phantom: PhantomData<&'d mut ()>, + tx: Option>, + cts: Option>, + de: Option>, } /// Rx-only buffered UART @@ -166,7 +166,8 @@ pub struct BufferedUartRx<'d> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - _phantom: PhantomData<&'d mut ()>, + rx: Option>, + rts: Option>, } impl<'d> SetConfig for BufferedUart<'d> { @@ -207,9 +208,17 @@ impl<'d> BufferedUart<'d> { rx_buffer: &'d mut [u8], config: Config, ) -> Result { - rcc::enable_and_reset::(); - - Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) + Self::new_inner( + peri, + new_pin!(rx, AFType::Input), + new_pin!(tx, AFType::OutputPushPull), + None, + None, + None, + tx_buffer, + rx_buffer, + config, + ) } /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins @@ -224,18 +233,17 @@ impl<'d> BufferedUart<'d> { rx_buffer: &'d mut [u8], config: Config, ) -> Result { - into_ref!(cts, rts); - - rcc::enable_and_reset::(); - - rts.set_as_af(rts.af_num(), AFType::OutputPushPull); - cts.set_as_af(cts.af_num(), AFType::Input); - T::info().regs.cr3().write(|w| { - w.set_rtse(true); - w.set_ctse(true); - }); - - Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) + Self::new_inner( + peri, + new_pin!(rx, AFType::Input), + new_pin!(tx, AFType::OutputPushPull), + new_pin!(rts, AFType::OutputPushPull), + new_pin!(cts, AFType::Input), + None, + tx_buffer, + rx_buffer, + config, + ) } /// Create a new bidirectional buffered UART driver with a driver-enable pin @@ -250,66 +258,89 @@ impl<'d> BufferedUart<'d> { rx_buffer: &'d mut [u8], config: Config, ) -> Result { - into_ref!(de); - - rcc::enable_and_reset::(); - - de.set_as_af(de.af_num(), AFType::OutputPushPull); - T::info().regs.cr3().write(|w| { - w.set_dem(true); - }); - - Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) + Self::new_inner( + peri, + new_pin!(rx, AFType::Input), + new_pin!(tx, AFType::OutputPushPull), + None, + None, + new_pin!(de, AFType::OutputPushPull), + tx_buffer, + rx_buffer, + config, + ) } fn new_inner( _peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, + rx: Option>, + tx: Option>, + rts: Option>, + cts: Option>, + de: Option>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> Result { - into_ref!(_peri, rx, tx); - let info = T::info(); let state = T::buffered_state(); let kernel_clock = T::frequency(); - let len = tx_buffer.len(); - unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; - let len = rx_buffer.len(); - unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; - let r = info.regs; - rx.set_as_af(rx.af_num(), AFType::Input); - tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - - configure(info, kernel_clock, &config, true, true)?; - - r.cr1().modify(|w| { - w.set_rxneie(true); - w.set_idleie(true); - }); - - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - state.tx_rx_refcount.store(2, Ordering::Relaxed); - - Ok(Self { + let mut this = Self { rx: BufferedUartRx { info, state, kernel_clock, - _phantom: PhantomData, + rx, + rts, }, tx: BufferedUartTx { info, state, kernel_clock, - _phantom: PhantomData, + tx, + cts, + de, }, - }) + }; + this.enable_and_configure(tx_buffer, rx_buffer, &config)?; + Ok(this) + } + + fn enable_and_configure( + &mut self, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + config: &Config, + ) -> Result<(), ConfigError> { + let info = self.rx.info; + let state = self.rx.state; + state.tx_rx_refcount.store(2, Ordering::Relaxed); + + info.rcc.enable_and_reset(); + + let len = tx_buffer.len(); + unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; + let len = rx_buffer.len(); + unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; + + info.regs.cr3().write(|w| { + w.set_rtse(self.rx.rts.is_some()); + w.set_ctse(self.tx.cts.is_some()); + #[cfg(not(any(usart_v1, usart_v2)))] + w.set_dem(self.tx.de.is_some()); + }); + configure(info, self.rx.kernel_clock, &config, true, true)?; + + info.regs.cr1().modify(|w| { + w.set_rxneie(true); + w.set_idleie(true); + }); + + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; + + Ok(()) } /// Split the driver into a Tx and Rx part (useful for sending to separate tasks) @@ -516,6 +547,8 @@ impl<'d> Drop for BufferedUartRx<'d> { } } + self.rx.as_ref().map(|x| x.set_as_disconnected()); + self.rts.as_ref().map(|x| x.set_as_disconnected()); drop_tx_rx(self.info, state); } } @@ -533,6 +566,9 @@ impl<'d> Drop for BufferedUartTx<'d> { } } + self.tx.as_ref().map(|x| x.set_as_disconnected()); + self.cts.as_ref().map(|x| x.set_as_disconnected()); + self.de.as_ref().map(|x| x.set_as_disconnected()); drop_tx_rx(self.info, state); } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2a39c6301..53321391a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -14,7 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker; use futures_util::future::{select, Either}; use crate::dma::ChannelAndRequest; -use crate::gpio::{AFType, AnyPin, SealedPin}; +use crate::gpio::{AFType, AnyPin, SealedPin as _}; use crate::interrupt::typelevel::Interrupt as _; use crate::interrupt::{self, Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; @@ -28,7 +28,7 @@ use crate::pac::usart::Lpuart as Regs; #[cfg(any(usart_v1, usart_v2))] use crate::pac::usart::Usart as Regs; use crate::pac::usart::{regs, vals}; -use crate::rcc::{self, RccInfo, SealedRccPeripheral}; +use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; use crate::Peripheral; @@ -429,29 +429,33 @@ impl<'d, M: Mode> UartTx<'d, M> { tx_dma: Option>, config: Config, ) -> Result { - rcc::enable_and_reset::(); - - let info = T::info(); - let state = T::state(); - let kernel_clock = T::frequency(); - let r = info.regs; - r.cr3().modify(|w| { - w.set_ctse(cts.is_some()); - }); - configure(info, kernel_clock, &config, false, true)?; - - state.tx_rx_refcount.store(1, Ordering::Relaxed); - - Ok(Self { - info, - state, - kernel_clock, + let mut this = Self { + info: T::info(), + state: T::state(), + kernel_clock: T::frequency(), tx, cts, de: None, tx_dma, _phantom: PhantomData, - }) + }; + this.enable_and_configure(&config)?; + Ok(this) + } + + fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> { + let info = self.info; + let state = self.state; + state.tx_rx_refcount.store(1, Ordering::Relaxed); + + info.rcc.enable_and_reset(); + + info.regs.cr3().modify(|w| { + w.set_ctse(self.cts.is_some()); + }); + configure(info, self.kernel_clock, config, false, true)?; + + Ok(()) } /// Reconfigure the driver @@ -775,34 +779,38 @@ impl<'d, M: Mode> UartRx<'d, M> { rx_dma: Option>, config: Config, ) -> Result { - rcc::enable_and_reset::(); - - let info = T::info(); - let state = T::state(); - let kernel_clock = T::frequency(); - let r = info.regs; - r.cr3().write(|w| { - w.set_rtse(rts.is_some()); - }); - configure(info, kernel_clock, &config, true, false)?; - - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - state.tx_rx_refcount.store(1, Ordering::Relaxed); - - Ok(Self { + let mut this = Self { _phantom: PhantomData, - info, - state, - kernel_clock, + info: T::info(), + state: T::state(), + kernel_clock: T::frequency(), rx, rts, rx_dma, detect_previous_overrun: config.detect_previous_overrun, #[cfg(any(usart_v1, usart_v2))] buffered_sr: stm32_metapac::usart::regs::Sr(0), - }) + }; + this.enable_and_configure(&config)?; + Ok(this) + } + + fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> { + let info = self.info; + let state = self.state; + state.tx_rx_refcount.store(1, Ordering::Relaxed); + + info.rcc.enable_and_reset(); + + info.regs.cr3().write(|w| { + w.set_rtse(self.rts.is_some()); + }); + configure(info, self.kernel_clock, &config, true, false)?; + + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; + + Ok(()) } /// Reconfigure the driver @@ -1228,27 +1236,11 @@ impl<'d, M: Mode> Uart<'d, M> { rx_dma: Option>, config: Config, ) -> Result { - rcc::enable_and_reset::(); - let info = T::info(); let state = T::state(); let kernel_clock = T::frequency(); - let r = info.regs; - r.cr3().write(|w| { - w.set_rtse(rts.is_some()); - w.set_ctse(cts.is_some()); - #[cfg(not(any(usart_v1, usart_v2)))] - w.set_dem(de.is_some()); - }); - configure(info, kernel_clock, &config, true, true)?; - - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - state.tx_rx_refcount.store(2, Ordering::Relaxed); - - Ok(Self { + let mut this = Self { tx: UartTx { _phantom: PhantomData, info, @@ -1271,7 +1263,30 @@ impl<'d, M: Mode> Uart<'d, M> { #[cfg(any(usart_v1, usart_v2))] buffered_sr: stm32_metapac::usart::regs::Sr(0), }, - }) + }; + this.enable_and_configure(&config)?; + Ok(this) + } + + fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> { + let info = self.rx.info; + let state = self.rx.state; + state.tx_rx_refcount.store(2, Ordering::Relaxed); + + info.rcc.enable_and_reset(); + + info.regs.cr3().write(|w| { + w.set_rtse(self.rx.rts.is_some()); + w.set_ctse(self.tx.cts.is_some()); + #[cfg(not(any(usart_v1, usart_v2)))] + w.set_dem(self.tx.de.is_some()); + }); + configure(info, self.rx.kernel_clock, config, true, true)?; + + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; + + Ok(()) } /// Perform a blocking write diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index f3a88b93f..8cf75933a 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -4,10 +4,12 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; +use embassy_hal_internal::PeripheralRef; use futures_util::future::{select, Either}; use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; use crate::dma::ReadableRingBuffer; +use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; use crate::time::Hertz; use crate::usart::{Regs, Sr}; @@ -19,6 +21,8 @@ pub struct RingBufferedUartRx<'d> { info: &'static Info, state: &'static State, kernel_clock: Hertz, + rx: Option>, + rts: Option>, ring_buf: ReadableRingBuffer<'d, u8>, } @@ -49,6 +53,8 @@ impl<'d> UartRx<'d, Async> { let state = self.state; let kernel_clock = self.kernel_clock; let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(info.regs), dma_buf, opts) }; + let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) }; + let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) }; // Don't disable the clock mem::forget(self); @@ -57,6 +63,8 @@ impl<'d> UartRx<'d, Async> { info, state, kernel_clock, + rx, + rts, ring_buf, } } @@ -221,6 +229,8 @@ impl<'d> RingBufferedUartRx<'d> { impl Drop for RingBufferedUartRx<'_> { fn drop(&mut self) { self.teardown_uart(); + self.rx.as_ref().map(|x| x.set_as_disconnected()); + self.rts.as_ref().map(|x| x.set_as_disconnected()); super::drop_tx_rx(self.info, self.state); } }