diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-06-05 16:34:36 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-06-05 16:34:36 +0200 |
| commit | 5bd0aa9cb5bfb26122dc2f7755abd14975fadb31 (patch) | |
| tree | 22637b57ece2a3a240800db0d853b7c4f8e49c0c | |
| parent | 6f5c85c50f20fa336d2144c8161aea391bea52f7 (diff) | |
| parent | 749633ddf2b5022f61cbba9350ce4d09f6b25691 (diff) | |
Merge pull request #222 from folkertdev/nrf-async-twim
nrf async twim
| -rw-r--r-- | embassy-nrf/src/spim.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/twim.rs | 210 | ||||
| -rw-r--r-- | embassy-traits/src/i2c.rs | 20 |
3 files changed, 225 insertions, 8 deletions
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 0ca18d88c..b5e9afbc1 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs | |||
| @@ -196,8 +196,9 @@ impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> { | |||
| 196 | 196 | ||
| 197 | fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> { | 197 | fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> { |
| 198 | async move { | 198 | async move { |
| 199 | slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?; | ||
| 200 | slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; | 199 | slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; |
| 200 | // NOTE: RAM slice check for rx is not necessary, as a mutable | ||
| 201 | // slice can only be built from data located in RAM. | ||
| 201 | 202 | ||
| 202 | // Conservative compiler fence to prevent optimizations that do not | 203 | // Conservative compiler fence to prevent optimizations that do not |
| 203 | // take in to account actions by DMA. The fence has been placed here, | 204 | // take in to account actions by DMA. The fence has been placed here, |
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ea3ac7553..160868d7d 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -6,11 +6,16 @@ | |||
| 6 | //! | 6 | //! |
| 7 | //! - nRF52832: Section 33 | 7 | //! - nRF52832: Section 33 |
| 8 | //! - nRF52840: Section 6.31 | 8 | //! - nRF52840: Section 6.31 |
| 9 | use core::future::Future; | ||
| 9 | use core::marker::PhantomData; | 10 | use core::marker::PhantomData; |
| 10 | use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; | 11 | use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; |
| 12 | use core::task::Poll; | ||
| 11 | use embassy::interrupt::{Interrupt, InterruptExt}; | 13 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 14 | use embassy::traits; | ||
| 12 | use embassy::util::{AtomicWaker, Unborrow}; | 15 | use embassy::util::{AtomicWaker, Unborrow}; |
| 13 | use embassy_extras::unborrow; | 16 | use embassy_extras::unborrow; |
| 17 | use futures::future::poll_fn; | ||
| 18 | use traits::i2c::I2c; | ||
| 14 | 19 | ||
| 15 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 20 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 16 | use crate::gpio::Pin as GpioPin; | 21 | use crate::gpio::Pin as GpioPin; |
| @@ -418,6 +423,26 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 418 | 423 | ||
| 419 | self.write_then_read(address, wr_ram_buffer, rd_buffer) | 424 | self.write_then_read(address, wr_ram_buffer, rd_buffer) |
| 420 | } | 425 | } |
| 426 | |||
| 427 | fn wait_for_stopped_event(cx: &mut core::task::Context) -> Poll<()> { | ||
| 428 | let r = T::regs(); | ||
| 429 | let s = T::state(); | ||
| 430 | |||
| 431 | s.end_waker.register(cx.waker()); | ||
| 432 | if r.events_stopped.read().bits() != 0 { | ||
| 433 | r.events_stopped.reset(); | ||
| 434 | |||
| 435 | return Poll::Ready(()); | ||
| 436 | } | ||
| 437 | |||
| 438 | // stop if an error occured | ||
| 439 | if r.events_error.read().bits() != 0 { | ||
| 440 | r.events_error.reset(); | ||
| 441 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 442 | } | ||
| 443 | |||
| 444 | Poll::Pending | ||
| 445 | } | ||
| 421 | } | 446 | } |
| 422 | 447 | ||
| 423 | impl<'a, T: Instance> Drop for Twim<'a, T> { | 448 | impl<'a, T: Instance> Drop for Twim<'a, T> { |
| @@ -437,6 +462,191 @@ impl<'a, T: Instance> Drop for Twim<'a, T> { | |||
| 437 | } | 462 | } |
| 438 | } | 463 | } |
| 439 | 464 | ||
| 465 | impl<'d, T> I2c for Twim<'d, T> | ||
| 466 | where | ||
| 467 | T: Instance, | ||
| 468 | { | ||
| 469 | type Error = Error; | ||
| 470 | |||
| 471 | #[rustfmt::skip] | ||
| 472 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 473 | #[rustfmt::skip] | ||
| 474 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 475 | #[rustfmt::skip] | ||
| 476 | type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 477 | |||
| 478 | fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 479 | async move { | ||
| 480 | // NOTE: RAM slice check for buffer is not necessary, as a mutable | ||
| 481 | // slice can only be built from data located in RAM. | ||
| 482 | |||
| 483 | let r = T::regs(); | ||
| 484 | |||
| 485 | // Conservative compiler fence to prevent optimizations that do not | ||
| 486 | // take in to account actions by DMA. The fence has been placed here, | ||
| 487 | // before any DMA action has started. | ||
| 488 | compiler_fence(SeqCst); | ||
| 489 | |||
| 490 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 491 | |||
| 492 | // Set up the DMA read. | ||
| 493 | unsafe { self.set_rx_buffer(buffer)? }; | ||
| 494 | |||
| 495 | // Reset events | ||
| 496 | r.events_stopped.reset(); | ||
| 497 | r.events_error.reset(); | ||
| 498 | self.clear_errorsrc(); | ||
| 499 | |||
| 500 | // Enable events | ||
| 501 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 502 | |||
| 503 | // Start read operation. | ||
| 504 | r.shorts.write(|w| w.lastrx_stop().enabled()); | ||
| 505 | r.tasks_startrx.write(|w| | ||
| 506 | // `1` is a valid value to write to task registers. | ||
| 507 | unsafe { w.bits(1) }); | ||
| 508 | |||
| 509 | // Conservative compiler fence to prevent optimizations that do not | ||
| 510 | // take in to account actions by DMA. The fence has been placed here, | ||
| 511 | // after all possible DMA actions have completed. | ||
| 512 | compiler_fence(SeqCst); | ||
| 513 | |||
| 514 | // Wait for 'stopped' event. | ||
| 515 | poll_fn(Self::wait_for_stopped_event).await; | ||
| 516 | |||
| 517 | self.read_errorsrc()?; | ||
| 518 | |||
| 519 | if r.rxd.amount.read().bits() != buffer.len() as u32 { | ||
| 520 | return Err(Error::Receive); | ||
| 521 | } | ||
| 522 | |||
| 523 | Ok(()) | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 528 | async move { | ||
| 529 | slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?; | ||
| 530 | |||
| 531 | // Conservative compiler fence to prevent optimizations that do not | ||
| 532 | // take in to account actions by DMA. The fence has been placed here, | ||
| 533 | // before any DMA action has started. | ||
| 534 | compiler_fence(SeqCst); | ||
| 535 | |||
| 536 | let r = T::regs(); | ||
| 537 | |||
| 538 | // Set up current address we're trying to talk to | ||
| 539 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 540 | |||
| 541 | // Set up DMA write. | ||
| 542 | unsafe { | ||
| 543 | self.set_tx_buffer(bytes)?; | ||
| 544 | } | ||
| 545 | |||
| 546 | // Reset events | ||
| 547 | r.events_stopped.reset(); | ||
| 548 | r.events_error.reset(); | ||
| 549 | r.events_lasttx.reset(); | ||
| 550 | self.clear_errorsrc(); | ||
| 551 | |||
| 552 | // Enable events | ||
| 553 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 554 | |||
| 555 | // Start write operation. | ||
| 556 | r.shorts.write(|w| w.lasttx_stop().enabled()); | ||
| 557 | r.tasks_starttx.write(|w| | ||
| 558 | // `1` is a valid value to write to task registers. | ||
| 559 | unsafe { w.bits(1) }); | ||
| 560 | |||
| 561 | // Conservative compiler fence to prevent optimizations that do not | ||
| 562 | // take in to account actions by DMA. The fence has been placed here, | ||
| 563 | // after all possible DMA actions have completed. | ||
| 564 | compiler_fence(SeqCst); | ||
| 565 | |||
| 566 | // Wait for 'stopped' event. | ||
| 567 | poll_fn(Self::wait_for_stopped_event).await; | ||
| 568 | |||
| 569 | self.read_errorsrc()?; | ||
| 570 | |||
| 571 | if r.txd.amount.read().bits() != bytes.len() as u32 { | ||
| 572 | return Err(Error::Transmit); | ||
| 573 | } | ||
| 574 | |||
| 575 | Ok(()) | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 579 | fn write_read<'a>( | ||
| 580 | &'a mut self, | ||
| 581 | address: u8, | ||
| 582 | bytes: &'a [u8], | ||
| 583 | buffer: &'a mut [u8], | ||
| 584 | ) -> Self::WriteReadFuture<'a> { | ||
| 585 | async move { | ||
| 586 | slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?; | ||
| 587 | // NOTE: RAM slice check for buffer is not necessary, as a mutable | ||
| 588 | // slice can only be built from data located in RAM. | ||
| 589 | |||
| 590 | // Conservative compiler fence to prevent optimizations that do not | ||
| 591 | // take in to account actions by DMA. The fence has been placed here, | ||
| 592 | // before any DMA action has started. | ||
| 593 | compiler_fence(SeqCst); | ||
| 594 | |||
| 595 | let r = T::regs(); | ||
| 596 | |||
| 597 | // Set up current address we're trying to talk to | ||
| 598 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 599 | |||
| 600 | // Set up DMA buffers. | ||
| 601 | unsafe { | ||
| 602 | self.set_tx_buffer(bytes)?; | ||
| 603 | self.set_rx_buffer(buffer)?; | ||
| 604 | } | ||
| 605 | |||
| 606 | // Reset events | ||
| 607 | r.events_stopped.reset(); | ||
| 608 | r.events_error.reset(); | ||
| 609 | r.events_lasttx.reset(); | ||
| 610 | self.clear_errorsrc(); | ||
| 611 | |||
| 612 | // Enable events | ||
| 613 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 614 | |||
| 615 | // Start write+read operation. | ||
| 616 | r.shorts.write(|w| { | ||
| 617 | w.lasttx_startrx().enabled(); | ||
| 618 | w.lastrx_stop().enabled(); | ||
| 619 | w | ||
| 620 | }); | ||
| 621 | // `1` is a valid value to write to task registers. | ||
| 622 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 623 | |||
| 624 | // Conservative compiler fence to prevent optimizations that do not | ||
| 625 | // take in to account actions by DMA. The fence has been placed here, | ||
| 626 | // after all possible DMA actions have completed. | ||
| 627 | compiler_fence(SeqCst); | ||
| 628 | |||
| 629 | // Wait for 'stopped' event. | ||
| 630 | poll_fn(Self::wait_for_stopped_event).await; | ||
| 631 | |||
| 632 | self.read_errorsrc()?; | ||
| 633 | |||
| 634 | let bad_write = r.txd.amount.read().bits() != bytes.len() as u32; | ||
| 635 | let bad_read = r.rxd.amount.read().bits() != buffer.len() as u32; | ||
| 636 | |||
| 637 | if bad_write { | ||
| 638 | return Err(Error::Transmit); | ||
| 639 | } | ||
| 640 | |||
| 641 | if bad_read { | ||
| 642 | return Err(Error::Receive); | ||
| 643 | } | ||
| 644 | |||
| 645 | Ok(()) | ||
| 646 | } | ||
| 647 | } | ||
| 648 | } | ||
| 649 | |||
| 440 | impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> { | 650 | impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> { |
| 441 | type Error = Error; | 651 | type Error = Error; |
| 442 | 652 | ||
diff --git a/embassy-traits/src/i2c.rs b/embassy-traits/src/i2c.rs index abe932d9c..e426a00b0 100644 --- a/embassy-traits/src/i2c.rs +++ b/embassy-traits/src/i2c.rs | |||
| @@ -94,9 +94,15 @@ pub trait I2c<A: AddressMode = SevenBitAddress> { | |||
| 94 | /// Error type | 94 | /// Error type |
| 95 | type Error; | 95 | type Error; |
| 96 | 96 | ||
| 97 | type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a; | 97 | type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a |
| 98 | type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a; | 98 | where |
| 99 | type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a; | 99 | Self: 'a; |
| 100 | type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a | ||
| 101 | where | ||
| 102 | Self: 'a; | ||
| 103 | type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a | ||
| 104 | where | ||
| 105 | Self: 'a; | ||
| 100 | 106 | ||
| 101 | /// Reads enough bytes from slave with `address` to fill `buffer` | 107 | /// Reads enough bytes from slave with `address` to fill `buffer` |
| 102 | /// | 108 | /// |
| @@ -116,7 +122,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> { | |||
| 116 | /// - `MAK` = master acknowledge | 122 | /// - `MAK` = master acknowledge |
| 117 | /// - `NMAK` = master no acknowledge | 123 | /// - `NMAK` = master no acknowledge |
| 118 | /// - `SP` = stop condition | 124 | /// - `SP` = stop condition |
| 119 | fn read<'a>(&'a mut self, address: A, buffer: &mut [u8]) -> Self::ReadFuture<'a>; | 125 | fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a>; |
| 120 | 126 | ||
| 121 | /// Sends bytes to slave with address `address` | 127 | /// Sends bytes to slave with address `address` |
| 122 | /// | 128 | /// |
| @@ -134,7 +140,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> { | |||
| 134 | /// - `SAK` = slave acknowledge | 140 | /// - `SAK` = slave acknowledge |
| 135 | /// - `Bi` = ith byte of data | 141 | /// - `Bi` = ith byte of data |
| 136 | /// - `SP` = stop condition | 142 | /// - `SP` = stop condition |
| 137 | fn write<'a>(&'a mut self, address: A, bytes: &[u8]) -> Self::WriteFuture<'a>; | 143 | fn write<'a>(&'a mut self, address: A, bytes: &'a [u8]) -> Self::WriteFuture<'a>; |
| 138 | 144 | ||
| 139 | /// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a | 145 | /// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a |
| 140 | /// single transaction* | 146 | /// single transaction* |
| @@ -161,7 +167,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> { | |||
| 161 | fn write_read<'a>( | 167 | fn write_read<'a>( |
| 162 | &'a mut self, | 168 | &'a mut self, |
| 163 | address: A, | 169 | address: A, |
| 164 | bytes: &[u8], | 170 | bytes: &'a [u8], |
| 165 | buffer: &mut [u8], | 171 | buffer: &'a mut [u8], |
| 166 | ) -> Self::WriteReadFuture<'a>; | 172 | ) -> Self::WriteReadFuture<'a>; |
| 167 | } | 173 | } |
