atsamd_hal/sercom/spi/
length.rs

1//! Define a trait to track the transaction [`Length`], which represents the
2//! [`Config`] [`Size`] for SAMx5x chips
3//!
4//! This module defines the `Size` trait for SAMx5x chips. These chips always
5//! operate in 32-bit extension mode and use the hardware `LENGTH` counter to
6//! track the length of each transaction, in bytes. See the [`Length`]
7//! documentation for more details.
8//!
9//! [`Config`]: super::Config
10//! [`Size`]: super::Size
11
12use seq_macro::seq;
13use typenum::{Unsigned, U0, U1, U2, U3, U4};
14
15use crate::typelevel::Sealed;
16
17//=============================================================================
18// Transaction length
19//=============================================================================
20
21/// Type-level enum representing the SPI transaction length, in bytes
22///
23/// This trait acts as both a [type-level enum], forming a type class for
24/// transaction lengths, as well as a [type-level function] mapping the `Length`
25/// to the corresponding [`Word`] size.
26///
27/// The SPI transaction length is represented in the type domain using
28/// [`Unsigned`] types from the [`typenum`] crate. The length can be set
29/// statically, using a length from `U1` to `U255`, or it can be set
30/// dynamically, using the [`DynLength`] marker type. All valid `Length` types
31/// are re-exported in this module.
32///
33/// The SPI transaction length affects the word size for the embedded HAL
34/// traits, as well as other aspects of the SPI API. Transaction lengths of 1-4
35/// only require a single read/write of the `DATA` register, so they have an
36/// [`AtomicSize`] behave differently than longer transaction lengths.
37///
38/// [type-level enum]: crate::typelevel#type-level-enums
39/// [type-level function]: crate::typelevel#type-level-functions
40/// [`OpMode`]: super::OpMode
41/// [`AtomicSize`]: super::AtomicSize
42pub trait Length: Sealed + Unsigned + 'static {
43    /// Word size for the transaction length
44    ///
45    /// For lengths 1-4, this type is `u8`, `u16` or `u32`. For longer
46    /// transactions, this type is `[u8, Self::USIZE]`.
47    type Word: 'static;
48}
49
50/// Type alias to recover the [`Word`](Length::Word) type from an
51/// implementation of [`Length`]
52pub type Word<L> = <L as Length>::Word;
53
54/// Marker type for a run-time dynamic [`Length`]
55pub type DynLength = U0;
56
57impl Length for DynLength {
58    type Word = ();
59}
60
61/// Marker trait for statically known transaction [`Length`]s
62pub trait StaticLength: Length {}
63
64impl StaticLength for U1 {}
65impl Length for U1 {
66    type Word = u8;
67}
68
69impl StaticLength for U2 {}
70impl Length for U2 {
71    type Word = u16;
72}
73
74impl StaticLength for U3 {}
75impl Length for U3 {
76    type Word = u32;
77}
78
79impl StaticLength for U4 {}
80impl Length for U4 {
81    type Word = u32;
82}
83
84/// Marker trait for transaction [`Length`]s greater than four
85pub trait GreaterThan4: Length {}
86
87seq!(N in 5..=255 {
88    impl StaticLength for typenum::U~N {}
89    impl GreaterThan4 for typenum::U~N {}
90    impl Length for typenum::U~N {
91        type Word = [u8; typenum::U~N::USIZE];
92    }
93});