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

1//! # Digital Frequency Locked Loop
2//!
3//! The `dfll` module provides access to the 48 MHz digital frequency locked
4//! loop (DFLL or DFLL48M) within the `OSCCTRL` peripheral.
5//!
6//! ## Operation modes
7//!
8//! The DFLL is represented by the type [`Dfll<M>`], where `M` is one of three
9//! operating [`Mode`] types. The default type is [`OpenLoop`], while the other
10//! two types, [`FromPclk`] and [`FromUsb`], represent closed-loop `Mode`s with
11//! the corresponding [`Reference`] clock.
12//!  
13//! ### Open-loop mode
14//! In open-loop mode, the DFLL uses an internal oscillator to produce an
15//! unreferenced, 48 MHz output clock.
16//!
17//! Open-loop mode can only be used when the main voltage regulator is operating
18//! in linear mode (the default).
19//!
20//! ### Closed-loop modes
21//! In closed-loop mode, the DFLL multiplies a low-frequency input clock to
22//! yield a 48 MHz output clock. The reference clock can be provided by a GCLK,
23//! through the DFLL peripheral channel clock, or it can be provided by the USB
24//! start-of-frame signal.
25//!
26//! ## The DFLL at power-on reset
27//!
28//! Because the DFLL can produce a 48 MHz clock from an internal oscillator, it
29//! is used as the system's default master clock at power-on reset. While most
30//! clocks are disabled at reset and represented by items in the [`Tokens`]
31//! struct, the [`Dfll`] is [`Enabled`] at reset, so it is found in the
32//! [`Clocks`] struct.
33//!
34//! At reset, the [`EnabledDfll`] is in [`OpenLoop`] [`Mode`] and has one
35//! consumer clock, so its complete type is `EnabledDfll<U1>`. The corresponding
36//! consumer is [`Gclk0`], which is represented as `EnabledGclk0<DfllId, U1>`.
37//! Here, the [`EnabledGclk0`] has its own consumer as well, which is the
38//! system's master clock.
39//!
40//! ## Example
41//!
42//! Configuring the [`Dfll`] proceeds according to the principles outlined in
43//! the [`clock` module documentation]. Suppose we start with the default clock
44//! tree after power-on reset.
45//!
46//! ```text
47//! DFLL (48 MHz; open-loop mode)
48//! └── GCLK0 (48 MHz)
49//!     └── Master clock (48 MHz)
50//! ```
51//!
52//! We would like to transform it to a clock tree like this:
53//!
54//! ```text
55//! XOSC0 (24 MHz; external clock)
56//! └── GCLK0 (24 MHz)
57//!     ├── Master clock (24 MHz)
58//!     └── DFLL (48 MHz; closed-loop mode)
59//! ```
60//!
61//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking
62//! structs. We'll also need access to the GPIO [`Pins`].
63//!
64//! ```no_run
65//! use atsamd_hal::{
66//!     clock::v2::{clock_system_at_reset, dfll::Dfll, xosc::Xosc},
67//!     gpio::Pins,
68//!     pac::Peripherals,
69//!     fugit::RateExtU32,
70//! };
71//! let mut pac = Peripherals::take().unwrap();
72//! let pins = Pins::new(pac.port);
73//! let (buses, clocks, tokens) = clock_system_at_reset(
74//!     pac.oscctrl,
75//!     pac.osc32kctrl,
76//!     pac.gclk,
77//!     pac.mclk,
78//!     &mut pac.nvmctrl,
79//! );
80//! ```
81//!
82//! Next, we create a 24 MHz [`Xosc`] clock from one of the [`Pins`] and enable
83//! it.
84//!
85//! ```no_run
86//! # use atsamd_hal::{
87//! #     clock::v2::{clock_system_at_reset, dfll::Dfll, xosc::Xosc},
88//! #     gpio::Pins,
89//! #     pac::Peripherals,
90//! #     fugit::RateExtU32,
91//! # };
92//! # let mut pac = Peripherals::take().unwrap();
93//! # let pins = Pins::new(pac.port);
94//! # let (buses, clocks, tokens) = clock_system_at_reset(
95//! #     pac.oscctrl,
96//! #     pac.osc32kctrl,
97//! #     pac.gclk,
98//! #     pac.mclk,
99//! #     &mut pac.nvmctrl,
100//! # );
101//! let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.MHz()).enable();
102//! ```
103//!
104//! We can then swap [`Gclk0`] from the [`EnabledDfll`] to the [`EnabledXosc`].
105//! This releases the [`EnabledDfll`] and [`Decrement`]s its consumer count,
106//! which allows us to disable it and retrieve the underlying [`DfllToken`].
107//!
108//! ```no_run
109//! # use atsamd_hal::{
110//! #     clock::v2::{clock_system_at_reset, dfll::Dfll, xosc::Xosc},
111//! #     gpio::Pins,
112//! #     pac::Peripherals,
113//! #     fugit::RateExtU32,
114//! # };
115//! # let mut pac = Peripherals::take().unwrap();
116//! # let pins = Pins::new(pac.port);
117//! # let (buses, clocks, tokens) = clock_system_at_reset(
118//! #     pac.oscctrl,
119//! #     pac.osc32kctrl,
120//! #     pac.gclk,
121//! #     pac.mclk,
122//! #     &mut pac.nvmctrl,
123//! # );
124//! # let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.MHz()).enable();
125//! let (gclk0, dfll, xosc0) = clocks.gclk0.swap_sources(clocks.dfll, xosc0);
126//! let token_dfll = dfll.disable().free();
127//! ```
128//!
129//! Next, we can enable the peripheral channel clock, or [`Pclk`], for the
130//! [`Dfll`], sourcing it from [`Gclk0`]. With the `Pclk`, we can then recreate
131//! the `Dfll` in closed-loop mode. Finally, we can adjust some of the
132//! closed-loop parameters before we enable it. The returned [`EnabledDfll`] can
133//! be used as a clock [`Source`] elsewhere in the clock tree.
134//!
135//! ```no_run
136//! # use atsamd_hal::{
137//! #     clock::v2::{clock_system_at_reset, dfll::Dfll, pclk::Pclk, xosc::Xosc},
138//! #     gpio::Pins,
139//! #     pac::Peripherals,
140//! #     fugit::RateExtU32,
141//! # };
142//! # let mut pac = Peripherals::take().unwrap();
143//! # let pins = Pins::new(pac.port);
144//! # let (buses, clocks, tokens) = clock_system_at_reset(
145//! #     pac.oscctrl,
146//! #     pac.osc32kctrl,
147//! #     pac.gclk,
148//! #     pac.mclk,
149//! #     &mut pac.nvmctrl,
150//! # );
151//! # let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.MHz()).enable();
152//! # let (gclk0, dfll, xosc0) = clocks.gclk0.swap_sources(clocks.dfll, xosc0);
153//! # let token_dfll = dfll.disable().free();
154//! let (pclk_dfll, gclk0) = Pclk::enable(tokens.pclks.dfll, gclk0);
155//! let dfll = Dfll::from_pclk(token_dfll, pclk_dfll)
156//!     .coarse_max_step(1)
157//!     .fine_max_step(10)
158//!     .quick_lock(false)
159//!     .enable();
160//! ```
161//!
162//! The entire example is provided below.
163//!
164//! ```no_run
165//! use atsamd_hal::{
166//!     clock::v2::{clock_system_at_reset, dfll::Dfll, pclk::Pclk, xosc::Xosc},
167//!     gpio::Pins,
168//!     pac::Peripherals,
169//!     fugit::RateExtU32,
170//! };
171//! let mut pac = Peripherals::take().unwrap();
172//! let pins = Pins::new(pac.port);
173//! let (buses, clocks, tokens) = clock_system_at_reset(
174//!     pac.oscctrl,
175//!     pac.osc32kctrl,
176//!     pac.gclk,
177//!     pac.mclk,
178//!     &mut pac.nvmctrl,
179//! );
180//! let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.MHz()).enable();
181//! let (gclk0, dfll, xosc0) = clocks.gclk0.swap_sources(clocks.dfll, xosc0);
182//! let token_dfll = dfll.disable().free();
183//! let (pclk_dfll, gclk0) = Pclk::enable(tokens.pclks.dfll, gclk0);
184//! let dfll = Dfll::from_pclk(token_dfll, pclk_dfll)
185//!     .coarse_max_step(1)
186//!     .fine_max_step(10)
187//!     .quick_lock(false)
188//!     .enable();
189//! ```
190//!
191//! # Reconfiguring an [`EnabledDfll`]
192//!
193//! In some cases, users may want to reconfigure the DFLL while it remains
194//! enabled. For instance, a user may want to place the DFLL in its closed-loop,
195//! USB recovery mode while in use by the system's master clock. It would
196//! normally be impossible to do so with other clocks in the `clock` module,
197//! because changing the clock source would break an invariant of the clock
198//! tree. However, the DFLL is special, because its output frequency is always
199//! 48 MHz. Moreover, by design, consumers of the DFLL aren't affected by its
200//! configuration (see the discussion on [`Id` types]).
201//!
202//! For this reason, we define a special [`into_mode`] function on
203//! [`EnabledDfll`]. It will consume the `EnabledDfll` and transform it to use a
204//! different [`Mode`].
205//!
206//! While the [`Dfll`] constructors (i.e. [`open_loop`], [`from_pclk`], and
207//! [`from_usb`]) handle the [`Mode`] type for you, [`into_mode`] is generic
208//! over the initial and final `Mode`, so it takes and returns the corresponding
209//! `Mode` types directly. Furthermore, `into_mode` also accepts a closure,
210//! allowing you to modify the [`Dfll`] before the new `Mode` is applied.
211//!
212//! Consider the following example. As above, we start with the clocks in their
213//! default configuration at power-on reset. Remember that the [`Dfll`] is used
214//! by the system's master clock. At this point, we would like to reconfigure it
215//! to use an external 32 kHz clock on pin PA10. First, we construct a [`Gclk`]
216//! from the corresponding [`gpio`] [`Pin`]. Then we enable the [`Pclk`] for the
217//! DFLL and construct an instance of [`FromPclk`]. Finally, we call
218//! `into_mode`, which takes an instance of [`FromPclk`] and returns an instance
219//! of [`OpenLoop`]. Neither [`OpenLoop`] nor [`FromUsb`] need to store a
220//! corresponding resource, so they are both effectively equivalent to the `()`
221//! type. We can also change some of the DFLL control loop settings prior to the
222//! [`Mode`] change using the closure argument to `into_mode`.
223//!
224//! ```no_run
225//! use atsamd_hal::{
226//!     clock::v2::{
227//!         clock_system_at_reset,
228//!         dfll::{Dfll, FromPclk},
229//!         gclk::Gclk,
230//!         pclk::Pclk,
231//!     },
232//!     gpio::Pins,
233//!     pac::Peripherals,
234//!     fugit::RateExtU32,
235//! };
236//! let mut pac = Peripherals::take().unwrap();
237//! let pins = Pins::new(pac.port);
238//! let (buses, mut clocks, tokens) = clock_system_at_reset(
239//!     pac.oscctrl,
240//!     pac.osc32kctrl,
241//!     pac.gclk,
242//!     pac.mclk,
243//!     &mut pac.nvmctrl,
244//! );
245//! let gclk4 = Gclk::from_pin(tokens.gclks.gclk4, pins.pa10, 32_768.hz()).enable();
246//! let (pclk, gclk4) = Pclk::enable(tokens.pclks.dfll, gclk4);
247//! let from_pclk = FromPclk { pclk };
248//! let (dfll, open_loop) = clocks.dfll.into_mode(from_pclk, |dfll| {
249//!     dfll.set_coarse_max_step(1);
250//!     dfll.set_fine_max_step(8);
251//!     dfll.set_chill_cycle(false);
252//!     dfll.set_run_standby(true);
253//! });
254//! ```
255//!
256//! [`clock_system_at_reset`]: super::clock_system_at_reset
257//! [`clock` module documentation]: super
258//! [`Id` types]: super#id-types
259//! [`Clocks`]: super::Clocks
260//! [`Tokens`]: super::Tokens
261//! [`gpio`]: crate::gpio
262//! [`Pin`]: crate::gpio::Pin
263//! [`Pins`]: crate::gpio::Pins
264//! [`Xosc`]: super::xosc::Xosc
265//! [`Gclk`]: super::gclk::Gclk
266//! [`EnabledXosc`]: super::xosc::EnabledXosc
267//! [`Gclk0`]: super::gclk::Gclk0
268//! [`EnabledGclk0`]: super::gclk::EnabledGclk0
269//! [`Decrement`]: crate::typelevel::Decrement
270//! [`open_loop`]: Dfll::open_loop
271//! [`from_pclk`]: Dfll::from_pclk
272//! [`from_usb`]: Dfll::from_usb
273//! [`into_mode`]: EnabledDfll::into_mode
274
275use fugit::RateExtU32;
276use typenum::U0;
277
278use crate::time::Hertz;
279use crate::typelevel::{NoneT, Sealed};
280
281use super::gclk::GclkId;
282use super::pclk::Pclk;
283use super::{Enabled, Source};
284
285//==============================================================================
286// DfllToken
287//==============================================================================
288
289/// Singleton token that can be exchanged for the [`Dfll`]
290///
291/// As explained in the [`clock` module documentation](super), instances of
292/// various `Token` types represent disabled clocks and can be exchanged for
293/// actual clock types. However, unlike most other clocks in the module, the
294/// [`Dfll`] is [`Enabled`] at power-on reset. Thus, users will never deal with
295/// the `DfllToken` unless they first disable the [`EnabledDfll`].
296pub struct DfllToken(());
297
298impl DfllToken {
299    /// Create a new [`DfllToken`]
300    ///
301    /// # Safety
302    ///
303    /// The `DfllToken`s is a singleton. There must never be two simulatenous
304    /// instances of it. See the notes on `Token` types and memory safety in the
305    /// root of the `clock` module for more details.
306    #[inline]
307    pub(crate) unsafe fn new() -> Self {
308        Self(())
309    }
310
311    #[inline]
312    fn oscctrl(&self) -> &crate::pac::oscctrl::RegisterBlock {
313        // Safety: The `DfllToken` only has access to a mutually exclusive set
314        // of registers for the DFLL, and we use a shared reference to the
315        // register block. See the notes on `Token` types and memory safety in
316        // the root of the `clock` module for more details.
317        unsafe { &*crate::pac::Oscctrl::PTR }
318    }
319
320    #[inline]
321    fn dfllctrla(&self) -> &crate::pac::oscctrl::Dfllctrla {
322        self.oscctrl().dfllctrla()
323    }
324
325    #[inline]
326    fn dfllctrlb(&self) -> &crate::pac::oscctrl::Dfllctrlb {
327        self.oscctrl().dfllctrlb()
328    }
329
330    #[inline]
331    fn dfllmul(&self) -> &crate::pac::oscctrl::Dfllmul {
332        self.oscctrl().dfllmul()
333    }
334
335    #[inline]
336    fn dfllsync(&self) -> &crate::pac::oscctrl::Dfllsync {
337        self.oscctrl().dfllsync()
338    }
339
340    #[inline]
341    fn wait_sync_enable(&self) {
342        while self.dfllsync().read().enable().bit() {}
343    }
344
345    #[inline]
346    fn wait_sync_dfllmul(&self) {
347        while self.dfllsync().read().dfllmul().bit() {}
348    }
349
350    #[inline]
351    fn wait_sync_dfllctrlb(&self) {
352        while self.dfllsync().read().dfllctrlb().bit() {}
353    }
354
355    #[inline]
356    fn configure(&mut self, settings: settings::All) {
357        self.dfllctrlb().modify(|_, w| {
358            w.mode().bit(settings.closed_loop);
359            w.usbcrm().bit(settings.usb_recovery);
360            w.ccdis().bit(!settings.chill_cycle);
361            w.qldis().bit(!settings.quick_lock)
362        });
363        self.wait_sync_dfllctrlb();
364        if settings.closed_loop {
365            self.dfllmul().modify(|_, w|
366            // Safety: All bit patterns are valid for these fields
367            unsafe {
368                w.mul().bits(settings.mult_factor);
369                w.cstep().bits(settings.coarse_max_step);
370                w.fstep().bits(settings.fine_max_step)
371            });
372            self.wait_sync_dfllmul();
373        }
374        self.dfllctrla().modify(|_, w| {
375            w.runstdby().bit(settings.run_standby);
376            w.ondemand().bit(settings.on_demand)
377        });
378    }
379
380    #[inline]
381    fn enable(&mut self) {
382        self.dfllctrla().modify(|_, w| w.enable().set_bit());
383        self.wait_sync_enable();
384    }
385
386    #[inline]
387    fn disable(&mut self) {
388        self.dfllctrla().modify(|_, w| w.enable().clear_bit());
389        self.wait_sync_enable();
390    }
391
392    #[inline]
393    fn is_ready(&self) -> bool {
394        self.oscctrl().status().read().dfllrdy().bit()
395    }
396}
397
398//==============================================================================
399// Aliases
400//==============================================================================
401
402type MultFactor = u16;
403type CoarseMaxStep = u8;
404type FineMaxStep = u8;
405
406//==============================================================================
407// DfllId
408//==============================================================================
409
410/// [`Id` type](super#id-types) representing the identity of the DFLL clock
411pub enum DfllId {}
412
413impl Sealed for DfllId {}
414
415//==============================================================================
416// Mode types
417//==============================================================================
418
419pub struct OpenLoop;
420
421pub struct FromUsb;
422
423pub struct FromPclk<G: GclkId> {
424    pub pclk: Pclk<DfllId, G>,
425}
426
427//==============================================================================
428// DynReference
429//==============================================================================
430
431/// Value-level enum identifying one of two possible reference clocks for the
432/// [`Dfll`]
433///
434/// When the [`Dfll`] is in closed-loop mode, it requires a reference clock
435/// input. The variants of this enum represent the two possible reference
436/// clocks.
437///
438/// `DynReference` is the value-level equivalent of [`Reference`].
439#[derive(Copy, Clone, PartialEq, Eq)]
440pub enum DynReference {
441    /// The DFLL is driven by a [`Pclk`]
442    Pclk,
443    /// The DFLL is driven by the USB start-of-frame signal
444    Usb,
445}
446
447//==============================================================================
448// Reference
449//==============================================================================
450
451/// Type-level enum identifying one of two possible [`Dfll`] reference clocks
452///
453/// When the [`Dfll`] is in closed-loop mode, it requires a reference clock
454/// input. The types implementing this trait, i.e. [`FromPclk`] and [`FromUsb`],
455/// are type-level variants of `Reference`, and they identify one of the two
456/// possible reference clocks.
457///
458/// `Reference` is the type-level equivalent of [`DynReference`]. See the
459/// documentation on [type-level programming] and specifically
460/// [type-level enums] for more details.
461///
462/// [type-level programming]: crate::typelevel
463/// [type-level enums]: crate::typelevel#type-level-enums
464pub trait Reference {
465    /// Corresponding variant of [`DynReference`]
466    const DYN: DynReference;
467    #[doc(hidden)]
468    type Settings: Settings;
469    #[doc(hidden)]
470    fn from_settings(reference: Self::Settings) -> Self;
471    #[doc(hidden)]
472    fn into_settings(self) -> Self::Settings;
473}
474
475impl Reference for FromUsb {
476    const DYN: DynReference = DynReference::Usb;
477    type Settings = settings::Usb;
478    fn from_settings(_: Self::Settings) -> Self {
479        FromUsb
480    }
481    fn into_settings(self) -> Self::Settings {
482        settings::Usb
483    }
484}
485
486impl<G: GclkId> Reference for FromPclk<G> {
487    const DYN: DynReference = DynReference::Pclk;
488    type Settings = settings::Pclk<G>;
489    fn from_settings(reference: Self::Settings) -> Self {
490        Self {
491            pclk: reference.pclk,
492        }
493    }
494    fn into_settings(self) -> Self::Settings {
495        settings::Pclk::new(self.pclk)
496    }
497}
498
499//==============================================================================
500// DynMode
501//==============================================================================
502
503/// Value-level enum identifying the [`Dfll`] control loop mode
504///
505/// The [`Dfll`] can operate in both open-loop and closed-loop modes.
506/// Furthermore, when the DFLL is in closed-loop mode, it requires a
507/// corresponding reference clock.
508///
509/// `DynMode` is the value-level equivalent of [`Mode`].
510#[derive(Copy, Clone, PartialEq, Eq)]
511pub enum DynMode {
512    OpenLoop,
513    ClosedLoop(DynReference),
514}
515
516//==============================================================================
517// Mode
518//==============================================================================
519
520/// Type-level enum identifying the [`Dfll`] control loop mode
521///
522/// The types implementing this trait, i.e. [`OpenLoop`], [`FromPclk`] and
523/// [`FromUsb`], are type-level variants of `Mode`, and they determine whether
524/// the DFLL operates in closed-loop mode, and if so, which [`Reference`] clock
525/// to use.
526///
527/// `Mode` is the type-level equivalent of [`DynMode`]. See the documentation on
528/// [type-level programming] and specifically [type-level enums] for more
529/// details.
530///
531/// [type-level programming]: crate::typelevel
532/// [type-level enums]: crate::typelevel#type-level-enums
533pub trait Mode {
534    /// Corresponding variant of [`DynMode`]
535    const DYN: DynMode;
536    #[doc(hidden)]
537    type Settings: Settings;
538    #[doc(hidden)]
539    fn from_settings(mode: Self::Settings) -> Self;
540    #[doc(hidden)]
541    fn into_settings(self) -> Self::Settings;
542}
543
544impl Mode for OpenLoop {
545    const DYN: DynMode = DynMode::OpenLoop;
546    type Settings = settings::OpenLoop;
547    fn from_settings(_: Self::Settings) -> Self {
548        OpenLoop
549    }
550    fn into_settings(self) -> Self::Settings {
551        settings::OpenLoop
552    }
553}
554
555impl<R: Reference> Mode for R {
556    const DYN: DynMode = DynMode::ClosedLoop(R::DYN);
557    type Settings = settings::ClosedLoop<R::Settings>;
558    fn from_settings(mode: Self::Settings) -> Self {
559        R::from_settings(mode.reference)
560    }
561    fn into_settings(self) -> Self::Settings {
562        let reference = R::into_settings(self);
563        settings::ClosedLoop::new(reference)
564    }
565}
566
567//==============================================================================
568// Settings
569//==============================================================================
570
571mod settings {
572    //! Store and retrieve [`Dfll`] settings in different modes
573    //!
574    //! Many of the [`Dfll`] settings are not valid or required in every
575    //! operating mode. This module provides a framework to store only the
576    //! minimum required settings for each mode in a generic way. Specifically,
577    //! the [`Minimum`] struct stores the few settings relevant in all modes,
578    //! along with a generic, mode-specific type. The [`Settings`] trait unifies
579    //! all concrete instances of [`Minimum`] by providing a function to return
580    //! a collection of [`All`] settings. Each sub-struct within [`Minimum`]
581    //! implements [`Settings`] and is responsible for filling the relevent
582    //! fields of [`All`].
583    //!
584    //! [`Dfll`]: super::Dfll
585
586    use super::super::pclk;
587    use super::RateExtU32;
588    use super::{CoarseMaxStep, DfllId, FineMaxStep, GclkId, Hertz, MultFactor};
589
590    /// Collection of all possible [`Dfll`] settings
591    ///
592    /// This struct is returned by the [`Settings`] trait.
593    ///
594    /// [`Dfll`]: super::Dfll
595    pub struct All {
596        pub src_freq: Hertz,
597        pub closed_loop: bool,
598        pub usb_recovery: bool,
599        pub mult_factor: MultFactor,
600        pub chill_cycle: bool,
601        pub quick_lock: bool,
602        pub coarse_max_step: CoarseMaxStep,
603        pub fine_max_step: FineMaxStep,
604        pub run_standby: bool,
605        pub on_demand: bool,
606    }
607
608    impl Default for All {
609        #[inline]
610        fn default() -> Self {
611            All {
612                src_freq: 48_000_000.Hz(),
613                closed_loop: false,
614                usb_recovery: false,
615                mult_factor: 1,
616                chill_cycle: true,
617                quick_lock: true,
618                coarse_max_step: 1,
619                fine_max_step: 1,
620                run_standby: false,
621                on_demand: true,
622            }
623        }
624    }
625
626    /// Collection of [`Dfll`] settings containing only the minimum required
627    /// for the specific mode
628    ///
629    /// Many [`Dfll`] settings are not valid or required in every operating
630    /// mode. This struct provides a framework to store and retrieve only the
631    /// minimum settings for each mode in a generic way.
632    ///
633    /// Specifically, it stores flags for the `RUNSTDBY` and `ONDEMAND` fields,
634    /// which are relevant in every mode, and it stores a mode-specific type,
635    /// `T`. This can be either [`OpenLoop`] or [`ClosedLoop`], which both
636    /// implement the [`Settings`] trait.
637    ///
638    /// [`Dfll`]: super::Dfll
639    pub struct Minimum<T: Settings> {
640        pub mode: T,
641        pub run_standby: bool,
642        pub on_demand: bool,
643    }
644
645    impl<T: Settings> Minimum<T> {
646        pub fn new(mode: T) -> Self {
647            Self {
648                mode,
649                run_standby: false,
650                on_demand: true,
651            }
652        }
653    }
654
655    /// Collection of settings specific to open-loop [`Dfll`] operation
656    ///
657    /// Right now, this struct is empty, as none of the settings are relevant to
658    /// open-loop operation.
659    ///
660    /// [`Dfll`]: super::Dfll
661    pub struct OpenLoop;
662
663    /// Collection of settings specific to closed-loop [`Dfll`] operation
664    ///
665    /// This struct stores the maximum step size for the coarse and fine
666    /// adjustments in closed-loop mode. It also stores an additional type, `T`,
667    /// containing settings specific to the reference clock, which can be either
668    /// [`Pclk`] or [`Usb`]. Both implement the [`Settings`] trait.
669    ///
670    /// [`Dfll`]: super::Dfll
671    pub struct ClosedLoop<T: Settings> {
672        pub reference: T,
673        pub coarse_max_step: CoarseMaxStep,
674        pub fine_max_step: FineMaxStep,
675    }
676
677    impl<T: Settings> ClosedLoop<T> {
678        pub fn new(reference: T) -> Self {
679            Self {
680                reference,
681                coarse_max_step: 1,
682                fine_max_step: 1,
683            }
684        }
685    }
686
687    /// Collection of settings specific to [`Dfll`] USB recovery mode
688    ///
689    /// Right now, this struct is empty, but its implementation of [`Settings`]
690    /// fills several fields of [`All`] with known, constant values for USB
691    /// recovery mode.
692    ///
693    /// [`Dfll`]: super::Dfll
694    pub struct Usb;
695
696    /// Collection of [`Dfll`] settings when used in closed-loop mode with a
697    /// [`Pclk`] reference
698    ///
699    /// This struct stores the [`Pclk`] and multiplication factor, which
700    /// determine the precise [`Dfll`] frequency, as well as flags to control
701    /// the chill-cycle and quick-lock features. Note that these flags indicate
702    /// whether the feature is *enabled*, while the corresponding register bits
703    /// indicate whether the feature is *disabled*.
704    ///
705    /// [`Dfll`]: super::Dfll
706    /// [`Pclk`]: pclk::Pclk
707    pub struct Pclk<G: GclkId> {
708        pub pclk: pclk::Pclk<DfllId, G>,
709        pub mult_factor: MultFactor,
710        pub chill_cycle: bool,
711        pub quick_lock: bool,
712    }
713
714    impl<G: GclkId> Pclk<G> {
715        pub fn new(pclk: pclk::Pclk<DfllId, G>) -> Self {
716            // Cast is fine because division result cannot be greater than u16::MAX
717            let mult_factor = (48_000_000 / pclk.freq().to_Hz()) as u16;
718            Self {
719                pclk,
720                mult_factor,
721                chill_cycle: true,
722                quick_lock: true,
723            }
724        }
725    }
726
727    /// Generic interface to convert the [`Minimum`] settings into a collection
728    /// of [`All`] settings
729    ///
730    /// Because many of the [`Dfll`] settings are not valid or relevant in every
731    /// operating mode, we only want to store the [`Minimum`] required settings
732    /// for each. To do so, we must have a generic interface to retrieve
733    /// settings in every mode.
734    ///
735    /// This trait provides a recursive interface to yield a collection of
736    /// [`All`] [`Dfll`] settings. Each implementer of [`Settings`] is required
737    /// to fill its respective fields of [`All`] and recursively defer other
738    /// fields to any sub-structs. At the bottom of the stack, structs can defer
739    /// to the [`Default`] settings for [`All`].
740    ///
741    /// [`Dfll`]: super::Dfll
742    pub trait Settings {
743        /// Fill the respective fields of [`All`] and recursively defer any
744        /// remaining fields to sub-structs or the [`Default`] settings
745        fn all(&self) -> All;
746    }
747
748    impl<T: Settings> Settings for Minimum<T> {
749        #[inline]
750        fn all(&self) -> All {
751            All {
752                run_standby: self.run_standby,
753                on_demand: self.on_demand,
754                ..self.mode.all()
755            }
756        }
757    }
758
759    impl Settings for OpenLoop {
760        #[inline]
761        fn all(&self) -> All {
762            All::default()
763        }
764    }
765
766    impl<T: Settings> Settings for ClosedLoop<T> {
767        #[inline]
768        fn all(&self) -> All {
769            All {
770                closed_loop: true,
771                coarse_max_step: self.coarse_max_step,
772                fine_max_step: self.fine_max_step,
773                ..self.reference.all()
774            }
775        }
776    }
777
778    impl Settings for Usb {
779        #[inline]
780        fn all(&self) -> All {
781            All {
782                usb_recovery: true,
783                src_freq: 1_000.Hz(),
784                mult_factor: 48_000,
785                ..All::default()
786            }
787        }
788    }
789
790    impl<G: GclkId> Settings for Pclk<G> {
791        #[inline]
792        fn all(&self) -> All {
793            All {
794                src_freq: self.pclk.freq(),
795                mult_factor: self.mult_factor,
796                chill_cycle: self.chill_cycle,
797                quick_lock: self.quick_lock,
798                ..All::default()
799            }
800        }
801    }
802}
803
804use settings::Settings;
805
806//==============================================================================
807// Dfll
808//==============================================================================
809
810/// Digital frequency-locked loop used to generate a 48 MHz clock
811///
812/// The DFLL generates a 48 MHz clock in two different possible [`Mode`]s. In
813/// [`OpenLoop`] `Mode`, it generates the output clock from an internal
814/// oscillator, while in the two closed-loop `Mode`s, it multiplies a
815/// low-frequency [`Reference`] clock.
816///
817/// On its own, the `Dfll` type does not represent the enabled DFLL. Instead, it
818/// must first be wrapped with [`Enabled`], which implements compile-time safety
819/// of the clock tree.
820///
821/// Because the terminal call to [`enable`] consumes the `Dfll` and returns an
822/// [`EnabledDfll`], the remaining API uses the builder pattern, where each
823/// method takes and returns `self` by value, allowing them to be easily
824/// chained.
825///
826/// See the [module-level documentation](self) for an example of creating,
827/// configuring and using the `Dfll`.
828///
829/// [`enable`]: Dfll::enable
830pub struct Dfll<M: Mode = OpenLoop> {
831    token: DfllToken,
832    settings: settings::Minimum<M::Settings>,
833}
834
835impl<M: Mode> Dfll<M> {
836    #[inline]
837    fn from_mode(token: DfllToken, mode: M) -> Self {
838        let mode = M::into_settings(mode);
839        let settings = settings::Minimum::new(mode);
840        Self { token, settings }
841    }
842}
843
844impl Dfll {
845    /// Create the [`Dfll`] in open-loop mode
846    ///
847    /// Creating a [`Dfll`] does not modify any of the hardware registers. It
848    /// only creates a struct to track the `Dfll` configuration.
849    ///
850    /// The configuration data is stored until the user calls [`enable`].
851    /// At that point, all of the registers are written according to the
852    /// initialization procedures specified in the datasheet, and an
853    /// [`EnabledDfll`] is returned. The `Dfll` is not active or useful until
854    /// that point.
855    ///
856    /// [`enable`]: Dfll::enable
857    #[inline]
858    pub fn open_loop(token: DfllToken) -> Self {
859        Self::from_mode(token, OpenLoop)
860    }
861
862    /// Consume the [`Dfll`] and release the [`DfllToken`]
863    #[inline]
864    pub fn free(self) -> DfllToken {
865        self.token
866    }
867}
868
869impl Dfll<FromUsb> {
870    /// Create the [`Dfll`] in USB recovery mode
871    ///
872    /// This creates the `Dfll` in closed-loop mode referenced to the USB
873    /// start-of-frame signal. For now, this function does not require any proof
874    /// of a functioning USB interface. Future versions of this function may
875    /// take ownership of some resource both to prove USB has been setup
876    /// correctly and to prevent modification while in use.
877    ///
878    /// Creating a [`Dfll`] does not modify any of the hardware registers. It
879    /// only creates a struct to track the `Dfll` configuration.
880    ///
881    /// The configuration data is stored until the user calls [`enable`].
882    /// At that point, all of the registers are written according to the
883    /// initialization procedures specified in the datasheet, and an
884    /// [`EnabledDfll`] is returned. The `Dfll` is not active or useful until
885    /// that point.
886    ///
887    /// [`enable`]: Dfll::enable
888    #[inline]
889    pub fn from_usb(token: DfllToken) -> Self {
890        Self::from_mode(token, FromUsb)
891    }
892
893    /// Consume the [`Dfll`] and release the [`DfllToken`]
894    #[inline]
895    pub fn free(self) -> DfllToken {
896        self.token
897    }
898}
899
900impl<G: GclkId> Dfll<FromPclk<G>> {
901    /// Create the [`Dfll`] in closed-loop mode
902    ///
903    /// This creates the `Dfll` in closed-loop mode referenced to a [`Gclk`]
904    /// through a [`Pclk`]. It will also auto-calculate the correct
905    /// multiplication factor to best yield 48 MHz at the output.
906    ///
907    /// Creating a [`Dfll`] does not modify any of the hardware registers. It
908    /// only creates a struct to track the `Dfll` configuration.
909    ///
910    /// The configuration data is stored until the user calls [`enable`].
911    /// At that point, all of the registers are written according to the
912    /// initialization procedures specified in the datasheet, and an
913    /// [`EnabledDfll`] is returned. The `Dfll` is not active or useful until
914    /// that point.
915    ///
916    /// # Panics
917    ///
918    /// According to the datasheet, the [`Pclk`] frequency must be between
919    /// 732 Hz and 33 kHz. This function will perform a run-time check of the
920    /// input frequency and panic if it is out of range. To use a `Pclk`
921    /// frequency outside this range or to force a particular multiplication
922    /// factor, use [`Dfll::from_pclk_unchecked`].
923    ///
924    /// [`Gclk`]: super::gclk::Gclk
925    /// [`enable`]: Dfll::enable
926    #[inline]
927    pub fn from_pclk(token: DfllToken, pclk: Pclk<DfllId, G>) -> Self {
928        const MIN: u32 = 48_000_000 / MultFactor::MAX as u32;
929        const MAX: u32 = 33_000;
930        let freq = pclk.freq().to_Hz();
931        if freq < MIN || freq > MAX {
932            panic!("Invalid Pclk<DfllId, _> input frequency");
933        }
934        Self::from_mode(token, FromPclk { pclk })
935    }
936
937    /// Create the [`Dfll`] in closed-loop mode
938    ///
939    /// This constructor behaves identically to [`Dfll::from_pclk`], but it
940    /// skips the run-time check of the [`Pclk`] frequency and does not
941    /// auto-calculate the multiplication factor.
942    #[inline]
943    pub fn from_pclk_unchecked(
944        token: DfllToken,
945        pclk: Pclk<DfllId, G>,
946        mult_factor: MultFactor,
947    ) -> Self {
948        let mut dfll = Self::from_mode(token, FromPclk { pclk });
949        dfll.settings.mode.reference.mult_factor = mult_factor;
950        dfll
951    }
952
953    /// Consume the [`Dfll`], release the [`DfllToken`], and return the [`Pclk`]
954    #[inline]
955    pub fn free(self) -> (DfllToken, Pclk<DfllId, G>) {
956        (self.token, self.settings.mode.reference.pclk)
957    }
958
959    /// Enable or disable the [`Dfll`] chill cycle
960    ///
961    /// See the documentation of [`chill_cycle`] for more details.
962    ///
963    /// [`chill_cycle`]: Dfll::chill_cycle
964    #[inline]
965    pub fn set_chill_cycle(&mut self, value: bool) {
966        self.settings.mode.reference.chill_cycle = value;
967    }
968
969    /// Enable or disable the [`Dfll`] chill cycle
970    ///
971    /// When operating in closed-loop mode with small multiplication factors,
972    /// the DFLL can sometimes have trouble locking. To avoid this, the hardware
973    /// normally implements a chill cycle, during which the output frequency is
974    /// not measured. The chill cycle is enabled by default, but it can be
975    /// disabled to reduce the duration before lock. See the datasheet for more
976    /// details.
977    #[inline]
978    pub fn chill_cycle(mut self, value: bool) -> Self {
979        self.set_chill_cycle(value);
980        self
981    }
982
983    /// Enable or disable the [`Dfll`] quick lock
984    ///
985    /// See the documentation of [`quick_lock`] for more details.
986    ///
987    /// [`quick_lock`]: Dfll::quick_lock
988    #[inline]
989    pub fn set_quick_lock(&mut self, value: bool) {
990        self.settings.mode.reference.quick_lock = value;
991    }
992
993    /// Enable or disable the [`Dfll`] quick lock
994    ///
995    /// By default, the DFLL locking requirements are somewhat loose. Users can
996    /// tighten these requirements by disabling the quick lock feature, which is
997    /// enabled by default. See the datasheet for more details.
998    #[inline]
999    pub fn quick_lock(mut self, value: bool) -> Self {
1000        self.set_quick_lock(value);
1001        self
1002    }
1003}
1004
1005impl<R: Reference> Dfll<R> {
1006    /// Set the maximum coarse step size during closed-loop frequency tuning
1007    ///
1008    /// See the documentation of [`coarse_max_step`] for more details.
1009    ///
1010    /// [`coarse_max_step`]: Dfll::coarse_max_step
1011    #[inline]
1012    pub fn set_coarse_max_step(&mut self, coarse_max_step: CoarseMaxStep) {
1013        self.settings.mode.coarse_max_step = coarse_max_step;
1014    }
1015
1016    /// Set the maximum coarse step size during closed-loop frequency tuning
1017    ///
1018    /// In closed-loop operation, the DFLL output frequency is continuously
1019    /// regulated against the reference clock by adjusting the coarse and fine
1020    /// tuning parameters. This function sets a maximum step size for the coarse
1021    /// tuning parameter.
1022    ///
1023    /// In general, a small step size will ensure low overshoot in the output
1024    /// frequency, but it will lengthen the time to lock. A larger step size
1025    /// will produce more overshoot but will be quicker to lock. See the
1026    /// datasheet for more details.
1027    #[inline]
1028    pub fn coarse_max_step(mut self, coarse_max_step: CoarseMaxStep) -> Self {
1029        self.set_coarse_max_step(coarse_max_step);
1030        self
1031    }
1032
1033    /// Set the maximum fine step size during closed-loop frequency tuning
1034    ///
1035    /// See the documentation of [`fine_max_step`] for more details.
1036    ///
1037    /// [`fine_max_step`]: Dfll::fine_max_step
1038    #[inline]
1039    pub fn set_fine_max_step(&mut self, fine_max_step: FineMaxStep) {
1040        self.settings.mode.fine_max_step = fine_max_step;
1041    }
1042
1043    /// Set the maximum fine step size during closed-loop frequency tuning
1044    ///
1045    /// In closed-loop operation, the DFLL output frequency is continuously
1046    /// regulated against the reference clock by adjusting the coarse and fine
1047    /// tuning parameters. This function sets a maximum step size for the fine
1048    /// tuning parameter.
1049    ///
1050    /// In general, a small step size will ensure low overshoot in the output
1051    /// frequency, but it will lengthen the time to lock. A larger step size
1052    /// will produce more overshoot but will be quicker to lock. See the
1053    /// datasheet for more details.
1054    #[inline]
1055    pub fn fine_max_step(mut self, fine_max_step: FineMaxStep) -> Self {
1056        self.set_fine_max_step(fine_max_step);
1057        self
1058    }
1059}
1060
1061impl<M: Mode> Dfll<M> {
1062    /// Return the [`Dfll`] output frequency
1063    ///
1064    /// The output frequency will always be close to, if not exactly, 48 MHz.
1065    #[inline]
1066    pub fn freq(&self) -> Hertz {
1067        // Valid for all modes based on default values
1068        let settings = self.settings.all();
1069        settings.src_freq * settings.mult_factor as u32
1070    }
1071
1072    /// Control the [`Dfll`] behavior during idle or standby sleep modes
1073    ///
1074    /// See the documentation of [`run_standby`] for more details.
1075    ///
1076    /// [`run_standby`]: Dfll::run_standby
1077    #[inline]
1078    pub fn set_run_standby(&mut self, value: bool) {
1079        self.settings.run_standby = value;
1080    }
1081
1082    /// Control the [`Dfll`] behavior during idle or standby sleep modes
1083    ///
1084    /// When `true`, the `Dfll` will run in standby sleep mode, but its behavior
1085    /// can still be modified by the on-demand setting. See the datasheet for
1086    /// more details.
1087    #[inline]
1088    pub fn run_standby(mut self, value: bool) -> Self {
1089        self.set_run_standby(value);
1090        self
1091    }
1092
1093    /// Control the [`Dfll`] on-demand functionality
1094    ///
1095    /// See the documentation of [`on_demand`] for more details.
1096    ///
1097    /// [`on_demand`]: Dfll::on_demand
1098    #[inline]
1099    pub fn set_on_demand(&mut self, value: bool) {
1100        self.settings.on_demand = value;
1101    }
1102
1103    /// Control the [`Dfll`] on-demand functionality
1104    ///
1105    /// When `true`, only run the clock when requested by peripheral. If `false`
1106    /// the clock will be always active. This setting will also modify the
1107    /// behavior in standby sleep modes. See the datasheet for more details.
1108    #[inline]
1109    pub fn on_demand(mut self, value: bool) -> Self {
1110        self.set_on_demand(value);
1111        self
1112    }
1113
1114    /// Enable the [`Dfll`], so that it can be used as a clock [`Source`]
1115    ///
1116    /// As mentioned when creating a new `Dfll`, no hardware registers are
1117    /// actually modified until this call. Rather, the desired configuration is
1118    /// stored internally, and the `Dfll` is initialized and configured here
1119    /// according to the datasheet.
1120    ///
1121    /// The returned value is an [`EnabledDfll`] that can be used as a clock
1122    /// [`Source`] for other clocks.
1123    #[inline]
1124    pub fn enable(mut self) -> EnabledDfll<M> {
1125        self.token.configure(self.settings.all());
1126        self.token.enable();
1127        Enabled::new(self)
1128    }
1129}
1130
1131//==============================================================================
1132// EnabledDfll
1133//==============================================================================
1134
1135/// An [`Enabled`] [`Dfll`]
1136///
1137/// As described in the [`clock` module documentation](super), the [`Enabled`]
1138/// wrapper implements compile-time clock tree safety by tracking the number of
1139/// consumer clocks and restricting access to the underlying [`Dfll`] to prevent
1140/// modification while in use.
1141///
1142/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
1143/// the counter is assumed to be zero.
1144pub type EnabledDfll<I = NoneT, N = U0> = Enabled<Dfll<I>, N>;
1145
1146impl<M: Mode> EnabledDfll<M> {
1147    /// Disable the [`Dfll`]
1148    #[inline]
1149    pub fn disable(mut self) -> Dfll<M> {
1150        self.0.token.disable();
1151        self.0
1152    }
1153}
1154
1155impl<M, N> EnabledDfll<M, N>
1156where
1157    M: Mode,
1158    N: Default,
1159{
1160    /// Change the [`Dfll`] [`Mode`] while it remains enabled
1161    ///
1162    /// Take ownership of an [`EnabledDfll`] and convert it to use a new
1163    /// [`Mode`]. This requires an instance of the new `Mode` type and returns
1164    /// an instance of the old `Mode` type. Users can also supply a closure to
1165    /// alter the [`Dfll`] settings before they are applied. The closure takes
1166    /// `&mut Dfll<T>` as its input, so it can only modify those settings with a
1167    /// `set_` method.
1168    ///
1169    /// See the [`dfll` module documentation] for more details on why and how
1170    /// this function would be used.
1171    ///
1172    /// [`dfll` module documentation]: super::dfll#reconfiguring-an-enableddfll
1173    pub fn into_mode<T, F>(self, mode: T, f: F) -> (EnabledDfll<T, N>, M)
1174    where
1175        T: Mode,
1176        F: FnOnce(&mut Dfll<T>),
1177    {
1178        let old = M::from_settings(self.0.settings.mode);
1179        let mut dfll = Dfll::from_mode(self.0.token, mode);
1180        f(&mut dfll);
1181        let dfll = dfll.enable().0;
1182        (Enabled::new(dfll), old)
1183    }
1184
1185    /// Test whether the [`Dfll`] is ready
1186    ///
1187    /// reads OSCCTRL STATUS DFLLRDY bit
1188    #[inline]
1189    pub fn is_ready(&self) -> bool {
1190        self.0.token.is_ready()
1191    }
1192}
1193
1194//==============================================================================
1195// Source
1196//==============================================================================
1197
1198impl<M: Mode, N> Source for EnabledDfll<M, N> {
1199    type Id = DfllId;
1200
1201    #[inline]
1202    fn freq(&self) -> Hertz {
1203        self.0.freq()
1204    }
1205}