Add further i2c error types

This commit is contained in:
Mathias 2022-08-26 14:24:49 +02:00 committed by Dario Nieuwenhuis
parent 603513e76e
commit be68d8ebb7
2 changed files with 45 additions and 26 deletions

View File

@ -114,7 +114,7 @@ pub unsafe fn init() {
reset::unreset_wait(peris); reset::unreset_wait(peris);
} }
pub(crate) fn clk_sys_freq() -> u32 { pub(crate) fn _clk_sys_freq() -> u32 {
125_000_000 125_000_000
} }

View File

@ -5,12 +5,25 @@ use pac::i2c;
use crate::{pac, peripherals, Peripheral}; use crate::{pac, peripherals, Peripheral};
/// I2C error abort reason
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AbortReason {
/// A bus operation was not acknowledged, e.g. due to the addressed device
/// not being available on the bus or the device not being ready to process
/// requests at the moment
NoAcknowledge,
/// The arbitration was lost, e.g. electrical problems with the clock signal
ArbitrationLoss,
Other(u32),
}
/// I2C error /// I2C error
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
/// I2C abort with error /// I2C abort with error
Abort(u32), Abort(AbortReason),
/// User passed in a read buffer that was 0 length /// User passed in a read buffer that was 0 length
InvalidReadBufferLength, InvalidReadBufferLength,
/// User passed in a write buffer that was 0 length /// User passed in a write buffer that was 0 length
@ -29,9 +42,7 @@ pub struct Config {
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self { frequency: 100_000 }
frequency: 100_000,
}
} }
} }
@ -164,18 +175,30 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
Ok(()) Ok(())
} }
fn read_and_clear_abort_reason(&mut self) -> Option<u32> { fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
let p = T::regs(); let p = T::regs();
unsafe { unsafe {
let abort_reason = p.ic_tx_abrt_source().read().0; let abort_reason = p.ic_tx_abrt_source().read();
if abort_reason != 0 { if abort_reason.0 != 0 {
// Note clearing the abort flag also clears the reason, and this // Note clearing the abort flag also clears the reason, and this
// instance of flag is clear-on-read! Note also the // instance of flag is clear-on-read! Note also the
// IC_CLR_TX_ABRT register always reads as 0. // IC_CLR_TX_ABRT register always reads as 0.
p.ic_clr_tx_abrt().read(); p.ic_clr_tx_abrt().read();
Some(abort_reason)
let reason = if abort_reason.abrt_7b_addr_noack()
| abort_reason.abrt_10addr1_noack()
| abort_reason.abrt_10addr2_noack()
{
AbortReason::NoAcknowledge
} else if abort_reason.arb_lost() {
AbortReason::ArbitrationLoss
} else {
AbortReason::Other(abort_reason.0)
};
Err(Error::Abort(reason))
} else { } else {
None Ok(())
} }
} }
} }
@ -204,9 +227,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
}); });
while p.ic_rxflr().read().rxflr() == 0 { while p.ic_rxflr().read().rxflr() == 0 {
if let Some(abort_reason) = self.read_and_clear_abort_reason() { self.read_and_clear_abort_reason()?;
return Err(Error::Abort(abort_reason));
}
} }
*byte = p.ic_data_cmd().read().dat(); *byte = p.ic_data_cmd().read().dat();
@ -241,7 +262,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
let abort_reason = self.read_and_clear_abort_reason(); let abort_reason = self.read_and_clear_abort_reason();
if abort_reason.is_some() || (send_stop && last) { if abort_reason.is_err() || (send_stop && last) {
// If the transaction was aborted or if it completed // If the transaction was aborted or if it completed
// successfully wait until the STOP condition has occured. // successfully wait until the STOP condition has occured.
@ -254,9 +275,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
// condition. Note also the hardware clears RX FIFO as well as // condition. Note also the hardware clears RX FIFO as well as
// TX on abort, ecause we set hwparam // TX on abort, ecause we set hwparam
// IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
if let Some(abort_reason) = abort_reason { abort_reason?;
return Err(Error::Abort(abort_reason));
}
} }
} }
Ok(()) Ok(())
@ -360,15 +379,15 @@ mod eh1 {
impl embedded_hal_1::i2c::Error for Error { impl embedded_hal_1::i2c::Error for Error {
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
match *self { match *self {
_ => embedded_hal_1::i2c::ErrorKind::Bus, Self::Abort(AbortReason::ArbitrationLoss) => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
// Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, Self::Abort(AbortReason::NoAcknowledge) => {
// Self::Nack => { embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
// embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown) }
// } Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other,
// Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
// Self::Crc => embedded_hal_1::i2c::ErrorKind::Other, Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
// Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, Self::AddressOutOfRange(_) => embedded_hal_1::i2c::ErrorKind::Other,
// Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other, Self::AddressReserved(_) => embedded_hal_1::i2c::ErrorKind::Other,
} }
} }
} }