Skip to content

Commit 6807aaf

Browse files
DmitriyNERahix
authored andcommitted
avr-hal-generic: Fix spurious NACK in I2c::transaction
When doing I2c transaction with several subsequent reads, non-final ones should be always ACKed. Previous implementation inserted NACK at the end of every Read operation.
1 parent e330e2a commit 6807aaf

File tree

1 file changed

+16
-7
lines changed

1 file changed

+16
-7
lines changed

avr-hal-generic/src/i2c.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,11 @@ pub trait I2cOps<H, SDA, SCL> {
181181
/// Read some bytes from the bus.
182182
///
183183
/// This method must only be called after a transaction in read mode was successfully started.
184+
/// If `last_read` is set then last byte will be nacked. Should be set to false if there will
185+
/// be a subsequent read without a start (e.g. when using `transaction`).
184186
///
185187
/// **Warning**: This is a low-level method and should not be called directly from user code.
186-
fn raw_read(&mut self, buffer: &mut [u8]) -> Result<(), Error>;
188+
fn raw_read(&mut self, buffer: &mut [u8], last_read: bool) -> Result<(), Error>;
187189

188190
/// Send a stop-condition and release the bus.
189191
///
@@ -386,7 +388,7 @@ impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> embedded_hal_v0::blocking::i2
386388

387389
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
388390
self.p.raw_start(address, Direction::Read)?;
389-
self.p.raw_read(buffer)?;
391+
self.p.raw_read(buffer, true)?;
390392
self.p.raw_stop()?;
391393
Ok(())
392394
}
@@ -406,7 +408,7 @@ impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> embedded_hal_v0::blocking::i2
406408
self.p.raw_start(address, Direction::Write)?;
407409
self.p.raw_write(bytes)?;
408410
self.p.raw_start(address, Direction::Read)?;
409-
self.p.raw_read(buffer)?;
411+
self.p.raw_read(buffer, true)?;
410412
self.p.raw_stop()?;
411413
Ok(())
412414
}
@@ -421,13 +423,20 @@ impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> embedded_hal::i2c::I2c<SevenB
421423
operations: &mut [embedded_hal::i2c::Operation<'_>],
422424
) -> Result<(), Self::Error> {
423425
let mut previous_direction = Direction::Read;
424-
for (idx, operation) in operations.iter_mut().enumerate() {
426+
let mut ops_iter = operations.iter_mut().enumerate().peekable();
427+
while let Some((idx, operation)) = ops_iter.next() {
425428
match operation {
426429
embedded_hal::i2c::Operation::Read(buffer) => {
427430
if idx == 0 || previous_direction != Direction::Read {
428431
self.p.raw_start(address, Direction::Read)?;
429432
}
430-
self.p.raw_read(buffer)?;
433+
434+
let next_op_is_read = matches!(
435+
ops_iter.peek(),
436+
Some((_, embedded_hal::i2c::Operation::Read(_)))
437+
);
438+
439+
self.p.raw_read(buffer, !next_op_is_read)?;
431440
previous_direction = Direction::Read;
432441
}
433442
embedded_hal::i2c::Operation::Write(bytes) => {
@@ -561,10 +570,10 @@ macro_rules! impl_i2c_twi {
561570
}
562571

563572
#[inline]
564-
fn raw_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
573+
fn raw_read(&mut self, buffer: &mut [u8], last_read: bool) -> Result<(), Error> {
565574
let last = buffer.len() - 1;
566575
for (i, byte) in buffer.iter_mut().enumerate() {
567-
if i != last {
576+
if i != last || !last_read {
568577
self.twcr
569578
.write(|w| w.twint().set_bit().twen().set_bit().twea().set_bit());
570579
// wait()

0 commit comments

Comments
 (0)