From e96cf29c55ba6844e9d775577e74f71fb634cc75 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 6 Feb 2022 07:22:21 +0300 Subject: [PATCH] make i2c hal methods inherent --- CHANGELOG.md | 2 + src/fmpi2c.rs | 117 ++++++++++++++++++++++++++++++++++++++++++ src/fmpi2c/hal_02.rs | 111 ++-------------------------------------- src/i2c.rs | 119 ++++++++++++++++++++++++++++++++++++------- src/i2c/hal_02.rs | 87 +++---------------------------- src/prelude.rs | 4 -- 6 files changed, 230 insertions(+), 210 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d63983b4..33eac4b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Move `i2c` `embedded-hal` trait impls to `I2c` methods [#431] - Reexport pins in `gpio` module - Add channel events, make Event use bitflags (simplify interrupt handling) [#425] - reexport `digital::v2::PinState` again [#428] @@ -32,6 +33,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [#428]: https://github.com/stm32-rs/stm32f4xx-hal/pull/428 [#425]: https://github.com/stm32-rs/stm32f4xx-hal/pull/425 [#429]: https://github.com/stm32-rs/stm32f4xx-hal/pull/429 +[#431]: https://github.com/stm32-rs/stm32f4xx-hal/pull/431 ### Changed diff --git a/src/fmpi2c.rs b/src/fmpi2c.rs index ddcfc199..65a4e317 100644 --- a/src/fmpi2c.rs +++ b/src/fmpi2c.rs @@ -200,4 +200,121 @@ where let value = self.i2c.rxdr.read().bits() as u8; Ok(value) } + + pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { + // Set up current address for reading + self.i2c.cr2.modify(|_, w| { + w.sadd() + .bits(u16::from(addr) << 1) + .nbytes() + .bits(buffer.len() as u8) + .rd_wrn() + .set_bit() + }); + + // Send a START condition + self.i2c.cr2.modify(|_, w| w.start().set_bit()); + + // Send the autoend after setting the start to get a restart + self.i2c.cr2.modify(|_, w| w.autoend().set_bit()); + + // Now read in all bytes + for c in buffer.iter_mut() { + *c = self.recv_byte()?; + } + + // Check and clear flags if they somehow ended up set + self.check_and_clear_error_flags(&self.i2c.isr.read())?; + + Ok(()) + } + + pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { + // Set up current slave address for writing and enable autoending + self.i2c.cr2.modify(|_, w| { + w.sadd() + .bits(u16::from(addr) << 1) + .nbytes() + .bits(bytes.len() as u8) + .rd_wrn() + .clear_bit() + .autoend() + .set_bit() + }); + + // Send a START condition + self.i2c.cr2.modify(|_, w| w.start().set_bit()); + + // Send out all individual bytes + for c in bytes { + self.send_byte(*c)?; + } + + // Check and clear flags if they somehow ended up set + self.check_and_clear_error_flags(&self.i2c.isr.read())?; + + Ok(()) + } + + pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { + // Set up current slave address for writing and disable autoending + self.i2c.cr2.modify(|_, w| { + w.sadd() + .bits(u16::from(addr) << 1) + .nbytes() + .bits(bytes.len() as u8) + .rd_wrn() + .clear_bit() + .autoend() + .clear_bit() + }); + + // Send a START condition + self.i2c.cr2.modify(|_, w| w.start().set_bit()); + + // Wait until the transmit buffer is empty and there hasn't been any error condition + while { + let isr = self.i2c.isr.read(); + self.check_and_clear_error_flags(&isr)?; + isr.txis().bit_is_clear() && isr.tc().bit_is_clear() + } {} + + // Send out all individual bytes + for c in bytes { + self.send_byte(*c)?; + } + + // Wait until data was sent + while { + let isr = self.i2c.isr.read(); + self.check_and_clear_error_flags(&isr)?; + isr.tc().bit_is_clear() + } {} + + // Set up current address for reading + self.i2c.cr2.modify(|_, w| { + w.sadd() + .bits(u16::from(addr) << 1) + .nbytes() + .bits(buffer.len() as u8) + .rd_wrn() + .set_bit() + }); + + // Send another START condition + self.i2c.cr2.modify(|_, w| w.start().set_bit()); + + // Send the autoend after setting the start to get a restart + self.i2c.cr2.modify(|_, w| w.autoend().set_bit()); + + // Now read in all bytes + for c in buffer.iter_mut() { + *c = self.recv_byte()?; + } + + // Check and clear flags if they somehow ended up set + self.check_and_clear_error_flags(&self.i2c.isr.read())?; + + Ok(()) + } } diff --git a/src/fmpi2c/hal_02.rs b/src/fmpi2c/hal_02.rs index 2c90d1a1..ad56de4c 100644 --- a/src/fmpi2c/hal_02.rs +++ b/src/fmpi2c/hal_02.rs @@ -10,65 +10,7 @@ mod blocking { type Error = Error; fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { - // Set up current slave address for writing and disable autoending - self.i2c.cr2.modify(|_, w| { - w.sadd() - .bits(u16::from(addr) << 1) - .nbytes() - .bits(bytes.len() as u8) - .rd_wrn() - .clear_bit() - .autoend() - .clear_bit() - }); - - // Send a START condition - self.i2c.cr2.modify(|_, w| w.start().set_bit()); - - // Wait until the transmit buffer is empty and there hasn't been any error condition - while { - let isr = self.i2c.isr.read(); - self.check_and_clear_error_flags(&isr)?; - isr.txis().bit_is_clear() && isr.tc().bit_is_clear() - } {} - - // Send out all individual bytes - for c in bytes { - self.send_byte(*c)?; - } - - // Wait until data was sent - while { - let isr = self.i2c.isr.read(); - self.check_and_clear_error_flags(&isr)?; - isr.tc().bit_is_clear() - } {} - - // Set up current address for reading - self.i2c.cr2.modify(|_, w| { - w.sadd() - .bits(u16::from(addr) << 1) - .nbytes() - .bits(buffer.len() as u8) - .rd_wrn() - .set_bit() - }); - - // Send another START condition - self.i2c.cr2.modify(|_, w| w.start().set_bit()); - - // Send the autoend after setting the start to get a restart - self.i2c.cr2.modify(|_, w| w.autoend().set_bit()); - - // Now read in all bytes - for c in buffer.iter_mut() { - *c = self.recv_byte()?; - } - - // Check and clear flags if they somehow ended up set - self.check_and_clear_error_flags(&self.i2c.isr.read())?; - - Ok(()) + self.write_read(addr, bytes, buffer) } } @@ -79,31 +21,7 @@ mod blocking { type Error = Error; fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { - // Set up current address for reading - self.i2c.cr2.modify(|_, w| { - w.sadd() - .bits(u16::from(addr) << 1) - .nbytes() - .bits(buffer.len() as u8) - .rd_wrn() - .set_bit() - }); - - // Send a START condition - self.i2c.cr2.modify(|_, w| w.start().set_bit()); - - // Send the autoend after setting the start to get a restart - self.i2c.cr2.modify(|_, w| w.autoend().set_bit()); - - // Now read in all bytes - for c in buffer.iter_mut() { - *c = self.recv_byte()?; - } - - // Check and clear flags if they somehow ended up set - self.check_and_clear_error_flags(&self.i2c.isr.read())?; - - Ok(()) + self.read(addr, buffer) } } @@ -114,30 +32,7 @@ mod blocking { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { - // Set up current slave address for writing and enable autoending - self.i2c.cr2.modify(|_, w| { - w.sadd() - .bits(u16::from(addr) << 1) - .nbytes() - .bits(bytes.len() as u8) - .rd_wrn() - .clear_bit() - .autoend() - .set_bit() - }); - - // Send a START condition - self.i2c.cr2.modify(|_, w| w.start().set_bit()); - - // Send out all individual bytes - for c in bytes { - self.send_byte(*c)?; - } - - // Check and clear flags if they somehow ended up set - self.check_and_clear_error_flags(&self.i2c.isr.read())?; - - Ok(()) + self.write(addr, bytes) } } } diff --git a/src/i2c.rs b/src/i2c.rs index 4ba2389d..5fdfdbfe 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -149,10 +149,7 @@ where } } -impl I2c -where - I2C: Instance, -{ +impl I2c { fn i2c_init>(&self, mode: M, pclk: Hertz) { let mode = mode.into(); // Make sure the I2C unit is disabled so we can configure it @@ -256,20 +253,7 @@ where Ok(sr1) } -} - -trait I2cCommon { - fn write_bytes(&mut self, addr: u8, bytes: impl Iterator) -> Result<(), Error>; - fn send_byte(&self, byte: u8) -> Result<(), Error>; - - fn recv_byte(&self) -> Result; -} - -impl I2cCommon for I2c -where - I2C: Instance, -{ fn write_bytes(&mut self, addr: u8, bytes: impl Iterator) -> Result<(), Error> { // Send a START condition self.i2c.cr1.modify(|_, w| w.start().set_bit()); @@ -343,4 +327,105 @@ where let value = self.i2c.dr.read().bits() as u8; Ok(value) } + + pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { + if let Some((last, buffer)) = buffer.split_last_mut() { + // Send a START condition and set ACK bit + self.i2c + .cr1 + .modify(|_, w| w.start().set_bit().ack().set_bit()); + + // Wait until START condition was generated + while self.i2c.sr1.read().sb().bit_is_clear() {} + + // Also wait until signalled we're master and everything is waiting for us + while { + let sr2 = self.i2c.sr2.read(); + sr2.msl().bit_is_clear() && sr2.busy().bit_is_clear() + } {} + + // Set up current address, we're trying to talk to + self.i2c + .dr + .write(|w| unsafe { w.bits((u32::from(addr) << 1) + 1) }); + + // Wait until address was sent + loop { + self.check_and_clear_error_flags()?; + if self.i2c.sr1.read().addr().bit_is_set() { + break; + } + } + + // Clear condition by reading SR2 + self.i2c.sr2.read(); + + // Receive bytes into buffer + for c in buffer { + *c = self.recv_byte()?; + } + + // Prepare to send NACK then STOP after next byte + self.i2c + .cr1 + .modify(|_, w| w.ack().clear_bit().stop().set_bit()); + + // Receive last byte + *last = self.recv_byte()?; + + // Wait for the STOP to be sent. + while self.i2c.cr1.read().stop().bit_is_set() {} + + // Fallthrough is success + Ok(()) + } else { + Err(Error::OVERRUN) + } + } + + pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { + self.write_bytes(addr, bytes.iter().cloned())?; + + // Send a STOP condition + self.i2c.cr1.modify(|_, w| w.stop().set_bit()); + + // Wait for STOP condition to transmit. + while self.i2c.cr1.read().stop().bit_is_set() {} + + // Fallthrough is success + Ok(()) + } + + pub fn write_iter(&mut self, addr: u8, bytes: B) -> Result<(), Error> + where + B: IntoIterator, + { + self.write_bytes(addr, bytes.into_iter())?; + + // Send a STOP condition + self.i2c.cr1.modify(|_, w| w.stop().set_bit()); + + // Wait for STOP condition to transmit. + while self.i2c.cr1.read().stop().bit_is_set() {} + + // Fallthrough is success + Ok(()) + } + + pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { + self.write_bytes(addr, bytes.iter().cloned())?; + self.read(addr, buffer)?; + + Ok(()) + } + + pub fn write_iter_read(&mut self, addr: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Error> + where + B: IntoIterator, + { + self.write_bytes(addr, bytes.into_iter())?; + self.read(addr, buffer)?; + + Ok(()) + } } diff --git a/src/i2c/hal_02.rs b/src/i2c/hal_02.rs index 440c0678..2bca63f5 100644 --- a/src/i2c/hal_02.rs +++ b/src/i2c/hal_02.rs @@ -1,5 +1,5 @@ mod blocking { - use super::super::{Error, I2c, I2cCommon, Instance}; + use super::super::{Error, I2c, Instance}; use embedded_hal::blocking::i2c::{Read, Write, WriteIter, WriteIterRead, WriteRead}; impl WriteRead for I2c @@ -14,10 +14,7 @@ mod blocking { bytes: &[u8], buffer: &mut [u8], ) -> Result<(), Self::Error> { - self.write_bytes(addr, bytes.iter().cloned())?; - self.read(addr, buffer)?; - - Ok(()) + self.write_read(addr, bytes, buffer) } } @@ -36,10 +33,7 @@ mod blocking { where B: IntoIterator, { - self.write_bytes(addr, bytes.into_iter())?; - self.read(addr, buffer)?; - - Ok(()) + self.write_iter_read(addr, bytes, buffer) } } @@ -50,16 +44,7 @@ mod blocking { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.write_bytes(addr, bytes.iter().cloned())?; - - // Send a STOP condition - self.i2c.cr1.modify(|_, w| w.stop().set_bit()); - - // Wait for STOP condition to transmit. - while self.i2c.cr1.read().stop().bit_is_set() {} - - // Fallthrough is success - Ok(()) + self.write(addr, bytes) } } @@ -73,16 +58,7 @@ mod blocking { where B: IntoIterator, { - self.write_bytes(addr, bytes.into_iter())?; - - // Send a STOP condition - self.i2c.cr1.modify(|_, w| w.stop().set_bit()); - - // Wait for STOP condition to transmit. - while self.i2c.cr1.read().stop().bit_is_set() {} - - // Fallthrough is success - Ok(()) + self.write_iter(addr, bytes) } } @@ -93,58 +69,7 @@ mod blocking { type Error = Error; fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - if let Some((last, buffer)) = buffer.split_last_mut() { - // Send a START condition and set ACK bit - self.i2c - .cr1 - .modify(|_, w| w.start().set_bit().ack().set_bit()); - - // Wait until START condition was generated - while self.i2c.sr1.read().sb().bit_is_clear() {} - - // Also wait until signalled we're master and everything is waiting for us - while { - let sr2 = self.i2c.sr2.read(); - sr2.msl().bit_is_clear() && sr2.busy().bit_is_clear() - } {} - - // Set up current address, we're trying to talk to - self.i2c - .dr - .write(|w| unsafe { w.bits((u32::from(addr) << 1) + 1) }); - - // Wait until address was sent - loop { - self.check_and_clear_error_flags()?; - if self.i2c.sr1.read().addr().bit_is_set() { - break; - } - } - - // Clear condition by reading SR2 - self.i2c.sr2.read(); - - // Receive bytes into buffer - for c in buffer { - *c = self.recv_byte()?; - } - - // Prepare to send NACK then STOP after next byte - self.i2c - .cr1 - .modify(|_, w| w.ack().clear_bit().stop().set_bit()); - - // Receive last byte - *last = self.recv_byte()?; - - // Wait for the STOP to be sent. - while self.i2c.cr1.read().stop().bit_is_set() {} - - // Fallthrough is success - Ok(()) - } else { - Err(Error::OVERRUN) - } + self.read(addr, buffer) } } } diff --git a/src/prelude.rs b/src/prelude.rs index 7f839ee0..f093c923 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -39,10 +39,6 @@ pub use embedded_hal::adc::OneShot as _embedded_hal_adc_OneShot; pub use embedded_hal::blocking::delay::DelayMs as _embedded_hal_blocking_delay_DelayMs; pub use embedded_hal::blocking::delay::DelayUs as _embedded_hal_blocking_delay_DelayUs; -pub use embedded_hal::blocking::i2c::{ - Read as _embedded_hal_blocking_i2c_Read, Write as _embedded_hal_blocking_i2c_Write, - WriteRead as _embedded_hal_blocking_i2c_WriteRead, -}; pub use embedded_hal::blocking::serial::Write as _embedded_hal_blocking_serial_Write; pub use embedded_hal::blocking::spi::{ Transfer as _embedded_hal_blocking_spi_Transfer, Write as _embedded_hal_blocking_spi_Write,