Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix i2c busy / bus busy handling #35

Merged
merged 1 commit into from
Aug 10, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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