@@ -90,3 +90,176 @@ impl<T: Transactional<W>, W: 'static> Transactional<W> for &mut T {
90
90
T :: exec ( self , operations)
91
91
}
92
92
}
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