nrf async twim

This commit is contained in:
Folkert 2021-06-04 17:31:35 +02:00
parent cd44b221ed
commit 857ac3386b
2 changed files with 126 additions and 7 deletions

View File

@ -6,11 +6,16 @@
//!
//! - nRF52832: Section 33
//! - nRF52840: Section 6.31
use core::future::Future;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
use core::task::Poll;
use embassy::interrupt::{Interrupt, InterruptExt};
use embassy::traits;
use embassy::util::{AtomicWaker, Unborrow};
use embassy_extras::unborrow;
use futures::future::poll_fn;
use traits::i2c::I2c;
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
use crate::gpio::Pin as GpioPin;
@ -437,6 +442,114 @@ impl<'a, T: Instance> Drop for Twim<'a, T> {
}
}
impl<'d, T> I2c for Twim<'d, T>
where
T: Instance,
{
type Error = Error;
#[rustfmt::skip]
type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
#[rustfmt::skip]
type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
#[rustfmt::skip]
type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
self.write_read(address, &[], buffer)
}
fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
self.write_read(address, bytes, &mut [])
}
fn write_read<'a>(
&'a mut self,
address: u8,
bytes: &'a [u8],
buffer: &'a mut [u8],
) -> Self::WriteReadFuture<'a> {
async move {
slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?;
// NOTE: RAM slice check for buffer is not necessary, as a mutable
// slice can only be built from data located in RAM.
// Conservative compiler fence to prevent optimizations that do not
// take in to account actions by DMA. The fence has been placed here,
// before any DMA action has started.
compiler_fence(SeqCst);
let r = T::regs();
let s = T::state();
// Set up current address we're trying to talk to
r.address.write(|w| unsafe { w.address().bits(address) });
// Set up DMA buffers.
unsafe {
self.set_tx_buffer(bytes)?;
self.set_rx_buffer(buffer)?;
}
// Reset and enable the events
r.events_stopped.reset();
r.events_error.reset();
r.events_lasttx.reset();
self.clear_errorsrc();
r.intenset.write(|w| w.stopped().set());
r.intenset.write(|w| w.error().set());
r.intenset.write(|w| w.lasttx().set());
// Start write+read operation.
r.shorts.write(|w| {
w.lasttx_startrx().enabled();
w.lastrx_stop().enabled();
w
});
// `1` is a valid value to write to task registers.
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
// Conservative compiler fence to prevent optimizations that do not
// take in to account actions by DMA. The fence has been placed here,
// after all possible DMA actions have completed.
compiler_fence(SeqCst);
// Wait for 'stopped' event.
poll_fn(|cx| {
s.end_waker.register(cx.waker());
if r.events_stopped.read().bits() != 0 {
r.events_stopped.reset();
return Poll::Ready(());
}
// stop if an error occured
if r.events_error.read().bits() != 0 {
r.events_error.reset();
r.tasks_stop.write(|w| unsafe { w.bits(1) });
}
Poll::Pending
})
.await;
let bad_write = r.txd.amount.read().bits() != bytes.len() as u32;
let bad_read = r.rxd.amount.read().bits() != buffer.len() as u32;
if bad_write {
return Err(Error::TxBufferTooLong);
}
if bad_read {
return Err(Error::RxBufferTooLong);
}
Ok(())
}
}
}
impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> {
type Error = Error;

View File

@ -94,9 +94,15 @@ pub trait I2c<A: AddressMode = SevenBitAddress> {
/// Error type
type Error;
type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
where
Self: 'a;
type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
where
Self: 'a;
type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
where
Self: 'a;
/// Reads enough bytes from slave with `address` to fill `buffer`
///
@ -116,7 +122,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> {
/// - `MAK` = master acknowledge
/// - `NMAK` = master no acknowledge
/// - `SP` = stop condition
fn read<'a>(&'a mut self, address: A, buffer: &mut [u8]) -> Self::ReadFuture<'a>;
fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a>;
/// Sends bytes to slave with address `address`
///
@ -134,7 +140,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> {
/// - `SAK` = slave acknowledge
/// - `Bi` = ith byte of data
/// - `SP` = stop condition
fn write<'a>(&'a mut self, address: A, bytes: &[u8]) -> Self::WriteFuture<'a>;
fn write<'a>(&'a mut self, address: A, bytes: &'a [u8]) -> Self::WriteFuture<'a>;
/// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a
/// single transaction*
@ -161,7 +167,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> {
fn write_read<'a>(
&'a mut self,
address: A,
bytes: &[u8],
buffer: &mut [u8],
bytes: &'a [u8],
buffer: &'a mut [u8],
) -> Self::WriteReadFuture<'a>;
}