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}