nrf/twim: expose all functionality as inherent methods.
This commit is contained in:
parent
a287fef687
commit
ecb4f8fb00
3 changed files with 157 additions and 267 deletions
|
@ -201,7 +201,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get Error instance, if any occurred.
|
/// Get Error instance, if any occurred.
|
||||||
fn read_errorsrc(&self) -> Result<(), Error> {
|
fn check_errorsrc(&self) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
let err = r.errorsrc.read();
|
let err = r.errorsrc.read();
|
||||||
|
@ -217,8 +217,26 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_rx(&self, len: usize) -> Result<(), Error> {
|
||||||
|
let r = T::regs();
|
||||||
|
if r.rxd.amount.read().bits() != len as u32 {
|
||||||
|
Err(Error::Receive)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_tx(&self, len: usize) -> Result<(), Error> {
|
||||||
|
let r = T::regs();
|
||||||
|
if r.txd.amount.read().bits() != len as u32 {
|
||||||
|
Err(Error::Transmit)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Wait for stop or error
|
/// Wait for stop or error
|
||||||
fn wait(&mut self) {
|
fn blocking_wait(&mut self) {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
loop {
|
loop {
|
||||||
if r.events_stopped.read().bits() != 0 {
|
if r.events_stopped.read().bits() != 0 {
|
||||||
|
@ -232,16 +250,32 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to an I2C slave.
|
/// Wait for stop or error
|
||||||
///
|
fn async_wait(&mut self) -> impl Future<Output = ()> {
|
||||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
poll_fn(move |cx| {
|
||||||
/// and at most 65535 bytes on the nRF52840.
|
let r = T::regs();
|
||||||
pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_write(&mut self, address: u8, buffer: &[u8], inten: bool) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
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);
|
compiler_fence(SeqCst);
|
||||||
|
|
||||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||||
|
@ -255,38 +289,21 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
r.events_lasttx.reset();
|
r.events_lasttx.reset();
|
||||||
self.clear_errorsrc();
|
self.clear_errorsrc();
|
||||||
|
|
||||||
// Start write operation.
|
if inten {
|
||||||
r.shorts.write(|w| w.lasttx_stop().enabled());
|
r.intenset.write(|w| w.stopped().set().error().set());
|
||||||
r.tasks_starttx.write(|w|
|
} else {
|
||||||
// `1` is a valid value to write to task registers.
|
r.intenclr.write(|w| w.stopped().clear().error().clear());
|
||||||
unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
self.wait();
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
self.read_errorsrc()?;
|
|
||||||
|
|
||||||
if r.txd.amount.read().bits() != buffer.len() as u32 {
|
|
||||||
return Err(Error::Transmit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start write operation.
|
||||||
|
r.shorts.write(|w| w.lasttx_stop().enabled());
|
||||||
|
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read from an I2C slave.
|
fn setup_read(&mut self, address: u8, buffer: &mut [u8], inten: bool) -> Result<(), Error> {
|
||||||
///
|
|
||||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
|
||||||
/// and at most 65535 bytes on the nRF52840.
|
|
||||||
pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
|
||||||
let r = T::regs();
|
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);
|
compiler_fence(SeqCst);
|
||||||
|
|
||||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||||
|
@ -299,44 +316,27 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
r.events_error.reset();
|
r.events_error.reset();
|
||||||
self.clear_errorsrc();
|
self.clear_errorsrc();
|
||||||
|
|
||||||
// Start read operation.
|
if inten {
|
||||||
r.shorts.write(|w| w.lastrx_stop().enabled());
|
r.intenset.write(|w| w.stopped().set().error().set());
|
||||||
r.tasks_startrx.write(|w|
|
} else {
|
||||||
// `1` is a valid value to write to task registers.
|
r.intenclr.write(|w| w.stopped().clear().error().clear());
|
||||||
unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
self.wait();
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
self.read_errorsrc()?;
|
|
||||||
|
|
||||||
if r.rxd.amount.read().bits() != buffer.len() as u32 {
|
|
||||||
return Err(Error::Receive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start read operation.
|
||||||
|
r.shorts.write(|w| w.lastrx_stop().enabled());
|
||||||
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write data to an I2C slave, then read data from the slave without
|
fn setup_write_read(
|
||||||
/// triggering a stop condition between the two.
|
|
||||||
///
|
|
||||||
/// The buffers must have a length of at most 255 bytes on the nRF52832
|
|
||||||
/// and at most 65535 bytes on the nRF52840.
|
|
||||||
pub fn write_then_read(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
wr_buffer: &[u8],
|
wr_buffer: &[u8],
|
||||||
rd_buffer: &mut [u8],
|
rd_buffer: &mut [u8],
|
||||||
|
inten: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
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);
|
compiler_fence(SeqCst);
|
||||||
|
|
||||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||||
|
@ -352,35 +352,65 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
r.events_error.reset();
|
r.events_error.reset();
|
||||||
self.clear_errorsrc();
|
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+read operation.
|
// Start write+read operation.
|
||||||
r.shorts.write(|w| {
|
r.shorts.write(|w| {
|
||||||
w.lasttx_startrx().enabled();
|
w.lasttx_startrx().enabled();
|
||||||
w.lastrx_stop().enabled();
|
w.lastrx_stop().enabled();
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
// `1` is a valid value to write to task registers.
|
|
||||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
self.wait();
|
/// Write to an I2C slave.
|
||||||
|
///
|
||||||
// Conservative compiler fence to prevent optimizations that do not
|
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||||
// take in to account actions by DMA. The fence has been placed here,
|
/// and at most 65535 bytes on the nRF52840.
|
||||||
// after all possible DMA actions have completed.
|
pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||||
|
self.setup_write(address, buffer, false)?;
|
||||||
|
self.blocking_wait();
|
||||||
compiler_fence(SeqCst);
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
|
self.check_tx(buffer.len())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
self.read_errorsrc()?;
|
/// Read from an I2C slave.
|
||||||
|
///
|
||||||
let bad_write = r.txd.amount.read().bits() != wr_buffer.len() as u32;
|
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||||
let bad_read = r.rxd.amount.read().bits() != rd_buffer.len() as u32;
|
/// and at most 65535 bytes on the nRF52840.
|
||||||
|
pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
if bad_write {
|
self.setup_read(address, buffer, false)?;
|
||||||
return Err(Error::Transmit);
|
self.blocking_wait();
|
||||||
}
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
if bad_read {
|
self.check_rx(buffer.len())?;
|
||||||
return Err(Error::Receive);
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write data to an I2C slave, then read data from the slave without
|
||||||
|
/// triggering a stop condition between the two.
|
||||||
|
///
|
||||||
|
/// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +418,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
///
|
///
|
||||||
/// The write buffer must have a length of at most 255 bytes on the nRF52832
|
/// The write buffer must have a length of at most 255 bytes on the nRF52832
|
||||||
/// and at most 1024 bytes on the nRF52840.
|
/// and at most 1024 bytes on the nRF52840.
|
||||||
pub fn copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> {
|
pub fn blocking_copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> {
|
||||||
if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE {
|
if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE {
|
||||||
return Err(Error::TxBufferTooLong);
|
return Err(Error::TxBufferTooLong);
|
||||||
}
|
}
|
||||||
|
@ -397,7 +427,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
||||||
wr_ram_buffer.copy_from_slice(wr_buffer);
|
wr_ram_buffer.copy_from_slice(wr_buffer);
|
||||||
|
|
||||||
self.write(address, wr_ram_buffer)
|
self.blocking_write(address, wr_ram_buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy data into RAM and write to an I2C slave, then read data from the slave without
|
/// Copy data into RAM and write to an I2C slave, then read data from the slave without
|
||||||
|
@ -408,7 +438,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
///
|
///
|
||||||
/// The read buffer must have a length of at most 255 bytes on the nRF52832
|
/// The read 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.
|
||||||
pub fn copy_write_then_read(
|
pub fn blocking_copy_write_read(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
wr_buffer: &[u8],
|
wr_buffer: &[u8],
|
||||||
|
@ -422,27 +452,40 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
||||||
wr_ram_buffer.copy_from_slice(wr_buffer);
|
wr_ram_buffer.copy_from_slice(wr_buffer);
|
||||||
|
|
||||||
self.write_then_read(address, wr_ram_buffer, rd_buffer)
|
self.blocking_write_read(address, wr_ram_buffer, rd_buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for_stopped_event(cx: &mut core::task::Context) -> Poll<()> {
|
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
self.setup_read(address, buffer, true)?;
|
||||||
let s = T::state();
|
self.async_wait().await;
|
||||||
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
|
self.check_rx(buffer.len())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
s.end_waker.register(cx.waker());
|
pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||||
if r.events_stopped.read().bits() != 0 {
|
self.setup_write(address, buffer, true)?;
|
||||||
r.events_stopped.reset();
|
self.async_wait().await;
|
||||||
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
|
self.check_tx(buffer.len())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
return Poll::Ready(());
|
pub async fn write_read(
|
||||||
}
|
&mut self,
|
||||||
|
address: u8,
|
||||||
// stop if an error occured
|
wr_buffer: &[u8],
|
||||||
if r.events_error.read().bits() != 0 {
|
rd_buffer: &mut [u8],
|
||||||
r.events_error.reset();
|
) -> Result<(), Error> {
|
||||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
self.setup_write_read(address, wr_buffer, rd_buffer, true)?;
|
||||||
}
|
self.async_wait().await;
|
||||||
|
compiler_fence(SeqCst);
|
||||||
Poll::Pending
|
self.check_errorsrc()?;
|
||||||
|
self.check_tx(wr_buffer.len())?;
|
||||||
|
self.check_rx(rd_buffer.len())?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +493,7 @@ impl<'a, T: Instance> Drop for Twim<'a, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
trace!("twim drop");
|
trace!("twim drop");
|
||||||
|
|
||||||
// TODO when implementing async here, check for abort
|
// TODO: check for abort
|
||||||
|
|
||||||
// disable!
|
// disable!
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
@ -483,174 +526,20 @@ where
|
||||||
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||||
async move {
|
self.read(address, buffer)
|
||||||
// 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> {
|
fn write<'a>(&'a mut self, address: u8, buffer: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||||
async move {
|
self.write(address, buffer)
|
||||||
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>(
|
fn write_read<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
bytes: &'a [u8],
|
wr_buffer: &'a [u8],
|
||||||
buffer: &'a mut [u8],
|
rd_buffer: &'a mut [u8],
|
||||||
) -> Self::WriteReadFuture<'a> {
|
) -> Self::WriteReadFuture<'a> {
|
||||||
async move {
|
self.write_read(address, wr_buffer, rd_buffer)
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,12 +548,12 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> {
|
||||||
|
|
||||||
fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> {
|
fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> {
|
||||||
if slice_in_ram(bytes) {
|
if slice_in_ram(bytes) {
|
||||||
self.write(addr, bytes)
|
self.blocking_write(addr, bytes)
|
||||||
} else {
|
} else {
|
||||||
let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..];
|
let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..];
|
||||||
for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) {
|
for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) {
|
||||||
buf[..chunk.len()].copy_from_slice(chunk);
|
buf[..chunk.len()].copy_from_slice(chunk);
|
||||||
self.write(addr, &buf[..chunk.len()])?;
|
self.blocking_write(addr, &buf[..chunk.len()])?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -675,7 +564,7 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::Read for Twim<'a, T> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> {
|
fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> {
|
||||||
self.read(addr, bytes)
|
self.blocking_read(addr, bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,15 +578,16 @@ impl<'a, T: Instance> embedded_hal::blocking::i2c::WriteRead for Twim<'a, T> {
|
||||||
buffer: &'w mut [u8],
|
buffer: &'w mut [u8],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if slice_in_ram(bytes) {
|
if slice_in_ram(bytes) {
|
||||||
self.write_then_read(addr, bytes, buffer)
|
self.blocking_write_read(addr, bytes, buffer)
|
||||||
} else {
|
} else {
|
||||||
self.copy_write_then_read(addr, bytes, buffer)
|
self.blocking_copy_write_read(addr, bytes, buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
TxBufferTooLong,
|
TxBufferTooLong,
|
||||||
RxBufferTooLong,
|
RxBufferTooLong,
|
||||||
|
|
|
@ -26,7 +26,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
|
|
||||||
let mut buf = [0u8; 16];
|
let mut buf = [0u8; 16];
|
||||||
unwrap!(twi.write_then_read(ADDRESS, &mut [0x00], &mut buf));
|
unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf));
|
||||||
|
|
||||||
info!("Read: {=[u8]:x}", buf);
|
info!("Read: {=[u8]:x}", buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ async fn main(_spawner: Spawner, mut p: Peripherals) {
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
|
|
||||||
let mut buf = [0u8; 16];
|
let mut buf = [0u8; 16];
|
||||||
unwrap!(twi.write_then_read(ADDRESS, &mut [0x00], &mut buf));
|
unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf));
|
||||||
|
|
||||||
info!("Read: {=[u8]:x}", buf);
|
info!("Read: {=[u8]:x}", buf);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue