aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-02-07 13:54:14 +0100
committerGitHub <[email protected]>2025-02-07 13:54:14 +0100
commitf2a6014cd36152a791c0c27b6dd3f6565f5e1a4c (patch)
treeeccb4829674943d302027487a63d4e3fd97dbbbd
parent4e69e5b3c719ccd73e2dee47294c9f599525997d (diff)
parentdc2ce92e32469eb99ab0ef703b7d265ea7184630 (diff)
Merge pull request #3844 from showier-drastic/main
SpiDevice cancel safety: always set CS pin to high on drop
-rw-r--r--embassy-embedded-hal/Cargo.toml1
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/spi.rs19
2 files changed, 20 insertions, 0 deletions
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index 9dd2e419f..f385963f1 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -22,6 +22,7 @@ time = ["dep:embassy-time"]
22default = ["time"] 22default = ["time"]
23 23
24[dependencies] 24[dependencies]
25embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" }
25embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 26embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
26embassy-sync = { version = "0.6.2", path = "../embassy-sync" } 27embassy-sync = { version = "0.6.2", path = "../embassy-sync" }
27embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } 28embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
index 30d4ecc36..78709b7d3 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
@@ -25,6 +25,7 @@
25//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128); 25//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128);
26//! ``` 26//! ```
27 27
28use embassy_hal_internal::drop::OnDrop;
28use embassy_sync::blocking_mutex::raw::RawMutex; 29use embassy_sync::blocking_mutex::raw::RawMutex;
29use embassy_sync::mutex::Mutex; 30use embassy_sync::mutex::Mutex;
30use embedded_hal_1::digital::OutputPin; 31use embedded_hal_1::digital::OutputPin;
@@ -70,6 +71,14 @@ where
70 let mut bus = self.bus.lock().await; 71 let mut bus = self.bus.lock().await;
71 self.cs.set_low().map_err(SpiDeviceError::Cs)?; 72 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
72 73
74 let cs_drop = OnDrop::new(|| {
75 // This drop guard deasserts CS pin if the async operation is cancelled.
76 // Errors are ignored in this drop handler, as there's nothing we can do about them.
77 // If the async operation is completed without cancellation, this handler will not
78 // be run, and the CS pin will be deasserted with proper error handling.
79 let _ = self.cs.set_high();
80 });
81
73 let op_res = 'ops: { 82 let op_res = 'ops: {
74 for op in operations { 83 for op in operations {
75 let res = match op { 84 let res = match op {
@@ -97,6 +106,10 @@ where
97 106
98 // On failure, it's important to still flush and deassert CS. 107 // On failure, it's important to still flush and deassert CS.
99 let flush_res = bus.flush().await; 108 let flush_res = bus.flush().await;
109
110 // Now that all the async operations are done, we defuse the CS guard,
111 // and manually set the CS pin low (to better handle the possible errors).
112 cs_drop.defuse();
100 let cs_res = self.cs.set_high(); 113 let cs_res = self.cs.set_high();
101 114
102 let op_res = op_res.map_err(SpiDeviceError::Spi)?; 115 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
@@ -155,6 +168,11 @@ where
155 bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?; 168 bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?;
156 self.cs.set_low().map_err(SpiDeviceError::Cs)?; 169 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
157 170
171 let cs_drop = OnDrop::new(|| {
172 // Please see comment in SpiDevice for an explanation of this drop handler.
173 let _ = self.cs.set_high();
174 });
175
158 let op_res = 'ops: { 176 let op_res = 'ops: {
159 for op in operations { 177 for op in operations {
160 let res = match op { 178 let res = match op {
@@ -182,6 +200,7 @@ where
182 200
183 // On failure, it's important to still flush and deassert CS. 201 // On failure, it's important to still flush and deassert CS.
184 let flush_res = bus.flush().await; 202 let flush_res = bus.flush().await;
203 cs_drop.defuse();
185 let cs_res = self.cs.set_high(); 204 let cs_res = self.cs.set_high();
186 205
187 let op_res = op_res.map_err(SpiDeviceError::Spi)?; 206 let op_res = op_res.map_err(SpiDeviceError::Spi)?;