Skip to content

Commit

Permalink
Refactoring and cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmoon committed Aug 21, 2024
1 parent f83bf01 commit fcf87a6
Showing 1 changed file with 95 additions and 86 deletions.
181 changes: 95 additions & 86 deletions embassy-nrf/src/twim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ impl<'d, T: Instance> Twim<'d, T> {
let r = T::regs();
loop {
if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 {
r.events_suspended.reset();
r.events_stopped.reset();
break;
}
Expand Down Expand Up @@ -372,15 +373,15 @@ impl<'d, T: Instance> Twim<'d, T> {
address: 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) });

let was_suspended = r.events_suspended.read().bits() != 0;
r.events_suspended.reset();
r.events_stopped.reset();
r.events_error.reset();
Expand All @@ -393,10 +394,12 @@ impl<'d, T: Instance> Twim<'d, T> {
.write(|w| w.suspended().clear().stopped().clear().error().clear());
}

assert!(!operations.is_empty());
match operations {
[Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..]
if !rd_buffer.is_empty() && !wr_buffer.is_empty() =>
{
[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.
Expand All @@ -417,10 +420,38 @@ impl<'d, T: Instance> Twim<'d, T> {

// 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) });
}

if was_suspended {
// 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() =>
Expand All @@ -439,36 +470,11 @@ impl<'d, T: Instance> Twim<'d, T> {
});

r.tasks_starttx.write(|w| unsafe { w.bits(1) });

if was_suspended {
r.tasks_resume.write(|w| unsafe { w.bits(1) });
}
}
[Operation::Read(buffer)] => {
// Set up DMA buffers.
unsafe {
self.set_rx_buffer(buffer)?;
}

// Start read operation.
r.shorts.write(|w| {
w.lastrx_stop().enabled();
w
});

r.tasks_startrx.write(|w| unsafe { w.bits(1) });

if was_suspended {
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) });
}
}
[Operation::Read(_), ..] => {
panic!("Suspending after a read is not supported!");
Ok(2)
}
[Operation::Write(buffer), rest @ ..] => {
let stop = rest.is_empty();
Expand All @@ -489,8 +495,7 @@ impl<'d, T: Instance> Twim<'d, T> {
});

r.tasks_starttx.write(|w| unsafe { w.bits(1) });

if was_suspended {
if last_op.is_some() {
r.tasks_resume.write(|w| unsafe { w.bits(1) });
}

Expand All @@ -502,43 +507,33 @@ impl<'d, T: Instance> Twim<'d, T> {
r.tasks_suspend.write(|w| unsafe { w.bits(1) });
}
}
}
[] => {
if was_suspended {
r.tasks_resume.write(|w| unsafe { w.bits(1) });
}

r.tasks_stop.write(|w| unsafe { w.bits(1) });
Ok(1)
}
[] => unreachable!(),
}

Ok(())
}

fn check_operations(&mut self, operations: &mut [Operation<'_>]) -> Result<usize, Error> {
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)]
if !rd_buffer.is_empty() && !wr_buffer.is_empty() =>
{
self.check_tx(wr_buffer.len())?;
[Operation::Read(rd_buffer), Operation::Write(wr_buffer)]
| [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] => {
self.check_rx(rd_buffer.len())?;
Ok(2)
self.check_tx(wr_buffer.len())?;
}
[Operation::Read(buffer)] => {
self.check_rx(buffer.len())?;
Ok(1)
}
[Operation::Read(_), ..] => unreachable!(),
[Operation::Write(buffer), ..] => {
self.check_tx(buffer.len())?;
Ok(1)
}
[] => Ok(0),
_ => unreachable!(),
}
Ok(())
}

// ===========================================
Expand All @@ -548,20 +543,21 @@ impl<'d, T: Instance> Twim<'d, T> {
/// Each buffer must have a length of at most 255 bytes on the nRF52832
/// and at most 65535 bytes on the nRF52840.
///
/// Consecutive `Read` operations are not supported because the Twim
/// hardware does not support suspending after a read operation. (Setting
/// the SUSPEND task in response to a LASTRX event causes the final byte of
/// the operation to be ACKed instead of NAKed. When the TWIM is resumed,
/// one more byte will be read before the new operation is started, leading
/// to an Overrun error if the RXD has not been updated, or an extraneous
/// byte read into the new buffer if the RXD has been updated.)
/// 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() {
self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false)?;
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();
let consumed = self.check_operations(operations)?;
operations = &mut operations[consumed..];
self.check_operations(in_progress)?;
last_op = in_progress.last();
operations = rest;
}
Ok(())
}
Expand All @@ -572,11 +568,14 @@ impl<'d, T: Instance> Twim<'d, T> {
address: u8,
mut operations: &mut [Operation<'_>],
) -> Result<(), Error> {
let mut last_op = None;
while !operations.is_empty() {
self.setup_operations(address, operations, None, false)?;
let ops = self.setup_operations(address, operations, None, last_op, false)?;
let (in_progress, rest) = operations.split_at_mut(ops);
self.blocking_wait();
let consumed = self.check_operations(operations)?;
operations = &mut operations[consumed..];
self.check_operations(in_progress)?;
last_op = in_progress.last();
operations = rest;
}
Ok(())
}
Expand All @@ -592,11 +591,14 @@ impl<'d, T: Instance> Twim<'d, T> {
timeout: Duration,
) -> Result<(), Error> {
let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
let mut last_op = None;
while !operations.is_empty() {
self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false)?;
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)?;
let consumed = self.check_operations(operations)?;
operations = &mut operations[consumed..];
self.check_operations(in_progress)?;
last_op = in_progress.last();
operations = rest;
}
Ok(())
}
Expand All @@ -609,11 +611,14 @@ impl<'d, T: Instance> Twim<'d, T> {
mut operations: &mut [Operation<'_>],
timeout: Duration,
) -> Result<(), Error> {
let mut last_op = None;
while !operations.is_empty() {
self.setup_operations(address, operations, None, false)?;
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)?;
let consumed = self.check_operations(operations)?;
operations = &mut operations[consumed..];
self.check_operations(in_progress)?;
last_op = in_progress.last();
operations = rest;
}
Ok(())
}
Expand All @@ -623,20 +628,21 @@ impl<'d, T: Instance> Twim<'d, T> {
/// Each buffer must have a length of at most 255 bytes on the nRF52832
/// and at most 65535 bytes on the nRF52840.
///
/// Consecutive `Read` operations are not supported because the Twim
/// hardware does not support suspending after a read operation. (Setting
/// the SUSPEND task in response to a LASTRX event causes the final byte of
/// the operation to be ACKed instead of NAKed. When the TWIM is resumed,
/// one more byte will be read before the new operation is started, leading
/// to an Overrun error if the RXD has not been updated, or an extraneous
/// byte read into the new buffer if the RXD has been updated.)
/// 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() {
self.setup_operations(address, operations, Some(&mut tx_ram_buffer), true)?;
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;
let consumed = self.check_operations(operations)?;
operations = &mut operations[consumed..];
self.check_operations(in_progress)?;
last_op = in_progress.last();
operations = rest;
}
Ok(())
}
Expand All @@ -647,11 +653,14 @@ impl<'d, T: Instance> Twim<'d, T> {
address: u8,
mut operations: &mut [Operation<'_>],
) -> Result<(), Error> {
let mut last_op = None;
while !operations.is_empty() {
self.setup_operations(address, operations, None, true)?;
let ops = self.setup_operations(address, operations, None, last_op, true)?;
let (in_progress, rest) = operations.split_at_mut(ops);
self.async_wait().await;
let consumed = self.check_operations(operations)?;
operations = &mut operations[consumed..];
self.check_operations(in_progress)?;
last_op = in_progress.last();
operations = rest;
}
Ok(())
}
Expand Down

0 comments on commit fcf87a6

Please sign in to comment.