From d7c817f6a25af2e41cfe48e2ec6e18a845225922 Mon Sep 17 00:00:00 2001 From: TheZoq2 Date: Wed, 23 Dec 2020 17:53:11 +0100 Subject: [PATCH 1/2] Use modify instead of write for clearing sr1 --- CHANGELOG.md | 1 + src/i2c.rs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c986fe0..522282f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fix > 2 byte i2c reads - Send stop after acknowledge errors on i2c - Fix i2c interactions after errors +- Only clear individual i2c status registers on error ### Changed - Use `cortex-m-rtic` instead of `cortex-m-rtfm` in the examples diff --git a/src/i2c.rs b/src/i2c.rs index ca835710..1420e6c2 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -220,16 +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()); + $i2c.sr1.modify(|_r, w| w.berr().clear_bit()); Err(Other(Error::Bus)) } else if sr1.arlo().bit_is_set() { - $i2c.sr1.write(|w| w.arlo().clear_bit()); + $i2c.sr1.modify(|_r, w| w.arlo().clear_bit()); Err(Other(Error::Arbitration)) } else if sr1.af().bit_is_set() { - $i2c.sr1.write(|w| w.af().clear_bit()); + $i2c.sr1.modify(|_r, w| w.af().clear_bit()); Err(Other(Error::Acknowledge)) } else if sr1.ovr().bit_is_set() { - $i2c.sr1.write(|w| w.ovr().clear_bit()); + $i2c.sr1.modify(|_r, w| w.ovr().clear_bit()); Err(Other(Error::Overrun)) } else if sr1.$flag().bit_is_set() { Ok(()) From d805d28601c73a4d34726bfb071bfc4ca38e204e Mon Sep 17 00:00:00 2001 From: TheZoq2 Date: Sat, 23 Jan 2021 10:27:20 +0100 Subject: [PATCH 2/2] Clear start bits before send --- src/i2c.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 1420e6c2..4ef3ddd0 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -219,17 +219,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.modify(|_r, 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.modify(|_r, 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.modify(|_r, 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.modify(|_r, 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(()) @@ -347,6 +355,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.write(|w| unsafe { w.bits(0) }); self.i2c.cr1.modify(|_, w| w.start().set_bit()); }