|
6 | 6 | //! - nRF52840: Section 6.31 |
7 | 7 | use core::ops::Deref; |
8 | 8 | use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; |
| 9 | +use embedded_hal::i2c::{self, ErrorKind, ErrorType, I2c, NoAcknowledgeSource, Operation}; |
9 | 10 |
|
10 | 11 | #[cfg(any(feature = "9160", feature = "5340-app", feature = "5340-net"))] |
11 | 12 | use crate::pac::{twim0_ns as twim0, TWIM0_NS as TWIM0}; |
@@ -194,6 +195,10 @@ where |
194 | 195 | self.0.events_stopped.reset(); |
195 | 196 | break; |
196 | 197 | } |
| 198 | + if self.0.events_suspended.read().bits() != 0 { |
| 199 | + self.0.events_suspended.reset(); |
| 200 | + break; |
| 201 | + } |
197 | 202 | if self.0.events_error.read().bits() != 0 { |
198 | 203 | self.0.events_error.reset(); |
199 | 204 | self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); |
@@ -392,6 +397,125 @@ where |
392 | 397 | }, |
393 | 398 | ) |
394 | 399 | } |
| 400 | + |
| 401 | + fn write_part( |
| 402 | + &mut self, |
| 403 | + buffer: &[u8], |
| 404 | + last_operation_read: Option<bool>, |
| 405 | + final_operation: bool, |
| 406 | + ) -> Result<(), Error> { |
| 407 | + unsafe { self.set_tx_buffer(buffer)? }; |
| 408 | + |
| 409 | + // Set appropriate lasttx shortcut. |
| 410 | + if final_operation { |
| 411 | + self.0.shorts.write(|w| w.lasttx_stop().enabled()); |
| 412 | + } else { |
| 413 | + self.0.shorts.write(|w| w.lasttx_suspend().enabled()); |
| 414 | + } |
| 415 | + |
| 416 | + if last_operation_read != Some(false) { |
| 417 | + // Start write. |
| 418 | + self.0.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 419 | + } |
| 420 | + self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); |
| 421 | + |
| 422 | + self.wait(); |
| 423 | + self.read_errorsrc()?; |
| 424 | + if self.0.txd.amount.read().bits() != buffer.len() as u32 { |
| 425 | + return Err(Error::Transmit); |
| 426 | + } |
| 427 | + |
| 428 | + Ok(()) |
| 429 | + } |
| 430 | +} |
| 431 | + |
| 432 | +impl<T> ErrorType for Twim<T> { |
| 433 | + type Error = Error; |
| 434 | +} |
| 435 | + |
| 436 | +impl<T: Instance> I2c for Twim<T> { |
| 437 | + fn transaction( |
| 438 | + &mut self, |
| 439 | + address: u8, |
| 440 | + operations: &mut [Operation], |
| 441 | + ) -> Result<(), Self::Error> { |
| 442 | + compiler_fence(SeqCst); |
| 443 | + |
| 444 | + self.0 |
| 445 | + .address |
| 446 | + .write(|w| unsafe { w.address().bits(address) }); |
| 447 | + |
| 448 | + // `Some(true)` if the last operation was a read, `Some(false)` if it was a write. |
| 449 | + let mut last_operation_read = None; |
| 450 | + let operations_count = operations.len(); |
| 451 | + for (i, operation) in operations.into_iter().enumerate() { |
| 452 | + // Clear events |
| 453 | + self.0.events_stopped.reset(); |
| 454 | + self.0.events_error.reset(); |
| 455 | + self.0.events_lasttx.reset(); |
| 456 | + self.0.events_lastrx.reset(); |
| 457 | + self.clear_errorsrc(); |
| 458 | + |
| 459 | + match operation { |
| 460 | + Operation::Read(buffer) => { |
| 461 | + unsafe { self.set_rx_buffer(buffer)? }; |
| 462 | + |
| 463 | + // Set appropriate lastrx shortcut. |
| 464 | + if i == operations_count - 1 { |
| 465 | + rtt_target::rprintln!("Stopping after read."); |
| 466 | + self.0.shorts.write(|w| w.lastrx_stop().enabled()); |
| 467 | + } else { |
| 468 | + #[cfg(not(any( |
| 469 | + feature = "5340-app", |
| 470 | + feature = "5340-net", |
| 471 | + feature = "52832" |
| 472 | + )))] |
| 473 | + self.0.shorts.write(|w| w.lastrx_suspend().enabled()); |
| 474 | + } |
| 475 | + |
| 476 | + if last_operation_read != Some(true) { |
| 477 | + // Start read. |
| 478 | + self.0.tasks_startrx.write(|w| unsafe { w.bits(1) }); |
| 479 | + } |
| 480 | + self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); |
| 481 | + |
| 482 | + self.wait(); |
| 483 | + self.read_errorsrc()?; |
| 484 | + if self.0.rxd.amount.read().bits() != buffer.len() as u32 { |
| 485 | + return Err(Error::Receive); |
| 486 | + } |
| 487 | + |
| 488 | + last_operation_read = Some(true); |
| 489 | + } |
| 490 | + Operation::Write(buffer) => { |
| 491 | + if crate::slice_in_ram(buffer) { |
| 492 | + self.write_part(buffer, last_operation_read, i == operations_count - 1)?; |
| 493 | + } else if buffer.len() > FORCE_COPY_BUFFER_SIZE { |
| 494 | + return Err(Error::TxBufferTooLong); |
| 495 | + } else { |
| 496 | + let mut copy = [0; FORCE_COPY_BUFFER_SIZE]; |
| 497 | + let num_chunks = buffer.len().div_ceil(FORCE_COPY_BUFFER_SIZE); |
| 498 | + for (chunk_index, chunk) in buffer |
| 499 | + .chunks(FORCE_COPY_BUFFER_SIZE) |
| 500 | + .into_iter() |
| 501 | + .enumerate() |
| 502 | + { |
| 503 | + copy[..chunk.len()].copy_from_slice(chunk); |
| 504 | + self.write_part( |
| 505 | + ©[..chunk.len()], |
| 506 | + last_operation_read, |
| 507 | + i == operations_count - 1 && chunk_index == num_chunks - 1, |
| 508 | + )?; |
| 509 | + } |
| 510 | + } |
| 511 | + |
| 512 | + last_operation_read = Some(false); |
| 513 | + } |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + Ok(()) |
| 518 | + } |
395 | 519 | } |
396 | 520 |
|
397 | 521 | #[cfg(feature = "embedded-hal-02")] |
@@ -473,6 +597,23 @@ pub enum Error { |
473 | 597 | Overrun, |
474 | 598 | } |
475 | 599 |
|
| 600 | +impl i2c::Error for Error { |
| 601 | + fn kind(&self) -> ErrorKind { |
| 602 | + match self { |
| 603 | + Self::TxBufferTooLong |
| 604 | + | Self::RxBufferTooLong |
| 605 | + | Self::TxBufferZeroLength |
| 606 | + | Self::RxBufferZeroLength |
| 607 | + | Self::Transmit |
| 608 | + | Self::Receive |
| 609 | + | Self::DMABufferNotInDataMemory => ErrorKind::Other, |
| 610 | + Self::AddressNack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address), |
| 611 | + Self::DataNack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data), |
| 612 | + Self::Overrun => ErrorKind::Overrun, |
| 613 | + } |
| 614 | + } |
| 615 | +} |
| 616 | + |
476 | 617 | /// Implemented by all TWIM instances |
477 | 618 | pub trait Instance: Deref<Target = twim0::RegisterBlock> + sealed::Sealed {} |
478 | 619 |
|
|
0 commit comments