1
1
//! Blocking SPI API
2
2
3
3
/// Blocking transfer
4
+ ///
5
+ /// This API provides no ordering guarantees as operations can be interleaved on the bus.
6
+ /// If you need to compose operations use the [Transactional] trait
4
7
pub trait Transfer < W > {
5
8
/// Error type
6
9
type Error ;
@@ -10,6 +13,9 @@ pub trait Transfer<W> {
10
13
}
11
14
12
15
/// Blocking write
16
+ ///
17
+ /// This API provides no ordering guarantees as operations can be interleaved on the bus.
18
+ /// If you need to compose operations use the [Transactional] trait
13
19
pub trait Write < W > {
14
20
/// Error type
15
21
type Error ;
@@ -19,6 +25,9 @@ pub trait Write<W> {
19
25
}
20
26
21
27
/// Blocking write (iterator version)
28
+ ///
29
+ /// This API provides no ordering guarantees as operations can be interleaved on the bus.
30
+ /// If you need to compose operations use the [Transactional] trait
22
31
pub trait WriteIter < W > {
23
32
/// Error type
24
33
type Error ;
@@ -29,6 +38,43 @@ pub trait WriteIter<W> {
29
38
WI : IntoIterator < Item = W > ;
30
39
}
31
40
41
+ /// ManagedCS marker trait indicates the CS pin is managed by the underlying driver.
42
+ ///
43
+ /// This specifies that all `spi` operations will be preceded by asserting the CS pin,
44
+ /// and followed by de-asserting the CS pin, prior to returning from the method.
45
+ ///
46
+ /// This is important for shared bus access to ensure that only one CS can be asserted
47
+ /// at a given time.
48
+ /// To chain operations within one transaction see [Transactional].
49
+ /// For or a convenience wrapper defining this type for non-shared / exclusive use
50
+ /// see [`SpiWithCs`](spi_with_cs::SpiWithCs).
51
+ pub trait ManagedCs { }
52
+
53
+ /// Blocking transfer
54
+ pub mod transfer {
55
+ /// Default implementation of `blocking::spi::Transfer<W>` for implementers of
56
+ /// `spi::FullDuplex<W>`
57
+ pub trait Default < W > : crate :: nb:: spi:: FullDuplex < W > { }
58
+
59
+ impl < W , S > crate :: blocking:: spi:: Transfer < W > for S
60
+ where
61
+ S : Default < W > ,
62
+ W : Clone ,
63
+ {
64
+ type Error = S :: Error ;
65
+
66
+ fn transfer < ' w > ( & mut self , words : & ' w mut [ W ] ) -> Result < & ' w [ W ] , S :: Error > {
67
+ for word in words. iter_mut ( ) {
68
+ nb:: block!( self . write( word. clone( ) ) ) ?;
69
+ * word = nb:: block!( self . read( ) ) ?;
70
+ }
71
+
72
+ Ok ( words)
73
+ }
74
+ }
75
+ }
76
+
77
+
32
78
/// Operation for transactional SPI trait
33
79
///
34
80
/// This allows composition of SPI operations into a single bus transaction
@@ -41,11 +87,154 @@ pub enum Operation<'a, W: 'static> {
41
87
}
42
88
43
89
/// Transactional trait allows multiple actions to be executed
44
- /// as part of a single SPI transaction
90
+ /// as part of a single SPI transaction.
91
+ ///
92
+ /// This API guarantees ordering, ensuring operations from
93
+ /// different sources will not be interleaved on a shared bus.
94
+ /// [ManagedCs]
45
95
pub trait Transactional < W : ' static > {
46
96
/// Associated error type
47
97
type Error ;
48
98
49
99
/// Execute the provided transactions
50
100
fn exec < ' a > ( & mut self , operations : & mut [ Operation < ' a , W > ] ) -> Result < ( ) , Self :: Error > ;
51
101
}
102
+
103
+ /// Provides SpiWithCS wrapper around an spi::* and OutputPin impl
104
+ pub mod spi_with_cs {
105
+
106
+ use core:: fmt:: Debug ;
107
+ use core:: marker:: PhantomData ;
108
+
109
+ use super :: { ManagedCs , Transfer , Write , WriteIter } ;
110
+ use crate :: blocking:: digital:: OutputPin ;
111
+
112
+ /// SpiWithCS wraps an blocking::spi* implementation with Chip Select (CS)
113
+ /// pin management for exclusive (non-shared) use.
114
+ /// For sharing SPI between peripherals, see [shared-bus](https://crates.io/crates/shared-bus)
115
+ pub struct SpiWithCs < Spi , SpiError , Pin , PinError > {
116
+ spi : Spi ,
117
+ cs : Pin ,
118
+
119
+ _spi_err : PhantomData < SpiError > ,
120
+ _pin_err : PhantomData < PinError > ,
121
+ }
122
+
123
+ /// Underlying causes for errors. Either SPI communication or CS pin state setting error
124
+ #[ derive( Clone , Debug , PartialEq ) ]
125
+ pub enum SpiWithCsError < SpiError , PinError > {
126
+ /// Underlying SPI communication error
127
+ Spi ( SpiError ) ,
128
+ /// Underlying chip-select pin state setting error
129
+ Pin ( PinError ) ,
130
+ }
131
+
132
+ /// ManagedCS marker trait indicates Chip Select management is automatic
133
+ impl < Spi , SpiError , Pin , PinError > ManagedCs for SpiWithCs < Spi , SpiError , Pin , PinError > { }
134
+
135
+ impl < Spi , SpiError , Pin , PinError > SpiWithCs < Spi , SpiError , Pin , PinError >
136
+ where
137
+ Pin : crate :: blocking:: digital:: OutputPin < Error = PinError > ,
138
+ SpiError : Debug ,
139
+ PinError : Debug ,
140
+ {
141
+ /// Create a new SpiWithCS wrapper with the provided Spi and Pin
142
+ pub fn new ( spi : Spi , cs : Pin ) -> Self {
143
+ Self {
144
+ spi,
145
+ cs,
146
+ _spi_err : PhantomData ,
147
+ _pin_err : PhantomData ,
148
+ }
149
+ }
150
+
151
+ /// Fetch references to the inner Spi and Pin types.
152
+ /// Note that using these directly will violate the `ManagedCs` constraint.
153
+ pub fn inner ( & mut self ) -> ( & mut Spi , & mut Pin ) {
154
+ ( & mut self . spi , & mut self . cs )
155
+ }
156
+
157
+ /// Destroy the SpiWithCs wrapper, returning the bus and pin objects
158
+ pub fn destroy ( self ) -> ( Spi , Pin ) {
159
+ ( self . spi , self . cs )
160
+ }
161
+ }
162
+
163
+ impl < Spi , SpiError , Pin , PinError > Transfer < u8 > for SpiWithCs < Spi , SpiError , Pin , PinError >
164
+ where
165
+ Spi : Transfer < u8 , Error = SpiError > ,
166
+ Pin : OutputPin < Error = PinError > ,
167
+ SpiError : Debug ,
168
+ PinError : Debug ,
169
+ {
170
+ type Error = SpiWithCsError < SpiError , PinError > ;
171
+
172
+ /// Attempt an SPI transfer with automated CS assert/deassert
173
+ fn transfer < ' w > ( & mut self , data : & ' w mut [ u8 ] ) -> Result < & ' w [ u8 ] , Self :: Error > {
174
+ // First assert CS
175
+ self . cs . set_low ( ) . map_err ( SpiWithCsError :: Pin ) ?;
176
+
177
+ // Attempt the transfer, storing the result for later
178
+ let spi_result = self . spi . transfer ( data) . map_err ( SpiWithCsError :: Spi ) ;
179
+
180
+ // Deassert CS
181
+ self . cs . set_high ( ) . map_err ( SpiWithCsError :: Pin ) ?;
182
+
183
+ // Return failures
184
+ spi_result
185
+ }
186
+ }
187
+
188
+ impl < Spi , SpiError , Pin , PinError > Write < u8 > for SpiWithCs < Spi , SpiError , Pin , PinError >
189
+ where
190
+ Spi : Write < u8 , Error = SpiError > ,
191
+ Pin : OutputPin < Error = PinError > ,
192
+ SpiError : Debug ,
193
+ PinError : Debug ,
194
+ {
195
+ type Error = SpiWithCsError < SpiError , PinError > ;
196
+
197
+ /// Attempt an SPI write with automated CS assert/deassert
198
+ fn write < ' w > ( & mut self , data : & ' w [ u8 ] ) -> Result < ( ) , Self :: Error > {
199
+ // First assert CS
200
+ self . cs . set_low ( ) . map_err ( SpiWithCsError :: Pin ) ?;
201
+
202
+ // Attempt the transfer, storing the result for later
203
+ let spi_result = self . spi . write ( data) . map_err ( SpiWithCsError :: Spi ) ;
204
+
205
+ // Deassert CS
206
+ self . cs . set_high ( ) . map_err ( SpiWithCsError :: Pin ) ?;
207
+
208
+ // Return failures
209
+ spi_result
210
+ }
211
+ }
212
+
213
+ impl < Spi , SpiError , Pin , PinError > WriteIter < u8 > for SpiWithCs < Spi , SpiError , Pin , PinError >
214
+ where
215
+ Spi : WriteIter < u8 , Error = SpiError > ,
216
+ Pin : OutputPin < Error = PinError > ,
217
+ SpiError : Debug ,
218
+ PinError : Debug ,
219
+ {
220
+ type Error = SpiWithCsError < SpiError , PinError > ;
221
+
222
+ /// Attempt an SPI write_iter with automated CS assert/deassert
223
+ fn write_iter < WI > ( & mut self , words : WI ) -> Result < ( ) , Self :: Error >
224
+ where
225
+ WI : IntoIterator < Item = u8 > ,
226
+ {
227
+ // First assert CS
228
+ self . cs . set_low ( ) . map_err ( SpiWithCsError :: Pin ) ?;
229
+
230
+ // Attempt the transfer, storing the result for later
231
+ let spi_result = self . spi . write_iter ( words) . map_err ( SpiWithCsError :: Spi ) ;
232
+
233
+ // Deassert CS
234
+ self . cs . set_high ( ) . map_err ( SpiWithCsError :: Pin ) ?;
235
+
236
+ // Return failures
237
+ spi_result
238
+ }
239
+ }
240
+ }
0 commit comments