From be68d8ebb773fcf6d0cb94f3bc580d6661f6779b Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 26 Aug 2022 14:24:49 +0200 Subject: [PATCH] Add further i2c error types --- embassy-rp/src/clocks.rs | 2 +- embassy-rp/src/i2c.rs | 69 +++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 875c129c..1c446f38 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -114,7 +114,7 @@ pub unsafe fn init() { reset::unreset_wait(peris); } -pub(crate) fn clk_sys_freq() -> u32 { +pub(crate) fn _clk_sys_freq() -> u32 { 125_000_000 } diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index b368c49c..20616cd6 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -5,12 +5,25 @@ use pac::i2c; 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 #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { /// I2C abort with error - Abort(u32), + Abort(AbortReason), /// User passed in a read buffer that was 0 length InvalidReadBufferLength, /// User passed in a write buffer that was 0 length @@ -29,9 +42,7 @@ pub struct Config { impl Default for Config { fn default() -> Self { - Self { - frequency: 100_000, - } + Self { frequency: 100_000 } } } @@ -164,18 +175,30 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { Ok(()) } - fn read_and_clear_abort_reason(&mut self) -> Option { + fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { let p = T::regs(); unsafe { - let abort_reason = p.ic_tx_abrt_source().read().0; - if abort_reason != 0 { + let abort_reason = p.ic_tx_abrt_source().read(); + if abort_reason.0 != 0 { // Note clearing the abort flag also clears the reason, and this // instance of flag is clear-on-read! Note also the // IC_CLR_TX_ABRT register always reads as 0. 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 { - None + Ok(()) } } } @@ -204,9 +227,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { }); while p.ic_rxflr().read().rxflr() == 0 { - if let Some(abort_reason) = self.read_and_clear_abort_reason() { - return Err(Error::Abort(abort_reason)); - } + self.read_and_clear_abort_reason()?; } *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(); - 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 // 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 // TX on abort, ecause we set hwparam // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. - if let Some(abort_reason) = abort_reason { - return Err(Error::Abort(abort_reason)); - } + abort_reason?; } } Ok(()) @@ -360,15 +379,15 @@ mod eh1 { impl embedded_hal_1::i2c::Error for Error { fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { match *self { - _ => embedded_hal_1::i2c::ErrorKind::Bus, - // Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, - // Self::Nack => { - // embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown) - // } - // Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, - // Self::Crc => embedded_hal_1::i2c::ErrorKind::Other, - // Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, - // Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other, + Self::Abort(AbortReason::ArbitrationLoss) => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, + Self::Abort(AbortReason::NoAcknowledge) => { + embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) + } + Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, + Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, + Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, + Self::AddressOutOfRange(_) => embedded_hal_1::i2c::ErrorKind::Other, + Self::AddressReserved(_) => embedded_hal_1::i2c::ErrorKind::Other, } } }