diff options
| author | Folkert <[email protected]> | 2021-06-04 17:31:35 +0200 |
|---|---|---|
| committer | Folkert <[email protected]> | 2021-06-04 17:31:35 +0200 |
| commit | 857ac3386bf13af1eeb9bf28b45b47b5169310e5 (patch) | |
| tree | d0b3e2c1de7c1d5e272e510f1a31bdb45c4c5b73 | |
| parent | cd44b221ed558689a20090771228c703e56e3371 (diff) | |
nrf async twim
| -rw-r--r-- | embassy-nrf/src/twim.rs | 113 | ||||
| -rw-r--r-- | embassy-traits/src/i2c.rs | 20 |
2 files changed, 126 insertions, 7 deletions
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ea3ac7553..6a7149044 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; |
| @@ -437,6 +442,114 @@ impl<'a, T: Instance> Drop for Twim<'a, T> { | |||
| 437 | } | 442 | } |
| 438 | } | 443 | } |
| 439 | 444 | ||
| 445 | impl<'d, T> I2c for Twim<'d, T> | ||
| 446 | where | ||
| 447 | T: Instance, | ||
| 448 | { | ||
| 449 | type Error = Error; | ||
| 450 | |||
| 451 | #[rustfmt::skip] | ||
| 452 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 453 | #[rustfmt::skip] | ||
| 454 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 455 | #[rustfmt::skip] | ||
| 456 | type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 457 | |||
| 458 | fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 459 | self.write_read(address, &[], buffer) | ||
| 460 | } | ||
| 461 | |||
| 462 | fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 463 | self.write_read(address, bytes, &mut []) | ||
| 464 | } | ||
| 465 | |||
| 466 | fn write_read<'a>( | ||
| 467 | &'a mut self, | ||
| 468 | address: u8, | ||
| 469 | bytes: &'a [u8], | ||
| 470 | buffer: &'a mut [u8], | ||
| 471 | ) -> Self::WriteReadFuture<'a> { | ||
| 472 | async move { | ||
| 473 | slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?; | ||
| 474 | // NOTE: RAM slice check for buffer is not necessary, as a mutable | ||
| 475 | // slice can only be built from data located in RAM. | ||
| 476 | |||
| 477 | // Conservative compiler fence to prevent optimizations that do not | ||
| 478 | // take in to account actions by DMA. The fence has been placed here, | ||
| 479 | // before any DMA action has started. | ||
| 480 | compiler_fence(SeqCst); | ||
| 481 | |||
| 482 | let r = T::regs(); | ||
| 483 | let s = T::state(); | ||
| 484 | |||
| 485 | // Set up current address we're trying to talk to | ||
| 486 | r.address.write(|w| unsafe { w.address().bits(address) }); | ||
| 487 | |||
| 488 | // Set up DMA buffers. | ||
| 489 | unsafe { | ||
| 490 | self.set_tx_buffer(bytes)?; | ||
| 491 | self.set_rx_buffer(buffer)?; | ||
| 492 | } | ||
| 493 | |||
| 494 | // Reset and enable the events | ||
| 495 | r.events_stopped.reset(); | ||
| 496 | r.events_error.reset(); | ||
| 497 | r.events_lasttx.reset(); | ||
| 498 | self.clear_errorsrc(); | ||
| 499 | |||
| 500 | r.intenset.write(|w| w.stopped().set()); | ||
| 501 | r.intenset.write(|w| w.error().set()); | ||
| 502 | r.intenset.write(|w| w.lasttx().set()); | ||
| 503 | |||
| 504 | // Start write+read operation. | ||
| 505 | r.shorts.write(|w| { | ||
| 506 | w.lasttx_startrx().enabled(); | ||
| 507 | w.lastrx_stop().enabled(); | ||
| 508 | w | ||
| 509 | }); | ||
| 510 | // `1` is a valid value to write to task registers. | ||
| 511 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 512 | |||
| 513 | // Conservative compiler fence to prevent optimizations that do not | ||
| 514 | // take in to account actions by DMA. The fence has been placed here, | ||
| 515 | // after all possible DMA actions have completed. | ||
| 516 | compiler_fence(SeqCst); | ||
| 517 | |||
| 518 | // Wait for 'stopped' event. | ||
| 519 | poll_fn(|cx| { | ||
| 520 | s.end_waker.register(cx.waker()); | ||
| 521 | if r.events_stopped.read().bits() != 0 { | ||
| 522 | r.events_stopped.reset(); | ||
| 523 | |||
| 524 | return Poll::Ready(()); | ||
| 525 | } | ||
| 526 | |||
| 527 | // stop if an error occured | ||
| 528 | if r.events_error.read().bits() != 0 { | ||
| 529 | r.events_error.reset(); | ||
| 530 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 531 | } | ||
| 532 | |||
| 533 | Poll::Pending | ||
| 534 | }) | ||
| 535 | .await; | ||
| 536 | |||
| 537 | let bad_write = r.txd.amount.read().bits() != bytes.len() as u32; | ||
| 538 | let bad_read = r.rxd.amount.read().bits() != buffer.len() as u32; | ||
| 539 | |||
| 540 | if bad_write { | ||
| 541 | return Err(Error::TxBufferTooLong); | ||
| 542 | } | ||
| 543 | |||
| 544 | if bad_read { | ||
| 545 | return Err(Error::RxBufferTooLong); | ||
| 546 | } | ||
| 547 | |||
| 548 | Ok(()) | ||
| 549 | } | ||
| 550 | } | ||
| 551 | } | ||
| 552 | |||
| 440 | impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> { | 553 | impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> { |
| 441 | type Error = Error; | 554 | type Error = Error; |
| 442 | 555 | ||
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 | } |
