Move EasyDMA documentation to module level
This commit is contained in:
parent
7540b44050
commit
63030bf998
@ -1,3 +1,39 @@
|
|||||||
|
//! ## EasyDMA considerations
|
||||||
|
//!
|
||||||
|
//! On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting
|
||||||
|
//! with peripherals. It takes care of sending/receiving data over a variety of bus protocols (TWI/I2C, UART, SPI).
|
||||||
|
//! However, EasyDMA requires the buffers used to transmit and receive data to reside in RAM. Unfortunately, Rust
|
||||||
|
//! slices will not always do so. The following example using the SPI peripheral shows a common situation where this might happen:
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! // As we pass a slice to the function whose contents will not ever change,
|
||||||
|
//! // the compiler writes it into the flash and thus the pointer to it will
|
||||||
|
//! // reference static memory. Since EasyDMA requires slices to reside in RAM,
|
||||||
|
//! // this function call will fail.
|
||||||
|
//! let result = spim.write_from_ram(&[1, 2, 3]);
|
||||||
|
//! assert_eq!(result, Err(Error::DMABufferNotInDataMemory));
|
||||||
|
//!
|
||||||
|
//! // The data is still static and located in flash. However, since we are assigning
|
||||||
|
//! // it to a variable, the compiler will load it into memory. Passing a reference to the
|
||||||
|
//! // variable will yield a pointer that references dynamic memory, thus making EasyDMA happy.
|
||||||
|
//! // This function call succeeds.
|
||||||
|
//! let data = [1, 2, 3];
|
||||||
|
//! let result = spim.write_from_ram(&data);
|
||||||
|
//! assert!(result.is_ok());
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Each peripheral struct which uses EasyDMA ([`Spim`](spim::Spim), [`Uarte`](uarte::Uarte), [`Twim`](twim::Twim)) has two variants of their mutating functions:
|
||||||
|
//! - Functions with the suffix (e.g. [`write_from_ram`](Spim::write_from_ram), [`transfer_from_ram`](Spim::transfer_from_ram)) will return an error if the passed slice does not reside in RAM.
|
||||||
|
//! - Functions without the suffix (e.g. [`write`](Spim::write), [`transfer`](Spim::transfer)) will check whether the data is in RAM and copy it into memory prior to transmission.
|
||||||
|
//!
|
||||||
|
//! Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will
|
||||||
|
//! fail and notify you, or the more convenient versions without the suffix which are potentially a little bit
|
||||||
|
//! more inefficient. Be aware that this overhead is not only in terms of instruction count but also in terms of memory usage
|
||||||
|
//! as the methods without the suffix will be allocating a statically sized buffer (up to 512 bytes for the nRF52840).
|
||||||
|
//!
|
||||||
|
//! Note that the methods that read data like [`read`](spim::Spim::read) and [`transfer_in_place`](spim::Spim::transfer_in_place) do not have the corresponding `_from_ram` variants as
|
||||||
|
//! mutable slices always reside in RAM.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
feature = "nightly",
|
feature = "nightly",
|
||||||
|
@ -31,38 +31,7 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Interface for the SPIM peripheral using EasyDMA to offload the transmission and reception workload.
|
/// Interface for the SPIM peripheral using EasyDMA to offload the transmission and reception workload.
|
||||||
///
|
///
|
||||||
/// ## Data locality requirements
|
/// For more details about EasyDMA, consult the module documentation.
|
||||||
///
|
|
||||||
/// On nRF chips, EasyDMA requires the buffers to reside in RAM. However, Rust
|
|
||||||
/// slices will not always do so. Take the following example:
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// // As we pass a slice to the function whose contents will not ever change,
|
|
||||||
/// // the compiler writes it into the flash and thus the pointer to it will
|
|
||||||
/// // reference static memory. Since EasyDMA requires slices to reside in RAM,
|
|
||||||
/// // this function call will fail.
|
|
||||||
/// let result = spim.write_from_ram(&[1, 2, 3]);
|
|
||||||
/// assert_eq!(result, Error::DMABufferNotInDataMemory);
|
|
||||||
///
|
|
||||||
/// // The data is still static and located in flash. However, since we are assigning
|
|
||||||
/// // it to a variable, the compiler will load it into memory. Passing a reference to the
|
|
||||||
/// // variable will yield a pointer that references dynamic memory, thus making EasyDMA happy.
|
|
||||||
/// // This function call succeeds.
|
|
||||||
/// let data = [1, 2, 3];
|
|
||||||
/// let result = spim.write_from_ram(&data);
|
|
||||||
/// assert!(result.is_ok());
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Each function in this struct has a `_from_ram` variant and one without this suffix.
|
|
||||||
/// - Functions with the suffix (e.g. [`write_from_ram`](Spim::write_from_ram), [`transfer_from_ram`](Spim::transfer_from_ram)) will return an error if the passed slice does not reside in RAM.
|
|
||||||
/// - Functions without the suffix (e.g. [`write`](Spim::write), [`transfer`](Spim::transfer)) will check whether the data is in RAM and copy it into memory prior to transmission.
|
|
||||||
///
|
|
||||||
/// Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will
|
|
||||||
/// fail and notify you, or the more convenient versions without the suffix which are potentially a little bit
|
|
||||||
/// more inefficient.
|
|
||||||
///
|
|
||||||
/// Note that the [`read`](Spim::read) and [`transfer_in_place`](Spim::transfer_in_place) methods do not have the corresponding `_from_ram` variants as
|
|
||||||
/// mutable slices always reside in RAM.
|
|
||||||
pub struct Spim<'d, T: Instance> {
|
pub struct Spim<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
}
|
}
|
||||||
@ -325,7 +294,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
self.blocking_inner(read, write)
|
self.blocking_inner(read, write)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [`blocking_transfer`](Spim::blocking_transfer) but will fail instead of copying data into RAM.
|
/// Same as [`blocking_transfer`](Spim::blocking_transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||||
pub fn blocking_transfer_from_ram(
|
pub fn blocking_transfer_from_ram(
|
||||||
&mut self,
|
&mut self,
|
||||||
read: &mut [u8],
|
read: &mut [u8],
|
||||||
@ -346,7 +315,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
self.blocking_inner(&mut [], data)
|
self.blocking_inner(&mut [], data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [`blocking_write`](Spim::blocking_write) but will fail instead of copying data into RAM.
|
/// Same as [`blocking_write`](Spim::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, data: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
|
||||||
self.blocking_inner(&mut [], data)
|
self.blocking_inner(&mut [], data)
|
||||||
}
|
}
|
||||||
@ -362,7 +331,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
self.async_inner(read, write).await
|
self.async_inner(read, write).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [`transfer`](Spim::transfer) but will fail instead of copying data into RAM.
|
/// Same as [`transfer`](Spim::transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||||
pub async fn transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
|
pub async fn transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
|
||||||
self.async_inner_from_ram(read, write).await
|
self.async_inner_from_ram(read, write).await
|
||||||
}
|
}
|
||||||
@ -378,7 +347,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
self.async_inner(&mut [], data).await
|
self.async_inner(&mut [], data).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [`write`](Spim::write) but will fail instead of copying data into RAM.
|
/// Same as [`write`](Spim::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, data: &[u8]) -> Result<(), Error> {
|
pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
|
||||||
self.async_inner_from_ram(&mut [], data).await
|
self.async_inner_from_ram(&mut [], data).await
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,9 @@ pub enum Error {
|
|||||||
Overrun,
|
Overrun,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interface to a TWIM instance.
|
/// Interface to a TWIM instance using EasyDMA to offload the transmission and reception workload.
|
||||||
|
///
|
||||||
|
/// For more details about EasyDMA, consult the module documentation.
|
||||||
pub struct Twim<'d, T: Instance> {
|
pub struct Twim<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
}
|
}
|
||||||
@ -432,6 +434,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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> {
|
pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||||
self.setup_write_from_ram(address, buffer, false)?;
|
self.setup_write_from_ram(address, buffer, false)?;
|
||||||
self.blocking_wait();
|
self.blocking_wait();
|
||||||
@ -474,6 +477,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
pub fn blocking_write_read_from_ram(
|
pub fn blocking_write_read_from_ram(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
@ -507,6 +511,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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> {
|
pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||||
self.setup_write_from_ram(address, buffer, true)?;
|
self.setup_write_from_ram(address, buffer, true)?;
|
||||||
self.async_wait().await;
|
self.async_wait().await;
|
||||||
@ -531,6 +536,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
|
||||||
pub async fn write_read_from_ram(
|
pub async fn write_read_from_ram(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
|
@ -60,7 +60,9 @@ pub enum Error {
|
|||||||
// TODO: add other error variants.
|
// TODO: add other error variants.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interface to the UARTE peripheral
|
/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload.
|
||||||
|
///
|
||||||
|
/// For more details about EasyDMA, consult the module documentation.
|
||||||
pub struct Uarte<'d, T: Instance> {
|
pub struct Uarte<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
tx: UarteTx<'d, T>,
|
tx: UarteTx<'d, T>,
|
||||||
@ -224,6 +226,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
self.tx.write(buffer).await
|
self.tx.write(buffer).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Same as [`write`](Uarte::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, buffer: &[u8]) -> Result<(), Error> {
|
pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
self.tx.write_from_ram(buffer).await
|
self.tx.write_from_ram(buffer).await
|
||||||
}
|
}
|
||||||
@ -236,6 +239,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
self.tx.blocking_write(buffer)
|
self.tx.blocking_write(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Same as [`blocking_write`](Uarte::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, buffer: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
self.tx.blocking_write_from_ram(buffer)
|
self.tx.blocking_write_from_ram(buffer)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user