Skip to content

Commit 8bc3297

Browse files
authored
Fix i2c data lost on start repeat condition (#137)
1 parent d4ad343 commit 8bc3297

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

src/i2c/mod.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,23 @@ pub enum SlaveAddressMask {
2424
MaskAllBits,
2525
}
2626

27+
/// Denotes which event marked the end of the I2C data
2728
#[derive(Debug, Clone, Copy)]
28-
pub enum I2cResult<'a> {
29-
Data(u16, I2cDirection, &'a [u8]), // contains address, direction and data slice reference
30-
Addressed(u16, I2cDirection), // a slave is addressed by a master
29+
pub enum EndMarker {
30+
/// A stop condition was encountered
31+
Stop,
32+
/// A start repeat condition was encountered
33+
StartRepeat,
3134
}
3235

3336
#[derive(Debug, Clone, Copy)]
37+
pub enum I2cResult<'a> {
38+
/// Contains address, direction, data slice reference, and the packet delimeter
39+
Data(u16, I2cDirection, &'a [u8], EndMarker),
40+
Addressed(u16, I2cDirection), // a slave is addressed by a master
41+
}
42+
43+
#[derive(Debug, Clone, Copy, PartialEq)]
3444
pub enum I2cDirection {
3545
MasterReadSlaveWrite = 0,
3646
MasterWriteSlaveRead = 1,
@@ -99,4 +109,5 @@ pub struct I2c<I2C, SDA, SCL> {
99109
length_write_read: usize, // for a master write_read operation this remembers the size of the read operation
100110
// for a slave device this must be 0
101111
data: [u8; 255], // during transfer the driver will be the owner of the buffer
112+
current_direction: I2cDirection,
102113
}

src/i2c/nonblocking.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use crate::gpio::*;
33
use crate::gpio::{AltFunction, OpenDrain, Output};
44
use crate::i2c::config::Config;
5-
use crate::i2c::{Error, I2c, I2cDirection, I2cExt, I2cResult, SCLPin, SDAPin};
5+
use crate::i2c::{EndMarker, Error, I2c, I2cDirection, I2cExt, I2cResult, SCLPin, SDAPin};
66
use crate::rcc::*;
77
use crate::stm32::{I2C1, I2C2};
88
use nb::Error::{Other, WouldBlock};
@@ -215,7 +215,8 @@ macro_rules! i2c {
215215
length:0,
216216
errors:0,
217217
length_write_read:0,
218-
data:[0_u8;255]
218+
data:[0_u8;255],
219+
current_direction: I2cDirection::MasterReadSlaveWrite,
219220
}
220221
}
221222
pub fn release(self) -> ($I2CX, SDA, SCL) {
@@ -306,7 +307,7 @@ macro_rules! i2c {
306307
}
307308
return Err( WouldBlock)
308309
} else
309-
if isr.rxne().bit_is_set() {
310+
if isr.rxne().bit_is_set() {
310311
// read byte from the wire
311312
if self.index < self.length {
312313
self.data[self.index] = self.i2c.rxdr.read().rxdata().bits();
@@ -317,7 +318,8 @@ macro_rules! i2c {
317318
}
318319
return Err( WouldBlock)
319320
} else
320-
if isr.stopf().bit_is_set() {
321+
if isr.stopf().bit_is_set() {
322+
321323
// Clear the stop condition flag
322324
self.i2c.icr.write(|w| w.stopcf().set_bit());
323325
// Disable the watchdog
@@ -334,9 +336,13 @@ macro_rules! i2c {
334336
} else {
335337
I2cDirection::MasterWriteSlaveRead
336338
};
339+
let index = self.index;
340+
// Clear the length so we don't think there is still data when we reach the address phase
341+
self.length = self.data.len();
342+
self.index = 0;
337343
// return the actual amount of data (self.index), not the requested (self.length)
338344
// application must evaluate the size of the frame
339-
return Ok( I2cResult::Data(self.address, direction, &self.data[0..self.index]) )
345+
return Ok( I2cResult::Data(self.address, direction, &self.data[0..index], EndMarker::Stop) )
340346
}
341347
}else
342348
if isr.tc().bit_is_set() {
@@ -393,7 +399,14 @@ macro_rules! i2c {
393399

394400
} else
395401
if isr.addr().bit_is_set() {
396-
// handle the slave device case, addressed by a master
402+
// Handle the case where there was no stop bit (repeated start)
403+
// In this case there will be data on the buffer which still needs to be delivered
404+
if self.current_direction == I2cDirection::MasterWriteSlaveRead && self.index >= 1 {
405+
let index = self.index;
406+
self.index = 0;
407+
return Ok( I2cResult::Data(self.address, self.current_direction, &self.data[0..index], EndMarker::StartRepeat) )
408+
}
409+
// handle the slave device case, addressed by a master
397410
let current_address = isr.addcode().bits() as u16;
398411
self.address = current_address;
399412
// guard against misbehavior
@@ -419,7 +432,7 @@ macro_rules! i2c {
419432
// return result
420433
I2cDirection::MasterWriteSlaveRead
421434
};
422-
435+
self.current_direction = direction;
423436
// do not yet release the clock stretching here
424437
return Ok(I2cResult::Addressed(current_address, direction))
425438
}

0 commit comments

Comments
 (0)