From ab42bc65cee96adbcc7522713a2e4acbb5f405b9 Mon Sep 17 00:00:00 2001 From: vchapuis Date: Fri, 31 May 2024 11:34:03 +0800 Subject: [PATCH] feat(embedded-hal-bus): Spi - Add support for cs to clock delay --- embedded-hal-bus/src/spi/atomic.rs | 32 ++++++++++++++++-- embedded-hal-bus/src/spi/critical_section.rs | 32 ++++++++++++++++-- embedded-hal-bus/src/spi/exclusive.rs | 34 ++++++++++++++++++-- embedded-hal-bus/src/spi/mutex.rs | 32 ++++++++++++++++-- embedded-hal-bus/src/spi/refcell.rs | 32 ++++++++++++++++-- embedded-hal-bus/src/spi/shared.rs | 8 +++++ 6 files changed, 159 insertions(+), 11 deletions(-) diff --git a/embedded-hal-bus/src/spi/atomic.rs b/embedded-hal-bus/src/spi/atomic.rs index 7d18e28c5..75725efb7 100644 --- a/embedded-hal-bus/src/spi/atomic.rs +++ b/embedded-hal-bus/src/spi/atomic.rs @@ -30,6 +30,9 @@ pub struct AtomicDevice<'a, BUS, CS, D> { bus: &'a AtomicCell, cs: CS, delay: D, + /// Implementation of + cs_to_clock_delay_ns: u32, + clock_to_cs_delay_ns: u32, } #[derive(Debug, Copy, Clone)] @@ -55,7 +58,23 @@ impl<'a, BUS, CS, D> AtomicDevice<'a, BUS, CS, D> { CS: OutputPin, { cs.set_high()?; - Ok(Self { bus, cs, delay }) + Ok(Self { + bus, + cs, + delay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, + }) + } + + /// Set the delay between the CS pin toggle and the first clock + pub fn set_cs_to_clock_delay_ns(&mut self, delay_ns: u32) { + self.cs_to_clock_delay_ns = delay_ns; + } + + /// Set the delay between the last clock and the CS pin reset + pub fn set_clock_to_cs_delay_ns(&mut self, delay_ns: u32) { + self.clock_to_cs_delay_ns = delay_ns; } } @@ -93,6 +112,8 @@ where bus, cs, delay: super::NoDelay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, }) } } @@ -134,7 +155,14 @@ where let bus = unsafe { &mut *self.bus.bus.get() }; - let result = transaction(operations, bus, &mut self.delay, &mut self.cs); + let result = transaction( + operations, + bus, + &mut self.delay, + &mut self.cs, + self.cs_to_clock_delay_ns, + self.clock_to_cs_delay_ns, + ); self.bus .busy diff --git a/embedded-hal-bus/src/spi/critical_section.rs b/embedded-hal-bus/src/spi/critical_section.rs index 4c3a46eb2..97ea49188 100644 --- a/embedded-hal-bus/src/spi/critical_section.rs +++ b/embedded-hal-bus/src/spi/critical_section.rs @@ -21,6 +21,9 @@ pub struct CriticalSectionDevice<'a, BUS, CS, D> { bus: &'a Mutex>, cs: CS, delay: D, + /// Implementation of + cs_to_clock_delay_ns: u32, + clock_to_cs_delay_ns: u32, } impl<'a, BUS, CS, D> CriticalSectionDevice<'a, BUS, CS, D> { @@ -34,7 +37,23 @@ impl<'a, BUS, CS, D> CriticalSectionDevice<'a, BUS, CS, D> { CS: OutputPin, { cs.set_high()?; - Ok(Self { bus, cs, delay }) + Ok(Self { + bus, + cs, + delay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, + }) + } + + /// Set the delay between the CS pin toggle and the first clock + pub fn set_cs_to_clock_delay_ns(&mut self, delay_ns: u32) { + self.cs_to_clock_delay_ns = delay_ns; + } + + /// Set the delay between the last clock and the CS pin reset + pub fn set_clock_to_cs_delay_ns(&mut self, delay_ns: u32) { + self.clock_to_cs_delay_ns = delay_ns; } } @@ -68,6 +87,8 @@ impl<'a, BUS, CS> CriticalSectionDevice<'a, BUS, CS, super::NoDelay> { bus, cs, delay: super::NoDelay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, }) } } @@ -91,7 +112,14 @@ where critical_section::with(|cs| { let bus = &mut *self.bus.borrow_ref_mut(cs); - transaction(operations, bus, &mut self.delay, &mut self.cs) + transaction( + operations, + bus, + &mut self.delay, + &mut self.cs, + self.cs_to_clock_delay_ns, + self.clock_to_cs_delay_ns, + ) }) } } diff --git a/embedded-hal-bus/src/spi/exclusive.rs b/embedded-hal-bus/src/spi/exclusive.rs index 1599ae7ae..5e43fb240 100644 --- a/embedded-hal-bus/src/spi/exclusive.rs +++ b/embedded-hal-bus/src/spi/exclusive.rs @@ -20,6 +20,9 @@ pub struct ExclusiveDevice { bus: BUS, cs: CS, delay: D, + /// Implementation of + cs_to_clock_delay_ns: u32, + clock_to_cs_delay_ns: u32, } impl ExclusiveDevice { @@ -28,12 +31,28 @@ impl ExclusiveDevice { /// This sets the `cs` pin high, and returns an error if that fails. It is recommended /// to set the pin high the moment it's configured as an output, to avoid glitches. #[inline] - pub fn new(bus: BUS, mut cs: CS, delay: D) -> Result + pub fn new(bus: BUS, mut cs: CS, delay: D, cs_to_clock_delay_ns: u32) -> Result where CS: OutputPin, { cs.set_high()?; - Ok(Self { bus, cs, delay }) + Ok(Self { + bus, + cs, + delay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, + }) + } + + /// Set the delay between the CS pin toggle and the first clock + pub fn set_cs_to_clock_delay_ns(&mut self, delay_ns: u32) { + self.cs_to_clock_delay_ns = delay_ns; + } + + /// Set the delay between the last clock and the CS pin reset + pub fn set_clock_to_cs_delay_ns(&mut self, delay_ns: u32) { + self.clock_to_cs_delay_ns = delay_ns; } /// Returns a reference to the underlying bus object. @@ -79,6 +98,8 @@ impl ExclusiveDevice { bus, cs, delay: super::NoDelay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, }) } } @@ -99,7 +120,14 @@ where { #[inline] fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> { - transaction(operations, &mut self.bus, &mut self.delay, &mut self.cs) + transaction( + operations, + &mut self.bus, + &mut self.delay, + &mut self.cs, + self.cs_to_clock_delay_ns, + self.clock_to_cs_delay_ns, + ) } } diff --git a/embedded-hal-bus/src/spi/mutex.rs b/embedded-hal-bus/src/spi/mutex.rs index 83fe85d88..d751e626f 100644 --- a/embedded-hal-bus/src/spi/mutex.rs +++ b/embedded-hal-bus/src/spi/mutex.rs @@ -19,6 +19,9 @@ pub struct MutexDevice<'a, BUS, CS, D> { bus: &'a Mutex, cs: CS, delay: D, + /// Implementation of + cs_to_clock_delay_ns: u32, + clock_to_cs_delay_ns: u32, } impl<'a, BUS, CS, D> MutexDevice<'a, BUS, CS, D> { @@ -32,7 +35,23 @@ impl<'a, BUS, CS, D> MutexDevice<'a, BUS, CS, D> { CS: OutputPin, { cs.set_high()?; - Ok(Self { bus, cs, delay }) + Ok(Self { + bus, + cs, + delay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, + }) + } + + /// Set the delay between the CS pin toggle and the first clock + pub fn set_cs_to_clock_delay_ns(&mut self, delay_ns: u32) { + self.cs_to_clock_delay_ns = delay_ns; + } + + /// Set the delay between the last clock and the CS pin reset + pub fn set_clock_to_cs_delay_ns(&mut self, delay_ns: u32) { + self.clock_to_cs_delay_ns = delay_ns; } } @@ -66,6 +85,8 @@ impl<'a, BUS, CS> MutexDevice<'a, BUS, CS, super::NoDelay> { bus, cs, delay: super::NoDelay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, }) } } @@ -88,6 +109,13 @@ where fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> { let bus = &mut *self.bus.lock().unwrap(); - transaction(operations, bus, &mut self.delay, &mut self.cs) + transaction( + operations, + bus, + &mut self.delay, + &mut self.cs, + self.cs_to_clock_delay_ns, + self.clock_to_cs_delay_ns, + ) } } diff --git a/embedded-hal-bus/src/spi/refcell.rs b/embedded-hal-bus/src/spi/refcell.rs index 35bea03a2..61f3bbb51 100644 --- a/embedded-hal-bus/src/spi/refcell.rs +++ b/embedded-hal-bus/src/spi/refcell.rs @@ -18,6 +18,9 @@ pub struct RefCellDevice<'a, BUS, CS, D> { bus: &'a RefCell, cs: CS, delay: D, + /// Implementation of + cs_to_clock_delay_ns: u32, + clock_to_cs_delay_ns: u32, } impl<'a, BUS, CS, D> RefCellDevice<'a, BUS, CS, D> { @@ -31,7 +34,23 @@ impl<'a, BUS, CS, D> RefCellDevice<'a, BUS, CS, D> { CS: OutputPin, { cs.set_high()?; - Ok(Self { bus, cs, delay }) + Ok(Self { + bus, + cs, + delay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, + }) + } + + /// Set the delay between the CS pin toggle and the first clock + pub fn set_cs_to_clock_delay_ns(&mut self, delay_ns: u32) { + self.cs_to_clock_delay_ns = delay_ns; + } + + /// Set the delay between the last clock and the CS pin reset + pub fn set_clock_to_cs_delay_ns(&mut self, delay_ns: u32) { + self.clock_to_cs_delay_ns = delay_ns; } } @@ -65,6 +84,8 @@ impl<'a, BUS, CS> RefCellDevice<'a, BUS, CS, super::NoDelay> { bus, cs, delay: super::NoDelay, + cs_to_clock_delay_ns: 0, + clock_to_cs_delay_ns: 0, }) } } @@ -87,6 +108,13 @@ where fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> { let bus = &mut *self.bus.borrow_mut(); - transaction(operations, bus, &mut self.delay, &mut self.cs) + transaction( + operations, + bus, + &mut self.delay, + &mut self.cs, + self.cs_to_clock_delay_ns, + self.clock_to_cs_delay_ns, + ) } } diff --git a/embedded-hal-bus/src/spi/shared.rs b/embedded-hal-bus/src/spi/shared.rs index 95730ba19..80f03021a 100644 --- a/embedded-hal-bus/src/spi/shared.rs +++ b/embedded-hal-bus/src/spi/shared.rs @@ -11,6 +11,8 @@ pub fn transaction( bus: &mut BUS, delay: &mut D, cs: &mut CS, + cs_to_clock_delay_ns: u32, + clock_to_cs_delay_ns: u32, ) -> Result<(), DeviceError> where BUS: SpiBus + ErrorType, @@ -19,6 +21,9 @@ where Word: Copy, { cs.set_low().map_err(DeviceError::Cs)?; + if cs_to_clock_delay_ns > 0 { + delay.delay_ns(cs_to_clock_delay_ns); + } let op_res = operations.iter_mut().try_for_each(|op| match op { Operation::Read(buf) => bus.read(buf), @@ -34,6 +39,9 @@ where // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush(); + if clock_to_cs_delay_ns > 0 { + delay.delay_ns(cs_to_clock_delay_ns); + } let cs_res = cs.set_high(); op_res.map_err(DeviceError::Spi)?;