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}