Skip to content

Commit 156e4a8

Browse files
committed
bus: expand docs for AtomicDevice a bit.
1 parent 21267f6 commit 156e4a8

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

embedded-hal-bus/src/spi/atomic.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,34 @@ impl<BUS> AtomicCell<BUS> {
2828
}
2929
}
3030

31-
/// `UnsafeCell`-based shared bus [`SpiDevice`] implementation.
31+
/// Atomics-based shared bus [`SpiDevice`] implementation.
3232
///
3333
/// This allows for sharing an [`SpiBus`], obtaining multiple [`SpiDevice`] instances,
3434
/// each with its own `CS` pin.
3535
///
36-
/// Sharing is implemented with a `UnsafeCell`. This means it has low overhead, and, unlike [`crate::spi::RefCellDevice`], instances are `Send`,
37-
/// so it only allows sharing across multiple threads (interrupt priority level). When attempting
38-
/// to preempt usage of the bus, a `AtomicError::Busy` error is returned.
36+
/// Sharing is implemented with a [`AtomicDevice`], which consists of an `UnsafeCell` and an `AtomicBool` "locked" flag.
37+
/// This means it has low overhead, like [`RefCellDevice`](crate::spi::RefCellDevice). Aditionally, it is `Send`,
38+
/// which allows sharing a single bus across multiple threads (interrupt priority level), like [`CriticalSectionDevice`](crate::spi::CriticalSectionDevice),
39+
/// while not using critical sections and therefore impacting real-time performance less.
3940
///
40-
/// This primitive is particularly well-suited for applications that have external arbitration
41-
/// rules, such as the RTIC framework.
41+
/// The downside is using a simple `AtomicBool` for locking doesn't prevent two threads from trying to lock it at once.
42+
/// For example, the main thread can be doing a SPI transaction, and an interrupt fires and tries to do another. In this
43+
/// case, a `Busy` error is returned that must be handled somehow, usually dropping the data or trying again later.
44+
///
45+
/// Note that retrying in a loop on `Busy` errors usually leads to deadlocks. In the above example, it'll prevent the
46+
/// interrupt handler from returning, which will starve the main thread and prevent it from releasing the lock. If
47+
/// this is an issue for your use case, you most likely should use [`CriticalSectionDevice`](crate::spi::CriticalSectionDevice) instead.
4248
///
49+
/// This primitive is particularly well-suited for applications that have external arbitration
50+
/// rules that prevent `Busy` errors in the first place, such as the RTIC framework.
4351
pub struct AtomicDevice<'a, BUS, CS, D> {
4452
bus: &'a AtomicCell<BUS>,
4553
cs: CS,
4654
delay: D,
4755
}
4856

4957
#[derive(Debug, Copy, Clone)]
50-
/// Wrapper type for errors originating from the atomically-checked SPI bus manager.
58+
/// Wrapper type for errors returned by [`AtomicDevice`].
5159
pub enum AtomicError<T: Error> {
5260
/// This error is returned if the SPI bus was already in use when an operation was attempted,
5361
/// which indicates that the driver requirements are not being met with regard to

0 commit comments

Comments
 (0)