Procházet zdrojové kódy

Various i2c fixes (#282)

* i2c: Clear error flags

clear the error flags after detecting them as the hardware does not
autoclear on read.

Signed-off-by: Sjoerd Simons <sjoerd@luon.net>

* i2c: Send stop after acknowledge error

If the remote device fails to acknowledge send a stop. This allows the
bus to go back to idle again.

Signed-off-by: Sjoerd Simons <sjoerd@luon.net>

* i2c: Set ack bit on multibyte reads

Enable the ack bit on multibyte (>2) reads otherwise bytes from the
remote device are not acknowledged.

Signed-off-by: Sjoerd Simons <sjoerd@luon.net>

* Update changelog

Co-authored-by: Frans Skarman <frans.skarman@protonmail.com>
Sjoerd Simons před 3 roky
rodič
revize
a100426a27
2 změnil soubory, kde provedl 31 přidání a 7 odebrání
  1. 5 0
      CHANGELOG.md
  2. 26 7
      src/i2c.rs

+ 5 - 0
CHANGELOG.md

@@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 - LSB/MSB bit format selection for `SPI`
 
+### Fixed
+- Fix > 2 byte i2c reads
+- Send stop after acknowledge errors on i2c
+- Fix i2c interactions after errors
+
 ## [v0.7.0]- 2020-10-17
 
 ### Breaking changes

+ 26 - 7
src/i2c.rs

@@ -220,12 +220,16 @@ macro_rules! wait_for_flag {
         let sr1 = $i2c.sr1.read();
 
         if sr1.berr().bit_is_set() {
+            $i2c.sr1.write(|w| w.berr().clear_bit());
             Err(Other(Error::Bus))
         } else if sr1.arlo().bit_is_set() {
+            $i2c.sr1.write(|w| w.arlo().clear_bit());
             Err(Other(Error::Arbitration))
         } else if sr1.af().bit_is_set() {
+            $i2c.sr1.write(|w| w.af().clear_bit());
             Err(Other(Error::Acknowledge))
         } else if sr1.ovr().bit_is_set() {
+            $i2c.sr1.write(|w| w.ovr().clear_bit());
             Err(Other(Error::Overrun))
         } else if sr1.$flag().bit_is_set() {
             Ok(())
@@ -432,12 +436,17 @@ where
         last_ret
     }
 
-    fn write_without_stop(&mut self, addr: u8, bytes: &[u8]) -> NbResult<(), Error> {
-        self.send_start_and_wait()?;
+    fn send_addr_and_wait(&mut self, addr: u8, read: bool) -> NbResult<(), Error> {
         self.nb.i2c.sr1.read();
-        self.nb.send_addr(addr, false);
+        self.nb.send_addr(addr, read);
+        let ret = busy_wait_cycles!(wait_for_flag!(self.nb.i2c, addr), self.addr_timeout);
+        if ret == Err(Other(Error::Acknowledge)) {
+            self.nb.send_stop();
+        }
+        ret
+    }
 
-        busy_wait_cycles!(wait_for_flag!(self.nb.i2c, addr), self.addr_timeout)?;
+    fn write_bytes_and_wait(&mut self, bytes: &[u8]) -> NbResult<(), Error> {
         self.nb.i2c.sr1.read();
         self.nb.i2c.sr2.read();
 
@@ -451,6 +460,17 @@ where
 
         Ok(())
     }
+
+    fn write_without_stop(&mut self, addr: u8, bytes: &[u8]) -> NbResult<(), Error> {
+        self.send_start_and_wait()?;
+        self.send_addr_and_wait(addr, false)?;
+
+        let ret = self.write_bytes_and_wait(bytes);
+        if ret == Err(Other(Error::Acknowledge)) {
+            self.nb.send_stop();
+        }
+        ret
+    }
 }
 
 impl<I2C, PINS> Write for BlockingI2c<I2C, PINS>
@@ -476,9 +496,7 @@ where
 
     fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
         self.send_start_and_wait()?;
-        self.nb.i2c.sr1.read();
-        self.nb.send_addr(addr, true);
-        busy_wait_cycles!(wait_for_flag!(self.nb.i2c, addr), self.addr_timeout)?;
+        self.send_addr_and_wait(addr, true)?;
 
         match buffer.len() {
             1 => {
@@ -515,6 +533,7 @@ where
                 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();