atsamd_hal/peripherals/clock/d5x/v2/xosc32k.rs
1//! # External, 32 kHz crystal oscillator controller
2//!
3//! ## Overview
4//!
5//! The `xosc32k` module provides access to the 32 kHz external crystal
6//! oscillator controller (XOSC32K) within the `OSC32KCTRL` peripheral.
7//!
8//! The peripheral can operate in two [`Mode`]s. It can accept an external
9//! clock, or it can interface with an crystal oscillator. In both cases, the
10//! clock must be 32,768 Hz.
11//!
12//! When used with an external clock, only one GPIO [`Pin`] is required, but
13//! when used with a crystal oscillator, two GPIO `Pin`s are required. The
14//! [`XIn32`] `Pin` is used in both `Mode`s, while the [`XOut32`] `Pin` is only
15//! used in [`CrystalMode`].
16//!
17//! ## Clock tree structure
18//!
19//! The `XOSC32K` clock is unlike most other clocks, because it has two separate
20//! outputs, one at 32 kHz and another divided down to 1 kHz. Moreover, none,
21//! either or both of these outputs can be enabled at any given time.
22//!
23//! We can see, then, that the `XOSC32K` peripheral forms its own, miniature
24//! clock tree. There is a 1:N producer clock that must be enabled first; and
25//! there are two possible consumer clocks that can be independently and
26//! optionally enabled. In fact, this structure is illustrated by the `XOSC32K`
27//! register, which has three different enable bits: `ENABLE`, `EN32K` and
28//! `EN1K`.
29//!
30//! To represent this structure in the type system, we divide the `XOSC32K`
31//! peripheral into these three clocks. Users start by enabling the
32//! [`Xosc32kBase`] clock, which corresponds to setting the `XOSC32K` register
33//! `ENABLE` bit. The call to [`Xosc32kBase::enable`] returns a 1:N [`Enabled`]
34//! clock [`Source`], which can be consumed by both the [`Xosc32k`] and
35//! [`Xosc1k`] clocks. Enabling either of these two clocks will [`Increment`]
36//! the [`EnabledXosc32kBase`] counter, preventing it from being disabled.
37//! Note that `Xosc32k` and `Xosc1k` are themselves 1:N clocks as well.
38//!
39//! ## Clock failure detection and write lock
40//!
41//! Like the [`Xosc`] clocks, the XOSC32K peripheral also has clock failure
42//! detection. However, unlike the `XOSCCTRL` registers, the `XOSC32K` register
43//! has a dedicated write lock bit that will freeze its configuration until the
44//! next power-on reset.
45//!
46//! While `Xosc` clock failure detection is configured directly in the
47//! `XOSCCTRL` register, the XOSC32K peripheral has a separate, dedicated
48//! clock failure detection register (`Cfdctrl`). This difference likely exists
49//! to provide control of clock failure detection *after* write lock has been
50//! enabled.
51//!
52//! In this module, write lock is implemented by simply dropping the
53//! [`Xosc32kBase`] clock, which prevents any further access to the `XOSC32K`
54//! register. Thus, to allow control of clock failure detection in the presence
55//! of write lock, we provide a dedicated [`Xosc32kCfd`] interface, which has
56//! exclusive control over the `Cfdctrl` register.
57//!
58//! ## Example
59//!
60//! Creating and configuring the XOSC32K clocks proceeds according to the
61//! principles outlined in the [`clock` module documentation]. It is best shown
62//! with an example.
63//!
64//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking
65//! structs. We'll also need access to the GPIO [`Pins`].
66//!
67//! ```no_run
68//! use atsamd_hal::{
69//! clock::v2::{
70//! clock_system_at_reset,
71//! osculp32k::OscUlp32k,
72//! xosc32k::{
73//! ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
74//! Xosc32kCfd,
75//! },
76//! },
77//! gpio::Pins,
78//! pac::Peripherals,
79//! };
80//! let mut pac = Peripherals::take().unwrap();
81//! let pins = Pins::new(pac.port);
82//! let (buses, clocks, tokens) = clock_system_at_reset(
83//! pac.oscctrl,
84//! pac.osc32kctrl,
85//! pac.gclk,
86//! pac.mclk,
87//! &mut pac.nvmctrl,
88//! );
89//! ```
90//!
91//! Next, we create the [`Xosc32kBase`] clock from a 32 kHz oscillator using its
92//! corresponding [`Xosc32kBaseToken`] and the [`XIn32`] and [`XOut32`] `Pin`s.
93//! We then set the delay before the clock is unmasked by providing a desired
94//! [`StartUpDelay`]. Finally, we select a [`ControlGainMode`] for the crystal
95//! before enabling it.
96//!
97//! ```no_run
98//! # use atsamd_hal::{
99//! # clock::v2::{
100//! # clock_system_at_reset,
101//! # osculp32k::OscUlp32k,
102//! # xosc32k::{
103//! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
104//! # Xosc32kCfd,
105//! # },
106//! # },
107//! # gpio::Pins,
108//! # pac::Peripherals,
109//! # };
110//! # let mut pac = Peripherals::take().unwrap();
111//! # let pins = Pins::new(pac.port);
112//! # let (buses, clocks, tokens) = clock_system_at_reset(
113//! # pac.oscctrl,
114//! # pac.osc32kctrl,
115//! # pac.gclk,
116//! # pac.mclk,
117//! # &mut pac.nvmctrl,
118//! # );
119//! let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
120//! .start_up_delay(StartUpDelay::Delay1s)
121//! .control_gain_mode(ControlGainMode::HighSpeed)
122//! .enable();
123//! ```
124//!
125//! At this point, we opt to wait until the `Xosc32kBase` oscillator `is_ready`
126//! and stable.
127//!
128//! ```no_run
129//! # use atsamd_hal::{
130//! # clock::v2::{
131//! # clock_system_at_reset,
132//! # osculp32k::OscUlp32k,
133//! # xosc32k::{
134//! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
135//! # Xosc32kCfd,
136//! # },
137//! # },
138//! # gpio::Pins,
139//! # pac::Peripherals,
140//! # };
141//! # let mut pac = Peripherals::take().unwrap();
142//! # let pins = Pins::new(pac.port);
143//! # let (buses, clocks, tokens) = clock_system_at_reset(
144//! # pac.oscctrl,
145//! # pac.osc32kctrl,
146//! # pac.gclk,
147//! # pac.mclk,
148//! # &mut pac.nvmctrl,
149//! # );
150//! # let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
151//! # .start_up_delay(StartUpDelay::Delay1s)
152//! # .control_gain_mode(ControlGainMode::HighSpeed)
153//! # .enable();
154//! while !xosc32k_base.is_ready() {}
155//! ```
156//!
157//! With the [`EnabledXosc32kBase`] clock in hand, we can enable the [`Xosc1k`]
158//! and [`Xosc32k`], each of which [`Increment`]s the [`Enabled`] counter.
159//! Once we are satisfied with the configuration, we can call `write_lock` to
160//! lock the XOSC32K configuration at the hardware level. Doing so also consumes
161//! the `EnabledXosc32kBase` clock, which eliminates any ability to change the
162//! configuration at the API level.
163//!
164//! ```no_run
165//! # use atsamd_hal::{
166//! # clock::v2::{
167//! # clock_system_at_reset,
168//! # osculp32k::OscUlp32k,
169//! # xosc32k::{
170//! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
171//! # Xosc32kCfd,
172//! # },
173//! # },
174//! # gpio::Pins,
175//! # pac::Peripherals,
176//! # };
177//! # let mut pac = Peripherals::take().unwrap();
178//! # let pins = Pins::new(pac.port);
179//! # let (buses, clocks, tokens) = clock_system_at_reset(
180//! # pac.oscctrl,
181//! # pac.osc32kctrl,
182//! # pac.gclk,
183//! # pac.mclk,
184//! # &mut pac.nvmctrl,
185//! # );
186//! # let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
187//! # .start_up_delay(StartUpDelay::Delay1s)
188//! # .control_gain_mode(ControlGainMode::HighSpeed)
189//! # .enable();
190//! # while !xosc32k_base.is_ready() {}
191//! let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base);
192//! let (xosc32k, xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base);
193//! xosc32k_base.write_lock();
194//! ```
195//!
196//! However, while we have locked the XOSC32K configuration, we still want to
197//! enable clock failure detection, which will continuously monitor the clock
198//! and switch to a safe, backup clock if necessary.
199//!
200//! To do so, we must first enable the backup clock, which, for the XOSC32K, is
201//! the [`OscUlp32k`]. The OSCULP32K peripheral has a nearly identical structure
202//! to the XOSC32K; we create an [`EnabledOscUlp32k`] from the
203//! [`EnabledOscUlp32kBase`] clock and the corresponding [`OscUlp32kToken`].
204//!
205//! Upon creation of the [`Xosc32kCfd`] struct, we register it as a consumer of
206//! the `EnabledOscUlp32k`, which will `Increment` its `Counter` as well. When
207//! creating the safe clock, the `OscUlp32k` can be optionally divided by two,
208//! which is selected with [`SafeClockDiv`].
209//!
210//! ```no_run
211//! # use atsamd_hal::{
212//! # clock::v2::{
213//! # clock_system_at_reset,
214//! # osculp32k::OscUlp32k,
215//! # xosc32k::{
216//! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
217//! # Xosc32kCfd,
218//! # },
219//! # },
220//! # gpio::Pins,
221//! # pac::Peripherals,
222//! # };
223//! # let mut pac = Peripherals::take().unwrap();
224//! # let pins = Pins::new(pac.port);
225//! # let (buses, clocks, tokens) = clock_system_at_reset(
226//! # pac.oscctrl,
227//! # pac.osc32kctrl,
228//! # pac.gclk,
229//! # pac.mclk,
230//! # &mut pac.nvmctrl,
231//! # );
232//! # let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
233//! # .start_up_delay(StartUpDelay::Delay1s)
234//! # .control_gain_mode(ControlGainMode::HighSpeed)
235//! # .enable();
236//! # while !xosc32k_base.is_ready() {}
237//! # let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base);
238//! # let (xosc32k, xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base);
239//! # xosc32k_base.write_lock();
240//! let (osculp32k, osculp32k_base) =
241//! OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base);
242//! let (mut cfd, osculp32k) =
243//! Xosc32kCfd::enable(tokens.xosc32k.cfd, osculp32k, SafeClockDiv::Div1);
244//! ```
245//!
246//! Finally, with the clock failure detection interface in hand, we can do
247//! things like check if the XOSC32K [`has_failed`] or if it [`is_switched`] to
248//! the safe clock. If we are able to recover from a clock failure, we can even
249//! [`switch_back`] to the crystal oscillator.
250//!
251//! ```no_run
252//! # use atsamd_hal::{
253//! # clock::v2::{
254//! # clock_system_at_reset,
255//! # osculp32k::OscUlp32k,
256//! # xosc32k::{
257//! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
258//! # Xosc32kCfd,
259//! # },
260//! # },
261//! # gpio::Pins,
262//! # pac::Peripherals,
263//! # };
264//! # let mut pac = Peripherals::take().unwrap();
265//! # let pins = Pins::new(pac.port);
266//! # let (buses, clocks, tokens) = clock_system_at_reset(
267//! # pac.oscctrl,
268//! # pac.osc32kctrl,
269//! # pac.gclk,
270//! # pac.mclk,
271//! # &mut pac.nvmctrl,
272//! # );
273//! # let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
274//! # .start_up_delay(StartUpDelay::Delay1s)
275//! # .control_gain_mode(ControlGainMode::HighSpeed)
276//! # .enable();
277//! # while !xosc32k_base.is_ready() {}
278//! # let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base);
279//! # let (xosc32k, xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base);
280//! # xosc32k_base.write_lock();
281//! # let (osculp32k, osculp32k_base) =
282//! # OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base);
283//! # let (mut cfd, osculp32k) =
284//! # Xosc32kCfd::enable(tokens.xosc32k.cfd, osculp32k, SafeClockDiv::Div1);
285//! if cfd.has_failed() && cfd.is_switched() {
286//! cfd.switch_back();
287//! }
288//! ```
289//!
290//! The complete example is provided below.
291//!
292//! ```no_run
293//! use atsamd_hal::{
294//! clock::v2::{
295//! clock_system_at_reset,
296//! osculp32k::OscUlp32k,
297//! xosc32k::{
298//! ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase,
299//! Xosc32kCfd,
300//! },
301//! },
302//! gpio::Pins,
303//! pac::Peripherals,
304//! };
305//! let mut pac = Peripherals::take().unwrap();
306//! let pins = Pins::new(pac.port);
307//! let (buses, clocks, tokens) = clock_system_at_reset(
308//! pac.oscctrl,
309//! pac.osc32kctrl,
310//! pac.gclk,
311//! pac.mclk,
312//! &mut pac.nvmctrl,
313//! );
314//! let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01)
315//! .start_up_delay(StartUpDelay::Delay1s)
316//! .control_gain_mode(ControlGainMode::HighSpeed)
317//! .enable();
318//! while !xosc32k_base.is_ready() {}
319//! let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base);
320//! let (xosc32k, xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base);
321//! xosc32k_base.write_lock();
322//! let (osculp32k, osculp32k_base) =
323//! OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base);
324//! let (mut cfd, osculp32k) =
325//! Xosc32kCfd::enable(tokens.xosc32k.cfd, osculp32k, SafeClockDiv::Div1);
326//! if cfd.has_failed() && cfd.is_switched() {
327//! cfd.switch_back();
328//! }
329//! ```
330//!
331//! [`clock` module documentation]: super
332//! [`Pins`]: crate::gpio::Pins
333//! [`clock_system_at_reset`]: super::clock_system_at_reset
334//! [`Xosc`]: super::xosc::Xosc
335//! [`OscUlp32k`]: super::osculp32k::OscUlp32k
336//! [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k
337//! [`OscUlp32kToken`]: super::osculp32k::OscUlp32kToken
338//! [`EnabledOscUlp32kBase`]: super::osculp32k::EnabledOscUlp32kBase
339//! [`OscUlp32k`]: super::osculp32k::OscUlp32k
340//! [`has_failed`]: Xosc32kCfd::has_failed
341//! [`is_switched`]: Xosc32kCfd::is_switched
342//! [`switch_back`]: Xosc32kCfd::switch_back
343
344use fugit::RateExtU32;
345use typenum::U0;
346
347use crate::pac::osc32kctrl::xosc32k::{Cgmselect, Startupselect};
348use crate::pac::osc32kctrl::{self, status, Cfdctrl};
349
350use crate::gpio::{FloatingDisabled, Pin, PA00, PA01};
351use crate::time::Hertz;
352use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed};
353
354use super::osculp32k::OscUlp32kId;
355use super::{Enabled, Source};
356
357//==============================================================================
358// Tokens
359//==============================================================================
360
361/// Singleton token that can be exchanged for [`Xosc32kBase`]
362///
363/// As explained in the [`clock` module documentation](super), instances of
364/// various `Token` types can be exchanged for actual clock types. They
365/// typically represent clocks that are disabled at power-on reset.
366///
367/// The [`Xosc32kBase`] clock is disabled at power-on reset. To use it, you must
368/// first exchange the token for an actual clock with
369/// [`Xosc32kBase::from_clock`] or [`Xosc32kBase::from_crystal`].
370pub struct Xosc32kBaseToken(());
371
372/// Singleton token that can be exchanged for [`Xosc1k`]
373///
374/// As explained in the [`clock` module documentation](super), instances of
375/// various `Token` types can be exchanged for actual clock types. They
376/// typically represent clocks that are disabled at power-on reset.
377///
378/// The [`Xosc1k`] clock is disabled at power-on reset. To use it, you must
379/// first exchange the token for an actual clock with [`Xosc1k::enable`].
380pub struct Xosc1kToken(());
381
382/// Singleton token that can be exchanged for [`Xosc32k`]
383///
384/// As explained in the [`clock` module documentation](super), instances of
385/// various `Token` types can be exchanged for actual clock types. They
386/// typically represent clocks that are disabled at power-on reset.
387///
388/// The [`Xosc32k`] clock is disabled at power-on reset. To use it, you must
389/// first exchange the token for an actual clock with [`Xosc32k::enable`].
390pub struct Xosc32kToken(());
391
392/// Singleton token that can be exchanged for [`Xosc32kCfd`]
393///
394/// As explained in the [module-level documentation](self), clock failure
395/// detection can be used even after the `XOSC32K` register has been write
396/// locked. For that reason, users control clock failure detection through the
397/// dedicated [`Xosc32kCfd`] type.
398///
399/// Clock failure detection is disabled at power-on reset. To use it, you must
400/// first enable it by exchanging the token with [`Xosc32kCfd::enable`].
401pub struct Xosc32kCfdToken(());
402
403/// Set of tokens representing the disabled XOSC32K clocks power-on reset
404pub struct Xosc32kTokens {
405 pub base: Xosc32kBaseToken,
406 pub xosc1k: Xosc1kToken,
407 pub xosc32k: Xosc32kToken,
408 pub cfd: Xosc32kCfdToken,
409}
410
411impl Xosc32kTokens {
412 /// Create the set of tokens
413 ///
414 /// # Safety
415 ///
416 /// There must never be more than one instance of these tokens at any given
417 /// time. See the notes on `Token` types and memory safety in the root of
418 /// the `clock` module for more details.
419 pub(super) unsafe fn new() -> Self {
420 Self {
421 base: Xosc32kBaseToken(()),
422 xosc1k: Xosc1kToken(()),
423 xosc32k: Xosc32kToken(()),
424 cfd: Xosc32kCfdToken(()),
425 }
426 }
427}
428
429impl Xosc32kBaseToken {
430 #[inline]
431 fn status(&self) -> status::R {
432 // Safety: We are only reading from the `STATUS` register, so there is
433 // no risk of memory corruption.
434 unsafe { (*crate::pac::Osc32kctrl::PTR).status().read() }
435 }
436
437 /// Check whether the XOSC32K is stable and ready
438 #[inline]
439 fn is_ready(&self) -> bool {
440 self.status().xosc32krdy().bit()
441 }
442
443 #[inline]
444 fn xosc32k(&self) -> &osc32kctrl::Xosc32k {
445 // Safety: The `Xosc32kBaseToken` has exclusive access to the `XOSC32K`
446 // register. See the notes on `Token` types and memory safety in the
447 // root of the `clock` module for more details.
448 unsafe { (*crate::pac::Osc32kctrl::PTR).xosc32k() }
449 }
450
451 /// Reset the XOSC32K register
452 #[inline]
453 fn reset(&mut self) {
454 self.xosc32k().reset();
455 }
456
457 /// Set most of the fields in the XOSC32K register
458 #[inline]
459 fn set_xosc32k(&mut self, settings: Settings) {
460 let xtalen = settings.mode == DynMode::CrystalMode;
461 self.xosc32k().modify(|_, w| {
462 w.cgm().variant(settings.cgm.into());
463 w.startup().variant(settings.start_up.into());
464 w.ondemand().bit(settings.on_demand);
465 w.runstdby().bit(settings.run_standby);
466 w.xtalen().bit(xtalen)
467 });
468 }
469
470 /// Disable the XOSC32K
471 #[inline]
472 fn enable(&mut self) {
473 self.xosc32k().modify(|_, w| w.enable().set_bit());
474 }
475
476 /// Disable the XOSC32K
477 #[inline]
478 fn disable(&mut self) {
479 self.xosc32k().modify(|_, w| w.enable().clear_bit());
480 }
481
482 /// Enable the 1 kHz output
483 #[inline]
484 fn enable_1k(&mut self) {
485 self.xosc32k().modify(|_, w| w.en1k().set_bit());
486 }
487
488 /// Disable the 1 kHz output
489 #[inline]
490 fn disable_1k(&mut self) {
491 self.xosc32k().modify(|_, w| w.en1k().clear_bit());
492 }
493
494 /// Enable the 32 kHz output
495 #[inline]
496 fn enable_32k(&mut self) {
497 self.xosc32k().modify(|_, w| w.en32k().set_bit());
498 }
499
500 /// Disable the 32 kHz output
501 #[inline]
502 fn disable_32k(&mut self) {
503 self.xosc32k().modify(|_, w| w.en32k().clear_bit());
504 }
505
506 /// Enable the write lock
507 #[inline]
508 fn write_lock(&mut self) {
509 self.xosc32k().modify(|_, w| w.wrtlock().set_bit());
510 }
511}
512
513impl Xosc32kCfdToken {
514 #[inline]
515 fn status(&self) -> status::R {
516 // Safety: We are only reading from the `STATUS` register, so there is
517 // no risk of memory corruption.
518 unsafe { (*crate::pac::Osc32kctrl::PTR).status().read() }
519 }
520
521 /// Check whether the XOSC32K has triggered failure detection
522 #[inline]
523 fn has_failed(&self) -> bool {
524 self.status().xosc32kfail().bit()
525 }
526
527 /// Check whether the XOSC32K has been switched to the safe clock
528 #[inline]
529 fn is_switched(&self) -> bool {
530 self.status().xosc32ksw().bit()
531 }
532
533 #[inline]
534 fn cfdctrl(&self) -> &Cfdctrl {
535 // Safety: The `Xosc32kCfdToken` has exclusive access to the `Cfdctrl`
536 // register. See the notes on `Token` types and memory safety in the
537 // root of the `clock` module for more details.
538 unsafe { (*crate::pac::Osc32kctrl::PTR).cfdctrl() }
539 }
540
541 /// Enable clock failure detection and set the safe clock divider
542 #[inline]
543 fn enable(&mut self, div: SafeClockDiv) {
544 self.cfdctrl().modify(|_, w| {
545 w.cfdpresc().bit(div.into());
546 w.cfden().set_bit()
547 });
548 }
549
550 /// Disable clock failure detection
551 #[inline]
552 fn disable(&mut self) {
553 self.cfdctrl().modify(|_, w| w.cfden().clear_bit());
554 }
555
556 /// Switch from the safe clock back to the XOSC32K clock/oscillator
557 ///
558 /// This bit is cleared by the hardware after successfully switching back
559 #[inline]
560 fn switch_back(&mut self) {
561 self.cfdctrl().modify(|_, w| w.swback().set_bit());
562 }
563}
564
565//==============================================================================
566// Settings
567//==============================================================================
568
569// Collection of XOSC32K register fields
570//
571// All of these fields are set in a single write to XOSC32K during the call to
572// [`Xosc32kBase::enable`]. The remaining fields are only modified after it has
573// been enabled.
574#[derive(Clone, Copy)]
575struct Settings {
576 start_up: StartUpDelay,
577 cgm: ControlGainMode,
578 on_demand: bool,
579 run_standby: bool,
580 mode: DynMode,
581}
582
583//==============================================================================
584// XIn32 & XOut32
585//==============================================================================
586
587/// Type alias for the XOSC32K input [`Pin`]
588pub type XIn32 = Pin<PA00, FloatingDisabled>;
589
590/// Type alias for the XOSC32K output [`Pin`]
591pub type XOut32 = Pin<PA01, FloatingDisabled>;
592
593//==============================================================================
594// SafeClockDiv
595//==============================================================================
596
597/// Division factor for the safe clock prescaler
598///
599/// If an XOSC32K clock failure is detected, the hardware will switch to a safe
600/// clock derived from the [`OscUlp32k`]. This enum sets the divider between it
601/// and the safe clock frequency. The divider can be 1 or 2.
602///
603///[`OscUlp32k`]: super::osculp32k::OscUlp32k
604#[repr(u8)]
605#[derive(Clone, Copy, Default, PartialEq, Eq)]
606pub enum SafeClockDiv {
607 #[default]
608 Div1,
609 Div2,
610}
611
612impl From<SafeClockDiv> for bool {
613 fn from(div: SafeClockDiv) -> Self {
614 match div {
615 SafeClockDiv::Div1 => false,
616 SafeClockDiv::Div2 => true,
617 }
618 }
619}
620
621//==============================================================================
622// StartUpDelay
623//==============================================================================
624
625/// Start up delay before continuous monitoring takes effect
626///
627/// After a hard reset or waking from sleep, the XOSC32K output will remained
628/// masked for the start up period, to ensure an unstable clock is not
629/// propagated into the digital logic.
630///
631/// The start up delay is counted using the [`OscUlp32k`] clock.
632///
633/// [`OscUlp32k`]: super::osculp32k::OscUlp32k
634#[repr(u8)]
635#[derive(Clone, Copy, Default, PartialEq, Eq)]
636pub enum StartUpDelay {
637 #[default]
638 Delay63ms,
639 Delay125ms,
640 Delay500ms,
641 Delay1s,
642 Delay2s,
643 Delay4s,
644 Delay8s,
645}
646
647impl From<StartUpDelay> for Startupselect {
648 fn from(delay: StartUpDelay) -> Self {
649 match delay {
650 StartUpDelay::Delay63ms => Startupselect::Cycle2048,
651 StartUpDelay::Delay125ms => Startupselect::Cycle4096,
652 StartUpDelay::Delay500ms => Startupselect::Cycle16384,
653 StartUpDelay::Delay1s => Startupselect::Cycle32768,
654 StartUpDelay::Delay2s => Startupselect::Cycle65536,
655 StartUpDelay::Delay4s => Startupselect::Cycle131072,
656 StartUpDelay::Delay8s => Startupselect::Cycle262144,
657 }
658 }
659}
660
661//==============================================================================
662// ControlGainMode
663//==============================================================================
664
665/// Gain mode for the XOSC32K control loop
666///
667/// The XOSC32K crystal oscillator control loop has a configurable gain to allow
668/// users to trade power for speed and stability.
669#[derive(Copy, Clone, Default, PartialEq, Eq)]
670pub enum ControlGainMode {
671 #[default]
672 Standard,
673 HighSpeed,
674}
675
676impl From<ControlGainMode> for Cgmselect {
677 fn from(cgm: ControlGainMode) -> Self {
678 match cgm {
679 ControlGainMode::Standard => Cgmselect::Xt,
680 ControlGainMode::HighSpeed => Cgmselect::Hs,
681 }
682 }
683}
684
685//==============================================================================
686// DynMode
687//==============================================================================
688
689/// Value-level enum identifying one of two possible XOSC32K operating modes
690///
691/// The XOSC32K clock can be sourced from either an external clock or crystal
692/// oscillator. The variants of this enum identify one of these two possible
693/// operating modes.
694///
695/// `DynMode` is the value-level equivalent of [`Mode`].
696#[derive(Clone, Copy, Default, PartialEq, Eq)]
697pub enum DynMode {
698 #[default]
699 ClockMode,
700 CrystalMode,
701}
702
703//==============================================================================
704// Mode
705//==============================================================================
706
707/// Type-level enum for the XOSC32K operation mode
708///
709/// The XOSC32K clock can be sourced from either an external clock or a crystal
710/// oscillator. This type-level `enum` provides two type-level variants,
711/// [`ClockMode`] and [`CrystalMode`], representing these operating modes.
712///
713/// `Mode` is the type-level equivalent of [`DynMode`]. See the documentation on
714/// [type-level programming] and specifically [type-level enums] for more
715/// details.
716///
717/// [type-level programming]: crate::typelevel
718/// [type-level enums]: crate::typelevel#type-level-enums
719pub trait Mode: Sealed {
720 const DYN: DynMode;
721 #[doc(hidden)]
722 type Pins;
723}
724
725/// Type-level variant of the XOSC32K operating [`Mode`]
726///
727/// In this `Mode`, the XOSC32K clock will be sourced from an external clock.
728///
729/// See the documentation on [type-level programming] and specifically
730/// [type-level enums] for more details.
731///
732/// [type-level programming]: crate::typelevel
733/// [type-level enums]: crate::typelevel#type-level-enums
734pub enum ClockMode {}
735impl Sealed for ClockMode {}
736impl Mode for ClockMode {
737 const DYN: DynMode = DynMode::ClockMode;
738 type Pins = XIn32;
739}
740
741/// Type-level variant of the XOSC32K operating [`Mode`]
742///
743/// In this `Mode`, the XOSC32K clock will be sourced from a crystal oscillator.
744///
745/// See the documentation on [type-level programming] and specifically
746/// [type-level enums] for more details.
747///
748/// [type-level programming]: crate::typelevel
749/// [type-level enums]: crate::typelevel#type-level-enums
750pub enum CrystalMode {}
751impl Sealed for CrystalMode {}
752impl Mode for CrystalMode {
753 const DYN: DynMode = DynMode::CrystalMode;
754 type Pins = (XIn32, XOut32);
755}
756
757//==============================================================================
758// Xosc32kBase
759//==============================================================================
760
761/// XOSC32K base clock, which feeds the [`Xosc1k`] and [`Xosc32k`] clocks
762///
763/// The XOSC32K peripheral has two possible clock outputs, one at 32 kHz and
764/// another at 1 kHz. This structure is represented in the type system as a set
765/// of three clocks forming a small clock tree. The [`Xosc32kBase`] clock
766/// represents the configurable base oscillator that feeds the optional
767/// [`Xosc1k`] and [`Xosc32k`] output clocks. See the
768/// [module-level documentation](super) for details and examples.
769pub struct Xosc32kBase<M: Mode> {
770 token: Xosc32kBaseToken,
771 pins: M::Pins,
772 settings: Settings,
773}
774
775/// The [`Enabled`] [`Xosc32kBase`] clock
776///
777/// As described in the [`clock` module documentation](super), the [`Enabled`]
778/// wrapper implements compile-time clock tree safety by tracking the number of
779/// clocks consuming the [`Xosc32kBase`] clock and restricts access to the
780/// underlying type to prevent misuse.
781///
782/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
783/// the counter is assumed to be zero.
784pub type EnabledXosc32kBase<M, N = U0> = Enabled<Xosc32kBase<M>, N>;
785
786impl Xosc32kBase<ClockMode> {
787 /// Create the [`Xosc32kBase`] clock from an external clock, taking
788 /// ownership of the [`XIn32`] [`Pin`]
789 ///
790 /// Creating an [`Xosc32kBase`] clock does not modify any of the hardware
791 /// registers. It only creates a struct to track the configuration. The
792 /// configuration data is stored until the user calls [`enable`]. At that
793 /// point, all of the registers are written according to the initialization
794 /// procedures specified in the datasheet, and an [`EnabledXosc32kBase`]
795 /// clock is returned. The `Xosc32kBase` clock is not active or useful until
796 /// that point.
797 ///
798 /// [`enable`]: Xosc32kBase::enable
799 #[inline]
800 pub fn from_clock(token: Xosc32kBaseToken, xin32: impl Into<XIn32>) -> Self {
801 let pins = xin32.into();
802 Self::new(token, pins)
803 }
804
805 /// Consume the [`Xosc32kBase`] and release the [`Xosc32kBaseToken`] and
806 /// [`XIn32`] [`Pin`]
807 #[inline]
808 pub fn free(self) -> (Xosc32kBaseToken, XIn32) {
809 (self.token, self.pins)
810 }
811}
812
813impl Xosc32kBase<CrystalMode> {
814 /// Create the [`Xosc32kBase`] clock from an external crystal oscillator,
815 /// taking ownership of the [`XIn32`] and [`XOut32`] [`Pin`]s.
816 ///
817 /// Creating an [`Xosc32kBase`] clock does not modify any of the hardware
818 /// registers. It only creates a struct to track the configuration. The
819 /// configuration data is stored until the user calls [`enable`]. At that
820 /// point, all of the registers are written according to the initialization
821 /// procedures specified in the datasheet, and an [`EnabledXosc32kBase`]
822 /// clock is returned. The `Xosc32kBase` is not active or useful until that
823 /// point.
824 ///
825 /// [`enable`]: Xosc32kBase::enable
826 #[inline]
827 pub fn from_crystal(
828 token: Xosc32kBaseToken,
829 xin32: impl Into<XIn32>,
830 xout32: impl Into<XOut32>,
831 ) -> Self {
832 let pins = (xin32.into(), xout32.into());
833 Self::new(token, pins)
834 }
835
836 /// Consume the [`Xosc32kBase`] and release the [`Xosc32kBaseToken`],
837 /// [`XIn32`] and [`XOut32`] [`Pin`]s
838 #[inline]
839 pub fn free(self) -> (Xosc32kBaseToken, XIn32, XOut32) {
840 let (xin32, xout32) = self.pins;
841 (self.token, xin32, xout32)
842 }
843
844 /// Set the crystal oscillator [`ControlGainMode`]
845 #[inline]
846 pub fn control_gain_mode(mut self, cgm: ControlGainMode) -> Self {
847 self.settings.cgm = cgm;
848 self
849 }
850}
851
852impl<M: Mode> Xosc32kBase<M> {
853 #[inline]
854 fn new(token: Xosc32kBaseToken, pins: M::Pins) -> Self {
855 let settings = Settings {
856 start_up: StartUpDelay::Delay63ms,
857 cgm: ControlGainMode::Standard,
858 on_demand: true,
859 run_standby: false,
860 mode: M::DYN,
861 };
862 Self {
863 token,
864 pins,
865 settings,
866 }
867 }
868
869 /// Set the start up delay before the [`Xosc32kBase`] clock is unmasked and
870 /// continuously monitored
871 ///
872 /// During the start up period, the [`Xosc32kBase`] clock is masked to
873 /// prevent clock instability from propagating to the digital logic. During
874 /// this time, clock failure detection is disabled.
875 #[inline]
876 pub fn start_up_delay(mut self, delay: StartUpDelay) -> Self {
877 self.settings.start_up = delay;
878 self
879 }
880
881 /// Control the XOSC32K on-demand behavior
882 ///
883 /// When the on-demand is enabled, the XOSC32K clocks will only run in Idle
884 /// or Standby sleep modes if it is requested by a peripheral. Otherwise,
885 /// its behavior is dependent on the run-standby setting.
886 #[inline]
887 pub fn on_demand(mut self, on_demand: bool) -> Self {
888 self.settings.on_demand = on_demand;
889 self
890 }
891
892 /// Control the XOSC32K behavior in Standby sleep mode
893 ///
894 /// When `RUNSTDBY` is disabled, the XOSC32K clocks will never run in
895 /// Standby sleep mode unless `ONDEMAND` is enabled and a clock is requested
896 /// by a peripheral.
897 ///
898 /// When `RUNSTDBY` is enabled, the `Xosc` will run in Standby sleep mode,
899 /// but it can still be disabled if `ONDEMAND` is enabled and a clock is not
900 /// requested.
901 #[inline]
902 pub fn run_standby(mut self, run_standby: bool) -> Self {
903 self.settings.run_standby = run_standby;
904 self
905 }
906
907 /// Freeze the XOSC32K configuration until power-on reset
908 ///
909 /// This function sets the write-lock bit, which freezes the XOSC32K
910 /// configuration at the hardware level until power-on reset. At the API
911 /// level, it also consumes and drops the [`Xosc32kBase`], which prevents
912 /// any further modifications.
913 ///
914 /// **NOTE:** Because the `Xosc32kBase` is not yet enabled, calling this
915 /// method will lock both the [`Xosc1k`] and [`Xosc32k`] in their disabled
916 /// state.
917 #[inline]
918 pub fn write_lock(mut self) {
919 self.token.write_lock();
920 }
921
922 /// Enable the [`Xosc32kBase`] clock, so that it can be used as a clock
923 /// [`Source`] for the [`Xosc1k`] and [`Xosc32k`] clocks
924 ///
925 /// As mentioned when creating a new `Xosc32kBase`, no hardware registers
926 /// are actually modified until this call. Rather, the desired configuration
927 /// is stored internally, and the `Xosc32kBase` is initialized and
928 /// configured here according to the datasheet.
929 ///
930 /// The returned value is an [`EnabledXosc32kBase`] that can be used as a
931 /// clock [`Source`] for the [`Xosc1k`] and [`Xosc32k`] clocks.
932 #[inline]
933 pub fn enable(mut self) -> EnabledXosc32kBase<M> {
934 self.token.reset();
935 self.token.set_xosc32k(self.settings);
936 self.token.enable();
937 Enabled::new(self)
938 }
939}
940
941impl<M: Mode> EnabledXosc32kBase<M> {
942 /// Disable the [`Xosc32kBase`] clock
943 ///
944 /// This method is only implemented for `N = U0`, which means the clock can
945 /// only be disabled when no other clocks consume this [`Xosc32kBase`]
946 /// clock.
947 #[inline]
948 pub fn disable(mut self) -> Xosc32kBase<M> {
949 self.0.token.disable();
950 self.0
951 }
952}
953
954impl<M: Mode, N> EnabledXosc32kBase<M, N> {
955 /// Check whether the XOSC32K is stable and ready to be used as a clock
956 /// [`Source`]
957 #[inline]
958 pub fn is_ready(&self) -> bool {
959 self.0.token.is_ready()
960 }
961
962 /// Freeze the XOSC32K configuration until power-on reset
963 ///
964 /// This function sets the write-lock bit, which freezes the XOSC32K
965 /// configuration at the hardware level until power-on reset. At the API
966 /// level, it also consumes and drops the [`Xosc32kBase`] clock, which
967 /// prevents any further modifications.
968 #[inline]
969 pub fn write_lock(mut self) {
970 self.0.token.write_lock();
971 }
972}
973
974//==============================================================================
975// Xosc32kCfd
976//==============================================================================
977
978/// Clock failure detection interface for the XOSC32K peripheral
979///
980/// The XOSC32K peripheral provides a hardware method to continuously monitor
981/// the clock to verify it is still running. In the event of a failure, the
982/// output will be switched to a "safe clock" derived from the [`OscUlp32k`].
983/// The XOSC32K peripheral provides a prescaler to optionally divide the
984/// `OscUlp32k` by two.
985///
986/// Note that clock failure is triggered when four safe clock periods pass
987/// without seeing a rising & falling edge pair on the XOSC32K clock. Once
988/// failure is detected, the corresponding bit in the `STATUS` register will
989/// go high and an interrupt will be triggered.
990///
991/// If the external clock can be fixed, the XOSC32K clock can be switched back
992/// using [`Xosc32kCfd::switch_back`].
993///
994/// Because the safe clock makes use of the `OscUlp32k`, the `Xosc32kCfd` must
995/// register as a consumer of the [`EnabledOscUlp32k`] and [`Increment`] its
996/// counter.
997///
998/// [`OscUlp32k`]: super::osculp32k::OscUlp32k
999/// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k
1000pub struct Xosc32kCfd {
1001 token: Xosc32kCfdToken,
1002}
1003
1004impl Xosc32kCfd {
1005 /// Enable continuous monitoring of the XOSC32K for clock failure
1006 ///
1007 /// Because the safe clock makes use of the [`OscUlp32k`], the `Xosc32kCfd`
1008 /// must register as a consumer of the [`EnabledOscUlp32k`] and
1009 /// [`Increment`] its counter.
1010 ///
1011 /// [`OscUlp32k`]: super::osculp32k::OscUlp32k
1012 /// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k
1013 #[inline]
1014 pub fn enable<S>(
1015 mut token: Xosc32kCfdToken,
1016 osc_ulp_32k: S,
1017 div: SafeClockDiv,
1018 ) -> (Xosc32kCfd, S::Inc)
1019 where
1020 S: Source<Id = OscUlp32kId> + Increment,
1021 {
1022 token.enable(div);
1023 (Self { token }, osc_ulp_32k.inc())
1024 }
1025
1026 /// Check whether the XOSC32K has triggered clock failure detection
1027 ///
1028 /// Failure is triggered when four safe clock periods pass without seeing a
1029 /// rising & falling edge pair on the XOSC32K clock.
1030 #[inline]
1031 pub fn has_failed(&self) -> bool {
1032 self.token.has_failed()
1033 }
1034
1035 /// Check whether the XOSC32K has been switched to the safe clock
1036 ///
1037 /// Returns `true` if the XOSC32K has been switched to the safe clock.
1038 #[inline]
1039 pub fn is_switched(&self) -> bool {
1040 self.token.is_switched()
1041 }
1042
1043 /// Attempt to switch from the safe clock back to the external clock
1044 ///
1045 /// This function will set the switch back bit (`SWBACK`) in the `Cfdctrl`
1046 /// register. Once the hardware has successfully switched back, this bit
1047 /// will be automatically cleared.
1048 ///
1049 /// Users can check whether switching back was successful by checking the
1050 /// `STATUS` register with [`Xosc32kCfd::is_switched`].
1051 #[inline]
1052 pub fn switch_back(&mut self) {
1053 self.token.switch_back()
1054 }
1055
1056 /// Disable continuous monitoring of the XOSC32K for clock failure
1057 ///
1058 /// Once failure monitoring is disabled, the [`OscUlp32k`] is no longer used
1059 /// as the safe clock, so the [`EnabledOscUlp32k`] counter can be
1060 /// [`Decrement`]ed.
1061 ///
1062 /// [`OscUlp32k`]: super::osculp32k::OscUlp32k
1063 /// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k
1064 #[inline]
1065 pub fn disable<S>(mut self, osc_ulp_32k: S) -> (Xosc32kCfdToken, S::Dec)
1066 where
1067 S: Source<Id = OscUlp32kId> + Decrement,
1068 {
1069 self.token.disable();
1070 (self.token, osc_ulp_32k.dec())
1071 }
1072}
1073
1074//==============================================================================
1075// Ids
1076//==============================================================================
1077
1078/// Type representing the identity of the [`Xosc1k`] clock
1079///
1080/// See the discussion on [`Id` types](super#id-types) for more information.
1081pub enum Xosc1kId {}
1082
1083impl Sealed for Xosc1kId {}
1084
1085/// Type representing the identity of the [`Xosc32k`] clock
1086///
1087/// See the discussion on [`Id` types](super#id-types) for more information.
1088pub enum Xosc32kId {}
1089
1090impl Sealed for Xosc32kId {}
1091
1092//==============================================================================
1093// Xosc1k
1094//==============================================================================
1095
1096/// Clock representing the 1 kHz output of the [`Xosc32kBase`] clock
1097///
1098/// The XOSC32K peripheral has two possible clock outputs, one at 32 kHz and
1099/// another at 1 kHz. This structure is represented in the type system as a set
1100/// of three clocks forming a small clock tree. The [`Xosc1k`] clock is derived
1101/// from the [`Xosc32kBase`] clock. See the [module-level documentation](super)
1102/// for details and examples.
1103pub struct Xosc1k {
1104 token: Xosc1kToken,
1105}
1106
1107/// The [`Enabled`] [`Xosc1k`] clock
1108///
1109/// As described in the [`clock` module documentation](super), the [`Enabled`]
1110/// wrapper implements compile-time clock tree safety by tracking the number of
1111/// clocks consuming the [`Xosc1k`] clock and restricts access to the underlying
1112/// type to prevent misuse.
1113///
1114/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
1115/// the counter is assumed to be zero.
1116pub type EnabledXosc1k<N = U0> = Enabled<Xosc1k, N>;
1117
1118impl Xosc1k {
1119 /// Enable 1 kHz output from the [`Xosc32kBase`] clock
1120 ///
1121 /// This will [`Increment`] the [`EnabledXosc32kBase`] counter.
1122 #[inline]
1123 pub fn enable<M, N>(
1124 token: Xosc1kToken,
1125 mut base: EnabledXosc32kBase<M, N>,
1126 ) -> (EnabledXosc1k, EnabledXosc32kBase<M, N::Inc>)
1127 where
1128 M: Mode,
1129 N: Increment,
1130 {
1131 base.0.token.enable_1k();
1132 (Enabled::new(Self { token }), base.inc())
1133 }
1134}
1135
1136impl EnabledXosc1k {
1137 /// Disable 1 kHz output from the [`Xosc32kBase`] clock
1138 ///
1139 /// This will [`Decrement`] the [`EnabledXosc32kBase`] counter.
1140 #[inline]
1141 pub fn disable<M, N>(
1142 self,
1143 mut base: EnabledXosc32kBase<M, N>,
1144 ) -> (Xosc1kToken, EnabledXosc32kBase<M, N::Dec>)
1145 where
1146 M: Mode,
1147 N: Decrement,
1148 {
1149 base.0.token.disable_1k();
1150 (self.0.token, base.dec())
1151 }
1152}
1153
1154impl<N> Source for EnabledXosc1k<N> {
1155 type Id = Xosc1kId;
1156
1157 #[inline]
1158 fn freq(&self) -> Hertz {
1159 1024.Hz()
1160 }
1161}
1162
1163//==============================================================================
1164// Xosc32k
1165//==============================================================================
1166
1167/// Clock representing the 32 kHz output of the [`Xosc32kBase`] clock
1168///
1169/// The XOSC32K peripheral has two possible clock outputs, one at 32 kHz and
1170/// another at 1 kHz. This structure is represented in the type system as a set
1171/// of three clocks forming a small clock tree. The [`Xosc32k`] clock is derived
1172/// from the [`Xosc32kBase`] clock. See the [module-level documentation](super)
1173/// for details and examples.
1174pub struct Xosc32k {
1175 token: Xosc32kToken,
1176}
1177
1178/// The [`Enabled`] [`Xosc32k`] clock
1179///
1180/// As described in the [`clock` module documentation](super), the [`Enabled`]
1181/// wrapper implements compile-time clock tree safety by tracking the number of
1182/// clocks consuming the [`Xosc32k`] clock and restricts access to the
1183/// underlying type to prevent misuse.
1184///
1185/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
1186/// the counter is assumed to be zero.
1187pub type EnabledXosc32k<N = U0> = Enabled<Xosc32k, N>;
1188
1189impl Xosc32k {
1190 /// Enable 32 kHz output from the [`Xosc32kBase`] clock
1191 ///
1192 /// This will [`Increment`] the [`EnabledXosc32kBase`] counter.
1193 #[inline]
1194 pub fn enable<M, N>(
1195 token: Xosc32kToken,
1196 mut base: EnabledXosc32kBase<M, N>,
1197 ) -> (EnabledXosc32k, EnabledXosc32kBase<M, N::Inc>)
1198 where
1199 M: Mode,
1200 N: Increment,
1201 {
1202 base.0.token.enable_32k();
1203 (Enabled::new(Self { token }), base.inc())
1204 }
1205}
1206
1207impl EnabledXosc32k {
1208 /// Disable 1 kHz output from the [`Xosc32kBase`] clock
1209 ///
1210 /// This will [`Decrement`] the [`EnabledXosc32kBase`] counter.
1211 #[inline]
1212 pub fn disable<M, N>(
1213 self,
1214 mut base: EnabledXosc32kBase<M, N>,
1215 ) -> (Xosc32kToken, EnabledXosc32kBase<M, N::Dec>)
1216 where
1217 M: Mode,
1218 N: Decrement,
1219 {
1220 base.0.token.disable_32k();
1221 (self.0.token, base.dec())
1222 }
1223}
1224
1225impl<N> Source for EnabledXosc32k<N> {
1226 type Id = Xosc32kId;
1227
1228 #[inline]
1229 fn freq(&self) -> Hertz {
1230 32_768.Hz()
1231 }
1232}