From 27de0ec671b9d026eb6a7e2a4914bf245e765c38 Mon Sep 17 00:00:00 2001 From: techmccat Date: Tue, 30 Jul 2024 17:15:57 +0200 Subject: [PATCH 1/5] i2c: move methods from macro to instance trait --- src/i2c.rs | 456 +++++++++++++++++++++++++++++------------------------ 1 file changed, 250 insertions(+), 206 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 272af5bb..33e1f890 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", @@ -200,6 +200,18 @@ macro_rules! busy_wait { }; } +pub trait Instance: + crate::Sealed + + Enable + + Reset + + GetBusFreq +{ + const PTR: *const crate::stm32::i2c1::RegisterBlock; + fn registers(&self) -> &crate::stm32::i2c1::RegisterBlock { + unsafe { &*Self::PTR } + } +} + macro_rules! i2c { ($I2CX:ident, $i2cx:ident, sda: [ $($( #[ $pmetasda:meta ] )* $PSDA:ident<$AFDA:ident>,)+ ], @@ -215,237 +227,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 { + const PTR: *const crate::stm32::i2c1::RegisterBlock = $I2CX::PTR as *const crate::stm32::i2c1::RegisterBlock; } + } +} - 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 } - } +impl I2cExt for I2C { + fn i2c(self, sda: SDA, scl: SCL, config: impl Into, rcc: &mut Rcc) -> I2c + where + SDA: SDAPin, + SCL: SCLPin, + { + I2c::i2c(self, sda, scl, config.into(), rcc) + } +} - /// 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(); - } +impl I2c +where + I2C: Instance, + SDA: SDAPin, + SCL: SCLPin, +{ + /// Initializes the I2C peripheral. + pub fn i2c(i2c: I2C, sda: SDA, scl: SCL, config: Config, rcc: &mut Rcc) -> Self + where + SDA: SDAPin, + SCL: SCLPin, + { + // Enable and reset I2C + I2C::enable(rcc); + I2C::reset(rcc); + + // Make sure the I2C unit is disabled so we can configure it + i2c.registers().cr1().modify(|_, w| w.pe().clear_bit()); + + // Setup protocol timings + i2c.registers().timingr().write(|w| + config.timing_bits(I2C::get_frequency(&rcc.clocks), w) + ); + + // Enable the I2C processing + i2c.registers().cr1().modify(|_, w| { + w.pe() + .set_bit() + .dnf() + .set(config.digital_filter) + .anfoff() + .bit(!config.analog_filter) + }); + + I2c { i2c, sda, scl } + } - (self.i2c, self.sda, self.scl) - } + /// 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> { - // 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); - } - } - - // 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(()) - } + (self.i2c, self.sda, self.scl) + } - 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(()) + // 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.registers().cr2().modify(|_, w| { + if i == 0 { + w.add10().bit(addr_10b); + w.sadd().set(addr); + w.rd_wrn().read(); + 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 have received something + busy_wait!(self.i2c.registers(), rxne, is_not_empty); + *byte = self.i2c.registers().rxdr().read().rxdata().bits(); + } + + 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.registers(), 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.registers(), stopf, is_stop); + self.i2c.registers().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)?, - } - }) - } + 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.registers().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(()); } - 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)?, - } - }) + // Process 255 bytes at a time + for (i, buffer) in buffer.chunks(0xFF).enumerate() { + // Prepare to receive `bytes` + self.i2c.registers().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.registers(), txis, is_empty); + self.i2c.registers().txdr().write(|w| w.txdata().set(*byte)); } - } - 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(()) + if i != end { + // Wait until the last transmission is finished + busy_wait!(self.i2c.registers(), tcr, is_complete); } } - impl Write for I2c<$I2CX, SDA, SCL> { - type Error = Error; + // Wait until the last transmission is finished + // auto stop is set + busy_wait!(self.i2c.registers(), stopf, is_stop); + self.i2c.registers().icr().write(|w| w.stopcf().clear()); + Ok(()) + } +} + +impl embedded_hal::i2c::ErrorType for I2c { + type Error = Error; +} - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.write_inner(addr as u16, false, bytes)?; - 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.registers().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 Read for I2c<$I2CX, SDA, SCL> { - type Error = Error; - - fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read_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.registers().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 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(()) + } +} + +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(()) } } From 41d2c2553516d20ccb7e965c032065bb8e3c27bd Mon Sep 17 00:00:00 2001 From: techmccat Date: Thu, 17 Jul 2025 10:34:56 +0200 Subject: [PATCH 2/5] i2c: use deref in instance --- src/i2c.rs | 59 ++++++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 33e1f890..88602168 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -14,8 +14,7 @@ use crate::rcc::{Enable, GetBusFreq, Rcc, Reset}; use crate::stm32::I2C4; use crate::stm32::{I2C1, I2C2, I2C3}; use crate::time::Hertz; -use core::cmp; -use core::convert::TryInto; +use core::{convert::TryInto, cmp, ops::Deref}; /// I2C bus configuration. #[derive(Debug, Clone, Copy)] @@ -200,17 +199,13 @@ macro_rules! busy_wait { }; } -pub trait Instance: +pub trait Instance: crate::Sealed - + Enable - + Reset - + GetBusFreq -{ - const PTR: *const crate::stm32::i2c1::RegisterBlock; - fn registers(&self) -> &crate::stm32::i2c1::RegisterBlock { - unsafe { &*Self::PTR } - } -} + + Deref + + Enable + + Reset + + GetBusFreq +{} macro_rules! i2c { ($I2CX:ident, $i2cx:ident, @@ -227,9 +222,7 @@ macro_rules! i2c { impl SCLPin<$I2CX> for gpio::$PSCL> {} )+ - impl Instance for $I2CX { - const PTR: *const crate::stm32::i2c1::RegisterBlock = $I2CX::PTR as *const crate::stm32::i2c1::RegisterBlock; - } + impl Instance for $I2CX {} } } @@ -260,15 +253,15 @@ where I2C::reset(rcc); // Make sure the I2C unit is disabled so we can configure it - i2c.registers().cr1().modify(|_, w| w.pe().clear_bit()); + i2c.cr1().modify(|_, w| w.pe().clear_bit()); // Setup protocol timings - i2c.registers().timingr().write(|w| + i2c.timingr().write(|w| config.timing_bits(I2C::get_frequency(&rcc.clocks), w) ); // Enable the I2C processing - i2c.registers().cr1().modify(|_, w| { + i2c.cr1().modify(|_, w| { w.pe() .set_bit() .dnf() @@ -306,7 +299,7 @@ where // Process 255 bytes at a time for (i, buffer) in buffer.chunks_mut(0xFF).enumerate() { // Prepare to receive `bytes` - self.i2c.registers().cr2().modify(|_, w| { + self.i2c.cr2().modify(|_, w| { if i == 0 { w.add10().bit(addr_10b); w.sadd().set(addr); @@ -323,20 +316,20 @@ where for byte in buffer { // Wait until we have received something - busy_wait!(self.i2c.registers(), rxne, is_not_empty); - *byte = self.i2c.registers().rxdr().read().rxdata().bits(); + 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.registers(), tcr, is_complete); + busy_wait!(self.i2c, tcr, is_complete); } } // Wait until the last transmission is finished // auto stop is set - busy_wait!(self.i2c.registers(), stopf, is_stop); - self.i2c.registers().icr().write(|w| w.stopcf().clear()); + busy_wait!(self.i2c, stopf, is_stop); + self.i2c.icr().write(|w| w.stopcf().clear()); Ok(()) } @@ -348,7 +341,7 @@ where if buffer.is_empty() { // 0 byte write - self.i2c.registers().cr2().modify(|_, w| { + self.i2c.cr2().modify(|_, w| { w.add10().bit(addr_10b); w.sadd().set(addr); w.rd_wrn().write(); @@ -362,7 +355,7 @@ where // Process 255 bytes at a time for (i, buffer) in buffer.chunks(0xFF).enumerate() { // Prepare to receive `bytes` - self.i2c.registers().cr2().modify(|_, w| { + self.i2c.cr2().modify(|_, w| { if i == 0 { w.add10().bit(addr_10b); w.sadd().set(addr); @@ -380,20 +373,20 @@ where 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.registers(), txis, is_empty); - self.i2c.registers().txdr().write(|w| w.txdata().set(*byte)); + 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.registers(), tcr, is_complete); + busy_wait!(self.i2c, tcr, is_complete); } } // Wait until the last transmission is finished // auto stop is set - busy_wait!(self.i2c.registers(), stopf, is_stop); - self.i2c.registers().icr().write(|w| w.stopcf().clear()); + busy_wait!(self.i2c, stopf, is_stop); + self.i2c.icr().write(|w| w.stopcf().clear()); Ok(()) } } @@ -417,7 +410,7 @@ where 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.registers().isr().read().busy().bit_is_set() {} + 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)?, @@ -440,7 +433,7 @@ where 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.registers().isr().read().busy().bit_is_set() {} + 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)?, From 3f9ea67855d9c1a24cba69c4ffb6af367c30adb0 Mon Sep 17 00:00:00 2001 From: techmccat Date: Thu, 17 Jul 2025 14:50:13 +0200 Subject: [PATCH 3/5] i2c: run cargo fmt --- src/i2c.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 88602168..654619a7 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -14,7 +14,7 @@ use crate::rcc::{Enable, GetBusFreq, Rcc, Reset}; use crate::stm32::I2C4; use crate::stm32::{I2C1, I2C2, I2C3}; use crate::time::Hertz; -use core::{convert::TryInto, cmp, ops::Deref}; +use core::{cmp, convert::TryInto, ops::Deref}; /// I2C bus configuration. #[derive(Debug, Clone, Copy)] @@ -200,12 +200,9 @@ macro_rules! busy_wait { } pub trait Instance: - crate::Sealed - + Deref - + Enable - + Reset - + GetBusFreq -{} + crate::Sealed + Deref + Enable + Reset + GetBusFreq +{ +} macro_rules! i2c { ($I2CX:ident, $i2cx:ident, @@ -227,7 +224,13 @@ macro_rules! i2c { } impl I2cExt for I2C { - fn i2c(self, sda: SDA, scl: SCL, config: impl Into, rcc: &mut Rcc) -> I2c + fn i2c( + self, + sda: SDA, + scl: SCL, + config: impl Into, + rcc: &mut Rcc, + ) -> I2c where SDA: SDAPin, SCL: SCLPin, @@ -256,9 +259,8 @@ where i2c.cr1().modify(|_, w| w.pe().clear_bit()); // Setup protocol timings - i2c.timingr().write(|w| - config.timing_bits(I2C::get_frequency(&rcc.clocks), w) - ); + i2c.timingr() + .write(|w| config.timing_bits(I2C::get_frequency(&rcc.clocks), w)); // Enable the I2C processing i2c.cr1().modify(|_, w| { From be1105446f62c07544ca36147ec556868e37e3c3 Mon Sep 17 00:00:00 2001 From: techmccat Date: Thu, 17 Jul 2025 17:55:28 +0200 Subject: [PATCH 4/5] i2c: new() constructor --- src/i2c.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 654619a7..c177410c 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -205,7 +205,7 @@ pub trait Instance: } macro_rules! i2c { - ($I2CX:ident, $i2cx:ident, + ($I2CX:ident, sda: [ $($( #[ $pmetasda:meta ] )* $PSDA:ident<$AFDA:ident>,)+ ], scl: [ $($( #[ $pmetascl:meta ] )* $PSCL:ident<$AFCL:ident>,)+ ], ) => { @@ -235,7 +235,7 @@ impl I2cExt for I2C { SDA: SDAPin, SCL: SCLPin, { - I2c::i2c(self, sda, scl, config.into(), rcc) + I2c::new(self, (sda, scl), config.into(), rcc) } } @@ -246,7 +246,7 @@ where SCL: SCLPin, { /// Initializes the I2C peripheral. - pub fn i2c(i2c: I2C, sda: SDA, scl: SCL, config: Config, rcc: &mut Rcc) -> Self + pub fn new(i2c: I2C, (sda, scl): (SDA, SCL), config: Config, rcc: &mut Rcc) -> Self where SDA: SDAPin, SCL: SCLPin, @@ -490,7 +490,6 @@ where i2c!( I2C1, - i2c1, sda: [ PA14, PB7, @@ -505,7 +504,6 @@ i2c!( i2c!( I2C2, - i2c2, sda: [ PA8, PF0, @@ -525,7 +523,6 @@ i2c!( i2c!( I2C3, - i2c3, sda: [ PB5, PC11, @@ -573,7 +570,6 @@ i2c!( ))] i2c!( I2C4, - i2c4, sda: [ PB7, PC7, From cb4bb015da41d00933effd6a720e1c064c2c219b Mon Sep 17 00:00:00 2001 From: techmccat Date: Wed, 23 Jul 2025 11:28:21 +0200 Subject: [PATCH 5/5] i2c: drop new, make pins tuple --- examples/i2c-bme680.rs | 2 +- examples/i2c-mpu6050.rs | 2 +- examples/i2c.rs | 2 +- src/i2c.rs | 44 ++++++++++++++++------------------------- 4 files changed, 20 insertions(+), 30 deletions(-) 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 c177410c..7ac4542c 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -111,8 +111,7 @@ impl From for Config { /// I2C abstraction pub struct I2c { i2c: I2C, - sda: SDA, - scl: SCL, + pins: (SDA, SCL), } /// I2C SDA pin @@ -148,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 @@ -226,8 +224,7 @@ macro_rules! i2c { impl I2cExt for I2C { fn i2c( self, - sda: SDA, - scl: SCL, + pins: (SDA, SCL), config: impl Into, rcc: &mut Rcc, ) -> I2c @@ -235,35 +232,21 @@ impl I2cExt for I2C { SDA: SDAPin, SCL: SCLPin, { - I2c::new(self, (sda, scl), config.into(), rcc) - } -} + let config = config.into(); -impl I2c -where - I2C: Instance, - SDA: SDAPin, - SCL: SCLPin, -{ - /// Initializes the I2C peripheral. - pub fn new(i2c: I2C, (sda, scl): (SDA, SCL), config: Config, rcc: &mut Rcc) -> Self - where - SDA: SDAPin, - SCL: SCLPin, - { // Enable and reset I2C I2C::enable(rcc); I2C::reset(rcc); // Make sure the I2C unit is disabled so we can configure it - i2c.cr1().modify(|_, w| w.pe().clear_bit()); + self.cr1().modify(|_, w| w.pe().clear_bit()); // Setup protocol timings - i2c.timingr() + self.timingr() .write(|w| config.timing_bits(I2C::get_frequency(&rcc.clocks), w)); // Enable the I2C processing - i2c.cr1().modify(|_, w| { + self.cr1().modify(|_, w| { w.pe() .set_bit() .dnf() @@ -272,18 +255,25 @@ where .bit(!config.analog_filter) }); - I2c { i2c, sda, scl } + 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) { + pub fn release(self) -> (I2C, (SDA, SCL)) { // Disable I2C. unsafe { I2C::reset_unchecked(); I2C::disable_unchecked(); } - (self.i2c, self.sda, self.scl) + (self.i2c, self.pins) } // copied from f3 hal