diff options
| author | Mathias <[email protected]> | 2022-08-26 14:24:49 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-09-27 22:08:49 +0200 |
| commit | be68d8ebb773fcf6d0cb94f3bc580d6661f6779b (patch) | |
| tree | 24e863b91aa615598979ded49655deb562b79bd8 | |
| parent | 603513e76e0cf727808033540598c6c7dd597133 (diff) | |
Add further i2c error types
| -rw-r--r-- | embassy-rp/src/clocks.rs | 2 | ||||
| -rw-r--r-- | 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 875c129c0..1c446f389 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs | |||
| @@ -114,7 +114,7 @@ pub unsafe fn init() { | |||
| 114 | reset::unreset_wait(peris); | 114 | reset::unreset_wait(peris); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | pub(crate) fn clk_sys_freq() -> u32 { | 117 | pub(crate) fn _clk_sys_freq() -> u32 { |
| 118 | 125_000_000 | 118 | 125_000_000 |
| 119 | } | 119 | } |
| 120 | 120 | ||
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index b368c49cf..20616cd62 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs | |||
| @@ -5,12 +5,25 @@ use pac::i2c; | |||
| 5 | 5 | ||
| 6 | use crate::{pac, peripherals, Peripheral}; | 6 | use crate::{pac, peripherals, Peripheral}; |
| 7 | 7 | ||
| 8 | /// I2C error abort reason | ||
| 9 | #[derive(Debug)] | ||
| 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 11 | pub enum AbortReason { | ||
| 12 | /// A bus operation was not acknowledged, e.g. due to the addressed device | ||
| 13 | /// not being available on the bus or the device not being ready to process | ||
| 14 | /// requests at the moment | ||
| 15 | NoAcknowledge, | ||
| 16 | /// The arbitration was lost, e.g. electrical problems with the clock signal | ||
| 17 | ArbitrationLoss, | ||
| 18 | Other(u32), | ||
| 19 | } | ||
| 20 | |||
| 8 | /// I2C error | 21 | /// I2C error |
| 9 | #[derive(Debug)] | 22 | #[derive(Debug)] |
| 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 23 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 11 | pub enum Error { | 24 | pub enum Error { |
| 12 | /// I2C abort with error | 25 | /// I2C abort with error |
| 13 | Abort(u32), | 26 | Abort(AbortReason), |
| 14 | /// User passed in a read buffer that was 0 length | 27 | /// User passed in a read buffer that was 0 length |
| 15 | InvalidReadBufferLength, | 28 | InvalidReadBufferLength, |
| 16 | /// User passed in a write buffer that was 0 length | 29 | /// User passed in a write buffer that was 0 length |
| @@ -29,9 +42,7 @@ pub struct Config { | |||
| 29 | 42 | ||
| 30 | impl Default for Config { | 43 | impl Default for Config { |
| 31 | fn default() -> Self { | 44 | fn default() -> Self { |
| 32 | Self { | 45 | Self { frequency: 100_000 } |
| 33 | frequency: 100_000, | ||
| 34 | } | ||
| 35 | } | 46 | } |
| 36 | } | 47 | } |
| 37 | 48 | ||
| @@ -164,18 +175,30 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 164 | Ok(()) | 175 | Ok(()) |
| 165 | } | 176 | } |
| 166 | 177 | ||
| 167 | fn read_and_clear_abort_reason(&mut self) -> Option<u32> { | 178 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { |
| 168 | let p = T::regs(); | 179 | let p = T::regs(); |
| 169 | unsafe { | 180 | unsafe { |
| 170 | let abort_reason = p.ic_tx_abrt_source().read().0; | 181 | let abort_reason = p.ic_tx_abrt_source().read(); |
| 171 | if abort_reason != 0 { | 182 | if abort_reason.0 != 0 { |
| 172 | // Note clearing the abort flag also clears the reason, and this | 183 | // Note clearing the abort flag also clears the reason, and this |
| 173 | // instance of flag is clear-on-read! Note also the | 184 | // instance of flag is clear-on-read! Note also the |
| 174 | // IC_CLR_TX_ABRT register always reads as 0. | 185 | // IC_CLR_TX_ABRT register always reads as 0. |
| 175 | p.ic_clr_tx_abrt().read(); | 186 | p.ic_clr_tx_abrt().read(); |
| 176 | Some(abort_reason) | 187 | |
| 188 | let reason = if abort_reason.abrt_7b_addr_noack() | ||
| 189 | | abort_reason.abrt_10addr1_noack() | ||
| 190 | | abort_reason.abrt_10addr2_noack() | ||
| 191 | { | ||
| 192 | AbortReason::NoAcknowledge | ||
| 193 | } else if abort_reason.arb_lost() { | ||
| 194 | AbortReason::ArbitrationLoss | ||
| 195 | } else { | ||
| 196 | AbortReason::Other(abort_reason.0) | ||
| 197 | }; | ||
| 198 | |||
| 199 | Err(Error::Abort(reason)) | ||
| 177 | } else { | 200 | } else { |
| 178 | None | 201 | Ok(()) |
| 179 | } | 202 | } |
| 180 | } | 203 | } |
| 181 | } | 204 | } |
| @@ -204,9 +227,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 204 | }); | 227 | }); |
| 205 | 228 | ||
| 206 | while p.ic_rxflr().read().rxflr() == 0 { | 229 | while p.ic_rxflr().read().rxflr() == 0 { |
| 207 | if let Some(abort_reason) = self.read_and_clear_abort_reason() { | 230 | self.read_and_clear_abort_reason()?; |
| 208 | return Err(Error::Abort(abort_reason)); | ||
| 209 | } | ||
| 210 | } | 231 | } |
| 211 | 232 | ||
| 212 | *byte = p.ic_data_cmd().read().dat(); | 233 | *byte = p.ic_data_cmd().read().dat(); |
| @@ -241,7 +262,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 241 | 262 | ||
| 242 | let abort_reason = self.read_and_clear_abort_reason(); | 263 | let abort_reason = self.read_and_clear_abort_reason(); |
| 243 | 264 | ||
| 244 | if abort_reason.is_some() || (send_stop && last) { | 265 | if abort_reason.is_err() || (send_stop && last) { |
| 245 | // If the transaction was aborted or if it completed | 266 | // If the transaction was aborted or if it completed |
| 246 | // successfully wait until the STOP condition has occured. | 267 | // successfully wait until the STOP condition has occured. |
| 247 | 268 | ||
| @@ -254,9 +275,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | |||
| 254 | // condition. Note also the hardware clears RX FIFO as well as | 275 | // condition. Note also the hardware clears RX FIFO as well as |
| 255 | // TX on abort, ecause we set hwparam | 276 | // TX on abort, ecause we set hwparam |
| 256 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | 277 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. |
| 257 | if let Some(abort_reason) = abort_reason { | 278 | abort_reason?; |
| 258 | return Err(Error::Abort(abort_reason)); | ||
| 259 | } | ||
| 260 | } | 279 | } |
| 261 | } | 280 | } |
| 262 | Ok(()) | 281 | Ok(()) |
| @@ -360,15 +379,15 @@ mod eh1 { | |||
| 360 | impl embedded_hal_1::i2c::Error for Error { | 379 | impl embedded_hal_1::i2c::Error for Error { |
| 361 | fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { | 380 | fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { |
| 362 | match *self { | 381 | match *self { |
| 363 | _ => embedded_hal_1::i2c::ErrorKind::Bus, | 382 | Self::Abort(AbortReason::ArbitrationLoss) => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, |
| 364 | // Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, | 383 | Self::Abort(AbortReason::NoAcknowledge) => { |
| 365 | // Self::Nack => { | 384 | embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) |
| 366 | // embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown) | 385 | } |
| 367 | // } | 386 | Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, |
| 368 | // Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, | 387 | Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, |
| 369 | // Self::Crc => embedded_hal_1::i2c::ErrorKind::Other, | 388 | Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, |
| 370 | // Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, | 389 | Self::AddressOutOfRange(_) => embedded_hal_1::i2c::ErrorKind::Other, |
| 371 | // Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other, | 390 | Self::AddressReserved(_) => embedded_hal_1::i2c::ErrorKind::Other, |
| 372 | } | 391 | } |
| 373 | } | 392 | } |
| 374 | } | 393 | } |
