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 busy available and then wait for the controller to be ready
at intermediate step.
Modify the i2c_busy_wait to implement this behavior.

fix rust-embedded-community#34
  • Loading branch information
dkm committed Jul 21, 2020
1 parent 71b2988 commit 68a3714
Showing 1 changed file with 49 additions and 40 deletions.
89 changes: 49 additions & 40 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 @@ -60,26 +62,45 @@ macro_rules! i2c_busy_wait {
.write(|w| unsafe { w.cntl().bits((1_000 >> 4) as u8) });

let mcs = loop {
let mcs = $i2c.mcs.read();
let mcs = $i2c.mcs.read();

if mcs.busy().bit_is_clear() {
break mcs;
}
};

if mcs.busy().bit_is_clear() {
break mcs;
}
};

if mcs.clkto().bit_is_set() {
Err(Error::Timeout)
} else if mcs.busbsy().bit_is_set() {
Err(Error::BusBusy)
} 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::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);
}
}

$( 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 @@ -240,7 +249,9 @@ macro_rules! i2c_hal {
.stop().set_bit()
});


i2c_busy_wait!(self.i2c)?;

buffer[recv_sz-1] = self.i2c.mdr.read().data().bits();
}

Expand Down Expand Up @@ -278,13 +289,7 @@ 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()
Expand Down Expand Up @@ -322,6 +327,7 @@ macro_rules! i2c_hal {
});

i2c_busy_wait!(self.i2c)?;

buffer[0] = self.i2c.mdr.read().data().bits();
} else {
// emit Repeated START
Expand All @@ -332,6 +338,7 @@ macro_rules! i2c_hal {
});

i2c_busy_wait!(self.i2c)?;

buffer[0] = self.i2c.mdr.read().data().bits();

for byte in &mut buffer[1..recv_sz-1] {
Expand All @@ -340,6 +347,7 @@ macro_rules! i2c_hal {
.ack().set_bit()
});
i2c_busy_wait!(self.i2c)?;

*byte = self.i2c.mdr.read().data().bits();
}

Expand All @@ -349,6 +357,7 @@ macro_rules! i2c_hal {
});

i2c_busy_wait!(self.i2c)?;

buffer[recv_sz-1] = self.i2c.mdr.read().data().bits();
}

Expand Down

0 comments on commit 68a3714

Please sign in to comment.