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}