diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-02-07 13:54:14 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-02-07 13:54:14 +0100 |
| commit | f2a6014cd36152a791c0c27b6dd3f6565f5e1a4c (patch) | |
| tree | eccb4829674943d302027487a63d4e3fd97dbbbd | |
| parent | 4e69e5b3c719ccd73e2dee47294c9f599525997d (diff) | |
| parent | dc2ce92e32469eb99ab0ef703b7d265ea7184630 (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.toml | 1 | ||||
| -rw-r--r-- | embassy-embedded-hal/src/shared_bus/asynch/spi.rs | 19 |
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"] | |||
| 22 | default = ["time"] | 22 | default = ["time"] |
| 23 | 23 | ||
| 24 | [dependencies] | 24 | [dependencies] |
| 25 | embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } | ||
| 25 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 26 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 26 | embassy-sync = { version = "0.6.2", path = "../embassy-sync" } | 27 | embassy-sync = { version = "0.6.2", path = "../embassy-sync" } |
| 27 | embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } | 28 | embassy-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 | ||
| 28 | use embassy_hal_internal::drop::OnDrop; | ||
| 28 | use embassy_sync::blocking_mutex::raw::RawMutex; | 29 | use embassy_sync::blocking_mutex::raw::RawMutex; |
| 29 | use embassy_sync::mutex::Mutex; | 30 | use embassy_sync::mutex::Mutex; |
| 30 | use embedded_hal_1::digital::OutputPin; | 31 | use 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)?; |
