atsamd_hal/sercom/spi/pads_thumbv7em.rs
1//! Define a container for a set of SERCOM pads
2//!
3//! See the [spi module](super) documentation for more details on declaring and
4//! instantiating a [`Pads`] type.
5
6use core::marker::PhantomData;
7
8use crate::gpio::AnyPin;
9use crate::sercom::*;
10use crate::typelevel::{NoneT, Sealed};
11
12use super::{Capability, Duplex, Rx, Tx};
13
14//=============================================================================
15// Dipo
16//=============================================================================
17
18/// Map an [`OptionalPadNum`] to its corresponding `DIPO` value
19pub trait Dipo: OptionalPadNum {
20 const DIPO: Option<u8>;
21}
22
23impl Dipo for NoneT {
24 const DIPO: Option<u8> = None;
25}
26
27impl Dipo for Pad0 {
28 const DIPO: Option<u8> = Some(0);
29}
30impl Dipo for Pad1 {
31 const DIPO: Option<u8> = Some(1);
32}
33impl Dipo for Pad2 {
34 const DIPO: Option<u8> = Some(2);
35}
36impl Dipo for Pad3 {
37 const DIPO: Option<u8> = Some(3);
38}
39
40//=============================================================================
41// Dopo
42//=============================================================================
43
44/// Map an [`OptionalPadNum`] to its corresponding `DOPO` value
45pub trait Dopo: OptionalPadNum {
46 const DOPO: Option<u8>;
47}
48
49impl Dopo for NoneT {
50 const DOPO: Option<u8> = None;
51}
52
53impl Dopo for Pad0 {
54 const DOPO: Option<u8> = Some(0);
55}
56
57impl Dopo for Pad1 {
58 const DOPO: Option<u8> = Some(1);
59}
60
61impl Dopo for Pad3 {
62 const DOPO: Option<u8> = Some(2);
63}
64
65//=============================================================================
66// DipoDopo
67//=============================================================================
68
69/// Configure the `DIPO` and `DOPO` fields based on a set of [`Pads`]
70pub trait DipoDopo: Sealed {
71 const DIPO_DOPO: (u8, u8);
72}
73
74/// Lift the implementations of [`DipoDopo`] from implementations on
75/// [`OptionalPadNum`]s to the corresponding [`Pads`] types.
76impl<S, DI, DO, CK, SS> DipoDopo for Pads<S, DI, DO, CK, SS>
77where
78 S: Sercom,
79 DI: OptionalPad,
80 DO: OptionalPad,
81 CK: OptionalPad,
82 SS: OptionalPad,
83 (DI, DO, CK, SS): ShareIoSet,
84 DI::PadNum: Dipo,
85 DO::PadNum: Dopo,
86{
87 const DIPO_DOPO: (u8, u8) = match (DI::PadNum::DIPO, DO::PadNum::DOPO) {
88 (None, None) => (0, 2),
89 (Some(dipo), None) => {
90 let dopo = if dipo == 0 { 2 } else { 0 };
91 (dipo, dopo)
92 }
93 (None, Some(dopo)) => {
94 let dipo = if dopo == 0 { 3 } else { 0 };
95 (dipo, dopo)
96 }
97 (Some(dipo), Some(dopo)) => (dipo, dopo),
98 };
99}
100
101//=============================================================================
102// Pads
103//=============================================================================
104
105/// Container for a set of SERCOM pads
106///
107/// See the [spi module](super) documentation for more details on declaring and
108/// instantiating a [`Pads`] type.
109pub struct Pads<S, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT>
110where
111 S: Sercom,
112 DI: OptionalPad,
113 DO: OptionalPad,
114 CK: OptionalPad,
115 SS: OptionalPad,
116 (DI, DO, CK, SS): ShareIoSet,
117{
118 sercom: PhantomData<S>,
119 data_in: DI,
120 data_out: DO,
121 sclk: CK,
122 ss: SS,
123}
124
125impl<S: Sercom> Default for Pads<S> {
126 fn default() -> Self {
127 Self {
128 sercom: PhantomData,
129 data_in: NoneT,
130 data_out: NoneT,
131 sclk: NoneT,
132 ss: NoneT,
133 }
134 }
135}
136
137impl<S, DI, DO, CK, SS> Pads<S, DI, DO, CK, SS>
138where
139 S: Sercom,
140 DI: OptionalPad,
141 DO: OptionalPad,
142 CK: OptionalPad,
143 SS: OptionalPad,
144 (DI, DO, CK, SS): ShareIoSet,
145{
146 /// Set the `DI` pad
147 ///
148 /// In a [`MasterMode`], this is MISO. In [`Slave`] [`OpMode`], this is
149 /// MOSI.
150 ///
151 /// [`MasterMode`]: super::MasterMode
152 /// [`Slave`]: super::Slave
153 /// [`OpMode`]: super::OpMode
154 #[inline]
155 pub fn data_in<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, Pad<S, Id>, DO, CK, SS>
156 where
157 Id: GetPad<S>,
158 Id::PadNum: Dipo,
159 (Pad<S, Id>, DO, CK, SS): ShareIoSet,
160 Pad<S, Id>: IsPad,
161 {
162 Pads {
163 sercom: self.sercom,
164 data_in: pin.into().into_mode(),
165 data_out: self.data_out,
166 sclk: self.sclk,
167 ss: self.ss,
168 }
169 }
170
171 /// Set the `DO` pad
172 ///
173 /// In a [`MasterMode`], this is MOSI. In [`Slave`] [`OpMode`], this is
174 /// MISO.
175 ///
176 /// [`MasterMode`]: super::MasterMode
177 /// [`Slave`]: super::Slave
178 /// [`OpMode`]: super::OpMode
179 #[inline]
180 pub fn data_out<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, DI, Pad<S, Id>, CK, SS>
181 where
182 Id: GetPad<S>,
183 Id::PadNum: Dopo,
184 (DI, Pad<S, Id>, CK, SS): ShareIoSet,
185 Pad<S, Id>: IsPad,
186 {
187 Pads {
188 sercom: self.sercom,
189 data_in: self.data_in,
190 data_out: pin.into().into_mode(),
191 sclk: self.sclk,
192 ss: self.ss,
193 }
194 }
195
196 /// Set the `SCK` pad, which is always [`Pad1`]
197 #[inline]
198 pub fn sclk<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, DI, DO, Pad<S, Id>, SS>
199 where
200 Id: GetPad<S, PadNum = Pad1>,
201 (DI, DO, Pad<S, Id>, SS): ShareIoSet,
202 Pad<S, Id>: IsPad,
203 {
204 Pads {
205 sercom: self.sercom,
206 data_in: self.data_in,
207 data_out: self.data_out,
208 sclk: pin.into().into_mode(),
209 ss: self.ss,
210 }
211 }
212
213 /// Set the `SS` pad, which is always [`Pad2`]
214 #[inline]
215 pub fn ss<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, DI, DO, CK, Pad<S, Id>>
216 where
217 Id: GetPad<S, PadNum = Pad2>,
218 (DI, DO, CK, Pad<S, Id>): ShareIoSet,
219 Pad<S, Id>: IsPad,
220 {
221 Pads {
222 sercom: self.sercom,
223 data_in: self.data_in,
224 data_out: self.data_out,
225 sclk: self.sclk,
226 ss: pin.into().into_mode(),
227 }
228 }
229
230 /// Consume the [`Pads`] and return each individual
231 /// [`Pin`](crate::gpio::Pin)
232 #[inline]
233 pub fn free(self) -> (DI, DO, CK, SS) {
234 (self.data_in, self.data_out, self.sclk, self.ss)
235 }
236}
237
238//=============================================================================
239// PadsFromIds
240//=============================================================================
241
242/// Define a set of [`Pads`] using [`PinId`]s instead of [`Pin`]s
243///
244/// In some cases, it is more convenient to specify a set of `Pads` using
245/// `PinId`s rather than `Pin`s. This alias makes it easier to do so.
246///
247/// The first parameter is the [`Sercom`], while the
248/// remaining four are effectively [`OptionalPinId`]s representing the
249/// corresponding type parameters of [`Pads`], i.e. `DI`, `DO`, `CK` & `SS`.
250/// Each of the remaining type parameters defaults to [`NoneT`].
251///
252/// ```
253/// use atsamd_hal::pac::Peripherals;
254/// use atsamd_hal::gpio::{PA08, PA09, Pins};
255/// use atsamd_hal::sercom::{Sercom0, spi};
256/// use atsamd_hal::typelevel::NoneT;
257///
258/// pub type Pads = spi::PadsFromIds<Sercom0, PA08, NoneT, PA09>;
259///
260/// pub fn create_pads() -> Pads {
261/// let peripherals = Peripherals::take().unwrap();
262/// let pins = Pins::new(peripherals.PORT);
263/// spi::Pads::default().sclk(pins.pa09).data_in(pins.pa08)
264/// }
265/// ```
266///
267/// [`Pin`]: crate::gpio::Pin
268/// [`PinId`]: crate::gpio::PinId
269/// [`OptionalPinId`]: crate::gpio::OptionalPinId
270pub type PadsFromIds<S, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT> = Pads<
271 S,
272 <DI as GetOptionalPad<S>>::Pad,
273 <DO as GetOptionalPad<S>>::Pad,
274 <CK as GetOptionalPad<S>>::Pad,
275 <SS as GetOptionalPad<S>>::Pad,
276>;
277
278//=============================================================================
279// PadSet
280//=============================================================================
281
282/// Type-level function to recover the [`OptionalPad`] types from a generic set
283/// of [`Pads`]
284///
285/// This trait is used as an interface between the [`Pads`] type and other
286/// types in this module. It acts as a [type-level function], returning the
287/// corresponding [`Sercom`] and [`OptionalPad`] types. It serves to cut down on
288/// the total number of type parameters needed in the [`Config`](super::Config)
289/// struct. The `Config` struct doesn't need access to the [`Pin`]s directly.
290/// Rather, it only needs to apply the [`SomePad`] trait bound when a `Pin` is
291/// required. The `PadSet` trait allows each `Config` struct to store an
292/// instance of `Pads` without itself being generic over all six type parameters
293/// of the `Pads` type.
294///
295/// This trait is a simplified version of the [`AnyKind`] trait pattern.
296///
297/// [`Pin`]: crate::gpio::Pin
298/// [type-level function]: crate::typelevel#type-level-functions
299/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
300pub trait PadSet: Sealed {
301 type Sercom: Sercom;
302 type DataIn: OptionalPad;
303 type DataOut: OptionalPad;
304 type Sclk: OptionalPad;
305 type SS: OptionalPad;
306}
307
308impl<S, DI, DO, CK, SS> Sealed for Pads<S, DI, DO, CK, SS>
309where
310 S: Sercom,
311 DI: OptionalPad,
312 DO: OptionalPad,
313 CK: OptionalPad,
314 SS: OptionalPad,
315 (DI, DO, CK, SS): ShareIoSet,
316{
317}
318
319impl<S, DI, DO, CK, SS> PadSet for Pads<S, DI, DO, CK, SS>
320where
321 S: Sercom,
322 DI: OptionalPad,
323 DO: OptionalPad,
324 CK: OptionalPad,
325 SS: OptionalPad,
326 (DI, DO, CK, SS): ShareIoSet,
327{
328 type Sercom = S;
329 type DataIn = DI;
330 type DataOut = DO;
331 type Sclk = CK;
332 type SS = SS;
333}
334
335//=============================================================================
336// ValidPads
337//=============================================================================
338
339/// Marker trait for valid sets of [`Pads`]
340///
341/// This trait labels sets of `Pads` that:
342/// - Specify [`SomePad`] for `CK` and at least one of `DI` or `DO`
343/// - Use a valid combination of [`PadNum`]s, so that the `Pads` implement
344/// [`DipoDopo`]
345pub trait ValidPads: PadSet + DipoDopo {
346 type Capability: Capability;
347}
348
349impl<S, DI, CK, SS> ValidPads for Pads<S, DI, NoneT, CK, SS>
350where
351 S: Sercom,
352 DI: SomePad,
353 CK: SomePad,
354 SS: OptionalPad,
355 (DI, NoneT, CK, SS): ShareIoSet,
356 Pads<S, DI, NoneT, CK, SS>: DipoDopo,
357{
358 type Capability = Rx;
359}
360
361impl<S, DO, CK, SS> ValidPads for Pads<S, NoneT, DO, CK, SS>
362where
363 S: Sercom,
364 DO: SomePad,
365 CK: SomePad,
366 SS: OptionalPad,
367 (NoneT, DO, CK, SS): ShareIoSet,
368 Pads<S, NoneT, DO, CK, SS>: DipoDopo,
369{
370 type Capability = Tx;
371}
372
373impl<S, DI, DO, CK, SS> ValidPads for Pads<S, DI, DO, CK, SS>
374where
375 S: Sercom,
376 DI: SomePad,
377 DO: SomePad,
378 CK: SomePad,
379 SS: OptionalPad,
380 (DI, DO, CK, SS): ShareIoSet,
381 Pads<S, DI, DO, CK, SS>: DipoDopo,
382{
383 type Capability = Duplex;
384}