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

1//! # Digital Phase-Locked Loop
2//!
3//! ## Overview
4//!
5//! The `dpll` module provides access to the two digital phase-locked loops
6//! (DPLLs) within the `OSCCTRL` peripheral.
7//!
8//! A DPLL is used to multiply clock frequencies. It takes a lower-frequency
9//! input clock and produces a higher-frequency output clock. It works by taking
10//! the output clock, dividing it down to the same frequency as the input clock,
11//! comparing phase between the two signals, and locking that phase difference
12//! to zero. Consequently, the clock divider within the feedback loop sets the
13//! frequency multiplication factor.
14//!
15//! The DPLLs operate over a large range of frequencies, but their operating
16//! region is not infinite. Specifically, they can only accept input frequencies
17//! between 32 kHz and 3.2 MHz, and they can only output frequencies in the
18//! range of 96 MHz to 200 MHz.
19//!
20//! Creating and configuring a [`Dpll`] proceeds according to the principles
21//! outlined in the [`clock` module documentation]. It is best shown with an
22//! example.
23//!
24//! ## Example
25//!
26//! Suppose we start with the default clock tree after power-on reset.
27//!
28//! ```text
29//! DFLL (48 MHz)
30//! └── GCLK0 (48 MHz)
31//!     └── Master clock (48 MHz)
32//! ```
33//!
34//! We would like to transform it to a clock tree like this:
35//!
36//! ```text
37//! DFLL (48 MHz)
38//! └── GCLK1 (2 MHz)
39//!     └── DPLL (200 MHz)
40//!         └── GCLK0 (200 MHz)
41//!             └── Master clock (200 MHz)
42//! ```
43//!
44//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking
45//! structs.
46//!
47//! ```no_run
48//! use atsamd_hal::{
49//!     clock::v2::{
50//!         clock_system_at_reset,
51//!         dpll::Dpll,
52//!         gclk::{Gclk, GclkDiv16},
53//!         pclk::Pclk,
54//!     },
55//!     pac::Peripherals,
56//! };
57//! let mut pac = Peripherals::take().unwrap();
58//! let (buses, clocks, tokens) = clock_system_at_reset(
59//!     pac.oscctrl,
60//!     pac.osc32kctrl,
61//!     pac.gclk,
62//!     pac.mclk,
63//!     &mut pac.nvmctrl,
64//! );
65//! ```
66//!
67//! First, we would like to divide down the 48 MHz output of the [`Dfll`] to
68//! produce a valid input frequency for the [`Dpll`]. We start by feeding the
69//! already-[`Enabled`] [`Dfll`] to [`Gclk1`] with a [`GclkDivider`] of 24,
70//! producing a 2 MHz output frequency. This has the side effect of
71//! [`Increment`]ing the counter for [`EnabledDfll`].
72//!
73//! ```no_run
74//! # use atsamd_hal::{
75//! #     clock::v2::{
76//! #         clock_system_at_reset,
77//! #         dpll::Dpll,
78//! #         gclk::{Gclk, GclkDiv16},
79//! #         pclk::Pclk,
80//! #     },
81//! #     pac::Peripherals,
82//! # };
83//! # let mut pac = Peripherals::take().unwrap();
84//! # let (buses, clocks, tokens) = clock_system_at_reset(
85//! #     pac.oscctrl,
86//! #     pac.osc32kctrl,
87//! #     pac.gclk,
88//! #     pac.mclk,
89//! #     &mut pac.nvmctrl,
90//! # );
91//! let (gclk1, dfll) = Gclk::from_source(tokens.gclks.gclk1, clocks.dfll);
92//! let gclk1 = gclk1.div(GclkDiv16::Div(24)).enable();
93//! ```
94//!
95//! Next, we use the output of [`Gclk1`] to enable the peripheral channel clock
96//! ([`Pclk`]) for [`Dpll0`]. This [`Increment`]s the counter for
97//! [`EnabledGclk1`].
98//!
99//! ```no_run
100//! # use atsamd_hal::{
101//! #     clock::v2::{
102//! #         clock_system_at_reset,
103//! #         dpll::Dpll,
104//! #         gclk::{Gclk, GclkDiv16},
105//! #         pclk::Pclk,
106//! #     },
107//! #     pac::Peripherals,
108//! # };
109//! # let mut pac = Peripherals::take().unwrap();
110//! # let (buses, clocks, tokens) = clock_system_at_reset(
111//! #     pac.oscctrl,
112//! #     pac.osc32kctrl,
113//! #     pac.gclk,
114//! #     pac.mclk,
115//! #     &mut pac.nvmctrl,
116//! # );
117//! # let (gclk1, dfll) = Gclk::from_source(tokens.gclks.gclk1, clocks.dfll);
118//! # let gclk1 = gclk1.div(GclkDiv16::Div(24)).enable();
119//! let (pclk_dpll0, gclk1) = Pclk::enable(tokens.pclks.dpll0, gclk1);
120//! ```
121//!
122//! Now we use [`Dpll::from_pclk`], which consumes the [`Pclk`] and returns an
123//! instance of [`Dpll0`]. We use builder API functions to set the loop divider
124//! to 100 and enable the [`Dpll`]. This will multiply the 2 MHz input clock to
125//! produce a 200 MHz output clock.
126//!
127//! ```no_run
128//! # use atsamd_hal::{
129//! #     clock::v2::{
130//! #         clock_system_at_reset,
131//! #         dpll::Dpll,
132//! #         gclk::{Gclk, GclkDiv16},
133//! #         pclk::Pclk,
134//! #     },
135//! #     pac::Peripherals,
136//! # };
137//! # let mut pac = Peripherals::take().unwrap();
138//! # let (buses, clocks, tokens) = clock_system_at_reset(
139//! #     pac.oscctrl,
140//! #     pac.osc32kctrl,
141//! #     pac.gclk,
142//! #     pac.mclk,
143//! #     &mut pac.nvmctrl,
144//! # );
145//! # let (gclk1, dfll) = Gclk::from_source(tokens.gclks.gclk1, clocks.dfll);
146//! # let gclk1 = gclk1.div(GclkDiv16::Div(24)).enable();
147//! # let (pclk_dpll0, gclk1) = Pclk::enable(tokens.pclks.dpll0, gclk1);
148//! let dpll0 = Dpll::from_pclk(tokens.dpll0, pclk_dpll0)
149//!     .loop_div(100, 0)
150//!     .enable();
151//! ```
152//!
153//! There are two things to note at this point.
154//!
155//! First, the loop divider has both an integer part and a fractional part.
156//! However, users should generally avoid using fractional division, if
157//! possible, because it increases the jitter of the output clock. See the
158//! [`Dpll::loop_div`] documentation for more details.
159//!
160//! Second, because the input clock frequency and loop division factors are
161//! run-time values, the [`Dpll`] cannot verify at compile time that the input
162//! and output frequencies satisfy the requirements specified in the
163//! [overview](self#overview). Instead, these values are checked at run-time. If
164//! either frequency violates its requirement, the call to [`Dpll::enable`] will
165//! panic.
166//!
167//! Finally, we wait until the [`EnabledDpll0`] output is ready, and then we
168//! swap the [`EnabledGclk0`], which feeds the processor master clock, from the
169//! 48 MHz [`EnabledDfll`] to the 200 MHz [`EnabledDpll0`].
170//!
171//! ```no_run
172//! # use atsamd_hal::{
173//! #     clock::v2::{
174//! #         clock_system_at_reset,
175//! #         dpll::Dpll,
176//! #         gclk::{Gclk, GclkDiv16},
177//! #         pclk::Pclk,
178//! #     },
179//! #     pac::Peripherals,
180//! # };
181//! # let mut pac = Peripherals::take().unwrap();
182//! # let (buses, clocks, tokens) = clock_system_at_reset(
183//! #     pac.oscctrl,
184//! #     pac.osc32kctrl,
185//! #     pac.gclk,
186//! #     pac.mclk,
187//! #     &mut pac.nvmctrl,
188//! # );
189//! # let (gclk1, dfll) = Gclk::from_source(tokens.gclks.gclk1, clocks.dfll);
190//! # let gclk1 = gclk1.div(GclkDiv16::Div(24)).enable();
191//! # let (pclk_dpll0, gclk1) = Pclk::enable(tokens.pclks.dpll0, gclk1);
192//! # let dpll0 = Dpll::from_pclk(tokens.dpll0, pclk_dpll0)
193//! #     .loop_div(100, 0)
194//! #     .enable();
195//! while !dpll0.is_ready() {}
196//! let (gclk0, dfll, dpll0) = clocks.gclk0.swap_sources(dfll, dpll0);
197//! ```
198//!
199//! We have now achieved the disired clock tree. The complete example is
200//! provided below.
201//!
202//! ```no_run
203//! use atsamd_hal::{
204//!     clock::v2::{
205//!         clock_system_at_reset,
206//!         dpll::Dpll,
207//!         gclk::{Gclk, GclkDiv16},
208//!         pclk::Pclk,
209//!     },
210//!     pac::Peripherals,
211//! };
212//! let mut pac = Peripherals::take().unwrap();
213//! let (buses, clocks, tokens) = clock_system_at_reset(
214//!     pac.oscctrl,
215//!     pac.osc32kctrl,
216//!     pac.gclk,
217//!     pac.mclk,
218//!     &mut pac.nvmctrl,
219//! );
220//! let (gclk1, dfll) = Gclk::from_source(tokens.gclks.gclk1, clocks.dfll);
221//! let gclk1 = gclk1.div(GclkDiv16::Div(24)).enable();
222//! let (pclk_dpll0, gclk1) = Pclk::enable(tokens.pclks.dpll0, gclk1);
223//! let dpll0 = Dpll::from_pclk(tokens.dpll0, pclk_dpll0)
224//!     .loop_div(100, 0)
225//!     .enable();
226//! while !dpll0.is_ready() {}
227//! let (gclk0, dfll, dpll0) = clocks.gclk0.swap_sources(dfll, dpll0);
228//! ```
229//!
230//! [`clock` module documentation]: super
231//! [`clock_system_at_reset`]: super::clock_system_at_reset
232//! [`Dfll`]: super::dfll::Dfll
233//! [`EnabledDfll`]: super::dfll::EnabledDfll
234//! [`EnabledGclk0`]: super::gclk::EnabledGclk0
235//! [`Gclk1`]: super::gclk::Gclk1
236//! [`EnabledGclk1`]: super::gclk::EnabledGclk1
237//! [`GclkDivider`]: super::gclk::GclkDivider
238//! [`Pclk`]: super::pclk::Pclk
239
240use core::marker::PhantomData;
241
242use fugit::RateExtU32;
243use typenum::U0;
244
245use crate::pac::oscctrl;
246use crate::pac::oscctrl::dpll::{dpllstatus, dpllsyncbusy, Dpllctrla, Dpllctrlb, Dpllratio};
247
248use crate::pac::oscctrl::dpll::dpllctrlb::Refclkselect;
249
250use crate::time::Hertz;
251use crate::typelevel::{Decrement, Increment, Sealed};
252
253use super::gclk::GclkId;
254use super::pclk::{Pclk, PclkId};
255use super::xosc::{Xosc0Id, Xosc1Id, XoscId};
256use super::xosc32k::Xosc32kId;
257use super::{Enabled, Source};
258
259//==============================================================================
260// DpllToken
261//==============================================================================
262
263/// Singleton token that can be exchanged for a [`Dpll`]
264///
265/// As explained in the [`clock` module documentation](super), instances of
266/// various `Token` types can be exchanged for actual clock types. They
267/// typically represent clocks that are disabled at power-on reset.
268///
269/// [`DpllToken`]s are no different. Both [`Dpll`]s are disabled at power-on
270/// reset. To use a [`Dpll`], you must first exchange the token for an actual
271/// clock with [`Dpll::from_pclk`], [`Dpll::from_xosc`] or
272/// [`Dpll::from_xosc32k`].
273///
274/// [`DpllToken`] is generic over the [`DpllId`], where each corresponding token
275/// represents one of the two respective [`Dpll`]s.
276pub struct DpllToken<D: DpllId> {
277    dpll: PhantomData<D>,
278}
279
280impl<D: DpllId> DpllToken<D> {
281    /// Create a new instance of [`DpllToken`]
282    ///
283    /// # Safety
284    ///
285    /// Each `DpllToken`s is a singleton. There must never be two simulatenous
286    /// instances with the same [`DpllId`]. See the notes on `Token` types and
287    /// memory safety in the root of the `clock` module for more details.
288    #[inline]
289    pub(super) unsafe fn new() -> Self {
290        Self { dpll: PhantomData }
291    }
292
293    /// Access the corresponding PAC `DPLL` struct
294    #[inline]
295    fn dpll(&self) -> &oscctrl::Dpll {
296        // Safety: Each `DpllToken` only has access to a mutually exclusive set
297        // of registers for the corresponding `DpllId`, and we use a shared
298        // reference to the register block. See the notes on `Token` types and
299        // memory safety in the root of the `clock` module for more details.
300        unsafe { (*crate::pac::Oscctrl::PTR).dpll(D::NUM) }
301    }
302
303    /// Access the corresponding Dpllctrla register
304    #[inline]
305    fn ctrla(&self) -> &Dpllctrla {
306        self.dpll().dpllctrla()
307    }
308
309    /// Access the corresponding Dpllctrlb register
310    #[inline]
311    fn ctrlb(&self) -> &Dpllctrlb {
312        self.dpll().dpllctrlb()
313    }
314
315    /// Access the corresponding Dpllratio register
316    #[inline]
317    fn ratio(&self) -> &Dpllratio {
318        self.dpll().dpllratio()
319    }
320
321    /// Access the corresponding DPLLSYNCBUSY register for reading only
322    #[inline]
323    fn syncbusy(&self) -> dpllsyncbusy::R {
324        self.dpll().dpllsyncbusy().read()
325    }
326
327    /// Access the corresponding DPLLSTATUS register for reading only
328    #[inline]
329    fn status(&self) -> dpllstatus::R {
330        self.dpll().dpllstatus().read()
331    }
332
333    #[inline]
334    fn configure(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) {
335        // Convert the actual predivider to the `div` register field value
336        let div = match id {
337            DynDpllSourceId::Xosc0 | DynDpllSourceId::Xosc1 => prediv / 2 - 1,
338            _ => 0,
339        };
340        self.ctrlb().modify(|_, w| {
341            // Safety: The value is masked to the correct bit width by the PAC.
342            // An invalid value could produce an invalid clock frequency, but
343            // that does not break memory safety.
344            unsafe { w.div().bits(div) };
345            w.refclk().variant(id.into());
346            w.lbypass().bit(settings.lock_bypass);
347            w.wuf().bit(settings.wake_up_fast);
348            if let Some(cap) = settings.dco_filter {
349                w.dcoen().bit(true);
350                unsafe { w.dcofilter().bits(cap as u8); }
351            } else {
352                w.dcoen().bit(false);
353            }
354            unsafe { w.filter().bits(settings.filter as u8) }
355        });
356        // Safety: The values are masked to the correct bit width by the PAC.
357        // Invalid values here could produce invalid clock frequencies, but that
358        // does not break memory safety.
359        self.ratio().write(|w| unsafe {
360            w.ldr().bits(settings.mult - 1);
361            w.ldrfrac().bits(settings.frac)
362        });
363        while self.syncbusy().dpllratio().bit_is_set() {}
364        self.ctrla().modify(|_, w| {
365            w.ondemand().bit(settings.on_demand);
366            w.runstdby().bit(settings.run_standby)
367        });
368    }
369
370    /// Enable the [`Dpll`]
371    #[inline]
372    fn enable(&mut self) {
373        self.ctrla().modify(|_, w| w.enable().set_bit());
374        while self.syncbusy().enable().bit_is_set() {}
375    }
376
377    /// Disable the [`Dpll`]
378    #[inline]
379    fn disable(&mut self) {
380        self.ctrla().modify(|_, w| w.enable().clear_bit());
381        while self.syncbusy().enable().bit_is_set() {}
382    }
383
384    /// Check the STATUS register to see if the clock is locked
385    #[inline]
386    fn is_locked(&self) -> bool {
387        self.status().lock().bit()
388    }
389
390    /// Check the STATUS register to see if the clock is ready
391    #[inline]
392    fn is_ready(&self) -> bool {
393        self.status().clkrdy().bit()
394    }
395}
396
397//==============================================================================
398// DynDpllId
399//==============================================================================
400
401/// Value-level enum identifying one of two possible [`Dpll`]s
402///
403/// The variants of this enum identify one of the two possible digital
404/// phase-locked loops.
405///
406/// `DynDpllId` is the value-level equivalent of [`DpllId`].
407pub enum DynDpllId {
408    Dpll0,
409    Dpll1,
410}
411
412//==============================================================================
413// DpllId
414//==============================================================================
415
416/// Type-level enum identifying one of two possible [`Dpll`]s
417///
418/// The types implementing this trait, i.e. [`Dpll0Id`] and [`Dpll1Id`], are
419/// type-level variants of `DpllId`, and they identify one of the two possible
420/// digital phase-locked loops.
421///
422/// `DpllId` is the type-level equivalent of [`DynDpllId`]. See the
423/// documentation on [type-level programming] and specifically
424/// [type-level enums] for more details.
425///
426/// [type-level programming]: crate::typelevel
427/// [type-level enums]: crate::typelevel#type-level-enums
428pub trait DpllId: Sealed + PclkId {
429    /// Corresponding variant of [`DynDpllId`]
430    const DYN: DynDpllId;
431    /// Corresponding numeric index
432    const NUM: usize;
433}
434
435/// Type-level variant of [`DpllId`] representing the identity of DPLL0
436///
437/// See the documentation on [type-level programming] and specifically
438/// [type-level enums] for more details.
439///
440/// [type-level programming]: crate::typelevel
441/// [type-level enums]: crate::typelevel#type-level-enums
442pub enum Dpll0Id {}
443
444impl Sealed for Dpll0Id {}
445
446impl DpllId for Dpll0Id {
447    const DYN: DynDpllId = DynDpllId::Dpll0;
448    const NUM: usize = 0;
449}
450
451/// Type-level variant of [`DpllId`] representing the identity of DPLL1
452///
453/// See the documentation on [type-level programming] and specifically
454/// [type-level enums] for more details.
455///
456/// [type-level programming]: crate::typelevel
457/// [type-level enums]: crate::typelevel#type-level-enums
458pub enum Dpll1Id {}
459
460impl Sealed for Dpll1Id {}
461
462impl DpllId for Dpll1Id {
463    const DYN: DynDpllId = DynDpllId::Dpll1;
464    const NUM: usize = 1;
465}
466
467//==============================================================================
468// DynDpllSourceId
469//==============================================================================
470
471/// Value-level enum of possible clock sources for a [`Dpll`]
472///
473/// The variants of this enum identify one of four possible clock sources for
474/// a given [`Dpll`].
475///
476/// `DynDpllSourceId` is the value-level equivalent of [`DpllSourceId`].
477#[derive(Copy, Clone, PartialEq, Eq, Debug)]
478pub enum DynDpllSourceId {
479    /// The DPLL is driven by a [`Pclk`]
480    Pclk,
481    /// The DPLL is driven by [`Xosc0`](super::xosc::Xosc0)
482    Xosc0,
483    /// The DPLL is driven by [`Xosc1`](super::xosc::Xosc1)
484    Xosc1,
485    /// The DPLL is driven by [`Xosc32k`](super::xosc32k::Xosc32k)
486    Xosc32k,
487}
488
489impl From<DynDpllSourceId> for Refclkselect {
490    fn from(source: DynDpllSourceId) -> Self {
491        match source {
492            DynDpllSourceId::Pclk => Refclkselect::Gclk,
493            DynDpllSourceId::Xosc0 => Refclkselect::Xosc0,
494            DynDpllSourceId::Xosc1 => Refclkselect::Xosc1,
495            DynDpllSourceId::Xosc32k => Refclkselect::Xosc32,
496        }
497    }
498}
499
500//==============================================================================
501// DpllSourceId
502//==============================================================================
503
504/// Type-level enum of possible clock [`Source`]s for a [`Dpll`]
505///
506/// The types implementing this trait are type-level variants of `DpllSourceId`,
507/// and they identify one of four possible clock [`Source`]s for a given
508/// [`Dpll`]. All implementers of this trait are `Id` types, which are described
509/// in more detail in the [`clock` module documentation](super).
510///
511/// `DpllSourceId` is the type-level equivalent of [`DynDpllSourceId`]. See the
512/// documentation on [type-level programming] and specifically
513/// [type-level enums] for more details.
514///
515/// [type-level programming]: crate::typelevel
516/// [type-level enums]: crate::typelevel#type-level-enums
517pub trait DpllSourceId {
518    /// Corresponding variant of [`DynDpllSourceId`]
519    const DYN: DynDpllSourceId;
520
521    /// Reference-specific settings type
522    #[doc(hidden)]
523    type Reference<D: DpllId>: settings::Reference;
524}
525
526impl<G: GclkId> DpllSourceId for G {
527    const DYN: DynDpllSourceId = DynDpllSourceId::Pclk;
528    type Reference<D: DpllId> = settings::Pclk<D, G>;
529}
530impl DpllSourceId for Xosc0Id {
531    const DYN: DynDpllSourceId = DynDpllSourceId::Xosc0;
532    type Reference<D: DpllId> = settings::Xosc;
533}
534impl DpllSourceId for Xosc1Id {
535    const DYN: DynDpllSourceId = DynDpllSourceId::Xosc1;
536    type Reference<D: DpllId> = settings::Xosc;
537}
538impl DpllSourceId for Xosc32kId {
539    const DYN: DynDpllSourceId = DynDpllSourceId::Xosc32k;
540    type Reference<D: DpllId> = settings::Xosc32k;
541}
542
543//==============================================================================
544// Settings
545//==============================================================================
546
547/// [`Dpll`] Proportional Integral Filter
548///
549/// Filter settings affect PLL stability and jitter.  The datasheet suggests a
550/// good compromise is automatically selected, however this API allows manual
551/// selection.
552#[derive(Copy, Clone)]
553pub enum PiFilter {
554    /// PLL Bandwidth 23.2kHz, Damping Factor 0.75
555    Bw23p2kHzDf0p75 = 0xA,
556    /// PLL Bandwidth 32.8kHz, Damping Factor 0.53
557    Bw32p8kHzDf0p53 = 0xE,
558    /// PLL Bandwidth 32.8kHz, Damping Factor 1.06
559    Bw32p8kHzDf1p06 = 0xB,
560    /// PLL Bandwidth 46.4kHz, Damping Factor 0.38
561    Bw46p4kHzDf0p38 = 0x2,
562    /// PLL Bandwidth 46.4kHz, Damping Factor 0.75
563    Bw46p4kHzDf0p75 = 0xF,
564    /// PLL Bandwidth 46.4kHz, Damping Factor 1.49
565    Bw46p4kHzDf1p49 = 0x8,
566    /// PLL Bandwidth 65.6kHz, Damping Factor 0.28
567    Bw65p6kHzDf0p28 = 0x6,
568    /// PLL Bandwidth 65.6kHz, Damping Factor 0.54
569    Bw65p6kHzDf0p54 = 0x3,
570    /// PLL Bandwidth 65.6kHz, Damping Factor 1.07
571    Bw65p6kHzDf1p07 = 0xC,
572    /// PLL Bandwidth 65.6kHz, Damping Factor 2.11
573    Bw65p6kHzDf2p11 = 0x9,
574    /// PLL Bandwidth 92.7kHz, Damping Factor 0.39
575    Bw92p7kHzDf0p39 = 0x7,
576    /// PLL Bandwidth 92.7kHz, Damping Factor 0.76
577    Bw92p7kHzDf0p76 = 0x0,
578    /// PLL Bandwidth 92.7kHz, Damping Factor 1.51
579    Bw92p7kHzDf1p51 = 0xD,
580    /// PLL Bandwidth 131kHz, Damping Factor 0.56
581    Bw131kHzDf0p56 = 0x4,
582    /// PLL Bandwidth 131kHz, Damping Factor 1.08
583    Bw131kHzDf1p08 = 0x1,
584    /// PLL Bandwidth 185kHz, Damping Factor 0.79
585    Bw185kHzDf0p79 = 0x5,
586}
587
588/// Capacitor choice for DCO filter
589#[derive(Copy, Clone)]
590pub enum DcoFilter {
591    /// 0.5pF, Bandwidth Fn 3.21MHz
592    C0p5pF = 0,
593    /// 1pF, Bandwidth Fn 1.6MHz
594    C1pF = 1,
595    /// 1.5pF, Bandwidth Fn 1.1MHz
596    C1p5pF = 2,
597    /// 2pF, Bandwidth Fn 0.8MHz
598    C2pF = 3,
599    /// 2.5pF, Bandwidth Fn 0.64MHz
600    C2p5pF = 4,
601    /// 3pF, Bandwidth Fn 0.55MHz
602    C3pF = 5,
603    /// 3.5pF, Bandwidth Fn 0.45MHz
604    C3p5pF = 6,
605    /// 4pF, Bandwidth Fn 0.4MHz
606    C4pF = 7,
607}
608
609
610/// [`Dpll`] settings relevant to all reference clocks
611#[derive(Copy, Clone)]
612struct Settings {
613    mult: u16,
614    frac: u8,
615    lock_bypass: bool,
616    wake_up_fast: bool,
617    on_demand: bool,
618    run_standby: bool,
619    filter: PiFilter,
620    dco_filter: Option<DcoFilter>,
621}
622
623/// Store and retrieve [`Dpll`] settings for different reference clocks
624mod settings {
625    use super::super::pclk;
626    use super::RateExtU32;
627    use super::{DpllId, GclkId, Hertz};
628
629    /// [`Dpll`] settings when referenced to a [`Pclk`]
630    ///
631    /// [`Dpll`]: super::Dpll
632    /// [`Pclk`]: pclk::Pclk
633    pub struct Pclk<D: DpllId, G: GclkId> {
634        pub pclk: pclk::Pclk<D, G>,
635    }
636
637    /// [`Dpll`] settings when referenced to an [`Xosc`]
638    ///
639    /// [`Dpll`]: super::Dpll
640    /// [`Xosc`]: super::super::xosc::Xosc
641    pub struct Xosc {
642        pub freq: Hertz,
643        pub prediv: u16,
644    }
645
646    /// [`Dpll`] settings when referenced to an [`Xosc32k`]
647    ///
648    /// [`Dpll`]: super::Dpll
649    /// [`Xosc32k`]: super::super::xosc32k::Xosc32k
650    pub struct Xosc32k;
651
652    /// Generic interface for the frequency and predivider of a reference clock
653    pub trait Reference {
654        fn freq(&self) -> Hertz;
655        fn prediv(&self) -> u16;
656    }
657
658    impl<D: DpllId, G: GclkId> Reference for Pclk<D, G> {
659        #[inline]
660        fn freq(&self) -> Hertz {
661            self.pclk.freq()
662        }
663        #[inline]
664        fn prediv(&self) -> u16 {
665            1
666        }
667    }
668
669    impl Reference for Xosc {
670        #[inline]
671        fn freq(&self) -> Hertz {
672            self.freq
673        }
674        #[inline]
675        fn prediv(&self) -> u16 {
676            self.prediv
677        }
678    }
679
680    impl Reference for Xosc32k {
681        #[inline]
682        fn freq(&self) -> Hertz {
683            32_768.Hz()
684        }
685        #[inline]
686        fn prediv(&self) -> u16 {
687            1
688        }
689    }
690}
691
692//==============================================================================
693// Dpll
694//==============================================================================
695
696/// Digital phase-locked loop used to multiply clock frequencies
697///
698/// A DPLL is used to multiply clock frequencies, taking a lower-frequency input
699/// clock and producing a higher-frequency output clock.
700///
701/// The type parameter `D` is a [`DpllId`] that determines which of the two
702/// instances this `Dpll` represents ([`Dpll0`] or [`Dpll1`]). The type
703/// parameter `I` represents the `Id` type for the clock [`Source`] driving this
704/// `Dpll`. It must be one of the valid [`DpllSourceId`]s. See the
705/// [`clock` module documentation](super) for more detail on
706/// [`Id` types](super#id-types).
707///
708/// On its own, an instance of `Dpll` does not represent an enabled DPLL.
709/// Instead, it must first be wrapped with [`Enabled`], which implements
710/// compile-time safety of the clock tree.
711///
712/// Because the terminal call to [`enable`] consumes the `Dpll` and returns an
713/// [`EnabledDpll`], the remaining API uses the builder pattern, where each
714/// method takes and returns `self` by value, allowing them to be easily
715/// chained.
716///
717/// See the [module-level documentation](self) for an example of creating,
718/// configuring and using a `Dpll`.
719///
720/// [`enable`]: Dpll::enable
721pub struct Dpll<D, I>
722where
723    D: DpllId,
724    I: DpllSourceId,
725{
726    token: DpllToken<D>,
727    reference: I::Reference<D>,
728    settings: Settings,
729}
730
731/// Type alias for the corresponding [`Dpll`]
732pub type Dpll0<M> = Dpll<Dpll0Id, M>;
733
734/// Type alias for the corresponding [`Dpll`]
735pub type Dpll1<M> = Dpll<Dpll1Id, M>;
736
737impl<D, I> Dpll<D, I>
738where
739    D: DpllId,
740    I: DpllSourceId,
741{
742    fn new(token: DpllToken<D>, reference: I::Reference<D>) -> Self {
743        let settings = Settings {
744            mult: 1,
745            frac: 0,
746            lock_bypass: false,
747            wake_up_fast: false,
748            on_demand: true,
749            run_standby: false,
750            filter: PiFilter::Bw92p7kHzDf0p76,
751            dco_filter: None,
752        };
753        Self {
754            token,
755            reference,
756            settings,
757        }
758    }
759}
760
761impl<D, G> Dpll<D, G>
762where
763    D: DpllId,
764    G: GclkId,
765{
766    /// Create a [`Dpll`] from a [`Pclk`]
767    ///
768    /// Creating a [`Dpll`] does not modify any of the hardware registers. It
769    /// only creates a struct to track the DPLL configuration.
770    ///
771    /// The configuration data is stored until the user calls [`enable`]. At
772    /// that point, all of the registers are written according to the
773    /// initialization procedures specified in the datasheet, and an
774    /// [`EnabledDpll`] is returned. The `Dpll` is not active or useful until
775    /// that point.
776    ///
777    /// [`enable`]: Dpll::enable
778    #[inline]
779    pub fn from_pclk(token: DpllToken<D>, pclk: Pclk<D, G>) -> Self {
780        let reference = settings::Pclk { pclk };
781        Dpll::new(token, reference)
782    }
783
784    /// Consume the [`Dpll`], release the [`DpllToken`], and return the [`Pclk`]
785    #[inline]
786    pub fn free_pclk(self) -> (DpllToken<D>, Pclk<D, G>) {
787        (self.token, self.reference.pclk)
788    }
789}
790
791impl<D, X> Dpll<D, X>
792where
793    D: DpllId,
794    X: XoscId + DpllSourceId<Reference<D> = settings::Xosc>,
795{
796    /// Create a [`Dpll`] from an [`Xosc`]
797    ///
798    /// Note that, when the [`Dpll`] is driven by an [`Xosc`], there is an extra
799    /// clock divider between the `Xosc` output and the input to the actual
800    /// phase-locked loop. This allows the [`Xosc`] frequency to be above the
801    /// maximum DPLL input frequency of 3.2 MHz.
802    ///
803    /// The `Xosc` pre-divider can be set to any *even* value in the range
804    /// `[2, 4096]`. It defaults to the minimum value of 2, but it can be
805    /// changed with the [`Dpll::prediv`] method.
806    ///
807    /// Creating a [`Dpll`] does not modify any of the hardware registers. It
808    /// only creates a struct to track the DPLL configuration and [`Increment`]s
809    /// the [`Source`] [`Enabled`] counter.
810    ///
811    /// The configuration data is stored until the user calls [`enable`]. At
812    /// that point, all of the registers are written according to the
813    /// initialization procedures specified in the datasheet, and an
814    /// [`EnabledDpll`] is returned. The `Dpll` is not active or useful until
815    /// that point.
816    ///
817    /// [`Xosc`]: super::xosc::Xosc
818    /// [`enable`]: Dpll::enable
819    #[inline]
820    pub fn from_xosc<S>(token: DpllToken<D>, source: S) -> (Self, S::Inc)
821    where
822        S: Source<Id = X> + Increment,
823    {
824        let reference = settings::Xosc {
825            freq: source.freq(),
826            prediv: 2,
827        };
828        let dpll = Dpll::new(token, reference);
829        (dpll, source.inc())
830    }
831
832    /// Consume the [`Dpll`], release the [`DpllToken`], and [`Decrement`] the
833    /// [`EnabledXosc`] consumer count
834    ///
835    /// [`EnabledXosc`]: super::xosc::EnabledXosc
836    #[inline]
837    pub fn free_xosc<S>(self, source: S) -> (DpllToken<D>, S::Dec)
838    where
839        S: Source<Id = X> + Decrement,
840    {
841        (self.token, source.dec())
842    }
843
844    /// Set the [`Xosc`] pre-division factor
845    ///
846    /// The [`Xosc`] output frequency is divided down before it enters the
847    /// actual phase-locked loop. This function will panic if the pre-division
848    /// factor is not an *even* number in the range `[2, 4096]`.
849    ///
850    /// [`Xosc`]: super::xosc::Xosc
851    #[inline]
852    pub fn prediv(mut self, prediv: u16) -> Self {
853        if prediv % 2 != 0 || prediv < 2 || prediv > 4096 {
854            panic!("DPLL prediv must be an even integer in the range [2, 4096]")
855        }
856        self.reference.prediv = prediv;
857        self
858    }
859}
860
861impl<D: DpllId> Dpll<D, Xosc32kId> {
862    /// Create a [`Dpll`] from an [`Xosc32k`]
863    ///
864    /// Creating a [`Dpll`] does not modify any of the hardware registers. It
865    /// only creates a struct to track the DPLL configuration and [`Increment`]s
866    /// the [`Source`] [`Enabled`] counter.
867    ///
868    /// The configuration data is stored until the user calls [`enable`]. At
869    /// that point, all of the registers are written according to the
870    /// initialization procedures specified in the datasheet, and an
871    /// [`EnabledDpll`] is returned. The `Dpll` is not active or useful until
872    /// that point.
873    ///
874    /// [`Xosc32k`]: super::xosc32k::Xosc32k
875    /// [`enable`]: Dpll::enable
876    #[inline]
877    pub fn from_xosc32k<S>(token: DpllToken<D>, source: S) -> (Self, S::Inc)
878    where
879        S: Source<Id = Xosc32kId> + Increment,
880    {
881        let dpll = Dpll::new(token, settings::Xosc32k);
882        (dpll, source.inc())
883    }
884
885    /// Consume the [`Dpll`], release the [`DpllToken`], and [`Decrement`] the
886    /// [`EnabledXosc32k`] consumer count
887    ///
888    /// [`EnabledXosc32k`]: super::xosc32k::EnabledXosc32k
889    /// d`] consumer count
890    pub fn free_xosc32k<S>(self, source: S) -> (DpllToken<D>, S::Dec)
891    where
892        S: Source<Id = Xosc32kId> + Decrement,
893    {
894        (self.token, source.dec())
895    }
896}
897
898impl<D, I> Dpll<D, I>
899where
900    D: DpllId,
901    I: DpllSourceId,
902{
903    /// Set the [`Dpll`] loop divider, which is also the frequency
904    /// multiplication factor
905    ///
906    /// The inputs to this function are the natural integer and fractional
907    /// parts of the division factor, i.e. the division factor is:
908    ///
909    /// ```text
910    /// int + frac / 32
911    /// ```
912    ///
913    /// This function will confirm that the `int` and `frac` values convert to
914    /// valid `LDR` and `LDRFRAC` register fields, panicking otherwise.
915    #[inline]
916    pub fn loop_div(mut self, int: u16, frac: u8) -> Self {
917        if int < 1 || int > 0x2000 {
918            panic!("Invalid integer part of the DPLL loop divider")
919        }
920        if frac > 31 {
921            panic!("Invalid fractional part of the DPLL loop divider")
922        }
923        self.settings.mult = int;
924        self.settings.frac = frac;
925        self
926    }
927
928    /// Bypass the [`Dpll`] lock
929    ///
930    /// If `true`, the [`Dpll`] will output its clock regardless of whether it
931    /// is locked.
932    #[inline]
933    pub fn lock_bypass(mut self, bypass: bool) -> Self {
934        self.settings.lock_bypass = bypass;
935        self
936    }
937
938    /// Output the [`Dpll`] clock immediately, without waiting for various
939    /// conditions
940    ///
941    /// See the datasheet for complete details.
942    #[inline]
943    pub fn wake_up_fast(mut self, wuf: bool) -> Self {
944        self.settings.wake_up_fast = wuf;
945        self
946    }
947
948    /// Set digital PI Filter coefficients
949    ///
950    /// Filter settings affect PLL stability and jitter.  The datasheet suggests
951    /// a good compromise is automatically selected, however this API allows
952    /// manual selection.
953    #[inline]
954    pub fn filter(mut self, filter: PiFilter) -> Self {
955        self.settings.filter = filter;
956        self
957    }
958
959    /// Enable sigma-delta DAC low pass filter
960    #[inline]
961    pub fn dco_filter(mut self, capacitor: DcoFilter) -> Self {
962        self.settings.dco_filter = Some(capacitor);
963        self
964    }
965
966    /// Set on-demand mode
967    ///
968    /// See the datasheet for complete details.
969    #[inline]
970    pub fn on_demand(mut self, on_demand: bool) -> Self {
971        self.settings.on_demand = on_demand;
972        self
973    }
974
975    /// Set run-in-standby mode
976    ///
977    /// See the datasheet for complete details.
978    #[inline]
979    pub fn run_standby(mut self, run_standby: bool) -> Self {
980        self.settings.run_standby = run_standby;
981        self
982    }
983
984    #[inline]
985    fn input_freq(&self) -> Hertz {
986        use settings::Reference;
987        self.reference.freq() / self.reference.prediv() as u32
988    }
989
990    #[inline]
991    fn output_freq(&self) -> Hertz {
992        self.input_freq() * (self.settings.mult as u32 + self.settings.frac as u32 / 32)
993    }
994
995    /// Return the output frequency of the [`Dpll`]
996    #[inline]
997    pub fn freq(&self) -> Hertz {
998        self.output_freq()
999    }
1000
1001    /// Enable the [`Dpll`], so that it can be used as a clock [`Source`]
1002    ///
1003    /// As mentioned when creating a new `Dpll`, no hardware registers are
1004    /// actually modified until this call. Rather, the desired configuration is
1005    /// stored internally, and the [`Dpll`] is initialized and configured here
1006    /// according to the datasheet.
1007    ///
1008    /// The returned value is an [`EnabledDpll`] that can be used as a clock
1009    /// [`Source`] for other clocks.
1010    ///
1011    /// # Panics
1012    ///
1013    /// This function will also check that the input and output clock
1014    /// frequencies fall within the valid ranges specified in the datasheet.
1015    /// Specifically, the input frequency must be between 32 kHz and 3.2 MHz,
1016    /// while the output frequency must be between 96 MHz and 200 MHz. If either
1017    /// frequency is invalid, this call will panic.
1018    #[inline]
1019    pub fn enable(self) -> EnabledDpll<D, I> {
1020        let input_freq = self.input_freq().to_Hz();
1021        let output_freq = self.output_freq().to_Hz();
1022        if input_freq < 32_000 || input_freq > 3_200_000 {
1023            panic!("Invalid DPLL input frequency");
1024        }
1025        if output_freq < 96_000_000 || output_freq > 200_000_000 {
1026            panic!("Invalid DPLL output frequency");
1027        }
1028        self.enable_unchecked()
1029    }
1030
1031    /// Enable the [`Dpll`] without validating the input & output frequencies
1032    ///
1033    /// This is equivalent to calling [`Dpll::enable`] but without the checks on
1034    /// input and output frequencies. Using frequencies outside the ranges
1035    /// specified in the datasheet may not work and could cause clocking
1036    /// problems.
1037    #[inline]
1038    pub fn enable_unchecked(mut self) -> EnabledDpll<D, I> {
1039        use settings::Reference;
1040        let prediv = self.reference.prediv();
1041        self.token.configure(I::DYN, self.settings, prediv);
1042        self.token.enable();
1043        Enabled::new(self)
1044    }
1045}
1046
1047//==============================================================================
1048// EnabledDpll
1049//==============================================================================
1050
1051/// An [`Enabled`] [`Dpll`]
1052///
1053/// As described in the [`clock` module documentation](super), the [`Enabled`]
1054/// wrapper implements compile-time clock tree safety by tracking the number of
1055/// consumer clocks and restricting access to the underlying [`Dpll`] to prevent
1056/// modification while in use.
1057///
1058/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified,
1059/// the counter is assumed to be zero.
1060pub type EnabledDpll<D, I, N = U0> = Enabled<Dpll<D, I>, N>;
1061
1062/// Type alias for the corresponding [`EnabledDpll`]
1063pub type EnabledDpll0<I, N = U0> = EnabledDpll<Dpll0Id, I, N>;
1064
1065/// Type alias for the corresponding [`EnabledDpll`]
1066pub type EnabledDpll1<I, N = U0> = EnabledDpll<Dpll1Id, I, N>;
1067
1068impl<D, I> EnabledDpll<D, I>
1069where
1070    D: DpllId,
1071    I: DpllSourceId,
1072{
1073    /// Disable the [`Dpll`]
1074    ///
1075    /// This method is only implemented for `N = U0`, which means the clock can
1076    /// only be disabled when no other clocks consume this [`Dpll`].
1077    #[inline]
1078    pub fn disable(mut self) -> Dpll<D, I> {
1079        self.0.token.disable();
1080        self.0
1081    }
1082}
1083
1084impl<D, I, N> EnabledDpll<D, I, N>
1085where
1086    D: DpllId,
1087    I: DpllSourceId,
1088{
1089    /// Test whether the [`Dpll`] is locked
1090    #[inline]
1091    pub fn is_locked(&self) -> bool {
1092        self.0.token.is_locked()
1093    }
1094
1095    /// Test whether the [`Dpll`] is ready
1096    #[inline]
1097    pub fn is_ready(&self) -> bool {
1098        self.0.token.is_ready()
1099    }
1100}
1101
1102//==============================================================================
1103// Source
1104//==============================================================================
1105
1106impl<D, I, N> Source for EnabledDpll<D, I, N>
1107where
1108    D: DpllId,
1109    I: DpllSourceId,
1110{
1111    type Id = D;
1112
1113    #[inline]
1114    fn freq(&self) -> Hertz {
1115        self.0.freq()
1116    }
1117}