mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-24 07:42:29 +00:00
Merge pull request #3257 from alexmoon/nrf-twim-transactions
Add support for transactions to Twim in embassy-nrf
This commit is contained in:
commit
cd9e581c65
@ -4,6 +4,7 @@
|
||||
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::sync::atomic::compiler_fence;
|
||||
use core::sync::atomic::Ordering::SeqCst;
|
||||
use core::task::Poll;
|
||||
@ -13,11 +14,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
#[cfg(feature = "time")]
|
||||
use embassy_time::{Duration, Instant};
|
||||
use embedded_hal_1::i2c::Operation;
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::Pin as GpioPin;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::util::{slice_in_ram, slice_in_ram_or};
|
||||
use crate::util::slice_in_ram;
|
||||
use crate::{gpio, interrupt, pac, Peripheral};
|
||||
|
||||
/// TWI frequency
|
||||
@ -103,6 +105,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_suspended.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.suspended().clear());
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.stopped().clear());
|
||||
@ -182,8 +188,22 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
}
|
||||
|
||||
/// Set TX buffer, checking that it is in RAM and has suitable length.
|
||||
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
||||
unsafe fn set_tx_buffer(
|
||||
&mut self,
|
||||
buffer: &[u8],
|
||||
ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
|
||||
) -> Result<(), Error> {
|
||||
let buffer = if slice_in_ram(buffer) {
|
||||
buffer
|
||||
} else {
|
||||
let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?;
|
||||
trace!("Copying TWIM tx buffer into RAM for DMA");
|
||||
let ram_buffer = &mut ram_buffer[..buffer.len()];
|
||||
// Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer)
|
||||
let uninit_src: &[MaybeUninit<u8>] = unsafe { core::mem::transmute(buffer) };
|
||||
ram_buffer.copy_from_slice(uninit_src);
|
||||
unsafe { &*(ram_buffer as *const [MaybeUninit<u8>] as *const [u8]) }
|
||||
};
|
||||
|
||||
if buffer.len() > EASY_DMA_SIZE {
|
||||
return Err(Error::TxBufferTooLong);
|
||||
@ -290,7 +310,8 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
fn blocking_wait(&mut self) {
|
||||
let r = T::regs();
|
||||
loop {
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 {
|
||||
r.events_suspended.reset();
|
||||
r.events_stopped.reset();
|
||||
break;
|
||||
}
|
||||
@ -307,7 +328,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
let r = T::regs();
|
||||
let deadline = Instant::now() + timeout;
|
||||
loop {
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
break;
|
||||
}
|
||||
@ -331,7 +352,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
let s = T::state();
|
||||
|
||||
s.end_waker.register(cx.waker());
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
|
||||
return Poll::Ready(());
|
||||
@ -347,168 +368,316 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn setup_write_from_ram(&mut self, address: u8, buffer: &[u8], inten: bool) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||
|
||||
// Set up the DMA write.
|
||||
unsafe { self.set_tx_buffer(buffer)? };
|
||||
|
||||
// Clear events
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
r.events_lasttx.reset();
|
||||
self.clear_errorsrc();
|
||||
|
||||
if inten {
|
||||
r.intenset.write(|w| w.stopped().set().error().set());
|
||||
} else {
|
||||
r.intenclr.write(|w| w.stopped().clear().error().clear());
|
||||
}
|
||||
|
||||
// Start write operation.
|
||||
r.shorts.write(|w| w.lasttx_stop().enabled());
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
if buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves.
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_read(&mut self, address: u8, buffer: &mut [u8], inten: bool) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||
|
||||
// Set up the DMA read.
|
||||
unsafe { self.set_rx_buffer(buffer)? };
|
||||
|
||||
// Clear events
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
self.clear_errorsrc();
|
||||
|
||||
if inten {
|
||||
r.intenset.write(|w| w.stopped().set().error().set());
|
||||
} else {
|
||||
r.intenclr.write(|w| w.stopped().clear().error().clear());
|
||||
}
|
||||
|
||||
// Start read operation.
|
||||
r.shorts.write(|w| w.lastrx_stop().enabled());
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
if buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves.
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_write_read_from_ram(
|
||||
fn setup_operations(
|
||||
&mut self,
|
||||
address: u8,
|
||||
wr_buffer: &[u8],
|
||||
rd_buffer: &mut [u8],
|
||||
operations: &mut [Operation<'_>],
|
||||
tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
|
||||
last_op: Option<&Operation<'_>>,
|
||||
inten: bool,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<usize, Error> {
|
||||
let r = T::regs();
|
||||
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||
|
||||
// Set up DMA buffers.
|
||||
unsafe {
|
||||
self.set_tx_buffer(wr_buffer)?;
|
||||
self.set_rx_buffer(rd_buffer)?;
|
||||
}
|
||||
|
||||
// Clear events
|
||||
r.events_suspended.reset();
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
self.clear_errorsrc();
|
||||
|
||||
if inten {
|
||||
r.intenset.write(|w| w.stopped().set().error().set());
|
||||
r.intenset.write(|w| w.suspended().set().stopped().set().error().set());
|
||||
} else {
|
||||
r.intenclr.write(|w| w.stopped().clear().error().clear());
|
||||
r.intenclr
|
||||
.write(|w| w.suspended().clear().stopped().clear().error().clear());
|
||||
}
|
||||
|
||||
// Start write+read operation.
|
||||
r.shorts.write(|w| {
|
||||
w.lasttx_startrx().enabled();
|
||||
w.lastrx_stop().enabled();
|
||||
w
|
||||
});
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
if wr_buffer.is_empty() && rd_buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTRX/LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves.
|
||||
// TODO handle when only one of the buffers is zero length
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
assert!(!operations.is_empty());
|
||||
match operations {
|
||||
[Operation::Read(_), Operation::Read(_), ..] => {
|
||||
panic!("Consecutive read operations are not supported!")
|
||||
}
|
||||
[Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] => {
|
||||
let stop = rest.is_empty();
|
||||
|
||||
// Set up DMA buffers.
|
||||
unsafe {
|
||||
self.set_tx_buffer(wr_buffer, tx_ram_buffer)?;
|
||||
self.set_rx_buffer(rd_buffer)?;
|
||||
}
|
||||
|
||||
r.shorts.write(|w| {
|
||||
w.lastrx_starttx().enabled();
|
||||
if stop {
|
||||
w.lasttx_stop().enabled();
|
||||
} else {
|
||||
w.lasttx_suspend().enabled();
|
||||
}
|
||||
w
|
||||
});
|
||||
|
||||
// Start read+write operation.
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
if last_op.is_some() {
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
// TODO: Handle empty write buffer
|
||||
if rd_buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STARTTX ourselves.
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
Ok(2)
|
||||
}
|
||||
[Operation::Read(buffer)] => {
|
||||
// Set up DMA buffers.
|
||||
unsafe {
|
||||
self.set_rx_buffer(buffer)?;
|
||||
}
|
||||
|
||||
r.shorts.write(|w| w.lastrx_stop().enabled());
|
||||
|
||||
// Start read operation.
|
||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||
if last_op.is_some() {
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
if buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves.
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
Ok(1)
|
||||
}
|
||||
[Operation::Write(wr_buffer), Operation::Read(rd_buffer)]
|
||||
if !wr_buffer.is_empty() && !rd_buffer.is_empty() =>
|
||||
{
|
||||
// Set up DMA buffers.
|
||||
unsafe {
|
||||
self.set_tx_buffer(wr_buffer, tx_ram_buffer)?;
|
||||
self.set_rx_buffer(rd_buffer)?;
|
||||
}
|
||||
|
||||
// Start write+read operation.
|
||||
r.shorts.write(|w| {
|
||||
w.lasttx_startrx().enabled();
|
||||
w.lastrx_stop().enabled();
|
||||
w
|
||||
});
|
||||
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
if last_op.is_some() {
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
Ok(2)
|
||||
}
|
||||
[Operation::Write(buffer), rest @ ..] => {
|
||||
let stop = rest.is_empty();
|
||||
|
||||
// Set up DMA buffers.
|
||||
unsafe {
|
||||
self.set_tx_buffer(buffer, tx_ram_buffer)?;
|
||||
}
|
||||
|
||||
// Start write operation.
|
||||
r.shorts.write(|w| {
|
||||
if stop {
|
||||
w.lasttx_stop().enabled();
|
||||
} else {
|
||||
w.lasttx_suspend().enabled();
|
||||
}
|
||||
w
|
||||
});
|
||||
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
if last_op.is_some() {
|
||||
r.tasks_resume.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
if buffer.is_empty() {
|
||||
// With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves.
|
||||
if stop {
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
} else {
|
||||
r.tasks_suspend.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
}
|
||||
|
||||
Ok(1)
|
||||
}
|
||||
[] => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_operations(&mut self, operations: &[Operation<'_>]) -> Result<(), Error> {
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
|
||||
assert!(operations.len() == 1 || operations.len() == 2);
|
||||
match operations {
|
||||
[Operation::Read(rd_buffer), Operation::Write(wr_buffer)]
|
||||
| [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] => {
|
||||
self.check_rx(rd_buffer.len())?;
|
||||
self.check_tx(wr_buffer.len())?;
|
||||
}
|
||||
[Operation::Read(buffer)] => {
|
||||
self.check_rx(buffer.len())?;
|
||||
}
|
||||
[Operation::Write(buffer), ..] => {
|
||||
self.check_tx(buffer.len())?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_write_read(
|
||||
&mut self,
|
||||
address: u8,
|
||||
wr_buffer: &[u8],
|
||||
rd_buffer: &mut [u8],
|
||||
inten: bool,
|
||||
) -> Result<(), Error> {
|
||||
match self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, inten) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(Error::BufferNotInRAM) => {
|
||||
trace!("Copying TWIM tx buffer into RAM for DMA");
|
||||
let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
||||
tx_ram_buf.copy_from_slice(wr_buffer);
|
||||
self.setup_write_read_from_ram(address, tx_ram_buf, rd_buffer, inten)
|
||||
}
|
||||
Err(error) => Err(error),
|
||||
// ===========================================
|
||||
|
||||
/// Execute the provided operations on the I2C bus.
|
||||
///
|
||||
/// Each buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
///
|
||||
/// Consecutive `Operation::Read`s are not supported due to hardware
|
||||
/// limitations.
|
||||
///
|
||||
/// An `Operation::Write` following an `Operation::Read` must have a
|
||||
/// non-empty buffer.
|
||||
pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> {
|
||||
let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
|
||||
let mut last_op = None;
|
||||
while !operations.is_empty() {
|
||||
let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?;
|
||||
let (in_progress, rest) = operations.split_at_mut(ops);
|
||||
self.blocking_wait();
|
||||
self.check_operations(in_progress)?;
|
||||
last_op = in_progress.last();
|
||||
operations = rest;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_write(&mut self, address: u8, wr_buffer: &[u8], inten: bool) -> Result<(), Error> {
|
||||
match self.setup_write_from_ram(address, wr_buffer, inten) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(Error::BufferNotInRAM) => {
|
||||
trace!("Copying TWIM tx buffer into RAM for DMA");
|
||||
let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
||||
tx_ram_buf.copy_from_slice(wr_buffer);
|
||||
self.setup_write_from_ram(address, tx_ram_buf, inten)
|
||||
}
|
||||
Err(error) => Err(error),
|
||||
/// Same as [`blocking_transaction`](Twim::blocking_transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
pub fn blocking_transaction_from_ram(
|
||||
&mut self,
|
||||
address: u8,
|
||||
mut operations: &mut [Operation<'_>],
|
||||
) -> Result<(), Error> {
|
||||
let mut last_op = None;
|
||||
while !operations.is_empty() {
|
||||
let ops = self.setup_operations(address, operations, None, last_op, false)?;
|
||||
let (in_progress, rest) = operations.split_at_mut(ops);
|
||||
self.blocking_wait();
|
||||
self.check_operations(in_progress)?;
|
||||
last_op = in_progress.last();
|
||||
operations = rest;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute the provided operations on the I2C bus with timeout.
|
||||
///
|
||||
/// See [`blocking_transaction`].
|
||||
#[cfg(feature = "time")]
|
||||
pub fn blocking_transaction_timeout(
|
||||
&mut self,
|
||||
address: u8,
|
||||
mut operations: &mut [Operation<'_>],
|
||||
timeout: Duration,
|
||||
) -> Result<(), Error> {
|
||||
let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
|
||||
let mut last_op = None;
|
||||
while !operations.is_empty() {
|
||||
let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?;
|
||||
let (in_progress, rest) = operations.split_at_mut(ops);
|
||||
self.blocking_wait_timeout(timeout)?;
|
||||
self.check_operations(in_progress)?;
|
||||
last_op = in_progress.last();
|
||||
operations = rest;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Same as [`blocking_transaction_timeout`](Twim::blocking_transaction_timeout) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
#[cfg(feature = "time")]
|
||||
pub fn blocking_transaction_from_ram_timeout(
|
||||
&mut self,
|
||||
address: u8,
|
||||
mut operations: &mut [Operation<'_>],
|
||||
timeout: Duration,
|
||||
) -> Result<(), Error> {
|
||||
let mut last_op = None;
|
||||
while !operations.is_empty() {
|
||||
let ops = self.setup_operations(address, operations, None, last_op, false)?;
|
||||
let (in_progress, rest) = operations.split_at_mut(ops);
|
||||
self.blocking_wait_timeout(timeout)?;
|
||||
self.check_operations(in_progress)?;
|
||||
last_op = in_progress.last();
|
||||
operations = rest;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute the provided operations on the I2C bus.
|
||||
///
|
||||
/// Each buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
///
|
||||
/// Consecutive `Operation::Read`s are not supported due to hardware
|
||||
/// limitations.
|
||||
///
|
||||
/// An `Operation::Write` following an `Operation::Read` must have a
|
||||
/// non-empty buffer.
|
||||
pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> {
|
||||
let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
|
||||
let mut last_op = None;
|
||||
while !operations.is_empty() {
|
||||
let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, true)?;
|
||||
let (in_progress, rest) = operations.split_at_mut(ops);
|
||||
self.async_wait().await;
|
||||
self.check_operations(in_progress)?;
|
||||
last_op = in_progress.last();
|
||||
operations = rest;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Same as [`transaction`](Twim::transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
pub async fn transaction_from_ram(
|
||||
&mut self,
|
||||
address: u8,
|
||||
mut operations: &mut [Operation<'_>],
|
||||
) -> Result<(), Error> {
|
||||
let mut last_op = None;
|
||||
while !operations.is_empty() {
|
||||
let ops = self.setup_operations(address, operations, None, last_op, true)?;
|
||||
let (in_progress, rest) = operations.split_at_mut(ops);
|
||||
self.async_wait().await;
|
||||
self.check_operations(in_progress)?;
|
||||
last_op = in_progress.last();
|
||||
operations = rest;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
|
||||
/// Write to an I2C slave.
|
||||
///
|
||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||
self.setup_write(address, buffer, false)?;
|
||||
self.blocking_wait();
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction(address, &mut [Operation::Write(buffer)])
|
||||
}
|
||||
|
||||
/// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||
self.setup_write_from_ram(address, buffer, false)?;
|
||||
self.blocking_wait();
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)])
|
||||
}
|
||||
|
||||
/// Read from an I2C slave.
|
||||
@ -516,12 +685,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
self.setup_read(address, buffer, false)?;
|
||||
self.blocking_wait();
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_rx(buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction(address, &mut [Operation::Read(buffer)])
|
||||
}
|
||||
|
||||
/// Write data to an I2C slave, then read data from the slave without
|
||||
@ -530,13 +694,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// The buffers must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub fn blocking_write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> {
|
||||
self.setup_write_read(address, wr_buffer, rd_buffer, false)?;
|
||||
self.blocking_wait();
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(wr_buffer.len())?;
|
||||
self.check_rx(rd_buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
|
||||
}
|
||||
|
||||
/// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
@ -546,13 +704,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
wr_buffer: &[u8],
|
||||
rd_buffer: &mut [u8],
|
||||
) -> Result<(), Error> {
|
||||
self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?;
|
||||
self.blocking_wait();
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(wr_buffer.len())?;
|
||||
self.check_rx(rd_buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
@ -562,12 +714,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// See [`blocking_write`].
|
||||
#[cfg(feature = "time")]
|
||||
pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> {
|
||||
self.setup_write(address, buffer, false)?;
|
||||
self.blocking_wait_timeout(timeout)?;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout)
|
||||
}
|
||||
|
||||
/// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
@ -578,12 +725,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
buffer: &[u8],
|
||||
timeout: Duration,
|
||||
) -> Result<(), Error> {
|
||||
self.setup_write_from_ram(address, buffer, false)?;
|
||||
self.blocking_wait_timeout(timeout)?;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], timeout)
|
||||
}
|
||||
|
||||
/// Read from an I2C slave.
|
||||
@ -592,12 +734,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
#[cfg(feature = "time")]
|
||||
pub fn blocking_read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> {
|
||||
self.setup_read(address, buffer, false)?;
|
||||
self.blocking_wait_timeout(timeout)?;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_rx(buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction_timeout(address, &mut [Operation::Read(buffer)], timeout)
|
||||
}
|
||||
|
||||
/// Write data to an I2C slave, then read data from the slave without
|
||||
@ -613,13 +750,11 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
rd_buffer: &mut [u8],
|
||||
timeout: Duration,
|
||||
) -> Result<(), Error> {
|
||||
self.setup_write_read(address, wr_buffer, rd_buffer, false)?;
|
||||
self.blocking_wait_timeout(timeout)?;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(wr_buffer.len())?;
|
||||
self.check_rx(rd_buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction_timeout(
|
||||
address,
|
||||
&mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)],
|
||||
timeout,
|
||||
)
|
||||
}
|
||||
|
||||
/// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
@ -631,13 +766,11 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
rd_buffer: &mut [u8],
|
||||
timeout: Duration,
|
||||
) -> Result<(), Error> {
|
||||
self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?;
|
||||
self.blocking_wait_timeout(timeout)?;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(wr_buffer.len())?;
|
||||
self.check_rx(rd_buffer.len())?;
|
||||
Ok(())
|
||||
self.blocking_transaction_from_ram_timeout(
|
||||
address,
|
||||
&mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)],
|
||||
timeout,
|
||||
)
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
@ -647,12 +780,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
self.setup_read(address, buffer, true)?;
|
||||
self.async_wait().await;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_rx(buffer.len())?;
|
||||
Ok(())
|
||||
self.transaction(address, &mut [Operation::Read(buffer)]).await
|
||||
}
|
||||
|
||||
/// Write to an I2C slave.
|
||||
@ -660,22 +788,13 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||
self.setup_write(address, buffer, true)?;
|
||||
self.async_wait().await;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(buffer.len())?;
|
||||
Ok(())
|
||||
self.transaction(address, &mut [Operation::Write(buffer)]).await
|
||||
}
|
||||
|
||||
/// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||
self.setup_write_from_ram(address, buffer, true)?;
|
||||
self.async_wait().await;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(buffer.len())?;
|
||||
Ok(())
|
||||
self.transaction_from_ram(address, &mut [Operation::Write(buffer)])
|
||||
.await
|
||||
}
|
||||
|
||||
/// Write data to an I2C slave, then read data from the slave without
|
||||
@ -684,13 +803,8 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// The buffers must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> {
|
||||
self.setup_write_read(address, wr_buffer, rd_buffer, true)?;
|
||||
self.async_wait().await;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(wr_buffer.len())?;
|
||||
self.check_rx(rd_buffer.len())?;
|
||||
Ok(())
|
||||
self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
|
||||
.await
|
||||
}
|
||||
|
||||
/// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||
@ -700,13 +814,8 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
wr_buffer: &[u8],
|
||||
rd_buffer: &mut [u8],
|
||||
) -> Result<(), Error> {
|
||||
self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, true)?;
|
||||
self.async_wait().await;
|
||||
compiler_fence(SeqCst);
|
||||
self.check_errorsrc()?;
|
||||
self.check_tx(wr_buffer.len())?;
|
||||
self.check_rx(rd_buffer.len())?;
|
||||
Ok(())
|
||||
self.transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@ -777,16 +886,7 @@ mod eh02 {
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
|
||||
if slice_in_ram(bytes) {
|
||||
self.blocking_write(addr, bytes)
|
||||
} else {
|
||||
let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..];
|
||||
for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) {
|
||||
buf[..chunk.len()].copy_from_slice(chunk);
|
||||
self.blocking_write(addr, &buf[..chunk.len()])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
self.blocking_write(addr, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
@ -832,47 +932,14 @@ impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> {
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> {
|
||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_read(address, buffer)
|
||||
}
|
||||
|
||||
fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_write(address, buffer)
|
||||
}
|
||||
|
||||
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_write_read(address, wr_buffer, rd_buffer)
|
||||
}
|
||||
|
||||
fn transaction(
|
||||
&mut self,
|
||||
_address: u8,
|
||||
_operations: &mut [embedded_hal_1::i2c::Operation<'_>],
|
||||
) -> Result<(), Self::Error> {
|
||||
todo!();
|
||||
fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {
|
||||
self.blocking_transaction(address, operations)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> {
|
||||
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.read(address, read).await
|
||||
}
|
||||
|
||||
async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
||||
self.write(address, write).await
|
||||
}
|
||||
async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.write_read(address, write, read).await
|
||||
}
|
||||
|
||||
async fn transaction(
|
||||
&mut self,
|
||||
address: u8,
|
||||
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
|
||||
) -> Result<(), Self::Error> {
|
||||
let _ = address;
|
||||
let _ = operations;
|
||||
todo!()
|
||||
async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {
|
||||
self.transaction(address, operations).await
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user