diff --git a/examples/display-touch.rs b/examples/display-touch.rs index 04f6af1d..1976403e 100644 --- a/examples/display-touch.rs +++ b/examples/display-touch.rs @@ -32,7 +32,7 @@ use embedded_graphics_07::{ }; #[cfg(feature = "stm32f413")] -use stm32f4xx_hal::fmpi2c::FMPI2c; +use stm32f4xx_hal::fmpi2c::I2c; #[cfg(feature = "stm32f412")] use stm32f4xx_hal::i2c::I2c; @@ -153,7 +153,7 @@ fn main() -> ! { // STM32F413 uses FMPI2C1 type. // The pins are mentioned in documentation -um2135-discovery-kit-with-stm32f413zh-mcu-stmicroelectronics #[cfg(feature = "stm32f413")] - let mut i2c = { FMPI2c::new(p.FMPI2C1, (gpioc.pc6, gpioc.pc7), 400.kHz()) }; + let mut i2c = { I2c::new(p.FMPI2C1, (gpioc.pc6, gpioc.pc7), 400.kHz()) }; #[cfg(feature = "stm32f412")] let ts_int = gpiog.pg5.into_pull_down_input(); diff --git a/src/fmpi2c.rs b/src/fmpi2c.rs index 42858d4e..7040e2bb 100644 --- a/src/fmpi2c.rs +++ b/src/fmpi2c.rs @@ -2,54 +2,67 @@ use core::ops::Deref; use crate::gpio; use crate::i2c::{Error, NoAcknowledgeSource}; -use crate::pac::{fmpi2c1, FMPI2C1, RCC}; -use crate::rcc::{Enable, Reset}; +use crate::pac::fmpi2c1 as i2c1; +use crate::pac::{self, RCC}; +use crate::rcc::{BusClock, Enable, Reset}; use fugit::{HertzU32 as Hertz, RateExtU32}; +// Old names +pub use I2c as FmpI2c; +pub use Mode as FmpMode; + mod hal_02; mod hal_1; pub trait Instance: crate::Sealed - + crate::Ptr + + crate::Ptr + Deref + Enable + Reset + + BusClock + gpio::alt::I2cCommon { fn clock_hsi(rcc: &crate::pac::rcc::RegisterBlock); } -impl Instance for FMPI2C1 { - fn clock_hsi(rcc: &crate::pac::rcc::RegisterBlock) { - rcc.dckcfgr2().modify(|_, w| w.fmpi2c1sel().hsi()); - } -} +macro_rules! i2c { + ($I2C:ty, $i2csel:ident, $I2Calias:ident) => { + pub type $I2Calias = I2c<$I2C>; -impl crate::Ptr for FMPI2C1 { - type RB = fmpi2c1::RegisterBlock; - #[inline(always)] - fn ptr() -> *const Self::RB { - Self::ptr() - } + impl Instance for $I2C { + fn clock_hsi(rcc: &crate::pac::rcc::RegisterBlock) { + rcc.dckcfgr2().modify(|_, w| w.$i2csel().hsi()); + } + } + + impl crate::Ptr for $I2C { + type RB = i2c1::RegisterBlock; + #[inline(always)] + fn ptr() -> *const Self::RB { + Self::ptr() + } + } + }; } +#[cfg(feature = "fmpi2c1")] +i2c!(pac::FMPI2C1, fmpi2c1sel, FMPI2c1); + /// I2C FastMode+ abstraction -pub struct FMPI2c { +pub struct I2c { i2c: I2C, pins: (I2C::Scl, I2C::Sda), } -pub type FMPI2c1 = FMPI2c; - -#[derive(Debug, PartialEq)] -pub enum FmpMode { +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Mode { Standard { frequency: Hertz }, Fast { frequency: Hertz }, FastPlus { frequency: Hertz }, } -impl FmpMode { +impl Mode { pub fn standard(frequency: Hertz) -> Self { Self::Standard { frequency } } @@ -71,7 +84,7 @@ impl FmpMode { } } -impl From for FmpMode { +impl From for Mode { fn from(frequency: Hertz) -> Self { let k100: Hertz = 100.kHz(); let k400: Hertz = 400.kHz(); @@ -85,26 +98,39 @@ impl From for FmpMode { } } -impl FMPI2c { +pub trait I2cExt: Sized + Instance { + fn i2c<'a>( + self, + pins: (impl Into, impl Into), + mode: impl Into, + ) -> I2c; +} + +impl I2cExt for I2C { + fn i2c<'a>( + self, + pins: (impl Into, impl Into), + mode: impl Into, + ) -> I2c { + I2c::new(self, pins, mode) + } +} + +impl I2c { pub fn new( i2c: I2C, pins: (impl Into, impl Into), - mode: impl Into, + mode: impl Into, ) -> Self { unsafe { - // NOTE(unsafe) this reference will only be used for atomic writes with no side effects. - let rcc = &(*RCC::ptr()); - // Enable and reset clock. - I2C::enable(rcc); - I2C::reset(rcc); - - I2C::clock_hsi(rcc); + I2C::enable_unchecked(); + I2C::reset_unchecked(); } let pins = (pins.0.into(), pins.1.into()); - let i2c = FMPI2c { i2c, pins }; + let i2c = I2c { i2c, pins }; i2c.i2c_init(mode); i2c } @@ -114,14 +140,18 @@ impl FMPI2c { } } -impl FMPI2c { - fn i2c_init>(&self, mode: M) { +impl I2c { + fn i2c_init(&self, mode: impl Into) { let mode = mode.into(); use core::cmp; // Make sure the I2C unit is disabled so we can configure it self.i2c.cr1().modify(|_, w| w.pe().clear_bit()); + // NOTE(unsafe) this reference will only be used for atomic writes with no side effects. + let rcc = unsafe { &(*RCC::ptr()) }; + I2C::clock_hsi(rcc); + // Calculate settings for I2C speed modes let presc; let scldel; @@ -135,21 +165,21 @@ impl FMPI2c { // Normal I2C speeds use a different scaling than fast mode below and fast mode+ even more // below match mode { - FmpMode::Standard { frequency } => { + Mode::Standard { frequency } => { presc = 3; scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 1, 255) as u8; sclh = scll - 4; sdadel = 2; scldel = 4; } - FmpMode::Fast { frequency } => { + Mode::Fast { frequency } => { presc = 1; scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 1, 255) as u8; sclh = scll - 6; sdadel = 2; scldel = 3; } - FmpMode::FastPlus { frequency } => { + Mode::FastPlus { frequency } => { presc = 0; scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 4, 255) as u8; sclh = scll - 2; @@ -171,7 +201,8 @@ impl FMPI2c { self.i2c.cr1().modify(|_, w| w.pe().set_bit()); } - fn check_and_clear_error_flags(&self, isr: &fmpi2c1::isr::R) -> Result<(), Error> { + #[inline(always)] + fn check_and_clear_error_flags(&self, isr: &i2c1::isr::R) -> Result<(), Error> { // If we received a NACK, then this is an error if isr.nackf().bit_is_set() { self.i2c @@ -183,6 +214,7 @@ impl FMPI2c { Ok(()) } + #[inline(always)] fn end_transaction(&self) -> Result<(), Error> { // Check and clear flags if they somehow ended up set self.check_and_clear_error_flags(&self.i2c.isr().read()) diff --git a/src/fmpi2c/hal_02.rs b/src/fmpi2c/hal_02.rs index 465201f0..0cfa55df 100644 --- a/src/fmpi2c/hal_02.rs +++ b/src/fmpi2c/hal_02.rs @@ -1,12 +1,8 @@ mod blocking { - use super::super::{fmpi2c1, Error, FMPI2c, Instance}; - use core::ops::Deref; + use super::super::{Error, I2c, Instance}; use embedded_hal_02::blocking::i2c::{Read, Write, WriteRead}; - impl WriteRead for FMPI2c - where - I2C: Deref, - { + impl WriteRead for I2c { type Error = Error; fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { @@ -14,10 +10,7 @@ mod blocking { } } - impl Read for FMPI2c - where - I2C: Deref, - { + impl Read for I2c { type Error = Error; fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { @@ -25,10 +18,7 @@ mod blocking { } } - impl Write for FMPI2c - where - I2C: Deref, - { + impl Write for I2c { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { diff --git a/src/fmpi2c/hal_1.rs b/src/fmpi2c/hal_1.rs index 34a48ee4..ad556c57 100644 --- a/src/fmpi2c/hal_1.rs +++ b/src/fmpi2c/hal_1.rs @@ -2,19 +2,15 @@ use embedded_hal::i2c::ErrorType; use super::Instance; -impl ErrorType for super::FMPI2c { +impl ErrorType for super::I2c { type Error = super::Error; } mod blocking { - use super::super::{fmpi2c1, FMPI2c, Instance}; - use core::ops::Deref; + use super::super::{I2c, Instance}; use embedded_hal::i2c::Operation; - impl embedded_hal::i2c::I2c for FMPI2c - where - I2C: Deref, - { + impl embedded_hal::i2c::I2c for I2c { fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { self.read(addr, buffer) } diff --git a/src/i2c/hal_02.rs b/src/i2c/hal_02.rs index e85bb30c..0204394b 100644 --- a/src/i2c/hal_02.rs +++ b/src/i2c/hal_02.rs @@ -4,10 +4,7 @@ mod blocking { Operation, Read, Transactional, Write, WriteIter, WriteIterRead, WriteRead, }; - impl WriteRead for I2c - where - I2C: Instance, - { + impl WriteRead for I2c { type Error = Error; fn write_read( @@ -20,10 +17,7 @@ mod blocking { } } - impl WriteIterRead for I2c - where - I2C: Instance, - { + impl WriteIterRead for I2c { type Error = Error; fn write_iter_read( @@ -39,10 +33,7 @@ mod blocking { } } - impl Write for I2c - where - I2C: Instance, - { + impl Write for I2c { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { @@ -50,10 +41,7 @@ mod blocking { } } - impl WriteIter for I2c - where - I2C: Instance, - { + impl WriteIter for I2c { type Error = Error; fn write(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> @@ -64,10 +52,7 @@ mod blocking { } } - impl Read for I2c - where - I2C: Instance, - { + impl Read for I2c { type Error = Error; fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { @@ -75,10 +60,7 @@ mod blocking { } } - impl Transactional for I2c - where - I2C: Instance, - { + impl Transactional for I2c { type Error = Error; fn exec( diff --git a/src/prelude.rs b/src/prelude.rs index 1e80849d..d3722cca 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -55,6 +55,8 @@ pub use crate::dma::traits::DmaEventExt as _; pub use crate::dma::traits::DmaFlagExt as _; pub use crate::dma::traits::Stream as _; pub use crate::dma::traits::StreamISR as _; +#[cfg(feature = "fmpi2c1")] +pub use crate::fmpi2c::I2cExt as _; pub use crate::gpio::outport::OutPort as _; pub use crate::gpio::ExtiPin as _stm32f4xx_hal_gpio_ExtiPin; pub use crate::gpio::GpioExt as _stm32f4xx_hal_gpio_GpioExt;