1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
use core::marker::PhantomData;
use paste::paste;
use super::pin::DynBankId;
pub(crate) mod func_sealed {
use super::DynFunction;
pub trait Function {
fn from(f: DynFunction) -> Self;
fn as_dyn(&self) -> DynFunction;
}
}
/// Type-level `enum` for pin function.
pub trait Function: func_sealed::Function {}
/// Describes the function currently assigned to a pin with a dynamic type.
///
/// A 'pin' on the RP2040 can be connected to different parts of the chip
/// internally - for example, it could be configured as a GPIO pin and connected
/// to the SIO block, or it could be configured as a UART pin and connected to
/// the UART block.
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DynFunction {
/// The 'XIP' (or Execute-in-place) function, which means talking to the QSPI Flash.
Xip,
/// The 'SPI' (or serial-peripheral-interface) function.
Spi,
/// The 'UART' (or serial-port) function.
Uart,
/// The 'I2C' (or inter-integrated circuit) function. This is sometimes also called TWI (for
/// two-wire-interface).
I2c,
/// The 'PWM' (or pulse-width-modulation) function.
Pwm,
/// The 'SIO' (or single-cycle input-output) function. This is the function to use for
/// 'manually' controlling the GPIO.
Sio(DynSioConfig),
/// The 'PIO' (or programmable-input-output) function for the PIO0 peripheral block.
Pio0,
/// The 'PIO' (or programmable-input-output) function for the PIO1 peripheral block.
Pio1,
/// The 'Clock' function. This can be used to input or output clock references to or from the
/// rp2040.
Clock,
/// The 'USB' function. Only VBUS detect, VBUS enable and overcurrent detect are configurable.
/// Other USB io have dedicated pins.
Usb,
/// The 'Null' function for unused pins.
Null,
}
/// Value-level `enum` for SIO configuration.
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DynSioConfig {
/// Pin is configured as Input.
Input,
/// Pin is configured as Output.
Output,
}
impl Function for DynFunction {}
impl func_sealed::Function for DynFunction {
#[inline]
fn from(f: DynFunction) -> Self {
f
}
#[inline]
fn as_dyn(&self) -> DynFunction {
*self
}
}
macro_rules! pin_func {
($($fn:ident $(as $alias:ident)?),*) => {
$(paste! {
/// Type-level `variant` for pin [`Function`].
pub struct [<Function $fn>](pub(super) ());
impl Function for [<Function $fn>] {}
impl func_sealed::Function for [<Function $fn>] {
#[inline]
fn from(_f: DynFunction) -> Self {
Self(())
}
#[inline]
fn as_dyn(&self) -> DynFunction {
DynFunction::[<$fn>]
}
}
$(
#[doc = "Alias to [`Function" $fn "`]."]
pub type [<Function $alias>] = [<Function $fn>];
)?
})*
};
}
pin_func!(Xip, Spi, Uart, I2c as I2C, Pwm, Pio0, Pio1, Clock, Usb, Null);
//==============================================================================
// SIO sub-types
//==============================================================================
/// Type-level `variant` for pin [`Function`].
pub struct FunctionSio<C>(PhantomData<C>);
impl<C: SioConfig> Function for FunctionSio<C> {}
impl<C: SioConfig> func_sealed::Function for FunctionSio<C> {
fn from(_f: DynFunction) -> Self {
FunctionSio(PhantomData)
}
fn as_dyn(&self) -> DynFunction {
DynFunction::Sio(C::DYN)
}
}
/// Alias to [`FunctionSio<Input>`].
pub type FunctionSioInput = FunctionSio<SioInput>;
/// Alias to [`FunctionSio<Output>`].
pub type FunctionSioOutput = FunctionSio<SioOutput>;
/// Type-level `enum` for SIO configuration.
pub trait SioConfig {
#[allow(missing_docs)]
const DYN: DynSioConfig;
}
/// Type-level `variant` for SIO configuration.
pub enum SioInput {}
impl SioConfig for SioInput {
#[allow(missing_docs)]
const DYN: DynSioConfig = DynSioConfig::Input;
}
/// Type-level `variant` for SIO configuration.
pub enum SioOutput {}
impl SioConfig for SioOutput {
#[allow(missing_docs)]
const DYN: DynSioConfig = DynSioConfig::Output;
}
//==============================================================================
// Pin to function mapping
//==============================================================================
/// Error type for invalid function conversion.
pub struct InvalidFunction;
/// Marker of valid pin -> function combination.
///
/// Where `impl ValidFunction<F> for I` reads as `F is a valid function implemented for the pin I`.
pub trait ValidFunction<F: Function>: super::pin::PinId {}
impl DynFunction {
pub(crate) fn is_valid<P: super::pin::PinId>(&self, id: &P) -> bool {
use DynBankId::*;
use DynFunction::*;
let dyn_pin = id.as_dyn();
match (self, dyn_pin.bank, dyn_pin.num) {
(Xip, Bank0, _) => false,
(Clock, _, 0..=19 | 26..=29) => false,
(_, Bank0, 0..=29) => true,
(Xip | Sio(_), Qspi, 0..=5) => true,
(_, Qspi, 0..=5) => false,
_ => unreachable!(),
}
}
}
impl<P: super::pin::PinId> ValidFunction<DynFunction> for P {}
macro_rules! pin_valid_func {
($bank:ident as $prefix:ident, [$head:ident $(, $func:ident)*], [$($name:tt),+]) => {
pin_valid_func!($bank as $prefix, [$($func),*], [$($name),+]);
paste::paste!{$(
impl ValidFunction<[<Function $head>]> for super::pin::[<$bank:lower>]::[<$prefix $name>] {}
)+}
};
($bank:ident as $prefix:ident, [], [$($name:tt),+]) => {};
}
pin_valid_func!(
bank0 as Gpio,
[Spi, Uart, I2c, Pwm, Pio0, Pio1, Usb, Null],
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29
]
);
pin_valid_func!(bank0 as Gpio, [Clock], [20, 21, 22, 23, 24, 25]);
pin_valid_func!(qspi as Qspi, [Xip, Null], [Sclk, Sd0, Sd1, Sd2, Sd3, Ss]);
macro_rules! pin_valid_func_sio {
($bank:ident as $prefix:ident, [$($name:tt),+]) => {
paste::paste!{$(
impl<C: SioConfig> ValidFunction<FunctionSio<C>> for super::pin::[<$bank:lower>]::[<$prefix $name>] {}
)+}
};
}
pin_valid_func_sio!(
bank0 as Gpio,
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29
]
);
pin_valid_func_sio!(qspi as Qspi, [Sclk, Sd0, Sd1, Sd2, Sd3, Ss]);