1use atsamd_hal_macros::hal_cfg;
47
48use core::ops::Deref;
49
50use crate::pac;
51use pac::Peripherals;
52use pac::sercom0;
53
54#[hal_cfg("sercom0-d5x")]
55use pac::Mclk as ApbClkCtrl;
56#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
57use pac::Pm as ApbClkCtrl;
58
59#[cfg(feature = "dma")]
60use crate::dmac::TriggerSource;
61
62use crate::typelevel::Sealed;
63
64pub mod pad;
65pub use pad::*;
66
67pub mod i2c;
68pub mod spi;
69
70pub mod uart;
71
72#[cfg(feature = "dma")]
73pub mod dma;
74
75pub trait Sercom: Sealed + Deref<Target = sercom0::RegisterBlock> {
81 const NUM: usize;
83
84 #[cfg(feature = "dma")]
86 const DMA_RX_TRIGGER: TriggerSource;
87
88 #[cfg(feature = "dma")]
90 const DMA_TX_TRIGGER: TriggerSource;
91
92 #[cfg(feature = "async")]
93 type Interrupt: crate::async_hal::interrupts::InterruptSource;
94
95 fn enable_apb_clock(&mut self, ctrl: &ApbClkCtrl);
97
98 fn reg_block(peripherals: &mut Peripherals) -> &crate::pac::sercom0::RegisterBlock;
101
102 #[cfg(feature = "async")]
104 #[inline]
105 fn rx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
106 &crate::sercom::async_api::RX_WAKERS[Self::NUM]
107 }
108
109 #[cfg(feature = "async")]
111 #[inline]
112 fn tx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
113 &crate::sercom::async_api::TX_WAKERS[Self::NUM]
114 }
115}
116
117macro_rules! sercom {
118 ( $apbmask:ident, $N:expr) => {
119 paste::paste! {
120 pub type [< Sercom $N >] = $crate::pac::[< Sercom $N >];
123 impl Sealed for [< Sercom $N >] {}
124 impl Sercom for [< Sercom $N >] {
125 const NUM: usize = $N;
126
127 #[cfg(feature = "dma")]
128 const DMA_RX_TRIGGER: TriggerSource = TriggerSource::[< Sercom $N Rx >];
129
130 #[cfg(feature = "dma")]
131 const DMA_TX_TRIGGER: TriggerSource = TriggerSource::[< Sercom $N Tx >];
132
133 #[cfg(feature = "async")]
134 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
135 type Interrupt = $crate::async_hal::interrupts::[< SERCOM $N >];
136
137 #[cfg(feature = "async")]
138 #[hal_cfg("sercom0-d5x")]
139 type Interrupt = $crate::async_hal::interrupts::[< SERCOM $N >];
140
141 #[inline]
142 fn enable_apb_clock(&mut self, ctrl: &ApbClkCtrl) {
143 ctrl.$apbmask().modify(|_, w| w.[< sercom $N _>]().set_bit());
144 }
145
146 #[inline]
147 fn reg_block(peripherals: &mut Peripherals) -> &crate::pac::sercom0::RegisterBlock {
148 &*peripherals.[< sercom $N >]
149 }
150 }
151
152
153 }
154 };
155}
156
157#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
159sercom!(apbcmask, 0);
160
161#[hal_cfg(any("sercom1-d11", "sercom1-d21"))]
162sercom!(apbcmask, 1);
163
164#[hal_cfg(any("sercom2-d11", "sercom2-d21"))]
165sercom!(apbcmask, 2);
166
167#[hal_cfg("sercom3-d21")]
168sercom!(apbcmask, 3);
169
170#[hal_cfg("sercom4-d21")]
171sercom!(apbcmask, 4);
172
173#[hal_cfg("sercom5-d21")]
174sercom!(apbcmask, 5);
175
176#[hal_cfg("sercom0-d5x")]
178sercom!(apbamask, 0);
179
180#[hal_cfg("sercom1-d5x")]
181sercom!(apbamask, 1);
182
183#[hal_cfg("sercom2-d5x")]
184sercom!(apbbmask, 2);
185
186#[hal_cfg("sercom3-d5x")]
187sercom!(apbbmask, 3);
188
189#[hal_cfg("sercom4-d5x")]
190sercom!(apbdmask, 4);
191
192#[hal_cfg("sercom5-d5x")]
193sercom!(apbdmask, 5);
194
195#[hal_cfg("sercom6-d5x")]
196sercom!(apbdmask, 6);
197
198#[hal_cfg("sercom7-d5x")]
199sercom!(apbdmask, 7);
200
201#[hal_cfg("sercom0-d11")]
205#[cfg(feature = "async")]
206const NUM_SERCOM: usize = 3;
207
208#[hal_cfg("sercom0-d21")]
209#[cfg(feature = "async")]
210const NUM_SERCOM: usize = 6;
211
212#[hal_cfg("sercom0-d5x")]
213#[cfg(feature = "async")]
214const NUM_SERCOM: usize = 8;
215
216#[cfg(feature = "async")]
217pub(super) mod async_api {
218 use embassy_sync::waitqueue::AtomicWaker;
219
220 #[allow(clippy::declare_interior_mutable_const)]
221 const NEW_WAKER: AtomicWaker = AtomicWaker::new();
222 pub(super) static RX_WAKERS: [AtomicWaker; super::NUM_SERCOM] = [NEW_WAKER; super::NUM_SERCOM];
225 pub(super) static TX_WAKERS: [AtomicWaker; super::NUM_SERCOM] = [NEW_WAKER; super::NUM_SERCOM];
227}