1//! # Configure the SERCOM peripherals
2//!
3//! The SERCOM module is used to configure the SERCOM peripherals as USART, SPI
4//! or I2C interfaces.
5//! # Undocumented features
6//!
7//! The ATSAMx5x chips contain certain features that aren't documented in the
8//! datasheet. These features are implemented in the HAL based on
9//! experimentation with certain boards which have verifiably demonstrated that
10//! those features work as intended.
11//!
12//! * [`UndocIoSet1`]: Implement an undocumented `IoSet` for PA16, PA17, PB22 &
13//! PB23 configured for [`Sercom1`]. The pygamer & feather_m4 use this
14//! combination, but it is not listed as valid in the datasheet.
15//!
16//! * [`UndocIoSet2`]: Implement an undocumented `IoSet` for PA00, PA01, PB22 &
17//! PB23 configured for [`Sercom1`]. The itsybitsy_m4 uses this combination,
18//! but it is not listed as valid in the datasheet.
19//!
20//! * [`PB02`] is I2C-capable according to metro_m4. As such, [`PB02`]
21//! implements [`IsI2cPad`].
22//!
23//! * [`PB03`] is I2C-capable according to metro_m4. As such, [`PB03`]
24//! implements [`IsI2cPad`].
25//!
26//! [`PB02`]: crate::gpio::pin::PB02
27//! [`PB03`]: crate::gpio::pin::PB03
28//! [`IsI2cPad`]: pad::IsI2cPad
2930use atsamd_hal_macros::hal_cfg;
3132use core::ops::Deref;
3334use crate::pac;
35use pac::sercom0;
36use pac::Peripherals;
3738#[hal_cfg("sercom0-d5x")]
39use pac::Mclk as ApbClkCtrl;
40#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
41use pac::Pm as ApbClkCtrl;
4243#[cfg(feature = "dma")]
44use crate::dmac::TriggerSource;
4546use crate::typelevel::Sealed;
4748pub mod pad;
49pub use pad::*;
5051pub mod i2c;
52pub mod spi;
5354#[deprecated(
55 since = "0.19.0",
56 note = "spi_future is deprecated and will be removed in a later version of atsamd_hal. Consider using the `async` APIs available in the `spi` module as a replacement."
57)]
58pub mod spi_future;
59pub mod uart;
6061#[cfg(feature = "dma")]
62pub mod dma;
6364//==============================================================================
65// Sercom
66//==============================================================================
6768/// Type-level `enum` representing a Serial Communication Interface (SERCOM)
69pub trait Sercom: Sealed + Deref<Target = sercom0::RegisterBlock> {
70/// SERCOM number
71const NUM: usize;
7273/// RX Trigger source for DMA transactions
74#[cfg(feature = "dma")]
75const DMA_RX_TRIGGER: TriggerSource;
7677/// TX trigger source for DMA transactions
78#[cfg(feature = "dma")]
79const DMA_TX_TRIGGER: TriggerSource;
8081#[cfg(feature = "async")]
82type Interrupt: crate::async_hal::interrupts::InterruptSource;
8384/// Enable the corresponding APB clock
85fn enable_apb_clock(&mut self, ctrl: &ApbClkCtrl);
8687/// Get a reference to the sercom from a
88 /// [`Peripherals`] block
89fn reg_block(peripherals: &mut Peripherals) -> &crate::pac::sercom0::RegisterBlock;
9091/// Get a reference to this [`Sercom`]'s associated RX Waker
92#[cfg(feature = "async")]
93 #[inline]
94fn rx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
95&crate::sercom::async_api::RX_WAKERS[Self::NUM]
96 }
9798/// Get a reference to this [`Sercom`]'s associated TX Waker
99#[cfg(feature = "async")]
100 #[inline]
101fn tx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
102&crate::sercom::async_api::TX_WAKERS[Self::NUM]
103 }
104}
105106macro_rules! sercom {
107 ( $apbmask:ident, $N:expr) => {
108paste::paste! {
109// use pac::$pac_type;
110/// Type alias for the corresponding SERCOM instance
111pub type [< Sercom $N >] = $crate::pac::[< Sercom $N >];
112impl Sealed for [< Sercom $N >] {}
113impl Sercom for [< Sercom $N >] {
114const NUM: usize = $N;
115116#[cfg(feature = "dma")]
117const DMA_RX_TRIGGER: TriggerSource = TriggerSource::[< Sercom $N Rx >];
118119#[cfg(feature = "dma")]
120const DMA_TX_TRIGGER: TriggerSource = TriggerSource::[< Sercom $N Tx >];
121122#[cfg(feature = "async")]
123 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
124type Interrupt = $crate::async_hal::interrupts::[< SERCOM $N >];
125126#[cfg(feature = "async")]
127 #[hal_cfg("sercom0-d5x")]
128type Interrupt = $crate::async_hal::interrupts::[< SERCOM $N >];
129130#[inline]
131fn enable_apb_clock(&mut self, ctrl: &ApbClkCtrl) {
132 ctrl.$apbmask().modify(|_, w| w.[< sercom $N _>]().set_bit());
133 }
134135#[inline]
136fn reg_block(peripherals: &mut Peripherals) -> &crate::pac::sercom0::RegisterBlock {
137&*peripherals.[< sercom $N >]
138 }
139 }
140141142 }
143 };
144}
145146// d11 and d21 families
147#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
148sercom!(apbcmask, 0);
149150#[hal_cfg(any("sercom1-d11", "sercom1-d21"))]
151sercom!(apbcmask, 1);
152153#[hal_cfg(any("sercom2-d11", "sercom2-d21"))]
154sercom!(apbcmask, 2);
155156#[hal_cfg("sercom3-d21")]
157sercom!(apbcmask, 3);
158159#[hal_cfg("sercom4-d21")]
160sercom!(apbcmask, 4);
161162#[hal_cfg("sercom5-d21")]
163sercom!(apbcmask, 5);
164165// d5x family
166#[hal_cfg("sercom0-d5x")]
167sercom!(apbamask, 0);
168169#[hal_cfg("sercom1-d5x")]
170sercom!(apbamask, 1);
171172#[hal_cfg("sercom2-d5x")]
173sercom!(apbbmask, 2);
174175#[hal_cfg("sercom3-d5x")]
176sercom!(apbbmask, 3);
177178#[hal_cfg("sercom4-d5x")]
179sercom!(apbdmask, 4);
180181#[hal_cfg("sercom5-d5x")]
182sercom!(apbdmask, 5);
183184#[hal_cfg("sercom6-d5x")]
185sercom!(apbdmask, 6);
186187#[hal_cfg("sercom7-d5x")]
188sercom!(apbdmask, 7);
189190// Reserve space for the max number of SERCOM peripherals based on chip type,
191// even though some wakers may not be used on some chips if they actually don't
192// exist on variant's hardware
193#[hal_cfg("sercom0-d11")]
194#[cfg(feature = "async")]
195const NUM_SERCOM: usize = 3;
196197#[hal_cfg("sercom0-d21")]
198#[cfg(feature = "async")]
199const NUM_SERCOM: usize = 6;
200201#[hal_cfg("sercom0-d5x")]
202#[cfg(feature = "async")]
203const NUM_SERCOM: usize = 8;
204205#[cfg(feature = "async")]
206pub(super) mod async_api {
207use embassy_sync::waitqueue::AtomicWaker;
208209#[allow(clippy::declare_interior_mutable_const)]
210const NEW_WAKER: AtomicWaker = AtomicWaker::new();
211/// Waker for a RX event. By convention, if a SERCOM has only one type of
212 /// event (ie, I2C), this the waker to be used.
213pub(super) static RX_WAKERS: [AtomicWaker; super::NUM_SERCOM] = [NEW_WAKER; super::NUM_SERCOM];
214/// Waker for a TX event.
215pub(super) static TX_WAKERS: [AtomicWaker; super::NUM_SERCOM] = [NEW_WAKER; super::NUM_SERCOM];
216}