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,19 @@ 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
+
32
54
/// Operation for transactional SPI trait
33
55
///
34
56
/// This allows composition of SPI operations into a single bus transaction
@@ -41,11 +63,154 @@ pub enum Operation<'a, W: 'static> {
41
63
}
42
64
43
65
/// Transactional trait allows multiple actions to be executed
44
- /// as part of a single SPI transaction
66
+ /// as part of a single SPI transaction.
67
+ ///
68
+ /// This API guarantees ordering, ensuring operations from
69
+ /// different sources will not be interleaved on a shared bus.
70
+ /// [ManagedCs]
45
71
pub trait Transactional < W : ' static > {
46
72
/// Associated error type
47
73
type Error ;
48
74
49
75
/// Execute the provided transactions
50
76
fn exec < ' a > ( & mut self , operations : & mut [ Operation < ' a , W > ] ) -> Result < ( ) , Self :: Error > ;
51
77
}
78
+
79
+ /// Provides SpiWithCS wrapper around an spi::* and OutputPin impl
80
+ pub mod spi_with_cs {
81
+
82
+ use core:: fmt:: Debug ;
83
+ use core:: marker:: PhantomData ;
84
+
85
+ use super :: { ManagedCs , Transfer , Write , WriteIter } ;
86
+ use crate :: blocking:: digital:: OutputPin ;
87
+
88
+ /// SpiWithCS wraps an blocking::spi* implementation with Chip Select (CS)
89
+ /// pin management for exclusive (non-shared) use.
90
+ /// For sharing SPI between peripherals, see [shared-bus](https://crates.io/crates/shared-bus)
91
+ pub struct SpiWithCs < Spi , SpiError , Pin , PinError > {
92
+ spi : Spi ,
93
+ cs : Pin ,
94
+
95
+ _spi_err : PhantomData < SpiError > ,
96
+ _pin_err : PhantomData < PinError > ,
97
+ }
98
+
99
+ /// Underlying causes for errors. Either SPI communication or CS pin state setting error
100
+ #[ derive( Clone , Debug , PartialEq ) ]
101
+ pub enum SpiWithCsError < SpiError , PinError > {
102
+ /// Underlying SPI communication error
103
+ Spi ( SpiError ) ,
104
+ /// Underlying chip-select pin state setting error
105
+ Pin ( PinError ) ,
106
+ }
107
+
108
+ /// ManagedCS marker trait indicates Chip Select management is automatic
109
+ impl < Spi , SpiError , Pin , PinError > ManagedCs for SpiWithCs < Spi , SpiError , Pin , PinError > { }
110
+
111
+ impl < Spi , SpiError , Pin , PinError > SpiWithCs < Spi , SpiError , Pin , PinError >
112
+ where
113
+ Pin : crate :: blocking:: digital:: OutputPin < Error = PinError > ,
114
+ SpiError : Debug ,
115
+ PinError : Debug ,
116
+ {
117
+ /// Create a new SpiWithCS wrapper with the provided Spi and Pin
118
+ pub fn new ( spi : Spi , cs : Pin ) -> Self {
119
+ Self {
120
+ spi,
121
+ cs,
122
+ _spi_err : PhantomData ,
123
+ _pin_err : PhantomData ,
124
+ }
125
+ }
126
+
127
+ /// Fetch references to the inner Spi and Pin types.
128
+ /// Note that using these directly will violate the `ManagedCs` constraint.
129
+ pub fn inner ( & mut self ) -> ( & mut Spi , & mut Pin ) {
130
+ ( & mut self . spi , & mut self . cs )
131
+ }
132
+
133
+ /// Destroy the SpiWithCs wrapper, returning the bus and pin objects
134
+ pub fn destroy ( self ) -> ( Spi , Pin ) {
135
+ ( self . spi , self . cs )
136
+ }
137
+ }
138
+
139
+ impl < Spi , SpiError , Pin , PinError > Transfer < u8 > for SpiWithCs < Spi , SpiError , Pin , PinError >
140
+ where
141
+ Spi : Transfer < u8 , Error = SpiError > ,
142
+ Pin : OutputPin < Error = PinError > ,
143
+ SpiError : Debug ,
144
+ PinError : Debug ,
145
+ {
146
+ type Error = SpiWithCsError < SpiError , PinError > ;
147
+
148
+ /// Attempt an SPI transfer with automated CS assert/deassert
149
+ fn transfer < ' w > ( & mut self , data : & ' w mut [ u8 ] ) -> Result < & ' w [ u8 ] , Self :: Error > {
150
+ // First assert CS
151
+ self . cs . set_low ( ) . map_err ( SpiWithCsError :: Pin ) ?;
152
+
153
+ // Attempt the transfer, storing the result for later
154
+ let spi_result = self . spi . transfer ( data) . map_err ( SpiWithCsError :: Spi ) ;
155
+
156
+ // Deassert CS
157
+ self . cs . set_high ( ) . map_err ( SpiWithCsError :: Pin ) ?;
158
+
159
+ // Return failures
160
+ spi_result
161
+ }
162
+ }
163
+
164
+ impl < Spi , SpiError , Pin , PinError > Write < u8 > for SpiWithCs < Spi , SpiError , Pin , PinError >
165
+ where
166
+ Spi : Write < u8 , Error = SpiError > ,
167
+ Pin : OutputPin < Error = PinError > ,
168
+ SpiError : Debug ,
169
+ PinError : Debug ,
170
+ {
171
+ type Error = SpiWithCsError < SpiError , PinError > ;
172
+
173
+ /// Attempt an SPI write with automated CS assert/deassert
174
+ fn write < ' w > ( & mut self , data : & ' w [ u8 ] ) -> Result < ( ) , Self :: Error > {
175
+ // First assert CS
176
+ self . cs . set_low ( ) . map_err ( SpiWithCsError :: Pin ) ?;
177
+
178
+ // Attempt the transfer, storing the result for later
179
+ let spi_result = self . spi . write ( data) . map_err ( SpiWithCsError :: Spi ) ;
180
+
181
+ // Deassert CS
182
+ self . cs . set_high ( ) . map_err ( SpiWithCsError :: Pin ) ?;
183
+
184
+ // Return failures
185
+ spi_result
186
+ }
187
+ }
188
+
189
+ impl < Spi , SpiError , Pin , PinError > WriteIter < u8 > for SpiWithCs < Spi , SpiError , Pin , PinError >
190
+ where
191
+ Spi : WriteIter < u8 , Error = SpiError > ,
192
+ Pin : OutputPin < Error = PinError > ,
193
+ SpiError : Debug ,
194
+ PinError : Debug ,
195
+ {
196
+ type Error = SpiWithCsError < SpiError , PinError > ;
197
+
198
+ /// Attempt an SPI write_iter with automated CS assert/deassert
199
+ fn write_iter < WI > ( & mut self , words : WI ) -> Result < ( ) , Self :: Error >
200
+ where
201
+ WI : IntoIterator < Item = u8 > ,
202
+ {
203
+ // First assert CS
204
+ self . cs . set_low ( ) . map_err ( SpiWithCsError :: Pin ) ?;
205
+
206
+ // Attempt the transfer, storing the result for later
207
+ let spi_result = self . spi . write_iter ( words) . map_err ( SpiWithCsError :: Spi ) ;
208
+
209
+ // Deassert CS
210
+ self . cs . set_high ( ) . map_err ( SpiWithCsError :: Pin ) ?;
211
+
212
+ // Return failures
213
+ spi_result
214
+ }
215
+ }
216
+ }
0 commit comments