From 85ff92c7b3200e761b62871bdd340d3162fb9f02 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 11 Apr 2024 15:35:19 +0100 Subject: [PATCH 1/7] Implement embedded-hal 1.0 I2c for Twi. --- nrf-hal-common/src/twi.rs | 97 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/nrf-hal-common/src/twi.rs b/nrf-hal-common/src/twi.rs index ffdbcded..e8ee0059 100644 --- a/nrf-hal-common/src/twi.rs +++ b/nrf-hal-common/src/twi.rs @@ -1,11 +1,11 @@ //! HAL interface to the TWI peripheral. -use core::ops::Deref; - use crate::{ gpio::{Floating, Input, Pin}, pac::{twi0, GPIO, TWI0, TWI1}, }; +use core::ops::Deref; +use embedded_hal::i2c::{self, ErrorKind, ErrorType, I2c, Operation}; pub use twi0::frequency::FREQUENCY_A as Frequency; @@ -250,6 +250,92 @@ where } } +impl ErrorType for Twi { + type Error = Error; +} + +impl I2c for Twi { + fn transaction( + &mut self, + address: u8, + operations: &mut [Operation], + ) -> Result<(), Self::Error> { + // Make sure all previously used shortcuts are disabled. + self.0 + .shorts + .write(|w| w.bb_stop().disabled().bb_suspend().disabled()); + + // Set Slave I2C address. + self.0 + .address + .write(|w| unsafe { w.address().bits(address.into()) }); + + // `Some(true)` if the last operation was a read, `Some(false)` if it was a write. + let mut last_operation_read = None; + let operations_count = operations.len(); + for (i, operation) in operations.into_iter().enumerate() { + match operation { + Operation::Read(buffer) => { + // Clear reception event. + self.0.events_rxdready.write(|w| unsafe { w.bits(0) }); + + if last_operation_read != Some(true) { + // Start data reception. + self.0.tasks_startrx.write(|w| unsafe { w.bits(1) }); + } + + if let Some((last, before)) = buffer.split_last_mut() { + for byte in before { + *byte = self.recv_byte()?; + } + + if i == operations_count - 1 { + // Send stop after receiving the last byte. + self.0.events_stopped.write(|w| unsafe { w.bits(0) }); + self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); + + *last = self.recv_byte()?; + + // Wait until stop was sent. + while self.0.events_stopped.read().bits() == 0 { + // Bail out if we get an error instead. + if self.0.events_error.read().bits() != 0 { + self.0.events_error.write(|w| unsafe { w.bits(0) }); + return Err(Error::Transmit); + } + } + } else { + *last = self.recv_byte()?; + } + } else { + self.send_stop()?; + } + last_operation_read = Some(true); + } + Operation::Write(buffer) => { + if last_operation_read != Some(false) { + // Start data transmission. + self.0.tasks_starttx.write(|w| unsafe { w.bits(1) }); + } + + // Clock out all bytes. + for byte in *buffer { + self.send_byte(*byte)?; + } + + if i == operations_count - 1 { + // Send stop. + self.send_stop()?; + } + last_operation_read = Some(false); + } + } + } + + Ok(()) + } +} + #[cfg(feature = "embedded-hal-02")] impl embedded_hal_02::blocking::i2c::Write for Twi where @@ -308,6 +394,13 @@ pub enum Error { Receive, } +impl i2c::Error for Error { + fn kind(&self) -> ErrorKind { + // TODO + ErrorKind::Other + } +} + /// Implemented by all TWIM instances. pub trait Instance: Deref + sealed::Sealed {} From 5049fc938a55ed584785be6f6b8e039116e236eb Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 11 Apr 2024 15:35:42 +0100 Subject: [PATCH 2/7] Implement embedded-hal 1.0 I2c for Twim. --- nrf-hal-common/src/twim.rs | 140 +++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/nrf-hal-common/src/twim.rs b/nrf-hal-common/src/twim.rs index e16bd636..056ae7f0 100644 --- a/nrf-hal-common/src/twim.rs +++ b/nrf-hal-common/src/twim.rs @@ -6,6 +6,7 @@ //! - nRF52840: Section 6.31 use core::ops::Deref; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; +use embedded_hal::i2c::{self, ErrorKind, ErrorType, I2c, NoAcknowledgeSource, Operation}; #[cfg(any(feature = "9160", feature = "5340-app", feature = "5340-net"))] use crate::pac::{twim0_ns as twim0, TWIM0_NS as TWIM0}; @@ -194,6 +195,10 @@ where self.0.events_stopped.reset(); break; } + if self.0.events_suspended.read().bits() != 0 { + self.0.events_suspended.reset(); + break; + } if self.0.events_error.read().bits() != 0 { self.0.events_error.reset(); self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); @@ -392,6 +397,124 @@ where }, ) } + + fn write_part( + &mut self, + buffer: &[u8], + last_operation_read: Option, + final_operation: bool, + ) -> Result<(), Error> { + unsafe { self.set_tx_buffer(buffer)? }; + + // Set appropriate lasttx shortcut. + if final_operation { + self.0.shorts.write(|w| w.lasttx_stop().enabled()); + } else { + self.0.shorts.write(|w| w.lasttx_suspend().enabled()); + } + + if last_operation_read != Some(false) { + // Start write. + self.0.tasks_starttx.write(|w| unsafe { w.bits(1) }); + } + self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); + + self.wait(); + self.read_errorsrc()?; + if self.0.txd.amount.read().bits() != buffer.len() as u32 { + return Err(Error::Transmit); + } + + Ok(()) + } +} + +impl ErrorType for Twim { + type Error = Error; +} + +impl I2c for Twim { + fn transaction( + &mut self, + address: u8, + operations: &mut [Operation], + ) -> Result<(), Self::Error> { + compiler_fence(SeqCst); + + self.0 + .address + .write(|w| unsafe { w.address().bits(address) }); + + // `Some(true)` if the last operation was a read, `Some(false)` if it was a write. + let mut last_operation_read = None; + let operations_count = operations.len(); + for (i, operation) in operations.into_iter().enumerate() { + // Clear events + self.0.events_stopped.reset(); + self.0.events_error.reset(); + self.0.events_lasttx.reset(); + self.0.events_lastrx.reset(); + self.clear_errorsrc(); + + match operation { + Operation::Read(buffer) => { + unsafe { self.set_rx_buffer(buffer)? }; + + // Set appropriate lastrx shortcut. + if i == operations_count - 1 { + self.0.shorts.write(|w| w.lastrx_stop().enabled()); + } else { + #[cfg(not(any( + feature = "5340-app", + feature = "5340-net", + feature = "52832" + )))] + self.0.shorts.write(|w| w.lastrx_suspend().enabled()); + } + + if last_operation_read != Some(true) { + // Start read. + self.0.tasks_startrx.write(|w| unsafe { w.bits(1) }); + } + self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); + + self.wait(); + self.read_errorsrc()?; + if self.0.rxd.amount.read().bits() != buffer.len() as u32 { + return Err(Error::Receive); + } + + last_operation_read = Some(true); + } + Operation::Write(buffer) => { + if crate::slice_in_ram(buffer) { + self.write_part(buffer, last_operation_read, i == operations_count - 1)?; + } else if buffer.len() > FORCE_COPY_BUFFER_SIZE { + return Err(Error::TxBufferTooLong); + } else { + let mut copy = [0; FORCE_COPY_BUFFER_SIZE]; + let num_chunks = buffer.len().div_ceil(FORCE_COPY_BUFFER_SIZE); + for (chunk_index, chunk) in buffer + .chunks(FORCE_COPY_BUFFER_SIZE) + .into_iter() + .enumerate() + { + copy[..chunk.len()].copy_from_slice(chunk); + self.write_part( + ©[..chunk.len()], + last_operation_read, + i == operations_count - 1 && chunk_index == num_chunks - 1, + )?; + } + } + + last_operation_read = Some(false); + } + } + } + + Ok(()) + } } #[cfg(feature = "embedded-hal-02")] @@ -473,6 +596,23 @@ pub enum Error { Overrun, } +impl i2c::Error for Error { + fn kind(&self) -> ErrorKind { + match self { + Self::TxBufferTooLong + | Self::RxBufferTooLong + | Self::TxBufferZeroLength + | Self::RxBufferZeroLength + | Self::Transmit + | Self::Receive + | Self::DMABufferNotInDataMemory => ErrorKind::Other, + Self::AddressNack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address), + Self::DataNack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data), + Self::Overrun => ErrorKind::Overrun, + } + } +} + /// Implemented by all TWIM instances pub trait Instance: Deref + sealed::Sealed {} From 1b6424eeae2a909041b7ae40c36c96413fe327ee Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 12 Apr 2024 17:51:02 +0100 Subject: [PATCH 3/7] Combine consecutive writes via temporary buffer. --- nrf-hal-common/src/twim.rs | 91 ++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 32 deletions(-) diff --git a/nrf-hal-common/src/twim.rs b/nrf-hal-common/src/twim.rs index 056ae7f0..be7067b5 100644 --- a/nrf-hal-common/src/twim.rs +++ b/nrf-hal-common/src/twim.rs @@ -398,12 +398,7 @@ where ) } - fn write_part( - &mut self, - buffer: &[u8], - last_operation_read: Option, - final_operation: bool, - ) -> Result<(), Error> { + fn write_part(&mut self, buffer: &[u8], final_operation: bool) -> Result<(), Error> { unsafe { self.set_tx_buffer(buffer)? }; // Set appropriate lasttx shortcut. @@ -413,10 +408,8 @@ where self.0.shorts.write(|w| w.lasttx_suspend().enabled()); } - if last_operation_read != Some(false) { - // Start write. - self.0.tasks_starttx.write(|w| unsafe { w.bits(1) }); - } + // Start write. + self.0.tasks_starttx.write(|w| unsafe { w.bits(1) }); self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); self.wait(); @@ -441,14 +434,23 @@ impl I2c for Twim { ) -> Result<(), Self::Error> { compiler_fence(SeqCst); + // Buffer used when writing data from flash, or combining multiple consecutive write operations. + let mut tx_copy = [0; FORCE_COPY_BUFFER_SIZE]; + // Number of bytes waiting in `tx_copy` to be sent. + let mut pending_tx_bytes = 0; + self.0 .address .write(|w| unsafe { w.address().bits(address) }); - // `Some(true)` if the last operation was a read, `Some(false)` if it was a write. - let mut last_operation_read = None; - let operations_count = operations.len(); - for (i, operation) in operations.into_iter().enumerate() { + for i in 0..operations.len() { + let next_operation_write = match operations.get(i + 1) { + None => None, + Some(Operation::Write(_)) => Some(true), + Some(Operation::Read(_)) => Some(false), + }; + let operation = &mut operations[i]; + // Clear events self.0.events_stopped.reset(); self.0.events_error.reset(); @@ -461,7 +463,7 @@ impl I2c for Twim { unsafe { self.set_rx_buffer(buffer)? }; // Set appropriate lastrx shortcut. - if i == operations_count - 1 { + if next_operation_write.is_none() { self.0.shorts.write(|w| w.lastrx_stop().enabled()); } else { #[cfg(not(any( @@ -472,10 +474,8 @@ impl I2c for Twim { self.0.shorts.write(|w| w.lastrx_suspend().enabled()); } - if last_operation_read != Some(true) { - // Start read. - self.0.tasks_startrx.write(|w| unsafe { w.bits(1) }); - } + // Start read. + self.0.tasks_startrx.write(|w| unsafe { w.bits(1) }); self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); self.wait(); @@ -483,32 +483,59 @@ impl I2c for Twim { if self.0.rxd.amount.read().bits() != buffer.len() as u32 { return Err(Error::Receive); } - - last_operation_read = Some(true); } Operation::Write(buffer) => { - if crate::slice_in_ram(buffer) { - self.write_part(buffer, last_operation_read, i == operations_count - 1)?; + // Will the current buffer fit in the remaining space in `tx_copy`? If not, + // send `tx_copy` immediately. + if buffer.len() > FORCE_COPY_BUFFER_SIZE - pending_tx_bytes + && pending_tx_bytes > 0 + { + self.write_part(&tx_copy[..pending_tx_bytes], false)?; + pending_tx_bytes = 0; + } + + if crate::slice_in_ram(buffer) + && pending_tx_bytes == 0 + && next_operation_write != Some(true) + { + // Simple case: the buffer is in RAM, and there are no consecutive write + // operations, so send it directly. + self.write_part(buffer, next_operation_write.is_none())?; } else if buffer.len() > FORCE_COPY_BUFFER_SIZE { - return Err(Error::TxBufferTooLong); - } else { - let mut copy = [0; FORCE_COPY_BUFFER_SIZE]; + // This must be true because if it wasn't we must have hit the case above to send + // `tx_copy` immediately and reset `pending_tx_bytes` to 0. + assert!(pending_tx_bytes == 0); + + // Send the buffer in chunks immediately. let num_chunks = buffer.len().div_ceil(FORCE_COPY_BUFFER_SIZE); for (chunk_index, chunk) in buffer .chunks(FORCE_COPY_BUFFER_SIZE) .into_iter() .enumerate() { - copy[..chunk.len()].copy_from_slice(chunk); + tx_copy[..chunk.len()].copy_from_slice(chunk); + self.write_part( + &tx_copy[..chunk.len()], + next_operation_write.is_none() && chunk_index == num_chunks - 1, + )?; + } + } else { + // Copy the current buffer to `tx_copy`. It must fit, as otherwise we + // would have hit one of the cases above. + tx_copy[pending_tx_bytes..pending_tx_bytes + buffer.len()] + .copy_from_slice(&buffer); + pending_tx_bytes += buffer.len(); + + // If the next operation is not a write (or there is no next operation), + // send `tx_copy` now. + if next_operation_write != Some(true) { self.write_part( - ©[..chunk.len()], - last_operation_read, - i == operations_count - 1 && chunk_index == num_chunks - 1, + &tx_copy[..pending_tx_bytes], + next_operation_write == None, )?; + pending_tx_bytes = 0; } } - - last_operation_read = Some(false); } } } From f96389afef220f24fc7490e0b14a5b5e9651184a Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Mon, 15 Apr 2024 14:57:07 +0100 Subject: [PATCH 4/7] Combine consecutive reads. --- nrf-hal-common/src/twim.rs | 79 ++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/nrf-hal-common/src/twim.rs b/nrf-hal-common/src/twim.rs index be7067b5..79c52ae3 100644 --- a/nrf-hal-common/src/twim.rs +++ b/nrf-hal-common/src/twim.rs @@ -420,6 +420,31 @@ where Ok(()) } + + fn read_part(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + compiler_fence(SeqCst); + unsafe { self.set_rx_buffer(buffer)? }; + + // Set appropriate lastrx shortcut. + if next_operation_write.is_none() { + self.0.shorts.write(|w| w.lastrx_stop().enabled()); + } else { + #[cfg(not(any(feature = "5340-app", feature = "5340-net", feature = "52832")))] + self.0.shorts.write(|w| w.lastrx_suspend().enabled()); + } + + // Start read. + self.0.tasks_startrx.write(|w| unsafe { w.bits(1) }); + self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); + + self.wait(); + self.read_errorsrc()?; + if self.0.rxd.amount.read().bits() != buffer.len() as u32 { + return Err(Error::Receive); + } + + Ok(()) + } } impl ErrorType for Twim { @@ -438,6 +463,10 @@ impl I2c for Twim { let mut tx_copy = [0; FORCE_COPY_BUFFER_SIZE]; // Number of bytes waiting in `tx_copy` to be sent. let mut pending_tx_bytes = 0; + // Buffer used when combining multiple consecutive read operations. + let mut rx_copy = [0; FORCE_COPY_BUFFER_SIZE]; + // Number of bytes from earlier read operations not yet actually read. + let mut pending_rx_bytes = 0; self.0 .address @@ -460,28 +489,36 @@ impl I2c for Twim { match operation { Operation::Read(buffer) => { - unsafe { self.set_rx_buffer(buffer)? }; - - // Set appropriate lastrx shortcut. - if next_operation_write.is_none() { - self.0.shorts.write(|w| w.lastrx_stop().enabled()); + if buffer.len() > FORCE_COPY_BUFFER_SIZE - pending_rx_bytes { + // Splitting into multiple reads isn't going to work, so just return an + // error. + return Err(Error::RxBufferTooLong); + } else if pending_rx_bytes == 0 && next_operation_write != Some(false) { + // Simple case: there are no consecutive read operations, so receive + // directly. + self.read_part(buffer)?; } else { - #[cfg(not(any( - feature = "5340-app", - feature = "5340-net", - feature = "52832" - )))] - self.0.shorts.write(|w| w.lastrx_suspend().enabled()); - } - - // Start read. - self.0.tasks_startrx.write(|w| unsafe { w.bits(1) }); - self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); - - self.wait(); - self.read_errorsrc()?; - if self.0.rxd.amount.read().bits() != buffer.len() as u32 { - return Err(Error::Receive); + pending_rx_bytes += buffer.len(); + + // If the next operation is not a read (or these is no next operation), + // receive into `rx_copy` now. + if next_operation_write != Some(false) { + self.read_part(&mut rx_copy[..pending_rx_bytes])?; + + // Copy the resulting data back to the various buffers. + for j in (0..=i).rev() { + if let Operation::Read(buffer) = &mut operations[j] { + buffer.copy_from_slice( + &rx_copy[pending_rx_bytes - buffer.len()..pending_rx_bytes], + ); + pending_rx_bytes -= buffer.len(); + } else { + break; + } + } + + assert_eq!(pending_rx_bytes, 0); + } } } Operation::Write(buffer) => { From 2001114efa8b87d5b88d11d66ce799e7dcae8a0a Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Mon, 15 Apr 2024 15:17:29 +0100 Subject: [PATCH 5/7] Always stop after reading. For some reason suspending causes subsequent reads to overrun. --- nrf-hal-common/src/twim.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/nrf-hal-common/src/twim.rs b/nrf-hal-common/src/twim.rs index 79c52ae3..d53b9695 100644 --- a/nrf-hal-common/src/twim.rs +++ b/nrf-hal-common/src/twim.rs @@ -425,13 +425,10 @@ where compiler_fence(SeqCst); unsafe { self.set_rx_buffer(buffer)? }; - // Set appropriate lastrx shortcut. - if next_operation_write.is_none() { - self.0.shorts.write(|w| w.lastrx_stop().enabled()); - } else { - #[cfg(not(any(feature = "5340-app", feature = "5340-net", feature = "52832")))] - self.0.shorts.write(|w| w.lastrx_suspend().enabled()); - } + // TODO: We should suspend rather than stopping if there are more operations to + // follow, but for some reason that results in an overrun error and reading bad + // data in the next read. + self.0.shorts.write(|w| w.lastrx_stop().enabled()); // Start read. self.0.tasks_startrx.write(|w| unsafe { w.bits(1) }); From 450218294c25070a655006b43618fa34dc4cd7fa Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 16 Apr 2024 15:15:24 +0100 Subject: [PATCH 6/7] Use enum rather than boolean. --- nrf-hal-common/src/twim.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/nrf-hal-common/src/twim.rs b/nrf-hal-common/src/twim.rs index d53b9695..2071684d 100644 --- a/nrf-hal-common/src/twim.rs +++ b/nrf-hal-common/src/twim.rs @@ -448,6 +448,12 @@ impl ErrorType for Twim { type Error = Error; } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum OperationType { + Read, + Write, +} + impl I2c for Twim { fn transaction( &mut self, @@ -470,10 +476,10 @@ impl I2c for Twim { .write(|w| unsafe { w.address().bits(address) }); for i in 0..operations.len() { - let next_operation_write = match operations.get(i + 1) { + let next_operation_type = match operations.get(i + 1) { None => None, - Some(Operation::Write(_)) => Some(true), - Some(Operation::Read(_)) => Some(false), + Some(Operation::Write(_)) => Some(OperationType::Write), + Some(Operation::Read(_)) => Some(OperationType::Read), }; let operation = &mut operations[i]; @@ -490,7 +496,9 @@ impl I2c for Twim { // Splitting into multiple reads isn't going to work, so just return an // error. return Err(Error::RxBufferTooLong); - } else if pending_rx_bytes == 0 && next_operation_write != Some(false) { + } else if pending_rx_bytes == 0 + && next_operation_type != Some(OperationType::Read) + { // Simple case: there are no consecutive read operations, so receive // directly. self.read_part(buffer)?; @@ -499,7 +507,7 @@ impl I2c for Twim { // If the next operation is not a read (or these is no next operation), // receive into `rx_copy` now. - if next_operation_write != Some(false) { + if next_operation_type != Some(OperationType::Read) { self.read_part(&mut rx_copy[..pending_rx_bytes])?; // Copy the resulting data back to the various buffers. @@ -530,11 +538,11 @@ impl I2c for Twim { if crate::slice_in_ram(buffer) && pending_tx_bytes == 0 - && next_operation_write != Some(true) + && next_operation_type != Some(OperationType::Write) { // Simple case: the buffer is in RAM, and there are no consecutive write // operations, so send it directly. - self.write_part(buffer, next_operation_write.is_none())?; + self.write_part(buffer, next_operation_type.is_none())?; } else if buffer.len() > FORCE_COPY_BUFFER_SIZE { // This must be true because if it wasn't we must have hit the case above to send // `tx_copy` immediately and reset `pending_tx_bytes` to 0. @@ -550,7 +558,7 @@ impl I2c for Twim { tx_copy[..chunk.len()].copy_from_slice(chunk); self.write_part( &tx_copy[..chunk.len()], - next_operation_write.is_none() && chunk_index == num_chunks - 1, + next_operation_type.is_none() && chunk_index == num_chunks - 1, )?; } } else { @@ -562,10 +570,10 @@ impl I2c for Twim { // If the next operation is not a write (or there is no next operation), // send `tx_copy` now. - if next_operation_write != Some(true) { + if next_operation_type != Some(OperationType::Write) { self.write_part( &tx_copy[..pending_tx_bytes], - next_operation_write == None, + next_operation_type.is_none(), )?; pending_tx_bytes = 0; } From b6cc800a702d75b045631c4d8ed68e81aabd8112 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 16 Apr 2024 15:18:04 +0100 Subject: [PATCH 7/7] Add more compiler fences. --- nrf-hal-common/src/twim.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nrf-hal-common/src/twim.rs b/nrf-hal-common/src/twim.rs index 2071684d..d7eaa827 100644 --- a/nrf-hal-common/src/twim.rs +++ b/nrf-hal-common/src/twim.rs @@ -399,6 +399,7 @@ where } fn write_part(&mut self, buffer: &[u8], final_operation: bool) -> Result<(), Error> { + compiler_fence(SeqCst); unsafe { self.set_tx_buffer(buffer)? }; // Set appropriate lasttx shortcut. @@ -413,6 +414,7 @@ where self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); self.wait(); + compiler_fence(SeqCst); self.read_errorsrc()?; if self.0.txd.amount.read().bits() != buffer.len() as u32 { return Err(Error::Transmit); @@ -435,6 +437,7 @@ where self.0.tasks_resume.write(|w| unsafe { w.bits(1) }); self.wait(); + compiler_fence(SeqCst); self.read_errorsrc()?; if self.0.rxd.amount.read().bits() != buffer.len() as u32 { return Err(Error::Receive);