diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c527d97..64d1559e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Implementation of blocking i2c without timeouts - `From>` for `i2c::Mode` - `exti_rtic` example - Support for OpenDrain pin configuration on SPI CLK and MOSI pins diff --git a/src/i2c.rs b/src/i2c.rs index 94d45cb6..0b069373 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -8,12 +8,10 @@ use crate::afio::MAPR; use crate::gpio::gpiob::{PB10, PB11, PB6, PB7, PB8, PB9}; use crate::gpio::{Alternate, OpenDrain}; use crate::hal::blocking::i2c::{Read, Write, WriteRead}; -use crate::pac::{DWT, I2C1, I2C2, RCC}; +use crate::pac::{self, DWT, I2C1, I2C2, RCC}; use crate::rcc::{Clocks, Enable, GetBusFreq, Reset}; use crate::time::Hertz; use core::ops::Deref; -use nb::Error::{Other, WouldBlock}; -use nb::{Error as NbError, Result as NbResult}; pub mod blocking; pub use blocking::BlockingI2c; @@ -113,11 +111,12 @@ pub struct I2c { i2c: I2C, pins: PINS, mode: Mode, - pclk1: u32, + clk: Hertz, + start_retries: u8, } pub trait Instance: - crate::Sealed + Deref + Enable + Reset + GetBusFreq + crate::Sealed + Deref + Enable + Reset + GetBusFreq { } @@ -162,7 +161,7 @@ where I2C::enable(rcc); I2C::reset(rcc); - let pclk1 = I2C::get_frequency(&clocks).0; + let clk = I2C::get_frequency(&clocks); assert!(mode.get_frequency().0 <= 400_000); @@ -170,11 +169,17 @@ where i2c, pins, mode, - pclk1, + clk, + start_retries: 1, }; i2c.init(); i2c } + + fn retries(mut self, start_retries: u8) -> Self { + self.start_retries = start_retries; + self + } } impl I2c @@ -185,34 +190,34 @@ where /// according to the system frequency and I2C mode. fn init(&mut self) { let freq = self.mode.get_frequency(); - let pclk1_mhz = (self.pclk1 / 1000000) as u16; + let clk_mhz = (self.clk.0 / 1000000) as u16; self.i2c .cr2 - .write(|w| unsafe { w.freq().bits(pclk1_mhz as u8) }); + .write(|w| unsafe { w.freq().bits(clk_mhz as u8) }); self.i2c.cr1.write(|w| w.pe().clear_bit()); match self.mode { Mode::Standard { .. } => { self.i2c .trise - .write(|w| w.trise().bits((pclk1_mhz + 1) as u8)); + .write(|w| w.trise().bits((clk_mhz + 1) as u8)); self.i2c.ccr.write(|w| unsafe { - w.ccr().bits(((self.pclk1 / (freq.0 * 2)) as u16).max(4)) + w.ccr().bits(((self.clk.0 / (freq.0 * 2)) as u16).max(4)) }); } Mode::Fast { ref duty_cycle, .. } => { self.i2c .trise - .write(|w| w.trise().bits((pclk1_mhz * 300 / 1000 + 1) as u8)); + .write(|w| w.trise().bits((clk_mhz * 300 / 1000 + 1) as u8)); self.i2c.ccr.write(|w| { let (freq, duty) = match duty_cycle { DutyCycle::Ratio2to1 => { - (((self.pclk1 / (freq.0 * 3)) as u16).max(1), false) + (((self.clk.0 / (freq.0 * 3)) as u16).max(1), false) } DutyCycle::Ratio16to9 => { - (((self.pclk1 / (freq.0 * 25)) as u16).max(1), true) + (((self.clk.0 / (freq.0 * 25)) as u16).max(1), true) } }; @@ -233,6 +238,9 @@ where /// Generate START condition fn send_start(&mut self) { + // Clear all pending error bits + // NOTE(unsafe): Writing 0 clears the r/w bits and has no effect on the r bits + self.i2c.sr1.reset(); self.i2c.cr1.modify(|_, w| w.start().set_bit()); } @@ -249,6 +257,12 @@ where self.i2c.cr1.modify(|_, w| w.stop().set_bit()); } + /// Clears the I2C ADDR pending flag + fn clear_addr_flag(&self) { + self.i2c.sr1.read(); + self.i2c.sr2.read(); + } + /// Releases the I2C peripheral and associated pins pub fn release(self) -> (I2C, PINS) { (self.i2c, self.pins) @@ -259,3 +273,221 @@ where self.release() } } + +impl I2c +where + I2C: Instance, +{ + fn check_and_clear_error_flags(&self) -> Result { + let sr1 = self.i2c.sr1.read(); + if sr1.bits() != 0 { + // Writing 1s in order to only clear the flag we spotted even + // if the register gets modified externally + // NOTE(unsafe): Writing 1 to registers which are cleared by 0 has no effect. + // Similarly, writing to read-only registers has no effect + if sr1.berr().bit_is_set() { + self.i2c + .sr1 + .write(|w| unsafe { w.bits(0xffff).berr().clear_bit() }); + return Err(Error::Bus); + } else if sr1.arlo().bit_is_set() { + self.i2c + .sr1 + .write(|w| unsafe { w.bits(0xffff).arlo().clear_bit() }); + return Err(Error::Arbitration); + } else if sr1.af().bit_is_set() { + self.i2c + .sr1 + .write(|w| unsafe { w.bits(0xffff).af().clear_bit() }); + return Err(Error::Acknowledge); + } else if sr1.ovr().bit_is_set() { + self.i2c + .sr1 + .write(|w| unsafe { w.bits(0xffff).ovr().clear_bit() }); + return Err(Error::Overrun); + } + } + Ok(sr1) + } + + /// Check if STOP condition is generated + fn wait_for_stop(&mut self) { + while self.i2c.cr1.read().stop().is_stop() {} + } + + fn send_start_and_wait(&mut self) -> Result<(), Error> { + // According to http://www.st.com/content/ccc/resource/technical/document/errata_sheet/f5/50/c9/46/56/db/4a/f6/CD00197763.pdf/files/CD00197763.pdf/jcr:content/translations/en.CD00197763.pdf + // 2.14.4 Wrong behavior of I2C peripheral in master mode after a misplaced STOP + let mut retries_left = self.start_retries.max(1); + loop { + retries_left -= 1; + self.send_start(); + loop { + match self.check_and_clear_error_flags() { + Ok(sr1) => { + // Check if START condition is generated + if sr1.sb().bit_is_set() { + return Ok(()); + } + } + Err(e) => { + if retries_left > 0 { + self.reset(); + break; + } else { + return Err(e); + } + } + } + } + } + } + + fn send_addr_and_wait(&mut self, addr: u8, read: bool) -> Result<(), Error> { + self.i2c.sr1.read(); + self.send_addr(addr, read); + loop { + match self.check_and_clear_error_flags() { + Ok(sr1) => { + if sr1.addr().bit_is_set() { + break Ok(()); + } + } + Err(Error::Acknowledge) => { + self.send_stop(); + break Err(Error::Acknowledge); + } + Err(e) => break Err(e), + } + } + } + + fn write_bytes_and_wait(&mut self, bytes: &[u8]) -> Result<(), Error> { + self.clear_addr_flag(); + + self.i2c.dr.write(|w| w.dr().bits(bytes[0])); + + for byte in &bytes[1..] { + while self.check_and_clear_error_flags()?.tx_e().bit_is_clear() {} + self.i2c.dr.write(|w| w.dr().bits(*byte)); + } + while self.check_and_clear_error_flags()?.btf().bit_is_clear() {} + + Ok(()) + } + + fn write_without_stop(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { + self.send_start_and_wait()?; + self.send_addr_and_wait(addr, false)?; + + let ret = self.write_bytes_and_wait(bytes); + if ret == Err(Error::Acknowledge) { + self.send_stop(); + } + ret + } +} + +impl Write for I2c +where + I2C: Instance, +{ + type Error = Error; + + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.write_without_stop(addr, bytes)?; + self.send_stop(); + self.wait_for_stop(); + + Ok(()) + } +} + +impl Read for I2c +where + I2C: Instance, +{ + type Error = Error; + + fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.send_start_and_wait()?; + self.send_addr_and_wait(addr, true)?; + + match buffer { + [b0] => { + self.i2c.cr1.modify(|_, w| w.ack().clear_bit()); + self.clear_addr_flag(); + self.send_stop(); + + while self.check_and_clear_error_flags()?.rx_ne().bit_is_clear() {} + *b0 = self.i2c.dr.read().dr().bits(); + + self.wait_for_stop(); + self.i2c.cr1.modify(|_, w| w.ack().set_bit()); + } + [b0, b1] => { + self.i2c + .cr1 + .modify(|_, w| w.pos().set_bit().ack().set_bit()); + self.clear_addr_flag(); + self.i2c.cr1.modify(|_, w| w.ack().clear_bit()); + + while self.check_and_clear_error_flags()?.btf().bit_is_clear() {} + self.send_stop(); + *b0 = self.i2c.dr.read().dr().bits(); + *b1 = self.i2c.dr.read().dr().bits(); + + self.wait_for_stop(); + self.i2c + .cr1 + .modify(|_, w| w.pos().clear_bit().ack().clear_bit()); + self.i2c.cr1.modify(|_, w| w.ack().set_bit()); + } + _ => { + self.i2c.cr1.modify(|_, w| w.ack().set_bit()); + self.clear_addr_flag(); + + let (first_bytes, last_3_bytes) = buffer.split_at_mut(buffer.len() - 3); + for byte in first_bytes { + while self.check_and_clear_error_flags()?.rx_ne().bit_is_clear() {} + *byte = self.i2c.dr.read().dr().bits(); + } + + while self.check_and_clear_error_flags()?.btf().bit_is_clear() {} + self.i2c.cr1.modify(|_, w| w.ack().clear_bit()); + last_3_bytes[0] = self.i2c.dr.read().dr().bits(); + self.send_stop(); + last_3_bytes[1] = self.i2c.dr.read().dr().bits(); + while self.check_and_clear_error_flags()?.rx_ne().bit_is_clear() {} + last_3_bytes[2] = self.i2c.dr.read().dr().bits(); + + self.wait_for_stop(); + self.i2c.cr1.modify(|_, w| w.ack().set_bit()); + } + } + + Ok(()) + } +} + +impl WriteRead for I2c +where + I2C: Instance, +{ + type Error = Error; + + fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { + if !bytes.is_empty() { + self.write_without_stop(addr, bytes)?; + } + + if !buffer.is_empty() { + self.read(addr, buffer)?; + } else if !bytes.is_empty() { + self.send_stop(); + self.wait_for_stop(); + } + + Ok(()) + } +} diff --git a/src/i2c/blocking.rs b/src/i2c/blocking.rs index 929e1945..750fa048 100644 --- a/src/i2c/blocking.rs +++ b/src/i2c/blocking.rs @@ -1,4 +1,6 @@ use super::*; +use nb::Error::{Other, WouldBlock}; +use nb::{Error as NbError, Result as NbResult}; /// embedded-hal compatible blocking I2C implementation /// @@ -6,7 +8,6 @@ use super::*; /// [DWT::enable_cycle_counter] method. pub struct BlockingI2c { nb: I2c, - start_retries: u8, timeouts: DwtTimeouts, } @@ -77,12 +78,14 @@ impl BlockingI2c { } } -impl I2c { +impl I2c +where + I2C: Instance, +{ /// Generates a blocking I2C instance from a universal I2C object pub fn blocking( self, start_timeout_us: u32, - start_retries: u8, addr_timeout_us: u32, data_timeout_us: u32, clocks: Clocks, @@ -90,7 +93,6 @@ impl I2c { let sysclk_mhz = clocks.sysclk().0 / 1_000_000; BlockingI2c { nb: self, - start_retries, timeouts: DwtTimeouts { start: start_timeout_us * sysclk_mhz, addr: addr_timeout_us * sysclk_mhz, @@ -102,7 +104,6 @@ impl I2c { let sysclk_mhz = clocks.sysclk().0 / 1_000_000; BlockingI2c { nb: self, - start_retries: 10, timeouts: DwtTimeouts { start: 1000 * sysclk_mhz, addr: 1000 * sysclk_mhz, @@ -116,17 +117,25 @@ macro_rules! wait_for_flag { ($i2c:expr, $flag:ident) => {{ let sr1 = $i2c.sr1.read(); + // Writing 1s in order to only clear the flag we spotted even + // if the register gets modified externally + // NOTE(unsafe): Writing 1 to registers which are cleared by 0 has no effect. + // Similarly, writing to read-only registers has no effect if sr1.berr().bit_is_set() { - $i2c.sr1.write(|w| w.berr().clear_bit()); + $i2c.sr1 + .write(|w| unsafe { w.bits(0xffff).berr().clear_bit() }); Err(Other(Error::Bus)) } else if sr1.arlo().bit_is_set() { - $i2c.sr1.write(|w| w.arlo().clear_bit()); + $i2c.sr1 + .write(|w| unsafe { w.bits(0xffff).arlo().clear_bit() }); Err(Other(Error::Arbitration)) } else if sr1.af().bit_is_set() { - $i2c.sr1.write(|w| w.af().clear_bit()); + $i2c.sr1 + .write(|w| unsafe { w.bits(0xffff).af().clear_bit() }); Err(Other(Error::Acknowledge)) } else if sr1.ovr().bit_is_set() { - $i2c.sr1.write(|w| w.ovr().clear_bit()); + $i2c.sr1 + .write(|w| unsafe { w.bits(0xffff).ovr().clear_bit() }); Err(Other(Error::Overrun)) } else if sr1.$flag().bit_is_set() { Ok(()) @@ -176,13 +185,9 @@ where addr_timeout_us: u32, data_timeout_us: u32, ) -> Self { - I2c::::_i2c(i2c, pins, mode, clocks).blocking( - start_timeout_us, - start_retries, - addr_timeout_us, - data_timeout_us, - clocks, - ) + I2c::::_i2c(i2c, pins, mode, clocks) + .retries(start_retries) + .blocking(start_timeout_us, addr_timeout_us, data_timeout_us, clocks) } } @@ -211,7 +216,7 @@ where fn send_start_and_wait(&mut self) -> NbResult<(), Error> { // According to http://www.st.com/content/ccc/resource/technical/document/errata_sheet/f5/50/c9/46/56/db/4a/f6/CD00197763.pdf/files/CD00197763.pdf/jcr:content/translations/en.CD00197763.pdf // 2.14.4 Wrong behavior of I2C peripheral in master mode after a misplaced STOP - let mut retries_left = self.start_retries; + let mut retries_left = self.nb.start_retries; let mut last_ret: NbResult<(), Error> = Err(WouldBlock); while retries_left > 0 { self.nb.send_start(); @@ -237,8 +242,7 @@ where } fn write_bytes_and_wait(&mut self, bytes: &[u8]) -> NbResult<(), Error> { - self.nb.i2c.sr1.read(); - self.nb.i2c.sr2.read(); + self.nb.clear_addr_flag(); self.nb.i2c.dr.write(|w| w.dr().bits(bytes[0])); @@ -288,32 +292,30 @@ where self.send_start_and_wait()?; self.send_addr_and_wait(addr, true)?; - match buffer.len() { - 1 => { + match buffer { + [b0] => { self.nb.i2c.cr1.modify(|_, w| w.ack().clear_bit()); - self.nb.i2c.sr1.read(); - self.nb.i2c.sr2.read(); + self.nb.clear_addr_flag(); self.nb.send_stop(); busy_wait_cycles!(wait_for_flag!(self.nb.i2c, rx_ne), self.timeouts.data)?; - buffer[0] = self.nb.i2c.dr.read().dr().bits(); + *b0 = self.nb.i2c.dr.read().dr().bits(); busy_wait_cycles!(self.wait_for_stop(), self.timeouts.data)?; self.nb.i2c.cr1.modify(|_, w| w.ack().set_bit()); } - 2 => { + [b0, b1] => { self.nb .i2c .cr1 .modify(|_, w| w.pos().set_bit().ack().set_bit()); - self.nb.i2c.sr1.read(); - self.nb.i2c.sr2.read(); + self.nb.clear_addr_flag(); self.nb.i2c.cr1.modify(|_, w| w.ack().clear_bit()); busy_wait_cycles!(wait_for_flag!(self.nb.i2c, btf), self.timeouts.data)?; self.nb.send_stop(); - buffer[0] = self.nb.i2c.dr.read().dr().bits(); - buffer[1] = self.nb.i2c.dr.read().dr().bits(); + *b0 = self.nb.i2c.dr.read().dr().bits(); + *b1 = self.nb.i2c.dr.read().dr().bits(); busy_wait_cycles!(self.wait_for_stop(), self.timeouts.data)?; self.nb @@ -322,12 +324,11 @@ where .modify(|_, w| w.pos().clear_bit().ack().clear_bit()); self.nb.i2c.cr1.modify(|_, w| w.ack().set_bit()); } - buffer_len => { + _ => { self.nb.i2c.cr1.modify(|_, w| w.ack().set_bit()); - self.nb.i2c.sr1.read(); - self.nb.i2c.sr2.read(); + self.nb.clear_addr_flag(); - let (first_bytes, last_two_bytes) = buffer.split_at_mut(buffer_len - 3); + let (first_bytes, last_3_bytes) = buffer.split_at_mut(buffer.len() - 3); for byte in first_bytes { busy_wait_cycles!(wait_for_flag!(self.nb.i2c, rx_ne), self.timeouts.data)?; *byte = self.nb.i2c.dr.read().dr().bits(); @@ -335,11 +336,11 @@ where busy_wait_cycles!(wait_for_flag!(self.nb.i2c, btf), self.timeouts.data)?; self.nb.i2c.cr1.modify(|_, w| w.ack().clear_bit()); - last_two_bytes[0] = self.nb.i2c.dr.read().dr().bits(); + last_3_bytes[0] = self.nb.i2c.dr.read().dr().bits(); self.nb.send_stop(); - last_two_bytes[1] = self.nb.i2c.dr.read().dr().bits(); + last_3_bytes[1] = self.nb.i2c.dr.read().dr().bits(); busy_wait_cycles!(wait_for_flag!(self.nb.i2c, rx_ne), self.timeouts.data)?; - last_two_bytes[2] = self.nb.i2c.dr.read().dr().bits(); + last_3_bytes[2] = self.nb.i2c.dr.read().dr().bits(); busy_wait_cycles!(self.wait_for_stop(), self.timeouts.data)?; self.nb.i2c.cr1.modify(|_, w| w.ack().set_bit());