Add further i2c error types
This commit is contained in:
parent
603513e76e
commit
be68d8ebb7
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user