Skip to content

Commit a903ac4

Browse files
committed
updated for [email protected]
1 parent 683e41e commit a903ac4

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed

src/spi/blocking.rs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,176 @@ impl<T: Transactional<W>, W: 'static> Transactional<W> for &mut T {
9090
T::exec(self, operations)
9191
}
9292
}
93+
94+
95+
96+
/// ManagedChipSelect marker trait indicates the CS pin is managed by the underlying driver.
97+
///
98+
/// This specifies that `spi` operations will be grouped.
99+
/// Preceded by asserting the CS pin, and followed by
100+
/// de-asserting the CS pin, prior to returning from the method.
101+
///
102+
/// This is important for shared bus access to ensure that only one CS can be asserted
103+
/// at a given time. Drivers should require this (and not manage their own CS pins)
104+
/// in order to support shared use.
105+
///
106+
/// To chain operations within one transaction see [`Transactional`].
107+
/// For or a convenience wrapper defining this type for non-shared / exclusive use
108+
/// see [`SpiWithCs`](spi_with_cs::SpiWithCs).
109+
pub trait ManagedChipSelect {}
110+
111+
112+
/// Provides SpiWithCS wrapper around an spi::* and OutputPin impl
113+
pub mod spi_with_cs {
114+
115+
use core::fmt::Debug;
116+
117+
use crate::digital::blocking::OutputPin;
118+
use crate::spi::ErrorKind;
119+
use super::{ManagedChipSelect, Transfer, Write, WriteIter};
120+
121+
/// SpiWithCS wraps an blocking::spi* implementation with Chip Select (CS)
122+
/// pin management for exclusive (non-shared) use.
123+
/// For sharing SPI between peripherals, see [shared-bus](https://crates.io/crates/shared-bus)
124+
pub struct SpiWithCs<Spi, Pin> {
125+
spi: Spi,
126+
cs: Pin,
127+
}
128+
129+
/// Underlying causes for errors. Either SPI communication or CS pin state setting error
130+
#[derive(Clone, Debug, PartialEq)]
131+
pub enum SpiWithCsError<SpiError, PinError> {
132+
/// Underlying SPI communication error
133+
Spi(SpiError),
134+
/// Underlying chip-select pin state setting error
135+
Pin(PinError),
136+
}
137+
138+
/// Implement [`spi::Error'] for wrapped types
139+
impl <SpiError, PinError> crate::spi::Error for SpiWithCsError<SpiError, PinError>
140+
where
141+
SpiError: crate::spi::Error + Debug,
142+
PinError: Debug,
143+
{
144+
fn kind(&self) -> ErrorKind {
145+
match self {
146+
SpiWithCsError::Spi(e) => e.kind(),
147+
SpiWithCsError::Pin(_e) => ErrorKind::Other
148+
}
149+
}
150+
}
151+
152+
/// ManagedChipSelect marker trait indicates Chip Select management is automatic
153+
impl<Spi, Pin> ManagedChipSelect for SpiWithCs<Spi, Pin> {}
154+
155+
impl<Spi, Pin> SpiWithCs<Spi, Pin>
156+
where
157+
Pin: OutputPin,
158+
{
159+
/// Create a new SpiWithCS wrapper with the provided Spi and Pin
160+
pub fn new(spi: Spi, cs: Pin) -> Self {
161+
Self {
162+
spi,
163+
cs,
164+
}
165+
}
166+
167+
/// Fetch references to the inner Spi and Pin types.
168+
/// Note that using these directly will violate the `ManagedChipSelect` constraint.
169+
pub fn inner(&mut self) -> (&mut Spi, &mut Pin) {
170+
(&mut self.spi, &mut self.cs)
171+
}
172+
173+
/// Destroy the SpiWithCs wrapper, returning the bus and pin objects
174+
pub fn destroy(self) -> (Spi, Pin) {
175+
(self.spi, self.cs)
176+
}
177+
}
178+
179+
impl<Spi, Pin> Transfer<u8> for SpiWithCs<Spi, Pin>
180+
where
181+
Spi: Transfer<u8>,
182+
Pin: OutputPin,
183+
<Spi as Transfer<u8>>::Error: Debug,
184+
<Pin as OutputPin>::Error: Debug,
185+
{
186+
type Error = SpiWithCsError<
187+
<Spi as Transfer<u8>>::Error,
188+
<Pin as OutputPin>::Error
189+
>;
190+
191+
/// Attempt an SPI transfer with automated CS assert/deassert
192+
fn transfer<'w>(&mut self, data: &'w mut [u8]) -> Result<(), Self::Error> {
193+
// First assert CS
194+
self.cs.set_low().map_err(SpiWithCsError::Pin)?;
195+
196+
// Attempt the transfer, storing the result for later
197+
let spi_result = self.spi.transfer(data).map_err(SpiWithCsError::Spi);
198+
199+
// Deassert CS
200+
self.cs.set_high().map_err(SpiWithCsError::Pin)?;
201+
202+
// Return failures
203+
spi_result
204+
}
205+
}
206+
207+
impl<Spi, Pin> Write<u8> for SpiWithCs<Spi, Pin>
208+
where
209+
Spi: Write<u8>,
210+
Pin: OutputPin,
211+
<Spi as Write<u8>>::Error: Debug,
212+
<Pin as OutputPin>::Error: Debug,
213+
{
214+
type Error = SpiWithCsError<
215+
<Spi as Write<u8>>::Error,
216+
<Pin as OutputPin>::Error
217+
>;
218+
219+
/// Attempt an SPI write with automated CS assert/deassert
220+
fn write<'w>(&mut self, data: &'w [u8]) -> Result<(), Self::Error> {
221+
// First assert CS
222+
self.cs.set_low().map_err(SpiWithCsError::Pin)?;
223+
224+
// Attempt the transfer, storing the result for later
225+
let spi_result = self.spi.write(data).map_err(SpiWithCsError::Spi);
226+
227+
// Deassert CS
228+
self.cs.set_high().map_err(SpiWithCsError::Pin)?;
229+
230+
// Return failures
231+
spi_result
232+
}
233+
}
234+
235+
impl<Spi, Pin> WriteIter<u8> for SpiWithCs<Spi, Pin>
236+
where
237+
Spi: WriteIter<u8>,
238+
Pin: OutputPin,
239+
<Spi as WriteIter<u8>>::Error: Debug,
240+
<Pin as OutputPin>::Error: Debug,
241+
{
242+
type Error = SpiWithCsError<
243+
<Spi as WriteIter<u8>>::Error,
244+
<Pin as OutputPin>::Error
245+
>;
246+
247+
/// Attempt an SPI write_iter with automated CS assert/deassert
248+
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
249+
where
250+
WI: IntoIterator<Item = u8>,
251+
{
252+
// First assert CS
253+
self.cs.set_low().map_err(SpiWithCsError::Pin)?;
254+
255+
// Attempt the transfer, storing the result for later
256+
let spi_result = self.spi.write_iter(words).map_err(SpiWithCsError::Spi);
257+
258+
// Deassert CS
259+
self.cs.set_high().map_err(SpiWithCsError::Pin)?;
260+
261+
// Return failures
262+
spi_result
263+
}
264+
}
265+
}

0 commit comments

Comments
 (0)