Skip to content

Commit

Permalink
include #298
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Jul 30, 2021
1 parent ee8bf81 commit e923dbc
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 43 deletions.
79 changes: 48 additions & 31 deletions src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,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());
}

Expand All @@ -262,6 +265,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)
Expand All @@ -279,21 +288,34 @@ where
{
fn check_and_clear_error_flags(&self) -> Result<pac::i2c1::sr1::R, Error> {
let sr1 = self.i2c.sr1.read();
if sr1.berr().bit_is_set() {
self.i2c.sr1.write(|w| w.berr().clear_bit());
Err(Error::Bus)
} else if sr1.arlo().bit_is_set() {
self.i2c.sr1.write(|w| w.arlo().clear_bit());
Err(Error::Arbitration)
} else if sr1.af().bit_is_set() {
self.i2c.sr1.write(|w| w.af().clear_bit());
Err(Error::Acknowledge)
} else if sr1.ovr().bit_is_set() {
self.i2c.sr1.write(|w| w.ovr().clear_bit());
Err(Error::Overrun)
} else {
Ok(sr1)
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
Expand Down Expand Up @@ -339,19 +361,17 @@ where
break Ok(());
}
}
Err(e) => {
if let Error::Acknowledge = e {
self.send_stop();
}
break Err(e);
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.i2c.sr1.read();
self.i2c.sr2.read();
self.clear_addr_flag();

self.i2c.dr.write(|w| w.dr().bits(bytes[0]));

Expand Down Expand Up @@ -404,8 +424,7 @@ where
match buffer.len() {
1 => {
self.i2c.cr1.modify(|_, w| w.ack().clear_bit());
self.i2c.sr1.read();
self.i2c.sr2.read();
self.clear_addr_flag();
self.send_stop();

while self.check_and_clear_error_flags()?.rx_ne().bit_is_clear() {}
Expand All @@ -418,8 +437,7 @@ where
self.i2c
.cr1
.modify(|_, w| w.pos().set_bit().ack().set_bit());
self.i2c.sr1.read();
self.i2c.sr2.read();
self.clear_addr_flag();
self.i2c.cr1.modify(|_, w| w.ack().clear_bit());

while self.check_and_clear_error_flags()?.btf().bit_is_clear() {}
Expand All @@ -435,22 +453,21 @@ where
}
buffer_len => {
self.i2c.cr1.modify(|_, w| w.ack().set_bit());
self.i2c.sr1.read();
self.i2c.sr2.read();
self.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 {
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_two_bytes[0] = self.i2c.dr.read().dr().bits();
last_3_bytes[0] = self.i2c.dr.read().dr().bits();
self.send_stop();
last_two_bytes[1] = self.i2c.dr.read().dr().bits();
last_3_bytes[1] = self.i2c.dr.read().dr().bits();
while self.check_and_clear_error_flags()?.rx_ne().bit_is_clear() {}
last_two_bytes[2] = self.i2c.dr.read().dr().bits();
last_3_bytes[2] = self.i2c.dr.read().dr().bits();

self.wait_for_stop();
self.i2c.cr1.modify(|_, w| w.ack().set_bit());
Expand Down
28 changes: 16 additions & 12 deletions src/i2c/blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,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(())
Expand Down Expand Up @@ -237,8 +245,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]));

Expand Down Expand Up @@ -291,8 +298,7 @@ where
match buffer.len() {
1 => {
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)?;
Expand All @@ -306,8 +312,7 @@ where
.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)?;
Expand All @@ -324,8 +329,7 @@ where
}
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);
for byte in first_bytes {
Expand Down

0 comments on commit e923dbc

Please sign in to comment.