1use atsamd_hal_macros::hal_cfg;
31
32use core::ops::Deref;
33
34use crate::pac;
35use pac::Peripherals;
36use pac::sercom0;
37
38#[hal_cfg("sercom0-d5x")]
39use pac::Mclk as ApbClkCtrl;
40#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
41use pac::Pm as ApbClkCtrl;
42
43#[cfg(feature = "dma")]
44use crate::dmac::TriggerSource;
45
46use crate::typelevel::Sealed;
47
48pub mod pad;
49pub use pad::*;
50
51pub mod i2c;
52pub mod spi;
53
54pub mod uart;
55
56#[cfg(feature = "dma")]
57pub mod dma;
58
59pub trait Sercom: Sealed + Deref<Target = sercom0::RegisterBlock> {
65 const NUM: usize;
67
68 #[cfg(feature = "dma")]
70 const DMA_RX_TRIGGER: TriggerSource;
71
72 #[cfg(feature = "dma")]
74 const DMA_TX_TRIGGER: TriggerSource;
75
76 #[cfg(feature = "async")]
77 type Interrupt: crate::async_hal::interrupts::InterruptSource;
78
79 fn enable_apb_clock(&mut self, ctrl: &ApbClkCtrl);
81
82 fn reg_block(peripherals: &mut Peripherals) -> &crate::pac::sercom0::RegisterBlock;
85
86 #[cfg(feature = "async")]
88 #[inline]
89 fn rx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
90 &crate::sercom::async_api::RX_WAKERS[Self::NUM]
91 }
92
93 #[cfg(feature = "async")]
95 #[inline]
96 fn tx_waker() -> &'static embassy_sync::waitqueue::AtomicWaker {
97 &crate::sercom::async_api::TX_WAKERS[Self::NUM]
98 }
99}
100
101macro_rules! sercom {
102 ( $apbmask:ident, $N:expr) => {
103 paste::paste! {
104 pub type [< Sercom $N >] = $crate::pac::[< Sercom $N >];
107 impl Sealed for [< Sercom $N >] {}
108 impl Sercom for [< Sercom $N >] {
109 const NUM: usize = $N;
110
111 #[cfg(feature = "dma")]
112 const DMA_RX_TRIGGER: TriggerSource = TriggerSource::[< Sercom $N Rx >];
113
114 #[cfg(feature = "dma")]
115 const DMA_TX_TRIGGER: TriggerSource = TriggerSource::[< Sercom $N Tx >];
116
117 #[cfg(feature = "async")]
118 #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
119 type Interrupt = $crate::async_hal::interrupts::[< SERCOM $N >];
120
121 #[cfg(feature = "async")]
122 #[hal_cfg("sercom0-d5x")]
123 type Interrupt = $crate::async_hal::interrupts::[< SERCOM $N >];
124
125 #[inline]
126 fn enable_apb_clock(&mut self, ctrl: &ApbClkCtrl) {
127 ctrl.$apbmask().modify(|_, w| w.[< sercom $N _>]().set_bit());
128 }
129
130 #[inline]
131 fn reg_block(peripherals: &mut Peripherals) -> &crate::pac::sercom0::RegisterBlock {
132 &*peripherals.[< sercom $N >]
133 }
134 }
135
136
137 }
138 };
139}
140
141#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
143sercom!(apbcmask, 0);
144
145#[hal_cfg(any("sercom1-d11", "sercom1-d21"))]
146sercom!(apbcmask, 1);
147
148#[hal_cfg(any("sercom2-d11", "sercom2-d21"))]
149sercom!(apbcmask, 2);
150
151#[hal_cfg("sercom3-d21")]
152sercom!(apbcmask, 3);
153
154#[hal_cfg("sercom4-d21")]
155sercom!(apbcmask, 4);
156
157#[hal_cfg("sercom5-d21")]
158sercom!(apbcmask, 5);
159
160#[hal_cfg("sercom0-d5x")]
162sercom!(apbamask, 0);
163
164#[hal_cfg("sercom1-d5x")]
165sercom!(apbamask, 1);
166
167#[hal_cfg("sercom2-d5x")]
168sercom!(apbbmask, 2);
169
170#[hal_cfg("sercom3-d5x")]
171sercom!(apbbmask, 3);
172
173#[hal_cfg("sercom4-d5x")]
174sercom!(apbdmask, 4);
175
176#[hal_cfg("sercom5-d5x")]
177sercom!(apbdmask, 5);
178
179#[hal_cfg("sercom6-d5x")]
180sercom!(apbdmask, 6);
181
182#[hal_cfg("sercom7-d5x")]
183sercom!(apbdmask, 7);
184
185#[hal_cfg("sercom0-d11")]
189#[cfg(feature = "async")]
190const NUM_SERCOM: usize = 3;
191
192#[hal_cfg("sercom0-d21")]
193#[cfg(feature = "async")]
194const NUM_SERCOM: usize = 6;
195
196#[hal_cfg("sercom0-d5x")]
197#[cfg(feature = "async")]
198const NUM_SERCOM: usize = 8;
199
200#[cfg(feature = "async")]
201pub(super) mod async_api {
202 use embassy_sync::waitqueue::AtomicWaker;
203
204 #[allow(clippy::declare_interior_mutable_const)]
205 const NEW_WAKER: AtomicWaker = AtomicWaker::new();
206 pub(super) static RX_WAKERS: [AtomicWaker; super::NUM_SERCOM] = [NEW_WAKER; super::NUM_SERCOM];
209 pub(super) static TX_WAKERS: [AtomicWaker; super::NUM_SERCOM] = [NEW_WAKER; super::NUM_SERCOM];
211}