diff --git a/examples/i2c-bme680.rs b/examples/i2c-bme680.rs index f3f18033..4aec94a9 100644 --- a/examples/i2c-bme680.rs +++ b/examples/i2c-bme680.rs @@ -33,7 +33,7 @@ fn main() -> ! { let sda = gpiob.pb9.into_alternate_open_drain(); let scl = gpiob.pb8.into_alternate_open_drain(); - let i2c = dp.I2C1.i2c(sda, scl, Config::new(100.kHz()), &mut rcc); + let i2c = dp.I2C1.i2c((sda, scl), Config::new(100.kHz()), &mut rcc); let mut delayer = cp.SYST.delay(&rcc.clocks); let timer2 = Timer::new(dp.TIM2, &rcc.clocks); diff --git a/examples/i2c-mpu6050.rs b/examples/i2c-mpu6050.rs index bda7bcbb..bb29e915 100644 --- a/examples/i2c-mpu6050.rs +++ b/examples/i2c-mpu6050.rs @@ -29,7 +29,7 @@ fn main() -> ! { let sda = gpiob.pb9.into_alternate_open_drain(); let scl = gpiob.pb8.into_alternate_open_drain(); - let i2c = dp.I2C1.i2c(sda, scl, 100.kHz(), &mut rcc); + let i2c = dp.I2C1.i2c((sda, scl), 100.kHz(), &mut rcc); let mut mpu = Mpu6050::new(i2c); let mut delay = cp.SYST.delay(&rcc.clocks); diff --git a/examples/i2c.rs b/examples/i2c.rs index 8f327fbe..a8f8b4b8 100644 --- a/examples/i2c.rs +++ b/examples/i2c.rs @@ -26,7 +26,7 @@ fn main() -> ! { let sda = gpiob.pb9.into_alternate_open_drain(); let scl = gpiob.pb8.into_alternate_open_drain(); - let mut i2c = dp.I2C1.i2c(sda, scl, 40.kHz(), &mut rcc); + let mut i2c = dp.I2C1.i2c((sda, scl), 40.kHz(), &mut rcc); // Alternatively, it is possible to specify the exact timing as follows (see the documentation // of with_timing() for an explanation of the constant): //let mut i2c = dp diff --git a/src/i2c.rs b/src/i2c.rs index 272af5bb..7ac4542c 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -4,7 +4,7 @@ use embedded_hal::i2c::{ErrorKind, Operation, SevenBitAddress, TenBitAddress}; use embedded_hal_old::blocking::i2c::{Read, Write, WriteRead}; use crate::gpio::{self, OpenDrain}; -use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; +use crate::rcc::{Enable, GetBusFreq, Rcc, Reset}; #[cfg(any( feature = "stm32g473", feature = "stm32g474", @@ -14,8 +14,7 @@ use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; use crate::stm32::I2C4; use crate::stm32::{I2C1, I2C2, I2C3}; use crate::time::Hertz; -use core::cmp; -use core::convert::TryInto; +use core::{cmp, convert::TryInto, ops::Deref}; /// I2C bus configuration. #[derive(Debug, Clone, Copy)] @@ -112,8 +111,7 @@ impl From for Config { /// I2C abstraction pub struct I2c { i2c: I2C, - sda: SDA, - scl: SCL, + pins: (SDA, SCL), } /// I2C SDA pin @@ -149,8 +147,7 @@ impl embedded_hal::i2c::Error for Error { pub trait I2cExt { fn i2c( self, - sda: SDA, - scl: SCL, + pins: (SDA, SCL), config: impl Into, rcc: &mut Rcc, ) -> I2c @@ -200,8 +197,13 @@ macro_rules! busy_wait { }; } +pub trait Instance: + crate::Sealed + Deref + Enable + Reset + GetBusFreq +{ +} + macro_rules! i2c { - ($I2CX:ident, $i2cx:ident, + ($I2CX:ident, sda: [ $($( #[ $pmetasda:meta ] )* $PSDA:ident<$AFDA:ident>,)+ ], scl: [ $($( #[ $pmetascl:meta ] )* $PSCL:ident<$AFCL:ident>,)+ ], ) => { @@ -215,243 +217,269 @@ macro_rules! i2c { impl SCLPin<$I2CX> for gpio::$PSCL> {} )+ - impl I2cExt<$I2CX> for $I2CX { - fn i2c( - self, - sda: SDA, - scl: SCL, - config: impl Into, - rcc: &mut Rcc, - ) -> I2c<$I2CX, SDA, SCL> - where - SDA: SDAPin<$I2CX>, - SCL: SCLPin<$I2CX>, - { - I2c::$i2cx(self, sda, scl, config, rcc) - } + impl Instance for $I2CX {} + } +} + +impl I2cExt for I2C { + fn i2c( + self, + pins: (SDA, SCL), + config: impl Into, + rcc: &mut Rcc, + ) -> I2c + where + SDA: SDAPin, + SCL: SCLPin, + { + let config = config.into(); + + // Enable and reset I2C + I2C::enable(rcc); + I2C::reset(rcc); + + // Make sure the I2C unit is disabled so we can configure it + self.cr1().modify(|_, w| w.pe().clear_bit()); + + // Setup protocol timings + self.timingr() + .write(|w| config.timing_bits(I2C::get_frequency(&rcc.clocks), w)); + + // Enable the I2C processing + self.cr1().modify(|_, w| { + w.pe() + .set_bit() + .dnf() + .set(config.digital_filter) + .anfoff() + .bit(!config.analog_filter) + }); + + I2c { i2c: self, pins } + } +} + +impl I2c +where + I2C: Instance, + SDA: SDAPin, + SCL: SCLPin, +{ + /// Disables I2C and releases the peripheral as well as the pins. + pub fn release(self) -> (I2C, (SDA, SCL)) { + // Disable I2C. + unsafe { + I2C::reset_unchecked(); + I2C::disable_unchecked(); } - impl I2c<$I2CX, SDA, SCL> where - SDA: SDAPin<$I2CX>, - SCL: SCLPin<$I2CX> - { - /// Initializes the I2C peripheral. - pub fn $i2cx(i2c: $I2CX, sda: SDA, scl: SCL, config: impl Into, rcc: &mut Rcc) -> Self - where - SDA: SDAPin<$I2CX>, - SCL: SCLPin<$I2CX>, - { - let config = config.into(); - // Enable and reset I2C - $I2CX::enable(rcc); - $I2CX::reset(rcc); - - // Make sure the I2C unit is disabled so we can configure it - i2c.cr1().modify(|_, w| w.pe().clear_bit()); - - // Setup protocol timings - i2c.timingr().write(|w| config.timing_bits(<$I2CX as RccBus>::Bus::get_frequency(&rcc.clocks), w)); - - // Enable the I2C processing - i2c.cr1().modify(|_, w| { - w.pe().set_bit(); - w.dnf().set(config.digital_filter); - w.anfoff().bit(!config.analog_filter) - }); - - I2c { i2c, sda, scl } - } + (self.i2c, self.pins) + } - /// Disables I2C and releases the peripheral as well as the pins. - pub fn release(self) -> ($I2CX, SDA, SCL) { - // Disable I2C. - unsafe { - $I2CX::reset_unchecked(); - $I2CX::disable_unchecked(); + // copied from f3 hal + fn read_inner( + &mut self, + mut addr: u16, + addr_10b: bool, + buffer: &mut [u8], + ) -> Result<(), Error> { + if !addr_10b { + addr <<= 1 + }; + let end = buffer.len() / 0xFF; + + // Process 255 bytes at a time + for (i, buffer) in buffer.chunks_mut(0xFF).enumerate() { + // Prepare to receive `bytes` + self.i2c.cr2().modify(|_, w| { + if i == 0 { + w.add10().bit(addr_10b); + w.sadd().set(addr); + w.rd_wrn().read(); + w.start().start(); + } + w.nbytes().set(buffer.len() as u8); + if i == end { + w.reload().completed().autoend().automatic() + } else { + w.reload().not_completed() } + }); - (self.i2c, self.sda, self.scl) + for byte in buffer { + // Wait until we have received something + busy_wait!(self.i2c, rxne, is_not_empty); + *byte = self.i2c.rxdr().read().rxdata().bits(); } - } - - impl I2c<$I2CX, SDA, SCL> { - // copied from f3 hal - fn read_inner(&mut self, mut addr: u16, addr_10b: bool, buffer: &mut [u8]) -> Result<(), Error> { - if !addr_10b { addr <<= 1 }; - let end = buffer.len() / 0xFF; - - // Process 255 bytes at a time - for (i, buffer) in buffer.chunks_mut(0xFF).enumerate() { - // Prepare to receive `bytes` - self.i2c.cr2().modify(|_, w| { - if i == 0 { - w.add10().bit(addr_10b); - w.sadd().set(addr); - w.rd_wrn().read(); - w.start().start(); - } - w.nbytes().set(buffer.len() as u8); - if i == end { - w.reload().completed().autoend().automatic() - } else { - w.reload().not_completed() - } - }); - - for byte in buffer { - // Wait until we have received something - busy_wait!(self.i2c, rxne, is_not_empty); - *byte = self.i2c.rxdr().read().rxdata().bits(); - } - - if i != end { - // Wait until the last transmission is finished - busy_wait!(self.i2c, tcr, is_complete); - } - } + if i != end { // Wait until the last transmission is finished - // auto stop is set - busy_wait!(self.i2c, stopf, is_stop); - self.i2c.icr().write(|w| w.stopcf().clear()); - - Ok(()) + busy_wait!(self.i2c, tcr, is_complete); } + } + + // Wait until the last transmission is finished + // auto stop is set + busy_wait!(self.i2c, stopf, is_stop); + self.i2c.icr().write(|w| w.stopcf().clear()); + Ok(()) + } - fn write_inner(&mut self, mut addr: u16, addr_10b: bool, buffer: &[u8]) -> Result<(), Error> { - if !addr_10b { addr <<= 1 }; - let end = buffer.len() / 0xFF; - - if buffer.is_empty() { - // 0 byte write - self.i2c.cr2().modify(|_, w| { - w.add10().bit(addr_10b); - w.sadd().set(addr); - w.rd_wrn().write(); - w.nbytes().set(0); - w.reload().completed(); - w.autoend().automatic(); - w.start().start() - }); - return Ok(()) + fn write_inner(&mut self, mut addr: u16, addr_10b: bool, buffer: &[u8]) -> Result<(), Error> { + if !addr_10b { + addr <<= 1 + }; + let end = buffer.len() / 0xFF; + + if buffer.is_empty() { + // 0 byte write + self.i2c.cr2().modify(|_, w| { + w.add10().bit(addr_10b); + w.sadd().set(addr); + w.rd_wrn().write(); + w.nbytes().set(0); + w.reload().completed(); + w.autoend().automatic(); + w.start().start() + }); + return Ok(()); + } + // Process 255 bytes at a time + for (i, buffer) in buffer.chunks(0xFF).enumerate() { + // Prepare to receive `bytes` + self.i2c.cr2().modify(|_, w| { + if i == 0 { + w.add10().bit(addr_10b); + w.sadd().set(addr); + w.rd_wrn().write(); + w.start().start(); } - // Process 255 bytes at a time - for (i, buffer) in buffer.chunks(0xFF).enumerate() { - // Prepare to receive `bytes` - self.i2c.cr2().modify(|_, w| { - if i == 0 { - w.add10().bit(addr_10b); - w.sadd().set(addr); - w.rd_wrn().write(); - w.start().start(); - } - w.nbytes().set(buffer.len() as u8); - if i == end { - w.reload().completed().autoend().automatic() - } else { - w.reload().not_completed() - } - }); - - for byte in buffer { - // Wait until we are allowed to send data - // (START has been ACKed or last byte went through) - busy_wait!(self.i2c, txis, is_empty); - self.i2c.txdr().write(|w| w.txdata().set(*byte)); - } - - if i != end { - // Wait until the last transmission is finished - busy_wait!(self.i2c, tcr, is_complete); - } + w.nbytes().set(buffer.len() as u8); + if i == end { + w.reload().completed().autoend().automatic() + } else { + w.reload().not_completed() } + }); + for byte in buffer { + // Wait until we are allowed to send data + // (START has been ACKed or last byte went through) + busy_wait!(self.i2c, txis, is_empty); + self.i2c.txdr().write(|w| w.txdata().set(*byte)); + } + + if i != end { // Wait until the last transmission is finished - // auto stop is set - busy_wait!(self.i2c, stopf, is_stop); - self.i2c.icr().write(|w| w.stopcf().clear()); - Ok(()) + busy_wait!(self.i2c, tcr, is_complete); } } - impl embedded_hal::i2c::ErrorType for I2c<$I2CX, SDA, SCL> { - type Error = Error; - } + // Wait until the last transmission is finished + // auto stop is set + busy_wait!(self.i2c, stopf, is_stop); + self.i2c.icr().write(|w| w.stopcf().clear()); + Ok(()) + } +} - // TODO: custom read/write/read_write impl with hardware stop logic - impl embedded_hal::i2c::I2c for I2c<$I2CX, SDA, SCL> { - fn transaction( - &mut self, - address: SevenBitAddress, - operation: &mut [Operation<'_>] - ) -> Result<(), Self::Error> { - Ok(for op in operation { - // Wait for any operation on the bus to finish - // for example in the case of another bus master having claimed the bus - while self.i2c.isr().read().busy().bit_is_set() {}; - match op { - Operation::Read(data) => self.read_inner(address as u16, false, data)?, - Operation::Write(data) => self.write_inner(address as u16, false, data)?, - } - }) - } - } - impl embedded_hal::i2c::I2c for I2c<$I2CX, SDA, SCL> { - fn transaction( - &mut self, - address: TenBitAddress, - operation: &mut [Operation<'_>] - ) -> Result<(), Self::Error> { - Ok(for op in operation { - // Wait for any operation on the bus to finish - // for example in the case of another bus master having claimed the bus - while self.i2c.isr().read().busy().bit_is_set() {}; - match op { - Operation::Read(data) => self.read_inner(address, true, data)?, - Operation::Write(data) => self.write_inner(address, true, data)?, - } - }) - } - } +impl embedded_hal::i2c::ErrorType for I2c { + type Error = Error; +} - impl WriteRead for I2c<$I2CX, SDA, SCL> { - type Error = Error; - - fn write_read( - &mut self, - addr: u8, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - self.write_inner(addr as u16, false, bytes)?; - self.read_inner(addr as u16, false, buffer)?; - Ok(()) +// TODO: custom read/write/read_write impl with hardware stop logic +impl embedded_hal::i2c::I2c for I2c +where + I2C: Instance, + SDA: SDAPin, + SCL: SCLPin, +{ + fn transaction( + &mut self, + address: SevenBitAddress, + operation: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + for op in operation { + // Wait for any operation on the bus to finish + // for example in the case of another bus master having claimed the bus + while self.i2c.isr().read().busy().bit_is_set() {} + match op { + Operation::Read(data) => self.read_inner(address as u16, false, data)?, + Operation::Write(data) => self.write_inner(address as u16, false, data)?, } } - - impl Write for I2c<$I2CX, SDA, SCL> { - type Error = Error; - - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.write_inner(addr as u16, false, bytes)?; - Ok(()) + Ok(()) + } +} +impl embedded_hal::i2c::I2c for I2c +where + I2C: Instance, + SDA: SDAPin, + SCL: SCLPin, +{ + fn transaction( + &mut self, + address: TenBitAddress, + operation: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + for op in operation { + // Wait for any operation on the bus to finish + // for example in the case of another bus master having claimed the bus + while self.i2c.isr().read().busy().bit_is_set() {} + match op { + Operation::Read(data) => self.read_inner(address, true, data)?, + Operation::Write(data) => self.write_inner(address, true, data)?, } } + Ok(()) + } +} - impl Read for I2c<$I2CX, SDA, SCL> { - type Error = Error; +impl WriteRead for I2c +where + I2C: Instance, + SDA: SDAPin, + SCL: SCLPin, +{ + type Error = Error; + + fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { + self.write_inner(addr as u16, false, bytes)?; + self.read_inner(addr as u16, false, buffer)?; + Ok(()) + } +} - fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read_inner(addr as u16, false, bytes)?; - Ok(()) - } - } +impl Write for I2c +where + I2C: Instance, + SDA: SDAPin, + SCL: SCLPin, +{ + type Error = Error; + + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.write_inner(addr as u16, false, bytes)?; + Ok(()) + } +} + +impl Read for I2c +where + I2C: Instance, + SDA: SDAPin, + SCL: SCLPin, +{ + type Error = Error; + + fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Self::Error> { + self.read_inner(addr as u16, false, bytes)?; + Ok(()) } } i2c!( I2C1, - i2c1, sda: [ PA14, PB7, @@ -466,7 +494,6 @@ i2c!( i2c!( I2C2, - i2c2, sda: [ PA8, PF0, @@ -486,7 +513,6 @@ i2c!( i2c!( I2C3, - i2c3, sda: [ PB5, PC11, @@ -534,7 +560,6 @@ i2c!( ))] i2c!( I2C4, - i2c4, sda: [ PB7, PC7,