From a6555649c246da9a0b82fed167d6e4bd9a698d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Poulhi=C3=A8s?= Date: Tue, 21 Jul 2020 07:18:44 +0200 Subject: [PATCH] Fix i2c busy / bus busy handling 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 --- tm4c-hal/src/i2c.rs | 71 +++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/tm4c-hal/src/i2c.rs b/tm4c-hal/src/i2c.rs index 71cd33b..3faa7a4 100644 --- a/tm4c-hal/src/i2c.rs +++ b/tm4c-hal/src/i2c.rs @@ -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 @@ -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(()) }}; } @@ -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 @@ -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(); @@ -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)