Skip to content

Various issue 819 fixes #841

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 42 additions & 23 deletions hal/src/peripherals/clock/d5x/v2/dfll.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
//! # Digital Frequency Locked Loop
//!
//! The `dfll` module provides access to the 48 MHz digital frequency locked
//! loop (DFLL) within the `OSCCTRL` peripheral.
//! loop (DFLL or DFLL48M) within the `OSCCTRL` peripheral.
//!
//! ## Operation modes
//!
//! The DFLL can operate in both open-loop and closed-loop modes. In open-loop
//! mode, it uses an internal oscillator to produce an unreferenced, 48 MHz
//! output clock. While in closed-loop mode, the DFLL multiplies a low-frequency
//! input clock to yield a 48 MHz output clock. The reference clock can be
//! provided by a GCLK, through the DFLL peripheral channel clock, or it can be
//! provided by the USB start-of-frame signal.
//!
//! The DFLL is represented by the type [`Dfll<M>`], where `M` is one of three
//! [`Mode`] types. The default type is [`OpenLoop`], while the other two types,
//! [`FromPclk`] and [`FromUsb`], represent closed-loop `Mode`s with the
//! corresponding [`Reference`] clock.
//! operating [`Mode`] types. The default type is [`OpenLoop`], while the other
//! two types, [`FromPclk`] and [`FromUsb`], represent closed-loop `Mode`s with
//! the corresponding [`Reference`] clock.
//!
//! ### Open-loop mode
//! In open-loop mode, the DFLL uses an internal oscillator to produce an
//! unreferenced, 48 MHz output clock.
//!
//! Open-loop mode can only be used when the main voltage regulator is operating
//! in linear mode (the default).
//!
//! ### Closed-loop modes
//! In closed-loop mode, the DFLL multiplies a low-frequency input clock to
//! yield a 48 MHz output clock. The reference clock can be provided by a GCLK,
//! through the DFLL peripheral channel clock, or it can be provided by the USB
//! start-of-frame signal.
//!
//! ## The DFLL at power-on reset
//!
Expand Down Expand Up @@ -60,7 +66,7 @@
//! clock::v2::{clock_system_at_reset, dfll::Dfll, xosc::Xosc},
//! gpio::Pins,
//! pac::Peripherals,
//! time::U32Ext,
//! fugit::RateExtU32,
//! };
//! let mut pac = Peripherals::take().unwrap();
//! let pins = Pins::new(pac.port);
Expand All @@ -81,7 +87,7 @@
//! # clock::v2::{clock_system_at_reset, dfll::Dfll, xosc::Xosc},
//! # gpio::Pins,
//! # pac::Peripherals,
//! # time::U32Ext,
//! # fugit::RateExtU32,
//! # };
//! # let mut pac = Peripherals::take().unwrap();
//! # let pins = Pins::new(pac.port);
Expand All @@ -92,7 +98,7 @@
//! # pac.mclk,
//! # &mut pac.nvmctrl,
//! # );
//! let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.mhz()).enable();
//! let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.MHz()).enable();
//! ```
//!
//! We can then swap [`Gclk0`] from the [`EnabledDfll`] to the [`EnabledXosc`].
Expand All @@ -104,7 +110,7 @@
//! # clock::v2::{clock_system_at_reset, dfll::Dfll, xosc::Xosc},
//! # gpio::Pins,
//! # pac::Peripherals,
//! # time::U32Ext,
//! # fugit::RateExtU32,
//! # };
//! # let mut pac = Peripherals::take().unwrap();
//! # let pins = Pins::new(pac.port);
Expand All @@ -115,7 +121,7 @@
//! # pac.mclk,
//! # &mut pac.nvmctrl,
//! # );
//! # let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.mhz()).enable();
//! # let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.MHz()).enable();
//! let (gclk0, dfll, xosc0) = clocks.gclk0.swap_sources(clocks.dfll, xosc0);
//! let token_dfll = dfll.disable().free();
//! ```
Expand All @@ -131,7 +137,7 @@
//! # clock::v2::{clock_system_at_reset, dfll::Dfll, pclk::Pclk, xosc::Xosc},
//! # gpio::Pins,
//! # pac::Peripherals,
//! # time::U32Ext,
//! # fugit::RateExtU32,
//! # };
//! # let mut pac = Peripherals::take().unwrap();
//! # let pins = Pins::new(pac.port);
Expand All @@ -142,7 +148,7 @@
//! # pac.mclk,
//! # &mut pac.nvmctrl,
//! # );
//! # let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.mhz()).enable();
//! # let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.MHz()).enable();
//! # let (gclk0, dfll, xosc0) = clocks.gclk0.swap_sources(clocks.dfll, xosc0);
//! # let token_dfll = dfll.disable().free();
//! let (pclk_dfll, gclk0) = Pclk::enable(tokens.pclks.dfll, gclk0);
Expand All @@ -160,7 +166,7 @@
//! clock::v2::{clock_system_at_reset, dfll::Dfll, pclk::Pclk, xosc::Xosc},
//! gpio::Pins,
//! pac::Peripherals,
//! time::U32Ext,
//! fugit::RateExtU32,
//! };
//! let mut pac = Peripherals::take().unwrap();
//! let pins = Pins::new(pac.port);
Expand All @@ -171,7 +177,7 @@
//! pac.mclk,
//! &mut pac.nvmctrl,
//! );
//! let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.mhz()).enable();
//! let xosc0 = Xosc::from_clock(tokens.xosc0, pins.pa14, 24.MHz()).enable();
//! let (gclk0, dfll, xosc0) = clocks.gclk0.swap_sources(clocks.dfll, xosc0);
//! let token_dfll = dfll.disable().free();
//! let (pclk_dfll, gclk0) = Pclk::enable(tokens.pclks.dfll, gclk0);
Expand All @@ -194,8 +200,8 @@
//! configuration (see the discussion on [`Id` types]).
//!
//! For this reason, we define a special [`into_mode`] function on
//! [`EnabledDfll`]. It will consume the `EnabledDfll` and transform it to use
//! a different [`Mode`].
//! [`EnabledDfll`]. It will consume the `EnabledDfll` and transform it to use a
//! different [`Mode`].
//!
//! While the [`Dfll`] constructors (i.e. [`open_loop`], [`from_pclk`], and
//! [`from_usb`]) handle the [`Mode`] type for you, [`into_mode`] is generic
Expand Down Expand Up @@ -225,7 +231,7 @@
//! },
//! gpio::Pins,
//! pac::Peripherals,
//! time::U32Ext,
//! fugit::RateExtU32,
//! };
//! let mut pac = Peripherals::take().unwrap();
//! let pins = Pins::new(pac.port);
Expand Down Expand Up @@ -382,6 +388,11 @@ impl DfllToken {
self.dfllctrla().modify(|_, w| w.enable().clear_bit());
self.wait_sync_enable();
}

#[inline]
fn is_ready(&self) -> bool {
self.oscctrl().status().read().dfllrdy().bit()
}
}

//==============================================================================
Expand Down Expand Up @@ -1170,6 +1181,14 @@ where
let dfll = dfll.enable().0;
(Enabled::new(dfll), old)
}

/// Test whether the [`Dfll`] is ready
///
/// reads OSCCTRL STATUS DFLLRDY bit
#[inline]
pub fn is_ready(&self) -> bool {
self.0.token.is_ready()
}
}

//==============================================================================
Expand Down
94 changes: 93 additions & 1 deletion hal/src/peripherals/clock/d5x/v2/dpll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,14 @@ impl<D: DpllId> DpllToken<D> {
unsafe { w.div().bits(div) };
w.refclk().variant(id.into());
w.lbypass().bit(settings.lock_bypass);
w.wuf().bit(settings.wake_up_fast)
w.wuf().bit(settings.wake_up_fast);
if let Some(cap) = settings.dco_filter {
w.dcoen().bit(true);
unsafe { w.dcofilter().bits(cap as u8); }
} else {
w.dcoen().bit(false);
}
unsafe { w.filter().bits(settings.filter as u8) }
});
// Safety: The values are masked to the correct bit width by the PAC.
// Invalid values here could produce invalid clock frequencies, but that
Expand Down Expand Up @@ -537,6 +544,69 @@ impl DpllSourceId for Xosc32kId {
// Settings
//==============================================================================

/// [`Dpll`] Proportional Integral Filter
///
/// Filter settings affect PLL stability and jitter. The datasheet suggests a
/// good compromise is automatically selected, however this API allows manual
/// selection.
#[derive(Copy, Clone)]
pub enum PiFilter {
/// PLL Bandwidth 23.2kHz, Damping Factor 0.75
Bw23p2kHzDf0p75 = 0xA,
/// PLL Bandwidth 32.8kHz, Damping Factor 0.53
Bw32p8kHzDf0p53 = 0xE,
/// PLL Bandwidth 32.8kHz, Damping Factor 1.06
Bw32p8kHzDf1p06 = 0xB,
/// PLL Bandwidth 46.4kHz, Damping Factor 0.38
Bw46p4kHzDf0p38 = 0x2,
/// PLL Bandwidth 46.4kHz, Damping Factor 0.75
Bw46p4kHzDf0p75 = 0xF,
/// PLL Bandwidth 46.4kHz, Damping Factor 1.49
Bw46p4kHzDf1p49 = 0x8,
/// PLL Bandwidth 65.6kHz, Damping Factor 0.28
Bw65p6kHzDf0p28 = 0x6,
/// PLL Bandwidth 65.6kHz, Damping Factor 0.54
Bw65p6kHzDf0p54 = 0x3,
/// PLL Bandwidth 65.6kHz, Damping Factor 1.07
Bw65p6kHzDf1p07 = 0xC,
/// PLL Bandwidth 65.6kHz, Damping Factor 2.11
Bw65p6kHzDf2p11 = 0x9,
/// PLL Bandwidth 92.7kHz, Damping Factor 0.39
Bw92p7kHzDf0p39 = 0x7,
/// PLL Bandwidth 92.7kHz, Damping Factor 0.76
Bw92p7kHzDf0p76 = 0x0,
/// PLL Bandwidth 92.7kHz, Damping Factor 1.51
Bw92p7kHzDf1p51 = 0xD,
/// PLL Bandwidth 131kHz, Damping Factor 0.56
Bw131kHzDf0p56 = 0x4,
/// PLL Bandwidth 131kHz, Damping Factor 1.08
Bw131kHzDf1p08 = 0x1,
/// PLL Bandwidth 185kHz, Damping Factor 0.79
Bw185kHzDf0p79 = 0x5,
}

/// Capacitor choice for DCO filter
#[derive(Copy, Clone)]
pub enum DcoFilter {
/// 0.5pF, Bandwidth Fn 3.21MHz
C0p5pF = 0,
/// 1pF, Bandwidth Fn 1.6MHz
C1pF = 1,
/// 1.5pF, Bandwidth Fn 1.1MHz
C1p5pF = 2,
/// 2pF, Bandwidth Fn 0.8MHz
C2pF = 3,
/// 2.5pF, Bandwidth Fn 0.64MHz
C2p5pF = 4,
/// 3pF, Bandwidth Fn 0.55MHz
C3pF = 5,
/// 3.5pF, Bandwidth Fn 0.45MHz
C3p5pF = 6,
/// 4pF, Bandwidth Fn 0.4MHz
C4pF = 7,
}


/// [`Dpll`] settings relevant to all reference clocks
#[derive(Copy, Clone)]
struct Settings {
Expand All @@ -546,6 +616,8 @@ struct Settings {
wake_up_fast: bool,
on_demand: bool,
run_standby: bool,
filter: PiFilter,
dco_filter: Option<DcoFilter>,
}

/// Store and retrieve [`Dpll`] settings for different reference clocks
Expand Down Expand Up @@ -675,6 +747,8 @@ where
wake_up_fast: false,
on_demand: true,
run_standby: false,
filter: PiFilter::Bw92p7kHzDf0p76,
dco_filter: None,
};
Self {
token,
Expand Down Expand Up @@ -871,6 +945,24 @@ where
self
}

/// Set digital PI Filter coefficients
///
/// Filter settings affect PLL stability and jitter. The datasheet suggests
/// a good compromise is automatically selected, however this API allows
/// manual selection.
#[inline]
pub fn filter(mut self, filter: PiFilter) -> Self {
self.settings.filter = filter;
self
}

/// Enable sigma-delta DAC low pass filter
#[inline]
pub fn dco_filter(mut self, capacitor: DcoFilter) -> Self {
self.settings.dco_filter = Some(capacitor);
self
}

/// Set on-demand mode
///
/// See the datasheet for complete details.
Expand Down
Loading
Loading