Refactoring and cleanup

This commit is contained in:
Alex Moon 2024-08-21 10:57:14 -04:00
parent 110d87bbd2
commit 55805de05b
No known key found for this signature in database
GPG Key ID: A6D388B98A7DB071

View File

@ -311,6 +311,7 @@ impl<'d, T: Instance> Twim<'d, T> {
let r = T::regs(); let r = T::regs();
loop { loop {
if r.events_suspended.read().bits() != 0 || 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(); r.events_stopped.reset();
break; break;
} }
@ -372,15 +373,15 @@ impl<'d, T: Instance> Twim<'d, T> {
address: u8, address: u8,
operations: &mut [Operation<'_>], operations: &mut [Operation<'_>],
tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>, tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
last_op: Option<&Operation<'_>>,
inten: bool, inten: bool,
) -> Result<(), Error> { ) -> Result<usize, Error> {
let r = T::regs(); let r = T::regs();
compiler_fence(SeqCst); compiler_fence(SeqCst);
r.address.write(|w| unsafe { w.address().bits(address) }); r.address.write(|w| unsafe { w.address().bits(address) });
let was_suspended = r.events_suspended.read().bits() != 0;
r.events_suspended.reset(); r.events_suspended.reset();
r.events_stopped.reset(); r.events_stopped.reset();
r.events_error.reset(); r.events_error.reset();
@ -393,10 +394,12 @@ impl<'d, T: Instance> Twim<'d, T> {
.write(|w| w.suspended().clear().stopped().clear().error().clear()); .write(|w| w.suspended().clear().stopped().clear().error().clear());
} }
assert!(!operations.is_empty());
match operations { match operations {
[Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] [Operation::Read(_), Operation::Read(_), ..] => {
if !rd_buffer.is_empty() && !wr_buffer.is_empty() => panic!("Consecutive read operations are not supported!")
{ }
[Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] => {
let stop = rest.is_empty(); let stop = rest.is_empty();
// Set up DMA buffers. // Set up DMA buffers.
@ -417,10 +420,38 @@ impl<'d, T: Instance> Twim<'d, T> {
// Start read+write operation. // Start read+write operation.
r.tasks_startrx.write(|w| unsafe { w.bits(1) }); r.tasks_startrx.write(|w| unsafe { w.bits(1) });
if last_op.is_some() {
if was_suspended {
r.tasks_resume.write(|w| unsafe { w.bits(1) }); 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)] [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]
if !wr_buffer.is_empty() && !rd_buffer.is_empty() => if !wr_buffer.is_empty() && !rd_buffer.is_empty() =>
@ -439,36 +470,11 @@ impl<'d, T: Instance> Twim<'d, T> {
}); });
r.tasks_starttx.write(|w| unsafe { w.bits(1) }); r.tasks_starttx.write(|w| unsafe { w.bits(1) });
if last_op.is_some() {
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 {
r.tasks_resume.write(|w| unsafe { w.bits(1) }); r.tasks_resume.write(|w| unsafe { w.bits(1) });
} }
if buffer.is_empty() { Ok(2)
// 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!");
} }
[Operation::Write(buffer), rest @ ..] => { [Operation::Write(buffer), rest @ ..] => {
let stop = rest.is_empty(); let stop = rest.is_empty();
@ -489,8 +495,7 @@ impl<'d, T: Instance> Twim<'d, T> {
}); });
r.tasks_starttx.write(|w| unsafe { w.bits(1) }); r.tasks_starttx.write(|w| unsafe { w.bits(1) });
if last_op.is_some() {
if was_suspended {
r.tasks_resume.write(|w| unsafe { w.bits(1) }); r.tasks_resume.write(|w| unsafe { w.bits(1) });
} }
@ -502,43 +507,33 @@ impl<'d, T: Instance> Twim<'d, T> {
r.tasks_suspend.write(|w| unsafe { w.bits(1) }); 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); compiler_fence(SeqCst);
self.check_errorsrc()?; self.check_errorsrc()?;
assert!(operations.len() == 1 || operations.len() == 2);
match operations { match operations {
[Operation::Read(rd_buffer), Operation::Write(wr_buffer), ..] [Operation::Read(rd_buffer), Operation::Write(wr_buffer)]
| [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] => {
if !rd_buffer.is_empty() && !wr_buffer.is_empty() =>
{
self.check_tx(wr_buffer.len())?;
self.check_rx(rd_buffer.len())?; self.check_rx(rd_buffer.len())?;
Ok(2) self.check_tx(wr_buffer.len())?;
} }
[Operation::Read(buffer)] => { [Operation::Read(buffer)] => {
self.check_rx(buffer.len())?; self.check_rx(buffer.len())?;
Ok(1)
} }
[Operation::Read(_), ..] => unreachable!(),
[Operation::Write(buffer), ..] => { [Operation::Write(buffer), ..] => {
self.check_tx(buffer.len())?; self.check_tx(buffer.len())?;
Ok(1)
} }
[] => Ok(0), _ => unreachable!(),
} }
Ok(())
} }
// =========================================== // ===========================================
@ -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 /// Each buffer must have a length of at most 255 bytes on the nRF52832
/// and at most 65535 bytes on the nRF52840. /// and at most 65535 bytes on the nRF52840.
/// ///
/// Consecutive `Read` operations are not supported because the Twim /// Consecutive `Operation::Read`s are not supported due to hardware
/// hardware does not support suspending after a read operation. (Setting /// limitations.
/// 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, /// An `Operation::Write` following an `Operation::Read` must have a
/// one more byte will be read before the new operation is started, leading /// non-empty buffer.
/// 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.)
pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 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 tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
let mut last_op = None;
while !operations.is_empty() { 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(); self.blocking_wait();
let consumed = self.check_operations(operations)?; self.check_operations(in_progress)?;
operations = &mut operations[consumed..]; last_op = in_progress.last();
operations = rest;
} }
Ok(()) Ok(())
} }
@ -572,11 +568,14 @@ impl<'d, T: Instance> Twim<'d, T> {
address: u8, address: u8,
mut operations: &mut [Operation<'_>], mut operations: &mut [Operation<'_>],
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut last_op = None;
while !operations.is_empty() { 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(); self.blocking_wait();
let consumed = self.check_operations(operations)?; self.check_operations(in_progress)?;
operations = &mut operations[consumed..]; last_op = in_progress.last();
operations = rest;
} }
Ok(()) Ok(())
} }
@ -592,11 +591,14 @@ impl<'d, T: Instance> Twim<'d, T> {
timeout: Duration, timeout: Duration,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
let mut last_op = None;
while !operations.is_empty() { 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)?; self.blocking_wait_timeout(timeout)?;
let consumed = self.check_operations(operations)?; self.check_operations(in_progress)?;
operations = &mut operations[consumed..]; last_op = in_progress.last();
operations = rest;
} }
Ok(()) Ok(())
} }
@ -609,11 +611,14 @@ impl<'d, T: Instance> Twim<'d, T> {
mut operations: &mut [Operation<'_>], mut operations: &mut [Operation<'_>],
timeout: Duration, timeout: Duration,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut last_op = None;
while !operations.is_empty() { 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)?; self.blocking_wait_timeout(timeout)?;
let consumed = self.check_operations(operations)?; self.check_operations(in_progress)?;
operations = &mut operations[consumed..]; last_op = in_progress.last();
operations = rest;
} }
Ok(()) Ok(())
} }
@ -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 /// Each buffer must have a length of at most 255 bytes on the nRF52832
/// and at most 65535 bytes on the nRF52840. /// and at most 65535 bytes on the nRF52840.
/// ///
/// Consecutive `Read` operations are not supported because the Twim /// Consecutive `Operation::Read`s are not supported due to hardware
/// hardware does not support suspending after a read operation. (Setting /// limitations.
/// 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, /// An `Operation::Write` following an `Operation::Read` must have a
/// one more byte will be read before the new operation is started, leading /// non-empty buffer.
/// 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.)
pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 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 tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
let mut last_op = None;
while !operations.is_empty() { 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; self.async_wait().await;
let consumed = self.check_operations(operations)?; self.check_operations(in_progress)?;
operations = &mut operations[consumed..]; last_op = in_progress.last();
operations = rest;
} }
Ok(()) Ok(())
} }
@ -647,11 +653,14 @@ impl<'d, T: Instance> Twim<'d, T> {
address: u8, address: u8,
mut operations: &mut [Operation<'_>], mut operations: &mut [Operation<'_>],
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut last_op = None;
while !operations.is_empty() { 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; self.async_wait().await;
let consumed = self.check_operations(operations)?; self.check_operations(in_progress)?;
operations = &mut operations[consumed..]; last_op = in_progress.last();
operations = rest;
} }
Ok(()) Ok(())
} }