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

1//! This module is intentionally private. Its contents are publicly exported
2//! from the `v2` module, which is where the corresponding documentation will
3//! appear.
4
5use typenum::U1;
6
7use crate::pac::{Gclk, Mclk, Nvmctrl, Osc32kctrl, Oscctrl};
8
9use super::*;
10
11/// Collection of low-level PAC structs
12///
13/// This struct serves to guard access to the low-level PAC structs. It places
14/// them behind an `unsafe` barrier.
15///
16/// Normally, users trade the low-level PAC structs for the higher-level
17/// `clock::v2` API. However, in some cases, the `clock::v2` API may not be
18/// sufficient. In these cases, users can access the registers directly by
19/// calling [`Pac::steal`] to recover the PAC structs.
20pub struct Pac {
21    oscctrl: Oscctrl,
22    osc32kctrl: Osc32kctrl,
23    gclk: Gclk,
24    mclk: Mclk,
25}
26
27impl Pac {
28    /// Escape hatch allowing to access low-level PAC structs
29    ///
30    /// Consume the [`Pac`] and return the low-level PAC structs. This is
31    /// useful when the `clock::v2` API does not provide a necessary feature, or
32    /// when dealing with the legacy `clock::v1` API. For example, many of the
33    /// `clock::v1` functions require access to the [`Mclk`] peripheral.
34    ///
35    /// # Safety
36    ///
37    /// Directly configuring clocks through the PAC API can invalidate the
38    /// type-level guarantees of the `clock` module API.
39    pub unsafe fn steal(self) -> (Oscctrl, Osc32kctrl, Gclk, Mclk) {
40        (self.oscctrl, self.osc32kctrl, self.gclk, self.mclk)
41    }
42}
43
44/// Bus clock objects
45///
46/// This type is constructed using the [`clock_system_at_reset`] function, which
47/// consumes the PAC-level clocking structs and returns the HAL-level clocking
48/// structs in their reset state.
49///
50/// This type contains the [bus clocks](super#bus-clocks), which are a necessary
51/// to implement memory safety for the [`AhbClk`]s and [`ApbClk`]s.
52///
53/// [`AhbClk`]: super::ahb::AhbClk
54/// [`ApbClk`]: super::apb::ApbClk
55pub struct Buses {
56    pub ahb: ahb::Ahb,
57    pub apb: apb::Apb,
58}
59
60/// Enabled clocks at power-on reset
61///
62/// This type is constructed using the [`clock_system_at_reset`] function, which
63/// consumes the PAC-level clocking structs and returns the HAL-level clocking
64/// structs in their reset state.
65///
66/// This type represents the clocks as they are configured at power-on reset.
67/// The main clock, [`Gclk0`](gclk::Gclk0), runs at 48 MHz using the
68/// [`Dfll`](dfll::Dfll) in open-loop mode. The ultra-low power
69/// [base oscillator](osculp32k::OscUlp32kBase) is also enabled and running, as
70/// it can never be disabled.
71///
72/// As described in the [top-level](super::super) documentation for the `clock`
73/// module, only [`Enabled`] clocks can be used as a [`Source`] for downstream
74/// clocks. This struct contains all of the `Enabled` clocks at reset.
75///
76/// This struct also contains the [`Pac`] wrapper struct, which provides
77/// `unsafe` access to the low-level PAC structs.
78pub struct Clocks {
79    /// Wrapper providing `unsafe` access to low-level PAC structs
80    pub pac: Pac,
81    /// Enabled AHB clocks
82    pub ahbs: ahb::AhbClks,
83    /// Enabled APB clocks
84    pub apbs: apb::ApbClks,
85    /// Main system clock, driven at 48 MHz by the DFLL in open loop mode
86    pub gclk0: Enabled<gclk::Gclk0<dfll::DfllId>, U1>,
87    /// DFLL48 in open loop mode
88    pub dfll: Enabled<dfll::Dfll, U1>,
89    /// Always-enabled base oscillator for the [`OscUlp1k`](osculp32k::OscUlp1k)
90    /// and [`OscUlp32k`](osculp32k::OscUlp32k) clocks.
91    pub osculp32k_base: Enabled<osculp32k::OscUlp32kBase>,
92}
93
94/// Type-level tokens for unused clocks at power-on reset
95///
96/// This type is constructed using the [`clock_system_at_reset`] function, which
97/// consumes the PAC-level clocking structs and returns the HAL-level clocking
98/// structs in their reset state.
99///
100/// As described in the [top-level](super::super) documentation for the `clock`
101/// module, token types are used to guanrantee the uniqueness of each clock. To
102/// configure or enable a clock, you must provide the corresponding token.
103pub struct Tokens {
104    /// Tokens to create [`apb::ApbClk`]s
105    pub apbs: apb::ApbTokens,
106    /// Token to create [`dpll::Dpll0`]
107    pub dpll0: dpll::DpllToken<dpll::Dpll0Id>,
108    /// Token to create [`dpll::Dpll1`]
109    pub dpll1: dpll::DpllToken<dpll::Dpll1Id>,
110    /// Tokens to create [`gclk::Gclk`]
111    pub gclks: gclk::GclkTokens,
112    /// Tokens to create [`pclk::Pclk`]s
113    pub pclks: pclk::PclkTokens,
114    /// Tokens to create [`rtcosc::RtcOsc`]
115    pub rtcosc: rtcosc::RtcOscToken,
116    /// Tokens [`xosc::Xosc0`]
117    pub xosc0: xosc::XoscToken<xosc::Xosc0Id>,
118    /// Token to create [`xosc::Xosc1`]
119    pub xosc1: xosc::XoscToken<xosc::Xosc1Id>,
120    /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and
121    /// [`xosc32k::Xosc32k`]
122    pub xosc32k: xosc32k::Xosc32kTokens,
123    /// Tokens to create [`osculp32k::OscUlp1k`] and [`osculp32k::OscUlp32k`]
124    pub osculp32k: osculp32k::OscUlp32kTokens,
125}
126
127/// Consume the PAC clocking structs and return a HAL-level
128/// representation of the clocks at power-on reset
129///
130/// This function consumes the [`Oscctrl`], [`Osc32kctrl`], [`Gclk`] and
131/// [`Mclk`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`].
132///
133/// See the [module-level documentation](super) for more details.
134#[inline]
135pub fn clock_system_at_reset(
136    oscctrl: Oscctrl,
137    osc32kctrl: Osc32kctrl,
138    gclk: Gclk,
139    mclk: Mclk,
140    nvmctrl: &mut Nvmctrl,
141) -> (Buses, Clocks, Tokens) {
142    // Safety: No bus, clock or token is instantiated more than once
143    unsafe {
144        let buses = Buses {
145            ahb: ahb::Ahb::new(),
146            apb: apb::Apb::new(),
147        };
148        let pac = Pac {
149            oscctrl,
150            osc32kctrl,
151            gclk,
152            mclk,
153        };
154        let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new()));
155        let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll);
156        let gclk0 = Enabled::new(gclk0);
157        let clocks = Clocks {
158            pac,
159            ahbs: ahb::AhbClks::new(),
160            apbs: apb::ApbClks::new(),
161            gclk0,
162            dfll,
163            osculp32k_base: osculp32k::OscUlp32kBase::new(),
164        };
165        let tokens = Tokens {
166            apbs: apb::ApbTokens::new(),
167            dpll0: dpll::DpllToken::new(),
168            dpll1: dpll::DpllToken::new(),
169            gclks: gclk::GclkTokens::new(nvmctrl),
170            pclks: pclk::PclkTokens::new(),
171            rtcosc: rtcosc::RtcOscToken::new(),
172            xosc0: xosc::XoscToken::new(),
173            xosc1: xosc::XoscToken::new(),
174            xosc32k: xosc32k::Xosc32kTokens::new(),
175            osculp32k: osculp32k::OscUlp32kTokens::new(),
176        };
177        (buses, clocks, tokens)
178    }
179}