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