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 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
//! Type-level tools to configure SERCOM pads
//!
//! This module helps configure [`Pin`]s as SERCOM pads. It provides type-level
//! tools to convert `Pin`s to the correct [`PinMode`] and to enforce type-level
//! constraints at compile-time.
//!
//! # Overview
//!
//! A SERCOM pad is defined by two types, its corresponding [`Sercom`] instance
//! and its [`PadNum`], from [`Pad0`] to [`Pad3`]. However, a given SERCOM pad
//! can usually be mapped to several possible [`PinId`]s.
//!
//! There are two primary traits defined in this module:
//! - The [`IsPad`] trait is implemented on `Pin` types that are properly
//! configured as SERCOM pads, with `PinMode` [`AlternateC`] or
//! [`AlternateD`]. It acts as both a [type class] for SERCOM pads and as a
//! [type-level function] to recover the corresponding [`Sercom`] and
//! [`PadNum`] types from the `Pin`.
//! - The [`GetPad`] trait maps each [`PinId`] to its corresponding, pad-related
//! types. The [`PadMode`] alias uses `GetPad` to recover the corresponding
//! `PinMode` for a given SERCOM pad, while the [`Pad`] alias recovers the
//! configured [`Pin`] type.
//!
//! [`AlternateC`]: crate::gpio::AlternateC
//! [`AlternateD`]: crate::gpio::AlternateD
//! [type class]: crate::typelevel#type-classes
//! [type-level function]: crate::typelevel#type-level-functions
#![cfg_attr(
feature = "min-samd51g",
doc = "
# IOSET\n
\n
SAMx5x chips do not allow arbitrary combinations of `PinId` for a given
SERCOM. Instead, all `PinId`s must belong to the same IOSET. This module
defines a [type-level enum], [`IoSet`], to enforce this restriction, and the
[`InIoSet`] [type class] is responsible for labeling each `IsPad` type with
its corresponding, valid `IoSet`\\(s).\n
\n
"
)]
use paste::paste;
use seq_macro::seq;
use super::Sercom;
#[cfg(not(feature = "samd11"))]
use crate::gpio::OptionalPinId;
use crate::gpio::{AnyPin, OptionalPin, Pin, PinId, PinMode};
use crate::typelevel::{NoneT, Sealed};
#[cfg(any(feature = "samd11", feature = "samd21"))]
#[path = "pad/impl_pad_thumbv6m.rs"]
mod impl_pad;
#[cfg(feature = "min-samd51g")]
#[path = "pad/impl_pad_thumbv7em.rs"]
mod impl_pad;
//==============================================================================
// PadNum
//==============================================================================
/// Type-level enum representing a SERCOM pad number
///
/// It has variants [`Pad0`], [`Pad1`], [`Pad2`] & [`Pad3`]. See the [type-level
/// enum] documentation for an explanation of the pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub trait PadNum: Sealed {}
seq!(N in 0..=3 {
paste! {
#[doc = "Type-level variant of [`PadNum`] representing SERCOM pad " N]
///
/// See the [type-level enum] documentation for an explanation of the
/// pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub enum Pad~N {}
impl Sealed for Pad~N {}
impl PadNum for Pad~N {}
}
});
//==============================================================================
// OptionalPadNum
//==============================================================================
/// Type-level equivalent of `Option<PadNum>`
///
/// See the [`OptionalKind`] documentation for more details on the pattern.
///
/// [`OptionalKind`]: crate::typelevel#optionalkind-trait-pattern
pub trait OptionalPadNum: Sealed {}
impl OptionalPadNum for NoneT {}
impl<N: PadNum> OptionalPadNum for N {}
//==============================================================================
// IsPad
//==============================================================================
/// Type class for [`Pin`]s configured as SERCOM pads
///
/// This trait serves as both a [type class] for `Pin`s configured as SERCOM
/// pads and as a [type-level function] mapping each `Pin` type to its
/// corresponding [`Sercom`] and [`PadNum`].
///
/// [type class]: crate::typelevel#type-classes
/// [type-level function]: crate::typelevel#type-level-functions
pub trait IsPad: AnyPin {
type Sercom: Sercom;
type PadNum: PadNum;
}
//==============================================================================
// IsI2cPad
//==============================================================================
/// Type class for [`Pin`]s which can be used as I2C pads
///
/// This trait serves as a [type class] for `Pin`s configured as I2C pads.
///
/// [type class]: crate::typelevel#type-classes
pub trait IsI2cPad: IsPad {}
//==============================================================================
// OptionalPad
//==============================================================================
/// Type-level equivalent of `Option<Pad>`
///
/// See the [`OptionalKind`] documentation for more details on the pattern.
///
/// [`OptionalKind`]: crate::typelevel#optionalkind-trait-pattern
pub trait OptionalPad: OptionalPin {
type PadNum: OptionalPadNum;
}
impl OptionalPad for NoneT {
type PadNum = NoneT;
}
impl<P: IsPad> OptionalPad for P {
type PadNum = P::PadNum;
}
/// Type-level equivalent of `Some(Pad)`
///
/// See the [`OptionalKind`] documentation for more details on the pattern.
///
/// [`OptionalKind`]: crate::typelevel#optionalkind-trait-pattern
pub trait SomePad: IsPad {}
impl<P: IsPad> SomePad for P {}
//==============================================================================
// GetPad
//==============================================================================
/// Type-level function mapping [`PinId`]s to SERCOM-pad-related types
///
/// For SAMD21 and SAMx5x chips, a [`Sercom`] and a [`PinId`] is enough
/// information to uniquely identify a pad, so this trait returns the
/// corresponding [`PadNum`] and [`PinMode`].
///
/// For SAMD11 chips, on the other hand, some `PinId`s can serve as two
/// different `PadNum`s for the *same* `Sercom`. For these chips, `GetPad`
/// requires a second type parameter to specify the `PadNum` and only returns
/// the `PinMode`.
///
/// See the documentation on [type-level functions] for more details.
///
/// [type-level functions]: crate::typelevel#type-level-functions
#[cfg(feature = "samd11")]
pub trait GetPad<S, N>
where
S: Sercom,
N: PadNum,
Self: PinId,
{
type PinMode: PinMode;
}
/// Type-level function mapping [`PinId`]s to SERCOM-pad-related types
///
/// For SAMD21 and SAMx5x chips, a [`Sercom`] and a [`PinId`] is enough
/// information to uniquely identify a pad, so this trait returns the
/// corresponding [`PadNum`] and [`PinMode`].
///
/// For SAMD11 chips, on the other hand, some `PinId`s can serve as two
/// different `PadNum`s for the *same* `Sercom`. For these chips, `GetPad`
/// requires a second type parameter to specify the `PadNum` and only returns
/// the `PinMode`.
///
/// See the documentation on [type-level functions] for more details.
///
/// [type-level functions]: crate::typelevel#type-level-functions
#[cfg(not(feature = "samd11"))]
pub trait GetPad<S>
where
S: Sercom,
Self: PinId,
{
type PadNum: PadNum;
type PinMode: PinMode;
}
//==============================================================================
// GetPad aliases
//==============================================================================
/// Type alias using [`GetPad`] to recover the [`PinMode`] for a given SERCOM
/// pad
#[cfg(feature = "samd11")]
pub type PadMode<S, N, I> = <I as GetPad<S, N>>::PinMode;
/// Type alias using [`GetPad`] to recover the [`PinMode`] for a given SERCOM
/// pad
#[cfg(not(feature = "samd11"))]
pub type PadMode<S, I> = <I as GetPad<S>>::PinMode;
/// Type alias to recover a [`Pin`] configured as a SERCOM pad in the correct
/// [`PadMode`]
#[cfg(feature = "samd11")]
pub type Pad<S, N, I> = Pin<I, PadMode<S, N, I>>;
/// Type alias to recover a [`Pin`] configured as a SERCOM pad in the correct
/// [`PadMode`]
#[cfg(not(feature = "samd11"))]
pub type Pad<S, I> = Pin<I, PadMode<S, I>>;
//==============================================================================
// GetOptionalPad
//==============================================================================
/// Type-level function mapping [`OptionalPinId`]s to their corresponding
/// [`OptionalPad`]s
///
/// This trait acts as a [type-level function] mapping `OptionalPinId`s to their
/// corresponding `OptionalPad`. In pseudo-Rust, it is the type-level equivalent
/// of starting with `Option<PinId>` and calling `.map(GetPad)` to recover an
/// `Option<Pad>`.
///
/// [type-level functions]: crate::typelevel#type-level-functions
#[cfg(not(feature = "samd11"))]
pub trait GetOptionalPad<S: Sercom>: OptionalPinId {
type PadNum: OptionalPadNum;
type Pad: OptionalPad;
}
#[cfg(not(feature = "samd11"))]
impl<S: Sercom> GetOptionalPad<S> for NoneT {
type PadNum = NoneT;
type Pad = NoneT;
}
#[cfg(not(feature = "samd11"))]
impl<S, I> GetOptionalPad<S> for I
where
S: Sercom,
I: PinId + GetPad<S>,
Pad<S, I>: IsPad,
{
type PadNum = I::PadNum;
type Pad = Pad<S, I>;
}
//==============================================================================
// IoSet
//==============================================================================
#[cfg(feature = "min-samd51g")]
mod ioset {
use super::*;
/// Type-level enum representing a SERCOM IOSET
///
/// See the [type-level enum] documentation for more details on the pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub trait IoSet: Sealed {}
seq!(N in 1..=6 {
paste! {
#[doc = "Type-level variant of [`IoSet`] representing SERCOM IOSET " N]
///
/// See the [type-level enum] documentation for more details on the
/// pattern.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub enum IoSet~N {}
impl Sealed for IoSet~N {}
impl IoSet for IoSet~N {}
}
});
/// Type-level variant of [`IoSet`] representing an undocumented SERCOM
/// IOSET
///
/// After implementing `IoSet` type checking, it became clear that some
/// existing boards were using a combinations of pins that did not match any
/// IOSET in the datasheet. From that, we infer that there must be at least
/// two undocumented IOSETs, and we added these new `IoSet`s to account for
/// it.
///
/// As of writing this documentation, only two undocumented IOSETs have been
/// discovered:
/// - [`UndocIoSet1`]: PA16, PA17, PB22 & PB23 configured for `Sercom1`.
/// Both the
/// pygamer & feather_m4 uses this combination.
/// - [`UndocIoSet2`]: PA00, PA01, PB22 & PB23 configured for `Sercom1`. The
/// itsybitsy_m4 uses this combination.
///
/// See the [type-level enum] documentation for more details on type-level
/// variants.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub enum UndocIoSet1 {}
impl Sealed for UndocIoSet1 {}
impl IoSet for UndocIoSet1 {}
/// Type-level variant of [`IoSet`] representing an undocumented SERCOM
/// IOSET
///
/// After implementing `IoSet` type checking, it became clear that some
/// existing boards were using a combinations of pins that did not match any
/// IOSET in the datasheet. From that, we infer that there must be at least
/// two undocumented IOSETs, and we added these new `IoSet`s to account for
/// it.
///
/// As of writing this documentation, only two undocumented IOSETs have been
/// discovered:
/// - [`UndocIoSet1`]: PA16, PA17, PB22 & PB23 configured for `Sercom1`.
/// Both the
/// pygamer & feather_m4 uses this combination.
/// - [`UndocIoSet2`]: PA00, PA01, PB22 & PB23 configured for `Sercom1`. The
/// itsybitsy_m4 uses this combination.
///
/// See the [type-level enum] documentation for more details on type-level
/// variants.
///
/// [type-level enum]: crate::typelevel#type-level-enum
pub enum UndocIoSet2 {}
impl Sealed for UndocIoSet2 {}
impl IoSet for UndocIoSet2 {}
/// Type class for SERCOM pads in a given [`IoSet`]
///
/// This trait is used to label each [`Pin`] implementing [`IsPad`] with its
/// corresponding [`IoSet`]\(s). Downstream types can use this trait as a
/// [type class] to restrict [`Pin`]s to a given [`IoSet`]. See the [type
/// class] documentation for more details on the pattern.
///
/// [type class]: crate::typelevel#type-classes
pub trait InIoSet<I>
where
Self: IsPad,
I: IoSet,
{
}
}
#[cfg(feature = "min-samd51g")]
pub use ioset::*;