aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTil Blechschmidt <[email protected]>2022-03-08 16:42:46 +0100
committerTil Blechschmidt <[email protected]>2022-03-08 17:49:15 +0100
commit63030bf998b0787b421f30af4f75159e2cb5c99f (patch)
tree3a585a07c805b16abc59bb0850a5ede4af6d09e8
parent7540b44050f42ba75ea855f904b959cc4cfdefe5 (diff)
Move EasyDMA documentation to module level
-rw-r--r--embassy-nrf/src/lib.rs36
-rw-r--r--embassy-nrf/src/spim.rs41
-rw-r--r--embassy-nrf/src/twim.rs8
-rw-r--r--embassy-nrf/src/uarte.rs6
4 files changed, 53 insertions, 38 deletions
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index b448f6ab6..06e8235e3 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -1,3 +1,39 @@
1//! ## EasyDMA considerations
2//!
3//! On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting
4//! with peripherals. It takes care of sending/receiving data over a variety of bus protocols (TWI/I2C, UART, SPI).
5//! However, EasyDMA requires the buffers used to transmit and receive data to reside in RAM. Unfortunately, Rust
6//! slices will not always do so. The following example using the SPI peripheral shows a common situation where this might happen:
7//!
8//! ```no_run
9//! // As we pass a slice to the function whose contents will not ever change,
10//! // the compiler writes it into the flash and thus the pointer to it will
11//! // reference static memory. Since EasyDMA requires slices to reside in RAM,
12//! // this function call will fail.
13//! let result = spim.write_from_ram(&[1, 2, 3]);
14//! assert_eq!(result, Err(Error::DMABufferNotInDataMemory));
15//!
16//! // The data is still static and located in flash. However, since we are assigning
17//! // it to a variable, the compiler will load it into memory. Passing a reference to the
18//! // variable will yield a pointer that references dynamic memory, thus making EasyDMA happy.
19//! // This function call succeeds.
20//! let data = [1, 2, 3];
21//! let result = spim.write_from_ram(&data);
22//! assert!(result.is_ok());
23//! ```
24//!
25//! Each peripheral struct which uses EasyDMA ([`Spim`](spim::Spim), [`Uarte`](uarte::Uarte), [`Twim`](twim::Twim)) has two variants of their mutating functions:
26//! - 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.
27//! - 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.
28//!
29//! Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will
30//! fail and notify you, or the more convenient versions without the suffix which are potentially a little bit
31//! more inefficient. Be aware that this overhead is not only in terms of instruction count but also in terms of memory usage
32//! as the methods without the suffix will be allocating a statically sized buffer (up to 512 bytes for the nRF52840).
33//!
34//! 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
35//! mutable slices always reside in RAM.
36
1#![no_std] 37#![no_std]
2#![cfg_attr( 38#![cfg_attr(
3 feature = "nightly", 39 feature = "nightly",
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index c9c9cb25a..5d88b2326 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -31,38 +31,7 @@ pub enum Error {
31 31
32/// Interface for the SPIM peripheral using EasyDMA to offload the transmission and reception workload. 32/// Interface for the SPIM peripheral using EasyDMA to offload the transmission and reception workload.
33/// 33///
34/// ## Data locality requirements 34/// For more details about EasyDMA, consult the module documentation.
35///
36/// On nRF chips, EasyDMA requires the buffers to reside in RAM. However, Rust
37/// slices will not always do so. Take the following example:
38///
39/// ```no_run
40/// // As we pass a slice to the function whose contents will not ever change,
41/// // the compiler writes it into the flash and thus the pointer to it will
42/// // reference static memory. Since EasyDMA requires slices to reside in RAM,
43/// // this function call will fail.
44/// let result = spim.write_from_ram(&[1, 2, 3]);
45/// assert_eq!(result, Error::DMABufferNotInDataMemory);
46///
47/// // The data is still static and located in flash. However, since we are assigning
48/// // it to a variable, the compiler will load it into memory. Passing a reference to the
49/// // variable will yield a pointer that references dynamic memory, thus making EasyDMA happy.
50/// // This function call succeeds.
51/// let data = [1, 2, 3];
52/// let result = spim.write_from_ram(&data);
53/// assert!(result.is_ok());
54/// ```
55///
56/// Each function in this struct has a `_from_ram` variant and one without this suffix.
57/// - 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.
58/// - 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.
59///
60/// Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will
61/// fail and notify you, or the more convenient versions without the suffix which are potentially a little bit
62/// more inefficient.
63///
64/// Note that the [`read`](Spim::read) and [`transfer_in_place`](Spim::transfer_in_place) methods do not have the corresponding `_from_ram` variants as
65/// mutable slices always reside in RAM.
66pub struct Spim<'d, T: Instance> { 35pub struct Spim<'d, T: Instance> {
67 phantom: PhantomData<&'d mut T>, 36 phantom: PhantomData<&'d mut T>,
68} 37}
@@ -325,7 +294,7 @@ impl<'d, T: Instance> Spim<'d, T> {
325 self.blocking_inner(read, write) 294 self.blocking_inner(read, write)
326 } 295 }
327 296
328 /// Same as [`blocking_transfer`](Spim::blocking_transfer) but will fail instead of copying data into RAM. 297 /// Same as [`blocking_transfer`](Spim::blocking_transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
329 pub fn blocking_transfer_from_ram( 298 pub fn blocking_transfer_from_ram(
330 &mut self, 299 &mut self,
331 read: &mut [u8], 300 read: &mut [u8],
@@ -346,7 +315,7 @@ impl<'d, T: Instance> Spim<'d, T> {
346 self.blocking_inner(&mut [], data) 315 self.blocking_inner(&mut [], data)
347 } 316 }
348 317
349 /// Same as [`blocking_write`](Spim::blocking_write) but will fail instead of copying data into RAM. 318 /// Same as [`blocking_write`](Spim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
350 pub fn blocking_write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> { 319 pub fn blocking_write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
351 self.blocking_inner(&mut [], data) 320 self.blocking_inner(&mut [], data)
352 } 321 }
@@ -362,7 +331,7 @@ impl<'d, T: Instance> Spim<'d, T> {
362 self.async_inner(read, write).await 331 self.async_inner(read, write).await
363 } 332 }
364 333
365 /// Same as [`transfer`](Spim::transfer) but will fail instead of copying data into RAM. 334 /// Same as [`transfer`](Spim::transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
366 pub async fn transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { 335 pub async fn transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
367 self.async_inner_from_ram(read, write).await 336 self.async_inner_from_ram(read, write).await
368 } 337 }
@@ -378,7 +347,7 @@ impl<'d, T: Instance> Spim<'d, T> {
378 self.async_inner(&mut [], data).await 347 self.async_inner(&mut [], data).await
379 } 348 }
380 349
381 /// Same as [`write`](Spim::write) but will fail instead of copying data into RAM. 350 /// Same as [`write`](Spim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
382 pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> { 351 pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
383 self.async_inner_from_ram(&mut [], data).await 352 self.async_inner_from_ram(&mut [], data).await
384 } 353 }
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index c8ad2a0e3..40705477f 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -64,7 +64,9 @@ pub enum Error {
64 Overrun, 64 Overrun,
65} 65}
66 66
67/// Interface to a TWIM instance. 67/// Interface to a TWIM instance using EasyDMA to offload the transmission and reception workload.
68///
69/// For more details about EasyDMA, consult the module documentation.
68pub struct Twim<'d, T: Instance> { 70pub struct Twim<'d, T: Instance> {
69 phantom: PhantomData<&'d mut T>, 71 phantom: PhantomData<&'d mut T>,
70} 72}
@@ -432,6 +434,7 @@ impl<'d, T: Instance> Twim<'d, T> {
432 Ok(()) 434 Ok(())
433 } 435 }
434 436
437 /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
435 pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { 438 pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
436 self.setup_write_from_ram(address, buffer, false)?; 439 self.setup_write_from_ram(address, buffer, false)?;
437 self.blocking_wait(); 440 self.blocking_wait();
@@ -474,6 +477,7 @@ impl<'d, T: Instance> Twim<'d, T> {
474 Ok(()) 477 Ok(())
475 } 478 }
476 479
480 /// 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.
477 pub fn blocking_write_read_from_ram( 481 pub fn blocking_write_read_from_ram(
478 &mut self, 482 &mut self,
479 address: u8, 483 address: u8,
@@ -507,6 +511,7 @@ impl<'d, T: Instance> Twim<'d, T> {
507 Ok(()) 511 Ok(())
508 } 512 }
509 513
514 /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
510 pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { 515 pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
511 self.setup_write_from_ram(address, buffer, true)?; 516 self.setup_write_from_ram(address, buffer, true)?;
512 self.async_wait().await; 517 self.async_wait().await;
@@ -531,6 +536,7 @@ impl<'d, T: Instance> Twim<'d, T> {
531 Ok(()) 536 Ok(())
532 } 537 }
533 538
539 /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
534 pub async fn write_read_from_ram( 540 pub async fn write_read_from_ram(
535 &mut self, 541 &mut self,
536 address: u8, 542 address: u8,
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 7d7b904b1..111c8341b 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -60,7 +60,9 @@ pub enum Error {
60 // TODO: add other error variants. 60 // TODO: add other error variants.
61} 61}
62 62
63/// Interface to the UARTE peripheral 63/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload.
64///
65/// For more details about EasyDMA, consult the module documentation.
64pub struct Uarte<'d, T: Instance> { 66pub struct Uarte<'d, T: Instance> {
65 phantom: PhantomData<&'d mut T>, 67 phantom: PhantomData<&'d mut T>,
66 tx: UarteTx<'d, T>, 68 tx: UarteTx<'d, T>,
@@ -224,6 +226,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
224 self.tx.write(buffer).await 226 self.tx.write(buffer).await
225 } 227 }
226 228
229 /// Same as [`write`](Uarte::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
227 pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { 230 pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
228 self.tx.write_from_ram(buffer).await 231 self.tx.write_from_ram(buffer).await
229 } 232 }
@@ -236,6 +239,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
236 self.tx.blocking_write(buffer) 239 self.tx.blocking_write(buffer)
237 } 240 }
238 241
242 /// Same as [`blocking_write`](Uarte::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
239 pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { 243 pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
240 self.tx.blocking_write_from_ram(buffer) 244 self.tx.blocking_write_from_ram(buffer)
241 } 245 }