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