Merge pull request #3844 from showier-drastic/main
SpiDevice cancel safety: always set CS pin to high on drop
This commit is contained in:
		
						commit
						f2a6014cd3
					
				@ -22,6 +22,7 @@ time = ["dep:embassy-time"]
 | 
				
			|||||||
default = ["time"]
 | 
					default = ["time"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
 | 
					embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" }
 | 
				
			||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
 | 
					embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
 | 
				
			||||||
embassy-sync = { version = "0.6.2", path = "../embassy-sync" }
 | 
					embassy-sync = { version = "0.6.2", path = "../embassy-sync" }
 | 
				
			||||||
embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
 | 
					embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,7 @@
 | 
				
			|||||||
//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128);
 | 
					//! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128);
 | 
				
			||||||
//! ```
 | 
					//! ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use embassy_hal_internal::drop::OnDrop;
 | 
				
			||||||
use embassy_sync::blocking_mutex::raw::RawMutex;
 | 
					use embassy_sync::blocking_mutex::raw::RawMutex;
 | 
				
			||||||
use embassy_sync::mutex::Mutex;
 | 
					use embassy_sync::mutex::Mutex;
 | 
				
			||||||
use embedded_hal_1::digital::OutputPin;
 | 
					use embedded_hal_1::digital::OutputPin;
 | 
				
			||||||
@ -70,6 +71,14 @@ where
 | 
				
			|||||||
        let mut bus = self.bus.lock().await;
 | 
					        let mut bus = self.bus.lock().await;
 | 
				
			||||||
        self.cs.set_low().map_err(SpiDeviceError::Cs)?;
 | 
					        self.cs.set_low().map_err(SpiDeviceError::Cs)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let cs_drop = OnDrop::new(|| {
 | 
				
			||||||
 | 
					            // This drop guard deasserts CS pin if the async operation is cancelled.
 | 
				
			||||||
 | 
					            // Errors are ignored in this drop handler, as there's nothing we can do about them.
 | 
				
			||||||
 | 
					            // If the async operation is completed without cancellation, this handler will not
 | 
				
			||||||
 | 
					            // be run, and the CS pin will be deasserted with proper error handling.
 | 
				
			||||||
 | 
					            let _ = self.cs.set_high();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let op_res = 'ops: {
 | 
					        let op_res = 'ops: {
 | 
				
			||||||
            for op in operations {
 | 
					            for op in operations {
 | 
				
			||||||
                let res = match op {
 | 
					                let res = match op {
 | 
				
			||||||
@ -97,6 +106,10 @@ where
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // On failure, it's important to still flush and deassert CS.
 | 
					        // On failure, it's important to still flush and deassert CS.
 | 
				
			||||||
        let flush_res = bus.flush().await;
 | 
					        let flush_res = bus.flush().await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Now that all the async operations are done, we defuse the CS guard,
 | 
				
			||||||
 | 
					        // and manually set the CS pin low (to better handle the possible errors).
 | 
				
			||||||
 | 
					        cs_drop.defuse();
 | 
				
			||||||
        let cs_res = self.cs.set_high();
 | 
					        let cs_res = self.cs.set_high();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let op_res = op_res.map_err(SpiDeviceError::Spi)?;
 | 
					        let op_res = op_res.map_err(SpiDeviceError::Spi)?;
 | 
				
			||||||
@ -155,6 +168,11 @@ where
 | 
				
			|||||||
        bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?;
 | 
					        bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?;
 | 
				
			||||||
        self.cs.set_low().map_err(SpiDeviceError::Cs)?;
 | 
					        self.cs.set_low().map_err(SpiDeviceError::Cs)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let cs_drop = OnDrop::new(|| {
 | 
				
			||||||
 | 
					            // Please see comment in SpiDevice for an explanation of this drop handler.
 | 
				
			||||||
 | 
					            let _ = self.cs.set_high();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let op_res = 'ops: {
 | 
					        let op_res = 'ops: {
 | 
				
			||||||
            for op in operations {
 | 
					            for op in operations {
 | 
				
			||||||
                let res = match op {
 | 
					                let res = match op {
 | 
				
			||||||
@ -182,6 +200,7 @@ where
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // On failure, it's important to still flush and deassert CS.
 | 
					        // On failure, it's important to still flush and deassert CS.
 | 
				
			||||||
        let flush_res = bus.flush().await;
 | 
					        let flush_res = bus.flush().await;
 | 
				
			||||||
 | 
					        cs_drop.defuse();
 | 
				
			||||||
        let cs_res = self.cs.set_high();
 | 
					        let cs_res = self.cs.set_high();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let op_res = op_res.map_err(SpiDeviceError::Spi)?;
 | 
					        let op_res = op_res.map_err(SpiDeviceError::Spi)?;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user