commit
5bd0aa9cb5
@ -196,8 +196,9 @@ impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
|
|||||||
|
|
||||||
fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> {
|
fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> {
|
||||||
async move {
|
async move {
|
||||||
slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?;
|
|
||||||
slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?;
|
slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?;
|
||||||
|
// NOTE: RAM slice check for rx 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
|
// Conservative compiler fence to prevent optimizations that do not
|
||||||
// take in to account actions by DMA. The fence has been placed here,
|
// take in to account actions by DMA. The fence has been placed here,
|
||||||
|
@ -6,11 +6,16 @@
|
|||||||
//!
|
//!
|
||||||
//! - nRF52832: Section 33
|
//! - nRF52832: Section 33
|
||||||
//! - nRF52840: Section 6.31
|
//! - nRF52840: Section 6.31
|
||||||
|
use core::future::Future;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
|
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
|
||||||
|
use core::task::Poll;
|
||||||
use embassy::interrupt::{Interrupt, InterruptExt};
|
use embassy::interrupt::{Interrupt, InterruptExt};
|
||||||
|
use embassy::traits;
|
||||||
use embassy::util::{AtomicWaker, Unborrow};
|
use embassy::util::{AtomicWaker, Unborrow};
|
||||||
use embassy_extras::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::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||||
use crate::gpio::Pin as GpioPin;
|
use crate::gpio::Pin as GpioPin;
|
||||||
@ -418,6 +423,26 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
|
|
||||||
self.write_then_read(address, wr_ram_buffer, rd_buffer)
|
self.write_then_read(address, wr_ram_buffer, rd_buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wait_for_stopped_event(cx: &mut core::task::Context) -> Poll<()> {
|
||||||
|
let r = T::regs();
|
||||||
|
let s = T::state();
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Instance> Drop for Twim<'a, T> {
|
impl<'a, T: Instance> Drop for Twim<'a, T> {
|
||||||
@ -437,6 +462,191 @@ 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> {
|
||||||
|
async move {
|
||||||
|
// NOTE: RAM slice check for buffer is not necessary, as a mutable
|
||||||
|
// slice can only be built from data located in RAM.
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||||
|
|
||||||
|
// Set up the DMA read.
|
||||||
|
unsafe { self.set_rx_buffer(buffer)? };
|
||||||
|
|
||||||
|
// Reset events
|
||||||
|
r.events_stopped.reset();
|
||||||
|
r.events_error.reset();
|
||||||
|
self.clear_errorsrc();
|
||||||
|
|
||||||
|
// Enable events
|
||||||
|
r.intenset.write(|w| w.stopped().set().error().set());
|
||||||
|
|
||||||
|
// Start read operation.
|
||||||
|
r.shorts.write(|w| w.lastrx_stop().enabled());
|
||||||
|
r.tasks_startrx.write(|w|
|
||||||
|
// `1` is a valid value to write to task registers.
|
||||||
|
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(Self::wait_for_stopped_event).await;
|
||||||
|
|
||||||
|
self.read_errorsrc()?;
|
||||||
|
|
||||||
|
if r.rxd.amount.read().bits() != buffer.len() as u32 {
|
||||||
|
return Err(Error::Receive);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||||
|
async move {
|
||||||
|
slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// Set up current address we're trying to talk to
|
||||||
|
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||||
|
|
||||||
|
// Set up DMA write.
|
||||||
|
unsafe {
|
||||||
|
self.set_tx_buffer(bytes)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset events
|
||||||
|
r.events_stopped.reset();
|
||||||
|
r.events_error.reset();
|
||||||
|
r.events_lasttx.reset();
|
||||||
|
self.clear_errorsrc();
|
||||||
|
|
||||||
|
// Enable events
|
||||||
|
r.intenset.write(|w| w.stopped().set().error().set());
|
||||||
|
|
||||||
|
// Start write operation.
|
||||||
|
r.shorts.write(|w| w.lasttx_stop().enabled());
|
||||||
|
r.tasks_starttx.write(|w|
|
||||||
|
// `1` is a valid value to write to task registers.
|
||||||
|
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(Self::wait_for_stopped_event).await;
|
||||||
|
|
||||||
|
self.read_errorsrc()?;
|
||||||
|
|
||||||
|
if r.txd.amount.read().bits() != bytes.len() as u32 {
|
||||||
|
return Err(Error::Transmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 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 events
|
||||||
|
r.events_stopped.reset();
|
||||||
|
r.events_error.reset();
|
||||||
|
r.events_lasttx.reset();
|
||||||
|
self.clear_errorsrc();
|
||||||
|
|
||||||
|
// Enable events
|
||||||
|
r.intenset.write(|w| w.stopped().set().error().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(Self::wait_for_stopped_event).await;
|
||||||
|
|
||||||
|
self.read_errorsrc()?;
|
||||||
|
|
||||||
|
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::Transmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if bad_read {
|
||||||
|
return Err(Error::Receive);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> {
|
impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
|
@ -94,9 +94,15 @@ pub trait I2c<A: AddressMode = SevenBitAddress> {
|
|||||||
/// Error type
|
/// Error type
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
|
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
|
||||||
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
|
where
|
||||||
type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a;
|
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`
|
/// Reads enough bytes from slave with `address` to fill `buffer`
|
||||||
///
|
///
|
||||||
@ -116,7 +122,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> {
|
|||||||
/// - `MAK` = master acknowledge
|
/// - `MAK` = master acknowledge
|
||||||
/// - `NMAK` = master no acknowledge
|
/// - `NMAK` = master no acknowledge
|
||||||
/// - `SP` = stop condition
|
/// - `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`
|
/// Sends bytes to slave with address `address`
|
||||||
///
|
///
|
||||||
@ -134,7 +140,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> {
|
|||||||
/// - `SAK` = slave acknowledge
|
/// - `SAK` = slave acknowledge
|
||||||
/// - `Bi` = ith byte of data
|
/// - `Bi` = ith byte of data
|
||||||
/// - `SP` = stop condition
|
/// - `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
|
/// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a
|
||||||
/// single transaction*
|
/// single transaction*
|
||||||
@ -161,7 +167,7 @@ pub trait I2c<A: AddressMode = SevenBitAddress> {
|
|||||||
fn write_read<'a>(
|
fn write_read<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
address: A,
|
address: A,
|
||||||
bytes: &[u8],
|
bytes: &'a [u8],
|
||||||
buffer: &mut [u8],
|
buffer: &'a mut [u8],
|
||||||
) -> Self::WriteReadFuture<'a>;
|
) -> Self::WriteReadFuture<'a>;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user