atsamd_hal/peripherals/clock/d5x/v2/
apb.rs

1//! # Advanced peripheral bus clocks
2//!
3//! ## Overview
4//!
5//! APB clocks facilitate communication between the processor core and
6//! peripherals on the APB bus. To communicate with a peripheral, the
7//! corresponding APB clock must be enabled, which is done by setting a bit in
8//! one of the four `APBXMASK` registers.
9//!
10//! In this module, *enabled* APB clocks are represented by the [`ApbClk<A>`]
11//! struct, where the type parameter `A` is a type that implements [`ApbId`] and
12//! corresponds to one of the bits in an `APBXMASK` register.
13//!
14//! While most other clocks in the `clock` module are configured through
15//! mutually exclusive registers, the [`ApbClk`]s share the four `APBXMASK`
16//! registers. This presents a challenge for memory safety. Specifically, if we
17//! allowed unrestricted access to the corresponding `APBXMASK` register through
18//! each `ApbClk`, we could create data races.
19//!
20//! To solve this problem, we restrict access to the `APBXMASK` registers using
21//! the [`Apb`] type. `Apb` was created to act as a gateway to the `APBXMASK`
22//! registers, allowing us to use `&mut Apb` as compile-time proof of exclusive
23//! access to them.
24//!
25//! ## Example
26//!
27//! Enabling and disabling the [`ApbClk`]s proceeds according to the principles
28//! outlined in the [`clock` module documentation]. It is best shown with an
29//! example.
30//!
31//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking
32//! structs.
33//!
34//! ```no_run
35//! use atsamd_hal::{
36//!     clock::v2::{
37//!         clock_system_at_reset,
38//!     },
39//!     pac::Peripherals,
40//! };
41//! let mut pac = Peripherals::take().unwrap();
42//! let (mut buses, clocks, tokens) = clock_system_at_reset(
43//!     pac.oscctrl,
44//!     pac.osc32kctrl,
45//!     pac.gclk,
46//!     pac.mclk,
47//!     &mut pac.nvmctrl,
48//! );
49//! ```
50//!
51//! Some APB clocks are enabled at power-on reset. We can find these in the
52//! [`Clocks`] struct.
53//!
54//! ```no_run
55//! # use atsamd_hal::{
56//! #     clock::v2::{
57//! #         clock_system_at_reset,
58//! #     },
59//! #     pac::Peripherals,
60//! # };
61//! # let mut pac = Peripherals::take().unwrap();
62//! # let (mut buses, clocks, tokens) = clock_system_at_reset(
63//! #     pac.oscctrl,
64//! #     pac.osc32kctrl,
65//! #     pac.gclk,
66//! #     pac.mclk,
67//! #     &mut pac.nvmctrl,
68//! # );
69//! let apb_port = clocks.apbs.port;
70//! ```
71//!
72//! Other APB clocks are disabled at power-on reset. To enable these, we must
73//! have access to the [`Apb`] bus type, which is found in the [`Buses`] struct.
74//! As described above, [`Apb`] mediates access to the shared `APBXMASK`
75//! registers. We call [`Apb::enable`] to convert an [`ApbToken`] into the
76//! corresponding [`ApbClk`]. The existence of each `ApbClk` type represents
77//! proof that the corresponding APB clock has been enabled.
78//!
79//! ```no_run
80//! # use atsamd_hal::{
81//! #     clock::v2::{
82//! #         clock_system_at_reset,
83//! #     },
84//! #     pac::Peripherals,
85//! # };
86//! # let mut pac = Peripherals::take().unwrap();
87//! # let (mut buses, clocks, tokens) = clock_system_at_reset(
88//! #     pac.oscctrl,
89//! #     pac.osc32kctrl,
90//! #     pac.gclk,
91//! #     pac.mclk,
92//! #     &mut pac.nvmctrl,
93//! # );
94//! # let apb_port = clocks.apbs.port;
95//! let apb_sercom0 = buses.apb.enable(tokens.apbs.sercom0);
96//! ```
97//!
98//! The complete example is shown below.
99//!
100//! ```no_run
101//! use atsamd_hal::{
102//!     clock::v2::{
103//!         clock_system_at_reset,
104//!     },
105//!     pac::Peripherals,
106//! };
107//! let mut pac = Peripherals::take().unwrap();
108//! let (mut buses, clocks, tokens) = clock_system_at_reset(
109//!     pac.oscctrl,
110//!     pac.osc32kctrl,
111//!     pac.gclk,
112//!     pac.mclk,
113//!     &mut pac.nvmctrl,
114//! );
115//! let apb_port = clocks.apbs.port;
116//! let apb_sercom0 = buses.apb.enable(tokens.apbs.sercom0);
117//! ```
118//!
119//! [`clock` module documentation]: super
120//! [`clock_system_at_reset`]: super::clock_system_at_reset
121//! [`Clocks`]: super::Clocks
122//! [`Buses`]: super::Buses
123
124use atsamd_hal_macros::hal_macro_helper;
125use core::marker::PhantomData;
126
127use bitflags;
128use paste::paste;
129
130use crate::pac::{self, mclk};
131
132use crate::typelevel::Sealed;
133
134use super::types::*;
135
136//==============================================================================
137// Registers
138//==============================================================================
139
140/// APB clock controller
141///
142/// As described in the [module-level documentation](self), this struct mediates
143/// access to the shared `APBXMASK` registers. Users can convert a disabled
144/// [`ApbToken<A>`] into an enabled [`ApbClk<A>`] using [`Apb::enable`], and
145/// vice versa with [`Apb::disable`].
146pub struct Apb(());
147
148impl Apb {
149    /// Create a new instance of [`Apb`]
150    ///
151    /// # Safety
152    ///
153    /// Because the `Apb` mediates access to the `APBMASK` registers, it must be
154    /// a singleton. There must never be two simulatenous instances of it at a
155    /// time. See the notes on `Token` types and memory safety in the root of
156    /// the `clock` module for more details.
157    #[inline]
158    pub(super) unsafe fn new() -> Self {
159        Self(())
160    }
161
162    #[inline]
163    fn mclk(&self) -> &mclk::RegisterBlock {
164        // Safety: The `Apb` type has exclusive access to the `APBXMASK`
165        // registers, and it uses a shared reference to the register block. See
166        // the notes on `Token` types and memory safety in the root of the
167        // `clock` module for more details.
168        unsafe { &*pac::Mclk::PTR }
169    }
170
171    #[inline]
172    fn apbamask(&mut self) -> &mclk::Apbamask {
173        self.mclk().apbamask()
174    }
175
176    #[inline]
177    fn apbbmask(&mut self) -> &mclk::Apbbmask {
178        self.mclk().apbbmask()
179    }
180
181    #[inline]
182    fn apbcmask(&mut self) -> &mclk::Apbcmask {
183        self.mclk().apbcmask()
184    }
185
186    #[inline]
187    fn apbdmask(&mut self) -> &mclk::Apbdmask {
188        self.mclk().apbdmask()
189    }
190
191    #[inline]
192    fn enable_mask(&mut self, mask: ApbMask) {
193        // Safety: The mask bits are derived from a `bitflags` struct, so they
194        // are guaranteed to be valid.
195        unsafe {
196            match mask {
197                ApbMask::A(mask) => {
198                    self.apbamask()
199                        .modify(|r, w| w.bits(r.bits() | mask.bits()));
200                }
201                ApbMask::B(mask) => {
202                    self.apbbmask()
203                        .modify(|r, w| w.bits(r.bits() | mask.bits()));
204                }
205                ApbMask::C(mask) => {
206                    self.apbcmask()
207                        .modify(|r, w| w.bits(r.bits() | mask.bits()));
208                }
209                ApbMask::D(mask) => {
210                    self.apbdmask()
211                        .modify(|r, w| w.bits(r.bits() | mask.bits()));
212                }
213            }
214        }
215    }
216
217    #[inline]
218    fn disable_mask(&mut self, mask: ApbMask) {
219        // Safety: The mask bits are derived from a `bitflags` struct, so they
220        // are guaranteed to be valid.
221        unsafe {
222            match mask {
223                ApbMask::A(mask) => {
224                    self.apbamask()
225                        .modify(|r, w| w.bits(r.bits() & !mask.bits()));
226                }
227                ApbMask::B(mask) => {
228                    self.apbbmask()
229                        .modify(|r, w| w.bits(r.bits() & !mask.bits()));
230                }
231                ApbMask::C(mask) => {
232                    self.apbcmask()
233                        .modify(|r, w| w.bits(r.bits() & !mask.bits()));
234                }
235                ApbMask::D(mask) => {
236                    self.apbdmask()
237                        .modify(|r, w| w.bits(r.bits() & !mask.bits()));
238                }
239            }
240        }
241    }
242
243    /// Enable the corresponding APB clock
244    ///
245    /// Consume an [`ApbToken`], enable the corresponding APB clock and return
246    /// an [`ApbClk`]. The `ApbClk` represents proof that the corresponding APB
247    /// clock has been enabled.
248    #[inline]
249    pub fn enable<A: ApbId>(&mut self, token: ApbToken<A>) -> ApbClk<A> {
250        self.enable_mask(A::DYN.into());
251        ApbClk::new(token)
252    }
253
254    /// Disable the corresponding APB clock
255    ///
256    /// Consume the [`ApbClk`], disable the corresponding APB clock and return
257    /// the [`ApbToken`].
258    #[inline]
259    pub fn disable<A: ApbId>(&mut self, clock: ApbClk<A>) -> ApbToken<A> {
260        self.disable_mask(A::DYN.into());
261        clock.free()
262    }
263}
264
265//==============================================================================
266// DynApbId & ApbMask
267//==============================================================================
268
269/// A mask corresponding to one of the APB bridge registers
270///
271/// Each variant is a [`bitflags`] struct with a binary representation exactly
272/// matching the corresponding APB `MASK` register.
273enum ApbMask {
274    A(ApbAMask),
275    B(ApbBMask),
276    C(ApbCMask),
277    D(ApbDMask),
278}
279
280macro_rules! define_apb_types {
281    (
282        $(
283            $Reg:ident {
284                $(
285                    $( #[$( $cfg:tt )+] )?
286                    $Type:ident = $BIT:literal,
287                )+
288            }
289        )+
290    ) => {
291        /// Value-level enum identifying a single APB clock
292        ///
293        /// Each variant of this enum corresponds to a specific bit in one of
294        /// the four `APBXMASK` registers and identifies one of many possible
295        /// APB clocks, which can vary by chip.
296        ///
297        /// `DynApbId` is the value-level equivalent of [`ApbId`].
298        #[repr(u8)]
299        pub enum DynApbId {
300            $(
301                $(
302                    $( #[$( $cfg )+] )?
303                    $Type,
304                )+
305            )+
306        }
307
308        $(
309            $(
310                $( #[$( $cfg )+] )?
311                impl ApbId for $Type {
312                    const DYN: DynApbId = DynApbId::$Type;
313                }
314            )+
315        )+
316
317        paste! {
318            $(
319                bitflags::bitflags! {
320                    #[
321                        doc =
322                            "APB bridge `" $Reg "` register mask\n"
323                            "\n"
324                            "This is a [`bitflags`] struct with a binary representation "
325                            "exactly matching the `APB" $Reg "MASK` register."
326                    ]
327                    struct [<Apb $Reg Mask>]: u32 {
328                        $(
329                            $( #[$( $cfg )+] )?
330                            const [<$Type:upper>] = 1 << $BIT;
331                        )+
332                    }
333                }
334
335            )+
336
337            impl From<DynApbId> for ApbMask {
338                #[inline]
339                fn from(id: DynApbId) -> Self {
340                    use DynApbId::*;
341                    match id {
342                        $(
343                            $(
344                                $( #[$( $cfg )+] )?
345                                $Type => ApbMask::$Reg([<Apb $Reg Mask>]::[<$Type:upper>]),
346                            )+
347                        )+
348                    }
349                }
350            }
351        }
352    };
353}
354
355#[hal_macro_helper]
356define_apb_types!(
357    A {
358        Pac = 0,
359        Pm = 1,
360        Mclk = 2,
361        RstC = 3,
362        OscCtrl = 4,
363        Osc32kCtrl = 5,
364        SupC = 6,
365        Gclk = 7,
366        Wdt = 8,
367        Rtc = 9,
368        Eic = 10,
369        FreqM = 11,
370        Sercom0 = 12,
371        Sercom1 = 13,
372        Tc0 = 14,
373        Tc1 = 15,
374    }
375    B {
376        Usb = 0,
377        Dsu = 1,
378        NvmCtrl = 2,
379        Port = 4,
380        EvSys = 7,
381        Sercom2 = 9,
382        Sercom3 = 10,
383        Tcc0 = 11,
384        Tcc1 = 12,
385        Tc2 = 13,
386        Tc3 = 14,
387        RamEcc = 16,
388    }
389    C {
390        #[hal_cfg("gmac")]
391        Gmac = 2,
392        Tcc2 = 3,
393        #[hal_cfg("tcc3")]
394        Tcc3 = 4,
395        #[hal_cfg("tc4")]
396        Tc4 = 5,
397        #[hal_cfg("tc5")]
398        Tc5 = 6,
399        PDec = 7,
400        Ac = 8,
401        Aes = 9,
402        Trng = 10,
403        Icm = 11,
404        Qspi = 13,
405        Ccl = 14,
406    }
407    D {
408        Sercom4 = 0,
409        Sercom5 = 1,
410        #[hal_cfg("sercom6")]
411        Sercom6 = 2,
412        #[hal_cfg("sercom7")]
413        Sercom7 = 3,
414        #[hal_cfg("tcc4")]
415        Tcc4 = 4,
416        #[hal_cfg("tc6")]
417        Tc6 = 5,
418        #[hal_cfg("tc7")]
419        Tc7 = 6,
420        Adc0 = 7,
421        Adc1 = 8,
422        Dac = 9,
423        #[hal_cfg("i2s")]
424        I2S = 10,
425        Pcc = 11,
426    }
427);
428
429//==============================================================================
430// ApbId
431//==============================================================================
432
433/// Type-level enum identifying one of the possible APB clocks
434///
435/// The types implementing this trait are type-level variants of `ApbId`, and
436/// they identify one of the many possible APB clocks, which can vary by chip.
437/// Each type corresponds to a specific bit in one of the four `APBXMASK`
438/// registers.
439///
440/// `ApbId` is the type-level equivalent of [`DynApbId`]. See the documentation
441/// on [type-level programming] and specifically [type-level enums] for more
442/// details.
443///
444/// [type-level programming]: crate::typelevel
445/// [type-level enums]: crate::typelevel#type-level-enums
446pub trait ApbId: Sealed {
447    /// Corresponding variant of [`DynApbId`]
448    const DYN: DynApbId;
449}
450
451//==============================================================================
452// ApbToken
453//==============================================================================
454
455/// Singleton token that can be exchanged for an [`ApbClk`]
456///
457/// As explained in the [`clock` module documentation](super), instances of
458/// various `Token` types can be exchanged for actual clock types. They
459/// represent clocks that are disabled.
460///
461/// The type parameter `A` is an [`ApbId`] indicating which APB clock is
462/// represented by this token. To enable the corresponding APB clock, use the
463/// [`Apb::enable`] method.
464pub struct ApbToken<A: ApbId> {
465    id: PhantomData<A>,
466}
467
468impl<A: ApbId> ApbToken<A> {
469    /// Create a new instance of [`ApbToken`]
470    ///
471    /// # Safety
472    ///
473    /// Each `ApbToken` is a singleton. There must never be two simulatenous
474    /// instances with the same [`ApbId`]. See the notes on `Token` types and
475    /// memory safety in the root of the `clock` module for more details.
476    #[inline]
477    unsafe fn new() -> Self {
478        ApbToken { id: PhantomData }
479    }
480}
481
482//==============================================================================
483// ApbClk
484//==============================================================================
485
486/// An enabled APB clock
487///
488/// An [`ApbClk`] represents an enabled APB clock. The type parameter `A` is an
489/// [`ApbId`], which corresponds to a particular bit in the `APBXMASK`
490/// registers. An `ApbClk` can be disabled with the [`Apb::disable`] method.
491pub struct ApbClk<A: ApbId> {
492    token: ApbToken<A>,
493}
494
495impl<A: ApbId> ApbClk<A> {
496    #[inline]
497    fn new(token: ApbToken<A>) -> Self {
498        ApbClk { token }
499    }
500
501    #[inline]
502    fn free(self) -> ApbToken<A> {
503        self.token
504    }
505}
506
507//==============================================================================
508// ApbTokens
509//==============================================================================
510
511/// Set of [`ApbToken`]s for APB clocks that are disabled at power-on reset
512#[hal_macro_helper]
513pub struct ApbTokens {
514    pub freq_m: ApbToken<FreqM>,
515    pub sercom0: ApbToken<Sercom0>,
516    pub sercom1: ApbToken<Sercom1>,
517    pub tc0: ApbToken<Tc0>,
518    pub tc1: ApbToken<Tc1>,
519    pub usb: ApbToken<Usb>,
520    pub ev_sys: ApbToken<EvSys>,
521    pub sercom2: ApbToken<Sercom2>,
522    pub sercom3: ApbToken<Sercom3>,
523    pub tcc0: ApbToken<Tcc0>,
524    pub tcc1: ApbToken<Tcc1>,
525    pub tc2: ApbToken<Tc2>,
526    pub tc3: ApbToken<Tc3>,
527    #[hal_cfg("tc4")]
528    pub tc4: ApbToken<Tc4>,
529    pub tcc2: ApbToken<Tcc2>,
530    #[hal_cfg("tcc3")]
531    pub tcc3: ApbToken<Tcc3>,
532    #[hal_cfg("tc5")]
533    pub tc5: ApbToken<Tc5>,
534    pub p_dec: ApbToken<PDec>,
535    pub ac: ApbToken<Ac>,
536    pub aes: ApbToken<Aes>,
537    pub trng: ApbToken<Trng>,
538    pub icm: ApbToken<Icm>,
539    pub ccl: ApbToken<Ccl>,
540    pub sercom4: ApbToken<Sercom4>,
541    pub sercom5: ApbToken<Sercom5>,
542    #[hal_cfg("sercom6")]
543    pub sercom6: ApbToken<Sercom6>,
544    #[hal_cfg("sercom7")]
545    pub sercom7: ApbToken<Sercom7>,
546    #[hal_cfg("tcc4")]
547    pub tcc4: ApbToken<Tcc4>,
548    #[hal_cfg("tc6")]
549    pub tc6: ApbToken<Tc6>,
550    #[hal_cfg("tc7")]
551    pub tc7: ApbToken<Tc7>,
552    pub adc0: ApbToken<Adc0>,
553    pub adc1: ApbToken<Adc1>,
554    pub dac: ApbToken<Dac>,
555    #[hal_cfg("i2s")]
556    pub i2s: ApbToken<I2S>,
557    pub pcc: ApbToken<Pcc>,
558}
559
560impl ApbTokens {
561    /// Create the set of [`ApbToken`]s
562    ///
563    /// # Safety
564    ///
565    /// All invariants required by `ApbToken::new` must be upheld here as well.
566    #[inline]
567    #[hal_macro_helper]
568    pub(super) unsafe fn new() -> Self {
569        unsafe {
570            Self {
571                freq_m: ApbToken::new(),
572                sercom0: ApbToken::new(),
573                sercom1: ApbToken::new(),
574                tc0: ApbToken::new(),
575                tc1: ApbToken::new(),
576                usb: ApbToken::new(),
577                ev_sys: ApbToken::new(),
578                sercom2: ApbToken::new(),
579                sercom3: ApbToken::new(),
580                tcc0: ApbToken::new(),
581                tcc1: ApbToken::new(),
582                tc2: ApbToken::new(),
583                tc3: ApbToken::new(),
584                #[hal_cfg("tc4")]
585                tc4: ApbToken::new(),
586                tcc2: ApbToken::new(),
587                #[hal_cfg("tcc3")]
588                tcc3: ApbToken::new(),
589                #[hal_cfg("tc5")]
590                tc5: ApbToken::new(),
591                p_dec: ApbToken::new(),
592                ac: ApbToken::new(),
593                aes: ApbToken::new(),
594                trng: ApbToken::new(),
595                icm: ApbToken::new(),
596                ccl: ApbToken::new(),
597                sercom4: ApbToken::new(),
598                sercom5: ApbToken::new(),
599                #[hal_cfg("sercom6")]
600                sercom6: ApbToken::new(),
601                #[hal_cfg("sercom7")]
602                sercom7: ApbToken::new(),
603                #[hal_cfg("tcc4")]
604                tcc4: ApbToken::new(),
605                #[hal_cfg("tc6")]
606                tc6: ApbToken::new(),
607                #[hal_cfg("tc7")]
608                tc7: ApbToken::new(),
609                adc0: ApbToken::new(),
610                adc1: ApbToken::new(),
611                dac: ApbToken::new(),
612                #[hal_cfg("i2s")]
613                i2s: ApbToken::new(),
614                pcc: ApbToken::new(),
615            }
616        }
617    }
618}
619
620//==============================================================================
621// ApbClks
622//==============================================================================
623
624/// Set of [`ApbClk`]s for APB clocks that are enabled at power-on reset
625#[hal_macro_helper]
626pub struct ApbClks {
627    pub pac: ApbClk<Pac>,
628    pub pm: ApbClk<Pm>,
629    pub mclk: ApbClk<Mclk>,
630    pub rst_c: ApbClk<RstC>,
631    pub osc_ctrl: ApbClk<OscCtrl>,
632    pub osc32k_ctrl: ApbClk<Osc32kCtrl>,
633    pub sup_c: ApbClk<SupC>,
634    pub gclk: ApbClk<Gclk>,
635    pub wdt: ApbClk<Wdt>,
636    pub rtc: ApbClk<Rtc>,
637    pub eic: ApbClk<Eic>,
638    pub dsu: ApbClk<Dsu>,
639    pub nvm_ctrl: ApbClk<NvmCtrl>,
640    pub port: ApbClk<Port>,
641    pub ram_ecc: ApbClk<RamEcc>,
642    #[hal_cfg("gmac")]
643    pub gmac: ApbClk<Gmac>,
644    pub qspi: ApbClk<Qspi>,
645}
646
647impl ApbClks {
648    /// Create the set of [`ApbClk`]s
649    ///
650    /// # Safety
651    ///
652    /// All invariants required by `ApbToken::new` must be upheld here as well.
653    #[inline]
654    #[hal_macro_helper]
655    pub(super) unsafe fn new() -> Self {
656        unsafe {
657            ApbClks {
658                pac: ApbClk::new(ApbToken::new()),
659                pm: ApbClk::new(ApbToken::new()),
660                mclk: ApbClk::new(ApbToken::new()),
661                rst_c: ApbClk::new(ApbToken::new()),
662                osc_ctrl: ApbClk::new(ApbToken::new()),
663                osc32k_ctrl: ApbClk::new(ApbToken::new()),
664                sup_c: ApbClk::new(ApbToken::new()),
665                gclk: ApbClk::new(ApbToken::new()),
666                wdt: ApbClk::new(ApbToken::new()),
667                rtc: ApbClk::new(ApbToken::new()),
668                eic: ApbClk::new(ApbToken::new()),
669                dsu: ApbClk::new(ApbToken::new()),
670                nvm_ctrl: ApbClk::new(ApbToken::new()),
671                port: ApbClk::new(ApbToken::new()),
672                ram_ecc: ApbClk::new(ApbToken::new()),
673                #[hal_cfg("gmac")]
674                gmac: ApbClk::new(ApbToken::new()),
675                qspi: ApbClk::new(ApbToken::new()),
676            }
677        }
678    }
679}