Skip to content

Commit

Permalink
Fix i2c busy / bus busy handling
Browse files Browse the repository at this point in the history
Restore previous logic where a transaction starts by waiting for the controler
to be ready and the bus available and then only wait for the controller to be ready
at intermediate step (not the bus to be available as it will be busy).
Modify the i2c_busy_wait to implement this behavior.

fix #34
  • Loading branch information
dkm committed Jul 27, 2020
1 parent be36ae7 commit a655564
Showing 1 changed file with 36 additions and 35 deletions.
71 changes: 36 additions & 35 deletions tm4c-hal/src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ macro_rules! i2c_pins {
}

#[macro_export]
/// Spins on a given field on a TM4C I2C peripheral
/// Spins until the controler is ready (mcs.busy is clear) and optionally on
/// another field of the mcs register until it is clear or set (depending on op
/// parameter).
macro_rules! i2c_busy_wait {
($i2c:expr) => {{
($i2c:expr $(, $field:ident, $op:ident)? ) => {{
// in 'release' builds, the time between setting the `run` bit and checking the `busy`
// bit is too short and the `busy` bit is not reliably set by the time you get there,
// it can take up to 8 clock cycles for the `run` to begin so this delay allows time
Expand All @@ -67,19 +69,38 @@ macro_rules! i2c_busy_wait {
}
};


if mcs.clkto().bit_is_set() {
Err(Error::Timeout)
} else if mcs.busbsy().bit_is_set() {
Err(Error::BusBusy)
return Err(Error::Timeout)
} else if mcs.arblst().bit_is_set() {
Err(Error::Arbitration)
} else if mcs.datack().bit_is_set() {
Err(Error::DataAck)
} else if mcs.adrack().bit_is_set() {
Err(Error::AdrAck)
} else {
Ok(())
return Err(Error::Arbitration)
} else if mcs.error().bit_is_set() {
if mcs.adrack().bit_is_set() {
return Err(Error::AdrAck);
} else { // if mcs.datack().bit_is_set() {
return Err(Error::DataAck);
}
}

$( loop {
if mcs.clkto().bit_is_set() {
return Err(Error::Timeout)
} else if mcs.arblst().bit_is_set() {
return Err(Error::Arbitration)
} else if mcs.error().bit_is_set() {
if mcs.adrack().bit_is_set() {
return Err(Error::AdrAck);
} else { // if mcs.datack().bit_is_set() {
return Err(Error::DataAck);
}
} else if mcs.$field().$op() {
break;
} else {
// try again
}
};)?

Ok(())
}};
}

Expand Down Expand Up @@ -140,13 +161,7 @@ macro_rules! i2c_hal {

let sz = bytes.len();

loop {
match i2c_busy_wait!(self.i2c) {
Ok(()) => break,
Err(Error::BusBusy) => continue,
e @ Err(_) => return e,
}
}
i2c_busy_wait!(self.i2c, busbsy, bit_is_clear)?;

// Send START + RUN
// If single byte transfer, set STOP
Expand Down Expand Up @@ -197,13 +212,7 @@ macro_rules! i2c_hal {
.rs().set_bit()
});

loop {
match i2c_busy_wait!(self.i2c) {
Ok(()) => break,
Err(Error::BusBusy) => continue,
e @ Err(_) => return e,
}
}
i2c_busy_wait!(self.i2c, busbsy, bit_is_clear)?;

let recv_sz = buffer.len();

Expand Down Expand Up @@ -278,21 +287,13 @@ macro_rules! i2c_hal {
w.data().bits(bytes[0])
});

loop {
match i2c_busy_wait!(self.i2c) {
Ok(()) => break,
Err(Error::BusBusy) => continue,
e @ Err(_) => return e,
}
}

i2c_busy_wait!(self.i2c, busbsy, bit_is_clear)?;
self.i2c.mcs.write(|w| {
w.start().set_bit()
.run().set_bit()
});

i2c_busy_wait!(self.i2c)?;

for byte in (&bytes[1..write_len]).iter() {
self.i2c.mdr.write(|w| unsafe {
w.data().bits(*byte)
Expand Down

0 comments on commit a655564

Please sign in to comment.