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<PeripheralRef<'d, AnyPin>>, + sda: Option<PeripheralRef<'d, AnyPin>>, tx_dma: Option<ChannelAndRequest<'d>>, rx_dma: Option<ChannelAndRequest<'d>>, #[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<T: Instance>( _peri: impl Peripheral<P = T> + 'd, - scl: impl Peripheral<P = impl SclPin<T>> + 'd, - sda: impl Peripheral<P = impl SdaPin<T>> + 'd, + scl: Option<PeripheralRef<'d, AnyPin>>, + sda: Option<PeripheralRef<'d, AnyPin>>, tx_dma: Option<ChannelAndRequest<'d>>, rx_dma: Option<ChannelAndRequest<'d>>, freq: Hertz, config: Config, ) -> Self { - into_ref!(scl, sda); - - rcc::enable_and_reset::<T>(); - - 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