diff options
| -rw-r--r-- | embassy-nrf/src/twim.rs | 133 |
1 files changed, 131 insertions, 2 deletions
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ecad58f3a..5eb1932e5 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -456,11 +456,138 @@ where | |||
| 456 | type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | 456 | type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; |
| 457 | 457 | ||
| 458 | fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | 458 | fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 459 | self.write_read(address, &[], buffer) | 459 | async move { |
| 460 | // NOTE: RAM slice check for buffer is not necessary, as a mutable | ||
| 461 | // slice can only be built from data located in RAM. | ||
| 462 | |||
| 463 | let r = T::regs(); | ||
| 464 | let s = T::state(); | ||
| 465 | |||
| 466 | // Conservative compiler fence to prevent optimizations that do not | ||
| 467 | // take in to account actions by DMA. The fence has been placed here, | ||
| 468 | // before any DMA action has started. | ||
| 469 | compiler_fence(SeqCst); | ||
| 470 | |||
| 471 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 472 | |||
| 473 | // Set up the DMA read. | ||
| 474 | unsafe { self.set_rx_buffer(buffer)? }; | ||
| 475 | |||
| 476 | // Reset events | ||
| 477 | r.events_stopped.reset(); | ||
| 478 | r.events_error.reset(); | ||
| 479 | self.clear_errorsrc(); | ||
| 480 | |||
| 481 | // Enable events | ||
| 482 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 483 | |||
| 484 | // Start read operation. | ||
| 485 | r.shorts.write(|w| w.lastrx_stop().enabled()); | ||
| 486 | r.tasks_startrx.write(|w| | ||
| 487 | // `1` is a valid value to write to task registers. | ||
| 488 | unsafe { w.bits(1) }); | ||
| 489 | |||
| 490 | // Conservative compiler fence to prevent optimizations that do not | ||
| 491 | // take in to account actions by DMA. The fence has been placed here, | ||
| 492 | // after all possible DMA actions have completed. | ||
| 493 | compiler_fence(SeqCst); | ||
| 494 | |||
| 495 | // Wait for 'stopped' event. | ||
| 496 | poll_fn(|cx| { | ||
| 497 | s.end_waker.register(cx.waker()); | ||
| 498 | if r.events_stopped.read().bits() != 0 { | ||
| 499 | r.events_stopped.reset(); | ||
| 500 | |||
| 501 | return Poll::Ready(()); | ||
| 502 | } | ||
| 503 | |||
| 504 | // stop if an error occured | ||
| 505 | if r.events_error.read().bits() != 0 { | ||
| 506 | r.events_error.reset(); | ||
| 507 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 508 | } | ||
| 509 | |||
| 510 | Poll::Pending | ||
| 511 | }) | ||
| 512 | .await; | ||
| 513 | |||
| 514 | self.read_errorsrc()?; | ||
| 515 | |||
| 516 | if r.rxd.amount.read().bits() != buffer.len() as u32 { | ||
| 517 | return Err(Error::Receive); | ||
| 518 | } | ||
| 519 | |||
| 520 | Ok(()) | ||
| 521 | } | ||
| 460 | } | 522 | } |
| 461 | 523 | ||
| 462 | fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { | 524 | fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { |
| 463 | self.write_read(address, bytes, &mut []) | 525 | async move { |
| 526 | slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?; | ||
| 527 | |||
| 528 | // Conservative compiler fence to prevent optimizations that do not | ||
| 529 | // take in to account actions by DMA. The fence has been placed here, | ||
| 530 | // before any DMA action has started. | ||
| 531 | compiler_fence(SeqCst); | ||
| 532 | |||
| 533 | let r = T::regs(); | ||
| 534 | let s = T::state(); | ||
| 535 | |||
| 536 | // Set up current address we're trying to talk to | ||
| 537 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 538 | |||
| 539 | // Set up DMA buffers. | ||
| 540 | unsafe { | ||
| 541 | self.set_tx_buffer(bytes)?; | ||
| 542 | } | ||
| 543 | |||
| 544 | // Reset events | ||
| 545 | r.events_stopped.reset(); | ||
| 546 | r.events_error.reset(); | ||
| 547 | r.events_lasttx.reset(); | ||
| 548 | self.clear_errorsrc(); | ||
| 549 | |||
| 550 | // Enable events | ||
| 551 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 552 | |||
| 553 | // Start write operation. | ||
| 554 | r.shorts.write(|w| w.lasttx_stop().enabled()); | ||
| 555 | r.tasks_starttx.write(|w| | ||
| 556 | // `1` is a valid value to write to task registers. | ||
| 557 | unsafe { w.bits(1) }); | ||
| 558 | |||
| 559 | // Conservative compiler fence to prevent optimizations that do not | ||
| 560 | // take in to account actions by DMA. The fence has been placed here, | ||
| 561 | // after all possible DMA actions have completed. | ||
| 562 | compiler_fence(SeqCst); | ||
| 563 | |||
| 564 | // Wait for 'stopped' event. | ||
| 565 | poll_fn(|cx| { | ||
| 566 | s.end_waker.register(cx.waker()); | ||
| 567 | if r.events_stopped.read().bits() != 0 { | ||
| 568 | r.events_stopped.reset(); | ||
| 569 | |||
| 570 | return Poll::Ready(()); | ||
| 571 | } | ||
| 572 | |||
| 573 | // stop if an error occured | ||
| 574 | if r.events_error.read().bits() != 0 { | ||
| 575 | r.events_error.reset(); | ||
| 576 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 577 | } | ||
| 578 | |||
| 579 | Poll::Pending | ||
| 580 | }) | ||
| 581 | .await; | ||
| 582 | |||
| 583 | self.read_errorsrc()?; | ||
| 584 | |||
| 585 | if r.txd.amount.read().bits() != bytes.len() as u32 { | ||
| 586 | return Err(Error::Transmit); | ||
| 587 | } | ||
| 588 | |||
| 589 | Ok(()) | ||
| 590 | } | ||
| 464 | } | 591 | } |
| 465 | 592 | ||
| 466 | fn write_read<'a>( | 593 | fn write_read<'a>( |
| @@ -533,6 +660,8 @@ where | |||
| 533 | }) | 660 | }) |
| 534 | .await; | 661 | .await; |
| 535 | 662 | ||
| 663 | self.read_errorsrc()?; | ||
| 664 | |||
| 536 | let bad_write = r.txd.amount.read().bits() != bytes.len() as u32; | 665 | let bad_write = r.txd.amount.read().bits() != bytes.len() as u32; |
| 537 | let bad_read = r.rxd.amount.read().bits() != buffer.len() as u32; | 666 | let bad_read = r.rxd.amount.read().bits() != buffer.len() as u32; |
| 538 | 667 | ||
