You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: embedded-hal-bus/src/spi/atomic.rs
+15-7Lines changed: 15 additions & 7 deletions
Original file line number
Diff line number
Diff line change
@@ -28,26 +28,34 @@ impl<BUS> AtomicCell<BUS> {
28
28
}
29
29
}
30
30
31
-
/// `UnsafeCell`-based shared bus [`SpiDevice`] implementation.
31
+
/// Atomics-based shared bus [`SpiDevice`] implementation.
32
32
///
33
33
/// This allows for sharing an [`SpiBus`], obtaining multiple [`SpiDevice`] instances,
34
34
/// each with its own `CS` pin.
35
35
///
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.
39
40
///
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.
42
48
///
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.
43
51
pubstructAtomicDevice<'a,BUS,CS,D>{
44
52
bus:&'aAtomicCell<BUS>,
45
53
cs:CS,
46
54
delay:D,
47
55
}
48
56
49
57
#[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`].
51
59
pubenumAtomicError<T:Error>{
52
60
/// This error is returned if the SPI bus was already in use when an operation was attempted,
53
61
/// which indicates that the driver requirements are not being met with regard to
0 commit comments