Skip to main content

rp2040_hal/spi/
pins.rs

1use core::marker::PhantomData;
2
3use crate::{
4    gpio::{bank0::*, pin::pin_sealed::TypeLevelPinId, AnyPin, FunctionSpi},
5    pac::{SPI0, SPI1},
6    typelevel::{OptionT, OptionTNone, OptionTSome, Sealed},
7};
8
9use super::SpiDevice;
10
11macro_rules! pin_validation {
12    ($p:ident) => {
13        paste::paste!{
14            #[doc = "Indicates a valid " $p " pin for SPI0 or SPI1"]
15            pub trait [<ValidPinId $p>]<SPI: SpiDevice>: Sealed {}
16
17            #[doc = "Indicates a valid " $p " pin for SPI0 or SPI1"]
18            pub trait [<ValidPin $p>]<SPI: SpiDevice>: Sealed {}
19
20            impl<T, U: SpiDevice> [<ValidPin $p>]<U> for T
21            where
22                T: AnyPin<Function = FunctionSpi>,
23                T::Id: [<ValidPinId $p>]<U>,
24            {
25            }
26
27            #[doc = "A runtime validated " $p " pin for spi."]
28            pub struct [<ValidatedPin $p>]<P, Spi>(P, PhantomData<Spi>);
29            impl<P, SPI: SpiDevice> Sealed for [<ValidatedPin $p>]<P, SPI> {}
30            impl<P, SPI: SpiDevice> [<ValidPin $p>]<SPI> for [<ValidatedPin $p>]<P, SPI> {}
31            impl<P, S> [<ValidatedPin $p>]<P, S>
32            where
33                P: AnyPin<Function = FunctionSpi>,
34                S: SpiDevice,
35            {
36                /// Validate a pin's function on a spi peripheral.
37                ///
38                #[doc = "Will err if the pin cannot be used as a " $p " pin for that Spi."]
39                pub fn validate(p: P, _u: &S) -> Result<Self, P> {
40                    if [<$p:upper>].contains(&(p.borrow().id().num, S::ID)) &&
41                        p.borrow().id().bank == crate::gpio::DynBankId::Bank0 {
42                        Ok(Self(p, PhantomData))
43                    } else {
44                        Err(p)
45                    }
46                }
47            }
48
49            #[doc = "Indicates a valid optional " $p " pin for SPI0 or SPI1"]
50            pub trait [<ValidOption $p>]<U>: OptionT {}
51
52            impl<U: SpiDevice> [<ValidOption $p>]<U> for OptionTNone {}
53            impl<U, T> [<ValidOption $p>]<U> for OptionTSome<T>
54            where
55                U: SpiDevice,
56                T: [<ValidPin $p>]<U>,
57            {
58            }
59        }
60    };
61    ($($p:ident),*) => {
62        $(
63            pin_validation!($p);
64         )*
65    };
66}
67pin_validation!(Tx, Rx, Sck, Cs);
68
69macro_rules! impl_valid_spi {
70    ($($spi:ident: {
71        rx: [$($rx:ident),*],
72        cs: [$($cs:ident),*],
73        sck: [$($sck:ident),*],
74        tx: [$($tx:ident),*],
75    }),*) => {
76        $(
77            $(impl ValidPinIdRx<$spi> for $rx {})*
78            $(impl ValidPinIdTx<$spi> for $tx {})*
79            $(impl ValidPinIdSck<$spi> for $sck {})*
80            $(impl ValidPinIdCs<$spi> for $cs {})*
81        )*
82
83        const RX: &[(u8, usize)] = &[$($(($rx::ID.num, $spi::ID)),*),*];
84        const TX: &[(u8, usize)] = &[$($(($tx::ID.num, $spi::ID)),*),*];
85        const SCK: &[(u8, usize)] = &[$($(($sck::ID.num, $spi::ID)),*),*];
86        const CS: &[(u8, usize)] = &[$($(($cs::ID.num, $spi::ID)),*),*];
87    };
88}
89
90impl_valid_spi!(
91    SPI0: {
92        rx: [Gpio0, Gpio4, Gpio16, Gpio20],
93        cs: [Gpio1, Gpio5, Gpio17, Gpio21],
94        sck: [Gpio2, Gpio6, Gpio18, Gpio22],
95        tx: [Gpio3, Gpio7, Gpio19, Gpio23],
96    },
97    SPI1: {
98        rx: [Gpio8, Gpio12, Gpio24, Gpio28],
99        cs: [Gpio9, Gpio13, Gpio25, Gpio29],
100        sck: [Gpio10, Gpio14, Gpio26],
101        tx: [Gpio11, Gpio15, Gpio27],
102    }
103);
104
105/// Declares a valid SPI pinout.
106pub trait ValidSpiPinout<U: SpiDevice>: Sealed {
107    #[allow(missing_docs)]
108    type Rx: ValidOptionRx<U>;
109    #[allow(missing_docs)]
110    type Cs: ValidOptionCs<U>;
111    #[allow(missing_docs)]
112    type Sck: ValidOptionSck<U>;
113    #[allow(missing_docs)]
114    type Tx: ValidOptionTx<U>;
115}
116
117impl<Spi, Tx, Sck> ValidSpiPinout<Spi> for (Tx, Sck)
118where
119    Spi: SpiDevice,
120    Tx: ValidPinTx<Spi>,
121    Sck: ValidPinSck<Spi>,
122{
123    type Rx = OptionTNone;
124    type Cs = OptionTNone;
125    type Sck = OptionTSome<Sck>;
126    type Tx = OptionTSome<Tx>;
127}
128
129impl<Spi, Tx, Rx, Sck> ValidSpiPinout<Spi> for (Tx, Rx, Sck)
130where
131    Spi: SpiDevice,
132    Tx: ValidPinTx<Spi>,
133    Sck: ValidPinSck<Spi>,
134    Rx: ValidPinRx<Spi>,
135{
136    type Rx = OptionTSome<Rx>;
137    type Cs = OptionTNone;
138    type Sck = OptionTSome<Sck>;
139    type Tx = OptionTSome<Tx>;
140}
141
142impl<Spi, Tx, Rx, Sck, Cs> ValidSpiPinout<Spi> for (Tx, Rx, Sck, Cs)
143where
144    Spi: SpiDevice,
145    Tx: ValidPinTx<Spi>,
146    Sck: ValidPinSck<Spi>,
147    Rx: ValidPinRx<Spi>,
148    Cs: ValidPinCs<Spi>,
149{
150    type Rx = OptionTSome<Rx>;
151    type Cs = OptionTSome<Cs>;
152    type Sck = OptionTSome<Sck>;
153    type Tx = OptionTSome<Tx>;
154}