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, I, DI, DO, CK, SS> DipoDopo for Pads<S, I, DI, DO, CK, SS>
77where
78 S: Sercom,
79 I: IoSet,
80 DI: OptionalPad,
81 DO: OptionalPad,
82 CK: OptionalPad,
83 SS: OptionalPad,
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, I, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT>
110where
111 S: Sercom,
112 I: IoSet,
113 DI: OptionalPad,
114 DO: OptionalPad,
115 CK: OptionalPad,
116 SS: OptionalPad,
117{
118 sercom: PhantomData<S>,
119 ioset: PhantomData<I>,
120 data_in: DI,
121 data_out: DO,
122 sclk: CK,
123 ss: SS,
124}
125
126impl<S: Sercom, I: IoSet> Default for Pads<S, I> {
127 fn default() -> Self {
128 Self {
129 sercom: PhantomData,
130 ioset: PhantomData,
131 data_in: NoneT,
132 data_out: NoneT,
133 sclk: NoneT,
134 ss: NoneT,
135 }
136 }
137}
138
139impl<S, I, DI, DO, CK, SS> Pads<S, I, DI, DO, CK, SS>
140where
141 S: Sercom,
142 I: IoSet,
143 DI: OptionalPad,
144 DO: OptionalPad,
145 CK: OptionalPad,
146 SS: OptionalPad,
147{
148 /// Set the `DI` pad
149 ///
150 /// In a [`MasterMode`], this is MISO. In [`Slave`] [`OpMode`], this is
151 /// MOSI.
152 ///
153 /// [`MasterMode`]: super::MasterMode
154 /// [`Slave`]: super::Slave
155 /// [`OpMode`]: super::OpMode
156 #[inline]
157 pub fn data_in<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, I, Pad<S, Id>, DO, CK, SS>
158 where
159 Id: GetPad<S>,
160 Id::PadNum: Dipo,
161 Pad<S, Id>: InIoSet<I>,
162 {
163 Pads {
164 sercom: self.sercom,
165 ioset: self.ioset,
166 data_in: pin.into().into_mode(),
167 data_out: self.data_out,
168 sclk: self.sclk,
169 ss: self.ss,
170 }
171 }
172
173 /// Set the `DO` pad
174 ///
175 /// In a [`MasterMode`], this is MOSI. In [`Slave`] [`OpMode`], this is
176 /// MISO.
177 ///
178 /// [`MasterMode`]: super::MasterMode
179 /// [`Slave`]: super::Slave
180 /// [`OpMode`]: super::OpMode
181 #[inline]
182 pub fn data_out<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, I, DI, Pad<S, Id>, CK, SS>
183 where
184 Id: GetPad<S>,
185 Id::PadNum: Dopo,
186 Pad<S, Id>: InIoSet<I>,
187 {
188 Pads {
189 sercom: self.sercom,
190 ioset: self.ioset,
191 data_in: self.data_in,
192 data_out: pin.into().into_mode(),
193 sclk: self.sclk,
194 ss: self.ss,
195 }
196 }
197
198 /// Set the `SCK` pad, which is always [`Pad1`]
199 #[inline]
200 pub fn sclk<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, I, DI, DO, Pad<S, Id>, SS>
201 where
202 Id: GetPad<S, PadNum = Pad1>,
203 Pad<S, Id>: InIoSet<I>,
204 {
205 Pads {
206 sercom: self.sercom,
207 ioset: self.ioset,
208 data_in: self.data_in,
209 data_out: self.data_out,
210 sclk: pin.into().into_mode(),
211 ss: self.ss,
212 }
213 }
214
215 /// Set the `SS` pad, which is always [`Pad2`]
216 #[inline]
217 pub fn ss<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, I, DI, DO, CK, Pad<S, Id>>
218 where
219 Id: GetPad<S, PadNum = Pad2>,
220 Pad<S, Id>: InIoSet<I>,
221 {
222 Pads {
223 sercom: self.sercom,
224 ioset: self.ioset,
225 data_in: self.data_in,
226 data_out: self.data_out,
227 sclk: self.sclk,
228 ss: pin.into().into_mode(),
229 }
230 }
231
232 /// Consume the [`Pads`] and return each individual
233 /// [`Pin`](crate::gpio::Pin)
234 #[inline]
235 pub fn free(self) -> (DI, DO, CK, SS) {
236 (self.data_in, self.data_out, self.sclk, self.ss)
237 }
238}
239
240//=============================================================================
241// PadsFromIds
242//=============================================================================
243
244/// Define a set of [`Pads`] using [`PinId`]s instead of [`Pin`]s
245///
246/// In some cases, it is more convenient to specify a set of `Pads` using
247/// `PinId`s rather than `Pin`s. This alias makes it easier to do so.
248///
249/// The first two type parameters are the [`Sercom`] and [`IoSet`], while the
250/// remaining four are effectively [`OptionalPinId`]s representing the
251/// corresponding type parameters of [`Pads`], i.e. `DI`, `DO`, `CK` & `SS`.
252/// Each of the remaining type parameters defaults to [`NoneT`].
253///
254/// ```
255/// use atsamd_hal::pac::Peripherals;
256/// use atsamd_hal::gpio::{PA08, PA09, Pins};
257/// use atsamd_hal::sercom::{Sercom0, spi};
258/// use atsamd_hal::sercom::pad::IoSet1;
259/// use atsamd_hal::typelevel::NoneT;
260///
261/// pub type Pads = spi::PadsFromIds<Sercom0, IoSet1, PA08, NoneT, PA09>;
262///
263/// pub fn create_pads() -> Pads {
264/// let peripherals = Peripherals::take().unwrap();
265/// let pins = Pins::new(peripherals.PORT);
266/// spi::Pads::default().sclk(pins.pa09).data_in(pins.pa08)
267/// }
268/// ```
269///
270/// [`Pin`]: crate::gpio::Pin
271/// [`PinId`]: crate::gpio::PinId
272/// [`OptionalPinId`]: crate::gpio::OptionalPinId
273pub type PadsFromIds<S, I, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT> = Pads<
274 S,
275 I,
276 <DI as GetOptionalPad<S>>::Pad,
277 <DO as GetOptionalPad<S>>::Pad,
278 <CK as GetOptionalPad<S>>::Pad,
279 <SS as GetOptionalPad<S>>::Pad,
280>;
281
282//=============================================================================
283// PadSet
284//=============================================================================
285
286/// Type-level function to recover the [`OptionalPad`] types from a generic set
287/// of [`Pads`]
288///
289/// This trait is used as an interface between the [`Pads`] type and other
290/// types in this module. It acts as a [type-level function], returning the
291/// corresponding [`Sercom`] and [`OptionalPad`] types. It serves to cut down on
292/// the total number of type parameters needed in the [`Config`](super::Config)
293/// struct. The `Config` struct doesn't need access to the [`Pin`]s directly.
294/// Rather, it only needs to apply the [`SomePad`] trait bound when a `Pin` is
295/// required. The `PadSet` trait allows each `Config` struct to store an
296/// instance of `Pads` without itself being generic over all six type parameters
297/// of the `Pads` type.
298///
299/// This trait is a simplified version of the [`AnyKind`] trait pattern.
300///
301/// [`Pin`]: crate::gpio::Pin
302/// [type-level function]: crate::typelevel#type-level-functions
303/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
304pub trait PadSet: Sealed {
305 type Sercom: Sercom;
306 type IoSet: IoSet;
307 type DataIn: OptionalPad;
308 type DataOut: OptionalPad;
309 type Sclk: OptionalPad;
310 type SS: OptionalPad;
311}
312
313impl<S, I, DI, DO, CK, SS> Sealed for Pads<S, I, DI, DO, CK, SS>
314where
315 S: Sercom,
316 I: IoSet,
317 DI: OptionalPad,
318 DO: OptionalPad,
319 CK: OptionalPad,
320 SS: OptionalPad,
321{
322}
323
324impl<S, I, DI, DO, CK, SS> PadSet for Pads<S, I, DI, DO, CK, SS>
325where
326 S: Sercom,
327 I: IoSet,
328 DI: OptionalPad,
329 DO: OptionalPad,
330 CK: OptionalPad,
331 SS: OptionalPad,
332{
333 type Sercom = S;
334 type IoSet = I;
335 type DataIn = DI;
336 type DataOut = DO;
337 type Sclk = CK;
338 type SS = SS;
339}
340
341//=============================================================================
342// ValidPads
343//=============================================================================
344
345/// Marker trait for valid sets of [`Pads`]
346///
347/// This trait labels sets of `Pads` that:
348/// - Specify [`SomePad`] for `CK` and at least one of `DI` or `DO`
349/// - Use a valid combination of [`PadNum`]s, so that the `Pads` implement
350/// [`DipoDopo`]
351pub trait ValidPads: PadSet + DipoDopo {
352 type Capability: Capability;
353}
354
355impl<S, I, DI, CK, SS> ValidPads for Pads<S, I, DI, NoneT, CK, SS>
356where
357 S: Sercom,
358 I: IoSet,
359 DI: SomePad,
360 CK: SomePad,
361 SS: OptionalPad,
362 Pads<S, I, DI, NoneT, CK, SS>: DipoDopo,
363{
364 type Capability = Rx;
365}
366
367impl<S, I, DO, CK, SS> ValidPads for Pads<S, I, NoneT, DO, CK, SS>
368where
369 S: Sercom,
370 I: IoSet,
371 DO: SomePad,
372 CK: SomePad,
373 SS: OptionalPad,
374 Pads<S, I, NoneT, DO, CK, SS>: DipoDopo,
375{
376 type Capability = Tx;
377}
378
379impl<S, I, DI, DO, CK, SS> ValidPads for Pads<S, I, DI, DO, CK, SS>
380where
381 S: Sercom,
382 I: IoSet,
383 DI: SomePad,
384 DO: SomePad,
385 CK: SomePad,
386 SS: OptionalPad,
387 Pads<S, I, DI, DO, CK, SS>: DipoDopo,
388{
389 type Capability = Duplex;
390}