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