Skip to content

Commit

Permalink
i2c: properly handle bus errors
Browse files Browse the repository at this point in the history
In send_byte() wait for TX fifo empty before returning Ok. It would be
better to wait for end of transmission, but there is no such field in
I2C status register.

In recv_byte() return Err if error condition detected while waiting for
byte.

Before starting new transaction ensure that both TX and RX buffers are
empty. There are some corner cases where something may be there.
  • Loading branch information
hlukasz committed May 3, 2020
1 parent b8147f1 commit 657a1cc
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ where
}

fn start_transfer(&mut self, addr: u8, len: usize, direction: RD_WRN_A) {
// Ensure that TX/RX buffers are empty
self.i2c.isr.write(|w| w.txe().set_bit());
while self.i2c.isr.read().rxne().bit_is_set() {
self.i2c.rxdr.read();
};

self.i2c.cr2.write(|w|
w
// Start transfer
Expand Down Expand Up @@ -217,13 +223,26 @@ where
} else if isr.nackf().bit_is_set() {
self.i2c.icr.write(|w| w.nackcf().set_bit());
return Err(Error::Nack);
} else if isr.txe().bit_is_set() {
return Ok(());
}
return Ok(());
}
}

fn recv_byte(&self) -> Result<u8, Error> {
while self.i2c.isr.read().rxne().bit_is_clear() {}
while self.i2c.isr.read().rxne().bit_is_clear() {
let isr = self.i2c.isr.read();
if isr.berr().bit_is_set() {
self.i2c.icr.write(|w| w.berrcf().set_bit());
return Err(Error::BusError);
} else if isr.arlo().bit_is_set() {
self.i2c.icr.write(|w| w.arlocf().set_bit());
return Err(Error::ArbitrationLost);
} else if isr.nackf().bit_is_set() {
self.i2c.icr.write(|w| w.nackcf().set_bit());
return Err(Error::Nack);
}
}

let value = self.i2c.rxdr.read().rxdata().bits();
Ok(value)
Expand Down

0 comments on commit 657a1cc

Please sign in to comment.