From 2efe73c74f83632ef6bc76c0206b8388b77ad99c Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 10:16:21 +1200 Subject: [PATCH 01/75] Merge thumbv6m and thumbv7em clock modules Manually replicated from Bradley Harden's work, rebased as 4b94fb0aefdfcc2c6a70b2a183269ef66edfba4d --- hal/src/clock.rs | 16 ++++++++++++++++ .../clock/d11.rs => clock/v1_thumbv6m.rs} | 4 ++-- .../clock/d5x/v1.rs => clock/v1_thumbv7em.rs} | 2 +- hal/src/{peripherals/clock/d5x => clock}/v2.rs | 0 .../{peripherals/clock/d5x => clock}/v2/ahb.rs | 0 .../{peripherals/clock/d5x => clock}/v2/apb.rs | 0 .../{peripherals/clock/d5x => clock}/v2/dfll.rs | 0 .../{peripherals/clock/d5x => clock}/v2/dpll.rs | 0 .../{peripherals/clock/d5x => clock}/v2/gclk.rs | 0 .../clock/d5x => clock}/v2/osculp32k.rs | 0 .../{peripherals/clock/d5x => clock}/v2/pclk.rs | 0 .../{peripherals/clock/d5x => clock}/v2/reset.rs | 0 .../clock/d5x => clock}/v2/rtcosc.rs | 6 +++--- .../{peripherals/clock/d5x => clock}/v2/types.rs | 0 .../{peripherals/clock/d5x => clock}/v2/xosc.rs | 2 +- .../clock/d5x => clock}/v2/xosc32k.rs | 4 ++-- hal/src/lib.rs | 2 ++ hal/src/peripherals/clock/d5x/mod.rs | 9 --------- hal/src/peripherals/eic.rs | 2 +- hal/src/peripherals/mod.rs | 6 ------ 20 files changed, 28 insertions(+), 25 deletions(-) create mode 100644 hal/src/clock.rs rename hal/src/{peripherals/clock/d11.rs => clock/v1_thumbv6m.rs} (99%) rename hal/src/{peripherals/clock/d5x/v1.rs => clock/v1_thumbv7em.rs} (99%) rename hal/src/{peripherals/clock/d5x => clock}/v2.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/ahb.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/apb.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/dfll.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/dpll.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/gclk.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/osculp32k.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/pclk.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/reset.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/rtcosc.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/types.rs (100%) rename hal/src/{peripherals/clock/d5x => clock}/v2/xosc.rs (99%) rename hal/src/{peripherals/clock/d5x => clock}/v2/xosc32k.rs (99%) delete mode 100644 hal/src/peripherals/clock/d5x/mod.rs diff --git a/hal/src/clock.rs b/hal/src/clock.rs new file mode 100644 index 000000000000..830b82b36470 --- /dev/null +++ b/hal/src/clock.rs @@ -0,0 +1,16 @@ +//! # Clocking API +//! +//! Users are encouraged to use [`v2`] variant of an API because of the richer +//! feature set and safety. +use atsamd_hal_macros::{hal_cfg, hal_module}; + +#[hal_module( + any("clock-d11", "clock-d21") => "clock/v1_thumbv6m.rs", + "clock-d5x" => "clock/v1_thumbv7em.rs", +)] +pub mod v1 {} + +pub use v1::*; + +#[hal_cfg("clock-d5x")] +pub mod v2; diff --git a/hal/src/peripherals/clock/d11.rs b/hal/src/clock/v1_thumbv6m.rs similarity index 99% rename from hal/src/peripherals/clock/d11.rs rename to hal/src/clock/v1_thumbv6m.rs index 0ff080c2cf17..7573da6c4d55 100644 --- a/hal/src/peripherals/clock/d11.rs +++ b/hal/src/clock/v1_thumbv6m.rs @@ -488,7 +488,7 @@ fn enable_gclk_apb(pm: &mut Pm) { /// Turn on the internal 32hkz oscillator pub fn enable_internal_32kosc(sysctrl: &mut Sysctrl) { - let calibration = super::calibration::osc32k_cal(); + let calibration = crate::calibration::osc32k_cal(); sysctrl.osc32k().write(|w| { unsafe { w.ondemand().clear_bit(); @@ -562,7 +562,7 @@ fn configure_and_enable_dfll48m(sysctrl: &mut Sysctrl, use_external_crystal: boo }); } else { // Apply calibration - let coarse = super::calibration::dfll48m_coarse_cal(); + let coarse = crate::calibration::dfll48m_coarse_cal(); let fine = 0x1ff; sysctrl.dfllval().write(|w| unsafe { diff --git a/hal/src/peripherals/clock/d5x/v1.rs b/hal/src/clock/v1_thumbv7em.rs similarity index 99% rename from hal/src/peripherals/clock/d5x/v1.rs rename to hal/src/clock/v1_thumbv7em.rs index a04166d20068..b6369fa3a429 100644 --- a/hal/src/peripherals/clock/d5x/v1.rs +++ b/hal/src/clock/v1_thumbv7em.rs @@ -15,7 +15,7 @@ use crate::clock::v2::pclk::{Pclk, PclkSourceId, ids::*}; use crate::pac::gclk::genctrl::Srcselect::*; use crate::pac::gclk::pchctrl::Genselect::*; use crate::pac::{self, Gclk, Mclk, Nvmctrl, Osc32kctrl, Oscctrl}; -use crate::sercom::*; +// use crate::sercom::*; // TODO why does this warn now but not before? use crate::time::Hertz; pub type ClockGenId = pac::gclk::pchctrl::Genselect; diff --git a/hal/src/peripherals/clock/d5x/v2.rs b/hal/src/clock/v2.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2.rs rename to hal/src/clock/v2.rs diff --git a/hal/src/peripherals/clock/d5x/v2/ahb.rs b/hal/src/clock/v2/ahb.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/ahb.rs rename to hal/src/clock/v2/ahb.rs diff --git a/hal/src/peripherals/clock/d5x/v2/apb.rs b/hal/src/clock/v2/apb.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/apb.rs rename to hal/src/clock/v2/apb.rs diff --git a/hal/src/peripherals/clock/d5x/v2/dfll.rs b/hal/src/clock/v2/dfll.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/dfll.rs rename to hal/src/clock/v2/dfll.rs diff --git a/hal/src/peripherals/clock/d5x/v2/dpll.rs b/hal/src/clock/v2/dpll.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/dpll.rs rename to hal/src/clock/v2/dpll.rs diff --git a/hal/src/peripherals/clock/d5x/v2/gclk.rs b/hal/src/clock/v2/gclk.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/gclk.rs rename to hal/src/clock/v2/gclk.rs diff --git a/hal/src/peripherals/clock/d5x/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/osculp32k.rs rename to hal/src/clock/v2/osculp32k.rs diff --git a/hal/src/peripherals/clock/d5x/v2/pclk.rs b/hal/src/clock/v2/pclk.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/pclk.rs rename to hal/src/clock/v2/pclk.rs diff --git a/hal/src/peripherals/clock/d5x/v2/reset.rs b/hal/src/clock/v2/reset.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/reset.rs rename to hal/src/clock/v2/reset.rs diff --git a/hal/src/peripherals/clock/d5x/v2/rtcosc.rs b/hal/src/clock/v2/rtcosc.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/rtcosc.rs rename to hal/src/clock/v2/rtcosc.rs index 7edd596ea319..a13b7376b678 100644 --- a/hal/src/peripherals/clock/d5x/v2/rtcosc.rs +++ b/hal/src/clock/v2/rtcosc.rs @@ -93,16 +93,16 @@ use core::marker::PhantomData; -use crate::pac::osc32kctrl::rtcctrl::Rtcselselect; -use crate::pac::osc32kctrl::Rtcctrl; use crate::pac::Osc32kctrl; +use crate::pac::osc32kctrl::Rtcctrl; +use crate::pac::osc32kctrl::rtcctrl::Rtcselselect; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment}; +use super::Source; use super::osculp32k::{OscUlp1kId, OscUlp32kId}; use super::xosc32k::{Xosc1kId, Xosc32kId}; -use super::Source; //============================================================================== // RtcOscToken diff --git a/hal/src/peripherals/clock/d5x/v2/types.rs b/hal/src/clock/v2/types.rs similarity index 100% rename from hal/src/peripherals/clock/d5x/v2/types.rs rename to hal/src/clock/v2/types.rs diff --git a/hal/src/peripherals/clock/d5x/v2/xosc.rs b/hal/src/clock/v2/xosc.rs similarity index 99% rename from hal/src/peripherals/clock/d5x/v2/xosc.rs rename to hal/src/clock/v2/xosc.rs index 2169636ca691..13290f988085 100644 --- a/hal/src/peripherals/clock/d5x/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -210,7 +210,7 @@ use typenum::U0; use crate::pac::oscctrl::{self, Xoscctrl}; -use crate::gpio::{FloatingDisabled, Pin, PinId, PA14, PA15, PB22, PB23}; +use crate::gpio::{FloatingDisabled, PA14, PA15, PB22, PB23, Pin, PinId}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; diff --git a/hal/src/peripherals/clock/d5x/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs similarity index 99% rename from hal/src/peripherals/clock/d5x/v2/xosc32k.rs rename to hal/src/clock/v2/xosc32k.rs index 838d02b1cbf8..e33c983b3578 100644 --- a/hal/src/peripherals/clock/d5x/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -345,9 +345,9 @@ use fugit::RateExtU32; use typenum::U0; use crate::pac::osc32kctrl::xosc32k::{Cgmselect, Startupselect}; -use crate::pac::osc32kctrl::{self, status, Cfdctrl}; +use crate::pac::osc32kctrl::{self, Cfdctrl, status}; -use crate::gpio::{FloatingDisabled, Pin, PA00, PA01}; +use crate::gpio::{FloatingDisabled, PA00, PA01, Pin}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; diff --git a/hal/src/lib.rs b/hal/src/lib.rs index e20f6b5025d1..4bf3008b7bba 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -74,6 +74,8 @@ macro_rules! dbgprint { #[cfg(feature = "async")] pub mod async_hal; +#[cfg(feature = "device")] +pub mod clock; #[cfg(feature = "device")] pub mod delay; #[cfg(feature = "device")] diff --git a/hal/src/peripherals/clock/d5x/mod.rs b/hal/src/peripherals/clock/d5x/mod.rs deleted file mode 100644 index ce090b2fd4b5..000000000000 --- a/hal/src/peripherals/clock/d5x/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! # Clocking API -//! -//! Users are encouraged to use [`v2`] variant of an API because of the richer -//! feature set and safety. - -pub mod v1; -pub use v1::*; - -pub mod v2; diff --git a/hal/src/peripherals/eic.rs b/hal/src/peripherals/eic.rs index e3d4f2fe829d..b959d9e74c38 100644 --- a/hal/src/peripherals/eic.rs +++ b/hal/src/peripherals/eic.rs @@ -83,7 +83,7 @@ mod impls {} pub use impls::async_api::*; #[hal_cfg("eic-d5x")] -use super::clock::v2::{self, gclk::GclkId, osculp32k::OscUlp32kId, pclk::Pclk, rtcosc::RtcOsc}; +use crate::clock::v2::{self, gclk::GclkId, osculp32k::OscUlp32kId, pclk::Pclk, rtcosc::RtcOsc}; pub type Sense = pac::eic::config::Sense0select; diff --git a/hal/src/peripherals/mod.rs b/hal/src/peripherals/mod.rs index 78eb4048a08c..45259be902ac 100644 --- a/hal/src/peripherals/mod.rs +++ b/hal/src/peripherals/mod.rs @@ -31,12 +31,6 @@ pub mod usb {} )] pub mod pwm {} -#[hal_module( - any("clock-d11", "clock-d21") => "clock/d11.rs", - "clock-d5x" => "clock/d5x/mod.rs", -)] -pub mod clock {} - #[hal_module("aes")] pub mod aes {} From 6c2a9bc2c2bf56c82353d11820af91777f265c76 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 12:20:41 +1200 Subject: [PATCH 02/75] TODO Hack to compile, nightly only --- hal/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 4bf3008b7bba..d6b11ea42b72 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,4 +1,6 @@ #![no_std] +// TODO Allows using hal_cfg to gate clock v2 for thumbv6, nightly only +#![feature(proc_macro_hygiene)] pub use embedded_hal_1 as ehal; use embedded_hal_02 as ehal_02; From ceb1aca048ca4407000f737eef509a708c71b6a9 Mon Sep 17 00:00:00 2001 From: Bradley Harden Date: Wed, 28 Dec 2022 15:29:18 -0500 Subject: [PATCH 03/75] Work towards clock v2 GCLK and PCLK for thumbv6 This was the first "stash" in Bradley Harden's clock_v2_thumbv6m branch --- hal/src/clock/v2/gclk.rs | 274 +++++++++++++++++++++++++-------------- hal/src/clock/v2/pclk.rs | 65 +++++++--- 2 files changed, 226 insertions(+), 113 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 18a28eddf99e..4ca2372a3e30 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -335,6 +335,7 @@ //! [`Pins`]: crate::gpio::Pins //! [`Sercom0`]: crate::sercom::Sercom0 +use atsamd_hal_macros::hal_cfg; use core::cmp::max; use core::marker::PhantomData; @@ -344,19 +345,20 @@ use typenum::{U0, U1}; use crate::pac; use crate::pac::Nvmctrl; -use crate::pac::gclk::genctrl::Divselselect; -use crate::gpio::{self, AlternateM, AnyPin, Pin, PinId}; +use crate::gpio::{self, AlternateH, AnyPin, Pin, PinId}; use crate::pac::gclk::Genctrl; +#[hal_cfg(any("clock-d11", "clock-d21"))] +use crate::pac::gclk::Gendiv; use crate::pac::gclk::genctrl::Srcselect; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; use super::dfll::DfllId; -use super::dpll::{Dpll0Id, Dpll1Id}; -use super::osculp32k::OscUlp32kId; -use super::xosc::{Xosc0Id, Xosc1Id}; -use super::xosc32k::Xosc32kId; +// use super::dpll::{Dpll0Id, Dpll1Id}; +// use super::osculp32k::OscUlp32kId; +// use super::xosc::{Xosc0Id, Xosc1Id}; +// use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; //============================================================================== @@ -404,7 +406,20 @@ impl GclkToken { // of registers for the corresponding `GclkId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - unsafe { (*pac::Gclk::PTR).genctrl(G::NUM) } + #[hal_cfg("clock-d5x")] + unsafe { + &(*pac::Gclk::PTR).genctrl(G::NUM) + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*pac::Gclk::PTR).genctrl + } + } + + #[hal_cfg(any("clock-d11", "clock-d21"))] + #[inline] + fn gendiv(&self) -> &Gendiv { + unsafe { &(*pac::Gclk::PTR).gendiv } } /// Block until synchronization has completed @@ -416,8 +431,16 @@ impl GclkToken { // Safety: We are only reading from the `SYNCBUSY` register, and we are // only observing the bit corresponding to this particular `GclkId`, so // there is no risk of memory corruption. - let syncbusy = unsafe { &(*pac::Gclk::PTR).syncbusy() }; - while syncbusy.read().genctrl().bits() & Self::MASK != 0 {} + #[hal_cfg("clock-d5x")] + { + let syncbusy = unsafe { &(*pac::Gclk::PTR).syncbusy() }; + while syncbusy.read().genctrl().bits() & Self::MASK != 0 {} + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + let status = unsafe { &(*pac::Gclk::PTR).status }; + while status.read().syncbusy().bit() {} + } } /// Set the clock source for this [`Gclk`] @@ -436,10 +459,21 @@ impl GclkToken { let (divsel, div) = div.divsel_div(); // Safety: The `DIVSEL` and `DIV` values are derived from the // `GclkDivider` type, so they are guaranteed to be valid. - self.genctrl().modify(|_, w| unsafe { - w.divsel().variant(divsel); - w.div().bits(div) - }); + #[hal_cfg("clock-d5x")] + { + self.genctrl().modify(|_, w| unsafe { + w.divsel().bit(divsel); + w.div().bits(div) + }); + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + self.genctrl().write(|w| { + unsafe { w.id().bits(G::NUM as u8) }; + w.divsel().bit(divsel) + }); + self.gendiv().write(|w| unsafe { w.div().bits(div) }); + } self.wait_syncbusy(); } @@ -466,7 +500,7 @@ impl GclkToken { /// Disable [`Gclk`] output on a GPIO [`Pin`] /// - /// If a corresponding [`Pin`] is in the [`AlternateM`] mode, it's logic + /// If a corresponding [`Pin`] is in the [`AlternateH`] mode, it's logic /// level will depend on the [`output_off_value`]. #[inline] fn disable_gclk_out(&mut self) { @@ -475,33 +509,31 @@ impl GclkToken { } #[inline] - fn configure(&mut self, id: DynGclkSourceId, settings: Settings) { + fn enable(&mut self, id: DynGclkSourceId, settings: Settings) { let (divsel, div) = settings.div.divsel_div(); - self.genctrl().modify(|_, w| { + self.genctrl().write(|w| { // Safety: The `DIVSEL` and `DIV` values are derived from the // `GclkDivider` type, so they are guaranteed to be valid. unsafe { - w.divsel().variant(divsel); + #[hal_cfg("clock-d5x")] w.div().bits(div); + #[hal_cfg(any("clock-d11", "clock-d21"))] + w.id().bits(G::NUM as u8); }; + w.divsel().bit(divsel); w.src().variant(id.into()); w.idc().bit(settings.improve_duty_cycle); w.oov().bit(settings.output_off_value) }); - self.wait_syncbusy(); - } - - /// Enable the [`Gclk`] - #[inline] - fn enable(&mut self) { - self.genctrl().modify(|_, w| w.genen().set_bit()); + #[hal_cfg(any("clock-d11", "clock-d21"))] + self.gendiv().write(|w| unsafe { w.div().bits(div) }); self.wait_syncbusy(); } /// Disable the [`Gclk`] #[inline] fn disable(&mut self) { - self.genctrl().modify(|_, w| w.genen().clear_bit()); + self.genctrl().write(|w| w.genen().clear_bit()); self.wait_syncbusy(); } } @@ -516,6 +548,20 @@ impl GclkToken { /// generators. /// /// `DynGclkId` is the value-level equivalent of [`GclkId`]. +#[hal_cfg(any("clock-d11", "clock-d21"))] +pub enum DynGclkId { + Gclk0, + Gclk1, + Gclk2, + Gclk3, + Gclk4, + Gclk5, + Gclk6, + Gclk7, + Gclk8, +} + +#[hal_cfg("clock-d5x")] pub enum DynGclkId { Gclk0, Gclk1, @@ -589,7 +635,32 @@ impl GclkId for Gclk1Id { type Divider = GclkDiv16; } -seq!(N in 2..=11 { +macro_rules! with_gclk_max { + ($N:ident in $start:literal ..= max $mac:tt) => { + #[hal_cfg("clock-d5x")] + seq!($N in $start..=11 $mac); + #[hal_cfg(any("clock-d11", "clock-d21"))] + seq!($N in $start..=8 $mac); + }; +} + +#[hal_cfg("clock-d5x")] +macro_rules! with_gclk_max_expr { + ($N:ident in $start:literal ..= max $mac:tt) => { + seq!($N in $start..=11 $mac) + }; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +macro_rules! with_gclk_max_expr { + ($N:ident in $start:literal ..= max $mac:tt) => { + seq!($N in $start..=8 $mac) + }; +} + +pub(super) use with_gclk_max_expr; + +with_gclk_max!(N in 2..=max { paste! { /// Type-level variant of [`GclkId`] representing the identity of #[doc = "GCLK" N] @@ -631,7 +702,7 @@ pub trait GclkDivider: Sealed + Default + Copy { /// Returns the actual clock divider value as a `u32` fn divider(&self) -> u32; /// Return the corresponding `DIVSEL` and and `DIV` register fields - fn divsel_div(&self) -> (Divselselect, u16); + fn divsel_div(&self) -> (bool, u16); } //============================================================================== @@ -678,11 +749,11 @@ impl GclkDivider for GclkDiv8 { } #[inline] - fn divsel_div(&self) -> (Divselselect, u16) { + fn divsel_div(&self) -> (bool, u16) { match self { - GclkDiv8::Div(div) => (Divselselect::Div1, (*div).into()), - GclkDiv8::Div2Pow8 => (Divselselect::Div2, 7), - GclkDiv8::Div2Pow9 => (Divselselect::Div2, 8), + GclkDiv8::Div(div) => (false, (*div).into()), + GclkDiv8::Div2Pow8 => (true, 7), + GclkDiv8::Div2Pow9 => (true, 8), } } } @@ -730,11 +801,11 @@ impl GclkDivider for GclkDiv16 { } #[inline] - fn divsel_div(&self) -> (Divselselect, u16) { + fn divsel_div(&self) -> (bool, u16) { match self { - GclkDiv16::Div(div) => (Divselselect::Div1, *div), - GclkDiv16::Div2Pow16 => (Divselselect::Div2, 15), - GclkDiv16::Div2Pow17 => (Divselselect::Div2, 16), + GclkDiv16::Div(div) => (false, *div), + GclkDiv16::Div2Pow16 => (true, 15), + GclkDiv16::Div2Pow17 => (true, 16), } } } @@ -821,7 +892,7 @@ pub trait Gclk0Io where Self: Sized, Self: GclkIo, - Self: GclkSourceId>, + Self: GclkSourceId>, { } @@ -851,18 +922,33 @@ pub enum DynGclkSourceId { } impl From for Srcselect { + #[hal_cfg("clock-d5x")] fn from(source: DynGclkSourceId) -> Self { use DynGclkSourceId::*; match source { - Dfll => Self::Dfll, - Dpll0 => Self::Dpll0, - Dpll1 => Self::Dpll1, - Gclk1 => Self::Gclkgen1, - GclkIn => Self::Gclkin, - OscUlp32k => Self::Osculp32k, - Xosc0 => Self::Xosc0, - Xosc1 => Self::Xosc1, - Xosc32k => Self::Xosc32k, + Dfll => Srcselect::Dfll, + Dpll0 => Srcselect::Dpll0, + Dpll1 => Srcselect::Dpll1, + Gclk1 => Srcselect::Gclkgen1, + GclkIn => Srcselect::Gclkin, + OscUlp32k => Srcselect::Osculp32k, + Xosc0 => Srcselect::Xosc0, + Xosc1 => Srcselect::Xosc1, + Xosc32k => Srcselect::Xosc32k, + } + } + + #[hal_cfg(any("clock-d11", "clock-d21"))] + fn from(source: DynGclkSourceId) -> Self { + use DynGclkSourceId::*; + match source { + Dfll => Srcselect::Dfll48m, + Dpll => Srcselect::Dpll96m, + Gclk1 => Srcselect::Gclkgen1, + GclkIn => Srcselect::Gclkin, + OscUlp32k => Srcselect::Osculp32k, + Xosc => Srcselect::Xosc, + Xosc32k => Srcselect::Xosc32k, } } } @@ -900,38 +986,38 @@ impl GclkSourceId for DfllId { const DYN: DynGclkSourceId = DynGclkSourceId::Dfll; type Resource = (); } -impl GclkSourceId for Dpll0Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Dpll0; - type Resource = (); -} -impl GclkSourceId for Dpll1Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; - type Resource = (); -} -impl GclkSourceId for Gclk1Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; - type Resource = (); -} +//impl GclkSourceId for Dpll0Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Dpll0; +// type Resource = (); +//} +//impl GclkSourceId for Dpll1Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; +// type Resource = (); +//} +//impl GclkSourceId for Gclk1Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; +// type Resource = (); +//} impl GclkSourceId for I { const DYN: DynGclkSourceId = DynGclkSourceId::GclkIn; - type Resource = Pin; -} -impl GclkSourceId for OscUlp32kId { - const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; - type Resource = (); -} -impl GclkSourceId for Xosc0Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; - type Resource = (); -} -impl GclkSourceId for Xosc1Id { - const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; - type Resource = (); -} -impl GclkSourceId for Xosc32kId { - const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; - type Resource = (); + type Resource = Pin; } +//impl GclkSourceId for OscUlp32kId { +// const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; +// type Resource = (); +//} +//impl GclkSourceId for Xosc0Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; +// type Resource = (); +//} +//impl GclkSourceId for Xosc1Id { +// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; +// type Resource = (); +//} +//impl GclkSourceId for Xosc32kId { +// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; +// type Resource = (); +//} //============================================================================== // NotGclkIo @@ -1054,7 +1140,7 @@ pub type Gclk0 = Gclk; /// on [`EnabledGclk0`] to configure the `Gclk` while it is actively running. pub type EnabledGclk0 = EnabledGclk; -seq!(G in 1..=11 { +with_gclk_max!(G in 1..=max { paste! { /// Type alias for the corresponding [`Gclk`] pub type Gclk~G = Gclk<[], I>; @@ -1098,7 +1184,7 @@ where /// /// Freeing a [`Gclk`] returns the corresponding [`GclkToken`] and GPIO /// [`Pin`]. - pub fn free_pin(self) -> (GclkToken, Pin) { + pub fn free_pin(self) -> (GclkToken, Pin) { (self.token, self.resource) } } @@ -1212,10 +1298,10 @@ where /// When calling this function, the new OOV will take effect immediately. /// /// However, remember that the `Pin` is not controlled by the `Gclk` unless - /// the `Pin` is configured in [`AlternateM`] mode. `Pin`s are automatically - /// set to `AlternateM` mode when calling [`enable_gclk_out`], but by that + /// the `Pin` is configured in [`AlternateH`] mode. `Pin`s are automatically + /// set to `AlternateH` mode when calling [`enable_gclk_out`], but by that /// point, the OOV is irrelevant. If you need the `Pin` to be set to its - /// OOV, you must *manually* set it to `AlternateM` mode before constructing + /// OOV, you must *manually* set it to `AlternateH` mode before constructing /// the `GclkOut`. /// /// [`enable_gclk_out`]: EnabledGclk::enable_gclk_out @@ -1237,8 +1323,7 @@ where /// [`Source`] for other clocks. #[inline] pub fn enable(mut self) -> EnabledGclk { - self.token.configure(I::DYN, self.settings); - self.token.enable(); + self.token.enable(I::DYN, self.settings); Enabled::new(self) } } @@ -1296,7 +1381,7 @@ impl EnabledGclk0 { self, pin: P, freq: impl Into, - ) -> (EnabledGclk0, Pin) + ) -> (EnabledGclk0, Pin) where I: Gclk0Io, P: AnyPin, @@ -1337,7 +1422,7 @@ impl EnabledGclk0 { pub fn swap_pin_for_source( self, source: S, - ) -> (EnabledGclk0, Pin, S::Inc) + ) -> (EnabledGclk0, Pin, S::Inc) where I: Gclk0Io, S: Source + Increment, @@ -1403,7 +1488,7 @@ where // Tokens //============================================================================== -seq!(N in 1..=11 { +with_gclk_max!(N in 1..=max { paste! { /// Set of [`GclkToken`]s representing the disabled [`Gclk`]s at /// power-on reset @@ -1423,13 +1508,12 @@ seq!(N in 1..=11 { /// All of the invariants required by `GclkToken::new` must be /// upheld here as well. #[inline] - pub(super) unsafe fn new(nvmctrl: &mut Nvmctrl) -> Self { - unsafe { - // Use auto wait states - nvmctrl.ctrla().modify(|_, w| w.autows().set_bit()); - GclkTokens { - #( gclk~N: GclkToken::new(), )* - } + pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { + // Use auto wait states + //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); + todo!(); + GclkTokens { + #( gclk~N: unsafe {GclkToken::new()}, )* } } } @@ -1448,7 +1532,7 @@ seq!(N in 1..=11 { /// See the [module-level documentation](self) for an example of creating a /// [`GclkOut`] from an [`EnabledGclk`]. pub struct GclkOut { - pin: Pin, + pin: Pin, freq: Hertz, } @@ -1480,7 +1564,7 @@ where /// enforce this requirement. /// /// Finally, when a [`GclkOut`] is disabled, but the [`Pin`] is still in - /// [`AlternateM`] mode, it takes the "output off value" of the `Gclk`. See + /// [`AlternateH`] mode, it takes the "output off value" of the `Gclk`. See /// the [`Gclk::output_off_value`] documentation for more details. #[inline] pub fn enable_gclk_out

(mut self, pin: P) -> (EnabledGclk, GclkOut) @@ -1500,13 +1584,13 @@ where /// /// Disabling [`GclkIo`] output will [`Decrement`] the [`EnabledGclk`] /// counter. When a [`GclkOut`] is disabled, but the [`Pin`] is still in - /// [`AlternateM`] mode, it takes the "output off value" of the `Gclk`. See + /// [`AlternateH`] mode, it takes the "output off value" of the `Gclk`. See /// the [`Gclk::output_off_value`] documentation for more details. #[inline] pub fn disable_gclk_out( mut self, gclk_out: GclkOut, - ) -> (EnabledGclk, Pin) + ) -> (EnabledGclk, Pin) where N: Decrement, I: GclkIo, diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index cd58db8f6cca..59f644b2f91c 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -62,7 +62,7 @@ //! [`clock::v2::types`]: super::types //! [`Sercom`]: crate::sercom::Sercom -use atsamd_hal_macros::hal_macro_helper; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; @@ -70,13 +70,22 @@ use paste::paste; use seq_macro::seq; use crate::pac; + +#[hal_cfg(any("clock-d11", "clock-d21"))] +use crate::pac::gclk::clkctrl::Genselect; +#[hal_cfg("clock-d5x")] use crate::pac::gclk::pchctrl::Genselect; +#[hal_cfg(any("clock-d11", "clock-d21"))] +use crate::pac::gclk::Clkctrl as Ctrl; +#[hal_cfg("clock-d5x")] +use crate::pac::gclk::Pchctrl as Ctrl; + use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; use super::Source; -use super::gclk::{DynGclkId, GclkId}; +use super::gclk::{DynGclkId, GclkId, with_gclk_max_expr}; //============================================================================== // PclkToken @@ -113,31 +122,48 @@ impl PclkToken

{ /// Access the corresponding `PCHCTRL` register #[inline] - fn pchctrl(&self) -> &pac::gclk::Pchctrl { + fn ctrl(&self) -> &Ctrl { // Safety: Each `PclkToken` only has access to a mutually exclusive set // of registers for the corresponding `PclkId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - unsafe { (*pac::Gclk::PTR).pchctrl(P::DYN as usize) } + #[hal_cfg("clock-d5x")] + unsafe { + &(*pac::Gclk::PTR).pchctrl(P::DYN as usize) + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*pac::Gclk::PTR).clkctrl + } } /// Set the [`Pclk`] source #[inline] - fn set_source(&mut self, source: DynPclkSourceId) { - self.pchctrl() - .modify(|_, w| w.r#gen().variant(source.into())); - } - - /// Enable the [`Pclk`] - #[inline] - fn enable(&mut self) { - self.pchctrl().modify(|_, w| w.chen().set_bit()); + fn enable(&mut self, source: DynPclkSourceId) { + self.ctrl().write(|w| { + w.r#gen().variant(source.into()); + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + w.clken().set_bit(); + unsafe { w.id().bits(P::DYN as u8) } + } + #[hal_cfg("clock-d5x")] + w.chen().set_bit() + }); } /// Disable the [`Pclk`] #[inline] fn disable(&mut self) { - self.pchctrl().modify(|_, w| w.chen().clear_bit()); + self.ctrl().modify(|_, w| { + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + w.clken().clear_bit(); + unsafe { w.id().bits(P::DYN as u8) } + } + #[hal_cfg("clock-d5x")] + w.chen().clear_bit() + }); } } @@ -165,6 +191,9 @@ pub mod ids { pub use crate::sercom::Sercom7; pub use super::super::dfll::DfllId; + //pub struct DfllId; + //impl crate::typelevel::Sealed for DfllId {} + #[hal_cfg("clock-d5x")] pub use super::super::dpll::{Dpll0Id, Dpll1Id}; pub use super::super::types::{ @@ -188,7 +217,6 @@ pub mod ids { #[hal_cfg("i2s")] pub use super::super::types::{I2S0, I2S1}; } - use ids::*; /// Append the list of all [`PclkId`] types and `snake_case` id names to the @@ -231,7 +259,9 @@ macro_rules! with_pclk_types_ids { $some_macro!( $( $args )* (DfllId = 0, dfll) + #[hal_cfg("clock-d5x")] (Dpll0Id = 1, dpll0) + #[hal_cfg("clock-d5x")] (Dpll1Id = 2, dpll1) (SlowClk = 3, slow) (Eic = 4, eic) @@ -370,7 +400,7 @@ pub type DynPclkSourceId = DynGclkId; /// Convert from [`DynPclkSourceId`] to the equivalent [PAC](crate::pac) type impl From for Genselect { fn from(source: DynPclkSourceId) -> Self { - seq!(N in 0..=11 { + with_gclk_max_expr!(N in 0..=max { match source { #( DynGclkId::Gclk~N => Genselect::Gclk~N, @@ -472,8 +502,7 @@ where S: Source + Increment, { let freq = gclk.freq(); - token.set_source(I::DYN); - token.enable(); + token.enable(I::DYN); let pclk = Pclk::new(token, freq); (pclk, gclk.inc()) } From 8a00b08dbf40de6a8d85ab5d4593c0dc446b8061 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 12:23:07 +1200 Subject: [PATCH 04/75] TODO Another hack to compile --- hal/src/clock/v2/gclk.rs | 1 + hal/src/lib.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 4ca2372a3e30..585caeb0b6a9 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -1508,6 +1508,7 @@ with_gclk_max!(N in 1..=max { /// All of the invariants required by `GclkToken::new` must be /// upheld here as well. #[inline] + #[allow(unreachable_code)] // TODO remove when todo is removed pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { // Use auto wait states //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); diff --git a/hal/src/lib.rs b/hal/src/lib.rs index d6b11ea42b72..f5f588c13a1d 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,6 +1,8 @@ #![no_std] // TODO Allows using hal_cfg to gate clock v2 for thumbv6, nightly only #![feature(proc_macro_hygiene)] +// TODO as above +#![feature(stmt_expr_attributes)] pub use embedded_hal_1 as ehal; use embedded_hal_02 as ehal_02; From 1be5a79d5ef788d64bae40c9270651002c69f96e Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 12:59:00 +1200 Subject: [PATCH 05/75] stash 2 xosc32k --- hal/src/clock/v2/xosc32k.rs | 175 +++++++++++++++++++++++++++--------- 1 file changed, 135 insertions(+), 40 deletions(-) diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index e33c983b3578..92e61ca9bc90 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -341,17 +341,31 @@ //! [`is_switched`]: Xosc32kCfd::is_switched //! [`switch_back`]: Xosc32kCfd::switch_back +use atsamd_hal_macros::hal_cfg; use fugit::RateExtU32; use typenum::U0; -use crate::pac::osc32kctrl::xosc32k::{Cgmselect, Startupselect}; -use crate::pac::osc32kctrl::{self, Cfdctrl, status}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use super::super::osculp32k::OscUlp32kId; + pub use crate::pac::Osc32kctrl as PERIPHERAL; + pub use crate::pac::osc32kctrl::xosc32k::Cgmselect; + pub use crate::pac::osc32kctrl::{Cfdctrl, Xosc32k as PacXosc32k, status::R as STATUS_R}; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::Sysctrl as PERIPHERAL; + pub use crate::pac::sysctrl::Xosc32k as PacXosc32k; + pub use crate::pac::sysctrl::pclksr::R as STATUS_R; +} + +use imports::*; use crate::gpio::{FloatingDisabled, PA00, PA01, Pin}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; -use super::osculp32k::OscUlp32kId; use super::{Enabled, Source}; //============================================================================== @@ -398,8 +412,10 @@ pub struct Xosc32kToken(()); /// /// Clock failure detection is disabled at power-on reset. To use it, you must /// first enable it by exchanging the token with [`Xosc32kCfd::enable`]. +#[hal_cfg("clock-d5x")] pub struct Xosc32kCfdToken(()); +#[hal_cfg("clock-d5x")] /// Set of tokens representing the disabled XOSC32K clocks power-on reset pub struct Xosc32kTokens { pub base: Xosc32kBaseToken, @@ -408,6 +424,7 @@ pub struct Xosc32kTokens { pub cfd: Xosc32kCfdToken, } +#[hal_cfg("clock-d5x")] impl Xosc32kTokens { /// Create the set of tokens /// @@ -426,12 +443,46 @@ impl Xosc32kTokens { } } +#[hal_cfg(any("clock-d11", "clock-d21"))] + +/// Set of tokens representing the disabled XOSC32K clocks power-on reset +pub struct Xosc32kTokens { + pub base: Xosc32kBaseToken, + pub xosc1k: Xosc1kToken, + pub xosc32k: Xosc32kToken, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl Xosc32kTokens { + /// Create the set of tokens + /// + /// # Safety + /// + /// There must never be more than one instance of these tokens at any given + /// time. See the notes on `Token` types and memory safety in the root of + /// the `clock` module for more details. + pub(super) unsafe fn new() -> Self { + Self { + base: Xosc32kBaseToken(()), + xosc1k: Xosc1kToken(()), + xosc32k: Xosc32kToken(()), + } + } +} + impl Xosc32kBaseToken { #[inline] - fn status(&self) -> status::R { + fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. - unsafe { (*crate::pac::Osc32kctrl::PTR).status().read() } + #[hal_cfg("clock-d5x")] + unsafe { + (*PERIPHERAL::PTR).status().read() + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + (*PERIPHERAL::PTR).pclksr().read() + } } /// Check whether the XOSC32K is stable and ready @@ -441,11 +492,11 @@ impl Xosc32kBaseToken { } #[inline] - fn xosc32k(&self) -> &osc32kctrl::Xosc32k { + fn xosc32k(&self) -> &PacXosc32k { // Safety: The `Xosc32kBaseToken` has exclusive access to the `XOSC32K` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { (*crate::pac::Osc32kctrl::PTR).xosc32k() } + unsafe { &(*PERIPHERAL::PTR).xosc32k() } } /// Reset the XOSC32K register @@ -456,21 +507,31 @@ impl Xosc32kBaseToken { /// Set most of the fields in the XOSC32K register #[inline] - fn set_xosc32k(&mut self, settings: Settings) { - let xtalen = settings.mode == DynMode::CrystalMode; - self.xosc32k().modify(|_, w| { + #[hal_cfg("clock-d5x")] + fn enable(&mut self, mode: DynMode, settings: Settings) { + let xtalen = mode == DynMode::CrystalMode; + self.xosc32k().write(|w| { w.cgm().variant(settings.cgm.into()); - w.startup().variant(settings.start_up.into()); + unsafe { w.startup().bits(settings.start_up as u8) }; w.ondemand().bit(settings.on_demand); w.runstdby().bit(settings.run_standby); - w.xtalen().bit(xtalen) + w.xtalen().bit(xtalen); + w.enable().set_bit() }); } - /// Disable the XOSC32K #[inline] - fn enable(&mut self) { - self.xosc32k().modify(|_, w| w.enable().set_bit()); + #[hal_cfg(any("clock-d11", "clock-d21"))] + fn enable(&mut self, mode: DynMode, settings: Settings) { + let xtalen = mode == DynMode::CrystalMode; + self.xosc32k().write(|w| { + w.aampen().bit(settings.aampen); + unsafe { w.startup().bits(settings.start_up as u8) }; + w.ondemand().bit(settings.on_demand); + w.runstdby().bit(settings.run_standby); + w.xtalen().bit(xtalen); + w.enable().set_bit() + }); } /// Disable the XOSC32K @@ -510,12 +571,13 @@ impl Xosc32kBaseToken { } } +#[hal_cfg("clock-d5x")] impl Xosc32kCfdToken { #[inline] - fn status(&self) -> status::R { + fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. - unsafe { (*crate::pac::Osc32kctrl::PTR).status().read() } + unsafe { (*PERIPHERAL::PTR).status().read() } } /// Check whether the XOSC32K has triggered failure detection @@ -535,7 +597,7 @@ impl Xosc32kCfdToken { // Safety: The `Xosc32kCfdToken` has exclusive access to the `Cfdctrl` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { (*crate::pac::Osc32kctrl::PTR).cfdctrl() } + unsafe { &(*PERIPHERAL::PTR).cfdctrl() } } /// Enable clock failure detection and set the safe clock divider @@ -571,13 +633,46 @@ impl Xosc32kCfdToken { // All of these fields are set in a single write to XOSC32K during the call to // [`Xosc32kBase::enable`]. The remaining fields are only modified after it has // been enabled. +#[hal_cfg("clock-d5x")] #[derive(Clone, Copy)] struct Settings { start_up: StartUpDelay, cgm: ControlGainMode, on_demand: bool, run_standby: bool, - mode: DynMode, +} + +#[hal_cfg("clock-d5x")] +impl Default for Settings { + fn default() -> Self { + Settings { + start_up: StartUpDelay::Delay63ms, + cgm: ControlGainMode::Standard, + on_demand: true, + run_standby: false, + } + } +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[derive(Clone, Copy)] +struct Settings { + start_up: StartUpDelay, + aampen: bool, + on_demand: bool, + run_standby: bool, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl Default for Settings { + fn default() -> Self { + Settings { + start_up: StartUpDelay::Delay63ms, + aampen: false, + on_demand: true, + run_standby: false, + } + } } //============================================================================== @@ -631,6 +726,7 @@ impl From for bool { /// The start up delay is counted using the [`OscUlp32k`] clock. /// /// [`OscUlp32k`]: super::osculp32k::OscUlp32k +#[hal_cfg("clock-d5x")] #[repr(u8)] #[derive(Clone, Copy, Default, PartialEq, Eq)] pub enum StartUpDelay { @@ -644,18 +740,19 @@ pub enum StartUpDelay { Delay8s, } -impl From for Startupselect { - fn from(delay: StartUpDelay) -> Self { - match delay { - StartUpDelay::Delay63ms => Startupselect::Cycle2048, - StartUpDelay::Delay125ms => Startupselect::Cycle4096, - StartUpDelay::Delay500ms => Startupselect::Cycle16384, - StartUpDelay::Delay1s => Startupselect::Cycle32768, - StartUpDelay::Delay2s => Startupselect::Cycle65536, - StartUpDelay::Delay4s => Startupselect::Cycle131072, - StartUpDelay::Delay8s => Startupselect::Cycle262144, - } - } +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[repr(u8)] +#[derive(Clone, Copy, Default, PartialEq, Eq)] +pub enum StartUpDelay { + #[default] + Delay122us, + Delay1ms, + Delay63ms, + Delay125ms, + Delay500ms, + Delay1s, + Delay2s, + Delay4s, } //============================================================================== @@ -666,6 +763,7 @@ impl From for Startupselect { /// /// The XOSC32K crystal oscillator control loop has a configurable gain to allow /// users to trade power for speed and stability. +#[hal_cfg("clock-d5x")] #[derive(Copy, Clone, Default, PartialEq, Eq)] pub enum ControlGainMode { #[default] @@ -673,6 +771,7 @@ pub enum ControlGainMode { HighSpeed, } +#[hal_cfg("clock-d5x")] impl From for Cgmselect { fn from(cgm: ControlGainMode) -> Self { match cgm { @@ -843,6 +942,7 @@ impl Xosc32kBase { /// Set the crystal oscillator [`ControlGainMode`] #[inline] + #[hal_cfg("clock-d5x")] pub fn control_gain_mode(mut self, cgm: ControlGainMode) -> Self { self.settings.cgm = cgm; self @@ -852,13 +952,7 @@ impl Xosc32kBase { impl Xosc32kBase { #[inline] fn new(token: Xosc32kBaseToken, pins: M::Pins) -> Self { - let settings = Settings { - start_up: StartUpDelay::Delay63ms, - cgm: ControlGainMode::Standard, - on_demand: true, - run_standby: false, - mode: M::DYN, - }; + let settings = Settings::default(); Self { token, pins, @@ -932,8 +1026,7 @@ impl Xosc32kBase { #[inline] pub fn enable(mut self) -> EnabledXosc32kBase { self.token.reset(); - self.token.set_xosc32k(self.settings); - self.token.enable(); + self.token.enable(M::DYN, self.settings); Enabled::new(self) } } @@ -997,10 +1090,12 @@ impl EnabledXosc32kBase { /// /// [`OscUlp32k`]: super::osculp32k::OscUlp32k /// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k +#[hal_cfg("clock-d5x")] pub struct Xosc32kCfd { token: Xosc32kCfdToken, } +#[hal_cfg("clock-d5x")] impl Xosc32kCfd { /// Enable continuous monitoring of the XOSC32K for clock failure /// From ddfae16b3175e05de14c81f59d4ac29c7c0e0061 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:28:20 +1200 Subject: [PATCH 06/75] stash 2 xosc --- hal/src/clock/v2/xosc.rs | 231 ++++++++++++++++++++++++++++++--------- 1 file changed, 179 insertions(+), 52 deletions(-) diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 13290f988085..e5b03253263f 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -204,17 +204,32 @@ //! [`Dfll`]: super::dfll::Dfll //! [`EnabledDfll`]: super::dfll::EnabledDfll +use atsamd_hal_macros::hal_cfg; use core::marker::PhantomData; use typenum::U0; -use crate::pac::oscctrl::{self, Xoscctrl}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use super::super::dfll::DfllId; + pub use crate::gpio::{PB22, PB23}; + pub use crate::pac::Oscctrl as Peripheral; + pub use crate::pac::oscctrl::{Xoscctrl, status::R as STATUS_R}; + pub use crate::typelevel::{Decrement, Increment}; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::Sysctrl as Peripheral; + pub use crate::pac::sysctrl::{Xosc as Xoscctrl, pclksr::R as STATUS_R, xosc::Gainselect}; +} -use crate::gpio::{FloatingDisabled, PA14, PA15, PB22, PB23, Pin, PinId}; +use imports::*; + +use crate::gpio::{FloatingDisabled, PA14, PA15, Pin, PinId}; use crate::time::Hertz; -use crate::typelevel::{Decrement, Increment, Sealed}; +use crate::typelevel::Sealed; -use super::dfll::DfllId; use super::{Enabled, Source}; //============================================================================== @@ -257,15 +272,29 @@ impl XoscToken { // of registers for the corresponding `XoscId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - unsafe { (*crate::pac::Oscctrl::PTR).xoscctrl(X::NUM) } + #[hal_cfg("clock-d5x")] + unsafe { + &(*Peripheral::PTR).xoscctrl(X::NUM) + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*Peripheral::PTR).xosc() + } } /// Read the STATUS register #[inline] - fn status(&self) -> oscctrl::status::R { + fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. - unsafe { (*crate::pac::Oscctrl::PTR).status().read() } + #[hal_cfg("clock-d5x")] + unsafe { + (*Peripheral::PTR).status().read() + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + (*Peripheral::PTR).pclksr().read() + } } /// Check whether the XOSC is stable and ready @@ -276,6 +305,7 @@ impl XoscToken { } /// Check whether the XOSC has triggered failure detection + #[hal_cfg("clock-d5x")] #[inline] fn has_failed(&self) -> bool { let mask = 1 << (X::NUM + 2); @@ -283,27 +313,24 @@ impl XoscToken { } /// Check whether the XOSC has been switched to the safe clock + #[hal_cfg("clock-d5x")] #[inline] fn is_switched(&self) -> bool { let mask = 1 << (X::NUM + 4); self.status().bits() & mask != 0 } - /// Reset the XOSCCTRL register - #[inline] - fn reset(&self) { - self.xoscctrl().reset(); - } - /// Switch from the safe clock back to the XOSC clock/oscillator /// /// This bit is cleared by the hardware after successfully switching back + #[hal_cfg("clock-d5x")] #[inline] fn switch_back(&mut self) { self.xoscctrl().modify(|_, w| w.swben().set_bit()); } /// Enable clock failure detection and set the safe clock divider + #[hal_cfg("clock-d5x")] #[inline] fn enable_failure_detection(&mut self, div: SafeClockDiv) { // Safety: The divider is guaranteed to be in the valid range 0..16. @@ -317,6 +344,7 @@ impl XoscToken { } /// Disable clock failure detection + #[hal_cfg("clock-d5x")] #[inline] fn disable_failure_detection(&mut self) { self.xoscctrl().modify(|_, w| w.cfden().clear_bit()); @@ -324,32 +352,35 @@ impl XoscToken { /// Set most of the fields in the XOSCCTRL register #[inline] - fn set_xoscctrl(&mut self, settings: Settings) { - let xtalen = settings.mode == DynMode::CrystalMode; + fn enable(&mut self, mode: DynMode, settings: Settings) { + let xtalen = mode == DynMode::CrystalMode; // Safety: The `IMULT` and `IPTAT` values come from the // `CrystalCurrent`, so they are guaranteed to be valid. - self.xoscctrl().modify(|_, w| unsafe { + self.xoscctrl().write(|w| unsafe { w.startup().bits(settings.start_up as u8); - w.enalc().bit(settings.loop_control); - w.imult().bits(settings.current.imult()); - w.iptat().bits(settings.current.iptat()); - w.lowbufgain().bit(settings.low_buf_gain); + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + w.ampgc().bit(settings.ampgc); + w.gain().variant(settings.gain.into()) + }; + #[hal_cfg("clock-d5x")] + { + w.enalc().bit(settings.loop_control); + w.imult().bits(settings.current.imult()); + w.iptat().bits(settings.current.iptat()); + w.lowbufgain().bit(settings.low_buf_gain); + }; w.ondemand().bit(settings.on_demand); w.runstdby().bit(settings.run_standby); - w.xtalen().bit(xtalen) + w.xtalen().bit(xtalen); + w.enable().set_bit() }); } - /// Enable the XOSC - #[inline] - fn enable(&mut self) { - self.xoscctrl().modify(|_, w| w.enable().set_bit()); - } - /// Disable the XOSC #[inline] fn disable(&mut self) { - self.xoscctrl().modify(|_, w| w.enable().clear_bit()); + self.xoscctrl().write(|w| w.enable().clear_bit()); } } @@ -362,6 +393,7 @@ impl XoscToken { // All of these fields are set in a single write to XOSCCTRL during the call to // [`Xosc::enable`]. The remaining fields are only modified after it has been // enabled. +#[hal_cfg("clock-d5x")] #[derive(Clone, Copy)] struct Settings { start_up: StartUpDelay, @@ -370,7 +402,43 @@ struct Settings { low_buf_gain: bool, on_demand: bool, run_standby: bool, - mode: DynMode, +} + +#[hal_cfg("clock-d5x")] +impl Default for Settings { + fn default() -> Self { + Settings { + start_up: StartUpDelay::default(), + loop_control: false, + current: CrystalCurrent::default(), + low_buf_gain: false, + on_demand: true, + run_standby: false, + } + } +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[derive(Clone, Copy)] +struct Settings { + start_up: StartUpDelay, + ampgc: bool, + gain: Gain, + on_demand: bool, + run_standby: bool, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl Default for Settings { + fn default() -> Self { + Settings { + start_up: StartUpDelay::default(), + ampgc: false, + gain: Gain::default(), + on_demand: true, + run_standby: false, + } + } } //============================================================================== @@ -421,10 +489,13 @@ impl XoscId for Xosc0Id { /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums +#[hal_cfg("clock-d5x")] pub enum Xosc1Id {} +#[hal_cfg("clock-d5x")] impl Sealed for Xosc1Id {} +#[hal_cfg("clock-d5x")] impl XoscId for Xosc1Id { const NUM: usize = 1; type XIn = PB22; @@ -526,6 +597,7 @@ pub enum StartUpDelay { /// each frequency range, it also acknowledges some flexibility in that choice. /// Specifically, it notes that users can save power by selecting the next-lower /// frequency range if the capacitive load is small. +#[hal_cfg("clock-d5x")] #[derive(Clone, Copy, Default, PartialEq, Eq)] pub enum CrystalCurrent { /// Used only in [`ClockMode`] to represent the default register values @@ -541,6 +613,7 @@ pub enum CrystalCurrent { ExtraHigh, } +#[hal_cfg("clock-d5x")] impl CrystalCurrent { #[inline] fn imult(&self) -> u8 { @@ -565,6 +638,34 @@ impl CrystalCurrent { } } +//============================================================================== +// Gain +//============================================================================== + +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[derive(Clone, Copy, Default, PartialEq, Eq)] +pub enum Gain { + #[default] + Zero, + One, + Two, + Three, + Four, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl From for Gainselect { + fn from(gain: Gain) -> Self { + match gain { + Gain::Zero => Gainselect::_0, + Gain::One => Gainselect::_1, + Gain::Two => Gainselect::_2, + Gain::Three => Gainselect::_3, + Gain::Four => Gainselect::_4, + } + } +} + //============================================================================== // DynMode //============================================================================== @@ -692,6 +793,7 @@ where pub type Xosc0 = Xosc; /// Type alias for the corresponding [`Xosc`] +#[hal_cfg("clock-d5x")] pub type Xosc1 = Xosc; /// An [`Enabled`] [`Xosc`] @@ -709,6 +811,7 @@ pub type EnabledXosc = Enabled, N>; pub type EnabledXosc0 = EnabledXosc; /// Type alias for the corresponding [`EnabledXosc`] +#[hal_cfg("clock-d5x")] pub type EnabledXosc1 = EnabledXosc; impl Xosc { @@ -768,6 +871,7 @@ impl Xosc { } /// Set the [`CrystalCurrent`] drive strength + #[hal_cfg("clock-d5x")] #[inline] pub fn current(mut self, current: CrystalCurrent) -> Self { self.settings.current = current; @@ -778,6 +882,7 @@ impl Xosc { /// /// If enabled, the hardware will automatically adjust the oscillator /// amplitude. In most cases, this will lower power consumption. + #[hal_cfg("clock-d5x")] #[inline] pub fn loop_control(mut self, loop_control: bool) -> Self { self.settings.loop_control = loop_control; @@ -790,11 +895,26 @@ impl Xosc { /// loop control is enabled, setting the `LOWBUFGAIN` field to `1` will /// _increase_ the oscillator amplitude by a factor of appoximately 2. This /// can help solve stability issues. + #[hal_cfg("clock-d5x")] #[inline] pub fn low_buf_gain(mut self, low_buf_gain: bool) -> Self { self.settings.low_buf_gain = low_buf_gain; self } + + #[hal_cfg(any("clock-d11", "clock-d21"))] + #[inline] + pub fn amplitude_gain_control(mut self, enabled: bool) -> Self { + self.settings.ampgc = enabled; + self + } + + #[hal_cfg(any("clock-d11", "clock-d21"))] + #[inline] + pub fn gain(mut self, gain: Gain) -> Self { + self.settings.gain = gain; + self + } } impl Xosc @@ -802,28 +922,19 @@ where X: XoscId, M: Mode, { + #[hal_cfg("clock-d5x")] #[inline] fn new(token: XoscToken, pins: M::Pins, freq: Hertz) -> Self { - let current = match freq.to_Hz() { - 8_000_000 => CrystalCurrent::Low, - 8_000_001..=16_000_000 => CrystalCurrent::Medium, - 16_000_001..=24_000_000 => CrystalCurrent::High, - 24_000_001..=48_000_000 => CrystalCurrent::ExtraHigh, - _ => panic!("The XOSC input frequency must be 8-48 MHz"), - }; - let current = match M::DYN { - DynMode::ClockMode => CrystalCurrent::Zero, - DynMode::CrystalMode => current, - }; - let settings = Settings { - start_up: StartUpDelay::Delay31us, - loop_control: false, - current, - low_buf_gain: false, - on_demand: true, - run_standby: false, - mode: M::DYN, - }; + let mut settings = Settings::default(); + if M::DYN == DynMode::CrystalMode { + settings.current = match freq.to_Hz() { + 8_000_000 => CrystalCurrent::Low, + 8_000_001..=16_000_000 => CrystalCurrent::Medium, + 16_000_001..=24_000_000 => CrystalCurrent::High, + 24_000_001..=48_000_000 => CrystalCurrent::ExtraHigh, + _ => panic!("The XOSC input frequency must be 8-48 MHz"), + }; + } Self { token, pins, @@ -832,6 +943,17 @@ where } } + #[hal_cfg(any("clock-d11", "clock-d21"))] + #[inline] + fn new(token: XoscToken, pins: M::Pins, freq: Hertz) -> Self { + Self { + token, + pins, + freq, + settings: Settings::default(), + } + } + /// Return the clock or crystal frequency #[inline] pub fn freq(&self) -> Hertz { @@ -885,9 +1007,7 @@ where /// [`Source`] for other clocks. #[inline] pub fn enable(mut self) -> EnabledXosc { - self.token.reset(); - self.token.set_xoscctrl(self.settings); - self.token.enable(); + self.token.enable(M::DYN, self.settings); Enabled::new(self) } } @@ -919,7 +1039,14 @@ where pub fn is_ready(&self) -> bool { self.0.token.is_ready() } +} +#[hal_cfg("clock-d5x")] +impl EnabledXosc +where + X: XoscId, + M: Mode, +{ /// Enable continuous monitoring of the [`Xosc`] for clock failure /// /// Failure detection will continuously monitor the [`Xosc`] to verify it is From c38433a31486cf095ff08902568b9e610a4af2ae Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:45:32 +1200 Subject: [PATCH 07/75] stash 2 osculp32k --- hal/src/clock/v2/osculp32k.rs | 47 ++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index 1b4e1c30d99b..b4bc968b71ea 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -161,13 +161,25 @@ //! [`clock_system_at_reset`]: super::clock_system_at_reset //! [`Clocks`]: super::Clocks +use atsamd_hal_macros::hal_cfg; use fugit::RateExtU32; use typenum::U0; -use crate::pac::osc32kctrl::Osculp32k; +#[hal_cfg("clock-d5x")] +mod imports { + pub use crate::pac::osc32kctrl::Osculp32k; + pub use crate::typelevel::{Decrement, Increment}; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::sysctrl::Osculp32k; +} + +use imports::*; use crate::time::Hertz; -use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; +use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; use super::{Enabled, Source}; @@ -239,27 +251,38 @@ impl OscUlp32kBaseToken { // Safety: The `OscUlp32kBaseToken` has exclusive access to the // `OSCULP32K` register. See the notes on `Token` types and memory // safety in the root of the `clock` module for more details. - unsafe { (*crate::pac::Osc32kctrl::PTR).osculp32k() } + #[hal_cfg("clock-d5x")] + unsafe { + &(*crate::pac::Osc32kctrl::PTR).osculp32k() + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*crate::pac::Sysctrl::PTR).osculp32k() + } } + #[hal_cfg("clock-d5x")] /// Enable the 1 kHz output #[inline] fn enable_1k(&mut self) { self.osculp32k().modify(|_, w| w.en1k().set_bit()); } + #[hal_cfg("clock-d5x")] /// Disable the 1 kHz output #[inline] fn disable_1k(&mut self) { self.osculp32k().modify(|_, w| w.en1k().clear_bit()); } + #[hal_cfg("clock-d5x")] /// Enable the 32 kHz output #[inline] fn enable_32k(&mut self) { self.osculp32k().modify(|_, w| w.en32k().set_bit()); } + #[hal_cfg("clock-d5x")] /// Disable the 32 kHz output #[inline] fn disable_32k(&mut self) { @@ -362,6 +385,7 @@ impl Sealed for OscUlp32kId {} /// derived from the [`OscUlp32kBase`] clock. See the /// [module-level documentation](super) for details and examples. pub struct OscUlp1k { + #[allow(unused)] token: OscUlp1kToken, } @@ -377,9 +401,16 @@ pub struct OscUlp1k { pub type EnabledOscUlp1k = Enabled; impl OscUlp1k { + #[hal_cfg(any("clock-d11", "clock-d21"))] + pub(super) unsafe fn new() -> Self { + let token = OscUlp1kToken(()); + Self { token } + } + /// Enable 1 kHz output from the [`OscUlp32kBase`] clock /// /// This will [`Increment`] the [`EnabledOscUlp32kBase`] counter. + #[hal_cfg("clock-d5x")] #[inline] pub fn enable( token: OscUlp1kToken, @@ -394,6 +425,7 @@ impl EnabledOscUlp1k { /// Disable 1 kHz output from the [`OscUlp32kBase`] clock /// /// This will [`Decrement`] the [`EnabledOscUlp32kBase`] counter. + #[hal_cfg("clock-d5x")] #[inline] pub fn disable( self, @@ -425,6 +457,7 @@ impl Source for EnabledOscUlp1k { /// derived from the [`OscUlp32kBase`] clock. See the /// [module-level documentation](super) for details and examples. pub struct OscUlp32k { + #[allow(unused)] token: OscUlp32kToken, } @@ -440,9 +473,16 @@ pub struct OscUlp32k { pub type EnabledOscUlp32k = Enabled; impl OscUlp32k { + #[hal_cfg(any("clock-d11", "clock-d21"))] + pub(super) unsafe fn new() -> Self { + let token = OscUlp32kToken(()); + Self { token } + } + /// Enable 32 kHz output from the [`OscUlp32kBase`] clock /// /// This will [`Increment`] the [`EnabledOscUlp32kBase`] counter. + #[hal_cfg("clock-d5x")] #[inline] pub fn enable( token: OscUlp32kToken, @@ -457,6 +497,7 @@ impl EnabledOscUlp32k { /// Disable 32 kHz output from the [`OscUlp32kBase`] clock /// /// This will [`Decrement`] the [`EnabledOscUlp32kBase`] counter. + #[hal_cfg("clock-d5x")] #[inline] pub fn disable( self, From 7c953194944fef1b955678bdced83277c5cfd344 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:29:23 +1200 Subject: [PATCH 08/75] stash 2 reset --- hal/src/clock/v2/reset.rs | 101 +++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/hal/src/clock/v2/reset.rs b/hal/src/clock/v2/reset.rs index dda29b0e6479..3736da7bbf99 100644 --- a/hal/src/clock/v2/reset.rs +++ b/hal/src/clock/v2/reset.rs @@ -2,6 +2,7 @@ //! from the `v2` module, which is where the corresponding documentation will //! appear. +use atsamd_hal_macros::hal_cfg; use typenum::U1; use crate::pac::{Gclk, Mclk, Nvmctrl, Osc32kctrl, Oscctrl}; @@ -57,6 +58,18 @@ pub struct Buses { pub apb: apb::Apb, } +#[hal_cfg("clock-d5x")] +pub struct OscUlp32kClocks { + base: osculp32k::EnabledOscUlp32kBase, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +pub struct OscUlp32kClocks { + base: osculp32k::EnabledOscUlp32kBase, + osculp1k: EnabledOscUlp1k, + osculp32k: EnabledOscUlp32k, +} + /// Enabled clocks at power-on reset /// /// This type is constructed using the [`clock_system_at_reset`] function, which @@ -88,7 +101,7 @@ pub struct Clocks { pub dfll: Enabled, /// Always-enabled base oscillator for the [`OscUlp1k`](osculp32k::OscUlp1k) /// and [`OscUlp32k`](osculp32k::OscUlp32k) clocks. - pub osculp32k_base: Enabled, + pub osculp32k: OscUlp32kClocks, } /// Type-level tokens for unused clocks at power-on reset @@ -100,6 +113,7 @@ pub struct Clocks { /// As described in the [top-level](super::super) documentation for the `clock` /// module, token types are used to guanrantee the uniqueness of each clock. To /// configure or enable a clock, you must provide the corresponding token. +#[hal_cfg("clock-d5x")] pub struct Tokens { /// Tokens to create [`apb::ApbClk`]s pub apbs: apb::ApbTokens, @@ -124,6 +138,29 @@ pub struct Tokens { pub osculp32k: osculp32k::OscUlp32kTokens, } +#[hal_cfg(any("clock-d11", "clock-d21"))] +pub struct Tokens { + /// Tokens to create [`apb::ApbClk`]s + pub apbs: apb::ApbTokens, + /// Token to create [`dpll::Dpll0`] + pub dpll0: dpll::DpllToken, + /// Token to create [`dpll::Dpll1`] + pub dpll1: dpll::DpllToken, + /// Tokens to create [`gclk::Gclk`] + pub gclks: gclk::GclkTokens, + /// Tokens to create [`pclk::Pclk`]s + pub pclks: pclk::PclkTokens, + /// Tokens to create [`rtcosc::RtcOsc`] + pub rtcosc: rtcosc::RtcOscToken, + /// Tokens [`xosc::Xosc0`] + pub xosc0: xosc::XoscToken, + /// Token to create [`xosc::Xosc1`] + pub xosc1: xosc::XoscToken, + /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and + /// [`xosc32k::Xosc32k`] + pub xosc32k: xosc32k::Xosc32kTokens, +} + /// Consume the PAC clocking structs and return a HAL-level /// representation of the clocks at power-on reset /// @@ -131,6 +168,7 @@ pub struct Tokens { /// [`Mclk`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`]. /// /// See the [module-level documentation](super) for more details. +#[hal_cfg("clock-d5x")] #[inline] pub fn clock_system_at_reset( oscctrl: Oscctrl, @@ -154,13 +192,18 @@ pub fn clock_system_at_reset( let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new())); let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll); let gclk0 = Enabled::new(gclk0); + let osculp32k_clocks = { + OscUlp32kClocks { + base: osculp32k::OscUlp32kBase::new(), + } + }; let clocks = Clocks { pac, ahbs: ahb::AhbClks::new(), apbs: apb::ApbClks::new(), gclk0, dfll, - osculp32k_base: osculp32k::OscUlp32kBase::new(), + osculp32k: osculp32k_clocks, }; let tokens = Tokens { apbs: apb::ApbTokens::new(), @@ -177,3 +220,57 @@ pub fn clock_system_at_reset( (buses, clocks, tokens) } } + +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[inline] +pub fn clock_system_at_reset( + oscctrl: Oscctrl, + osc32kctrl: Osc32kctrl, + gclk: Gclk, + mclk: Mclk, + nvmctrl: &mut Nvmctrl, +) -> (Buses, Clocks, Tokens) { + // Safety: No bus, clock or token is instantiated more than once + unsafe { + let buses = Buses { + ahb: ahb::Ahb::new(), + apb: apb::Apb::new(), + }; + let pac = Pac { + oscctrl, + osc32kctrl, + gclk, + mclk, + }; + let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new())); + let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll); + let gclk0 = Enabled::new(gclk0); + let osculp32k_clocks = { + OscUlp32kClocks { + base: osculp32k::OscUlp32kBase::new(), + osculp1k: Enabled::new(osculp32k::OscUlp1k::new()), + osculp32k: Enabled::new(osculp32k::OscUlp32k::new()), + } + }; + let clocks = Clocks { + pac, + ahbs: ahb::AhbClks::new(), + apbs: apb::ApbClks::new(), + gclk0, + dfll, + osculp32k: osculp32k_clocks, + }; + let tokens = Tokens { + apbs: apb::ApbTokens::new(), + dpll0: dpll::DpllToken::new(), + dpll1: dpll::DpllToken::new(), + gclks: gclk::GclkTokens::new(nvmctrl), + pclks: pclk::PclkTokens::new(), + rtcosc: rtcosc::RtcOscToken::new(), + xosc0: xosc::XoscToken::new(), + xosc1: xosc::XoscToken::new(), + xosc32k: xosc32k::Xosc32kTokens::new(), + }; + (buses, clocks, tokens) + } +} From 06a42e0e7c92104da03a3e12dce2b6524d828f21 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 15:00:05 +1200 Subject: [PATCH 09/75] TODO squash warnings --- hal/src/clock/v2/reset.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/src/clock/v2/reset.rs b/hal/src/clock/v2/reset.rs index 3736da7bbf99..6cc535a263a7 100644 --- a/hal/src/clock/v2/reset.rs +++ b/hal/src/clock/v2/reset.rs @@ -59,11 +59,13 @@ pub struct Buses { } #[hal_cfg("clock-d5x")] +#[allow(dead_code)] pub struct OscUlp32kClocks { base: osculp32k::EnabledOscUlp32kBase, } #[hal_cfg(any("clock-d11", "clock-d21"))] +#[allow(dead_code)] pub struct OscUlp32kClocks { base: osculp32k::EnabledOscUlp32kBase, osculp1k: EnabledOscUlp1k, From ed91b5e332548ef7b40233644451de4df8c9cbc3 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:32:11 +1200 Subject: [PATCH 10/75] stash 2 pclk --- hal/src/clock/v2/pclk.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 59f644b2f91c..205f06fc1685 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -71,15 +71,19 @@ use seq_macro::seq; use crate::pac; -#[hal_cfg(any("clock-d11", "clock-d21"))] -use crate::pac::gclk::clkctrl::Genselect; #[hal_cfg("clock-d5x")] -use crate::pac::gclk::pchctrl::Genselect; +mod imports { + pub use crate::pac::gclk::Pchctrl as Ctrl; + pub use crate::pac::gclk::pchctrl::Genselect; +} #[hal_cfg(any("clock-d11", "clock-d21"))] -use crate::pac::gclk::Clkctrl as Ctrl; -#[hal_cfg("clock-d5x")] -use crate::pac::gclk::Pchctrl as Ctrl; +mod imports { + pub use crate::pac::gclk::Clkctrl as Ctrl; + pub use crate::pac::gclk::clkctrl::Genselect; +} + +use imports::*; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; @@ -133,7 +137,7 @@ impl PclkToken

{ } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*pac::Gclk::PTR).clkctrl + &(*pac::Gclk::PTR).clkctrl() } } @@ -191,8 +195,6 @@ pub mod ids { pub use crate::sercom::Sercom7; pub use super::super::dfll::DfllId; - //pub struct DfllId; - //impl crate::typelevel::Sealed for DfllId {} #[hal_cfg("clock-d5x")] pub use super::super::dpll::{Dpll0Id, Dpll1Id}; From fab2ae54e64a884ed23b5d3448d7831b7a0ecbbb Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:46:27 +1200 Subject: [PATCH 11/75] stash 2 gclk --- hal/src/clock/v2/gclk.rs | 55 +++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 585caeb0b6a9..01d45f60f903 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -356,9 +356,11 @@ use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, use super::dfll::DfllId; // use super::dpll::{Dpll0Id, Dpll1Id}; -// use super::osculp32k::OscUlp32kId; -// use super::xosc::{Xosc0Id, Xosc1Id}; -// use super::xosc32k::Xosc32kId; +use super::osculp32k::OscUlp32kId; +use super::xosc::Xosc0Id; +#[hal_cfg("clock-d5x")] +use super::xosc::Xosc1Id; +use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; //============================================================================== @@ -412,14 +414,14 @@ impl GclkToken { } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*pac::Gclk::PTR).genctrl + &(*pac::Gclk::PTR).genctrl() } } #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] fn gendiv(&self) -> &Gendiv { - unsafe { &(*pac::Gclk::PTR).gendiv } + unsafe { &(*pac::Gclk::PTR).gendiv() } } /// Block until synchronization has completed @@ -438,7 +440,7 @@ impl GclkToken { } #[hal_cfg(any("clock-d11", "clock-d21"))] { - let status = unsafe { &(*pac::Gclk::PTR).status }; + let status = unsafe { &(*pac::Gclk::PTR).status() }; while status.read().syncbusy().bit() {} } } @@ -994,30 +996,31 @@ impl GclkSourceId for DfllId { // const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; // type Resource = (); //} -//impl GclkSourceId for Gclk1Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; -// type Resource = (); -//} +impl GclkSourceId for Gclk1Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; + type Resource = (); +} impl GclkSourceId for I { const DYN: DynGclkSourceId = DynGclkSourceId::GclkIn; type Resource = Pin; } -//impl GclkSourceId for OscUlp32kId { -// const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; -// type Resource = (); -//} -//impl GclkSourceId for Xosc0Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; -// type Resource = (); -//} -//impl GclkSourceId for Xosc1Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; -// type Resource = (); -//} -//impl GclkSourceId for Xosc32kId { -// const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; -// type Resource = (); -//} +impl GclkSourceId for OscUlp32kId { + const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; + type Resource = (); +} +impl GclkSourceId for Xosc0Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; + type Resource = (); +} +#[hal_cfg("clock-d5x")] +impl GclkSourceId for Xosc1Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; + type Resource = (); +} +impl GclkSourceId for Xosc32kId { + const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; + type Resource = (); +} //============================================================================== // NotGclkIo From fef6c2b9bf459d65a0c53170b0b824195d2ee1be Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:49:59 +1200 Subject: [PATCH 12/75] stash 2 dpll --- hal/src/clock/v2/dpll.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 7f20db8a820c..ce58ff12fa3f 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -237,22 +237,38 @@ //! [`GclkDivider`]: super::gclk::GclkDivider //! [`Pclk`]: super::pclk::Pclk +use atsamd_hal_macros::hal_cfg; use core::marker::PhantomData; use fugit::RateExtU32; use typenum::U0; -use crate::pac::oscctrl; -use crate::pac::oscctrl::dpll::{Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus, dpllsyncbusy}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use super::super::xosc::Xosc1Id; + pub use crate::pac::oscctrl::{ + Dpll as PacDpll, + dpll::dpllctrlb::Refclkselect, + dpll::{Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus, dpllsyncbusy}, + }; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::sysctrl::{ + dpllctrlb::Refclkselect, + {Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus}, + }; +} -use crate::pac::oscctrl::dpll::dpllctrlb::Refclkselect; +use imports::*; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; use super::gclk::GclkId; use super::pclk::{Pclk, PclkId}; -use super::xosc::{Xosc0Id, Xosc1Id, XoscId}; +use super::xosc::{Xosc0Id, XoscId}; use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -292,7 +308,7 @@ impl DpllToken { /// Access the corresponding PAC `DPLL` struct #[inline] - fn dpll(&self) -> &oscctrl::Dpll { + fn dpll(&self) -> &PacDpll { // Safety: Each `DpllToken` only has access to a mutually exclusive set // of registers for the corresponding `DpllId`, and we use a shared // reference to the register block. See the notes on `Token` types and From 374a52af6748ddc8ee0cdf91af5fd6df792469fb Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:53:30 +1200 Subject: [PATCH 13/75] stash 2 dfll --- hal/src/clock/v2/dfll.rs | 104 +++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 20 deletions(-) diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index 58cbceef6af7..f10f725922e4 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -272,7 +272,22 @@ //! [`from_usb`]: Dfll::from_usb //! [`into_mode`]: EnabledDfll::into_mode +use atsamd_hal_macros::hal_cfg; + +#[hal_cfg("clock-d5x")] +mod imports { + pub use crate::pac::oscctrl::{ + Dfllctrla as Dfllctrl, Dfllctrlb, Dfllmul, Dfllsync, RegisterBlock, + }; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::sysctrl::{Dfllctrl, Dfllmul, Dfllsync, RegisterBlock}; +} + use fugit::RateExtU32; +use imports::*; use typenum::U0; use crate::time::Hertz; @@ -309,51 +324,71 @@ impl DfllToken { } #[inline] - fn oscctrl(&self) -> &crate::pac::oscctrl::RegisterBlock { + fn reg_block(&self) -> &RegisterBlock { // Safety: The `DfllToken` only has access to a mutually exclusive set // of registers for the DFLL, and we use a shared reference to the // register block. See the notes on `Token` types and memory safety in // the root of the `clock` module for more details. - unsafe { &*crate::pac::Oscctrl::PTR } + #[hal_cfg("clock-d5x")] + unsafe { + &*crate::pac::Oscctrl::PTR + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &*crate::pac::Sysctrl::PTR + } } + #[hal_cfg("clock-d5x")] #[inline] - fn dfllctrla(&self) -> &crate::pac::oscctrl::Dfllctrla { - self.oscctrl().dfllctrla() + fn dfllctrl(&self) -> &Dfllctrl { + &self.reg_block().dfllctrla() } + #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] - fn dfllctrlb(&self) -> &crate::pac::oscctrl::Dfllctrlb { - self.oscctrl().dfllctrlb() + fn dfllctrl(&self) -> &Dfllctrl { + &self.reg_block().dfllctrl() } + #[hal_cfg("clock-d5x")] #[inline] - fn dfllmul(&self) -> &crate::pac::oscctrl::Dfllmul { - self.oscctrl().dfllmul() + fn dfllctrlb(&self) -> &Dfllctrlb { + self.reg_block().dfllctrlb() } #[inline] - fn dfllsync(&self) -> &crate::pac::oscctrl::Dfllsync { - self.oscctrl().dfllsync() + fn dfllmul(&self) -> &Dfllmul { + &self.reg_block().dfllmul() } + #[hal_cfg("clock-d5x")] + #[inline] + fn dfllsync(&self) -> &Dfllsync { + &self.reg_block().dfllsync() + } + + #[hal_cfg("clock-d5x")] #[inline] fn wait_sync_enable(&self) { while self.dfllsync().read().enable().bit() {} } + #[hal_cfg("clock-d5x")] #[inline] fn wait_sync_dfllmul(&self) { while self.dfllsync().read().dfllmul().bit() {} } + #[hal_cfg("clock-d5x")] #[inline] fn wait_sync_dfllctrlb(&self) { while self.dfllsync().read().dfllctrlb().bit() {} } + #[hal_cfg("clock-d5x")] #[inline] - fn configure(&mut self, settings: settings::All) { + fn enable(&mut self, settings: settings::All) { self.dfllctrlb().modify(|_, w| { w.mode().bit(settings.closed_loop); w.usbcrm().bit(settings.usb_recovery); @@ -371,27 +406,54 @@ impl DfllToken { }); self.wait_sync_dfllmul(); } - self.dfllctrla().modify(|_, w| { + self.dfllctrl().modify(|_, w| { w.runstdby().bit(settings.run_standby); - w.ondemand().bit(settings.on_demand) + w.ondemand().bit(settings.on_demand); + w.enable().set_bit() }); + self.wait_sync_enable(); } + #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] - fn enable(&mut self) { - self.dfllctrla().modify(|_, w| w.enable().set_bit()); - self.wait_sync_enable(); + fn enable(&mut self, settings: settings::All) { + if settings.closed_loop { + self.dfllmul().write(|w| + // Safety: All bit patterns are valid for these fields + unsafe { + w.mul().bits(settings.mult_factor); + w.cstep().bits(settings.coarse_max_step); + w.fstep().bits(settings.fine_max_step) + }); + } + self.dfllctrl().write(|w| { + w.mode().bit(settings.closed_loop); + w.usbcrm().bit(settings.usb_recovery); + w.ccdis().bit(!settings.chill_cycle); + w.qldis().bit(!settings.quick_lock); + w.runstdby().bit(settings.run_standby); + w.ondemand().bit(settings.on_demand); + w.enable().set_bit() + }); } #[inline] fn disable(&mut self) { - self.dfllctrla().modify(|_, w| w.enable().clear_bit()); + self.dfllctrl().write(|w| w.enable().clear_bit()); + #[hal_cfg("clock-d5x")] self.wait_sync_enable(); } + #[hal_cfg("clock-d5x")] + #[inline] + fn is_ready(&self) -> bool { + self.reg_block().status().read().dfllrdy().bit() + } + + #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] fn is_ready(&self) -> bool { - self.oscctrl().status().read().dfllrdy().bit() + self.reg_block().pclksr().read().dfllrdy().bit() } } @@ -401,7 +463,10 @@ impl DfllToken { type MultFactor = u16; type CoarseMaxStep = u8; +#[hal_cfg("clock-d5x")] type FineMaxStep = u8; +#[hal_cfg(any("clock-d11", "clock-d21"))] +type FineMaxStep = u16; //============================================================================== // DfllId @@ -1122,8 +1187,7 @@ impl Dfll { /// [`Source`] for other clocks. #[inline] pub fn enable(mut self) -> EnabledDfll { - self.token.configure(self.settings.all()); - self.token.enable(); + self.token.enable(self.settings.all()); Enabled::new(self) } } From 8cf2229e8e117d11cadadc366c42ee19ed8e0e7f Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 16:06:28 +1200 Subject: [PATCH 14/75] Only enable RTC for D5x --- hal/src/clock/v2.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index c815762c2298..1afc58c8ed8f 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -854,6 +854,8 @@ #![allow(clippy::manual_range_contains)] +use atsamd_hal_macros::hal_module; + use typenum::U0; use crate::time::Hertz; @@ -866,7 +868,10 @@ pub mod dpll; pub mod gclk; pub mod osculp32k; pub mod pclk; -pub mod rtcosc; +#[hal_module( + "clock-d5x" => "v2/rtcosc.rs", +)] +pub mod rtcosc {} pub mod types; pub mod xosc; pub mod xosc32k; From 33dc4824aedd8df6d842c71fbc5dd041ede50cc3 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 22 Jul 2025 13:54:34 +1200 Subject: [PATCH 15/75] WIP stash 2 enable v2 for thumbv6m --- hal/src/clock.rs | 3 +-- hal/src/clock/v2.rs | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hal/src/clock.rs b/hal/src/clock.rs index 830b82b36470..df8cc9e27495 100644 --- a/hal/src/clock.rs +++ b/hal/src/clock.rs @@ -2,7 +2,7 @@ //! //! Users are encouraged to use [`v2`] variant of an API because of the richer //! feature set and safety. -use atsamd_hal_macros::{hal_cfg, hal_module}; +use atsamd_hal_macros::hal_module; #[hal_module( any("clock-d11", "clock-d21") => "clock/v1_thumbv6m.rs", @@ -12,5 +12,4 @@ pub mod v1 {} pub use v1::*; -#[hal_cfg("clock-d5x")] pub mod v2; diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 1afc58c8ed8f..da718a4aca46 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -861,10 +861,10 @@ use typenum::U0; use crate::time::Hertz; use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; -pub mod ahb; -pub mod apb; +// pub mod ahb; +// pub mod apb; pub mod dfll; -pub mod dpll; +// pub mod dpll; pub mod gclk; pub mod osculp32k; pub mod pclk; @@ -876,8 +876,8 @@ pub mod types; pub mod xosc; pub mod xosc32k; -mod reset; -pub use reset::*; +// mod reset; +// pub use reset::*; // `Token` types and memory safety // From 3b5fcc1c623e4787ab979be1c18f221a4493123c Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 11:18:30 +1200 Subject: [PATCH 16/75] stash 3 ahb --- hal/src/clock/v2.rs | 2 +- hal/src/clock/v2/ahb.rs | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index da718a4aca46..aaaa7645326a 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -861,7 +861,7 @@ use typenum::U0; use crate::time::Hertz; use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; -// pub mod ahb; +pub mod ahb; // pub mod apb; pub mod dfll; // pub mod dpll; diff --git a/hal/src/clock/v2/ahb.rs b/hal/src/clock/v2/ahb.rs index 75b7ee27bd14..abf0e988b612 100644 --- a/hal/src/clock/v2/ahb.rs +++ b/hal/src/clock/v2/ahb.rs @@ -122,14 +122,24 @@ //! [`Clocks`]: super::Clocks //! [`Buses`]: super::Buses -use atsamd_hal_macros::hal_macro_helper; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use bitflags; use paste::paste; -use crate::pac::{Mclk, mclk}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use crate::pac::{Mclk as Peripheral, mclk::Ahbmask}; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::{Pm as Peripheral, pm::Ahbmask}; +} + +use imports::*; use super::types::*; @@ -160,11 +170,11 @@ impl Ahb { } #[inline] - fn ahbmask(&mut self) -> &mclk::Ahbmask { + fn ahbmask(&mut self) -> &Ahbmask { // Safety: The `Ahb` type has exclusive access to the `AHBMASK` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { (*Mclk::PTR).ahbmask() } + unsafe { (*Peripheral::PTR).ahbmask() } } #[inline] From a12a72a189a3d77bac51a8c9ba4f8d81fbb28447 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:09:41 +1200 Subject: [PATCH 17/75] Rename Pac -> Pac0 --- hal/src/clock/v2/ahb.rs | 2 +- hal/src/clock/v2/types.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/clock/v2/ahb.rs b/hal/src/clock/v2/ahb.rs index abf0e988b612..a860445e4ba9 100644 --- a/hal/src/clock/v2/ahb.rs +++ b/hal/src/clock/v2/ahb.rs @@ -393,7 +393,7 @@ define_ahb_types!( Cmcc = 8, Dmac = 9, Usb = 10, - Pac = 12, + Pac0 = 12, Qspi = 13, #[hal_cfg("gmac")] Gmac = 14, diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index 88bfc43ee225..96afd9f85db2 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -95,7 +95,7 @@ create_types!(NvmCtrl, NvmCtrlSmeeProm, NvmCtrlCache); create_types!(I2S, I2S0, I2S1); create_types!(OscCtrl); create_types!(Osc32kCtrl); -create_types!(Pac); +create_types!(Pac0); create_types!(Pcc); create_types!(PDec); create_types!(Pm); From 81ebcfe8c504d20e3f6372ad196f428e5ba5ff0e Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 12:00:53 +1200 Subject: [PATCH 18/75] stash 3 pclk --- hal/src/clock/v2/pclk.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 205f06fc1685..6d08067957d0 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -195,8 +195,9 @@ pub mod ids { pub use crate::sercom::Sercom7; pub use super::super::dfll::DfllId; + pub use super::super::dpll::Dpll0Id; #[hal_cfg("clock-d5x")] - pub use super::super::dpll::{Dpll0Id, Dpll1Id}; + pub use super::super::dpll::Dpll1Id; pub use super::super::types::{ Ac, Adc0, Adc1, CM4Trace, Ccl, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, @@ -261,7 +262,6 @@ macro_rules! with_pclk_types_ids { $some_macro!( $( $args )* (DfllId = 0, dfll) - #[hal_cfg("clock-d5x")] (Dpll0Id = 1, dpll0) #[hal_cfg("clock-d5x")] (Dpll1Id = 2, dpll1) From 5d00b3dff59ae9986915ec92668afd4fd6388256 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 10:58:40 +1200 Subject: [PATCH 19/75] stash 3 dpll --- hal/src/clock/v2.rs | 2 +- hal/src/clock/v2/dpll.rs | 87 ++++++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index aaaa7645326a..22ee6790e522 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -864,7 +864,7 @@ use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; pub mod ahb; // pub mod apb; pub mod dfll; -// pub mod dpll; +pub mod dpll; pub mod gclk; pub mod osculp32k; pub mod pclk; diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index ce58ff12fa3f..1e2fb265a88a 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -246,6 +246,7 @@ use typenum::U0; #[hal_cfg("clock-d5x")] mod imports { pub use super::super::xosc::Xosc1Id; + pub use crate::pac::Oscctrl as Peripheral; pub use crate::pac::oscctrl::{ Dpll as PacDpll, dpll::dpllctrlb::Refclkselect, @@ -255,7 +256,9 @@ mod imports { #[hal_cfg(any("clock-d11", "clock-d21"))] mod imports { + pub use crate::pac::Sysctrl as Peripheral; pub use crate::pac::sysctrl::{ + RegisterBlock as PacDpll, dpllctrlb::Refclkselect, {Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus}, }; @@ -313,7 +316,14 @@ impl DpllToken { // of registers for the corresponding `DpllId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - unsafe { (*crate::pac::Oscctrl::PTR).dpll(D::NUM) } + #[hal_cfg("clock-d5x")] + unsafe { + &(*Peripheral::PTR).dpll(D::NUM) + } + #[hal_cfg(any("clock-d11", "clock-d21"))] + unsafe { + &(*Peripheral::PTR) + } } /// Access the corresponding Dpllctrla register @@ -334,6 +344,7 @@ impl DpllToken { self.dpll().dpllratio() } + #[hal_cfg("clock-d5x")] /// Access the corresponding DPLLSYNCBUSY register for reading only #[inline] fn syncbusy(&self) -> dpllsyncbusy::R { @@ -347,13 +358,22 @@ impl DpllToken { } #[inline] - fn configure(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) { + fn enable(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) { // Convert the actual predivider to the `div` register field value + #[hal_cfg("clock-d5x")] + let div = match id { + DynDpllSourceId::Xosc0 => prediv / 2 - 1, + DynDpllSourceId::Xosc1 => prediv / 2 - 1, + _ => 0, + }; + + #[hal_cfg(any("clock-d11", "clock-d21"))] let div = match id { - DynDpllSourceId::Xosc0 | DynDpllSourceId::Xosc1 => prediv / 2 - 1, + DynDpllSourceId::Xosc0 => prediv / 2 - 1, _ => 0, }; - self.ctrlb().modify(|_, w| { + + self.ctrlb().write(|w| { // Safety: The value is masked to the correct bit width by the PAC. // An invalid value could produce an invalid clock frequency, but // that does not break memory safety. @@ -378,25 +398,37 @@ impl DpllToken { w.ldr().bits(settings.mult - 1); w.ldrfrac().bits(settings.frac) }); + #[hal_cfg("clock-d5x")] while self.syncbusy().dpllratio().bit_is_set() {} self.ctrla().modify(|_, w| { w.ondemand().bit(settings.on_demand); - w.runstdby().bit(settings.run_standby) + w.runstdby().bit(settings.run_standby); + w.enable().set_bit() }); + self.wait_enabled(); + } + + /// Disable the [`Dpll`] + #[inline] + fn disable(&mut self) { + self.ctrla().modify(|_, w| w.enable().clear_bit()); + self.wait_disabled(); } - /// Enable the [`Dpll`] #[inline] - fn enable(&mut self) { - self.ctrla().modify(|_, w| w.enable().set_bit()); + fn wait_enabled(&self) { + #[hal_cfg("clock-d5x")] while self.syncbusy().enable().bit_is_set() {} + #[hal_cfg(any("clock-d11", "clock-d21"))] + while self.status().enable().bit_is_clear() {} } - /// Disable the [`Dpll`] #[inline] - fn disable(&mut self) { - self.ctrla().modify(|_, w| w.enable().clear_bit()); + fn wait_disabled(&self) { + #[hal_cfg("clock-d5x")] while self.syncbusy().enable().bit_is_set() {} + #[hal_cfg(any("clock-d11", "clock-d21"))] + while self.status().enable().bit_is_set() {} } /// Check the STATUS register to see if the clock is locked @@ -473,10 +505,13 @@ impl DpllId for Dpll0Id { /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums +#[hal_cfg("clock-d5x")] pub enum Dpll1Id {} +#[hal_cfg("clock-d5x")] impl Sealed for Dpll1Id {} +#[hal_cfg("clock-d5x")] impl DpllId for Dpll1Id { const DYN: DynDpllId = DynDpllId::Dpll1; const NUM: usize = 1; @@ -492,6 +527,7 @@ impl DpllId for Dpll1Id { /// a given [`Dpll`]. /// /// `DynDpllSourceId` is the value-level equivalent of [`DpllSourceId`]. +#[hal_cfg("clock-d5x")] #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DynDpllSourceId { /// The DPLL is driven by a [`Pclk`] @@ -504,6 +540,7 @@ pub enum DynDpllSourceId { Xosc32k, } +#[hal_cfg("clock-d5x")] impl From for Refclkselect { fn from(source: DynDpllSourceId) -> Self { match source { @@ -515,6 +552,28 @@ impl From for Refclkselect { } } +#[hal_cfg(any("clock-d11", "clock-d21"))] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum DynDpllSourceId { + /// The DPLL is driven by a [`Pclk`] + Pclk, + /// The DPLL is driven by [`Xosc0`](super::xosc::Xosc0) + Xosc0, + /// The DPLL is driven by [`Xosc32k`](super::xosc32k::Xosc32k) + Xosc32k, +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl From for Refclkselect { + fn from(source: DynDpllSourceId) -> Self { + match source { + DynDpllSourceId::Pclk => Refclkselect::Gclk, + DynDpllSourceId::Xosc0 => Refclkselect::Ref1, + DynDpllSourceId::Xosc32k => Refclkselect::Ref0, + } + } +} + //============================================================================== // DpllSourceId //============================================================================== @@ -549,6 +608,7 @@ impl DpllSourceId for Xosc0Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc0; type Reference = settings::Xosc; } +#[hal_cfg("clock-d5x")] impl DpllSourceId for Xosc1Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc1; type Reference = settings::Xosc; @@ -749,6 +809,7 @@ where pub type Dpll0 = Dpll; /// Type alias for the corresponding [`Dpll`] +#[hal_cfg("clock-d5x")] pub type Dpll1 = Dpll; impl Dpll @@ -1065,8 +1126,7 @@ where pub fn enable_unchecked(mut self) -> EnabledDpll { use settings::Reference; let prediv = self.reference.prediv(); - self.token.configure(I::DYN, self.settings, prediv); - self.token.enable(); + self.token.enable(I::DYN, self.settings, prediv); Enabled::new(self) } } @@ -1090,6 +1150,7 @@ pub type EnabledDpll = Enabled, N>; pub type EnabledDpll0 = EnabledDpll; /// Type alias for the corresponding [`EnabledDpll`] +#[hal_cfg("clock-d5x")] pub type EnabledDpll1 = EnabledDpll; impl EnabledDpll From 341452ae3c4ee4e3e963fe32ab07d192ad114250 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 12:08:28 +1200 Subject: [PATCH 20/75] TODO Hacky disable of DPLL DCO for thumbv6m The smaller chips use a simpler digital phase-locked oop, which doesn't support the DCO filter options that the larger chips do. --- hal/src/clock/v2/dpll.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 1e2fb265a88a..ba8b886b86e3 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -381,6 +381,7 @@ impl DpllToken { w.refclk().variant(id.into()); w.lbypass().bit(settings.lock_bypass); w.wuf().bit(settings.wake_up_fast); + #[hal_cfg("clock-d5x")] if let Some(cap) = settings.dco_filter { w.dcoen().bit(true); unsafe { From 3546f63ecfefc4da9fbd17787f6f6a18395886f9 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:13:01 +1200 Subject: [PATCH 21/75] stash 3 apb - needs types first --- hal/src/clock/v2.rs | 2 +- hal/src/clock/v2/apb.rs | 122 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 112 insertions(+), 12 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 22ee6790e522..6eb5585c6880 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -862,7 +862,7 @@ use crate::time::Hertz; use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; pub mod ahb; -// pub mod apb; +pub mod apb; pub mod dfll; pub mod dpll; pub mod gclk; diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 57944682144e..08b28797b0f5 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -121,13 +121,25 @@ //! [`Clocks`]: super::Clocks //! [`Buses`]: super::Buses -use atsamd_hal_macros::hal_macro_helper; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use bitflags; use paste::paste; -use crate::pac::{self, mclk}; +#[hal_cfg("clock-d5x")] +mod imports { + pub use crate::pac::mclk::{RegisterBlock as BLOCK, Apbamask, Apbbmask, Apbcmask, Apbdmask}; + pub use crate::pac::Mclk as Peripheral; +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod imports { + pub use crate::pac::pm::{RegisterBlock as BLOCK, Apbamask, Apbbmask, Apbcmask}; + pub use crate::pac::Pm as Peripheral; +} + +use imports::*; use crate::typelevel::Sealed; @@ -160,35 +172,37 @@ impl Apb { } #[inline] - fn mclk(&self) -> &mclk::RegisterBlock { + fn mclk(&self) -> &BLOCK { // Safety: The `Apb` type has exclusive access to the `APBXMASK` // registers, and it uses a shared reference to the register block. See // the notes on `Token` types and memory safety in the root of the // `clock` module for more details. - unsafe { &*pac::Mclk::PTR } + unsafe { &*Peripheral::PTR } } #[inline] - fn apbamask(&mut self) -> &mclk::Apbamask { + fn apbamask(&mut self) -> &Apbamask { self.mclk().apbamask() } #[inline] - fn apbbmask(&mut self) -> &mclk::Apbbmask { + fn apbbmask(&mut self) -> &Apbbmask { self.mclk().apbbmask() } #[inline] - fn apbcmask(&mut self) -> &mclk::Apbcmask { + fn apbcmask(&mut self) -> &Apbcmask { self.mclk().apbcmask() } #[inline] - fn apbdmask(&mut self) -> &mclk::Apbdmask { - self.mclk().apbdmask() + #[hal_cfg("clock-d5x")] + fn apbdmask(&mut self) -> &Apbdmask { + &self.mclk().apbdmask() } #[inline] + #[hal_macro_helper] fn enable_mask(&mut self, mask: ApbMask) { // Safety: The mask bits are derived from a `bitflags` struct, so they // are guaranteed to be valid. @@ -206,6 +220,7 @@ impl Apb { self.apbcmask() .modify(|r, w| w.bits(r.bits() | mask.bits())); } + #[hal_cfg("clock-d5x")] ApbMask::D(mask) => { self.apbdmask() .modify(|r, w| w.bits(r.bits() | mask.bits())); @@ -215,6 +230,7 @@ impl Apb { } #[inline] + #[hal_macro_helper] fn disable_mask(&mut self, mask: ApbMask) { // Safety: The mask bits are derived from a `bitflags` struct, so they // are guaranteed to be valid. @@ -232,6 +248,7 @@ impl Apb { self.apbcmask() .modify(|r, w| w.bits(r.bits() & !mask.bits())); } + #[hal_cfg("clock-d5x")] ApbMask::D(mask) => { self.apbdmask() .modify(|r, w| w.bits(r.bits() & !mask.bits())); @@ -270,10 +287,12 @@ impl Apb { /// /// Each variant is a [`bitflags`] struct with a binary representation exactly /// matching the corresponding APB `MASK` register. +#[hal_macro_helper] enum ApbMask { A(ApbAMask), B(ApbBMask), C(ApbCMask), + #[hal_cfg("clock-d5x")] D(ApbDMask), } @@ -353,9 +372,10 @@ macro_rules! define_apb_types { } #[hal_macro_helper] +#[hal_cfg("clock-d5x")] define_apb_types!( A { - Pac = 0, + Pac0 = 0, Pm = 1, Mclk = 2, RstC = 3, @@ -426,6 +446,52 @@ define_apb_types!( } ); +#[hal_cfg(any("clock-d11", "clock-d21"))] +define_apb_types!( + A { + Pac0 = 0, + Pm = 1, + SysCtrl = 2, + Gclk = 3, + Wdt = 4, + Rtc = 5, + Eic = 6, + } + B { + Pac1 = 0, + Dsu = 1, + NvmCtrl = 2, + Port = 3, + Dmac = 4, + Usb = 5, + } + C { + Pac2 = 0, + EvSys = 1, + Sercom0 = 2, + Sercom1 = 3, + Sercom2 = 4, + Sercom3 = 5, + Sercom4 = 6, + Sercom5 = 7, + Tcc0 = 8, + Tcc1 = 9, + Tcc2 = 10, + Tc3 = 11, + Tc4 = 12, + Tc5 = 13, + Tc6 = 14, + Tc7 = 15, + Adc0 = 16, + Ac = 17, + Dac = 18, + Ptc = 19, + I2S = 20, + Ac1 = 21, + Tcc3 = 24, + } +); + //============================================================================== // ApbId //============================================================================== @@ -509,12 +575,16 @@ impl ApbClk { //============================================================================== /// Set of [`ApbToken`]s for APB clocks that are disabled at power-on reset + #[hal_macro_helper] pub struct ApbTokens { + #[hal_cfg("clock-d5x")] pub freq_m: ApbToken, pub sercom0: ApbToken, pub sercom1: ApbToken, + #[hal_cfg("clock-d5x")] pub tc0: ApbToken, + #[hal_cfg("clock-d5x")] pub tc1: ApbToken, pub usb: ApbToken, pub ev_sys: ApbToken, @@ -522,6 +592,7 @@ pub struct ApbTokens { pub sercom3: ApbToken, pub tcc0: ApbToken, pub tcc1: ApbToken, + #[hal_cfg("clock-d5x")] pub tc2: ApbToken, pub tc3: ApbToken, #[hal_cfg("tc4")] @@ -531,11 +602,16 @@ pub struct ApbTokens { pub tcc3: ApbToken, #[hal_cfg("tc5")] pub tc5: ApbToken, + #[hal_cfg("clock-d5x")] pub p_dec: ApbToken, pub ac: ApbToken, + #[hal_cfg("clock-d5x")] pub aes: ApbToken, + #[hal_cfg("clock-d5x")] pub trng: ApbToken, + #[hal_cfg("clock-d5x")] pub icm: ApbToken, + #[hal_cfg("clock-d5x")] pub ccl: ApbToken, pub sercom4: ApbToken, pub sercom5: ApbToken, @@ -550,10 +626,12 @@ pub struct ApbTokens { #[hal_cfg("tc7")] pub tc7: ApbToken, pub adc0: ApbToken, + #[hal_cfg("clock-d5x")] pub adc1: ApbToken, pub dac: ApbToken, #[hal_cfg("i2s")] pub i2s: ApbToken, + #[hal_cfg("clock-d5x")] pub pcc: ApbToken, } @@ -568,6 +646,7 @@ impl ApbTokens { pub(super) unsafe fn new() -> Self { unsafe { Self { + #[hal_cfg("clock-d5x")] freq_m: ApbToken::new(), sercom0: ApbToken::new(), sercom1: ApbToken::new(), @@ -588,11 +667,16 @@ impl ApbTokens { tcc3: ApbToken::new(), #[hal_cfg("tc5")] tc5: ApbToken::new(), + #[hal_cfg("clock-d5x")] p_dec: ApbToken::new(), ac: ApbToken::new(), + #[hal_cfg("clock-d5x")] aes: ApbToken::new(), + #[hal_cfg("clock-d5x")] trng: ApbToken::new(), + #[hal_cfg("clock-d5x")] icm: ApbToken::new(), + #[hal_cfg("clock-d5x")] ccl: ApbToken::new(), sercom4: ApbToken::new(), sercom5: ApbToken::new(), @@ -607,10 +691,12 @@ impl ApbTokens { #[hal_cfg("tc7")] tc7: ApbToken::new(), adc0: ApbToken::new(), + #[hal_cfg("clock-d5x")] adc1: ApbToken::new(), dac: ApbToken::new(), #[hal_cfg("i2s")] i2s: ApbToken::new(), + #[hal_cfg("clock-d5x")] pcc: ApbToken::new(), } } @@ -624,12 +710,17 @@ impl ApbTokens { /// Set of [`ApbClk`]s for APB clocks that are enabled at power-on reset #[hal_macro_helper] pub struct ApbClks { - pub pac: ApbClk, + pub pac: ApbClk, pub pm: ApbClk, + #[hal_cfg("clock-d5x")] pub mclk: ApbClk, + #[hal_cfg("clock-d5x")] pub rst_c: ApbClk, + #[hal_cfg("clock-d5x")] pub osc_ctrl: ApbClk, + #[hal_cfg("clock-d5x")] pub osc32k_ctrl: ApbClk, + #[hal_cfg("clock-d5x")] pub sup_c: ApbClk, pub gclk: ApbClk, pub wdt: ApbClk, @@ -638,9 +729,11 @@ pub struct ApbClks { pub dsu: ApbClk, pub nvm_ctrl: ApbClk, pub port: ApbClk, + #[hal_cfg("clock-d5x")] pub ram_ecc: ApbClk, #[hal_cfg("gmac")] pub gmac: ApbClk, + #[hal_cfg("clock-d5x")] pub qspi: ApbClk, } @@ -657,10 +750,15 @@ impl ApbClks { ApbClks { pac: ApbClk::new(ApbToken::new()), pm: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] mclk: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] rst_c: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] osc_ctrl: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] osc32k_ctrl: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] sup_c: ApbClk::new(ApbToken::new()), gclk: ApbClk::new(ApbToken::new()), wdt: ApbClk::new(ApbToken::new()), @@ -669,9 +767,11 @@ impl ApbClks { dsu: ApbClk::new(ApbToken::new()), nvm_ctrl: ApbClk::new(ApbToken::new()), port: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] ram_ecc: ApbClk::new(ApbToken::new()), #[hal_cfg("gmac")] gmac: ApbClk::new(ApbToken::new()), + #[hal_cfg("clock-d5x")] qspi: ApbClk::new(ApbToken::new()), } } From e048b059fb6e6cd88171f6b2a2c85a7b8d48f963 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:55:56 +1200 Subject: [PATCH 22/75] More work on ahb --- hal/src/clock/v2/ahb.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hal/src/clock/v2/ahb.rs b/hal/src/clock/v2/ahb.rs index a860445e4ba9..5b0f92c42cf5 100644 --- a/hal/src/clock/v2/ahb.rs +++ b/hal/src/clock/v2/ahb.rs @@ -383,6 +383,7 @@ macro_rules! define_ahb_types { } #[hal_macro_helper] +#[hal_cfg("clock-d5x")] define_ahb_types!( Hpb0 = 0, Hpb1 = 1, @@ -410,3 +411,14 @@ define_ahb_types!( NvmCtrlSmeeProm = 22, NvmCtrlCache = 23, ); + +#[hal_cfg(any("clock-d11", "clock-d21"))] +define_ahb_types!( + Hpb0 = 0, + Hpb1 = 1, + Hpb2 = 2, + Dsu = 3, + NvmCtrl = 4, + Dmac = 5, + Usb = 6, +); From 85ae750145d07c66ef398ca425e0858864562071 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:56:27 +1200 Subject: [PATCH 23/75] stash 3 types --- hal/src/clock/v2/types.rs | 43 +++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index 96afd9f85db2..2dca13a9a3da 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -64,14 +64,20 @@ macro_rules! create_types { } create_types!(Ac); -create_types!(Adc0, Adc1); +create_types!(Adc0); +#[hal_cfg("clock-d5x")] +create_types!(Adc1); +#[hal_cfg("clock-d5x")] create_types!(Aes); #[hal_cfg("can0")] create_types!(Can0); #[hal_cfg("can1")] create_types!(Can1); +#[hal_cfg("clock-d5x")] create_types!(Ccl); +#[hal_cfg("clock-d5x")] create_types!(Cmcc); +#[hal_cfg("clock-d5x")] create_types!(CM4Trace); create_types!(Dac); create_types!(Dmac); @@ -81,47 +87,76 @@ create_types!( EvSys, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, EvSys11 ); +#[hal_cfg("clock-d5x")] create_types!(FreqM); +#[hal_cfg("clock-d5x")] create_types!(FreqMMeasure); +#[hal_cfg("clock-d5x")] create_types!(FreqMReference); create_types!(Gclk); #[hal_cfg("gmac")] create_types!(Gmac); -create_types!(Hpb0, Hpb1, Hpb2, Hpb3); +create_types!(Hpb0, Hpb1, Hpb2); +#[hal_cfg("clock-d5x")] +create_types!(Hpb3); +#[hal_cfg("clock-d5x")] create_types!(Icm); +#[hal_cfg("clock-d5x")] create_types!(Mclk); -create_types!(NvmCtrl, NvmCtrlSmeeProm, NvmCtrlCache); -#[hal_cfg("i2s")] +create_types!(NvmCtrl); +#[hal_cfg("clock-d5x")] +create_types!(NvmCtrlSmeeProm, NvmCtrlCache); +#[hal_cfg("clock-d5x")] // TODO was min-samd51j in Bradley's work create_types!(I2S, I2S0, I2S1); +#[hal_cfg("clock-d5x")] create_types!(OscCtrl); +#[hal_cfg("clock-d5x")] create_types!(Osc32kCtrl); create_types!(Pac0); +#[hal_cfg(any("clock-d11", "clock-d21"))] +create_types!(Pac1, Pac2); +#[hal_cfg("clock-d5x")] create_types!(Pcc); +#[hal_cfg("clock-d5x")] create_types!(PDec); create_types!(Pm); create_types!(Port); +#[hal_cfg("clock-d5x")] create_types!(Pukcc); +#[hal_cfg("clock-d5x")] create_types!(Qspi, Qspi2x); +#[hal_cfg("clock-d5x")] create_types!(RamEcc); +#[hal_cfg("clock-d5x")] create_types!(RstC); create_types!(Rtc); +#[hal_cfg("clock-d5x")] create_types!(Sdhc0); #[hal_cfg("sdhc1")] create_types!(Sdhc1); create_types!(SlowClk); +#[hal_cfg("clock-d5x")] create_types!(SupC); +#[hal_cfg(any("clock-d11", "clock-d21"))] +create_types!(SysCtrl); +#[hal_cfg("clock-d5x")] create_types!(Tc0Tc1, Tc0, Tc1); +#[hal_cfg("clock-d5x")] create_types!(Tc2Tc3, Tc2, Tc3); #[hal_cfg(all("tc4", "tc5"))] create_types!(Tc4Tc5, Tc4, Tc5); #[hal_cfg(all("tc6", "tc7"))] create_types!(Tc6Tc7, Tc6, Tc7); create_types!(Tcc0Tcc1, Tcc0, Tcc1); +#[hal_cfg("clock-d5x")] create_types!(Tcc2Tcc3, Tcc2); #[hal_cfg("tcc3")] create_types!(Tcc3); #[hal_cfg("tcc4")] create_types!(Tcc4); +#[hal_cfg(any("clock-d11", "clock-d21"))] +create_types!(Tcc2Tc3, Tcc2, Tc3); +#[hal_cfg("clock-d5x")] create_types!(Trng); create_types!(Usb); create_types!(Wdt); From 982eb40fd0dddf1c0726762b14662ace391d992b Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:56:51 +1200 Subject: [PATCH 24/75] stash 3 pclk --- hal/src/clock/v2/pclk.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 6d08067957d0..cc82ef1d41d3 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -199,12 +199,20 @@ pub mod ids { #[hal_cfg("clock-d5x")] pub use super::super::dpll::Dpll1Id; + // TODO crude hack + #[hal_cfg("clock-d5x")] pub use super::super::types::{ Ac, Adc0, Adc1, CM4Trace, Ccl, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, FreqMMeasure, FreqMReference, PDec, Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Tcc0Tcc1, Tcc2Tcc3, Usb, }; + #[hal_cfg(any("clock-d11", "clock-d21"))] + pub use super::super::types::{ + Ac, Adc0, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, + EvSys9, EvSys10, EvSys11, SlowClk, Tcc0Tcc1, Usb, + }; + #[hal_cfg("can0")] pub use super::super::types::Can0; #[hal_cfg("can1")] @@ -217,6 +225,7 @@ pub mod ids { pub use super::super::types::Tc6Tc7; #[hal_cfg("tcc4")] pub use super::super::types::Tcc4; + #[hal_cfg("clock-d5x")] // TODO #[hal_cfg("i2s")] pub use super::super::types::{I2S0, I2S1}; } @@ -267,10 +276,13 @@ macro_rules! with_pclk_types_ids { (Dpll1Id = 2, dpll1) (SlowClk = 3, slow) (Eic = 4, eic) + #[hal_cfg("clock-d5x")] (FreqMMeasure = 5, freq_m_measure) + #[hal_cfg("clock-d5x")] (FreqMReference = 6, freq_m_reference) (Sercom0 = 7, sercom0) (Sercom1 = 8, sercom1) + #[hal_cfg("clock-d5x")] (Tc0Tc1 = 9, tc0_tc1) (Usb = 10, usb) (EvSys0 = 11, ev_sys0) @@ -288,16 +300,20 @@ macro_rules! with_pclk_types_ids { (Sercom2 = 23, sercom2) (Sercom3 = 24, sercom3) (Tcc0Tcc1 = 25, tcc0_tcc1) + #[hal_cfg("clock-d5x")] (Tc2Tc3 = 26, tc2_tc3) #[hal_cfg("can0")] (Can0 = 27, can0) #[hal_cfg("can1")] (Can1 = 28, can1) + #[hal_cfg("clock-d5x")] (Tcc2Tcc3 = 29, tcc2_tcc3) #[hal_cfg(all("tc4", "tc5"))] (Tc4Tc5 = 30, tc4_tc5) + #[hal_cfg("clock-d5x")] (PDec = 31, pdec) (Ac = 32, ac) + #[hal_cfg("clock-d5x")] (Ccl = 33, ccl) (Sercom4 = 34, sercom4) (Sercom5 = 35, sercom5) @@ -310,15 +326,18 @@ macro_rules! with_pclk_types_ids { #[hal_cfg(all("tc6", "tc7"))] (Tc6Tc7 = 39, tc6_tc7) (Adc0 = 40, adc0) + #[hal_cfg("clock-d5x")] (Adc1 = 41, adc1) (Dac = 42, dac) - #[hal_cfg("i2s")] + #[hal_cfg(all("i2s", "clock-d5x"))] (I2S0 = 43, i2s0) - #[hal_cfg("i2s")] + #[hal_cfg(all("i2s", "clock-d5x"))] (I2S1 = 44, i2s1) + #[hal_cfg("clock-d5x")] (Sdhc0 = 45, sdhc0) #[hal_cfg("sdhc1")] (Sdhc1 = 46, sdhc1) + #[hal_cfg("clock-d5x")] (CM4Trace = 47, cm4_trace) ); }; From 21f11dabd076bbafa99c0c8b35e0f883ff61711f Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 13:56:56 +1200 Subject: [PATCH 25/75] stash 3 apb --- hal/src/clock/v2/apb.rs | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 08b28797b0f5..517c300cd91c 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -129,14 +129,14 @@ use paste::paste; #[hal_cfg("clock-d5x")] mod imports { - pub use crate::pac::mclk::{RegisterBlock as BLOCK, Apbamask, Apbbmask, Apbcmask, Apbdmask}; pub use crate::pac::Mclk as Peripheral; + pub use crate::pac::mclk::{Apbamask, Apbbmask, Apbcmask, Apbdmask, RegisterBlock as BLOCK}; } #[hal_cfg(any("clock-d11", "clock-d21"))] mod imports { - pub use crate::pac::pm::{RegisterBlock as BLOCK, Apbamask, Apbbmask, Apbcmask}; pub use crate::pac::Pm as Peripheral; + pub use crate::pac::pm::{Apbamask, Apbbmask, Apbcmask, RegisterBlock as BLOCK}; } use imports::*; @@ -480,15 +480,9 @@ define_apb_types!( Tc3 = 11, Tc4 = 12, Tc5 = 13, - Tc6 = 14, - Tc7 = 15, Adc0 = 16, Ac = 17, Dac = 18, - Ptc = 19, - I2S = 20, - Ac1 = 21, - Tcc3 = 24, } ); @@ -629,7 +623,7 @@ pub struct ApbTokens { #[hal_cfg("clock-d5x")] pub adc1: ApbToken, pub dac: ApbToken, - #[hal_cfg("i2s")] + #[hal_cfg(all("clock-d5x", "i2s"))] // TODO pub i2s: ApbToken, #[hal_cfg("clock-d5x")] pub pcc: ApbToken, @@ -646,11 +640,13 @@ impl ApbTokens { pub(super) unsafe fn new() -> Self { unsafe { Self { - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] freq_m: ApbToken::new(), sercom0: ApbToken::new(), sercom1: ApbToken::new(), + #[hal_cfg("tc0")] tc0: ApbToken::new(), + #[hal_cfg("tc1")] tc1: ApbToken::new(), usb: ApbToken::new(), ev_sys: ApbToken::new(), @@ -658,6 +654,7 @@ impl ApbTokens { sercom3: ApbToken::new(), tcc0: ApbToken::new(), tcc1: ApbToken::new(), + #[hal_cfg("tc2")] tc2: ApbToken::new(), tc3: ApbToken::new(), #[hal_cfg("tc4")] @@ -694,7 +691,7 @@ impl ApbTokens { #[hal_cfg("clock-d5x")] adc1: ApbToken::new(), dac: ApbToken::new(), - #[hal_cfg("i2s")] + #[hal_cfg(all("clock-d5x", "i2s"))] // TODO i2s: ApbToken::new(), #[hal_cfg("clock-d5x")] pcc: ApbToken::new(), @@ -750,15 +747,15 @@ impl ApbClks { ApbClks { pac: ApbClk::new(ApbToken::new()), pm: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] mclk: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] rst_c: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] osc_ctrl: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] osc32k_ctrl: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] sup_c: ApbClk::new(ApbToken::new()), gclk: ApbClk::new(ApbToken::new()), wdt: ApbClk::new(ApbToken::new()), @@ -767,11 +764,11 @@ impl ApbClks { dsu: ApbClk::new(ApbToken::new()), nvm_ctrl: ApbClk::new(ApbToken::new()), port: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] ram_ecc: ApbClk::new(ApbToken::new()), #[hal_cfg("gmac")] gmac: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] + #[hal_cfg("clock-d5x")] qspi: ApbClk::new(ApbToken::new()), } } From 1a36bfb9da3fe4fce4b204c375d6bb09656d55d1 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 23 Jul 2025 14:19:00 +1200 Subject: [PATCH 26/75] stash 4 reset. TODO: Remove thumbv6 from v7 file --- hal/src/clock/v2.rs | 8 +- hal/src/clock/v2/reset_thumbv6m.rs | 177 ++++++++++++++++++ .../clock/v2/{reset.rs => reset_thumbv7em.rs} | 0 3 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 hal/src/clock/v2/reset_thumbv6m.rs rename hal/src/clock/v2/{reset.rs => reset_thumbv7em.rs} (100%) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 6eb5585c6880..0e36b34e010d 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -876,8 +876,12 @@ pub mod types; pub mod xosc; pub mod xosc32k; -// mod reset; -// pub use reset::*; +#[hal_module( + any("clock-d11", "clock-d21") => "v2/reset_thumbv6m.rs", + "clock-d5x" => "v2/reset_thumbv7em.rs", +)] +mod reset {} +pub use reset::*; // `Token` types and memory safety // diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs new file mode 100644 index 000000000000..854a1b16b6b8 --- /dev/null +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -0,0 +1,177 @@ +//! This module is intentionally private. Its contents are publicly exported +//! from the `v2` module, which is where the corresponding documentation will +//! appear. + +use typenum::U1; + +use crate::pac::{Gclk, Pm, Sysctrl}; + +use super::*; + +/// Collection of low-level PAC structs +/// +/// This struct serves to guard access to the low-level PAC structs. It places +/// them behind an `unsafe` barrier. +/// +/// Normally, users trade the low-level PAC structs for the higher-level +/// `clock::v2` API. However, in some cases, the `clock::v2` API may not be +/// sufficient. In these cases, users can access the registers directly by +/// calling [`Pac::steal`] to recover the PAC structs. +pub struct Pac { + gclk: Gclk, + pm: Pm, + sysctrl: Syctrl, +} + +impl Pac { + /// Escape hatch allowing to access low-level PAC structs + /// + /// Consume the [`Pac`] and return the low-level PAC structs. This is + /// useful when the `clock::v2` API does not provide a necessary feature, or + /// when dealing with the legacy `clock::v1` API. For example, many of the + /// `clock::v1` functions require access to the [`MCLK`] peripheral. + /// + /// # Safety + /// + /// Directly configuring clocks through the PAC API can invalidate the + /// type-level guarantees of the `clock` module API. + pub unsafe fn steal(self) -> (Gclk, Pm, Syctrl) { + (self.gclk, self.pm, self.sysctrl) + } +} + +/// Bus clock objects +/// +/// This type is constructed using the [`clock_system_at_reset`] function, which +/// consumes the PAC-level clocking structs and returns the HAL-level clocking +/// structs in their reset state. +/// +/// This type contains the [bus clocks](super#bus-clocks), which are a necessary +/// to implement memory safety for the [`AhbClk`]s and [`ApbClk`]s. +/// +/// [`AhbClk`]: super::ahb::AhbClk +/// [`ApbClk`]: super::apb::ApbClk +pub struct Buses { + pub ahb: ahb::Ahb, + pub apb: apb::Apb, +} + +pub struct OscUlp32kClocks { + pub base: osculp32k::EnabledOscUlp32kBase, + pub osculp1k: osculp32k::EnabledOscUlp1k, + pub osculp32k: osculp32k::EnabledOscUlp32k, +} + +/// Enabled clocks at power-on reset +/// +/// This type is constructed using the [`clock_system_at_reset`] function, which +/// consumes the PAC-level clocking structs and returns the HAL-level clocking +/// structs in their reset state. +/// +/// This type represents the clocks as they are configured at power-on reset. +/// The main clock, [`Gclk0`](gclk::Gclk0), runs at 48 MHz using the +/// [`Dfll`](dfll::Dfll) in open-loop mode. The ultra-low power +/// [base oscillator](osculp32k::OscUlp32kBase) is also enabled and running, as +/// it can never be disabled. +/// +/// As described in the [top-level](super::super) documentation for the `clock` +/// module, only [`Enabled`] clocks can be used as a [`Source`] for downstream +/// clocks. This struct contains all of the `Enabled` clocks at reset. +/// +/// This struct also contains the [`Pac`] wrapper struct, which provides +/// `unsafe` access to the low-level PAC structs. +pub struct Clocks { + /// Wrapper providing `unsafe` access to low-level PAC structs + pub pac: Pac, + /// Enabled AHB clocks + pub ahbs: ahb::AhbClks, + /// Enabled APB clocks + pub apbs: apb::ApbClks, + /// Main system clock, driven at 1 MHz by the OSC8M divided by 8 + pub gclk0: Enabled, U1>, + /// GCLK2, driven at 32 kHz by the OSCULP + pub gclk2: Enabled, U1>, + /// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2) + pub wdt: pclk::Pclk, + /// Always-enabled OSCULP oscillators + pub osculp32k: OscUlp32kClocks, +} + +/// Type-level tokens for unused clocks at power-on reset +/// +/// This type is constructed using the [`clock_system_at_reset`] function, which +/// consumes the PAC-level clocking structs and returns the HAL-level clocking +/// structs in their reset state. +/// +/// As described in the [top-level](super::super) documentation for the `clock` +/// module, token types are used to guanrantee the uniqueness of each clock. To +/// configure or enable a clock, you must provide the corresponding token. +pub struct Tokens { + /// Tokens to create [`apb::ApbClk`]s + pub apbs: apb::ApbTokens, + /// Token to create [`dfll::Dfll`] + pub dfll: dfll::DfllToken, + /// Token to create [`dpll::Dpll0`] + pub dpll: dpll::DpllToken, + /// Tokens to create [`gclk::Gclk`] + pub gclks: gclk::GclkTokens, + /// Tokens to create [`pclk::Pclk`]s + pub pclks: pclk::PclkTokens, + /// Tokens [`xosc::Xosc0`] + pub xosc: xosc::XoscToken, + /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and + /// [`xosc32k::Xosc32k`] + pub xosc32k: xosc32k::Xosc32kTokens, +} + +/// Consume the PAC clocking structs and return a HAL-level +/// representation of the clocks at power-on reset +/// +/// This function consumes the [`OSCCTRL`], [`OSC32KCTRL`], [`Gclk`] and +/// [`MCLK`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`]. +/// +/// See the [module-level documentation](super) for more details. +#[inline] +pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Syctrl) -> (Buses, Clocks, Tokens) { + // Safety: No bus, clock or token is instantiated more than once + unsafe { + let buses = Buses { + ahb: ahb::Ahb::new(), + apb: apb::Apb::new(), + }; + let pac = Pac { gclk, pm, sysctrl }; + let osc8m = Enabled::new(osc8m::Osc8m::new(osc8m::Osc8mToken::new())); + let (gclk0, osc8m) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc8m); + let gclk0 = Enabled::new(gclk0); + let base = osculp32k::OscUlp32kBase::new(); + let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); + let osculp32k = Enabled::new(osculp32k::OscUlp32k::new()); + let (gclk2, osculp32k) = gclk::Gclk2::from_source(gclk::GclkToken::new(), osculp32k); + let gclk2 = Enabled::new(gclk2); + let wdt = pclk::Pclk::new(pclk::PclkToken::new(), gclk2.freq()); + let osculp32k = OscUlp32kClocks { + base, + osculp1k, + osculp32k, + }; + let clocks = Clocks { + pac, + ahbs: ahb::AhbClks::new(), + apbs: apb::ApbClks::new(), + gclk0, + gclk2, + wdt, + osculp32k, + }; + let tokens = Tokens { + apbs: apb::ApbTokens::new(), + dfll: dfll::DfllToken::new(), + dpll: dpll::DpllToken::new(), + gclks: gclk::GclkTokens::new(), + pclks: pclk::PclkTokens::new(), + xosc: xosc::XoscToken::new(), + xosc32k: xosc32k::Xosc32kTokens::new(), + }; + (buses, clocks, tokens) + } +} diff --git a/hal/src/clock/v2/reset.rs b/hal/src/clock/v2/reset_thumbv7em.rs similarity index 100% rename from hal/src/clock/v2/reset.rs rename to hal/src/clock/v2/reset_thumbv7em.rs From e025f40d4a4e6bd8c03df5ff0204522ad472ce0a Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jul 2025 12:46:02 +1200 Subject: [PATCH 27/75] TODO notes --- hal/src/clock/v2/ahb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/clock/v2/ahb.rs b/hal/src/clock/v2/ahb.rs index 5b0f92c42cf5..76b7ead58f5d 100644 --- a/hal/src/clock/v2/ahb.rs +++ b/hal/src/clock/v2/ahb.rs @@ -420,5 +420,5 @@ define_ahb_types!( Dsu = 3, NvmCtrl = 4, Dmac = 5, - Usb = 6, + Usb = 6, // TODO this should be conditional. Others? ); From e3f08edf297560c9c42442a3c7b90018393a9b6d Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jul 2025 13:42:26 +1200 Subject: [PATCH 28/75] stash 4 APB startup state using macro This could use further work - the macro now takes two booleans to indicate whether the type should be in the ApbTokens and ApbClocks structs, however each type should be in exactly one of those so it would be better for the macro to take a single boolean. --- hal/src/clock/v2/apb.rs | 451 ++++++++++++++-------------------------- 1 file changed, 157 insertions(+), 294 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 517c300cd91c..7f7a7e7fbf8d 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -296,13 +296,22 @@ enum ApbMask { D(ApbDMask), } +/// Define several APB-related types +/// +/// Define the [`DynApbId`], `ApbXMask`, [`ApbTokens`] and [`ApbClks`] types. +/// +/// This macro uses a slight hack to simplify its implementation. It uses +/// `#[cfg(all())]` and `#[cfg(any())]` to represent `#[cfg(true)]` and +/// `#[cfg(false)]`, respectively. We can use this to selectively place each +/// APB type into the [`ApbTokens`] struct or the [`ApbClks`] struct, depending +/// on whether or not the corresponding bit is enabled at power-on reset. macro_rules! define_apb_types { ( $( $Reg:ident { $( $( #[$( $cfg:tt )+] )? - $Type:ident = $BIT:literal, + $Type:ident = ($BIT:literal, $token:ident, $clk:ident) )+ } )+ @@ -367,122 +376,187 @@ macro_rules! define_apb_types { } } } + + /// Set of [`ApbToken`]s for APB clocks that are disabled at power-on reset + pub struct ApbTokens { + $( + $( + $( #[$( $cfg )+] )? + #[cfg($token())] + pub [<$Type:snake>]: ApbToken<$Type>, + )+ + )+ + } + + impl ApbTokens { + /// Create the set of [`ApbToken`]s + /// + /// # Safety + /// + /// All invariants required by `ApbToken::new` must be upheld here as well. + #[inline] + pub(super) unsafe fn new() -> Self { + Self { + $( + $( + $( #[$( $cfg )+] )? + #[cfg($token())] + [<$Type:snake>]: unsafe { ApbToken::new() }, + )+ + )+ + } + } + } + + /// Set of [`ApbClk`]s for APB clocks that are enabled at power-on reset + pub struct ApbClks { + $( + $( + $( #[$( $cfg )+] )? + #[cfg($clk())] + pub [<$Type:snake>]: ApbClk<$Type>, + )+ + )+ + } + + impl ApbClks { + /// Create the set of [`ApbClk`]s + /// + /// # Safety + /// + /// All invariants required by `ApbToken::new` must be upheld here as well. + #[inline] + pub(super) unsafe fn new() -> Self { + Self { + $( + $( + $( #[$( $cfg )+] )? + #[cfg($clk())] + [<$Type:snake>]: ApbClk::new( unsafe { ApbToken::new() } ), + )+ + )+ + } + } + } } }; } +// (N, all, any) => include in clocks not tokens = enabled at power-on #[hal_macro_helper] #[hal_cfg("clock-d5x")] define_apb_types!( A { - Pac0 = 0, - Pm = 1, - Mclk = 2, - RstC = 3, - OscCtrl = 4, - Osc32kCtrl = 5, - SupC = 6, - Gclk = 7, - Wdt = 8, - Rtc = 9, - Eic = 10, - FreqM = 11, - Sercom0 = 12, - Sercom1 = 13, - Tc0 = 14, - Tc1 = 15, + Pac0 = (0, all, any) + Pm = (1, all, any) + Mclk = (2, all, any) + RstC = (3, all, any) + OscCtrl = (4, all, any) + Osc32kCtrl = (5, all, any) + SupC = (6, all, any) + Gclk = (7, all, any) + Wdt = (8, all, any) + Rtc = (9, all, any) + Eic = (10, all, any) + FreqM = (11, any, all) + Sercom0 = (12, any, all) + Sercom1 = (13, any, all) + Tc0 = (14, any, all) + Tc1 = (15, any, all) } B { - Usb = 0, - Dsu = 1, - NvmCtrl = 2, - Port = 4, - EvSys = 7, - Sercom2 = 9, - Sercom3 = 10, - Tcc0 = 11, - Tcc1 = 12, - Tc2 = 13, - Tc3 = 14, - RamEcc = 16, + Usb = (0, any, all) + Dsu = (1, all, any) + NvmCtrl = (2, all, any) + Port = (4, all, any) + EvSys = (7, any, all) + Sercom2 = (9, any, all) + Sercom3 = (10, any, all) + Tcc0 = (11, any, all) + Tcc1 = (12, any, all) + Tc2 = (13, any, all) + Tc3 = (14, any, all) + RamEcc = (16, all, any) } C { #[hal_cfg("gmac")] - Gmac = 2, - Tcc2 = 3, + Gmac = (2, all, any) + Tcc2 = (3, any, all) #[hal_cfg("tcc3")] - Tcc3 = 4, + Tcc3 = (4, any, all) #[hal_cfg("tc4")] - Tc4 = 5, + Tc4 = (5, any, all) // TODO double check this is correct #[hal_cfg("tc5")] - Tc5 = 6, - PDec = 7, - Ac = 8, - Aes = 9, - Trng = 10, - Icm = 11, - Qspi = 13, - Ccl = 14, + Tc5 = (6, any, all) + PDec = (7, any, all) + Ac = (8, any, all) + Aes = (9, any, all) + Trng = (10, any, all) + Icm = (11, any, all) + Qspi = (13, all, any) + Ccl = (14, any, all) } D { - Sercom4 = 0, - Sercom5 = 1, + Sercom4 = (0, all, any) + Sercom5 = (1, all, any) #[hal_cfg("sercom6")] - Sercom6 = 2, + Sercom6 = (2, all, any) #[hal_cfg("sercom7")] - Sercom7 = 3, + Sercom7 = (3, all, any) #[hal_cfg("tcc4")] - Tcc4 = 4, + Tcc4 = (4, all, any) #[hal_cfg("tc6")] - Tc6 = 5, + Tc6 = (5, all, any) #[hal_cfg("tc7")] - Tc7 = 6, - Adc0 = 7, - Adc1 = 8, - Dac = 9, + Tc7 = (6, all, any) + Adc0 = (7, all, any) + Adc1 = (8, all, any) + Dac = (9, all, any) #[hal_cfg("i2s")] - I2S = 10, - Pcc = 11, + I2S = (10, all, any) + Pcc = (11, all, any) } ); +// See SAMD21/DA1 datasheet DS40001882H, 16.6.2.6 Peripheral Clock Masking +// TODO I2S needs to be added (disabled on startup) #[hal_cfg(any("clock-d11", "clock-d21"))] define_apb_types!( A { - Pac0 = 0, - Pm = 1, - SysCtrl = 2, - Gclk = 3, - Wdt = 4, - Rtc = 5, - Eic = 6, + Pac0 = (0, all, any) + Pm = (1, all, any) + SysCtrl = (2, all, any) + Gclk = (3, all, any) + Wdt = (4, all, any) + Rtc = (5, all, any) + Eic = (6, all, any) } B { - Pac1 = 0, - Dsu = 1, - NvmCtrl = 2, - Port = 3, - Dmac = 4, - Usb = 5, + Pac1 = (0, all, any) + Dsu = (1, all, any) + NvmCtrl = (2, all, any) + Port = (3, all, any) + Dmac = (4, all, any) + Usb = (5, all, any) // TODO should be conditional } C { - Pac2 = 0, - EvSys = 1, - Sercom0 = 2, - Sercom1 = 3, - Sercom2 = 4, - Sercom3 = 5, - Sercom4 = 6, - Sercom5 = 7, - Tcc0 = 8, - Tcc1 = 9, - Tcc2 = 10, - Tc3 = 11, - Tc4 = 12, - Tc5 = 13, - Adc0 = 16, - Ac = 17, - Dac = 18, + Pac2 = (0, any, all) + EvSys = (1, all, any) // TODO presume this is HMATRIX in data sheet DS40001882H + Sercom0 = (2, any, all) + Sercom1 = (3, any, all) + Sercom2 = (4, any, all) + Sercom3 = (5, any, all) + Sercom4 = (6, any, all) + Sercom5 = (7, any, all) + Tcc0 = (8, any, all) + Tcc1 = (9, any, all) + Tcc2 = (10, any, all) + Tc3 = (11, any, all) + Tc4 = (12, any, all) + Tc5 = (13, any, all) + Adc0 = (16, all, any) + Ac = (17, all, any) + Dac = (18, all, any) } ); @@ -563,214 +637,3 @@ impl ApbClk { self.token } } - -//============================================================================== -// ApbTokens -//============================================================================== - -/// Set of [`ApbToken`]s for APB clocks that are disabled at power-on reset - -#[hal_macro_helper] -pub struct ApbTokens { - #[hal_cfg("clock-d5x")] - pub freq_m: ApbToken, - pub sercom0: ApbToken, - pub sercom1: ApbToken, - #[hal_cfg("clock-d5x")] - pub tc0: ApbToken, - #[hal_cfg("clock-d5x")] - pub tc1: ApbToken, - pub usb: ApbToken, - pub ev_sys: ApbToken, - pub sercom2: ApbToken, - pub sercom3: ApbToken, - pub tcc0: ApbToken, - pub tcc1: ApbToken, - #[hal_cfg("clock-d5x")] - pub tc2: ApbToken, - pub tc3: ApbToken, - #[hal_cfg("tc4")] - pub tc4: ApbToken, - pub tcc2: ApbToken, - #[hal_cfg("tcc3")] - pub tcc3: ApbToken, - #[hal_cfg("tc5")] - pub tc5: ApbToken, - #[hal_cfg("clock-d5x")] - pub p_dec: ApbToken, - pub ac: ApbToken, - #[hal_cfg("clock-d5x")] - pub aes: ApbToken, - #[hal_cfg("clock-d5x")] - pub trng: ApbToken, - #[hal_cfg("clock-d5x")] - pub icm: ApbToken, - #[hal_cfg("clock-d5x")] - pub ccl: ApbToken, - pub sercom4: ApbToken, - pub sercom5: ApbToken, - #[hal_cfg("sercom6")] - pub sercom6: ApbToken, - #[hal_cfg("sercom7")] - pub sercom7: ApbToken, - #[hal_cfg("tcc4")] - pub tcc4: ApbToken, - #[hal_cfg("tc6")] - pub tc6: ApbToken, - #[hal_cfg("tc7")] - pub tc7: ApbToken, - pub adc0: ApbToken, - #[hal_cfg("clock-d5x")] - pub adc1: ApbToken, - pub dac: ApbToken, - #[hal_cfg(all("clock-d5x", "i2s"))] // TODO - pub i2s: ApbToken, - #[hal_cfg("clock-d5x")] - pub pcc: ApbToken, -} - -impl ApbTokens { - /// Create the set of [`ApbToken`]s - /// - /// # Safety - /// - /// All invariants required by `ApbToken::new` must be upheld here as well. - #[inline] - #[hal_macro_helper] - pub(super) unsafe fn new() -> Self { - unsafe { - Self { - #[hal_cfg("clock-d5x")] - freq_m: ApbToken::new(), - sercom0: ApbToken::new(), - sercom1: ApbToken::new(), - #[hal_cfg("tc0")] - tc0: ApbToken::new(), - #[hal_cfg("tc1")] - tc1: ApbToken::new(), - usb: ApbToken::new(), - ev_sys: ApbToken::new(), - sercom2: ApbToken::new(), - sercom3: ApbToken::new(), - tcc0: ApbToken::new(), - tcc1: ApbToken::new(), - #[hal_cfg("tc2")] - tc2: ApbToken::new(), - tc3: ApbToken::new(), - #[hal_cfg("tc4")] - tc4: ApbToken::new(), - tcc2: ApbToken::new(), - #[hal_cfg("tcc3")] - tcc3: ApbToken::new(), - #[hal_cfg("tc5")] - tc5: ApbToken::new(), - #[hal_cfg("clock-d5x")] - p_dec: ApbToken::new(), - ac: ApbToken::new(), - #[hal_cfg("clock-d5x")] - aes: ApbToken::new(), - #[hal_cfg("clock-d5x")] - trng: ApbToken::new(), - #[hal_cfg("clock-d5x")] - icm: ApbToken::new(), - #[hal_cfg("clock-d5x")] - ccl: ApbToken::new(), - sercom4: ApbToken::new(), - sercom5: ApbToken::new(), - #[hal_cfg("sercom6")] - sercom6: ApbToken::new(), - #[hal_cfg("sercom7")] - sercom7: ApbToken::new(), - #[hal_cfg("tcc4")] - tcc4: ApbToken::new(), - #[hal_cfg("tc6")] - tc6: ApbToken::new(), - #[hal_cfg("tc7")] - tc7: ApbToken::new(), - adc0: ApbToken::new(), - #[hal_cfg("clock-d5x")] - adc1: ApbToken::new(), - dac: ApbToken::new(), - #[hal_cfg(all("clock-d5x", "i2s"))] // TODO - i2s: ApbToken::new(), - #[hal_cfg("clock-d5x")] - pcc: ApbToken::new(), - } - } - } -} - -//============================================================================== -// ApbClks -//============================================================================== - -/// Set of [`ApbClk`]s for APB clocks that are enabled at power-on reset -#[hal_macro_helper] -pub struct ApbClks { - pub pac: ApbClk, - pub pm: ApbClk, - #[hal_cfg("clock-d5x")] - pub mclk: ApbClk, - #[hal_cfg("clock-d5x")] - pub rst_c: ApbClk, - #[hal_cfg("clock-d5x")] - pub osc_ctrl: ApbClk, - #[hal_cfg("clock-d5x")] - pub osc32k_ctrl: ApbClk, - #[hal_cfg("clock-d5x")] - pub sup_c: ApbClk, - pub gclk: ApbClk, - pub wdt: ApbClk, - pub rtc: ApbClk, - pub eic: ApbClk, - pub dsu: ApbClk, - pub nvm_ctrl: ApbClk, - pub port: ApbClk, - #[hal_cfg("clock-d5x")] - pub ram_ecc: ApbClk, - #[hal_cfg("gmac")] - pub gmac: ApbClk, - #[hal_cfg("clock-d5x")] - pub qspi: ApbClk, -} - -impl ApbClks { - /// Create the set of [`ApbClk`]s - /// - /// # Safety - /// - /// All invariants required by `ApbToken::new` must be upheld here as well. - #[inline] - #[hal_macro_helper] - pub(super) unsafe fn new() -> Self { - unsafe { - ApbClks { - pac: ApbClk::new(ApbToken::new()), - pm: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - mclk: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - rst_c: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - osc_ctrl: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - osc32k_ctrl: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - sup_c: ApbClk::new(ApbToken::new()), - gclk: ApbClk::new(ApbToken::new()), - wdt: ApbClk::new(ApbToken::new()), - rtc: ApbClk::new(ApbToken::new()), - eic: ApbClk::new(ApbToken::new()), - dsu: ApbClk::new(ApbToken::new()), - nvm_ctrl: ApbClk::new(ApbToken::new()), - port: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - ram_ecc: ApbClk::new(ApbToken::new()), - #[hal_cfg("gmac")] - gmac: ApbClk::new(ApbToken::new()), - #[hal_cfg("clock-d5x")] - qspi: ApbClk::new(ApbToken::new()), - } - } - } -} From 054d56ece22032e47efeeac5be5a28f9ab553299 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 25 Jul 2025 11:06:24 +1200 Subject: [PATCH 29/75] Fixes in APB for D11/D21 --- hal/src/clock/v2/apb.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 7f7a7e7fbf8d..dab3f3e11d76 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -518,8 +518,8 @@ define_apb_types!( } ); -// See SAMD21/DA1 datasheet DS40001882H, 16.6.2.6 Peripheral Clock Masking -// TODO I2S needs to be added (disabled on startup) +// SAMD21/DA1 datasheet DS40001882H, Table 12-1. Peripherals Configuration +// Summary TODO I2S needs to be added (disabled on startup) #[hal_cfg(any("clock-d11", "clock-d21"))] define_apb_types!( A { @@ -541,7 +541,7 @@ define_apb_types!( } C { Pac2 = (0, any, all) - EvSys = (1, all, any) // TODO presume this is HMATRIX in data sheet DS40001882H + EvSys = (1, any, all) Sercom0 = (2, any, all) Sercom1 = (3, any, all) Sercom2 = (4, any, all) @@ -554,9 +554,9 @@ define_apb_types!( Tc3 = (11, any, all) Tc4 = (12, any, all) Tc5 = (13, any, all) - Adc0 = (16, all, any) - Ac = (17, all, any) - Dac = (18, all, any) + Adc0 = (16, any, all) + Ac = (17, any, all) + Dac = (18, any, all) } ); From 88230b1e79f3e5f6db1b042ac6ec1238834a263c Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 25 Jul 2025 13:17:59 +1200 Subject: [PATCH 30/75] partial! stash 4 - gclk There's still some stuff to do, GclkIo etc. --- atsamd-hal-macros/devices.yaml | 6 +++--- hal/src/clock/v2/gclk.rs | 28 ++++++++++------------------ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/atsamd-hal-macros/devices.yaml b/atsamd-hal-macros/devices.yaml index 763d74a1003b..667c98742e38 100644 --- a/atsamd-hal-macros/devices.yaml +++ b/atsamd-hal-macros/devices.yaml @@ -21,7 +21,7 @@ families: - serial-numbers - dsu - clock - - gclk + - gclk: { count: 6 } - pm - sysctrl - wdt @@ -53,7 +53,7 @@ families: - serial-numbers - dsu - clock - - gclk + - gclk: { count: 8 } - pm - sysctrl - wdt @@ -96,7 +96,7 @@ families: - cmcc - dsu - clock - - gclk + - gclk: { count: 12 } - mclk - rstc - ramecc diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 01d45f60f903..901fe44ebd59 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -335,7 +335,7 @@ //! [`Pins`]: crate::gpio::Pins //! [`Sercom0`]: crate::sercom::Sercom0 -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::cmp::max; use core::marker::PhantomData; @@ -544,26 +544,12 @@ impl GclkToken { // DynGclkId //============================================================================== -/// Value-level enum identifying one of 12 possible [`Gclk`]s +/// Value-level enum identifying one of the possible [`Gclk`]s /// -/// The variants of this enum identify one of the 12 possible generic clock -/// generators. +/// The variants of this enum identify one generic clock generator. /// /// `DynGclkId` is the value-level equivalent of [`GclkId`]. -#[hal_cfg(any("clock-d11", "clock-d21"))] -pub enum DynGclkId { - Gclk0, - Gclk1, - Gclk2, - Gclk3, - Gclk4, - Gclk5, - Gclk6, - Gclk7, - Gclk8, -} - -#[hal_cfg("clock-d5x")] +#[hal_macro_helper] pub enum DynGclkId { Gclk0, Gclk1, @@ -571,11 +557,17 @@ pub enum DynGclkId { Gclk3, Gclk4, Gclk5, + #[hal_cfg("gclk6")] Gclk6, + #[hal_cfg("gclk7")] Gclk7, + #[hal_cfg("gclk8")] Gclk8, + #[hal_cfg("gclk9")] Gclk9, + #[hal_cfg("gclk10")] Gclk10, + #[hal_cfg("gclk11")] Gclk11, } From bfa22ddb6f60044cb8d838114901c2e611d2b53b Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 25 Jul 2025 16:10:20 +1200 Subject: [PATCH 31/75] Remove with_gclk_max_expr!() --- hal/src/clock/v2/gclk.rs | 200 +++++++++++++++++++++++---------------- hal/src/clock/v2/pclk.rs | 30 ++++-- 2 files changed, 142 insertions(+), 88 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 901fe44ebd59..babe4ad1ccd2 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -340,7 +340,6 @@ use core::cmp::max; use core::marker::PhantomData; use paste::paste; -use seq_macro::seq; use typenum::{U0, U1}; use crate::pac; @@ -629,50 +628,43 @@ impl GclkId for Gclk1Id { type Divider = GclkDiv16; } -macro_rules! with_gclk_max { - ($N:ident in $start:literal ..= max $mac:tt) => { - #[hal_cfg("clock-d5x")] - seq!($N in $start..=11 $mac); - #[hal_cfg(any("clock-d11", "clock-d21"))] - seq!($N in $start..=8 $mac); - }; -} - -#[hal_cfg("clock-d5x")] -macro_rules! with_gclk_max_expr { - ($N:ident in $start:literal ..= max $mac:tt) => { - seq!($N in $start..=11 $mac) - }; -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -macro_rules! with_gclk_max_expr { - ($N:ident in $start:literal ..= max $mac:tt) => { - seq!($N in $start..=8 $mac) - }; -} - -pub(super) use with_gclk_max_expr; - -with_gclk_max!(N in 2..=max { - paste! { - /// Type-level variant of [`GclkId`] representing the identity of - #[doc = "GCLK" N] - /// - /// See the documentation on [type-level programming] and specifically - /// [type-level enums] for more details. - /// - /// [type-level programming]: crate::typelevel - /// [type-level enums]: crate::typelevel#type-level-enums - pub enum [] {} - impl Sealed for [] {} - impl GclkId for [] { - const DYN: DynGclkId = DynGclkId::Gclk~N; - const NUM: usize = N; - type Divider = GclkDiv8; +macro_rules! make_gclk_id { + ($num:literal) => { + paste! { + #[doc = GCLK $num] + /// + /// See the documentation on [type-level programming] and specifically + /// [type-level enums] for more details. + /// + /// [type-level programming]: crate::typelevel + /// [type-level enums]: crate::typelevel#type-level-enums + pub enum [] {} + impl Sealed for [] {} + impl GclkId for [] { + const DYN: DynGclkId = DynGclkId::[]; + const NUM: usize = $num; + type Divider = GclkDiv8; + } } } -}); +} + +make_gclk_id!(2); +make_gclk_id!(3); +make_gclk_id!(4); +make_gclk_id!(5); +#[hal_cfg("gclk6")] +make_gclk_id!(6); +#[hal_cfg("gclk7")] +make_gclk_id!(7); +#[hal_cfg("gclk8")] +make_gclk_id!(8); +#[hal_cfg("gclk9")] +make_gclk_id!(9); +#[hal_cfg("gclk10")] +make_gclk_id!(10); +#[hal_cfg("gclk11")] +make_gclk_id!(11); //============================================================================== // GclkDivider @@ -1135,15 +1127,35 @@ pub type Gclk0 = Gclk; /// on [`EnabledGclk0`] to configure the `Gclk` while it is actively running. pub type EnabledGclk0 = EnabledGclk; -with_gclk_max!(G in 1..=max { - paste! { - /// Type alias for the corresponding [`Gclk`] - pub type Gclk~G = Gclk<[], I>; - - /// Type alias for the corresponding [`EnabledGclk`] - pub type EnabledGclk~G = EnabledGclk<[], I, N>; +macro_rules! make_gclk { + ($num:literal) => { + paste! { + /// Type alias for the corresponding [`Gclk`] + pub type [] = Gclk<[], I>; + + /// Type alias for the corresponding [`EnabledGclk`] + pub type [] = EnabledGclk<[], I, N>; + } } -}); +} + +make_gclk!(1); +make_gclk!(2); +make_gclk!(3); +make_gclk!(4); +make_gclk!(5); +#[hal_cfg("gclk6")] +make_gclk!(6); +#[hal_cfg("gclk7")] +make_gclk!(7); +#[hal_cfg("gclk8")] +make_gclk!(8); +#[hal_cfg("gclk9")] +make_gclk!(9); +#[hal_cfg("gclk10")] +make_gclk!(10); +#[hal_cfg("gclk11")] +make_gclk!(11); impl Gclk where @@ -1483,38 +1495,66 @@ where // Tokens //============================================================================== -with_gclk_max!(N in 1..=max { - paste! { - /// Set of [`GclkToken`]s representing the disabled [`Gclk`]s at - /// power-on reset - pub struct GclkTokens { - #( - /// [`GclkToken`] for - #[doc = "[`Gclk" N "`]"] - pub gclk~N: GclkToken<[]>, - )* - } +/// Set of [`GclkToken`]s representing the disabled [`Gclk`]s at +/// power-on reset +#[hal_macro_helper] +pub struct GclkTokens { + pub gclk0: GclkToken, + pub gclk1: GclkToken, + pub gclk2: GclkToken, + pub gclk3: GclkToken, + pub gclk4: GclkToken, + pub gclk5: GclkToken, + #[hal_cfg("gclk6")] + pub gclk6: GclkToken, + #[hal_cfg("gclk7")] + pub gclk7: GclkToken, + #[hal_cfg("gclk8")] + pub gclk8: GclkToken, + #[hal_cfg("gclk9")] + pub gclk9: GclkToken, + #[hal_cfg("gclk10")] + pub gclk10: GclkToken, + #[hal_cfg("gclk11")] + pub gclk11: GclkToken, +} - impl GclkTokens { - /// Create the set of [`GclkToken`]s - /// - /// # Safety - /// - /// All of the invariants required by `GclkToken::new` must be - /// upheld here as well. - #[inline] - #[allow(unreachable_code)] // TODO remove when todo is removed - pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { - // Use auto wait states - //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); - todo!(); - GclkTokens { - #( gclk~N: unsafe {GclkToken::new()}, )* - } - } +#[hal_macro_helper] +impl GclkTokens { + /// Create the set of [`GclkToken`]s + /// + /// # Safety + /// + /// All of the invariants required by `GclkToken::new` must be + /// upheld here as well. + #[inline] + #[allow(unreachable_code)] // TODO remove when todo is removed + pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { + // Use auto wait states + //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); + todo!(); + GclkTokens { + gclk0: unsafe {GclkToken::new()}, + gclk1: unsafe {GclkToken::new()}, + gclk2: unsafe {GclkToken::new()}, + gclk3: unsafe {GclkToken::new()}, + gclk4: unsafe {GclkToken::new()}, + gclk5: unsafe {GclkToken::new()}, + #[hal_cfg("gclk6")] + gclk6: unsafe {GclkToken::new()}, + #[hal_cfg("gclk7")] + gclk7: unsafe {GclkToken::new()}, + #[hal_cfg("gclk8")] + gclk8: unsafe {GclkToken::new()}, + #[hal_cfg("gclk9")] + gclk9: unsafe {GclkToken::new()}, + #[hal_cfg("gclk10")] + gclk10: unsafe {GclkToken::new()}, + #[hal_cfg("gclk11")] + gclk11: unsafe {GclkToken::new()}, } } -}); +} //============================================================================== // GclkOut diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index cc82ef1d41d3..b19402d381da 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -89,7 +89,7 @@ use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; use super::Source; -use super::gclk::{DynGclkId, GclkId, with_gclk_max_expr}; +use super::gclk::{DynGclkId, GclkId}; //============================================================================== // PclkToken @@ -419,15 +419,29 @@ pub trait PclkId: Sealed { pub type DynPclkSourceId = DynGclkId; /// Convert from [`DynPclkSourceId`] to the equivalent [PAC](crate::pac) type +#[hal_macro_helper] impl From for Genselect { fn from(source: DynPclkSourceId) -> Self { - with_gclk_max_expr!(N in 0..=max { - match source { - #( - DynGclkId::Gclk~N => Genselect::Gclk~N, - )* - } - }) + match source { + DynPclkSourceId::Gclk0 => Genselect::Gclk0, + DynPclkSourceId::Gclk1 => Genselect::Gclk1, + DynPclkSourceId::Gclk2 => Genselect::Gclk2, + DynPclkSourceId::Gclk3 => Genselect::Gclk3, + DynPclkSourceId::Gclk4 => Genselect::Gclk4, + DynPclkSourceId::Gclk5 => Genselect::Gclk5, + #[hal_cfg("gclk6")] + DynPclkSourceId::Gclk6 => Genselect::Gclk6, + #[hal_cfg("gclk7")] + DynPclkSourceId::Gclk7 => Genselect::Gclk7, + #[hal_cfg("gclk8")] + DynPclkSourceId::Gclk8 => Genselect::Gclk8, + #[hal_cfg("gclk9")] + DynPclkSourceId::Gclk9 => Genselect::Gclk9, + #[hal_cfg("gclk10")] + DynPclkSourceId::Gclk10 => Genselect::Gclk10, + #[hal_cfg("gclk11")] + DynPclkSourceId::Gclk11 => Genselect::Gclk11, + } } } From 3d3ca3d4c8326597b7ed597f2f46a1b87ce28c95 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jul 2025 15:28:24 +1200 Subject: [PATCH 32/75] stash 5 - osc --- hal/src/clock/v2/osc.rs | 168 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 hal/src/clock/v2/osc.rs diff --git a/hal/src/clock/v2/osc.rs b/hal/src/clock/v2/osc.rs new file mode 100644 index 000000000000..1f13f4552410 --- /dev/null +++ b/hal/src/clock/v2/osc.rs @@ -0,0 +1,168 @@ +use crate::pac::sysctrl::osc8m::{FRANGESELECT_A, PRESCSELECT_A}; +use crate::pac::sysctrl::OSC8M; +use crate::pac::SYSCTRL; + +use fugit::RateExtU32; +use crate::time::Hertz; +use crate::typelevel::Sealed; + +use super::{Enabled, Source}; + +pub struct OscToken(()); + +impl OscToken { + pub(super) unsafe fn new() -> Self { + Self(()) + } + + fn osc8m(&self) -> &OSC8M { + unsafe { &(*SYSCTRL::PTR).osc8m } + } + + fn enable(&mut self, settings: Settings) { + self.osc8m().modify(|_, w| { + if let Some(freq_range) = settings.freq_range { + w.frange().variant(freq_range.into()); + } + if let Some(calibration) = settings.calibration { + // Safety: The PAC will truncate the value to 12 bits, + // and all 12-bit values are valid + unsafe { w.calib().bits(calibration) }; + } + w.presc().variant(settings.prescaler.into()); + w.ondemand().bit(settings.on_demand); + w.runstdby().bit(settings.run_standby); + w.enable().set_bit() + }); + } + + fn disable(&mut self) { + self.osc8m().modify(|_, w| w.enable().clear_bit()) + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +struct Settings { + freq_range: Option, + calibration: Option, + prescaler: Prescaler, + on_demand: bool, + run_standby: bool, +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum FreqRange { + FourToSix, + SixToEight, + EightToEleven, + ElevenToFifteen, +} + +impl From for FRANGESELECT_A { + fn from(freq_range: FreqRange) -> Self { + match freq_range { + FreqRange::FourToSix => Self::_0, + FreqRange::SixToEight => Self::_1, + FreqRange::EightToEleven => Self::_2, + FreqRange::ElevenToFifteen => Self::_3, + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Prescaler { + One, + Two, + Four, + Eight, +} + +impl From for PRESCSELECT_A { + fn from(prescaler: Prescaler) -> Self { + match prescaler { + Prescaler::One => Self::_0, + Prescaler::Two => Self::_1, + Prescaler::Four => Self::_2, + Prescaler::Eight => Self::_3, + } + } +} + +pub enum OscId {} + +impl Sealed for OscId {} + +pub struct Osc { + token: OscToken, + settings: Settings, +} + +impl Osc { + pub fn new(token: OscToken) -> Self { + let settings = Settings { + freq_range: None, + calibration: None, + prescaler: Prescaler::Eight, + on_demand: true, + run_standby: false, + }; + Self { token, settings } + } + + pub fn freq_range(mut self, freq_range: FreqRange) -> Self { + self.settings.freq_range = Some(freq_range); + self + } + + pub fn calibration(mut self, calibration: u16) -> Self { + self.settings.calibration = Some(calibration); + self + } + + pub fn prescaler(mut self, prescaler: Prescaler) -> Self { + self.settings.prescaler = prescaler; + self + } + + pub fn on_demand(mut self, on_demand: bool) -> Self { + self.settings.on_demand = on_demand; + self + } + + pub fn run_standby(mut self, run_standby: bool) -> Self { + self.settings.run_standby = run_standby; + self + } + + pub fn freq(&self) -> Hertz { + let div = match self.settings.prescaler { + Prescaler::One => 1, + Prescaler::Two => 2, + Prescaler::Four => 4, + Prescaler::Eight => 8, + }; + (8_000_000u32 / div).Hz() + } + + pub fn enable(mut self) -> Enabled { + self.token.enable(self.settings); + Enabled::new(self) + } +} + +pub type EnabledOsc = Enabled; + +impl EnabledOsc { + pub fn disable(mut self) -> Osc { + self.0.token.disable(); + self.0 + } +} + +impl Source for EnabledOsc { + type Id = OscId; + + fn freq(&self) -> Hertz { + self.0.freq() + } +} From 9c55928559931933af301be226c4cb006c67f17b Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 25 Jul 2025 14:15:38 +1200 Subject: [PATCH 33/75] osc fixes and partial stash 5 - reset --- hal/src/clock/v2.rs | 4 ++++ hal/src/clock/v2/osc.rs | 17 ++++++++++------- hal/src/clock/v2/reset_thumbv6m.rs | 15 +++++++++------ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 0e36b34e010d..a998a14d758f 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -866,6 +866,10 @@ pub mod apb; pub mod dfll; pub mod dpll; pub mod gclk; +#[hal_module( + any("clock-d11", "clock-d21") => "v2/osc.rs", +)] +pub mod osc {} pub mod osculp32k; pub mod pclk; #[hal_module( diff --git a/hal/src/clock/v2/osc.rs b/hal/src/clock/v2/osc.rs index 1f13f4552410..71fb9013e354 100644 --- a/hal/src/clock/v2/osc.rs +++ b/hal/src/clock/v2/osc.rs @@ -1,6 +1,8 @@ -use crate::pac::sysctrl::osc8m::{FRANGESELECT_A, PRESCSELECT_A}; -use crate::pac::sysctrl::OSC8M; -use crate::pac::SYSCTRL; +//! Open-loop 8MHz oscillator + +use crate::pac::sysctrl::osc8m::{Frangeselect, Prescselect}; +use crate::pac::sysctrl::Osc8m; +use crate::pac::Sysctrl; use fugit::RateExtU32; use crate::time::Hertz; @@ -15,8 +17,8 @@ impl OscToken { Self(()) } - fn osc8m(&self) -> &OSC8M { - unsafe { &(*SYSCTRL::PTR).osc8m } + fn osc8m(&self) -> &Osc8m { + unsafe { &(*Sysctrl::PTR).osc8m() } } fn enable(&mut self, settings: Settings) { @@ -51,6 +53,7 @@ struct Settings { } #[derive(Clone, Copy, PartialEq, Eq)] +/// Frequency ranges in Megahertz pub enum FreqRange { FourToSix, SixToEight, @@ -58,7 +61,7 @@ pub enum FreqRange { ElevenToFifteen, } -impl From for FRANGESELECT_A { +impl From for Frangeselect { fn from(freq_range: FreqRange) -> Self { match freq_range { FreqRange::FourToSix => Self::_0, @@ -77,7 +80,7 @@ pub enum Prescaler { Eight, } -impl From for PRESCSELECT_A { +impl From for Prescselect { fn from(prescaler: Prescaler) -> Self { match prescaler { Prescaler::One => Self::_0, diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index 854a1b16b6b8..ead7f4a858d1 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -20,7 +20,7 @@ use super::*; pub struct Pac { gclk: Gclk, pm: Pm, - sysctrl: Syctrl, + sysctrl: Sysctrl, } impl Pac { @@ -35,7 +35,7 @@ impl Pac { /// /// Directly configuring clocks through the PAC API can invalidate the /// type-level guarantees of the `clock` module API. - pub unsafe fn steal(self) -> (Gclk, Pm, Syctrl) { + pub unsafe fn steal(self) -> (Gclk, Pm, Sysctrl) { (self.gclk, self.pm, self.sysctrl) } } @@ -88,9 +88,11 @@ pub struct Clocks { /// Enabled APB clocks pub apbs: apb::ApbClks, /// Main system clock, driven at 1 MHz by the OSC8M divided by 8 - pub gclk0: Enabled, U1>, + pub gclk0: Enabled, U1>, /// GCLK2, driven at 32 kHz by the OSCULP pub gclk2: Enabled, U1>, + /// 8 MHz internal oscillator, divided by 8 for a 1 MHz output + pub osc: Enabled, /// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2) pub wdt: pclk::Pclk, /// Always-enabled OSCULP oscillators @@ -132,7 +134,7 @@ pub struct Tokens { /// /// See the [module-level documentation](super) for more details. #[inline] -pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Syctrl) -> (Buses, Clocks, Tokens) { +pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Clocks, Tokens) { // Safety: No bus, clock or token is instantiated more than once unsafe { let buses = Buses { @@ -140,8 +142,8 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Syctrl) -> (Buses, Clo apb: apb::Apb::new(), }; let pac = Pac { gclk, pm, sysctrl }; - let osc8m = Enabled::new(osc8m::Osc8m::new(osc8m::Osc8mToken::new())); - let (gclk0, osc8m) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc8m); + let osc = Enabled::<_, U0>::new(osc::Osc::new(osc::OscToken::new())); + let (gclk0, osc8m) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc); let gclk0 = Enabled::new(gclk0); let base = osculp32k::OscUlp32kBase::new(); let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); @@ -160,6 +162,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Syctrl) -> (Buses, Clo apbs: apb::ApbClks::new(), gclk0, gclk2, + osc, wdt, osculp32k, }; From 915b3986033da0b15f622a729ae278affd8cdcb9 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 26 Jul 2025 10:35:20 +1200 Subject: [PATCH 34/75] stash 4 - dfll --- hal/src/clock/v2/dfll.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index f10f725922e4..daa623f139d3 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -276,6 +276,7 @@ use atsamd_hal_macros::hal_cfg; #[hal_cfg("clock-d5x")] mod imports { + pub use crate::pac::Oscctrl as PERIPHERAL; pub use crate::pac::oscctrl::{ Dfllctrla as Dfllctrl, Dfllctrlb, Dfllmul, Dfllsync, RegisterBlock, }; @@ -283,6 +284,7 @@ mod imports { #[hal_cfg(any("clock-d11", "clock-d21"))] mod imports { + pub use crate::pac::Sysctrl as PERIPHERAL; pub use crate::pac::sysctrl::{Dfllctrl, Dfllmul, Dfllsync, RegisterBlock}; } @@ -329,14 +331,7 @@ impl DfllToken { // of registers for the DFLL, and we use a shared reference to the // register block. See the notes on `Token` types and memory safety in // the root of the `clock` module for more details. - #[hal_cfg("clock-d5x")] - unsafe { - &*crate::pac::Oscctrl::PTR - } - #[hal_cfg(any("clock-d11", "clock-d21"))] - unsafe { - &*crate::pac::Sysctrl::PTR - } + unsafe { &*PERIPHERAL::PTR } } #[hal_cfg("clock-d5x")] From 7f985fb7cba416a4ced0bf5d1f238b9f02df3947 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 26 Jul 2025 16:15:29 +1200 Subject: [PATCH 35/75] fixup gclk --- hal/src/clock/v2/gclk.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index babe4ad1ccd2..ac6ac474a123 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -646,7 +646,7 @@ macro_rules! make_gclk_id { type Divider = GclkDiv8; } } - } + }; } make_gclk_id!(2); @@ -1132,11 +1132,11 @@ macro_rules! make_gclk { paste! { /// Type alias for the corresponding [`Gclk`] pub type [] = Gclk<[], I>; - + /// Type alias for the corresponding [`EnabledGclk`] pub type [] = EnabledGclk<[], I, N>; } - } + }; } make_gclk!(1); @@ -1534,24 +1534,24 @@ impl GclkTokens { //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); todo!(); GclkTokens { - gclk0: unsafe {GclkToken::new()}, - gclk1: unsafe {GclkToken::new()}, - gclk2: unsafe {GclkToken::new()}, - gclk3: unsafe {GclkToken::new()}, - gclk4: unsafe {GclkToken::new()}, - gclk5: unsafe {GclkToken::new()}, + gclk0: unsafe { GclkToken::new() }, + gclk1: unsafe { GclkToken::new() }, + gclk2: unsafe { GclkToken::new() }, + gclk3: unsafe { GclkToken::new() }, + gclk4: unsafe { GclkToken::new() }, + gclk5: unsafe { GclkToken::new() }, #[hal_cfg("gclk6")] - gclk6: unsafe {GclkToken::new()}, + gclk6: unsafe { GclkToken::new() }, #[hal_cfg("gclk7")] - gclk7: unsafe {GclkToken::new()}, + gclk7: unsafe { GclkToken::new() }, #[hal_cfg("gclk8")] - gclk8: unsafe {GclkToken::new()}, + gclk8: unsafe { GclkToken::new() }, #[hal_cfg("gclk9")] - gclk9: unsafe {GclkToken::new()}, + gclk9: unsafe { GclkToken::new() }, #[hal_cfg("gclk10")] - gclk10: unsafe {GclkToken::new()}, + gclk10: unsafe { GclkToken::new() }, #[hal_cfg("gclk11")] - gclk11: unsafe {GclkToken::new()}, + gclk11: unsafe { GclkToken::new() }, } } } From 5033501f2a9cb1bdc97697181a36891f3d9de155 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 26 Jul 2025 20:09:54 +1200 Subject: [PATCH 36/75] stash 4 - types --- hal/src/clock/v2/types.rs | 260 ++++++++++++++++++++++---------------- 1 file changed, 154 insertions(+), 106 deletions(-) diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index 2dca13a9a3da..0ff95ac3a475 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -21,30 +21,6 @@ use atsamd_hal_macros::hal_cfg; use crate::typelevel::Sealed; -#[hal_cfg("sercom0")] -pub use crate::sercom::Sercom0; - -#[hal_cfg("sercom1")] -pub use crate::sercom::Sercom1; - -#[hal_cfg("sercom2")] -pub use crate::sercom::Sercom2; - -#[hal_cfg("sercom3")] -pub use crate::sercom::Sercom3; - -#[hal_cfg("sercom4")] -pub use crate::sercom::Sercom4; - -#[hal_cfg("sercom5")] -pub use crate::sercom::Sercom5; - -#[hal_cfg("sercom6")] -pub use crate::sercom::Sercom6; - -#[hal_cfg("sercom7")] -pub use crate::sercom::Sercom7; - macro_rules! create_types { ( $( @@ -63,100 +39,172 @@ macro_rules! create_types { }; } +// AHB types +create_types!(Dmac); +create_types!(Dsu); +create_types!(Hpb0, Hpb1, Hpb2); +create_types!(NvmCtrl); +create_types!(Usb); + +// APB types create_types!(Ac); create_types!(Adc0); -#[hal_cfg("clock-d5x")] -create_types!(Adc1); -#[hal_cfg("clock-d5x")] -create_types!(Aes); -#[hal_cfg("can0")] -create_types!(Can0); -#[hal_cfg("can1")] -create_types!(Can1); -#[hal_cfg("clock-d5x")] -create_types!(Ccl); -#[hal_cfg("clock-d5x")] -create_types!(Cmcc); -#[hal_cfg("clock-d5x")] -create_types!(CM4Trace); create_types!(Dac); -create_types!(Dmac); -create_types!(Dsu); create_types!(Eic); -create_types!( - EvSys, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, - EvSys11 -); -#[hal_cfg("clock-d5x")] -create_types!(FreqM); -#[hal_cfg("clock-d5x")] -create_types!(FreqMMeasure); -#[hal_cfg("clock-d5x")] -create_types!(FreqMReference); +create_types!(EvSys); create_types!(Gclk); -#[hal_cfg("gmac")] -create_types!(Gmac); -create_types!(Hpb0, Hpb1, Hpb2); -#[hal_cfg("clock-d5x")] -create_types!(Hpb3); -#[hal_cfg("clock-d5x")] -create_types!(Icm); -#[hal_cfg("clock-d5x")] -create_types!(Mclk); -create_types!(NvmCtrl); -#[hal_cfg("clock-d5x")] -create_types!(NvmCtrlSmeeProm, NvmCtrlCache); -#[hal_cfg("clock-d5x")] // TODO was min-samd51j in Bradley's work -create_types!(I2S, I2S0, I2S1); -#[hal_cfg("clock-d5x")] -create_types!(OscCtrl); -#[hal_cfg("clock-d5x")] -create_types!(Osc32kCtrl); +#[hal_cfg("i2s")] +create_types!(I2S); create_types!(Pac0); -#[hal_cfg(any("clock-d11", "clock-d21"))] -create_types!(Pac1, Pac2); -#[hal_cfg("clock-d5x")] -create_types!(Pcc); -#[hal_cfg("clock-d5x")] -create_types!(PDec); create_types!(Pm); create_types!(Port); -#[hal_cfg("clock-d5x")] -create_types!(Pukcc); -#[hal_cfg("clock-d5x")] -create_types!(Qspi, Qspi2x); -#[hal_cfg("clock-d5x")] -create_types!(RamEcc); -#[hal_cfg("clock-d5x")] -create_types!(RstC); create_types!(Rtc); -#[hal_cfg("clock-d5x")] -create_types!(Sdhc0); -#[hal_cfg("sdhc1")] -create_types!(Sdhc1); -create_types!(SlowClk); -#[hal_cfg("clock-d5x")] -create_types!(SupC); -#[hal_cfg(any("clock-d11", "clock-d21"))] -create_types!(SysCtrl); -#[hal_cfg("clock-d5x")] -create_types!(Tc0Tc1, Tc0, Tc1); -#[hal_cfg("clock-d5x")] -create_types!(Tc2Tc3, Tc2, Tc3); -#[hal_cfg(all("tc4", "tc5"))] -create_types!(Tc4Tc5, Tc4, Tc5); -#[hal_cfg(all("tc6", "tc7"))] -create_types!(Tc6Tc7, Tc6, Tc7); -create_types!(Tcc0Tcc1, Tcc0, Tcc1); -#[hal_cfg("clock-d5x")] -create_types!(Tcc2Tcc3, Tcc2); +#[hal_cfg("sercom0")] +pub use crate::sercom::Sercom0; +#[hal_cfg("sercom1")] +pub use crate::sercom::Sercom1; +#[hal_cfg("sercom2")] +pub use crate::sercom::Sercom2; +#[hal_cfg("sercom3")] +pub use crate::sercom::Sercom3; +#[hal_cfg("sercom4")] +pub use crate::sercom::Sercom4; +#[hal_cfg("sercom5")] +pub use crate::sercom::Sercom5; +#[hal_cfg("sercom6")] +pub use crate::sercom::Sercom6; +#[hal_cfg("sercom7")] +pub use crate::sercom::Sercom7; + +#[hal_cfg("tc0")] +create_types!(Tc0); +#[hal_cfg("tc1")] +create_types!(Tc1); +#[hal_cfg("tc2")] +create_types!(Tc2); +#[hal_cfg("tc3")] +create_types!(Tc3); +#[hal_cfg("tc4")] +create_types!(Tc4); +#[hal_cfg("tc5")] +create_types!(Tc5); +#[hal_cfg("tc6")] +create_types!(Tc6); +#[hal_cfg("tc7")] +create_types!(Tc7); + +#[hal_cfg("tcc0")] +create_types!(Tcc0); +#[hal_cfg("tcc1")] +create_types!(Tcc1); +#[hal_cfg("tcc2")] +create_types!(Tcc2); #[hal_cfg("tcc3")] create_types!(Tcc3); #[hal_cfg("tcc4")] create_types!(Tcc4); + +// TODO +#[hal_cfg(all("tc0", "tc1"))] +create_types!(Tc0Tc1); +#[hal_cfg(all("tc2", "tc3"))] +create_types!(Tc2Tc3); +#[hal_cfg(all("tc4", "tc5"))] +create_types!(Tc4Tc5); +#[hal_cfg(all("tc6", "tc7"))] +create_types!(Tc6Tc7); + +#[hal_cfg(all("tcc0", "tcc1"))] +create_types!(Tcc0Tcc1); +#[hal_cfg(all("tcc2", "tcc3"))] +create_types!(Tcc2Tcc3); + +#[hal_cfg(all("tcc2", "tc3-d21"))] +create_types!(Tcc2Tc3); + +create_types!(Wdt); + +// PCLK types +// TODO set channel numbers in devices.yaml +create_types!( + EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, + EvSys11 +); +#[hal_cfg("i2s")] +create_types!(I2S0, I2S1); +create_types!(SlowClk); + +#[hal_cfg("clock-d5x")] +mod variant_ahb_types { + use super::{Sealed, hal_cfg}; + + #[hal_cfg("can0")] + create_types!(Can0); + #[hal_cfg("can1")] + create_types!(Can1); + create_types!(Cmcc); + #[hal_cfg("gmac")] + create_types!(Gmac); + create_types!(Hpb3); + create_types!(Icm); + create_types!(NvmCtrlSmeeProm, NvmCtrlCache); + create_types!(Pukcc); + create_types!(Qspi, Qspi2x); + #[hal_cfg("sdhc0")] + create_types!(Sdhc0); + #[hal_cfg("sdhc1")] + create_types!(Sdhc1); +} + +#[hal_cfg("clock-d5x")] +mod variant_apb_types { + use super::Sealed; + + create_types!(Adc1); + create_types!(Aes); + create_types!(Ccl); + create_types!(FreqM); + create_types!(Mclk); + create_types!(OscCtrl); + create_types!(Osc32kCtrl); + create_types!(Pcc); + create_types!(PDec); + create_types!(RamEcc); + create_types!(RstC); + create_types!(SupC); + create_types!(Trng); +} + +#[hal_cfg("clock-d5x")] +mod variant_pclk_types { + use super::Sealed; + + create_types!(CM4Trace); + create_types!(FreqMMeasure); + create_types!(FreqMReference); +} + +#[hal_cfg(any("clock-d11", "clock-d21"))] +mod variant_apb_types { + use super::{Sealed, hal_cfg}; + + #[hal_cfg("clock-d21")] + create_types!(Ac1); + create_types!(Pac1, Pac2); + create_types!(Ptc); + create_types!(SysCtrl); +} + #[hal_cfg(any("clock-d11", "clock-d21"))] -create_types!(Tcc2Tc3, Tcc2, Tc3); +mod variant_pclk_types { + use super::Sealed; + + create_types!(AcDig); + create_types!(AcAna); + create_types!(SercomSlow); +} + #[hal_cfg("clock-d5x")] -create_types!(Trng); -create_types!(Usb); -create_types!(Wdt); +pub use variant_ahb_types::*; +pub use variant_apb_types::*; +pub use variant_pclk_types::*; From d37788a51e665b90a802798a708531e660eb10bc Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 26 Jul 2025 16:16:44 +1200 Subject: [PATCH 37/75] stash 4 - pclk --- hal/src/clock/v2/pclk.rs | 119 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 8 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index b19402d381da..61e038463ea7 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -67,7 +67,6 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use paste::paste; -use seq_macro::seq; use crate::pac; @@ -184,11 +183,20 @@ impl PclkToken

{ /// ``` /// use atsamd_hal::clock::v2::pclk::ids::*; /// ``` + pub mod ids { use atsamd_hal_macros::hal_cfg; - pub use crate::sercom::{Sercom0, Sercom1, Sercom2, Sercom3, Sercom4, Sercom5}; + pub use crate::sercom::{Sercom0, Sercom1}; + #[hal_cfg("sercom2")] + pub use crate::sercom::Sercom2; + #[hal_cfg("sercom3")] + pub use crate::sercom::Sercom3; + #[hal_cfg("sercom4")] + pub use crate::sercom::Sercom4; + #[hal_cfg("sercom5")] + pub use crate::sercom::Sercom5; #[hal_cfg("sercom6")] pub use crate::sercom::Sercom6; #[hal_cfg("sercom7")] @@ -209,8 +217,9 @@ pub mod ids { #[hal_cfg(any("clock-d11", "clock-d21"))] pub use super::super::types::{ - Ac, Adc0, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, - EvSys9, EvSys10, EvSys11, SlowClk, Tcc0Tcc1, Usb, + Ac, AcAna, AcDig, Adc0, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, + EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, Ptc, Rtc, SercomSlow, SlowClk, Tcc0Tcc1, Usb, + Wdt, }; #[hal_cfg("can0")] @@ -225,7 +234,12 @@ pub mod ids { pub use super::super::types::Tc6Tc7; #[hal_cfg("tcc4")] pub use super::super::types::Tcc4; - #[hal_cfg("clock-d5x")] // TODO + + // TODO would it make sense to just pub use super::super::types::* and + // conditionally restrict what types we make there? + #[hal_cfg(all("tcc2", "tc3-d21"))] + pub use super::super::types::Tcc2Tc3; + #[hal_cfg("i2s")] pub use super::super::types::{I2S0, I2S1}; } @@ -265,6 +279,7 @@ use ids::*; /// /// with_pclk_types_ids!(some_macro!(first, second)); /// ``` +#[hal_cfg("clock-d5x")] #[hal_macro_helper] macro_rules! with_pclk_types_ids { ( $some_macro:ident ! ( $( $args:tt )* ) ) => { @@ -272,7 +287,6 @@ macro_rules! with_pclk_types_ids { $( $args )* (DfllId = 0, dfll) (Dpll0Id = 1, dpll0) - #[hal_cfg("clock-d5x")] (Dpll1Id = 2, dpll1) (SlowClk = 3, slow) (Eic = 4, eic) @@ -329,9 +343,9 @@ macro_rules! with_pclk_types_ids { #[hal_cfg("clock-d5x")] (Adc1 = 41, adc1) (Dac = 42, dac) - #[hal_cfg(all("i2s", "clock-d5x"))] + #[hal_cfg("i2s")] (I2S0 = 43, i2s0) - #[hal_cfg(all("i2s", "clock-d5x"))] + #[hal_cfg("i2s")] (I2S1 = 44, i2s1) #[hal_cfg("clock-d5x")] (Sdhc0 = 45, sdhc0) @@ -343,6 +357,95 @@ macro_rules! with_pclk_types_ids { }; } +#[hal_cfg("clock-d21")] +#[hal_macro_helper] +macro_rules! with_pclk_types_ids { + ( $some_macro:ident ! ( $( $args:tt )* ) ) => { + $some_macro!( + $( $args )* + (DfllId = 0, dfll) + (Dpll0Id = 1, dpll) + (SlowClk = 2, slow) + (Wdt = 3, wdt) + (Rtc = 4, rtc) + (Eic = 5, eic) + (Usb = 6, usb) + (EvSys0 = 7, ev_sys0) + (EvSys1 = 8, ev_sys1) + (EvSys2 = 9, ev_sys2) + (EvSys3 = 10, ev_sys3) + (EvSys4 = 11, ev_sys4) + (EvSys5 = 12, ev_sys5) + (EvSys6 = 13, ev_sys6) + (EvSys7 = 14, ev_sys7) + (EvSys8 = 15, ev_sys8) + (EvSys9 = 16, ev_sys9) + (EvSys10 = 17, ev_sys10) + (EvSys11 = 18, ev_sys11) + (SercomSlow = 19, sercom_slow) + (Sercom0 = 20, sercom0) + (Sercom1 = 21, sercom1) + #[hal_cfg("sercom2")] + (Sercom2 = 22, sercom2) + #[hal_cfg("sercom3")] + (Sercom3 = 23, sercom3) + #[hal_cfg("sercom4")] + (Sercom4 = 24, sercom4) + #[hal_cfg("sercom5")] + (Sercom5 = 25, sercom5) + (Tcc0Tcc1 = 26, tcc0_tcc1) + (Tcc2Tc3 = 27, tcc2_tc3) + (Tc4Tc5 = 28, tc4_tc5) + #[hal_cfg(all("tc6", "tc7"))] + (Tc6Tc7 = 29, tc6_tc7) + (Adc0 = 30, adc) + (AcDig = 31, ac_dig) + (AcAna = 32, ac_ana) + (Dac = 33, dac) + (Ptc = 34, ptc) + #[hal_cfg("i2s")] + (I2S0 = 35, i2s0) + #[hal_cfg("i2s")] + (I2S1 = 36, i2s1) + ); + }; +} + +#[hal_cfg("clock-d11")] +#[hal_macro_helper] +macro_rules! with_pclk_types_ids { + ( $some_macro:ident ! ( $( $args:tt )* ) ) => { + $some_macro!( + $( $args )* + (DfllId = 0, dfll) + (Dpll0Id = 1, dpll) + (SlowClk = 2, slow) + (Wdt = 3, wdt) + (Rtc = 4, rtc) + (Eic = 5, eic) + (Usb = 6, usb) + (EvSys0 = 7, ev_sys0) + (EvSys1 = 8, ev_sys1) + (EvSys2 = 9, ev_sys2) + (EvSys3 = 10, ev_sys3) + (EvSys4 = 11, ev_sys4) + (EvSys5 = 12, ev_sys5) + (SercomSlow = 13, sercom_slow) + (Sercom0 = 14, sercom0) + (Sercom1 = 15, sercom1) + #[hal_cfg("sercom2")] + (Sercom2 = 16, sercom2) + (Tcc0 = 17, tcc0) + (Tc1Tc2 = 18, tc1_tc2) + (Adc0 = 19, adc) + (AcDig = 20, ac_dig) + (AcAna = 21, ac_ana) + (Dac = 22, dac) + (Ptc = 23, ptc) + ); + }; +} + //============================================================================== // DynPclkId //============================================================================== From c32916be28b847252d5aa45554f521d0dd68396d Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 27 Jul 2025 19:24:53 +1200 Subject: [PATCH 38/75] stash 4 - xosc and xosc32k --- hal/src/clock/v2/xosc.rs | 18 ++++++++++++------ hal/src/clock/v2/xosc32k.rs | 13 ++++++++++--- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index e5b03253263f..55ac7e2c0ec7 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -212,7 +212,6 @@ use typenum::U0; #[hal_cfg("clock-d5x")] mod imports { pub use super::super::dfll::DfllId; - pub use crate::gpio::{PB22, PB23}; pub use crate::pac::Oscctrl as Peripheral; pub use crate::pac::oscctrl::{Xoscctrl, status::R as STATUS_R}; pub use crate::typelevel::{Decrement, Increment}; @@ -226,7 +225,14 @@ mod imports { use imports::*; -use crate::gpio::{FloatingDisabled, PA14, PA15, Pin, PinId}; +#[hal_cfg("clock-d11")] +pub use crate::gpio::{PA08 as XIn0Id, PA09 as XOut0Id}; +#[hal_cfg("clock-d21")] +pub use crate::gpio::{PA14 as XIn0Id, PA15 as XOut0Id}; +#[hal_cfg("clock-d5x")] +pub use crate::gpio::{PA14 as XIn0Id, PA15 as XOut0Id, PB22 as XIn1Id, PB23 as XOut1Id}; + +use crate::gpio::{FloatingDisabled, Pin, PinId}; use crate::time::Hertz; use crate::typelevel::Sealed; @@ -478,8 +484,8 @@ impl Sealed for Xosc0Id {} impl XoscId for Xosc0Id { const NUM: usize = 0; - type XIn = PA14; - type XOut = PA15; + type XIn = XIn0Id; + type XOut = XOut0Id; } /// Type-level variant of [`XoscId`] representing the identity of XOSC1 @@ -498,8 +504,8 @@ impl Sealed for Xosc1Id {} #[hal_cfg("clock-d5x")] impl XoscId for Xosc1Id { const NUM: usize = 1; - type XIn = PB22; - type XOut = PB23; + type XIn = XIn1Id; + type XOut = XOut1Id; } //============================================================================== diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index 92e61ca9bc90..4df5386e3157 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -362,7 +362,14 @@ mod imports { use imports::*; -use crate::gpio::{FloatingDisabled, PA00, PA01, Pin}; +#[hal_cfg("clock-d21")] +pub use crate::gpio::{PA00 as XIn32Id, PA01 as XOut32Id}; +#[hal_cfg("clock-d5x")] +pub use crate::gpio::{PA00 as XIn32Id, PA01 as XOut32Id}; +#[hal_cfg("clock-d11")] +pub use crate::gpio::{PA08 as XIn32Id, PA09 as XOut32Id}; + +use crate::gpio::{FloatingDisabled, Pin}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; @@ -680,10 +687,10 @@ impl Default for Settings { //============================================================================== /// Type alias for the XOSC32K input [`Pin`] -pub type XIn32 = Pin; +pub type XIn32 = Pin; /// Type alias for the XOSC32K output [`Pin`] -pub type XOut32 = Pin; +pub type XOut32 = Pin; //============================================================================== // SafeClockDiv From 1a9f1ab65e267e639a0996140cb7caa6ee4b1c43 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 27 Jul 2025 21:59:08 +1200 Subject: [PATCH 39/75] Remove nvmctrl from GCLK init f/u stash 4 reset --- hal/src/clock/v2/gclk.rs | 7 +------ hal/src/clock/v2/reset_thumbv7em.rs | 8 +++----- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index ac6ac474a123..7ad12d059e64 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -343,7 +343,6 @@ use paste::paste; use typenum::{U0, U1}; use crate::pac; -use crate::pac::Nvmctrl; use crate::gpio::{self, AlternateH, AnyPin, Pin, PinId}; use crate::pac::gclk::Genctrl; @@ -1528,11 +1527,7 @@ impl GclkTokens { /// All of the invariants required by `GclkToken::new` must be /// upheld here as well. #[inline] - #[allow(unreachable_code)] // TODO remove when todo is removed - pub(super) unsafe fn new(_nvmctrl: &mut Nvmctrl) -> Self { - // Use auto wait states - //nvmctrl.ctrla.modify(|_, w| w.autows().set_bit()); - todo!(); + pub(super) unsafe fn new() -> Self { GclkTokens { gclk0: unsafe { GclkToken::new() }, gclk1: unsafe { GclkToken::new() }, diff --git a/hal/src/clock/v2/reset_thumbv7em.rs b/hal/src/clock/v2/reset_thumbv7em.rs index 6cc535a263a7..b18f607c744f 100644 --- a/hal/src/clock/v2/reset_thumbv7em.rs +++ b/hal/src/clock/v2/reset_thumbv7em.rs @@ -5,7 +5,7 @@ use atsamd_hal_macros::hal_cfg; use typenum::U1; -use crate::pac::{Gclk, Mclk, Nvmctrl, Osc32kctrl, Oscctrl}; +use crate::pac::{Gclk, Mclk, Osc32kctrl, Oscctrl}; use super::*; @@ -177,7 +177,6 @@ pub fn clock_system_at_reset( osc32kctrl: Osc32kctrl, gclk: Gclk, mclk: Mclk, - nvmctrl: &mut Nvmctrl, ) -> (Buses, Clocks, Tokens) { // Safety: No bus, clock or token is instantiated more than once unsafe { @@ -211,7 +210,7 @@ pub fn clock_system_at_reset( apbs: apb::ApbTokens::new(), dpll0: dpll::DpllToken::new(), dpll1: dpll::DpllToken::new(), - gclks: gclk::GclkTokens::new(nvmctrl), + gclks: gclk::GclkTokens::new(), pclks: pclk::PclkTokens::new(), rtcosc: rtcosc::RtcOscToken::new(), xosc0: xosc::XoscToken::new(), @@ -230,7 +229,6 @@ pub fn clock_system_at_reset( osc32kctrl: Osc32kctrl, gclk: Gclk, mclk: Mclk, - nvmctrl: &mut Nvmctrl, ) -> (Buses, Clocks, Tokens) { // Safety: No bus, clock or token is instantiated more than once unsafe { @@ -266,7 +264,7 @@ pub fn clock_system_at_reset( apbs: apb::ApbTokens::new(), dpll0: dpll::DpllToken::new(), dpll1: dpll::DpllToken::new(), - gclks: gclk::GclkTokens::new(nvmctrl), + gclks: gclk::GclkTokens::new(), pclks: pclk::PclkTokens::new(), rtcosc: rtcosc::RtcOscToken::new(), xosc0: xosc::XoscToken::new(), From ec2498cee3e5c86b13a7eae475457df1b91e24c2 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 27 Jul 2025 22:14:24 +1200 Subject: [PATCH 40/75] Fix thumbv6 reset detail --- hal/src/clock/v2/reset_thumbv6m.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index ead7f4a858d1..b2dc0b419ace 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -143,7 +143,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl }; let pac = Pac { gclk, pm, sysctrl }; let osc = Enabled::<_, U0>::new(osc::Osc::new(osc::OscToken::new())); - let (gclk0, osc8m) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc); + let (gclk0, osc) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc); let gclk0 = Enabled::new(gclk0); let base = osculp32k::OscUlp32kBase::new(); let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); From 8a36df525b3c08119d5e243d67fbe5f8872eb56e Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 27 Jul 2025 22:16:29 +1200 Subject: [PATCH 41/75] more stash 4 - gclk --- hal/src/clock/v2/gclk.rs | 50 +++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 7ad12d059e64..f67d7c9928d9 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -354,6 +354,8 @@ use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, use super::dfll::DfllId; // use super::dpll::{Dpll0Id, Dpll1Id}; +#[hal_cfg(any("clock-d11", "clock-d21"))] +use super::osc::OscId; use super::osculp32k::OscUlp32kId; use super::xosc::Xosc0Id; #[hal_cfg("clock-d5x")] @@ -893,15 +895,22 @@ impl> Gclk0Io for I {} /// a given [`Gclk`]. /// /// `DynGclkSourceId` is the value-level equivalent of [`GclkSourceId`]. +#[hal_macro_helper] #[derive(Copy, Clone, PartialEq, Eq)] pub enum DynGclkSourceId { Dfll, Dpll0, + #[hal_cfg("clock-d5x")] Dpll1, Gclk1, GclkIn, + #[hal_cfg(any("clock-d11", "clock-d21"))] + Osc8M, + #[hal_cfg(any("clock-d11", "clock-d21"))] + Osc32k, OscUlp32k, Xosc0, + #[hal_cfg("clock-d5x")] Xosc1, Xosc32k, } @@ -909,31 +918,31 @@ pub enum DynGclkSourceId { impl From for Srcselect { #[hal_cfg("clock-d5x")] fn from(source: DynGclkSourceId) -> Self { - use DynGclkSourceId::*; match source { - Dfll => Srcselect::Dfll, - Dpll0 => Srcselect::Dpll0, - Dpll1 => Srcselect::Dpll1, - Gclk1 => Srcselect::Gclkgen1, - GclkIn => Srcselect::Gclkin, - OscUlp32k => Srcselect::Osculp32k, - Xosc0 => Srcselect::Xosc0, - Xosc1 => Srcselect::Xosc1, - Xosc32k => Srcselect::Xosc32k, + DynGclkSourceId::Dfll => Srcselect::Dfll, + DynGclkSourceId::Dpll0 => Srcselect::Dpll0, + DynGclkSourceId::Dpll1 => Srcselect::Dpll1, + DynGclkSourceId::Gclk1 => Srcselect::Gclkgen1, + DynGclkSourceId::GclkIn => Srcselect::Gclkin, + DynGclkSourceId::OscUlp32k => Srcselect::Osculp32k, + DynGclkSourceId::Xosc0 => Srcselect::Xosc0, + DynGclkSourceId::Xosc1 => Srcselect::Xosc1, + DynGclkSourceId::Xosc32k => Srcselect::Xosc32k, } } #[hal_cfg(any("clock-d11", "clock-d21"))] fn from(source: DynGclkSourceId) -> Self { - use DynGclkSourceId::*; match source { - Dfll => Srcselect::Dfll48m, - Dpll => Srcselect::Dpll96m, - Gclk1 => Srcselect::Gclkgen1, - GclkIn => Srcselect::Gclkin, - OscUlp32k => Srcselect::Osculp32k, - Xosc => Srcselect::Xosc, - Xosc32k => Srcselect::Xosc32k, + DynGclkSourceId::Dfll => Srcselect::Dfll48m, + DynGclkSourceId::Dpll0 => Srcselect::Dpll96m, + DynGclkSourceId::Gclk1 => Srcselect::Gclkgen1, + DynGclkSourceId::GclkIn => Srcselect::Gclkin, + DynGclkSourceId::Osc8M => Srcselect::Osc8m, + DynGclkSourceId::Osc32k => Srcselect::Osc32k, + DynGclkSourceId::OscUlp32k => Srcselect::Osculp32k, + DynGclkSourceId::Xosc0 => Srcselect::Xosc, + DynGclkSourceId::Xosc32k => Srcselect::Xosc32k, } } } @@ -991,6 +1000,11 @@ impl GclkSourceId for OscUlp32kId { const DYN: DynGclkSourceId = DynGclkSourceId::OscUlp32k; type Resource = (); } +#[hal_cfg(any("clock-d11", "clock-d21"))] +impl GclkSourceId for OscId { + const DYN: DynGclkSourceId = DynGclkSourceId::Osc8M; + type Resource = (); +} impl GclkSourceId for Xosc0Id { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; type Resource = (); From caf8daf314f704f7a43932a113c0d1bc9e239ed7 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jul 2025 15:42:05 +1200 Subject: [PATCH 42/75] stash 5 - osc32k --- hal/src/clock/v2.rs | 4 + hal/src/clock/v2/osc32k.rs | 591 +++++++++++++++++++++++++++++ hal/src/clock/v2/reset_thumbv6m.rs | 3 + 3 files changed, 598 insertions(+) create mode 100644 hal/src/clock/v2/osc32k.rs diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index a998a14d758f..eb689d63b6cb 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -870,6 +870,10 @@ pub mod gclk; any("clock-d11", "clock-d21") => "v2/osc.rs", )] pub mod osc {} +#[hal_module( + "sysctrl" => "v2/osc32k.rs", +)] +pub mod osc32k {} pub mod osculp32k; pub mod pclk; #[hal_module( diff --git a/hal/src/clock/v2/osc32k.rs b/hal/src/clock/v2/osc32k.rs new file mode 100644 index 000000000000..7e1c49f0b698 --- /dev/null +++ b/hal/src/clock/v2/osc32k.rs @@ -0,0 +1,591 @@ +//! # Tunable, low-speed and low-power clock source +//! +//! ## Overview +//! +//! TODO this documentation is for the SAMD51 version, not the SYSCTRL sub-peripheral +//! +//! The `osc32k` module provides access to the 32 kHz ultra low power +//! internal oscillator (OSC32K) within the `OSC32KCTRL` peripheral. +//! +//! The `OSC32K` clock is unlike most other clocks. First, it is an internal +//! clock that is always enabled and can't be disabled. And second, it has two +//! separate outputs, one at 32 kHz and another divided down to 1 kHz. Moreover, +//! none, either or both of these outputs can be enabled at any given time. +//! +//! We can see, then, that the `OSC32K` peripheral forms its own, miniature +//! clock tree. There is a 1:N producer clock that is always enabled; and there +//! are two possible consumer clocks that can be independently and optionally +//! enabled. In fact, this structure is illustrated by the `OSC32K` +//! register, which has no regular `ENABLE` bit and two different enable bits +//! for clock output, `EN32K` and `EN1K`. +//! +//! To represent this structure in the type system, we divide the `OSC32K` +//! peripheral into these three clocks. Users get access to the 1:N +//! [`EnabledOsc32kBase`] clock [`Source`] at power-on reset, which can be +//! consumed by both the [`Osc32k`] and [`Osc1k`] clocks. Note that +//! `Osc32k` and `Osc1k` are themselves 1:N clocks as well. +//! +//! ## Write lock +//! +//! Rhe `OSC32K` register has a dedicated write lock bit that will freeze its +//! configuration until the next power-on reset. We implement this by simply +//! dropping the [`Osc32kBase`] clock, which prevents any further access to +//! the `OSC32K` register. +//! +//! ## Example +//! +//! Creating and configuring the OSC32K clocks proceeds according to the +//! principles outlined in the [`clock` module documentation]. It is best shown +//! with an example. +//! +//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking +//! structs. +//! +//! ```no_run +//! use atsamd_hal::{ +//! clock::v2::{ +//! clock_system_at_reset, +//! osc32k::{Osc1k, Osc32k}, +//! }, +//! pac::Peripherals, +//! }; +//! let mut pac = Peripherals::take().unwrap(); +//! let (buses, clocks, tokens) = clock_system_at_reset( +//! pac.OSCCTRL, +//! pac.OSC32KCTRL, +//! pac.GCLK, +//! pac.MCLK, +//! &mut pac.NVMCTRL, +//! ); +//! ``` +//! +//! Next, we can extract the [`EnabledOsc32kBase`] clock from the [`Clocks`] +//! struct and use it to enable the [`Osc1k`] and [`Osc32k`] clocks. +//! +//! ```no_run +//! # use atsamd_hal::{ +//! # clock::v2::{ +//! # clock_system_at_reset, +//! # osc32k::{Osc1k, Osc32k}, +//! # }, +//! # pac::Peripherals, +//! # }; +//! # let mut pac = Peripherals::take().unwrap(); +//! # let (buses, clocks, tokens) = clock_system_at_reset( +//! # pac.OSCCTRL, +//! # pac.OSC32KCTRL, +//! # pac.GCLK, +//! # pac.MCLK, +//! # &mut pac.NVMCTRL, +//! # ); +//! let base = clocks.osc32k_base; +//! let (osc1k, base) = Osc1k::enable(tokens.osc32k.osc1k, base); +//! let (osc32k, base) = Osc32k::enable(tokens.osc32k.osc32k, base); +//! ``` +//! +//! We can then override the calibration value read from flash at start up. +//! +//! ```no_run +//! # use atsamd_hal::{ +//! # clock::v2::{ +//! # clock_system_at_reset, +//! # osc32k::{Osc1k, Osc32k}, +//! # }, +//! # pac::Peripherals, +//! # }; +//! # let mut pac = Peripherals::take().unwrap(); +//! # let (buses, clocks, tokens) = clock_system_at_reset( +//! # pac.OSCCTRL, +//! # pac.OSC32KCTRL, +//! # pac.GCLK, +//! # pac.MCLK, +//! # &mut pac.NVMCTRL, +//! # ); +//! # let base = clocks.osc32k_base; +//! # let (osc1k, base) = Osc1k::enable(tokens.osc32k.osc1k, base); +//! # let (osc32k, mut base) = Osc32k::enable(tokens.osc32k.osc32k, base); +//! base.set_calibration(128); +//! ``` +//! +//! And finally, we can set the write lock bit to freeze the configuation until +//! the next power-on reset. Doing so also drops the `EnabledOsc32kBase` +//! clock. +//! +//! ```no_run +//! # use atsamd_hal::{ +//! # clock::v2::{ +//! # clock_system_at_reset, +//! # osc32k::{Osc1k, Osc32k}, +//! # }, +//! # pac::Peripherals, +//! # }; +//! # let mut pac = Peripherals::take().unwrap(); +//! # let (buses, clocks, tokens) = clock_system_at_reset( +//! # pac.OSCCTRL, +//! # pac.OSC32KCTRL, +//! # pac.GCLK, +//! # pac.MCLK, +//! # &mut pac.NVMCTRL, +//! # ); +//! # let base = clocks.osc32k_base; +//! # let (osc1k, base) = Osc1k::enable(tokens.osc32k.osc1k, base); +//! # let (osc32k, mut base) = Osc32k::enable(tokens.osc32k.osc32k, base); +//! # base.set_calibration(128); +//! base.write_lock(); +//! ``` +//! +//! The complete example is shown below. +//! +//! ```no_run +//! use atsamd_hal::{ +//! clock::v2::{ +//! clock_system_at_reset, +//! osc32k::{Osc1k, Osc32k}, +//! }, +//! pac::Peripherals, +//! }; +//! let mut pac = Peripherals::take().unwrap(); +//! let (buses, clocks, tokens) = clock_system_at_reset( +//! pac.OSCCTRL, +//! pac.OSC32KCTRL, +//! pac.GCLK, +//! pac.MCLK, +//! &mut pac.NVMCTRL, +//! ); +//! let base = clocks.osc32k_base; +//! let (osc1k, base) = Osc1k::enable(tokens.osc32k.osc1k, base); +//! let (osc32k, mut base) = Osc32k::enable(tokens.osc32k.osc32k, base); +//! base.set_calibration(128); +//! base.write_lock(); +//! ``` +//! +//! [`clock` module documentation]: super +//! [`clock_system_at_reset`]: super::clock_system_at_reset +//! [`Clocks`]: super::Clocks + +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; + +use typenum::U0; + +use crate::pac::sysctrl::Osc32k as OSC32K; + +use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement}; + +use fugit::RateExtU32; +use crate::time::Hertz; +use crate::typelevel::Sealed; + +use super::{Enabled, Source}; + +//============================================================================== +// Tokens +//============================================================================== + +/// Singleton token for the [`Osc32kBase`] clock +// +// There should never be more than one instance of `Osc32kBaseToken`, because +// it relies on that fact for memory safety. +// +// Users never see `Osc32kBaseToken`, because the OSC32K base oscillator +// is always enabled. Internally, however, it is used as a register interface. +// The token is zero-sized, so it can be carried by clock types without +// introducing any memory bloat. +// +// As part of that register interface, the `Osc32kBaseToken` can access the +// `OSC32K` register. That the token is a singleton guarantees the register +// is written from only one location. This allows the token to be `Sync`, even +// though the PAC `OSC32KCTRL` struct is not. +pub struct Osc32kBaseToken(()); + +/// Singleton token that can be exchanged for [`Osc1k`] +/// +/// As explained in the [`clock` module documentation](super), instances of +/// various `Token` types can be exchanged for actual clock types. They +/// typically represent clocks that are disabled at power-on reset. +/// +/// The [`Osc1k`] clock is disabled at power-on reset. To use it, you must +/// first exchange the token for an actual clock with [`Osc1k::enable`]. + +#[hal_cfg("sysctrl-d11")] +pub struct Osc1kToken(()); + +/// Singleton token that can be exchanged for [`Osc32k`] +/// +/// As explained in the [`clock` module documentation](super), instances of +/// various `Token` types can be exchanged for actual clock types. They +/// typically represent clocks that are disabled at power-on reset. +/// +/// The [`Osc32k`] clock is disabled at power-on reset. To use it, you must +/// first exchange the token for an actual clock with [`Osc32k::enable`]. +pub struct Osc32kToken(()); + +/// Set of tokens representing the disabled OSC32K clocks power-on reset +#[hal_macro_helper] +pub struct Osc32kTokens { + pub base: Osc32kBaseToken, + #[hal_cfg("sysctrl-d11")] + pub osc1k: Osc1kToken, + pub osc32k: Osc32kToken, +} + +impl Osc32kTokens { + /// Create the set of tokens + /// + /// # Safety + /// + /// There must never be more than one instance of each token at any given + /// time. See the notes on `Token` types and memory safety in the root of + /// the `clock` module for more details. + #[allow(unused)] + #[hal_macro_helper] + pub(super) unsafe fn new() -> Self { + Self { + base: Osc32kBaseToken(()), + #[hal_cfg("sysctrl-d11")] + osc1k: Osc1kToken(()), + osc32k: Osc32kToken(()), + } + } +} + +impl Osc32kBaseToken { + #[inline] + fn osc32k(&self) -> &OSC32K { + // Safety: The `Osc32kBaseToken` has exclusive access to the + // `OSC32K` register. See the notes on `Token` types and memory + // safety in the root of the `clock` module for more details. + unsafe { &(*crate::pac::Sysctrl::PTR).osc32k() } + } + + /// Set the calibration + #[inline] + fn set_calibration(&mut self, calib: u8) { + // Safety: All bit patterns are valid for this field + self.osc32k() + .modify(|_, w| unsafe { w.calib().bits(calib) }); + } + + #[inline] + fn enable(&mut self, settings: Settings) { + self.osc32k().modify(|_, w| { + // Safety: The value comes from the `StartUpDelay` enum, + // so the value is guaranteed to be valid + unsafe { w.startup().bits(settings.start_up as u8) }; + w.ondemand().bit(settings.on_demand); + w.runstdby().bit(settings.run_standby); + w.enable().set_bit() + }); + } + + #[inline] + fn disable(&mut self) { + self.osc32k().modify(|_, w| w.enable().clear_bit()); + } + + /// Enable the 1 kHz output + #[hal_cfg("sysctrl-d11")] + #[inline] + fn enable_1k(&mut self) { + self.osc32k().modify(|_, w| w.en1k().set_bit()); + } + + /// Disable the 1 kHz output + #[hal_cfg("sysctrl-d11")] + #[inline] + fn disable_1k(&mut self) { + self.osc32k().modify(|_, w| w.en1k().clear_bit()); + } + + /// Enable the 32 kHz output + #[inline] + fn enable_32k(&mut self) { + self.osc32k().modify(|_, w| w.en32k().set_bit()); + } + + /// Disable the 32 kHz output + #[inline] + fn disable_32k(&mut self) { + self.osc32k().modify(|_, w| w.en32k().clear_bit()); + } + + /// Enable the write lock + #[inline] + fn write_lock(&mut self) { + self.osc32k().modify(|_, w| w.wrtlock().set_bit()); + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +struct Settings { + start_up: StartUpDelay, + on_demand: bool, + run_standby: bool, +} + +//============================================================================== +// StartUpDelay +//============================================================================== + +#[repr(u8)] +#[derive(Clone, Copy, Default, PartialEq, Eq)] +pub enum StartUpDelay { + #[default] + Delay92us, + Delay122us, + Delay183us, + Delay305us, + Delay549us, + Delay1ms, + Delay2ms, + Delay4ms, +} + +//============================================================================== +// OscBase +//============================================================================== + +/// OSC3ULP2K base clock, which feeds the [`Osc1k`] and [`Osc32k`] clocks +/// +/// The OSC32K peripheral has two possible clock outputs, one at 32 kHz and +/// another at 1 kHz. This structure is represented in the type system as a set +/// of three clocks forming a small clock tree. The [`Osc32kBase`] clock +/// represents the base oscillator that feeds the optional [`Osc1k`] and +/// [`Osc32k`] output clocks. See the [module-level documentation](super) for +/// details and examples. +pub struct Osc32kBase { + token: Osc32kBaseToken, + settings: Settings, +} + +/// The [`Enabled`] [`Osc32kBase`] clock +/// +/// As described in the [`clock` module documentation](super), the [`Enabled`] +/// wrapper implements compile-time clock tree safety by tracking the number of +/// clocks consuming the [`Osc32kBase`] clock and restricts access to the +/// underlying type to prevent misuse. +/// +/// **NOTE:** The `Osc32kBase` clock is internal and can never be disabled, +/// so we do not provide a `disable` method. +/// +/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified, +/// the counter is assumed to be zero. +pub type EnabledOsc32kBase = Enabled; + +impl Osc32kBase { + /// Create the ultra-low power base oscillator + /// + /// # Safety + /// + /// Because an `Osc32kBase` contains an `Osc32kBaseToken`, there must + /// never be more than one instance of this struct at any given time. See + /// the notes on `Token` types and memory safety in the root of the `clock` + /// module for more details. + #[inline] + pub fn new(token: Osc32kBaseToken) -> Self { + let settings = Settings { + start_up: StartUpDelay::Delay92us, + on_demand: true, + run_standby: false, + }; + Self { token, settings } + } + + pub fn start_up_delay(mut self, start_up: StartUpDelay) -> Self { + self.settings.start_up = start_up; + self + } + + pub fn on_demand(mut self, on_demand: bool) -> Self { + self.settings.on_demand = on_demand; + self + } + + pub fn run_standby(mut self, run_standby: bool) -> Self { + self.settings.run_standby = run_standby; + self + } + + #[inline] + pub fn enable(mut self) -> EnabledOsc32kBase { + self.token.enable(self.settings); + Enabled::new(self) + } +} + +impl EnabledOsc32kBase { + #[inline] + pub fn disable(mut self) -> Osc32kBase { + self.0.token.disable(); + self.0 + } + + /// Override the factory-default calibration value + #[inline] + pub fn set_calibration(&mut self, calib: u8) { + self.0.token.set_calibration(calib); + } + + /// Freeze the OSC32K configuration until power-on reset + /// + /// This function sets the write-lock bit, which freezes the OSC32K + /// configuration at the hardware level until power-on reset. At the API + /// level, it also consumes and drops the [`Osc32kBase`] clock, which + /// prevents any further modifications. + #[inline] + pub fn write_lock(mut self) { + self.0.token.write_lock(); + } +} + +//============================================================================== +// Ids +//============================================================================== + +/// Type representing the identity of the [`Osc1k`] clock +/// +/// See the discussion on [`Id` types](super#id-types) for more information. +#[hal_cfg("sysctrl-d11")] +pub enum Osc1kId {} + +#[hal_cfg("sysctrl-d11")] +impl Sealed for Osc1kId {} + +/// Type representing the identity of the [`Osc32k`] clock +/// +/// See the discussion on [`Id` types](super#id-types) for more information. +pub enum Osc32kId {} + +impl Sealed for Osc32kId {} + +//============================================================================== +// Osc1k +//============================================================================== + +/// Clock representing the 1 kHz output of the [`Osc32kBase`] clock +/// +/// The OSC32K peripheral has two possible clock outputs, one at 32 kHz and +/// another at 1 kHz. This structure is represented in the type system as a set +/// of three clocks forming a small clock tree. The [`Osc1k`] clock is +/// derived from the [`Osc32kBase`] clock. See the +/// [module-level documentation](super) for details and examples. +#[hal_cfg("sysctrl-d11")] +pub struct Osc1k { + #[allow(unused)] + token: Osc1kToken, +} + +/// The [`Enabled`] [`Osc1k`] clock +/// +/// As described in the [`clock` module documentation](super), the [`Enabled`] +/// wrapper implements compile-time clock tree safety by tracking the number of +/// clocks consuming the [`Osc1k`] clock and restricts access to the +/// underlying type to prevent misuse. +/// +/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified, +/// the counter is assumed to be zero. +#[hal_cfg("sysctrl-d11")] +pub type EnabledOsc1k = Enabled; + +#[hal_cfg("sysctrl-d11")] +impl Osc1k { + /// Enable 1 kHz output from the [`Osc32kBase`] clock + /// + /// This will [`Increment`] the [`EnabledOsc32kBase`] counter. + #[inline] + pub fn enable( + token: Osc1kToken, + mut base: EnabledOsc32kBase, + ) -> (EnabledOsc1k, EnabledOsc32kBase) { + base.0.token.enable_1k(); + (Enabled::new(Self { token }), base.inc()) + } +} + +#[hal_cfg("sysctrl-d11")] +impl EnabledOsc1k { + /// Disable 1 kHz output from the [`Osc32kBase`] clock + /// + /// This will [`Decrement`] the [`EnabledOsc32kBase`] counter. + #[inline] + pub fn disable( + self, + mut base: EnabledOsc32kBase, + ) -> (Osc1kToken, EnabledOsc32kBase) { + base.0.token.disable_1k(); + (self.0.token, base.dec()) + } +} + +#[hal_cfg("sysctrl-d11")] +impl Source for EnabledOsc1k { + type Id = Osc1kId; + + #[inline] + fn freq(&self) -> Hertz { + Hertz(1024) + } +} + +//============================================================================== +// Osc32k +//============================================================================== + +/// Clock representing the 32 kHz output of the [`Osc32kBase`] clock +/// +/// The OSC32K peripheral has two possible clock outputs, one at 32 kHz and +/// another at 1 kHz. This structure is represented in the type system as a set +/// of three clocks forming a small clock tree. The [`Osc32k`] clock is +/// derived from the [`Osc32kBase`] clock. See the +/// [module-level documentation](super) for details and examples. +pub struct Osc32k { + #[allow(unused)] + token: Osc32kToken, +} + +/// The [`Enabled`] [`Osc32k`] clock +/// +/// As described in the [`clock` module documentation](super), the [`Enabled`] +/// wrapper implements compile-time clock tree safety by tracking the number of +/// clocks consuming the [`Osc32k`] clock and restricts access to the +/// underlying type to prevent misuse. +/// +/// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified, +/// the counter is assumed to be zero. +pub type EnabledOsc32k = Enabled; + +impl Osc32k { + /// Enable 32 kHz output from the [`Osc32kBase`] clock + /// + /// This will [`Increment`] the [`EnabledOsc32kBase`] counter. + #[inline] + pub fn enable( + token: Osc32kToken, + mut base: EnabledOsc32kBase, + ) -> (EnabledOsc32k, EnabledOsc32kBase) { + base.0.token.enable_32k(); + (Enabled::new(Self { token }), base.inc()) + } +} + +impl EnabledOsc32k { + /// Disable 32 kHz output from the [`Osc32kBase`] clock + /// + /// This will [`Decrement`] the [`EnabledOsc32kBase`] counter. + #[inline] + pub fn disable( + self, + mut base: EnabledOsc32kBase, + ) -> (Osc32kToken, EnabledOsc32kBase) { + base.0.token.disable_32k(); + (self.0.token, base.dec()) + } +} + +impl Source for EnabledOsc32k { + type Id = Osc32kId; + + #[inline] + fn freq(&self) -> Hertz { + 32_768u32.Hz() + } +} diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index b2dc0b419ace..fef3159264e3 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -119,6 +119,8 @@ pub struct Tokens { pub gclks: gclk::GclkTokens, /// Tokens to create [`pclk::Pclk`]s pub pclks: pclk::PclkTokens, + /// Tokens to create the [`osc32k::Osc1k`] and [`osc32k::Osc32k`] clocks + pub osc32k: osc32k::Osc32kTokens, /// Tokens [`xosc::Xosc0`] pub xosc: xosc::XoscToken, /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and @@ -172,6 +174,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl dpll: dpll::DpllToken::new(), gclks: gclk::GclkTokens::new(), pclks: pclk::PclkTokens::new(), + osc32k: osc32k::Osc32kTokens::new(), xosc: xosc::XoscToken::new(), xosc32k: xosc32k::Xosc32kTokens::new(), }; From b720805a1299aeea1ab2023c4f990b5a9110cf6f Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Mon, 28 Jul 2025 11:08:29 +1200 Subject: [PATCH 43/75] stash 5 - reset, stash 5 - osculp32k --- hal/src/clock/v2/osculp32k.rs | 78 +++++++++---------- hal/src/clock/v2/reset_thumbv6m.rs | 14 ++-- hal/src/clock/v2/reset_thumbv7em.rs | 113 ++++------------------------ 3 files changed, 54 insertions(+), 151 deletions(-) diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index b4bc968b71ea..916b4383b2e7 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -3,7 +3,8 @@ //! ## Overview //! //! The `osculp32k` module provides access to the 32 kHz ultra low power -//! internal oscillator (OSCULP32K) within the `OSC32KCTRL` peripheral. +//! internal oscillator (OSCULP32K) within the `OSC32KCTRL` or `SYSCTRL` +//! peripheral. //! //! The `OSCULP32K` clock is unlike most other clocks. First, it is an internal //! clock that is always enabled and can't be disabled. And second, it has two @@ -13,9 +14,9 @@ //! We can see, then, that the `OSCULP32K` peripheral forms its own, miniature //! clock tree. There is a 1:N producer clock that is always enabled; and there //! are two possible consumer clocks that can be independently and optionally -//! enabled. In fact, this structure is illustrated by the `OSCULP32K` -//! register, which has no regular `ENABLE` bit and two different enable bits -//! for clock output, `EN32K` and `EN1K`. +//! enabled. In fact, this structure is illustrated by the `OSCULP32K` register, +//! which has no regular `ENABLE` bit and two different enable bits for clock +//! output, `EN32K` and `EN1K`. //! //! To represent this structure in the type system, we divide the `OSCULP32K` //! peripheral into these three clocks. Users get access to the 1:N @@ -165,21 +166,16 @@ use atsamd_hal_macros::hal_cfg; use fugit::RateExtU32; use typenum::U0; -#[hal_cfg("clock-d5x")] -mod imports { - pub use crate::pac::osc32kctrl::Osculp32k; - pub use crate::typelevel::{Decrement, Increment}; -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -mod imports { - pub use crate::pac::sysctrl::Osculp32k; -} +#[hal_cfg("osc32kctrl")] +use crate::pac::osc32kctrl::Osculp32k; +#[hal_cfg("osc32kctrl")] +use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement}; -use imports::*; +#[hal_cfg("sysctrl")] +use crate::pac::sysctrl::Osculp32k; use crate::time::Hertz; -use crate::typelevel::{PrivateDecrement, PrivateIncrement, Sealed}; +use crate::typelevel::Sealed; use super::{Enabled, Source}; @@ -223,39 +219,17 @@ pub struct OscUlp1kToken(()); /// first exchange the token for an actual clock with [`OscUlp32k::enable`]. pub struct OscUlp32kToken(()); -/// Set of tokens representing the disabled OSCULP32K clocks power-on reset -pub struct OscUlp32kTokens { - pub osculp1k: OscUlp1kToken, - pub osculp32k: OscUlp32kToken, -} - -impl OscUlp32kTokens { - /// Create the set of tokens - /// - /// # Safety - /// - /// There must never be more than one instance of each token at any given - /// time. See the notes on `Token` types and memory safety in the root of - /// the `clock` module for more details. - pub(super) unsafe fn new() -> Self { - Self { - osculp1k: OscUlp1kToken(()), - osculp32k: OscUlp32kToken(()), - } - } -} - impl OscUlp32kBaseToken { #[inline] fn osculp32k(&self) -> &Osculp32k { // Safety: The `OscUlp32kBaseToken` has exclusive access to the // `OSCULP32K` register. See the notes on `Token` types and memory // safety in the root of the `clock` module for more details. - #[hal_cfg("clock-d5x")] + #[hal_cfg("osc32kctrl")] unsafe { &(*crate::pac::Osc32kctrl::PTR).osculp32k() } - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] unsafe { &(*crate::pac::Sysctrl::PTR).osculp32k() } @@ -336,9 +310,9 @@ impl OscUlp32kBase { /// the notes on `Token` types and memory safety in the root of the `clock` /// module for more details. #[inline] - pub(super) unsafe fn new() -> EnabledOscUlp32kBase { + pub(super) unsafe fn new() -> Self { let token = OscUlp32kBaseToken(()); - Enabled::new(Self { token }) + Self { token } } } @@ -401,7 +375,15 @@ pub struct OscUlp1k { pub type EnabledOscUlp1k = Enabled; impl OscUlp1k { - #[hal_cfg(any("clock-d11", "clock-d21"))] + /// Create the ultra-low power base oscillator + /// + /// # Safety + /// + /// Because an `OscUlp1k` contains an `OscUlp1kToken`, there must never be + /// more than one instance of this struct at any given time. See the notes + /// on `Token` types and memory safety in the root of the `clock` module for + /// more details. + #[inline] pub(super) unsafe fn new() -> Self { let token = OscUlp1kToken(()); Self { token } @@ -473,7 +455,15 @@ pub struct OscUlp32k { pub type EnabledOscUlp32k = Enabled; impl OscUlp32k { - #[hal_cfg(any("clock-d11", "clock-d21"))] + /// Create the ultra-low power base oscillator + /// + /// # Safety + /// + /// Because an `OscUlp32k` contains an `OscUlp32kToken`, there must never be + /// more than one instance of this struct at any given time. See the notes + /// on `Token` types and memory safety in the root of the `clock` module for + /// more details. + #[inline] pub(super) unsafe fn new() -> Self { let token = OscUlp32kToken(()); Self { token } diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index fef3159264e3..ef4ede831cb6 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -56,7 +56,7 @@ pub struct Buses { pub apb: apb::Apb, } -pub struct OscUlp32kClocks { +pub struct OscUlpClocks { pub base: osculp32k::EnabledOscUlp32kBase, pub osculp1k: osculp32k::EnabledOscUlp1k, pub osculp32k: osculp32k::EnabledOscUlp32k, @@ -93,10 +93,10 @@ pub struct Clocks { pub gclk2: Enabled, U1>, /// 8 MHz internal oscillator, divided by 8 for a 1 MHz output pub osc: Enabled, + /// Always-enabled OSCULP oscillators + pub osculp: OscUlpClocks, /// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2) pub wdt: pclk::Pclk, - /// Always-enabled OSCULP oscillators - pub osculp32k: OscUlp32kClocks, } /// Type-level tokens for unused clocks at power-on reset @@ -147,13 +147,13 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl let osc = Enabled::<_, U0>::new(osc::Osc::new(osc::OscToken::new())); let (gclk0, osc) = gclk::Gclk0::from_source(gclk::GclkToken::new(), osc); let gclk0 = Enabled::new(gclk0); - let base = osculp32k::OscUlp32kBase::new(); + let base = Enabled::new(osculp32k::OscUlp32kBase::new()); let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); - let osculp32k = Enabled::new(osculp32k::OscUlp32k::new()); + let osculp32k = Enabled::<_, U0>::new(osculp32k::OscUlp32k::new()); let (gclk2, osculp32k) = gclk::Gclk2::from_source(gclk::GclkToken::new(), osculp32k); let gclk2 = Enabled::new(gclk2); let wdt = pclk::Pclk::new(pclk::PclkToken::new(), gclk2.freq()); - let osculp32k = OscUlp32kClocks { + let osculp = OscUlpClocks { base, osculp1k, osculp32k, @@ -166,7 +166,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl gclk2, osc, wdt, - osculp32k, + osculp, }; let tokens = Tokens { apbs: apb::ApbTokens::new(), diff --git a/hal/src/clock/v2/reset_thumbv7em.rs b/hal/src/clock/v2/reset_thumbv7em.rs index b18f607c744f..acac05d7d86d 100644 --- a/hal/src/clock/v2/reset_thumbv7em.rs +++ b/hal/src/clock/v2/reset_thumbv7em.rs @@ -2,7 +2,6 @@ //! from the `v2` module, which is where the corresponding documentation will //! appear. -use atsamd_hal_macros::hal_cfg; use typenum::U1; use crate::pac::{Gclk, Mclk, Osc32kctrl, Oscctrl}; @@ -58,18 +57,10 @@ pub struct Buses { pub apb: apb::Apb, } -#[hal_cfg("clock-d5x")] -#[allow(dead_code)] -pub struct OscUlp32kClocks { - base: osculp32k::EnabledOscUlp32kBase, -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -#[allow(dead_code)] -pub struct OscUlp32kClocks { - base: osculp32k::EnabledOscUlp32kBase, - osculp1k: EnabledOscUlp1k, - osculp32k: EnabledOscUlp32k, +pub struct OscUlpClocks { + pub base: osculp32k::EnabledOscUlp32kBase, + pub osculp1k: osculp32k::EnabledOscUlp1k, + pub osculp32k: osculp32k::EnabledOscUlp32k, } /// Enabled clocks at power-on reset @@ -103,7 +94,7 @@ pub struct Clocks { pub dfll: Enabled, /// Always-enabled base oscillator for the [`OscUlp1k`](osculp32k::OscUlp1k) /// and [`OscUlp32k`](osculp32k::OscUlp32k) clocks. - pub osculp32k: OscUlp32kClocks, + pub osculp: OscUlpClocks, } /// Type-level tokens for unused clocks at power-on reset @@ -115,32 +106,6 @@ pub struct Clocks { /// As described in the [top-level](super::super) documentation for the `clock` /// module, token types are used to guanrantee the uniqueness of each clock. To /// configure or enable a clock, you must provide the corresponding token. -#[hal_cfg("clock-d5x")] -pub struct Tokens { - /// Tokens to create [`apb::ApbClk`]s - pub apbs: apb::ApbTokens, - /// Token to create [`dpll::Dpll0`] - pub dpll0: dpll::DpllToken, - /// Token to create [`dpll::Dpll1`] - pub dpll1: dpll::DpllToken, - /// Tokens to create [`gclk::Gclk`] - pub gclks: gclk::GclkTokens, - /// Tokens to create [`pclk::Pclk`]s - pub pclks: pclk::PclkTokens, - /// Tokens to create [`rtcosc::RtcOsc`] - pub rtcosc: rtcosc::RtcOscToken, - /// Tokens [`xosc::Xosc0`] - pub xosc0: xosc::XoscToken, - /// Token to create [`xosc::Xosc1`] - pub xosc1: xosc::XoscToken, - /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and - /// [`xosc32k::Xosc32k`] - pub xosc32k: xosc32k::Xosc32kTokens, - /// Tokens to create [`osculp32k::OscUlp1k`] and [`osculp32k::OscUlp32k`] - pub osculp32k: osculp32k::OscUlp32kTokens, -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] pub struct Tokens { /// Tokens to create [`apb::ApbClk`]s pub apbs: apb::ApbTokens, @@ -170,59 +135,6 @@ pub struct Tokens { /// [`Mclk`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`]. /// /// See the [module-level documentation](super) for more details. -#[hal_cfg("clock-d5x")] -#[inline] -pub fn clock_system_at_reset( - oscctrl: Oscctrl, - osc32kctrl: Osc32kctrl, - gclk: Gclk, - mclk: Mclk, -) -> (Buses, Clocks, Tokens) { - // Safety: No bus, clock or token is instantiated more than once - unsafe { - let buses = Buses { - ahb: ahb::Ahb::new(), - apb: apb::Apb::new(), - }; - let pac = Pac { - oscctrl, - osc32kctrl, - gclk, - mclk, - }; - let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new())); - let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll); - let gclk0 = Enabled::new(gclk0); - let osculp32k_clocks = { - OscUlp32kClocks { - base: osculp32k::OscUlp32kBase::new(), - } - }; - let clocks = Clocks { - pac, - ahbs: ahb::AhbClks::new(), - apbs: apb::ApbClks::new(), - gclk0, - dfll, - osculp32k: osculp32k_clocks, - }; - let tokens = Tokens { - apbs: apb::ApbTokens::new(), - dpll0: dpll::DpllToken::new(), - dpll1: dpll::DpllToken::new(), - gclks: gclk::GclkTokens::new(), - pclks: pclk::PclkTokens::new(), - rtcosc: rtcosc::RtcOscToken::new(), - xosc0: xosc::XoscToken::new(), - xosc1: xosc::XoscToken::new(), - xosc32k: xosc32k::Xosc32kTokens::new(), - osculp32k: osculp32k::OscUlp32kTokens::new(), - }; - (buses, clocks, tokens) - } -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] pub fn clock_system_at_reset( oscctrl: Oscctrl, @@ -245,12 +157,13 @@ pub fn clock_system_at_reset( let dfll = Enabled::<_>::new(dfll::Dfll::open_loop(dfll::DfllToken::new())); let (gclk0, dfll) = gclk::Gclk0::from_source(gclk::GclkToken::new(), dfll); let gclk0 = Enabled::new(gclk0); - let osculp32k_clocks = { - OscUlp32kClocks { - base: osculp32k::OscUlp32kBase::new(), - osculp1k: Enabled::new(osculp32k::OscUlp1k::new()), - osculp32k: Enabled::new(osculp32k::OscUlp32k::new()), - } + let base = Enabled::new(osculp32k::OscUlp32kBase::new()); + let osculp1k = Enabled::new(osculp32k::OscUlp1k::new()); + let osculp32k = Enabled::new(osculp32k::OscUlp32k::new()); + let osculp = OscUlpClocks { + base, + osculp1k, + osculp32k, }; let clocks = Clocks { pac, @@ -258,7 +171,7 @@ pub fn clock_system_at_reset( apbs: apb::ApbClks::new(), gclk0, dfll, - osculp32k: osculp32k_clocks, + osculp, }; let tokens = Tokens { apbs: apb::ApbTokens::new(), From 83fedf6eebd6a2c76e299d9af6ba9daa131aa98f Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Mon, 28 Jul 2025 11:31:54 +1200 Subject: [PATCH 44/75] remainder of stash 4 - gclk --- hal/src/clock/v2/gclk.rs | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index f67d7c9928d9..65646e014af1 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -399,6 +399,7 @@ impl GclkToken { } /// SYNCBUSY register mask for the corresponding GCLK + #[hal_cfg("clock-d5x")] const MASK: u16 = 1 << G::NUM; /// Provide a reference to the corresponding [`Genctrl`] register @@ -814,6 +815,7 @@ pub trait GclkIo: PinId { // These implementations are much easier to read with `#[rustfmt::skip]` #[rustfmt::skip] +#[hal_cfg("clock-d5x")] mod gclkio_impl { use atsamd_hal_macros::hal_cfg; @@ -865,6 +867,80 @@ mod gclkio_impl { impl GclkIo for gpio::PB23 { type GclkId = Gclk1Id; } } +#[rustfmt::skip] +#[hal_cfg("clock-d21")] +mod gclkio_impl { + use super::*; + + impl GclkIo for gpio::PA10 { type GclkId = Gclk4Id; } + impl GclkIo for gpio::PA11 { type GclkId = Gclk5Id; } + impl GclkIo for gpio::PA14 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA15 { type GclkId = Gclk1Id; } + impl GclkIo for gpio::PA16 { type GclkId = Gclk2Id; } + impl GclkIo for gpio::PA17 { type GclkId = Gclk3Id; } + #[hal_cfg("pa20")] + impl GclkIo for gpio::PA20 { type GclkId = Gclk4Id; } + #[hal_cfg("pa21")] + impl GclkIo for gpio::PA21 { type GclkId = Gclk5Id; } + impl GclkIo for gpio::PA22 { type GclkId = Gclk6Id; } + impl GclkIo for gpio::PA23 { type GclkId = Gclk7Id; } + #[hal_cfg("pa27")] + impl GclkIo for gpio::PA27 { type GclkId = Gclk0Id; } + #[hal_cfg("pa28")] + impl GclkIo for gpio::PA28 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA30 { type GclkId = Gclk0Id; } + + #[hal_cfg("pb10")] + impl GclkIo for gpio::PB10 { type GclkId = Gclk4Id; } + #[hal_cfg("pb11")] + impl GclkIo for gpio::PB11 { type GclkId = Gclk5Id; } + #[hal_cfg("pb12")] + impl GclkIo for gpio::PB12 { type GclkId = Gclk6Id; } + #[hal_cfg("pb13")] + impl GclkIo for gpio::PB13 { type GclkId = Gclk7Id; } + #[hal_cfg("pb14")] + impl GclkIo for gpio::PB14 { type GclkId = Gclk0Id; } + #[hal_cfg("pb15")] + impl GclkIo for gpio::PB15 { type GclkId = Gclk1Id; } + #[hal_cfg("pb16")] + impl GclkIo for gpio::PB16 { type GclkId = Gclk2Id; } + #[hal_cfg("pb17")] + impl GclkIo for gpio::PB17 { type GclkId = Gclk3Id; } + #[hal_cfg("pb22")] + impl GclkIo for gpio::PB22 { type GclkId = Gclk0Id; } + #[hal_cfg("pb23")] + impl GclkIo for gpio::PB23 { type GclkId = Gclk1Id; } +} + +#[rustfmt::skip] +#[hal_cfg("clock-d11")] +mod gclkio_impl { + use super::*; + + impl GclkIo for gpio::PA08 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA09 { type GclkId = Gclk1Id; } + #[hal_cfg("pa10")] + impl GclkIo for gpio::PA10 { type GclkId = Gclk4Id; } + #[hal_cfg("pa11")] + impl GclkIo for gpio::PA11 { type GclkId = Gclk5Id; } + impl GclkIo for gpio::PA14 { type GclkId = Gclk4Id; } + impl GclkIo for gpio::PA15 { type GclkId = Gclk5Id; } + #[hal_cfg("pa16")] + impl GclkIo for gpio::PA16 { type GclkId = Gclk2Id; } + #[hal_cfg("pa17")] + impl GclkIo for gpio::PA17 { type GclkId = Gclk3Id; } + #[hal_cfg("pa22")] + impl GclkIo for gpio::PA22 { type GclkId = Gclk1Id; } + #[hal_cfg("pa23")] + impl GclkIo for gpio::PA23 { type GclkId = Gclk2Id; } + impl GclkIo for gpio::PA24 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA25 { type GclkId = Gclk0Id; } + #[hal_cfg("pa27")] + impl GclkIo for gpio::PA27 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA30 { type GclkId = Gclk0Id; } + impl GclkIo for gpio::PA31 { type GclkId = Gclk0Id; } +} + //============================================================================== // Gclk0Io //============================================================================== From d50486c93fe1d64862287f1b8a2e524004260a84 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Mon, 28 Jul 2025 13:26:36 +1200 Subject: [PATCH 45/75] Add xosc to devices table This makes a `hal_cfg()` argument available for xosc1 on bigger chips --- atsamd-hal-macros/devices.yaml | 3 +++ hal/src/clock/v2/dpll.rs | 35 ++++++++++------------------------ hal/src/clock/v2/gclk.rs | 6 +++--- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/atsamd-hal-macros/devices.yaml b/atsamd-hal-macros/devices.yaml index 667c98742e38..df6a7af81f8d 100644 --- a/atsamd-hal-macros/devices.yaml +++ b/atsamd-hal-macros/devices.yaml @@ -21,6 +21,7 @@ families: - serial-numbers - dsu - clock + - xosc: { count: 1 } - gclk: { count: 6 } - pm - sysctrl @@ -53,6 +54,7 @@ families: - serial-numbers - dsu - clock + - xosc: { count: 1 } - gclk: { count: 8 } - pm - sysctrl @@ -96,6 +98,7 @@ families: - cmcc - dsu - clock + - xosc: { count: 2 } - gclk: { count: 12 } - mclk - rstc diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index ba8b886b86e3..ab79025ef1f4 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -237,7 +237,7 @@ //! [`GclkDivider`]: super::gclk::GclkDivider //! [`Pclk`]: super::pclk::Pclk -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use fugit::RateExtU32; @@ -245,7 +245,6 @@ use typenum::U0; #[hal_cfg("clock-d5x")] mod imports { - pub use super::super::xosc::Xosc1Id; pub use crate::pac::Oscctrl as Peripheral; pub use crate::pac::oscctrl::{ Dpll as PacDpll, @@ -271,6 +270,8 @@ use crate::typelevel::{Decrement, Increment, Sealed}; use super::gclk::GclkId; use super::pclk::{Pclk, PclkId}; +#[hal_cfg("xosc1")] +use super::xosc::Xosc1Id; use super::xosc::{Xosc0Id, XoscId}; use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -360,19 +361,14 @@ impl DpllToken { #[inline] fn enable(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) { // Convert the actual predivider to the `div` register field value - #[hal_cfg("clock-d5x")] + #[hal_macro_helper] let div = match id { DynDpllSourceId::Xosc0 => prediv / 2 - 1, + #[hal_cfg("xosc1")] DynDpllSourceId::Xosc1 => prediv / 2 - 1, _ => 0, }; - #[hal_cfg(any("clock-d11", "clock-d21"))] - let div = match id { - DynDpllSourceId::Xosc0 => prediv / 2 - 1, - _ => 0, - }; - self.ctrlb().write(|w| { // Safety: The value is masked to the correct bit width by the PAC. // An invalid value could produce an invalid clock frequency, but @@ -528,20 +524,21 @@ impl DpllId for Dpll1Id { /// a given [`Dpll`]. /// /// `DynDpllSourceId` is the value-level equivalent of [`DpllSourceId`]. -#[hal_cfg("clock-d5x")] +#[hal_macro_helper] #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DynDpllSourceId { /// The DPLL is driven by a [`Pclk`] Pclk, /// The DPLL is driven by [`Xosc0`](super::xosc::Xosc0) Xosc0, + #[hal_cfg("xosc1")] /// The DPLL is driven by [`Xosc1`](super::xosc::Xosc1) Xosc1, /// The DPLL is driven by [`Xosc32k`](super::xosc32k::Xosc32k) Xosc32k, } -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] impl From for Refclkselect { fn from(source: DynDpllSourceId) -> Self { match source { @@ -553,18 +550,7 @@ impl From for Refclkselect { } } -#[hal_cfg(any("clock-d11", "clock-d21"))] -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum DynDpllSourceId { - /// The DPLL is driven by a [`Pclk`] - Pclk, - /// The DPLL is driven by [`Xosc0`](super::xosc::Xosc0) - Xosc0, - /// The DPLL is driven by [`Xosc32k`](super::xosc32k::Xosc32k) - Xosc32k, -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] +#[hal_cfg("sysctrl")] impl From for Refclkselect { fn from(source: DynDpllSourceId) -> Self { match source { @@ -574,7 +560,6 @@ impl From for Refclkselect { } } } - //============================================================================== // DpllSourceId //============================================================================== @@ -609,7 +594,7 @@ impl DpllSourceId for Xosc0Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc0; type Reference = settings::Xosc; } -#[hal_cfg("clock-d5x")] +#[hal_cfg("xosc1")] impl DpllSourceId for Xosc1Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc1; type Reference = settings::Xosc; diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 65646e014af1..3a847c99d0fd 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -358,7 +358,7 @@ use super::dfll::DfllId; use super::osc::OscId; use super::osculp32k::OscUlp32kId; use super::xosc::Xosc0Id; -#[hal_cfg("clock-d5x")] +#[hal_cfg("xosc1")] use super::xosc::Xosc1Id; use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -949,7 +949,7 @@ mod gclkio_impl { /// /// This is effectively a trait alias for [`PinId`]s that implement [`GclkIo`] /// with a `GclkId` associated type of [`Gclk0Id`], i.e. -/// `GclkIo`. The trait is useful to simply some function +/// `GclkIo`. The trait is useful to simplify some function /// signatures and to help type inference in a few cases. pub trait Gclk0Io where @@ -1085,7 +1085,7 @@ impl GclkSourceId for Xosc0Id { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc0; type Resource = (); } -#[hal_cfg("clock-d5x")] +#[hal_cfg("xosc1")] impl GclkSourceId for Xosc1Id { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; type Resource = (); From 3c424b4a544f0d4d594a97ebec69882a478b65c1 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Mon, 28 Jul 2025 13:35:42 +1200 Subject: [PATCH 46/75] stash 5 - dpll --- hal/src/clock/v2/dpll.rs | 111 ++++++++++++++++++++++++--------------- hal/src/clock/v2/gclk.rs | 21 ++++---- 2 files changed, 81 insertions(+), 51 deletions(-) diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index ab79025ef1f4..7d033a5023d6 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -1,9 +1,10 @@ -//! # Digital Phase-Locked Loop +//! # Fractional Digital Phase-Locked Loop //! //! ## Overview //! -//! The `dpll` module provides access to the two digital phase-locked loops -//! (DPLLs) within the `OSCCTRL` peripheral. +//! The `dpll` module provides access to the digital phase-locked loops (DPLLs) +//! within the `OSCCTRL` or `SYSCTRL` peripheral, datasheets refer to these as +//! FDPLL200M and FDPLL96M, respectively. //! //! A DPLL is used to multiply clock frequencies. It takes a lower-frequency //! input clock and produces a higher-frequency output clock. It works by taking @@ -243,27 +244,25 @@ use core::marker::PhantomData; use fugit::RateExtU32; use typenum::U0; -#[hal_cfg("clock-d5x")] -mod imports { - pub use crate::pac::Oscctrl as Peripheral; - pub use crate::pac::oscctrl::{ +#[hal_cfg("oscctrl")] +use crate::pac::{ + Oscctrl as Peripheral, + oscctrl::{ Dpll as PacDpll, dpll::dpllctrlb::Refclkselect, dpll::{Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus, dpllsyncbusy}, - }; -} + }, +}; -#[hal_cfg(any("clock-d11", "clock-d21"))] -mod imports { - pub use crate::pac::Sysctrl as Peripheral; - pub use crate::pac::sysctrl::{ +#[hal_cfg("sysctrl")] +use crate::pac::{ + Sysctrl as Peripheral, + sysctrl::{ RegisterBlock as PacDpll, dpllctrlb::Refclkselect, {Dpllctrla, Dpllctrlb, Dpllratio, dpllstatus}, - }; -} - -use imports::*; + }, +}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, Sealed}; @@ -317,11 +316,11 @@ impl DpllToken { // of registers for the corresponding `DpllId`, and we use a shared // reference to the register block. See the notes on `Token` types and // memory safety in the root of the `clock` module for more details. - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] unsafe { &(*Peripheral::PTR).dpll(D::NUM) } - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] unsafe { &(*Peripheral::PTR) } @@ -345,7 +344,7 @@ impl DpllToken { self.dpll().dpllratio() } - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] /// Access the corresponding DPLLSYNCBUSY register for reading only #[inline] fn syncbusy(&self) -> dpllsyncbusy::R { @@ -377,7 +376,7 @@ impl DpllToken { w.refclk().variant(id.into()); w.lbypass().bit(settings.lock_bypass); w.wuf().bit(settings.wake_up_fast); - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] if let Some(cap) = settings.dco_filter { w.dcoen().bit(true); unsafe { @@ -395,7 +394,7 @@ impl DpllToken { w.ldr().bits(settings.mult - 1); w.ldrfrac().bits(settings.frac) }); - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] while self.syncbusy().dpllratio().bit_is_set() {} self.ctrla().modify(|_, w| { w.ondemand().bit(settings.on_demand); @@ -414,17 +413,17 @@ impl DpllToken { #[inline] fn wait_enabled(&self) { - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] while self.status().enable().bit_is_clear() {} } #[inline] fn wait_disabled(&self) { - #[hal_cfg("clock-d5x")] + #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] while self.status().enable().bit_is_set() {} } @@ -502,13 +501,13 @@ impl DpllId for Dpll0Id { /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] pub enum Dpll1Id {} -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] impl Sealed for Dpll1Id {} -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] impl DpllId for Dpll1Id { const DYN: DynDpllId = DynDpllId::Dpll1; const NUM: usize = 1; @@ -608,6 +607,12 @@ impl DpllSourceId for Xosc32kId { // Settings //============================================================================== +/// Fractional divider for the `LDRFRAC` field +#[hal_cfg("sysctrl")] +pub const FRAC_DIV: u8 = 16; +#[hal_cfg("oscctrl")] +pub const FRAC_DIV: u8 = 32; + /// [`Dpll`] Proportional Integral Filter /// /// Filter settings affect PLL stability and jitter. The datasheet suggests a @@ -672,6 +677,7 @@ pub enum DcoFilter { /// [`Dpll`] settings relevant to all reference clocks #[derive(Copy, Clone)] +#[hal_macro_helper] struct Settings { mult: u16, frac: u8, @@ -680,6 +686,7 @@ struct Settings { on_demand: bool, run_standby: bool, filter: PiFilter, + #[hal_cfg("oscctrl")] dco_filter: Option, } @@ -795,7 +802,7 @@ where pub type Dpll0 = Dpll; /// Type alias for the corresponding [`Dpll`] -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] pub type Dpll1 = Dpll; impl Dpll @@ -803,6 +810,7 @@ where D: DpllId, I: DpllSourceId, { + #[hal_macro_helper] fn new(token: DpllToken, reference: I::Reference) -> Self { let settings = Settings { mult: 1, @@ -812,6 +820,7 @@ where on_demand: true, run_standby: false, filter: PiFilter::Bw92p7kHzDf0p76, + #[hal_cfg("oscctrl")] dco_filter: None, }; Self { @@ -971,7 +980,7 @@ where /// parts of the division factor, i.e. the division factor is: /// /// ```text - /// int + frac / 32 + /// int + frac / FRAC_DIV /// ``` /// /// This function will confirm that the `int` and `frac` values convert to @@ -981,7 +990,7 @@ where if int < 1 || int > 0x2000 { panic!("Invalid integer part of the DPLL loop divider") } - if frac > 31 { + if frac > FRAC_DIV - 1 { panic!("Invalid fractional part of the DPLL loop divider") } self.settings.mult = int; @@ -1022,6 +1031,7 @@ where /// Enable sigma-delta DAC low pass filter #[inline] + #[hal_cfg("oscctrl")] pub fn dco_filter(mut self, capacitor: DcoFilter) -> Self { self.settings.dco_filter = Some(capacitor); self @@ -1054,15 +1064,15 @@ where #[inline] fn output_freq(&self) -> Hertz { // The actual formula is: - // y = x * (mult + frac / 32) + // y = x * (mult + frac / FRAC_DIV) // To avoid integer precision loss, the formula is restructured: - // y = x * (mult + frac / 32) * 32 / 32 - // y = x * (32 * mult + 32 * frac / 32) / 32 - // y = x * (32 * mult + frac) / 32 + // y = x * (mult + frac / FRAC_DIV) * FRAC_DIV / FRAC_DIV + // y = x * (FRAC_DIV * mult + FRAC_DIV * frac / FRAC_DIV) / FRAC_DIV + // y = x * (FRAC_DIV * mult + frac) / FRAC_DIV let input = self.input_freq().to_Hz() as u64; - let multiplier_times_32 = - (32 * self.settings.mult as u32 + self.settings.frac as u32) as u64; - let output = (input * multiplier_times_32 / 32) as u32; + let multiplier_scaled = + (FRAC_DIV as u32 * self.settings.mult as u32 + self.settings.frac as u32) as u64; + let output = (input * multiplier_scaled / FRAC_DIV as u64) as u32; output.Hz() } @@ -1091,12 +1101,29 @@ where /// frequency is invalid, this call will panic. #[inline] pub fn enable(self) -> EnabledDpll { + const INPUT_MIN: u32 = 32_000; + + #[hal_cfg("sysctrl")] + const INPUT_MAX: u32 = 2_000_000; + #[hal_cfg("oscctrl")] + const INPUT_MAX: u32 = 3_200_000; + + #[hal_cfg("sysctrl")] + const OUTPUT_MIN: u32 = 48_000_000; + #[hal_cfg("oscctrl")] + const OUTPUT_MIN: u32 = 96_000_000; + + #[hal_cfg("sysctrl")] + const OUTPUT_MAX: u32 = 96_000_000; + #[hal_cfg("oscctrl")] + const OUTPUT_MAX: u32 = 200_000_000; + let input_freq = self.input_freq().to_Hz(); let output_freq = self.output_freq().to_Hz(); - if input_freq < 32_000 || input_freq > 3_200_000 { + if input_freq < INPUT_MIN || input_freq > INPUT_MAX { panic!("Invalid DPLL input frequency"); } - if output_freq < 96_000_000 || output_freq > 200_000_000 { + if output_freq < OUTPUT_MIN || output_freq > OUTPUT_MAX { panic!("Invalid DPLL output frequency"); } self.enable_unchecked() @@ -1136,7 +1163,7 @@ pub type EnabledDpll = Enabled, N>; pub type EnabledDpll0 = EnabledDpll; /// Type alias for the corresponding [`EnabledDpll`] -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] pub type EnabledDpll1 = EnabledDpll; impl EnabledDpll diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 3a847c99d0fd..56ba297be998 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -353,7 +353,9 @@ use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; use super::dfll::DfllId; -// use super::dpll::{Dpll0Id, Dpll1Id}; +use super::dpll::Dpll0Id; +#[hal_cfg("oscctrl")] +use super::dpll::Dpll1Id; #[hal_cfg(any("clock-d11", "clock-d21"))] use super::osc::OscId; use super::osculp32k::OscUlp32kId; @@ -1056,14 +1058,15 @@ impl GclkSourceId for DfllId { const DYN: DynGclkSourceId = DynGclkSourceId::Dfll; type Resource = (); } -//impl GclkSourceId for Dpll0Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Dpll0; -// type Resource = (); -//} -//impl GclkSourceId for Dpll1Id { -// const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; -// type Resource = (); -//} +impl GclkSourceId for Dpll0Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Dpll0; + type Resource = (); +} +#[hal_cfg("oscctrl")] +impl GclkSourceId for Dpll1Id { + const DYN: DynGclkSourceId = DynGclkSourceId::Dpll1; + type Resource = (); +} impl GclkSourceId for Gclk1Id { const DYN: DynGclkSourceId = DynGclkSourceId::Gclk1; type Resource = (); From 044ac1e4a003054a027ffaffc19efd0ecfa22cbb Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 08:44:34 +1200 Subject: [PATCH 47/75] minor doc fix from stash 5 - finer-grained configuration --- hal/src/clock/v2/types.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index 0ff95ac3a475..f16b7d3eb053 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -30,9 +30,9 @@ macro_rules! create_types { $( /// Marker type representing the corresponding peripheral /// - /// This type is defined by and used within the [`clock`](super) - /// module. See the the [`types`](self) module documentation for - /// more details. + /// This type is defined by and used within the + /// [`clock`](super::super) module. See the the [`types`](super) + /// module documentation for more details. pub enum $Type {} impl Sealed for $Type {} )+ From 5f1584702b8593d631b8d8cd248552517e7706ab Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 09:04:24 +1200 Subject: [PATCH 48/75] stash 5 - pclk Decided not to split the file up, doesn't seem necessary --- hal/src/clock/v2/pclk.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 61e038463ea7..f8f87522eaa5 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -290,13 +290,10 @@ macro_rules! with_pclk_types_ids { (Dpll1Id = 2, dpll1) (SlowClk = 3, slow) (Eic = 4, eic) - #[hal_cfg("clock-d5x")] (FreqMMeasure = 5, freq_m_measure) - #[hal_cfg("clock-d5x")] (FreqMReference = 6, freq_m_reference) (Sercom0 = 7, sercom0) (Sercom1 = 8, sercom1) - #[hal_cfg("clock-d5x")] (Tc0Tc1 = 9, tc0_tc1) (Usb = 10, usb) (EvSys0 = 11, ev_sys0) @@ -314,20 +311,16 @@ macro_rules! with_pclk_types_ids { (Sercom2 = 23, sercom2) (Sercom3 = 24, sercom3) (Tcc0Tcc1 = 25, tcc0_tcc1) - #[hal_cfg("clock-d5x")] (Tc2Tc3 = 26, tc2_tc3) #[hal_cfg("can0")] (Can0 = 27, can0) #[hal_cfg("can1")] (Can1 = 28, can1) - #[hal_cfg("clock-d5x")] (Tcc2Tcc3 = 29, tcc2_tcc3) #[hal_cfg(all("tc4", "tc5"))] (Tc4Tc5 = 30, tc4_tc5) - #[hal_cfg("clock-d5x")] (PDec = 31, pdec) (Ac = 32, ac) - #[hal_cfg("clock-d5x")] (Ccl = 33, ccl) (Sercom4 = 34, sercom4) (Sercom5 = 35, sercom5) @@ -340,18 +333,15 @@ macro_rules! with_pclk_types_ids { #[hal_cfg(all("tc6", "tc7"))] (Tc6Tc7 = 39, tc6_tc7) (Adc0 = 40, adc0) - #[hal_cfg("clock-d5x")] (Adc1 = 41, adc1) (Dac = 42, dac) #[hal_cfg("i2s")] (I2S0 = 43, i2s0) #[hal_cfg("i2s")] (I2S1 = 44, i2s1) - #[hal_cfg("clock-d5x")] (Sdhc0 = 45, sdhc0) #[hal_cfg("sdhc1")] (Sdhc1 = 46, sdhc1) - #[hal_cfg("clock-d5x")] (CM4Trace = 47, cm4_trace) ); }; From 3fcbb8ece54d0d7c4177dd2696b95859a3a2130e Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 09:47:18 +1200 Subject: [PATCH 49/75] stash 5 - xosc32k --- hal/src/clock/v2/xosc32k.rs | 112 +++++++++++++----------------------- 1 file changed, 41 insertions(+), 71 deletions(-) diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index 4df5386e3157..32dafa8be796 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -341,32 +341,28 @@ //! [`is_switched`]: Xosc32kCfd::is_switched //! [`switch_back`]: Xosc32kCfd::switch_back -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use fugit::RateExtU32; use typenum::U0; -#[hal_cfg("clock-d5x")] -mod imports { - pub use super::super::osculp32k::OscUlp32kId; - pub use crate::pac::Osc32kctrl as PERIPHERAL; - pub use crate::pac::osc32kctrl::xosc32k::Cgmselect; - pub use crate::pac::osc32kctrl::{Cfdctrl, Xosc32k as PacXosc32k, status::R as STATUS_R}; -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -mod imports { - pub use crate::pac::Sysctrl as PERIPHERAL; - pub use crate::pac::sysctrl::Xosc32k as PacXosc32k; - pub use crate::pac::sysctrl::pclksr::R as STATUS_R; -} - -use imports::*; - -#[hal_cfg("clock-d21")] +#[hal_cfg("osc32kctrl")] +use crate::{ + clock::v2::osculp32k::OscUlp32kId, + pac::{ + Osc32kctrl as PERIPHERAL, + osc32kctrl::{Cfdctrl, Xosc32k as PacXosc32k, status::R as STATUS_R, xosc32k::Cgmselect}, + }, +}; + +#[hal_cfg("sysctrl")] +use crate::pac::{ + Sysctrl as PERIPHERAL, + sysctrl::{Xosc32k as PacXosc32k, pclksr::R as STATUS_R}, +}; + +#[hal_cfg(any("port-d21", "port-d5x"))] pub use crate::gpio::{PA00 as XIn32Id, PA01 as XOut32Id}; -#[hal_cfg("clock-d5x")] -pub use crate::gpio::{PA00 as XIn32Id, PA01 as XOut32Id}; -#[hal_cfg("clock-d11")] +#[hal_cfg("port-d11")] pub use crate::gpio::{PA08 as XIn32Id, PA09 as XOut32Id}; use crate::gpio::{FloatingDisabled, Pin}; @@ -398,6 +394,7 @@ pub struct Xosc32kBaseToken(()); /// /// The [`Xosc1k`] clock is disabled at power-on reset. To use it, you must /// first exchange the token for an actual clock with [`Xosc1k::enable`]. +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] pub struct Xosc1kToken(()); /// Singleton token that can be exchanged for [`Xosc32k`] @@ -419,19 +416,21 @@ pub struct Xosc32kToken(()); /// /// Clock failure detection is disabled at power-on reset. To use it, you must /// first enable it by exchanging the token with [`Xosc32kCfd::enable`]. -#[hal_cfg("clock-d5x")] +#[hal_cfg("osc32kctrl")] pub struct Xosc32kCfdToken(()); -#[hal_cfg("clock-d5x")] +#[hal_macro_helper] /// Set of tokens representing the disabled XOSC32K clocks power-on reset pub struct Xosc32kTokens { pub base: Xosc32kBaseToken, + #[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] pub xosc1k: Xosc1kToken, pub xosc32k: Xosc32kToken, + #[hal_cfg("osc32kctrl")] pub cfd: Xosc32kCfdToken, } -#[hal_cfg("clock-d5x")] +#[hal_macro_helper] impl Xosc32kTokens { /// Create the set of tokens /// @@ -443,50 +442,25 @@ impl Xosc32kTokens { pub(super) unsafe fn new() -> Self { Self { base: Xosc32kBaseToken(()), + #[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] xosc1k: Xosc1kToken(()), xosc32k: Xosc32kToken(()), + #[hal_cfg("osc32kctrl")] cfd: Xosc32kCfdToken(()), } } } -#[hal_cfg(any("clock-d11", "clock-d21"))] - -/// Set of tokens representing the disabled XOSC32K clocks power-on reset -pub struct Xosc32kTokens { - pub base: Xosc32kBaseToken, - pub xosc1k: Xosc1kToken, - pub xosc32k: Xosc32kToken, -} - -#[hal_cfg(any("clock-d11", "clock-d21"))] -impl Xosc32kTokens { - /// Create the set of tokens - /// - /// # Safety - /// - /// There must never be more than one instance of these tokens at any given - /// time. See the notes on `Token` types and memory safety in the root of - /// the `clock` module for more details. - pub(super) unsafe fn new() -> Self { - Self { - base: Xosc32kBaseToken(()), - xosc1k: Xosc1kToken(()), - xosc32k: Xosc32kToken(()), - } - } -} - impl Xosc32kBaseToken { #[inline] fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. - #[hal_cfg("clock-d5x")] + #[hal_cfg("osc32kctrl")] unsafe { (*PERIPHERAL::PTR).status().read() } - #[hal_cfg(any("clock-d11", "clock-d21"))] + #[hal_cfg("sysctrl")] unsafe { (*PERIPHERAL::PTR).pclksr().read() } @@ -514,24 +488,13 @@ impl Xosc32kBaseToken { /// Set most of the fields in the XOSC32K register #[inline] - #[hal_cfg("clock-d5x")] + #[hal_macro_helper] fn enable(&mut self, mode: DynMode, settings: Settings) { let xtalen = mode == DynMode::CrystalMode; self.xosc32k().write(|w| { + #[hal_cfg("osc32kctrl")] w.cgm().variant(settings.cgm.into()); - unsafe { w.startup().bits(settings.start_up as u8) }; - w.ondemand().bit(settings.on_demand); - w.runstdby().bit(settings.run_standby); - w.xtalen().bit(xtalen); - w.enable().set_bit() - }); - } - - #[inline] - #[hal_cfg(any("clock-d11", "clock-d21"))] - fn enable(&mut self, mode: DynMode, settings: Settings) { - let xtalen = mode == DynMode::CrystalMode; - self.xosc32k().write(|w| { + #[hal_cfg("sysctrl")] w.aampen().bit(settings.aampen); unsafe { w.startup().bits(settings.start_up as u8) }; w.ondemand().bit(settings.on_demand); @@ -549,12 +512,14 @@ impl Xosc32kBaseToken { /// Enable the 1 kHz output #[inline] + #[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] fn enable_1k(&mut self) { self.xosc32k().modify(|_, w| w.en1k().set_bit()); } /// Disable the 1 kHz output #[inline] + #[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] fn disable_1k(&mut self) { self.xosc32k().modify(|_, w| w.en1k().clear_bit()); } @@ -578,7 +543,7 @@ impl Xosc32kBaseToken { } } -#[hal_cfg("clock-d5x")] +#[hal_cfg("osc32kctrl")] impl Xosc32kCfdToken { #[inline] fn status(&self) -> STATUS_R { @@ -1097,12 +1062,12 @@ impl EnabledXosc32kBase { /// /// [`OscUlp32k`]: super::osculp32k::OscUlp32k /// [`EnabledOscUlp32k`]: super::osculp32k::EnabledOscUlp32k -#[hal_cfg("clock-d5x")] +#[hal_cfg("osc32kctrl")] pub struct Xosc32kCfd { token: Xosc32kCfdToken, } -#[hal_cfg("clock-d5x")] +#[hal_cfg("osc32kctrl")] impl Xosc32kCfd { /// Enable continuous monitoring of the XOSC32K for clock failure /// @@ -1202,6 +1167,7 @@ impl Sealed for Xosc32kId {} /// of three clocks forming a small clock tree. The [`Xosc1k`] clock is derived /// from the [`Xosc32kBase`] clock. See the [module-level documentation](super) /// for details and examples. +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] pub struct Xosc1k { token: Xosc1kToken, } @@ -1215,8 +1181,10 @@ pub struct Xosc1k { /// /// As with [`Enabled`], the default value for `N` is `U0`; if left unspecified, /// the counter is assumed to be zero. +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] pub type EnabledXosc1k = Enabled; +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] impl Xosc1k { /// Enable 1 kHz output from the [`Xosc32kBase`] clock /// @@ -1235,6 +1203,7 @@ impl Xosc1k { } } +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] impl EnabledXosc1k { /// Disable 1 kHz output from the [`Xosc32kBase`] clock /// @@ -1253,6 +1222,7 @@ impl EnabledXosc1k { } } +#[hal_cfg(any("sysctrl-d11", "osc32kctrl"))] impl Source for EnabledXosc1k { type Id = Xosc1kId; From 4355c28ec194d2765d6e824c5940d6c4d0539525 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 10:01:01 +1200 Subject: [PATCH 50/75] stash 4 - gpio --- hal/src/gpio/dynpin.rs | 5 +---- hal/src/gpio/pin.rs | 6 +----- hal/src/gpio/reg.rs | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/hal/src/gpio/dynpin.rs b/hal/src/gpio/dynpin.rs index 913193b81e3a..1c6d5e290a24 100644 --- a/hal/src/gpio/dynpin.rs +++ b/hal/src/gpio/dynpin.rs @@ -111,7 +111,6 @@ pub enum DynAlternate { E, F, G, - #[hal_cfg(any("port-d21", "port-d5x"))] H, #[hal_cfg("port-d5x")] I, @@ -182,9 +181,7 @@ macro_rules! dyn_alternate { }; } -dyn_alternate!(B, C, D, E, F, G); -#[hal_cfg(any("port-d21", "port-d5x"))] -dyn_alternate!(H); +dyn_alternate!(B, C, D, E, F, G, H); #[hal_cfg("port-d5x")] dyn_alternate!(I, J, K, L, M, N); diff --git a/hal/src/gpio/pin.rs b/hal/src/gpio/pin.rs index 040c8473e8bd..62129af8fca0 100644 --- a/hal/src/gpio/pin.rs +++ b/hal/src/gpio/pin.rs @@ -341,10 +341,7 @@ macro_rules! alternate { }; } -alternate!(B, C, D, E, F, G); - -#[hal_cfg(any("port-d21", "port-d5x"))] -alternate!(H); +alternate!(B, C, D, E, F, G, H); #[hal_cfg("port-d5x")] alternate!(I, J, K, L, M, N); @@ -752,7 +749,6 @@ impl_core_convert_from!( AlternateE, AlternateF, AlternateG, - #[hal_cfg(any("port-d21", "port-d5x"))] AlternateH, #[hal_cfg("port-d5x")] AlternateI, diff --git a/hal/src/gpio/reg.rs b/hal/src/gpio/reg.rs index e1229fa425ae..1eb865fe8da8 100644 --- a/hal/src/gpio/reg.rs +++ b/hal/src/gpio/reg.rs @@ -125,7 +125,6 @@ impl From for ModeFields { G => { fields.pmux = 6; } - #[hal_cfg(any("port-d21", "port-d5x"))] H => { fields.pmux = 7; } From 710d68886688b06985a32954e4bb623854c10fbc Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 10:31:09 +1200 Subject: [PATCH 51/75] fix build for SAMD11 --- hal/src/clock/v2/apb.rs | 52 +++++++++++++++++++++++++++++++++++--- hal/src/clock/v2/osc32k.rs | 2 +- hal/src/clock/v2/pclk.rs | 10 +++++--- hal/src/clock/v2/types.rs | 3 +++ 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index dab3f3e11d76..a701134241b4 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -519,8 +519,9 @@ define_apb_types!( ); // SAMD21/DA1 datasheet DS40001882H, Table 12-1. Peripherals Configuration -// Summary TODO I2S needs to be added (disabled on startup) -#[hal_cfg(any("clock-d11", "clock-d21"))] +// Summary +#[hal_macro_helper] +#[hal_cfg("clock-d21")] define_apb_types!( A { Pac0 = (0, all, any) @@ -537,7 +538,8 @@ define_apb_types!( NvmCtrl = (2, all, any) Port = (3, all, any) Dmac = (4, all, any) - Usb = (5, all, any) // TODO should be conditional + #[hal_cfg("usb")] + Usb = (5, all, any) } C { Pac2 = (0, any, all) @@ -557,6 +559,50 @@ define_apb_types!( Adc0 = (16, any, all) Ac = (17, any, all) Dac = (18, any, all) + Ptc = (19, any, all) + #[hal_cfg("i2s")] + I2S = (20, any, all) + Ac1 = (21, any, all) + } +); + +// Atmel-42363H-SAM-D11-Datasheet_09/2016, Table 11-1. Peripherals Configuration +// Summary +#[hal_macro_helper] +#[hal_cfg("clock-d11")] +define_apb_types!( + A { + Pac0 = (0, all, any) + Pm = (1, all, any) + SysCtrl = (2, all, any) + Gclk = (3, all, any) + Wdt = (4, all, any) + Rtc = (5, all, any) + Eic = (6, all, any) + } + B { + Pac1 = (0, all, any) + Dsu = (1, all, any) + NvmCtrl = (2, all, any) + Port = (3, all, any) + Dmac = (4, all, any) + #[hal_cfg("usb")] + Usb = (5, all, any) + } + C { + Pac2 = (0, any, all) + EvSys = (1, any, all) + Sercom0 = (2, any, all) + Sercom1 = (3, any, all) + #[hal_cfg("sercom2")] + Sercom2 = (4, any, all) + Tcc0 = (5, any, all) + Tc1 = (6, any, all) + Tc2 = (7, any, all) + Adc0 = (8, any, all) + Ac = (9, any, all) + Dac = (10, any, all) + Ptc = (11, any, all) } ); diff --git a/hal/src/clock/v2/osc32k.rs b/hal/src/clock/v2/osc32k.rs index 7e1c49f0b698..39d7fb2dc646 100644 --- a/hal/src/clock/v2/osc32k.rs +++ b/hal/src/clock/v2/osc32k.rs @@ -522,7 +522,7 @@ impl Source for EnabledOsc1k { #[inline] fn freq(&self) -> Hertz { - Hertz(1024) + 1_024u32.Hz() } } diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index f8f87522eaa5..49c9abb2cd1a 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -212,16 +212,18 @@ pub mod ids { pub use super::super::types::{ Ac, Adc0, Adc1, CM4Trace, Ccl, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, FreqMMeasure, FreqMReference, PDec, - Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Tcc0Tcc1, Tcc2Tcc3, Usb, + Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Tcc2Tcc3, Usb, }; #[hal_cfg(any("clock-d11", "clock-d21"))] pub use super::super::types::{ Ac, AcAna, AcDig, Adc0, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, - EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, Ptc, Rtc, SercomSlow, SlowClk, Tcc0Tcc1, Usb, - Wdt, + EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, Ptc, Rtc, SercomSlow, SlowClk, Usb, Wdt, }; + #[hal_cfg("clock-d11")] + pub use super::super::types::{Tc1Tc2, Tcc0}; + #[hal_cfg("can0")] pub use super::super::types::Can0; #[hal_cfg("can1")] @@ -232,6 +234,8 @@ pub mod ids { pub use super::super::types::Tc4Tc5; #[hal_cfg(all("tc6", "tc7"))] pub use super::super::types::Tc6Tc7; + #[hal_cfg(all("tcc0", "tcc1"))] + pub use super::super::types::Tcc0Tcc1; #[hal_cfg("tcc4")] pub use super::super::types::Tcc4; diff --git a/hal/src/clock/v2/types.rs b/hal/src/clock/v2/types.rs index f16b7d3eb053..93b8dc81e7eb 100644 --- a/hal/src/clock/v2/types.rs +++ b/hal/src/clock/v2/types.rs @@ -119,6 +119,9 @@ create_types!(Tcc0Tcc1); #[hal_cfg(all("tcc2", "tcc3"))] create_types!(Tcc2Tcc3); +#[hal_cfg(all("tc1-d11", "tc2-d11"))] +create_types!(Tc1Tc2); + #[hal_cfg(all("tcc2", "tc3-d21"))] create_types!(Tcc2Tc3); From b769f1103d0ac158ff69033e07922ffc2f1db6b1 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 10:59:28 +1200 Subject: [PATCH 52/75] L variants don't have xosc32k --- atsamd-hal-macros/devices.yaml | 3 +++ hal/src/clock/v2.rs | 5 ++++- hal/src/clock/v2/dpll.rs | 7 +++++++ hal/src/clock/v2/gclk.rs | 2 ++ hal/src/clock/v2/reset_thumbv6m.rs | 6 ++++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/atsamd-hal-macros/devices.yaml b/atsamd-hal-macros/devices.yaml index df6a7af81f8d..bcfb70f40688 100644 --- a/atsamd-hal-macros/devices.yaml +++ b/atsamd-hal-macros/devices.yaml @@ -21,6 +21,7 @@ families: - serial-numbers - dsu - clock + - xosc32k - xosc: { count: 1 } - gclk: { count: 6 } - pm @@ -54,6 +55,7 @@ families: - serial-numbers - dsu - clock + - xosc32k: { except: ["samd21el", "samd21gl"] } - xosc: { count: 1 } - gclk: { count: 8 } - pm @@ -98,6 +100,7 @@ families: - cmcc - dsu - clock + - xosc32k - xosc: { count: 2 } - gclk: { count: 12 } - mclk diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index eb689d63b6cb..99a3959fe1d4 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -882,7 +882,10 @@ pub mod pclk; pub mod rtcosc {} pub mod types; pub mod xosc; -pub mod xosc32k; +#[hal_module( + "xosc32k" => "v2/xosc32k.rs" +)] +pub mod xosc32k {} #[hal_module( any("clock-d11", "clock-d21") => "v2/reset_thumbv6m.rs", diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 7d033a5023d6..0101eff3a46c 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -272,6 +272,7 @@ use super::pclk::{Pclk, PclkId}; #[hal_cfg("xosc1")] use super::xosc::Xosc1Id; use super::xosc::{Xosc0Id, XoscId}; +#[hal_cfg("xosc32k")] use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -598,6 +599,7 @@ impl DpllSourceId for Xosc1Id { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc1; type Reference = settings::Xosc; } +#[hal_cfg("xosc32k")] impl DpllSourceId for Xosc32kId { const DYN: DynDpllSourceId = DynDpllSourceId::Xosc32k; type Reference = settings::Xosc32k; @@ -693,7 +695,9 @@ struct Settings { /// Store and retrieve [`Dpll`] settings for different reference clocks mod settings { use super::super::pclk; + #[hal_cfg("xosc32k")] use super::RateExtU32; + use super::hal_cfg; use super::{DpllId, GclkId, Hertz}; /// [`Dpll`] settings when referenced to a [`Pclk`] @@ -717,6 +721,7 @@ mod settings { /// /// [`Dpll`]: super::Dpll /// [`Xosc32k`]: super::super::xosc32k::Xosc32k + #[hal_cfg("xosc32k")] pub struct Xosc32k; /// Generic interface for the frequency and predivider of a reference clock @@ -747,6 +752,7 @@ mod settings { } } + #[hal_cfg("xosc32k")] impl Reference for Xosc32k { #[inline] fn freq(&self) -> Hertz { @@ -931,6 +937,7 @@ where } } +#[hal_cfg("xosc32k")] impl Dpll { /// Create a [`Dpll`] from an [`Xosc32k`] /// diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 56ba297be998..e6cdd0ebed2f 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -362,6 +362,7 @@ use super::osculp32k::OscUlp32kId; use super::xosc::Xosc0Id; #[hal_cfg("xosc1")] use super::xosc::Xosc1Id; +#[hal_cfg("xosc32k")] use super::xosc32k::Xosc32kId; use super::{Enabled, Source}; @@ -1093,6 +1094,7 @@ impl GclkSourceId for Xosc1Id { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc1; type Resource = (); } +#[hal_cfg("xosc32k")] impl GclkSourceId for Xosc32kId { const DYN: DynGclkSourceId = DynGclkSourceId::Xosc32k; type Resource = (); diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index ef4ede831cb6..521159205195 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -2,6 +2,8 @@ //! from the `v2` module, which is where the corresponding documentation will //! appear. +use atsamd_hal_macros::hal_macro_helper; + use typenum::U1; use crate::pac::{Gclk, Pm, Sysctrl}; @@ -108,6 +110,7 @@ pub struct Clocks { /// As described in the [top-level](super::super) documentation for the `clock` /// module, token types are used to guanrantee the uniqueness of each clock. To /// configure or enable a clock, you must provide the corresponding token. +#[hal_macro_helper] pub struct Tokens { /// Tokens to create [`apb::ApbClk`]s pub apbs: apb::ApbTokens, @@ -125,6 +128,7 @@ pub struct Tokens { pub xosc: xosc::XoscToken, /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and /// [`xosc32k::Xosc32k`] + #[hal_cfg("xosc32k")] pub xosc32k: xosc32k::Xosc32kTokens, } @@ -168,6 +172,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl wdt, osculp, }; + #[hal_macro_helper] let tokens = Tokens { apbs: apb::ApbTokens::new(), dfll: dfll::DfllToken::new(), @@ -176,6 +181,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl pclks: pclk::PclkTokens::new(), osc32k: osc32k::Osc32kTokens::new(), xosc: xosc::XoscToken::new(), + #[hal_cfg("xosc32k")] xosc32k: xosc32k::Xosc32kTokens::new(), }; (buses, clocks, tokens) From 30fc013e5910a2a86247bbe49efe5ac9b4ddbd6a Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 11:00:06 +1200 Subject: [PATCH 53/75] Fixes for SAMD21E --- hal/src/clock/v2/apb.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index a701134241b4..27b9eb6680a2 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -548,7 +548,9 @@ define_apb_types!( Sercom1 = (3, any, all) Sercom2 = (4, any, all) Sercom3 = (5, any, all) + #[hal_cfg("sercom4")] Sercom4 = (6, any, all) + #[hal_cfg("sercom5")] Sercom5 = (7, any, all) Tcc0 = (8, any, all) Tcc1 = (9, any, all) From 3807c6efd7309425a378fe9e6417a64ff0e443da Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Tue, 29 Jul 2025 11:45:00 +1200 Subject: [PATCH 54/75] Fix builds for smaller SAMD51 --- hal/src/clock/v1_thumbv7em.rs | 1 + hal/src/clock/v2/pclk.rs | 5 ++++- hal/src/peripherals/pwm/d5x.rs | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hal/src/clock/v1_thumbv7em.rs b/hal/src/clock/v1_thumbv7em.rs index b6369fa3a429..efdd9572fc9e 100644 --- a/hal/src/clock/v1_thumbv7em.rs +++ b/hal/src/clock/v1_thumbv7em.rs @@ -439,6 +439,7 @@ clock_generator!( (tc0_tc1, Tc0Tc1Clock, TC0_TC1, Tc0Tc1), (tcc0_tcc1, Tcc0Tcc1Clock, TCC0_TCC1, Tcc0Tcc1), (tc2_tc3, Tc2Tc3Clock, TC2_TC3, Tc2Tc3), + #[hal_cfg(all("tcc2", "tcc3"))] (tcc2_tcc3, Tcc2Tcc3Clock, TCC2_TCC3, Tcc2Tcc3), #[hal_cfg(all("tc4", "tc5"))] (tc4_tc5, Tc4Tc5Clock, TC4_TC5, Tc4Tc5), diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 49c9abb2cd1a..137b81debe03 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -212,7 +212,7 @@ pub mod ids { pub use super::super::types::{ Ac, Adc0, Adc1, CM4Trace, Ccl, Dac, Eic, EvSys0, EvSys1, EvSys2, EvSys3, EvSys4, EvSys5, EvSys6, EvSys7, EvSys8, EvSys9, EvSys10, EvSys11, FreqMMeasure, FreqMReference, PDec, - Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Tcc2Tcc3, Usb, + Sdhc0, SlowClk, Tc0Tc1, Tc2Tc3, Usb, }; #[hal_cfg(any("clock-d11", "clock-d21"))] @@ -236,6 +236,8 @@ pub mod ids { pub use super::super::types::Tc6Tc7; #[hal_cfg(all("tcc0", "tcc1"))] pub use super::super::types::Tcc0Tcc1; + #[hal_cfg(all("tcc2", "tcc3"))] + pub use super::super::types::Tcc2Tcc3; #[hal_cfg("tcc4")] pub use super::super::types::Tcc4; @@ -320,6 +322,7 @@ macro_rules! with_pclk_types_ids { (Can0 = 27, can0) #[hal_cfg("can1")] (Can1 = 28, can1) + #[hal_cfg(all("tcc2", "tcc3"))] (Tcc2Tcc3 = 29, tcc2_tcc3) #[hal_cfg(all("tc4", "tc5"))] (Tc4Tc5 = 30, tc4_tc5) diff --git a/hal/src/peripherals/pwm/d5x.rs b/hal/src/peripherals/pwm/d5x.rs index a9094fac4ac6..c6b3400b3121 100644 --- a/hal/src/peripherals/pwm/d5x.rs +++ b/hal/src/peripherals/pwm/d5x.rs @@ -680,9 +680,9 @@ impl $crate::ehal_02::Pwm for $TYPE { pwm_tcc! { Tcc0Pwm: (Tcc0, TCC0Pinout, Tcc0Tcc1Clock, apbbmask, tcc0_, TccPwm0Wrapper) } #[hal_cfg("tcc1")] pwm_tcc! { Tcc1Pwm: (Tcc1, TCC1Pinout, Tcc0Tcc1Clock, apbbmask, tcc1_, TccPwm1Wrapper) } -#[hal_cfg("tcc2")] +#[hal_cfg(all("tcc2", "tcc3"))] pwm_tcc! { Tcc2Pwm: (Tcc2, TCC2Pinout, Tcc2Tcc3Clock, apbcmask, tcc2_, TccPwm2Wrapper) } -#[hal_cfg("tcc3")] +#[hal_cfg(all("tcc2", "tcc3"))] pwm_tcc! { Tcc3Pwm: (Tcc3, TCC3Pinout, Tcc2Tcc3Clock, apbcmask, tcc3_, TccPwm3Wrapper) } #[hal_cfg("tcc4")] pwm_tcc! { Tcc4Pwm: (Tcc4, TCC4Pinout, Tcc4Clock, apbdmask, tcc4_, TccPwm4Wrapper) } From 623259faf37ed7defdc0cc658283ab3174d42105 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 08:51:23 +1200 Subject: [PATCH 55/75] Build on stable Rust --- hal/src/clock/v2/dfll.rs | 3 ++- hal/src/clock/v2/dpll.rs | 5 ++++- hal/src/clock/v2/gclk.rs | 4 ++++ hal/src/clock/v2/osculp32k.rs | 3 ++- hal/src/clock/v2/pclk.rs | 3 +++ hal/src/clock/v2/reset_thumbv6m.rs | 2 +- hal/src/clock/v2/xosc.rs | 5 ++++- hal/src/clock/v2/xosc32k.rs | 1 + hal/src/lib.rs | 4 ---- 9 files changed, 21 insertions(+), 9 deletions(-) diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index daa623f139d3..1f4dbfc91d24 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -272,7 +272,7 @@ //! [`from_usb`]: Dfll::from_usb //! [`into_mode`]: EnabledDfll::into_mode -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; #[hal_cfg("clock-d5x")] mod imports { @@ -433,6 +433,7 @@ impl DfllToken { } #[inline] + #[hal_macro_helper] fn disable(&mut self) { self.dfllctrl().write(|w| w.enable().clear_bit()); #[hal_cfg("clock-d5x")] diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 0101eff3a46c..8c295c89e529 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -312,6 +312,7 @@ impl DpllToken { /// Access the corresponding PAC `DPLL` struct #[inline] + #[hal_macro_helper] fn dpll(&self) -> &PacDpll { // Safety: Each `DpllToken` only has access to a mutually exclusive set // of registers for the corresponding `DpllId`, and we use a shared @@ -359,9 +360,9 @@ impl DpllToken { } #[inline] + #[hal_macro_helper] fn enable(&mut self, id: DynDpllSourceId, settings: Settings, prediv: u16) { // Convert the actual predivider to the `div` register field value - #[hal_macro_helper] let div = match id { DynDpllSourceId::Xosc0 => prediv / 2 - 1, #[hal_cfg("xosc1")] @@ -413,6 +414,7 @@ impl DpllToken { } #[inline] + #[hal_macro_helper] fn wait_enabled(&self) { #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} @@ -421,6 +423,7 @@ impl DpllToken { } #[inline] + #[hal_macro_helper] fn wait_disabled(&self) { #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index e6cdd0ebed2f..2a90661c57e4 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -407,6 +407,7 @@ impl GclkToken { /// Provide a reference to the corresponding [`Genctrl`] register #[inline] + #[hal_macro_helper] fn genctrl(&self) -> &Genctrl { // Safety: Each `GclkToken` only has access to a mutually exclusive set // of registers for the corresponding `GclkId`, and we use a shared @@ -433,6 +434,7 @@ impl GclkToken { /// Reads or writes to synchronized fields must be accompanied by a check of /// the `SYNCBUSY` register. See the datasheet for more details. #[inline] + #[hal_macro_helper] fn wait_syncbusy(&self) { // Safety: We are only reading from the `SYNCBUSY` register, and we are // only observing the bit corresponding to this particular `GclkId`, so @@ -461,6 +463,7 @@ impl GclkToken { /// Use the internal interface of [`GclkDivider`] to set the `DIV` and /// `DIVSEL` fields of the `GENCTRL` register. #[inline] + #[hal_macro_helper] fn set_div(&mut self, div: G::Divider) { let (divsel, div) = div.divsel_div(); // Safety: The `DIVSEL` and `DIV` values are derived from the @@ -515,6 +518,7 @@ impl GclkToken { } #[inline] + #[hal_macro_helper] fn enable(&mut self, id: DynGclkSourceId, settings: Settings) { let (divsel, div) = settings.div.divsel_div(); self.genctrl().write(|w| { diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index 916b4383b2e7..64a1cb72df56 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -162,7 +162,7 @@ //! [`clock_system_at_reset`]: super::clock_system_at_reset //! [`Clocks`]: super::Clocks -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use fugit::RateExtU32; use typenum::U0; @@ -221,6 +221,7 @@ pub struct OscUlp32kToken(()); impl OscUlp32kBaseToken { #[inline] + #[hal_macro_helper] fn osculp32k(&self) -> &Osculp32k { // Safety: The `OscUlp32kBaseToken` has exclusive access to the // `OSCULP32K` register. See the notes on `Token` types and memory diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 137b81debe03..991aa396ae6c 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -125,6 +125,7 @@ impl PclkToken

{ /// Access the corresponding `PCHCTRL` register #[inline] + #[hal_macro_helper] fn ctrl(&self) -> &Ctrl { // Safety: Each `PclkToken` only has access to a mutually exclusive set // of registers for the corresponding `PclkId`, and we use a shared @@ -142,6 +143,7 @@ impl PclkToken

{ /// Set the [`Pclk`] source #[inline] + #[hal_macro_helper] fn enable(&mut self, source: DynPclkSourceId) { self.ctrl().write(|w| { w.r#gen().variant(source.into()); @@ -157,6 +159,7 @@ impl PclkToken

{ /// Disable the [`Pclk`] #[inline] + #[hal_macro_helper] fn disable(&mut self) { self.ctrl().modify(|_, w| { #[hal_cfg(any("clock-d11", "clock-d21"))] diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index 521159205195..2f9728911de6 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -140,6 +140,7 @@ pub struct Tokens { /// /// See the [module-level documentation](super) for more details. #[inline] +#[hal_macro_helper] pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Clocks, Tokens) { // Safety: No bus, clock or token is instantiated more than once unsafe { @@ -172,7 +173,6 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl wdt, osculp, }; - #[hal_macro_helper] let tokens = Tokens { apbs: apb::ApbTokens::new(), dfll: dfll::DfllToken::new(), diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 55ac7e2c0ec7..7f0a437aad2f 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -204,7 +204,7 @@ //! [`Dfll`]: super::dfll::Dfll //! [`EnabledDfll`]: super::dfll::EnabledDfll -use atsamd_hal_macros::hal_cfg; +use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; use core::marker::PhantomData; use typenum::U0; @@ -273,6 +273,7 @@ impl XoscToken { /// Return a reference to the corresponding XOSCCTRL register #[inline] + #[hal_macro_helper] fn xoscctrl(&self) -> &Xoscctrl { // Safety: Each `XoscToken` only has access to a mutually exclusive set // of registers for the corresponding `XoscId`, and we use a shared @@ -290,6 +291,7 @@ impl XoscToken { /// Read the STATUS register #[inline] + #[hal_macro_helper] fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. @@ -358,6 +360,7 @@ impl XoscToken { /// Set most of the fields in the XOSCCTRL register #[inline] + #[hal_macro_helper] fn enable(&mut self, mode: DynMode, settings: Settings) { let xtalen = mode == DynMode::CrystalMode; // Safety: The `IMULT` and `IPTAT` values come from the diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index 32dafa8be796..a3cd6d7857df 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -453,6 +453,7 @@ impl Xosc32kTokens { impl Xosc32kBaseToken { #[inline] + #[hal_macro_helper] fn status(&self) -> STATUS_R { // Safety: We are only reading from the `STATUS` register, so there is // no risk of memory corruption. diff --git a/hal/src/lib.rs b/hal/src/lib.rs index f5f588c13a1d..4bf3008b7bba 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,8 +1,4 @@ #![no_std] -// TODO Allows using hal_cfg to gate clock v2 for thumbv6, nightly only -#![feature(proc_macro_hygiene)] -// TODO as above -#![feature(stmt_expr_attributes)] pub use embedded_hal_1 as ehal; use embedded_hal_02 as ehal_02; From 7feb11338e0f39e3c9ca633de893c23708b6a361 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 10:32:49 +1200 Subject: [PATCH 56/75] Update Feather M4 examples --- boards/feather_m4/examples/adc.rs | 5 ++--- boards/feather_m4/examples/blinky_rtic.rs | 22 +++++++--------------- boards/feather_m4/examples/clocking_v2.rs | 7 ++----- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/boards/feather_m4/examples/adc.rs b/boards/feather_m4/examples/adc.rs index b6b892cf43d3..a8d736b0b5c5 100644 --- a/boards/feather_m4/examples/adc.rs +++ b/boards/feather_m4/examples/adc.rs @@ -17,13 +17,13 @@ use bsp::Pins; use pac::{CorePeripherals, Peripherals}; use hal::{ - adc::{Accumulation, Adc, Prescaler, Resolution}, + adc::{Accumulation, Prescaler}, clock::v2::{clock_system_at_reset, pclk::Pclk}, }; #[entry] fn main() -> ! { - let mut peripherals = Peripherals::take().unwrap(); + let peripherals = Peripherals::take().unwrap(); let _core = CorePeripherals::take().unwrap(); let pins = Pins::new(peripherals.port); @@ -33,7 +33,6 @@ fn main() -> ! { peripherals.osc32kctrl, peripherals.gclk, peripherals.mclk, - &mut peripherals.nvmctrl, ); // Enable the ADC0 ABP clock... diff --git a/boards/feather_m4/examples/blinky_rtic.rs b/boards/feather_m4/examples/blinky_rtic.rs index d853e3f52262..8945f5cf130b 100644 --- a/boards/feather_m4/examples/blinky_rtic.rs +++ b/boards/feather_m4/examples/blinky_rtic.rs @@ -10,7 +10,7 @@ use panic_halt as _; #[cfg(feature = "use_semihosting")] use panic_semihosting as _; -use hal::clock::v2::{clock_system_at_reset, osculp32k::OscUlp1k, rtcosc::RtcOsc}; +use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; use hal::prelude::*; use hal::rtc::rtic::rtc_clock; use rtic::app; @@ -33,25 +33,17 @@ mod app { #[init] fn init(cx: init::Context) -> (Shared, Resources) { - let mut device = cx.device; + let device = cx.device; let mut core: rtic::export::Peripherals = cx.core; // Use v2 of the clocks API so that we can set the RTC clock source - let (_, clocks, tokens) = clock_system_at_reset( - device.oscctrl, - device.osc32kctrl, - device.gclk, - device.mclk, - &mut device.nvmctrl, - ); - - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - - // Enable the RTC clock with the 1 kHz source. + let (_, clocks, tokens) = + clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); + + // Enable the RTC clock with the internal 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); // Start the monotonic Mono::start(device.rtc); diff --git a/boards/feather_m4/examples/clocking_v2.rs b/boards/feather_m4/examples/clocking_v2.rs index 7a9b763bbe14..fa86e38d160f 100644 --- a/boards/feather_m4/examples/clocking_v2.rs +++ b/boards/feather_m4/examples/clocking_v2.rs @@ -8,7 +8,6 @@ use atsamd_hal::{ self as clock, dpll::Dpll, gclk::{Gclk, GclkDiv16, GclkDiv8}, - osculp32k::OscUlp32k, pclk::Pclk, rtcosc::RtcOsc, xosc32k::{ControlGainMode, Xosc1k, Xosc32k, Xosc32kBase}, @@ -43,7 +42,7 @@ mod app { #[init] fn init(cx: init::Context) -> (SharedResources, LocalResources) { - let mut device = cx.device; + let device = cx.device; // Get the clocks & tokens let (_buses, clocks, tokens) = clock::clock_system_at_reset( @@ -51,7 +50,6 @@ mod app { device.osc32kctrl, device.gclk, device.mclk, - &mut device.nvmctrl, ); // This is required because the `sercom` and `rtc` modules have not yet @@ -113,8 +111,7 @@ mod app { // Output `OscUlp32k` on PB11 pin via `Gclk5`, without any division resulting in // 32 kHz output frequency - let (osculp32k, _osculp_base) = - OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base); + let osculp32k = clocks.osculp.osculp32k; let (gclk5, _osculp32k) = Gclk::from_source(tokens.gclks.gclk5, osculp32k); let gclk5 = gclk5.enable(); let (_gclk5, _gclk5_out) = gclk5.enable_gclk_out(pins.pb11); From 9c816cb67a34e5d87509175c8c5f35099694bb9f Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 11:23:58 +1200 Subject: [PATCH 57/75] Deduplicate feather_m4 and metro_m4 blinky_rtc example --- Cargo.toml | 2 + boards/examples/m4-blinky_rtic.rs | 82 +++++++++++++++++++++++ boards/feather_m4/examples/blinky_rtic.rs | 74 +------------------- boards/metro_m4/examples/blinky_rtic.rs | 82 +---------------------- 4 files changed, 86 insertions(+), 154 deletions(-) create mode 100644 boards/examples/m4-blinky_rtic.rs diff --git a/Cargo.toml b/Cargo.toml index 6613515bbc01..c7e8accbc2ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,8 @@ members = [ "pac/*", "boards/*", ] +# Fragments of example files, referenced by `include!()` from BSP examples +exclude = ["boards/examples"] [profile.dev] debug = true diff --git a/boards/examples/m4-blinky_rtic.rs b/boards/examples/m4-blinky_rtic.rs new file mode 100644 index 000000000000..2a055d3c0918 --- /dev/null +++ b/boards/examples/m4-blinky_rtic.rs @@ -0,0 +1,82 @@ +// Blink an led using an RTIC software task and the RTC-based monotonic. +// +// This file is included by one or more BSP examples. In normal usage, firmware +// source code needs to start with something like: +// +// ``` +// #![no_std] +// #![no_main] +// use feather_m4 as bsp; +//``` + +use bsp::{hal, Pins, RedLed}; +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; +use hal::prelude::*; +use hal::rtc::rtic::rtc_clock; +use rtic::app; + +hal::rtc_monotonic!(Mono, rtc_clock::Clock1k); + +#[app(device = bsp::pac, dispatchers = [EVSYS_0])] +mod app { + use super::*; + + #[local] + struct Resources {} + + #[shared] + struct Shared { + // The LED could be a local resource, since it is only used in one task + // But we want to showcase shared resources and locking + red_led: RedLed, + } + + #[init] + fn init(cx: init::Context) -> (Shared, Resources) { + let device = cx.device; + let mut core: rtic::export::Peripherals = cx.core; + + // Use v2 of the clocks API so that we can set the RTC clock source + let (_, clocks, tokens) = + clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); + + // Enable the RTC clock with the internal 1 kHz source. + // Note that currently the proof of this (the `RtcOsc` instance) is not + // required to start the monotonic. + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); + + // Start the monotonic + Mono::start(device.rtc); + + let pins = Pins::new(device.port); + + // We can use the RTC in standby for maximum power savings + core.SCB.set_sleepdeep(); + + blink_led::spawn().ok().unwrap(); + + ( + Shared { + red_led: pins.d13.into_push_pull_output(), + }, + Resources {}, + ) + } + + /// This function is spawned and never returns. + #[task(priority = 1, shared=[red_led])] + async fn blink_led(mut cx: blink_led::Context) { + loop { + // If the LED were a local resource, the lock would not be necessary + cx.shared.red_led.lock(|led| { + led.toggle().unwrap(); + }); + Mono::delay(400u64.millis()).await; + } + } +} diff --git a/boards/feather_m4/examples/blinky_rtic.rs b/boards/feather_m4/examples/blinky_rtic.rs index 8945f5cf130b..812fc88b53a6 100644 --- a/boards/feather_m4/examples/blinky_rtic.rs +++ b/boards/feather_m4/examples/blinky_rtic.rs @@ -1,77 +1,5 @@ -//! Blink an led using an RTIC software task and the RTC-based monotonic. - #![no_std] #![no_main] -use bsp::{hal, Pins, RedLed}; use feather_m4 as bsp; -#[cfg(not(feature = "use_semihosting"))] -use panic_halt as _; -#[cfg(feature = "use_semihosting")] -use panic_semihosting as _; - -use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; -use hal::prelude::*; -use hal::rtc::rtic::rtc_clock; -use rtic::app; - -hal::rtc_monotonic!(Mono, rtc_clock::Clock1k); - -#[app(device = bsp::pac, dispatchers = [EVSYS_0])] -mod app { - use super::*; - - #[local] - struct Resources {} - - #[shared] - struct Shared { - // The LED could be a local resource, since it is only used in one task - // But we want to showcase shared resources and locking - red_led: RedLed, - } - - #[init] - fn init(cx: init::Context) -> (Shared, Resources) { - let device = cx.device; - let mut core: rtic::export::Peripherals = cx.core; - - // Use v2 of the clocks API so that we can set the RTC clock source - let (_, clocks, tokens) = - clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); - - // Enable the RTC clock with the internal 1 kHz source. - // Note that currently the proof of this (the `RtcOsc` instance) is not - // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); - - // Start the monotonic - Mono::start(device.rtc); - - let pins = Pins::new(device.port); - - // We can use the RTC in standby for maximum power savings - core.SCB.set_sleepdeep(); - - blink_led::spawn().ok().unwrap(); - - ( - Shared { - red_led: pins.d13.into_push_pull_output(), - }, - Resources {}, - ) - } - - /// This function is spawned and never returns. - #[task(priority = 1, shared=[red_led])] - async fn blink_led(mut cx: blink_led::Context) { - loop { - // If the LED were a local resource, the lock would not be necessary - cx.shared.red_led.lock(|led| { - led.toggle().unwrap(); - }); - Mono::delay(400u64.millis()).await; - } - } -} +include!("../../examples/m4-blinky_rtic.rs"); diff --git a/boards/metro_m4/examples/blinky_rtic.rs b/boards/metro_m4/examples/blinky_rtic.rs index 13f39d41d5c2..34b385542b1e 100644 --- a/boards/metro_m4/examples/blinky_rtic.rs +++ b/boards/metro_m4/examples/blinky_rtic.rs @@ -1,85 +1,5 @@ -//! Blink an led using an RTIC software task and the RTC-based monotonic. - #![no_std] #![no_main] -use bsp::{hal, Pins, RedLed}; use metro_m4 as bsp; -#[cfg(not(feature = "use_semihosting"))] -use panic_halt as _; -#[cfg(feature = "use_semihosting")] -use panic_semihosting as _; - -use hal::clock::v2::{clock_system_at_reset, osculp32k::OscUlp1k, rtcosc::RtcOsc}; -use hal::prelude::*; -use hal::rtc::rtic::rtc_clock; -use rtic::app; - -hal::rtc_monotonic!(Mono, rtc_clock::Clock1k); - -#[app(device = bsp::pac, dispatchers = [EVSYS_0])] -mod app { - use super::*; - - #[local] - struct Resources {} - - #[shared] - struct Shared { - // The LED could be a local resource, since it is only used in one task - // But we want to showcase shared resources and locking - red_led: RedLed, - } - - #[init] - fn init(cx: init::Context) -> (Shared, Resources) { - let mut device = cx.device; - let mut core: rtic::export::Peripherals = cx.core; - - // Use v2 of the clocks API so that we can set the RTC clock source - let (_, clocks, tokens) = clock_system_at_reset( - device.oscctrl, - device.osc32kctrl, - device.gclk, - device.mclk, - &mut device.nvmctrl, - ); - - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - - // Enable the RTC clock with the 1 kHz source. - // Note that currently the proof of this (the `RtcOsc` instance) is not - // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); - - // Start the monotonic - Mono::start(device.rtc); - - let pins = Pins::new(device.port); - - // We can use the RTC in standby for maximum power savings - core.SCB.set_sleepdeep(); - - blink_led::spawn().ok().unwrap(); - - ( - Shared { - red_led: pins.d13.into_push_pull_output(), - }, - Resources {}, - ) - } - - /// This function is spawned and never returns. - #[task(priority = 1, shared=[red_led])] - async fn blink_led(mut cx: blink_led::Context) { - loop { - // If the LED were a local resource, the lock would not be necessary - cx.shared.red_led.lock(|led| { - led.toggle().unwrap(); - }); - Mono::delay(400u64.millis()).await; - } - } -} +include!("../../examples/m4-blinky_rtic.rs"); From c362dbab19560b20cb80911e5a1e18271f23e6c4 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 11:35:34 +1200 Subject: [PATCH 58/75] Deduplicate feather_m4 and metro_m4 adc example --- boards/examples/m4-adc.rs | 63 +++++++++++++++++++++++++++ boards/feather_m4/examples/adc.rs | 55 +---------------------- boards/metro_m4/examples/adc.rs | 55 +---------------------- boards/metro_m4/examples/async_adc.rs | 5 +-- 4 files changed, 67 insertions(+), 111 deletions(-) create mode 100644 boards/examples/m4-adc.rs diff --git a/boards/examples/m4-adc.rs b/boards/examples/m4-adc.rs new file mode 100644 index 000000000000..f6278c5fadf7 --- /dev/null +++ b/boards/examples/m4-adc.rs @@ -0,0 +1,63 @@ +// This file is included by one or more BSP examples. In normal usage, firmware +// source code needs to start with something like: +// +// ``` +// #![no_std] +// #![no_main] +// use feather_m4 as bsp; +//``` + +use atsamd_hal::adc::AdcBuilder; + +use bsp::hal; +use bsp::pac; + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::entry; +use bsp::Pins; +use pac::{CorePeripherals, Peripherals}; + +use hal::{ + adc::{Accumulation, Prescaler}, + clock::v2::{clock_system_at_reset, pclk::Pclk}, +}; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take().unwrap(); + let _core = CorePeripherals::take().unwrap(); + + let pins = Pins::new(peripherals.port); + + let (mut buses, clocks, tokens) = clock_system_at_reset( + peripherals.oscctrl, + peripherals.osc32kctrl, + peripherals.gclk, + peripherals.mclk, + ); + + // Enable the ADC0 ABP clock... + let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); + // ...and enable the ADC0 PCLK. Both of these are required for the + // ADC to run. + let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); + + let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) + .with_clock_cycles_per_sample(5) + // Overruns if clock divider < 32 in debug mode + .with_clock_divider(Prescaler::Div32) + .with_vref(atsamd_hal::adc::Reference::Arefa) + .enable(peripherals.adc0, apb_adc0, &pclk_adc0) + .unwrap(); + let mut adc_pin = pins.a0.into_alternate(); + + loop { + let res = adc.read(&mut adc_pin); + #[cfg(feature = "use_semihosting")] + let _ = cortex_m_semihosting::hprintln!("ADC value: {}", res); + } +} diff --git a/boards/feather_m4/examples/adc.rs b/boards/feather_m4/examples/adc.rs index a8d736b0b5c5..98d4a974135a 100644 --- a/boards/feather_m4/examples/adc.rs +++ b/boards/feather_m4/examples/adc.rs @@ -1,58 +1,5 @@ #![no_std] #![no_main] -use atsamd_hal::adc::AdcBuilder; use feather_m4 as bsp; - -use bsp::hal; -use bsp::pac; - -#[cfg(not(feature = "use_semihosting"))] -use panic_halt as _; -#[cfg(feature = "use_semihosting")] -use panic_semihosting as _; - -use bsp::entry; -use bsp::Pins; -use pac::{CorePeripherals, Peripherals}; - -use hal::{ - adc::{Accumulation, Prescaler}, - clock::v2::{clock_system_at_reset, pclk::Pclk}, -}; - -#[entry] -fn main() -> ! { - let peripherals = Peripherals::take().unwrap(); - let _core = CorePeripherals::take().unwrap(); - - let pins = Pins::new(peripherals.port); - - let (mut buses, clocks, tokens) = clock_system_at_reset( - peripherals.oscctrl, - peripherals.osc32kctrl, - peripherals.gclk, - peripherals.mclk, - ); - - // Enable the ADC0 ABP clock... - let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); - // ...and enable the ADC0 PCLK. Both of these are required for the - // ADC to run. - let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); - - let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) - .with_clock_cycles_per_sample(5) - // Overruns if clock divider < 32 in debug mode - .with_clock_divider(Prescaler::Div32) - .with_vref(atsamd_hal::adc::Reference::Arefa) - .enable(peripherals.adc0, apb_adc0, &pclk_adc0) - .unwrap(); - let mut adc_pin = pins.a0.into_alternate(); - - loop { - let res = adc.read(&mut adc_pin); - #[cfg(feature = "use_semihosting")] - cortex_m_semihosting::hprintln!("ADC value: {}", res); - } -} +include!("../../examples/m4-adc.rs"); \ No newline at end of file diff --git a/boards/metro_m4/examples/adc.rs b/boards/metro_m4/examples/adc.rs index 56c46bbd97f7..8af58dc94ef4 100644 --- a/boards/metro_m4/examples/adc.rs +++ b/boards/metro_m4/examples/adc.rs @@ -1,58 +1,5 @@ #![no_std] #![no_main] -use atsamd_hal::adc::AdcBuilder; use metro_m4 as bsp; - -use bsp::hal; -use bsp::pac; - -#[cfg(not(feature = "use_semihosting"))] -use panic_halt as _; -#[cfg(feature = "use_semihosting")] -use panic_semihosting as _; - -use bsp::entry; -use bsp::Pins; -use pac::{CorePeripherals, Peripherals}; - -use hal::{ - adc::{Accumulation, Adc, Prescaler, Resolution}, - clock::v2::{clock_system_at_reset, pclk::Pclk}, -}; - -#[entry] -fn main() -> ! { - let mut peripherals = Peripherals::take().unwrap(); - let _core = CorePeripherals::take().unwrap(); - - let pins = Pins::new(peripherals.port); - - let (mut buses, clocks, tokens) = clock_system_at_reset( - peripherals.oscctrl, - peripherals.osc32kctrl, - peripherals.gclk, - peripherals.mclk, - &mut peripherals.nvmctrl, - ); - - // Enable the ADC0 ABP clock... - let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); - // ...and enable the ADC0 PCLK. Both of these are required for the - // ADC to run. - let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); - - let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) - .with_clock_cycles_per_sample(5) - .with_clock_divider(Prescaler::Div32) - .with_vref(atsamd_hal::adc::Reference::Arefa) - .enable(peripherals.adc0, apb_adc0, &pclk_adc0) - .unwrap(); - let mut adc_pin = pins.a0.into_alternate(); - - loop { - let res = adc.read(&mut adc_pin); - #[cfg(feature = "use_semihosting")] - cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap(); - } -} +include!("../../examples/m4-adc.rs"); \ No newline at end of file diff --git a/boards/metro_m4/examples/async_adc.rs b/boards/metro_m4/examples/async_adc.rs index 818e395734d7..a9fe0763369f 100644 --- a/boards/metro_m4/examples/async_adc.rs +++ b/boards/metro_m4/examples/async_adc.rs @@ -16,7 +16,7 @@ use bsp::Pins; use pac::{CorePeripherals, Peripherals}; use hal::{ - adc::{Accumulation, Adc, Adc0, Prescaler, Resolution}, + adc::{Accumulation, Adc0, Prescaler}, clock::v2::{clock_system_at_reset, pclk::Pclk}, }; @@ -26,7 +26,7 @@ atsamd_hal::bind_multiple_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_s: embassy_executor::Spawner) -> ! { - let mut peripherals = Peripherals::take().unwrap(); + let peripherals = Peripherals::take().unwrap(); let _core = CorePeripherals::take().unwrap(); let pins = Pins::new(peripherals.port); @@ -36,7 +36,6 @@ async fn main(_s: embassy_executor::Spawner) -> ! { peripherals.osc32kctrl, peripherals.gclk, peripherals.mclk, - &mut peripherals.nvmctrl, ); // Enable the ADC0 ABP clock... From 7a9b29b201084175a8f061a98504fffdb75b4985 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 11:39:47 +1200 Subject: [PATCH 59/75] Update pygamer blinky_rtic example Couldn't deduplicate with the feather_m4 and metro_m4 examples, because the alias used for the LED is different. Sorting that out seems like a separate project. --- boards/pygamer/examples/blinky_rtic.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/boards/pygamer/examples/blinky_rtic.rs b/boards/pygamer/examples/blinky_rtic.rs index c4549b21702c..a13bb736f57f 100644 --- a/boards/pygamer/examples/blinky_rtic.rs +++ b/boards/pygamer/examples/blinky_rtic.rs @@ -8,7 +8,7 @@ use bsp::{hal, Pins, RedLed}; use panic_halt as _; use pygamer as bsp; -use hal::clock::v2::{clock_system_at_reset, osculp32k::OscUlp1k, rtcosc::RtcOsc}; +use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; use hal::prelude::*; use hal::rtc::rtic::rtc_clock; use rtic::app; @@ -31,25 +31,17 @@ mod app { #[init] fn init(cx: init::Context) -> (Shared, Resources) { - let mut device = cx.device; + let device = cx.device; let mut core: rtic::export::Peripherals = cx.core; // Use v2 of the clocks API so that we can set the RTC clock source - let (_, clocks, tokens) = clock_system_at_reset( - device.oscctrl, - device.osc32kctrl, - device.gclk, - device.mclk, - &mut device.nvmctrl, - ); - - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - - // Enable the RTC clock with the 1 kHz source. + let (_, clocks, tokens) = + clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); + + // Enable the RTC clock with the internal 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); // Start the monotonic Mono::start(device.rtc); From fe2959def6e05e6caf75158ff2626cd949c2a406 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 12:21:41 +1200 Subject: [PATCH 60/75] Update atsame54_xpro examples --- boards/atsame54_xpro/examples/blinky_rtic.rs | 10 +++------- boards/atsame54_xpro/examples/mcan.rs | 12 ++++-------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/boards/atsame54_xpro/examples/blinky_rtic.rs b/boards/atsame54_xpro/examples/blinky_rtic.rs index e331bedfcfa9..4289dfd56ee1 100644 --- a/boards/atsame54_xpro/examples/blinky_rtic.rs +++ b/boards/atsame54_xpro/examples/blinky_rtic.rs @@ -3,7 +3,7 @@ use atsame54_xpro as bsp; use bsp::hal; -use hal::clock::v2::{clock_system_at_reset, osculp32k::OscUlp1k, rtcosc::RtcOsc}; +use hal::clock::v2::{clock_system_at_reset, rtcosc::RtcOsc}; use hal::prelude::*; use hal::rtc::rtic::rtc_clock; use panic_rtt_target as _; @@ -27,7 +27,7 @@ mod app { #[init] fn init(ctx: init::Context) -> (Shared, Local) { - let mut device = ctx.device; + let device = ctx.device; let mut core: rtic::export::Peripherals = ctx.core; rtt_init_print!(); @@ -37,16 +37,12 @@ mod app { device.osc32kctrl, device.gclk, device.mclk, - &mut device.nvmctrl, ); - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - // Enable the RTC clock with the 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); // Start the monotonic Mono::start(device.rtc); diff --git a/boards/atsame54_xpro/examples/mcan.rs b/boards/atsame54_xpro/examples/mcan.rs index 5cad635297f6..6ba28ca63424 100644 --- a/boards/atsame54_xpro/examples/mcan.rs +++ b/boards/atsame54_xpro/examples/mcan.rs @@ -21,7 +21,7 @@ use atsame54_xpro as bsp; use bsp::hal; -use clock::{osculp32k::OscUlp1k, rtcosc::RtcOsc}; +use clock::rtcosc::RtcOsc; use hal::clock::v2 as clock; use hal::eic::{Ch15, Eic, ExtInt, Sense}; use hal::gpio::{Interrupt as GpioInterrupt, *}; @@ -115,7 +115,7 @@ mod app { can_memory: SharedMemory = SharedMemory::new() ])] fn init(ctx: init::Context) -> (Shared, Local) { - let mut device = ctx.device; + let device = ctx.device; rtt_init_print!(); rprintln!("Application up!"); @@ -125,16 +125,12 @@ mod app { device.osc32kctrl, device.gclk, device.mclk, - &mut device.nvmctrl, ); - // Enable the 1 kHz clock from the internal 32 kHz source - let (osculp1k, _) = OscUlp1k::enable(tokens.osculp32k.osculp1k, clocks.osculp32k_base); - // Enable the RTC clock with the 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not // required to start the monotonic. - let _ = RtcOsc::enable(tokens.rtcosc, osculp1k); + let _ = RtcOsc::enable(tokens.rtcosc, clocks.osculp.osculp1k); // Start the monotonic Mono::start(device.rtc); @@ -159,7 +155,7 @@ mod app { let _ = can1_standby.set_low(); - let (pclk_can1, gclk0) = clock::pclk::Pclk::enable(tokens.pclks.can1, gclk0); + let (pclk_can1, _gclk0) = clock::pclk::Pclk::enable(tokens.pclks.can1, gclk0); let (dependencies, _gclk0) = hal::can::Dependencies::new( gclk0, From e85d94d8e9d0956f4cfd42e54533e1d2e7c6fd83 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 12:31:04 +1200 Subject: [PATCH 61/75] dfll tidy --- hal/src/clock/v2/dfll.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index 1f4dbfc91d24..8227771c1ed6 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -274,7 +274,7 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; -#[hal_cfg("clock-d5x")] +#[hal_cfg("oscctrl")] mod imports { pub use crate::pac::Oscctrl as PERIPHERAL; pub use crate::pac::oscctrl::{ @@ -282,10 +282,10 @@ mod imports { }; } -#[hal_cfg(any("clock-d11", "clock-d21"))] +#[hal_cfg("sysctrl")] mod imports { pub use crate::pac::Sysctrl as PERIPHERAL; - pub use crate::pac::sysctrl::{Dfllctrl, Dfllmul, Dfllsync, RegisterBlock}; + pub use crate::pac::sysctrl::{Dfllctrl, Dfllmul, RegisterBlock}; } use fugit::RateExtU32; From 311c44b7ee77145402efbd9d27512dfd25ad6a66 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 12:48:34 +1200 Subject: [PATCH 62/75] TEMPORARY enable clock v2 for thumbv6 in delay --- hal/src/delay.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hal/src/delay.rs b/hal/src/delay.rs index 3ea6aa60bc8a..aad0273f3447 100644 --- a/hal/src/delay.rs +++ b/hal/src/delay.rs @@ -1,6 +1,5 @@ //! Delays -use atsamd_hal_macros::hal_cfg; use cortex_m::peripheral::SYST; use cortex_m::peripheral::syst::SystClkSource; @@ -9,10 +8,8 @@ use crate::ehal::delay::DelayNs; use crate::ehal_02; use crate::time::Hertz; -#[hal_cfg("rtc-d5x")] use crate::typelevel::Increment; -#[hal_cfg("rtc-d5x")] use crate::clock::v2::{Source, gclk::Gclk0Id}; /// System timer (SysTick) as a delay provider @@ -32,7 +29,6 @@ impl Delay { } } - #[hal_cfg("rtc-d5x")] /// Configures the system timer (SysTick) as a delay provide, compatible /// with the V2 clocking API pub fn new_with_source(mut syst: SYST, gclk0: S) -> (Self, S::Inc) From 2b9ba81bbcca4518a596746d603e9a20e268de60 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 12:52:02 +1200 Subject: [PATCH 63/75] Metro M0 blinky_basic update to clock v2 --- boards/metro_m0/examples/blinky_basic.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/boards/metro_m0/examples/blinky_basic.rs b/boards/metro_m0/examples/blinky_basic.rs index 0a41c9297814..5904df598d8f 100644 --- a/boards/metro_m0/examples/blinky_basic.rs +++ b/boards/metro_m0/examples/blinky_basic.rs @@ -11,24 +11,23 @@ use bsp::pac; use metro_m0 as bsp; use bsp::entry; -use hal::clock::GenericClockController; +use hal::clock::v2 as clock; use hal::delay::Delay; use hal::prelude::*; use pac::{CorePeripherals, Peripherals}; #[entry] fn main() -> ! { - let mut peripherals = Peripherals::take().unwrap(); + let peripherals = Peripherals::take().unwrap(); let core = CorePeripherals::take().unwrap(); - let mut clocks = GenericClockController::with_external_32kosc( - peripherals.gclk, - &mut peripherals.pm, - &mut peripherals.sysctrl, - &mut peripherals.nvmctrl, - ); + let (_buses, clocks, _tokens) = + clock::clock_system_at_reset(peripherals.gclk, peripherals.pm, peripherals.sysctrl); + + let gclk0 = clocks.gclk0; + let (mut delay, _gclk0) = Delay::new_with_source(core.SYST, gclk0); + let pins = bsp::Pins::new(peripherals.port); let mut red_led: bsp::RedLed = pins.d13.into(); - let mut delay = Delay::new(core.SYST, &mut clocks); loop { delay.delay_ms(200u8); red_led.set_high().unwrap(); From 5ca00a965fa8662efecb6de40828eec170bc26ab Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Wed, 30 Jul 2025 15:53:57 +1200 Subject: [PATCH 64/75] Clippy --- hal/src/clock/v2/apb.rs | 2 +- hal/src/clock/v2/dfll.rs | 8 ++++---- hal/src/clock/v2/dpll.rs | 2 +- hal/src/clock/v2/gclk.rs | 6 +++--- hal/src/clock/v2/osc.rs | 2 +- hal/src/clock/v2/osc32k.rs | 2 +- hal/src/clock/v2/osculp32k.rs | 4 ++-- hal/src/clock/v2/pclk.rs | 5 ++--- hal/src/clock/v2/xosc.rs | 4 ++-- hal/src/clock/v2/xosc32k.rs | 4 ++-- 10 files changed, 19 insertions(+), 20 deletions(-) diff --git a/hal/src/clock/v2/apb.rs b/hal/src/clock/v2/apb.rs index 27b9eb6680a2..1855be8fa7ab 100644 --- a/hal/src/clock/v2/apb.rs +++ b/hal/src/clock/v2/apb.rs @@ -198,7 +198,7 @@ impl Apb { #[inline] #[hal_cfg("clock-d5x")] fn apbdmask(&mut self) -> &Apbdmask { - &self.mclk().apbdmask() + self.mclk().apbdmask() } #[inline] diff --git a/hal/src/clock/v2/dfll.rs b/hal/src/clock/v2/dfll.rs index 8227771c1ed6..3dc39520b4db 100644 --- a/hal/src/clock/v2/dfll.rs +++ b/hal/src/clock/v2/dfll.rs @@ -337,13 +337,13 @@ impl DfllToken { #[hal_cfg("clock-d5x")] #[inline] fn dfllctrl(&self) -> &Dfllctrl { - &self.reg_block().dfllctrla() + self.reg_block().dfllctrla() } #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] fn dfllctrl(&self) -> &Dfllctrl { - &self.reg_block().dfllctrl() + self.reg_block().dfllctrl() } #[hal_cfg("clock-d5x")] @@ -354,13 +354,13 @@ impl DfllToken { #[inline] fn dfllmul(&self) -> &Dfllmul { - &self.reg_block().dfllmul() + self.reg_block().dfllmul() } #[hal_cfg("clock-d5x")] #[inline] fn dfllsync(&self) -> &Dfllsync { - &self.reg_block().dfllsync() + self.reg_block().dfllsync() } #[hal_cfg("clock-d5x")] diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index 8c295c89e529..e65886c973e4 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -320,7 +320,7 @@ impl DpllToken { // memory safety in the root of the `clock` module for more details. #[hal_cfg("oscctrl")] unsafe { - &(*Peripheral::PTR).dpll(D::NUM) + (*Peripheral::PTR).dpll(D::NUM) } #[hal_cfg("sysctrl")] unsafe { diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 2a90661c57e4..5d3717f579be 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -415,18 +415,18 @@ impl GclkToken { // memory safety in the root of the `clock` module for more details. #[hal_cfg("clock-d5x")] unsafe { - &(*pac::Gclk::PTR).genctrl(G::NUM) + (*pac::Gclk::PTR).genctrl(G::NUM) } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*pac::Gclk::PTR).genctrl() + (*pac::Gclk::PTR).genctrl() } } #[hal_cfg(any("clock-d11", "clock-d21"))] #[inline] fn gendiv(&self) -> &Gendiv { - unsafe { &(*pac::Gclk::PTR).gendiv() } + unsafe { (*pac::Gclk::PTR).gendiv() } } /// Block until synchronization has completed diff --git a/hal/src/clock/v2/osc.rs b/hal/src/clock/v2/osc.rs index 71fb9013e354..d0ebbae9c7a8 100644 --- a/hal/src/clock/v2/osc.rs +++ b/hal/src/clock/v2/osc.rs @@ -18,7 +18,7 @@ impl OscToken { } fn osc8m(&self) -> &Osc8m { - unsafe { &(*Sysctrl::PTR).osc8m() } + unsafe { (*Sysctrl::PTR).osc8m() } } fn enable(&mut self, settings: Settings) { diff --git a/hal/src/clock/v2/osc32k.rs b/hal/src/clock/v2/osc32k.rs index 39d7fb2dc646..3288210c1c73 100644 --- a/hal/src/clock/v2/osc32k.rs +++ b/hal/src/clock/v2/osc32k.rs @@ -254,7 +254,7 @@ impl Osc32kBaseToken { // Safety: The `Osc32kBaseToken` has exclusive access to the // `OSC32K` register. See the notes on `Token` types and memory // safety in the root of the `clock` module for more details. - unsafe { &(*crate::pac::Sysctrl::PTR).osc32k() } + unsafe { (*crate::pac::Sysctrl::PTR).osc32k() } } /// Set the calibration diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index 64a1cb72df56..df5b98136ac1 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -228,11 +228,11 @@ impl OscUlp32kBaseToken { // safety in the root of the `clock` module for more details. #[hal_cfg("osc32kctrl")] unsafe { - &(*crate::pac::Osc32kctrl::PTR).osculp32k() + (*crate::pac::Osc32kctrl::PTR).osculp32k() } #[hal_cfg("sysctrl")] unsafe { - &(*crate::pac::Sysctrl::PTR).osculp32k() + (*crate::pac::Sysctrl::PTR).osculp32k() } } diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index 991aa396ae6c..ace79da62e7a 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -133,11 +133,11 @@ impl PclkToken

{ // memory safety in the root of the `clock` module for more details. #[hal_cfg("clock-d5x")] unsafe { - &(*pac::Gclk::PTR).pchctrl(P::DYN as usize) + (*pac::Gclk::PTR).pchctrl(P::DYN as usize) } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*pac::Gclk::PTR).clkctrl() + (*pac::Gclk::PTR).clkctrl() } } @@ -186,7 +186,6 @@ impl PclkToken

{ /// ``` /// use atsamd_hal::clock::v2::pclk::ids::*; /// ``` - pub mod ids { use atsamd_hal_macros::hal_cfg; diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 7f0a437aad2f..4c1e5b2ef420 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -281,11 +281,11 @@ impl XoscToken { // memory safety in the root of the `clock` module for more details. #[hal_cfg("clock-d5x")] unsafe { - &(*Peripheral::PTR).xoscctrl(X::NUM) + (*Peripheral::PTR).xoscctrl(X::NUM) } #[hal_cfg(any("clock-d11", "clock-d21"))] unsafe { - &(*Peripheral::PTR).xosc() + (*Peripheral::PTR).xosc() } } diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index a3cd6d7857df..dbb8de87e9b9 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -478,7 +478,7 @@ impl Xosc32kBaseToken { // Safety: The `Xosc32kBaseToken` has exclusive access to the `XOSC32K` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { &(*PERIPHERAL::PTR).xosc32k() } + unsafe { (*PERIPHERAL::PTR).xosc32k() } } /// Reset the XOSC32K register @@ -570,7 +570,7 @@ impl Xosc32kCfdToken { // Safety: The `Xosc32kCfdToken` has exclusive access to the `Cfdctrl` // register. See the notes on `Token` types and memory safety in the // root of the `clock` module for more details. - unsafe { &(*PERIPHERAL::PTR).cfdctrl() } + unsafe { (*PERIPHERAL::PTR).cfdctrl() } } /// Enable clock failure detection and set the safe clock divider From 3494395feb44e4b330286eb9694a968ed60667d9 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 1 Aug 2025 21:31:57 +1200 Subject: [PATCH 65/75] Fix polarity in DPLL wait_enabled() --- hal/src/clock/v2/dpll.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index e65886c973e4..b67f3484a981 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -413,13 +413,14 @@ impl DpllToken { self.wait_disabled(); } + /// Waits for the enable bit to synchronize in the enabled state #[inline] #[hal_macro_helper] fn wait_enabled(&self) { #[hal_cfg("oscctrl")] while self.syncbusy().enable().bit_is_set() {} #[hal_cfg("sysctrl")] - while self.status().enable().bit_is_clear() {} + while self.status().enable().bit_is_set() {} } #[inline] From 3e16c949557138eb9c523960d215e8074da5a18d Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 1 Aug 2025 16:41:19 +1200 Subject: [PATCH 66/75] Fix missing ID field in GCLK divider selection --- hal/src/clock/v2/gclk.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 5d3717f579be..a7d42dcee23a 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -521,6 +521,13 @@ impl GclkToken { #[hal_macro_helper] fn enable(&mut self, id: DynGclkSourceId, settings: Settings) { let (divsel, div) = settings.div.divsel_div(); + #[hal_cfg(any("clock-d11", "clock-d21"))] + self.gendiv().write(|w| unsafe { + w.id().bits(G::NUM as u8); + w.div().bits(div) + }); + #[hal_cfg(any("clock-d11", "clock-d21"))] + self.wait_syncbusy(); self.genctrl().write(|w| { // Safety: The `DIVSEL` and `DIV` values are derived from the // `GclkDivider` type, so they are guaranteed to be valid. From 09584a5472b7c24bafc5a237993c96519d706f23 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Fri, 1 Aug 2025 16:54:37 +1200 Subject: [PATCH 67/75] GCLK refactor Reading the GCLK GENCTRL register isn't possible on the thumbv6m chips, on these there is only one GENCTRL register for the whole GCLK peripheral, in contrast to one GENCTRL per generator on the thumbv7em chips. On the thumbv6m chips, modifying GENCTRL is done by atomically writing the whole register, which has a field for the generator ID to be modified. The GENCTRL register had been modified from the GclkToken<> impl, per-field, but the state required to fill the other fields for the atomic register write wasn't available in the GclkToken<> scope. So, these GENCTRL accesses were moved up in to the Gclk<> impl. One more bit of state was added to the settings to handle the Output Enable bit. --- hal/src/clock/v2/gclk.rs | 288 ++++++++++++++++++++++----------------- 1 file changed, 163 insertions(+), 125 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index a7d42dcee23a..bfbd8fce5fc2 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -348,7 +348,7 @@ use crate::gpio::{self, AlternateH, AnyPin, Pin, PinId}; use crate::pac::gclk::Genctrl; #[hal_cfg(any("clock-d11", "clock-d21"))] use crate::pac::gclk::Gendiv; -use crate::pac::gclk::genctrl::Srcselect; +use crate::pac::gclk::genctrl::{self, Srcselect}; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; @@ -376,12 +376,13 @@ use super::{Enabled, Source}; /// various `Token` types can be exchanged for actual clock types. They /// typically represent clocks that are disabled at power-on reset. /// -/// [`GclkToken`]s are no different. All [`Gclk`]s other than [`Gclk0`] are -/// disabled at power-on reset. To use a [`Gclk`], you must first exchange the -/// token for an actual clock with [`Gclk::from_source`] or [`Gclk::from_pin`]. +/// [`GclkToken`]s are no different. [`Gclk`]s other than [`Gclk0`], and +/// [`Gclk2`] on SAMD21/SAMD11, are disabled at power-on reset. To use a +/// [`Gclk`], you must first exchange the token for an actual clock with +/// [`Gclk::from_source`] or [`Gclk::from_pin`]. /// /// [`GclkToken`] is generic over the [`GclkId`], where each corresponding token -/// represents one of the 12 respective [`Gclk`]s. +/// represents one of the [`Gclk`]s. pub struct GclkToken { generator: PhantomData, } @@ -450,109 +451,6 @@ impl GclkToken { while status.read().syncbusy().bit() {} } } - - /// Set the clock source for this [`Gclk`] - #[inline] - fn set_source(&mut self, source: DynGclkSourceId) { - self.genctrl().modify(|_, w| w.src().variant(source.into())); - self.wait_syncbusy(); - } - - /// Set the [`GclkDivider`] value - /// - /// Use the internal interface of [`GclkDivider`] to set the `DIV` and - /// `DIVSEL` fields of the `GENCTRL` register. - #[inline] - #[hal_macro_helper] - fn set_div(&mut self, div: G::Divider) { - let (divsel, div) = div.divsel_div(); - // Safety: The `DIVSEL` and `DIV` values are derived from the - // `GclkDivider` type, so they are guaranteed to be valid. - #[hal_cfg("clock-d5x")] - { - self.genctrl().modify(|_, w| unsafe { - w.divsel().bit(divsel); - w.div().bits(div) - }); - } - #[hal_cfg(any("clock-d11", "clock-d21"))] - { - self.genctrl().write(|w| { - unsafe { w.id().bits(G::NUM as u8) }; - w.divsel().bit(divsel) - }); - self.gendiv().write(|w| unsafe { w.div().bits(div) }); - } - self.wait_syncbusy(); - } - - /// Output a 50-50 duty-cycle clock when using an odd division factor - #[inline] - fn improve_duty_cycle(&mut self, flag: bool) { - self.genctrl().modify(|_, w| w.idc().bit(flag)); - self.wait_syncbusy(); - } - - /// Set the state of [`GclkOut`] pins when the GCLK_IO output is disabled - #[inline] - fn output_off_value(&mut self, high: bool) { - self.genctrl().modify(|_, w| w.oov().bit(high)); - self.wait_syncbusy(); - } - - /// Enable [`Gclk`] output to a GPIO [`Pin`] - #[inline] - fn enable_gclk_out(&mut self) { - self.genctrl().modify(|_, w| w.oe().set_bit()); - self.wait_syncbusy(); - } - - /// Disable [`Gclk`] output on a GPIO [`Pin`] - /// - /// If a corresponding [`Pin`] is in the [`AlternateH`] mode, it's logic - /// level will depend on the [`output_off_value`]. - #[inline] - fn disable_gclk_out(&mut self) { - self.genctrl().modify(|_, w| w.oe().clear_bit()); - self.wait_syncbusy(); - } - - #[inline] - #[hal_macro_helper] - fn enable(&mut self, id: DynGclkSourceId, settings: Settings) { - let (divsel, div) = settings.div.divsel_div(); - #[hal_cfg(any("clock-d11", "clock-d21"))] - self.gendiv().write(|w| unsafe { - w.id().bits(G::NUM as u8); - w.div().bits(div) - }); - #[hal_cfg(any("clock-d11", "clock-d21"))] - self.wait_syncbusy(); - self.genctrl().write(|w| { - // Safety: The `DIVSEL` and `DIV` values are derived from the - // `GclkDivider` type, so they are guaranteed to be valid. - unsafe { - #[hal_cfg("clock-d5x")] - w.div().bits(div); - #[hal_cfg(any("clock-d11", "clock-d21"))] - w.id().bits(G::NUM as u8); - }; - w.divsel().bit(divsel); - w.src().variant(id.into()); - w.idc().bit(settings.improve_duty_cycle); - w.oov().bit(settings.output_off_value) - }); - #[hal_cfg(any("clock-d11", "clock-d21"))] - self.gendiv().write(|w| unsafe { w.div().bits(div) }); - self.wait_syncbusy(); - } - - /// Disable the [`Gclk`] - #[inline] - fn disable(&mut self) { - self.genctrl().write(|w| w.genen().clear_bit()); - self.wait_syncbusy(); - } } //============================================================================== @@ -1133,11 +1031,16 @@ impl> NotGclkIo for I {} // Settings //============================================================================== -/// Collection of [`Gclk`] settings to configure on enable +/// Collection of [`Gclk`] settings +/// +/// This structure is largely required due to the thumbv6m chips sharing one +/// GENCTRL register among all the clock generators. On these chips, all fields +/// in the register need to be updated by a 32b atomic write. struct Settings { div: G::Divider, output_off_value: bool, improve_duty_cycle: bool, + output_enable: bool, } impl Clone for Settings { @@ -1154,6 +1057,7 @@ impl Default for Settings { div: G::Divider::default(), output_off_value: false, improve_duty_cycle: false, + output_enable: false, } } } @@ -1351,21 +1255,57 @@ where G: GclkId, I: GclkSourceId, { + #[hal_macro_helper] + fn update_genctrl(&self, writer: F, genen: bool) { + #[hal_cfg("clock-d5x")] + self.token.genctrl().modify(|_, w| { + let _ = genen; // Suppress warning on d5x builds + writer(w); + w + }); + + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + let (divsel, _div) = self.settings.div.divsel_div(); + + self.token.genctrl().write(|w| { + unsafe { w.id().bits(G::NUM as u8) }; + w.src().variant(I::DYN.into()); + w.divsel().bit(divsel); + w.oe().bit(self.settings.output_enable); + w.oov().bit(self.settings.output_off_value); + w.idc().bit(self.settings.improve_duty_cycle); + w.genen().bit(genen); + writer(w); + w + }); + } + self.token.wait_syncbusy(); + } + /// Modify the source of an existing clock /// /// This is a helper function for swapping Gclk0 to different clock sources. fn change_source( - mut self, + self, resource: N::Resource, freq: Hertz, ) -> (Gclk, I::Resource) { - self.token.set_source(N::DYN); let gclk = Gclk { token: self.token, resource, src_freq: freq, settings: self.settings, }; + + // Call update_genctrl() on object that has the correct source type + gclk.update_genctrl( + |w| { + w.src().variant(N::DYN.into()); + }, + // This method is always called on Gclk0, which is always enabled + true, + ); (gclk, self.resource) } @@ -1420,7 +1360,14 @@ where #[inline] pub fn output_off_value(mut self, high: bool) -> Self { self.settings.output_off_value = high; - self.token.output_off_value(high); + self.update_genctrl( + |w| { + w.oov().bit(high); + }, + // This method is only accessible via disabled GCLKs + false, + ); + self } @@ -1434,8 +1381,37 @@ where /// The returned value is an [`EnabledGclk`] that can be used as a clock /// [`Source`] for other clocks. #[inline] - pub fn enable(mut self) -> EnabledGclk { - self.token.enable(I::DYN, self.settings); + #[hal_macro_helper] + pub fn enable(self) -> EnabledGclk { + let (divsel, div) = self.settings.div.divsel_div(); + + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + self.token.gendiv().write(|w| unsafe { + w.id().bits(G::NUM as u8); + w.div().bits(div) + }); + self.token.wait_syncbusy(); + } + + self.token.genctrl().write(|w| { + // Safety: The `DIVSEL` and `DIV` values are derived from the + // `GclkDivider` type, so they are guaranteed to be valid. + unsafe { + #[hal_cfg("clock-d5x")] + w.div().bits(div); + #[hal_cfg(any("clock-d11", "clock-d21"))] + w.id().bits(G::NUM as u8); + }; + w.divsel().bit(divsel); + w.src().variant(I::DYN.into()); + w.idc().bit(self.settings.improve_duty_cycle); + w.oe().bit(self.settings.output_enable); + w.oov().bit(self.settings.output_off_value); + w.genen().set_bit() + }); + self.token.wait_syncbusy(); + Enabled::new(self) } } @@ -1450,8 +1426,13 @@ where /// This method is only implemented for `N = U0`, which means the clock can /// only be disabled when no other clocks consume this [`Gclk`]. #[inline] - pub fn disable(mut self) -> Gclk { - self.0.token.disable(); + pub fn disable(self) -> Gclk { + self.0.update_genctrl( + |w| { + w.genen().clear_bit(); + }, + false, + ); self.0 } } @@ -1473,6 +1454,11 @@ impl EnabledGclk0 { /// Swap [`Gclk0`] from one clock [`Source`] to another /// /// `Gclk0` will remain fully enabled during the swap. + /// + /// Note for thumbv6m chips: Before switching the Generic Clock Generator 0 + /// (GCLKGEN0) from a clock source A to another clock source B, enable the + /// "ONDEMAND" feature of the clock source A to ensure a proper transition + /// from clock source A to clock source B. #[inline] pub fn swap_sources(self, old: O, new: N) -> (EnabledGclk0, O::Dec, N::Inc) where @@ -1488,6 +1474,7 @@ impl EnabledGclk0 { /// Swap [`Gclk0`] from one [`GclkIo`] [`Pin`] to another /// /// `Gclk0` will remain fully enabled during the swap. + /// TODO there's only one input IO pad per... #[inline] pub fn swap_pins

( self, @@ -1549,16 +1536,46 @@ impl EnabledGclk0 { /// /// See [`Gclk::div`] documentation for more details. #[inline] - pub fn div(&mut self, div: GclkDiv8) { - self.0.settings.div = div; - self.0.token.set_div(div); + #[hal_macro_helper] + pub fn div(&mut self, divider: GclkDiv8) { + self.0.settings.div = divider; + + let (divsel, div) = divider.divsel_div(); + + // D5x div is in the GENCTRL register, smaller chips keep it separate + #[hal_cfg(any("clock-d11", "clock-d21"))] + { + self.0.token.gendiv().write(|w| unsafe { + w.id().bits(0); + w.div().bits(div) + }); + self.0.token.wait_syncbusy(); + } + + self.0.update_genctrl( + |w| { + // Safety: The `DIVSEL` and `DIV` values are derived from the + // `GclkDivider` type, so they are guaranteed to be valid. + #[hal_cfg("clock-d5x")] + unsafe { + w.div().bits(div); + } + w.divsel().bit(divsel); + }, + true, + ); } /// Output a 50-50 duty cycle clock when using an odd [`GclkDivider`] #[inline] pub fn improve_duty_cycle(&mut self, flag: bool) { self.0.settings.improve_duty_cycle = flag; - self.0.token.improve_duty_cycle(flag); + self.0.update_genctrl( + |w| { + w.idc().bit(flag); + }, + true, + ); } /// Return the [`Gclk0`] frequency @@ -1575,7 +1592,12 @@ impl EnabledGclk0 { #[inline] pub fn output_off_value(&mut self, high: bool) { self.0.settings.output_off_value = high; - self.0.token.output_off_value(high); + self.0.update_genctrl( + |w| { + w.oov().bit(high); + }, + true, + ); } } @@ -1711,9 +1733,18 @@ where P::Id: GclkIo, { let pin = pin.into().into_mode(); - let freq = self.freq(); - self.0.token.enable_gclk_out(); - let gclk_out = GclkOut { pin, freq }; + self.0.settings.output_enable = true; + self.0.update_genctrl( + |w| { + w.oe().set_bit(); + }, + true, + ); + + let gclk_out = GclkOut { + pin, + freq: self.freq(), + }; (self.inc(), gclk_out) } @@ -1732,7 +1763,14 @@ where N: Decrement, I: GclkIo, { - self.0.token.disable_gclk_out(); + self.0.settings.output_enable = false; + self.0.update_genctrl( + |w| { + w.oe().clear_bit(); + }, + true, + ); + (self.dec(), gclk_out.pin) } } From 08df818a36b09e156f910b921775ba5747bef44f Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 9 Aug 2025 16:57:21 +1200 Subject: [PATCH 68/75] GCLK refactor to update entire GENCTRL --- hal/src/clock/v2/gclk.rs | 123 +++++++++++++-------------------------- 1 file changed, 39 insertions(+), 84 deletions(-) diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index bfbd8fce5fc2..7b6b119b700a 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -348,7 +348,7 @@ use crate::gpio::{self, AlternateH, AnyPin, Pin, PinId}; use crate::pac::gclk::Genctrl; #[hal_cfg(any("clock-d11", "clock-d21"))] use crate::pac::gclk::Gendiv; -use crate::pac::gclk::genctrl::{self, Srcselect}; +use crate::pac::gclk::genctrl::Srcselect; use crate::time::Hertz; use crate::typelevel::{Decrement, Increment, PrivateDecrement, PrivateIncrement, Sealed}; @@ -1255,31 +1255,49 @@ where G: GclkId, I: GclkSourceId, { + /// Updates the GENCTRL register based on self.settings + /// + /// The thumbv7em chips use one GENCTRL per clock generator and are capable + /// of read-modify-write operations, but the thumbv6 chips share one GENCTRL + /// register among the clock generators so only support writes. To + /// accommodate both, this implementation maintains a [`Settings`] struct + /// containing the GENCTRL settings, and this method is called after + /// updating it to apply them. #[hal_macro_helper] - fn update_genctrl(&self, writer: F, genen: bool) { + fn update_genctrl(&self, genen: bool) { + let (divsel, div) = self.settings.div.divsel_div(); + #[hal_cfg("clock-d5x")] self.token.genctrl().modify(|_, w| { - let _ = genen; // Suppress warning on d5x builds - writer(w); - w + w.divsel().bit(divsel); + // Safety: The `DIVSEL` and `DIV` values are derived from the + // `GclkDivider` type, so they are guaranteed to be valid. + unsafe { + w.div().bits(div); + } + w.oe().bit(self.settings.output_enable); + w.oov().bit(self.settings.output_off_value); + w.idc().bit(self.settings.improve_duty_cycle); + w.genen().bit(genen); + w.src().variant(I::DYN.into()) }); #[hal_cfg(any("clock-d11", "clock-d21"))] { - let (divsel, _div) = self.settings.div.divsel_div(); + // Suppress warning for thumbv7em builds + let _ = div; self.token.genctrl().write(|w| { - unsafe { w.id().bits(G::NUM as u8) }; - w.src().variant(I::DYN.into()); w.divsel().bit(divsel); w.oe().bit(self.settings.output_enable); w.oov().bit(self.settings.output_off_value); w.idc().bit(self.settings.improve_duty_cycle); w.genen().bit(genen); - writer(w); - w + w.src().variant(I::DYN.into()); + unsafe { w.id().bits(G::NUM as u8) } }); } + self.token.wait_syncbusy(); } @@ -1300,9 +1318,6 @@ where // Call update_genctrl() on object that has the correct source type gclk.update_genctrl( - |w| { - w.src().variant(N::DYN.into()); - }, // This method is always called on Gclk0, which is always enabled true, ); @@ -1361,9 +1376,6 @@ where pub fn output_off_value(mut self, high: bool) -> Self { self.settings.output_off_value = high; self.update_genctrl( - |w| { - w.oov().bit(high); - }, // This method is only accessible via disabled GCLKs false, ); @@ -1373,20 +1385,14 @@ where /// Enable the [`Gclk`], so that it can be used as a clock [`Source`] /// - /// As mentioned in the [`Gclk`] documentation, no hardware registers are - /// actually modified until this call. Rather, the desired configuration is - /// stored internally, and the [`Gclk`] is initialized and configured here - /// according to the datasheet. - /// /// The returned value is an [`EnabledGclk`] that can be used as a clock /// [`Source`] for other clocks. #[inline] #[hal_macro_helper] pub fn enable(self) -> EnabledGclk { - let (divsel, div) = self.settings.div.divsel_div(); - #[hal_cfg(any("clock-d11", "clock-d21"))] { + let (_divsel, div) = self.settings.div.divsel_div(); self.token.gendiv().write(|w| unsafe { w.id().bits(G::NUM as u8); w.div().bits(div) @@ -1394,23 +1400,7 @@ where self.token.wait_syncbusy(); } - self.token.genctrl().write(|w| { - // Safety: The `DIVSEL` and `DIV` values are derived from the - // `GclkDivider` type, so they are guaranteed to be valid. - unsafe { - #[hal_cfg("clock-d5x")] - w.div().bits(div); - #[hal_cfg(any("clock-d11", "clock-d21"))] - w.id().bits(G::NUM as u8); - }; - w.divsel().bit(divsel); - w.src().variant(I::DYN.into()); - w.idc().bit(self.settings.improve_duty_cycle); - w.oe().bit(self.settings.output_enable); - w.oov().bit(self.settings.output_off_value); - w.genen().set_bit() - }); - self.token.wait_syncbusy(); + self.update_genctrl(true); Enabled::new(self) } @@ -1427,12 +1417,7 @@ where /// only be disabled when no other clocks consume this [`Gclk`]. #[inline] pub fn disable(self) -> Gclk { - self.0.update_genctrl( - |w| { - w.genen().clear_bit(); - }, - false, - ); + self.0.update_genctrl(false); self.0 } } @@ -1540,11 +1525,12 @@ impl EnabledGclk0 { pub fn div(&mut self, divider: GclkDiv8) { self.0.settings.div = divider; - let (divsel, div) = divider.divsel_div(); - // D5x div is in the GENCTRL register, smaller chips keep it separate #[hal_cfg(any("clock-d11", "clock-d21"))] { + let (_divsel, div) = divider.divsel_div(); + // Safety: The `DIVSEL` and `DIV` values are derived from the + // `GclkDivider` type, so they are guaranteed to be valid. self.0.token.gendiv().write(|w| unsafe { w.id().bits(0); w.div().bits(div) @@ -1552,30 +1538,14 @@ impl EnabledGclk0 { self.0.token.wait_syncbusy(); } - self.0.update_genctrl( - |w| { - // Safety: The `DIVSEL` and `DIV` values are derived from the - // `GclkDivider` type, so they are guaranteed to be valid. - #[hal_cfg("clock-d5x")] - unsafe { - w.div().bits(div); - } - w.divsel().bit(divsel); - }, - true, - ); + self.0.update_genctrl(true); } /// Output a 50-50 duty cycle clock when using an odd [`GclkDivider`] #[inline] pub fn improve_duty_cycle(&mut self, flag: bool) { self.0.settings.improve_duty_cycle = flag; - self.0.update_genctrl( - |w| { - w.idc().bit(flag); - }, - true, - ); + self.0.update_genctrl(true); } /// Return the [`Gclk0`] frequency @@ -1592,12 +1562,7 @@ impl EnabledGclk0 { #[inline] pub fn output_off_value(&mut self, high: bool) { self.0.settings.output_off_value = high; - self.0.update_genctrl( - |w| { - w.oov().bit(high); - }, - true, - ); + self.0.update_genctrl(true); } } @@ -1734,12 +1699,7 @@ where { let pin = pin.into().into_mode(); self.0.settings.output_enable = true; - self.0.update_genctrl( - |w| { - w.oe().set_bit(); - }, - true, - ); + self.0.update_genctrl(true); let gclk_out = GclkOut { pin, @@ -1764,12 +1724,7 @@ where I: GclkIo, { self.0.settings.output_enable = false; - self.0.update_genctrl( - |w| { - w.oe().clear_bit(); - }, - true, - ); + self.0.update_genctrl(true); (self.dec(), gclk_out.pin) } From b777ade2dfedfc8999ea45c318ab356d68a344bb Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sat, 9 Aug 2025 22:30:45 +1200 Subject: [PATCH 69/75] bsp(atsame54_xpro): Fix example --- boards/atsame54_xpro/examples/mcan.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/atsame54_xpro/examples/mcan.rs b/boards/atsame54_xpro/examples/mcan.rs index 6ba28ca63424..d79541b3561c 100644 --- a/boards/atsame54_xpro/examples/mcan.rs +++ b/boards/atsame54_xpro/examples/mcan.rs @@ -155,7 +155,7 @@ mod app { let _ = can1_standby.set_low(); - let (pclk_can1, _gclk0) = clock::pclk::Pclk::enable(tokens.pclks.can1, gclk0); + let (pclk_can1, gclk0) = clock::pclk::Pclk::enable(tokens.pclks.can1, gclk0); let (dependencies, _gclk0) = hal::can::Dependencies::new( gclk0, From 1bd2100fb737c794aed754d1a2a7ffafa1252aa3 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 17 Aug 2025 09:27:06 +1200 Subject: [PATCH 70/75] Documentation warnings for SAMD21G --- hal/src/clock/v2.rs | 85 ++++++++++++++---------------- hal/src/clock/v2/dpll.rs | 23 ++++---- hal/src/clock/v2/gclk.rs | 32 +++++------ hal/src/clock/v2/osc32k.rs | 42 +++++++-------- hal/src/clock/v2/osculp32k.rs | 20 +++++-- hal/src/clock/v2/reset_thumbv6m.rs | 16 +++--- hal/src/clock/v2/xosc.rs | 54 +++++++++++-------- hal/src/clock/v2/xosc32k.rs | 58 +++++++++++++------- hal/src/sercom/dma.rs | 14 +++-- 9 files changed, 186 insertions(+), 158 deletions(-) diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 99a3959fe1d4..3095055a5b80 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -65,7 +65,7 @@ //! In general, there are two classes of clock in ATSAMD chips. Some clocks map //! one-to-one (1:1) to a specific bus or peripheral. This is true for the AHB //! clocks ([`AhbClk`]s), APB clocks ([`ApbClk`]s), GCLK outputs ([`GclkOut`]s), -//! peripheral channel clocks ([`Pclk`]s), and RTC oscillator ([`RtcOsc`]). +//! peripheral channel clocks ([`Pclk`]s), and RTC oscillator (`RtcOsc`). //! Other clocks form one-to-many (1:N) relationships, like the external crystal //! oscillator ([`Xosc`]), the 48 MHz DFLL ([`Dfll`]) or the two DPLLs //! ([`Dpll`]). @@ -115,9 +115,9 @@ //! on the movement of `Producer` objects. //! //! Instead, the `clock` module takes a different approach. It uses type-level -//! programming to track, at compile-time, the number of consumer clocks, N, -//! fed by a particular producer clock. With this approach, we can move -//! `Producer` objects while still making them impossible to modify if N > 0. +//! programming to track, at compile-time, the number of consumer clocks, N, fed +//! by a particular producer clock. With this approach, we can move `Producer` +//! objects while still making them impossible to modify if N > 0. //! //! The following sections will describe the implementation of this strategy. //! @@ -175,9 +175,9 @@ //! can only `Decrement` the same producer it `Increment`ed. Stated differently, //! we need a way to track the identity of each consumer's clock source. //! -//! The [`Source`] trait is designed for this purpose. It marks -//! [`Enabled`] producer clocks, and it's associated type, [`Id`], is the -//! identity type that should be stored by consumers. +//! The [`Source`] trait is designed for this purpose. It marks [`Enabled`] producer clocks, and it's associated type, [`Id`], is the identity type +//! that should be stored by consumers. //! //! Given that all implementers of `Source` are instances of `Enabled`, //! the naïve choice for [`Source::Id`] would be `T`. However, in a moment, we @@ -194,8 +194,8 @@ //! //! While these type parameters are important and necessary for configuration of //! a given producer clock, they are not relevant to consumer clocks. A consumer -//! clock does not need to know or care which `Mode` the XOSC is using, but -//! it *does* need to track that its clock [`Source`] is XOSC0. +//! clock does not need to know or care which `Mode` the XOSC is using, but it +//! *does* need to track that its clock [`Source`] is XOSC0. //! //! From this, we can see that `Enabled, N>` should not implement //! `Source` with `Source::Id = Xosc0`, because that would require consumers @@ -219,13 +219,13 @@ //! corresponding clock. Moreover, they also fundamentally restructure the way //! registers are accessed relative to the [PAC]. //! -//! Each of the four PAC clocking structs ([`OSCCTRL`], [`OSC32KCTRL`], [`GCLK`] -//! and [`MCLK`]) is a singleton object that controls a set of MMIO registers. -//! It is impossible to create two instances of any PAC object without `unsafe`. -//! However, each object controls a large set of registers that can be further -//! sub-divided into smaller sets for individual clocks. For example, the -//! [`GCLK`] object controls registers for 12 different clock generators and 48 -//! peripheral channel clocks. +//! Each of the PAC clocking structs (which vary between targets, including +//! `OSCCTRL`, `SYSCTRL`, `OSC32KCTRL`, [`GCLK`] and `MCLK`) is a singleton object +//! that controls a set of MMIO registers. It is impossible to create two +//! instances of any PAC object without `unsafe`. However, each object controls +//! a large set of registers that can be further sub-divided into smaller sets +//! for individual clocks. For example, the [`GCLK`] object controls registers +//! for 12 different clock generators and 48 peripheral channel clocks. //! //! `Token` types serve to break up the large PAC objects into smaller, //! more-targetted pieces. And in the process, they also remove the PAC objects' @@ -238,8 +238,8 @@ //! Bus clocks are fundamentally different from the other clock types in this //! module, because they do not use mutually exclusive registers for //! configuration. For instance, the registers that control [`Dpll0`] are -//! mutually exclusive to those that control [`Dpll1`], but `ApbClk` -//! and `ApbClk` share a single register. +//! mutually exclusive to those that control `Dpll1`, but `ApbClk` and +//! `ApbClk` share a single register. //! //! This presents a challenge for memory safety, because we need some way to //! guarantee that there are no data races. For example, if both @@ -403,24 +403,24 @@ //! //! Next, we want to use a DPLL to multiply the 8 MHz crystal clock up to 100 //! MHz. Once again, we need to decide between two instances of a clock, because -//! each chip has two [`Dpll`]s. This time, however, our decision between -//! [`Dpll0`] and [`Dpll1`] is arbitrary. +//! this chip has two [`Dpll`]s. This time, however, our decision between +//! [`Dpll0`] and `Dpll1` is arbitrary. //! //! Also note that, like before, `Dpll0` and `Dpll1` are aliases for -//! `Dpll` and `Dpll`. [`Dpll0Id`] and [`Dpll1Id`] +//! `Dpll` and `Dpll`. [`Dpll0Id`] and `Dpll1Id` //! represent the *identity* of the respective DPLL, while `I` represents the //! [`Id` type](self#id-types) for the [`Source`] driving the DPLL. In this //! particular case, we aim to create an instance of `Dpll0`. //! //! Only certain clocks can drive the DPLL, so `I` is constrained by the -//! [`DpllSourceId`] trait. Specifically, only the [`Xosc0Id`], [`Xosc1Id`], -//! [`Xosc32kId`] and [`GclkId`] types implement this trait. +//! [`DpllSourceId`] trait. Specifically, only the [`Xosc0Id`], `Xosc1Id` (only +//! some targets), [`Xosc32kId`] and [`GclkId`] types implement this trait. //! //! As before, we access the [`Tokens`] struct and use the corresponding //! [`DpllToken`] when creating an instance of `Dpll`. However, unlike before, //! we are creating a new clock-tree relationship that must be tracked by the -//! type system. Because DPLL0 will now consume XOSC0, we must [`Increment`] -//! the [`Enabled`] counter for [`EnabledXosc0`]. +//! type system. Because DPLL0 will now consume XOSC0, we must [`Increment`] the +//! [`Enabled`] counter for [`EnabledXosc0`]. //! //! Thus, to create an instance of `Dpll0`, we must provide the //! `EnabledXosc0`, so that its `U0` type parameter can be incremented to `U1`. @@ -461,11 +461,11 @@ //! # ).enable(); //! let (dpll0, xosc0) = Dpll::from_xosc(tokens.dpll0, xosc0); //! ``` -//! Next, we set the DPLL pre-divider and loop divider. We must pre-divide -//! the XOSC clock down from 8 MHz to 2 MHz, so that it is within the valid -//! input frequency range for the DPLL. Then, we set the DPLL loop divider, so -//! that it will multiply the 2 MHz clock by 50 for a 100 MHz output. We do not -//! need fractional mutiplication here, so the fractional loop divider is zero. +//! Next, we set the DPLL pre-divider and loop divider. We must pre-divide the +//! XOSC clock down from 8 MHz to 2 MHz, so that it is within the valid input +//! frequency range for the DPLL. Then, we set the DPLL loop divider, so that it +//! will multiply the 2 MHz clock by 50 for a 100 MHz output. We do not need +//! fractional mutiplication here, so the fractional loop divider is zero. //! Finally, we can enable the `Dpll`, yielding an instance of //! `EnabledDpll0`. //! @@ -515,11 +515,11 @@ //! [`EnabledGclk0`] to change the base clock without disabling GCLK0 or the //! main clock. //! -//! This time we will be modifying two [`Enabled`] counters simultaneously. -//! We will [`Decrement`] the [`EnabledDfll`] count from `U1` to `U0`, and -//! we will [`Increment`] the [`EnabledDpll0`] count from `U0` to `U1`. -//! Again, we need to provide both the DFLL and DPLL clocks, so that their -//! type parameters can be changed. +//! This time we will be modifying two [`Enabled`] counters simultaneously. We +//! will [`Decrement`] the [`EnabledDfll`] count from `U1` to `U0`, and we will +//! [`Increment`] the [`EnabledDpll0`] count from `U0` to `U1`. Again, we need +//! to provide both the DFLL and DPLL clocks, so that their type parameters can +//! be changed. //! //! ```no_run //! # use atsamd_hal::{ @@ -597,8 +597,8 @@ //! ``` //! //! We have the clocks set up, but we're not using them for anything other than -//! the main clock. Our final steps will create SERCOM APB and peripheral -//! clocks and will output the raw GCLK0 to a GPIO pin. +//! the main clock. Our final steps will create SERCOM APB and peripheral clocks +//! and will output the raw GCLK0 to a GPIO pin. //! //! To enable the APB clock for SERCOM0, we must access the [`Apb`] bus struct. //! We provide an [`ApbToken`] to the [`Apb::enable`] method and receive an @@ -768,10 +768,7 @@ //! ``` //! //! [PAC]: crate::pac -//! [`OSCCTRL`]: crate::pac::Oscctrl -//! [`OSC32KCTRL`]: crate::pac::Osc32kctrl //! [`GCLK`]: crate::pac::Gclk -//! [`MCLK`]: crate::pac::Mclk //! [`Peripherals::steal`]: crate::pac::Peripherals::steal //! //! [`Ahb`]: ahb::Ahb @@ -795,9 +792,7 @@ //! [`Dpll`]: dpll::Dpll //! [`Dpll`]: dpll::Dpll //! [`Dpll0`]: dpll::Dpll0 -//! [`Dpll1`]: dpll::Dpll1 //! [`Dpll0Id`]: dpll::Dpll0Id -//! [`Dpll1Id`]: dpll::Dpll1Id //! [`DpllSourceId`]: dpll::DpllSourceId //! [`DpllToken`]: dpll::DpllToken //! [`EnabledDpll0`]: dpll::EnabledDpll0 @@ -819,15 +814,12 @@ //! [`PclkSourceId`]: pclk::PclkSourceId //! [`PclkToken`]: pclk::PclkToken //! -//! [`RtcOsc`]: rtcosc::RtcOsc -//! //! [`Xosc`]: xosc::Xosc //! [`Xosc::from_crystal`]: xosc::Xosc::from_crystal //! [`Xosc::enable`]: xosc::Xosc::enable //! [`Xosc0`]: xosc::Xosc0 //! [`Xosc0`]: xosc::Xosc0 //! [`Xosc0Id`]: xosc::Xosc0Id -//! [`Xosc1Id`]: xosc::Xosc1Id //! [`XoscToken`]: xosc::XoscToken //! [`EnabledXosc0`]: xosc::EnabledXosc0 //! [`EnabledXosc0`]: xosc::EnabledXosc0 @@ -850,7 +842,8 @@ //! [`Sub1`]: typenum::Sub1 //! [`Unsigned`]: typenum::Unsigned //! -//! [interior mutability]: https://doc.rust-lang.org/reference/interior-mutability.html +//! [interior mutability]: +//! https://doc.rust-lang.org/reference/interior-mutability.html #![allow(clippy::manual_range_contains)] diff --git a/hal/src/clock/v2/dpll.rs b/hal/src/clock/v2/dpll.rs index b67f3484a981..f1c35227aeb3 100644 --- a/hal/src/clock/v2/dpll.rs +++ b/hal/src/clock/v2/dpll.rs @@ -464,15 +464,14 @@ pub enum DynDpllId { // DpllId //============================================================================== -/// Type-level enum identifying one of two possible [`Dpll`]s +/// Type-level enum identifying a [`Dpll`] /// -/// The types implementing this trait, i.e. [`Dpll0Id`] and [`Dpll1Id`], are -/// type-level variants of `DpllId`, and they identify one of the two possible -/// digital phase-locked loops. +/// The types implementing this trait, i.e. [`Dpll0Id`] (and `Dpll1Id`, on +/// targets with two DPLLs), identify a specific digital phase-locked loop. /// /// `DpllId` is the type-level equivalent of [`DynDpllId`]. See the -/// documentation on [type-level programming] and specifically -/// [type-level enums] for more details. +/// documentation on [type-level programming] and specifically [type-level +/// enums] for more details. /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums @@ -778,12 +777,12 @@ mod settings { /// A DPLL is used to multiply clock frequencies, taking a lower-frequency input /// clock and producing a higher-frequency output clock. /// -/// The type parameter `D` is a [`DpllId`] that determines which of the two -/// instances this `Dpll` represents ([`Dpll0`] or [`Dpll1`]). The type -/// parameter `I` represents the `Id` type for the clock [`Source`] driving this -/// `Dpll`. It must be one of the valid [`DpllSourceId`]s. See the -/// [`clock` module documentation](super) for more detail on -/// [`Id` types](super#id-types). +/// The type parameter `D` is a [`DpllId`] that determines which of the one or +/// two (depending on the target) instances this `Dpll` represents ([`Dpll0`] or +/// `Dpll1`). The type parameter `I` represents the `Id` type for the clock +/// [`Source`] driving this `Dpll`. It must be one of the valid +/// [`DpllSourceId`]s. See the [`clock` module documentation](super) for more +/// detail on [`Id` types](super#id-types). /// /// On its own, an instance of `Dpll` does not represent an enabled DPLL. /// Instead, it must first be wrapped with [`Enabled`], which implements diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 7b6b119b700a..09037dd0f24e 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -83,10 +83,10 @@ //! //! At this point, notice that [`Gclk`] takes two type parameters. `G` is //! a [`GclkId`] identifying which of the 12 generators this `Gclk` represents. -//! [`Gclk1`] is simply an alias for `Gclk`. `I` is an -//! [`Id` type](super#id-types) identifying the input clock, which must be a -//! valid [`GclkSourceId`]. In this case, `I` is [`PB14`](gpio::PB14), which is -//! a `GclkSourceId` for `Gclk1`, because it implements [`GclkIo`] with +//! [`Gclk1`] is simply an alias for `Gclk`. `I` is an [`Id` +//! type](super#id-types) identifying the input clock, which must be a valid +//! [`GclkSourceId`]. In this case, `I` is `PB14`, which is a `GclkSourceId` for +//! `Gclk1` on this target, because it implements [`GclkIo`] with //! [`GclkIo::GclkId`]` = Gclk1Id`. //! //! ```no_run @@ -488,15 +488,15 @@ pub enum DynGclkId { // GclkId //============================================================================== -/// Type-level enum identifying one of 12 possible [`Gclk`]s +/// Type-level enum identifying one of possible [`Gclk`]s /// -/// The types implementing this trait, i.e. [`Gclk0Id`] - [`Gclk11Id`], are -/// type-level variants of `GclkId`, and they identify one of the 12 possible +/// The types implementing this trait, i.e. [`Gclk0Id`] - `Gclk11Id`, are +/// type-level variants of `GclkId`, and they identify one of the possible /// generic clock generators. /// /// `GclkId` is the type-level equivalent of [`DynGclkId`]. See the -/// documentation on [type-level programming] and specifically -/// [type-level enums] for more details. +/// documentation on [type-level programming] and specifically [type-level +/// enums] for more details. /// /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums @@ -1072,13 +1072,13 @@ impl Default for Settings { /// a root or branch clock to other branch or leaf clocks. In particular, all /// peripheral [`Pclk`]s must be derived from a `Gclk`. /// -/// The type parameter `G` is a [`GclkId`] that determines which of the 12 -/// generators this [`Gclk`] represents ([`Gclk0`] - [`Gclk11`]). The type -/// parameter `I` represents the `Id` type for the clock [`Source`] driving this -/// `Gclk`. It must be one of the valid [`GclkSourceId`]s. Alternatively, if the -/// `Gclk` is driven by a [GPIO](gpio) [`Pin`], then `I` is a [`PinId`] -/// implementing [`GclkIo`]. See the [`clock` module documentation](super) for -/// more detail on `Id` types. +/// The type parameter `G` is a [`GclkId`] that determines which of the +/// generators this [`Gclk`] represents ([`Gclk0`] - `Gclk11` on the largest +/// targets). The type parameter `I` represents the `Id` type for the clock +/// [`Source`] driving this `Gclk`. It must be one of the valid +/// [`GclkSourceId`]s. Alternatively, if the `Gclk` is driven by a [GPIO](gpio) +/// [`Pin`], then `I` is a [`PinId`] implementing [`GclkIo`]. See the [`clock` +/// module documentation](super) for more detail on `Id` types. /// /// On its own, an instance of `Gclk` does not represent an enabled clock /// generator. Instead, it must first be wrapped with [`Enabled`], which diff --git a/hal/src/clock/v2/osc32k.rs b/hal/src/clock/v2/osc32k.rs index 3288210c1c73..96f3bcfe4fa2 100644 --- a/hal/src/clock/v2/osc32k.rs +++ b/hal/src/clock/v2/osc32k.rs @@ -2,35 +2,27 @@ //! //! ## Overview //! -//! TODO this documentation is for the SAMD51 version, not the SYSCTRL sub-peripheral +//! The `osc32k` module provides access to the 32 kHz oscillator (OSC32K), +//! provided by the `SYSCTRL` peripheral. Depending on the target, it has one +//! or two outputs: one at 32 kHz and another divided down to 1 kHz. These +//! outputs can be disabled or enabled independently at any given time. //! -//! The `osc32k` module provides access to the 32 kHz ultra low power -//! internal oscillator (OSC32K) within the `OSC32KCTRL` peripheral. -//! -//! The `OSC32K` clock is unlike most other clocks. First, it is an internal -//! clock that is always enabled and can't be disabled. And second, it has two -//! separate outputs, one at 32 kHz and another divided down to 1 kHz. Moreover, -//! none, either or both of these outputs can be enabled at any given time. -//! -//! We can see, then, that the `OSC32K` peripheral forms its own, miniature -//! clock tree. There is a 1:N producer clock that is always enabled; and there -//! are two possible consumer clocks that can be independently and optionally -//! enabled. In fact, this structure is illustrated by the `OSC32K` -//! register, which has no regular `ENABLE` bit and two different enable bits -//! for clock output, `EN32K` and `EN1K`. +//! We can see, that the `OSC32K` peripheral forms its own, miniature clock +//! tree. There is a 1:N producer clock; and there are one or two possible +//! consumer clocks that can be independently and optionally enabled. //! //! To represent this structure in the type system, we divide the `OSC32K` //! peripheral into these three clocks. Users get access to the 1:N -//! [`EnabledOsc32kBase`] clock [`Source`] at power-on reset, which can be -//! consumed by both the [`Osc32k`] and [`Osc1k`] clocks. Note that -//! `Osc32k` and `Osc1k` are themselves 1:N clocks as well. +//! [`EnabledOsc32kBase`] clock [`Source`], which can be consumed by both the +//! [`Osc32k`] and [`Osc1k`] clocks. Note that `Osc32k` and `Osc1k` are +//! themselves 1:N clocks as well. //! //! ## Write lock //! -//! Rhe `OSC32K` register has a dedicated write lock bit that will freeze its +//! The `OSC32K` register has a dedicated write lock bit that will freeze its //! configuration until the next power-on reset. We implement this by simply -//! dropping the [`Osc32kBase`] clock, which prevents any further access to -//! the `OSC32K` register. +//! dropping the [`Osc32kBase`] clock, which prevents any further access to the +//! `OSC32K` register. //! //! ## Example //! @@ -108,8 +100,7 @@ //! ``` //! //! And finally, we can set the write lock bit to freeze the configuation until -//! the next power-on reset. Doing so also drops the `EnabledOsc32kBase` -//! clock. +//! the next power-on reset. Doing so also drops the `EnabledOsc32kBase` clock. //! //! ```no_run //! # use atsamd_hal::{ @@ -474,6 +465,11 @@ pub struct Osc1k { token: Osc1kToken, } +/// OSC1K is not available on the currently-documented target +#[cfg(doc)] +#[hal_cfg(not("sysctrl-d11"))] +pub struct Osc1k {} + /// The [`Enabled`] [`Osc1k`] clock /// /// As described in the [`clock` module documentation](super), the [`Enabled`] diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index df5b98136ac1..57b7f4d584ed 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -205,8 +205,9 @@ struct OscUlp32kBaseToken(()); /// various `Token` types can be exchanged for actual clock types. They /// typically represent clocks that are disabled at power-on reset. /// -/// The [`OscUlp1k`] clock is disabled at power-on reset. To use it, you must -/// first exchange the token for an actual clock with [`OscUlp1k::enable`]. +/// On some targets, the [`OscUlp1k`] clock is disabled at power-on reset, and +/// to use it the token must first be exchanged for an actual clock with +/// [`OscUlp1k::enable`]. pub struct OscUlp1kToken(()); /// Singleton token that can be exchanged for [`OscUlp32k`] @@ -215,8 +216,9 @@ pub struct OscUlp1kToken(()); /// various `Token` types can be exchanged for actual clock types. They /// typically represent clocks that are disabled at power-on reset. /// -/// The [`OscUlp32k`] clock is disabled at power-on reset. To use it, you must -/// first exchange the token for an actual clock with [`OscUlp32k::enable`]. +/// On some targets, the [`OscUlp32k`] clock is disabled at power-on reset, and +/// to use it the token must first be exchanged for an actual clock with +/// [`OscUlp32k::enable`]. pub struct OscUlp32kToken(()); impl OscUlp32kBaseToken { @@ -402,6 +404,11 @@ impl OscUlp1k { base.0.token.enable_1k(); (Enabled::new(Self { token }), base.inc()) } + + /// The OSCULP32K 1.024kHz output is always enabled on the documented target + #[cfg(doc)] + #[hal_cfg(not("clock-d5x"))] + pub fn enable(_token: OscUlp1kToken) {} } impl EnabledOscUlp1k { @@ -482,6 +489,11 @@ impl OscUlp32k { base.0.token.enable_32k(); (Enabled::new(Self { token }), base.inc()) } + + /// The OSCULP32K 32.768kHz output is always enabled on the documented target + #[cfg(doc)] + #[hal_cfg(not("clock-d5x"))] + pub fn enable(_token: OscUlp32kToken) {} } impl EnabledOscUlp32k { diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index 2f9728911de6..1c44f83f3268 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -30,8 +30,7 @@ impl Pac { /// /// Consume the [`Pac`] and return the low-level PAC structs. This is /// useful when the `clock::v2` API does not provide a necessary feature, or - /// when dealing with the legacy `clock::v1` API. For example, many of the - /// `clock::v1` functions require access to the [`MCLK`] peripheral. + /// when dealing with the legacy `clock::v1` API. /// /// # Safety /// @@ -122,21 +121,20 @@ pub struct Tokens { pub gclks: gclk::GclkTokens, /// Tokens to create [`pclk::Pclk`]s pub pclks: pclk::PclkTokens, - /// Tokens to create the [`osc32k::Osc1k`] and [`osc32k::Osc32k`] clocks + /// Tokens to create the [`osc32k`] clocks pub osc32k: osc32k::Osc32kTokens, /// Tokens [`xosc::Xosc0`] pub xosc: xosc::XoscToken, - /// Tokens to create [`xosc32k::Xosc32kBase`], [`xosc32k::Xosc1k`] and - /// [`xosc32k::Xosc32k`] + /// Tokens to create [`xosc32k`] clocks #[hal_cfg("xosc32k")] pub xosc32k: xosc32k::Xosc32kTokens, } -/// Consume the PAC clocking structs and return a HAL-level -/// representation of the clocks at power-on reset +/// Consume the PAC clocking structs and return a HAL-level representation of +/// the clocks at power-on reset /// -/// This function consumes the [`OSCCTRL`], [`OSC32KCTRL`], [`Gclk`] and -/// [`MCLK`] PAC structs and returns the [`Buses`], [`Clocks`] and [`Tokens`]. +/// This function consumes the [`Gclk`], [`Pm`], and [`Sysctrl``] PAC structs +/// and returns the [`Buses`], [`Clocks`] and [`Tokens`]. /// /// See the [module-level documentation](super) for more details. #[inline] diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 4c1e5b2ef420..5bc7a41424bb 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -11,8 +11,8 @@ //! //! When used with an external clock, only one GPIO [`Pin`] is required, but //! when used with a crystal oscillator, two GPIO `Pin`s are required. The -//! [`XIn`] `Pin` is used in both `Mode`s, while the [`XOut`] `Pin` is only -//! used in [`CrystalMode`]. +//! [`XIn`] `Pin` is used in both `Mode`s, while the [`XOut`] `Pin` is only used +//! in [`CrystalMode`]. //! //! When operating in [`CrystalMode`], the XOSC peripheral provides several //! configuration options to increase stability or reduce power consumption of @@ -86,14 +86,15 @@ //! //! We start by calling [`Xosc::from_crystal`], and we provide the corresponding //! [`XIn`] and [`XOut`] [`Pin`]s, as well as the nominal crystal frequency. We -//! then set the [`CrystalCurrent`] level to `Medium`. The default current level -//! for a 20 MHz signal is actually `High`, but we opt for a lower current under -//! the assumption that our crystal's capacitive load is small. Next, we turn on -//! automatic loop control, which should save power, but we also set -//! `LOWBUFGAIN` to `1`. Counterintuitively, this actually _increases_ the -//! crystal amplitude, which increases power consumption, but it also improves -//! stability. We then apply a 488 μs start up delay, to allow the clock to -//! stabilize before it is applied to any logic. Finally, we enable the `Xosc`. +//! then set the `CrystalCurrent` level to `Medium` (supported only on some +//! targets). The default current level for a 20 MHz signal is actually `High`, +//! but we opt for a lower current under the assumption that our crystal's +//! capacitive load is small. Next, we turn on automatic loop control, which +//! should save power, but we also set `LOWBUFGAIN` to `1`. Counterintuitively, +//! this actually _increases_ the crystal amplitude, which increases power +//! consumption, but it also improves stability. We then apply a 488 μs start up +//! delay, to allow the clock to stabilize before it is applied to any logic. +//! Finally, we enable the `Xosc`. //! //! Next, we wait until the `Xosc` is stable and ready to be used as a clock //! [`Source`]. @@ -126,11 +127,11 @@ //! while !xosc.is_ready() {} //! ``` //! -//! Once the clock is stable, we can also enable failure detection. To do so, we -//! must provide the [`EnabledDfll`] to act as the backup safe clock. We can -//! also select a divider for the safe clock, so that it loosely matches the -//! `Xosc` frequency. In thise case, we divide the 48 MHz [`Dfll`] down to -//! 24 MHz, which is the closest option to 20 MHz. +//! Once the clock is stable, we can also enable failure detection on targets +//! that support it. To do so, we must provide the [`EnabledDfll`] to act as the +//! backup safe clock. We can also select a divider for the safe clock, so that +//! it loosely matches the `Xosc` frequency. In thise case, we divide the 48 MHz +//! [`Dfll`] down to 24 MHz, which is the closest option to 20 MHz. //! //! ```no_run //! # use atsamd_hal::{ @@ -454,11 +455,11 @@ impl Default for Settings { // XoscId //============================================================================== -/// Type-level enum identifying one of two possible [`Xosc`]s +/// Type-level enum identifying [`Xosc`]s /// -/// The types implementing this trait, i.e. [`Xosc0Id`] and [`Xosc1Id`], are -/// type-level variants of `XoscId`, and they identify one of two possible -/// external crystal oscillators. +/// The types implementing this trait, i.e. [`Xosc0Id`] and `Xosc1Id` on +/// supporting targets, are type-level variants of `XoscId`, and they identify +/// one of two possible external crystal oscillators. /// /// See the documentation on [type-level programming] and specifically /// [type-level enums] for more details. @@ -770,8 +771,8 @@ impl Mode for CrystalMode { /// oscillator and delivers the resulting clock to the rest of the clock system. /// /// The type parameter `X` is a [`XoscId`] that determines which of the two -/// instances this `Xosc` represents ([`Xosc0`] or [`Xosc1`]). The type -/// parameter `M` represents the operating [`Mode`], either [`ClockMode`] or +/// instances this `Xosc` represents ([`Xosc0`] or `Xosc1`). The type parameter +/// `M` represents the operating [`Mode`], either [`ClockMode`] or /// [`CrystalMode`]. /// /// On its own, an instance of `Xosc` does not represent an enabled XOSC. @@ -1037,6 +1038,7 @@ where } } +#[hal_macro_helper] impl EnabledXosc where X: XoscId, @@ -1048,6 +1050,16 @@ where pub fn is_ready(&self) -> bool { self.0.token.is_ready() } + + /// XOSC failure detection is not supported by the currently-documented target + #[cfg(doc)] + #[hal_cfg(not("clock-d5x"))] + pub fn has_failed(&self) {} + + /// XOSC failure detection is not supported by the currently-documented target + #[cfg(doc)] + #[hal_cfg(not("clock-d5x"))] + pub fn switch_back(&self) {} } #[hal_cfg("clock-d5x")] diff --git a/hal/src/clock/v2/xosc32k.rs b/hal/src/clock/v2/xosc32k.rs index dbb8de87e9b9..4b574121cd7a 100644 --- a/hal/src/clock/v2/xosc32k.rs +++ b/hal/src/clock/v2/xosc32k.rs @@ -33,20 +33,20 @@ //! `ENABLE` bit. The call to [`Xosc32kBase::enable`] returns a 1:N [`Enabled`] //! clock [`Source`], which can be consumed by both the [`Xosc32k`] and //! [`Xosc1k`] clocks. Enabling either of these two clocks will [`Increment`] -//! the [`EnabledXosc32kBase`] counter, preventing it from being disabled. -//! Note that `Xosc32k` and `Xosc1k` are themselves 1:N clocks as well. +//! the [`EnabledXosc32kBase`] counter, preventing it from being disabled. Note +//! that `Xosc32k` and `Xosc1k` are themselves 1:N clocks as well. //! //! ## Clock failure detection and write lock //! -//! Like the [`Xosc`] clocks, the XOSC32K peripheral also has clock failure -//! detection. However, unlike the `XOSCCTRL` registers, the `XOSC32K` register -//! has a dedicated write lock bit that will freeze its configuration until the -//! next power-on reset. +//! The XOSC32K peripheral on some microcontrollers supports Clock Failure +//! Detection (CFD), like the [`Xosc`] clocks. However, unlike the `XOSCCTRL` +//! registers, the `XOSC32K` register has a dedicated write lock bit that will +//! freeze its configuration until the next power-on reset. //! //! While `Xosc` clock failure detection is configured directly in the -//! `XOSCCTRL` register, the XOSC32K peripheral has a separate, dedicated -//! clock failure detection register (`Cfdctrl`). This difference likely exists -//! to provide control of clock failure detection *after* write lock has been +//! `XOSCCTRL` register, the XOSC32K peripheral has a separate, dedicated clock +//! failure detection register (`Cfdctrl`). This difference likely exists to +//! provide control of clock failure detection *after* write lock has been //! enabled. //! //! In this module, write lock is implemented by simply dropping the @@ -71,7 +71,6 @@ //! osculp32k::OscUlp32k, //! xosc32k::{ //! ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase, -//! Xosc32kCfd, //! }, //! }, //! gpio::Pins, @@ -91,8 +90,8 @@ //! Next, we create the [`Xosc32kBase`] clock from a 32 kHz oscillator using its //! corresponding [`Xosc32kBaseToken`] and the [`XIn32`] and [`XOut32`] `Pin`s. //! We then set the delay before the clock is unmasked by providing a desired -//! [`StartUpDelay`]. Finally, we select a [`ControlGainMode`] for the crystal -//! before enabling it. +//! [`StartUpDelay`]. Finally, on supported targets, we select a +//! `ControlGainMode` for the crystal before enabling it. //! //! ```no_run //! # use atsamd_hal::{ @@ -101,7 +100,6 @@ //! # osculp32k::OscUlp32k, //! # xosc32k::{ //! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase, -//! # Xosc32kCfd, //! # }, //! # }, //! # gpio::Pins, @@ -118,6 +116,7 @@ //! # ); //! let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01) //! .start_up_delay(StartUpDelay::Delay1s) +//! // n.b. only some targets support this setting //! .control_gain_mode(ControlGainMode::HighSpeed) //! .enable(); //! ``` @@ -132,7 +131,6 @@ //! # osculp32k::OscUlp32k, //! # xosc32k::{ //! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase, -//! # Xosc32kCfd, //! # }, //! # }, //! # gpio::Pins, @@ -155,10 +153,10 @@ //! ``` //! //! With the [`EnabledXosc32kBase`] clock in hand, we can enable the [`Xosc1k`] -//! and [`Xosc32k`], each of which [`Increment`]s the [`Enabled`] counter. -//! Once we are satisfied with the configuration, we can call `write_lock` to -//! lock the XOSC32K configuration at the hardware level. Doing so also consumes -//! the `EnabledXosc32kBase` clock, which eliminates any ability to change the +//! and [`Xosc32k`], each of which [`Increment`]s the [`Enabled`] counter. Once +//! we are satisfied with the configuration, we can call `write_lock` to lock +//! the XOSC32K configuration at the hardware level. Doing so also consumes the +//! `EnabledXosc32kBase` clock, which eliminates any ability to change the //! configuration at the API level. //! //! ```no_run @@ -168,7 +166,6 @@ //! # osculp32k::OscUlp32k, //! # xosc32k::{ //! # ControlGainMode, SafeClockDiv, StartUpDelay, Xosc1k, Xosc32k, Xosc32kBase, -//! # Xosc32kCfd, //! # }, //! # }, //! # gpio::Pins, @@ -1139,6 +1136,22 @@ impl Xosc32kCfd { } } +/// Clock failure detection is not supported by the currently-documented target +#[cfg(doc)] +#[hal_cfg(not("osc32kctrl"))] +pub struct Xosc32kCfd; + +#[cfg(doc)] +#[hal_cfg(not("osc32kctrl"))] +impl Xosc32kCfd { + /// Clock failure detection is not supported by the currently-documented target + pub fn has_failed() {} + /// Clock failure detection is not supported by the currently-documented target + pub fn is_switched() {} + /// Clock failure detection is not supported by the currently-documented target + pub fn switch_back() {} +} + //============================================================================== // Ids //============================================================================== @@ -1173,6 +1186,13 @@ pub struct Xosc1k { token: Xosc1kToken, } + +/// XOSC1K is not available on the currently-documented target +#[cfg(doc)] +#[hal_cfg(not(any("sysctrl-d11", "osc32kctrl")))] +pub struct Xosc1k; + + /// The [`Enabled`] [`Xosc1k`] clock /// /// As described in the [`clock` module documentation](super), the [`Enabled`] diff --git a/hal/src/sercom/dma.rs b/hal/src/sercom/dma.rs index 02e1c0a337d1..703b8f0b0d10 100644 --- a/hal/src/sercom/dma.rs +++ b/hal/src/sercom/dma.rs @@ -176,10 +176,9 @@ where /// the provided buffer. /// /// In order to be (safely) non-blocking, his method has to take a `'static` - /// buffer. If you'd rather use DMA with the blocking - /// [`embedded_io::Read`] trait, and avoid having - /// to use static buffers, - /// use [`Uart::with_rx_channel`](Self::with_tx_channel) instead. + /// buffer. If you'd rather use DMA with the blocking [`embedded_io::Read`] + /// trait, and avoid having to use static buffers, use + /// [`Uart::with_rx_channel`](Self::with_tx_channel) instead. #[inline] #[hal_macro_helper] pub fn receive_with_dma( @@ -218,10 +217,9 @@ where /// provided buffer. /// /// In order to be (safely) non-blocking, his method takes a `'static` - /// buffer. If you'd rather use DMA with the blocking - /// [`embedded_io::Write`] trait, and avoid - /// having to use static buffers, - /// use[`Uart::with_tx_channel`](Self::with_tx_channel) instead. + /// buffer. If you'd rather use DMA with the blocking [`embedded_io::Write`] + /// trait, and avoid having to use static buffers, use + /// [`Uart::with_tx_channel`](Self::with_tx_channel) instead. #[inline] #[hal_macro_helper] pub fn send_with_dma( From 23f1461e37550e25a48f8a08119dba1c07ce93d1 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 17 Aug 2025 09:30:00 +1200 Subject: [PATCH 71/75] More doc fixes --- hal/src/gpio/pin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hal/src/gpio/pin.rs b/hal/src/gpio/pin.rs index 62129af8fca0..8979f0b63d4c 100644 --- a/hal/src/gpio/pin.rs +++ b/hal/src/gpio/pin.rs @@ -1084,8 +1084,7 @@ macro_rules! pins{ )+ } impl Pins { - /// Take ownership of the PAC - /// [`Port`] and split it into + /// Take ownership of the PAC [`Port`] and split it into /// discrete [`Pin`]s #[inline] pub fn new(port: Port) -> Pins { From 0fffb1dac2e9ee2f1ee8a0d67eb825072909e2e5 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Sun, 17 Aug 2025 09:51:23 +1200 Subject: [PATCH 72/75] Formatting, minor fix in /rustfmt.sh --- boards/atsame54_xpro/examples/blinky_rtic.rs | 8 ++------ boards/feather_m4/examples/adc.rs | 2 +- boards/metro_m4/examples/adc.rs | 2 +- hal/src/clock/v2.rs | 4 ++-- hal/src/clock/v2/osculp32k.rs | 3 ++- hal/src/clock/v2/xosc.rs | 6 ++++-- rustfmt.sh | 2 ++ 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/boards/atsame54_xpro/examples/blinky_rtic.rs b/boards/atsame54_xpro/examples/blinky_rtic.rs index 4289dfd56ee1..32b42710b483 100644 --- a/boards/atsame54_xpro/examples/blinky_rtic.rs +++ b/boards/atsame54_xpro/examples/blinky_rtic.rs @@ -32,12 +32,8 @@ mod app { rtt_init_print!(); - let (_buses, clocks, tokens) = clock_system_at_reset( - device.oscctrl, - device.osc32kctrl, - device.gclk, - device.mclk, - ); + let (_buses, clocks, tokens) = + clock_system_at_reset(device.oscctrl, device.osc32kctrl, device.gclk, device.mclk); // Enable the RTC clock with the 1 kHz source. // Note that currently the proof of this (the `RtcOsc` instance) is not diff --git a/boards/feather_m4/examples/adc.rs b/boards/feather_m4/examples/adc.rs index 98d4a974135a..9f90fe3682a3 100644 --- a/boards/feather_m4/examples/adc.rs +++ b/boards/feather_m4/examples/adc.rs @@ -2,4 +2,4 @@ #![no_main] use feather_m4 as bsp; -include!("../../examples/m4-adc.rs"); \ No newline at end of file +include!("../../examples/m4-adc.rs"); diff --git a/boards/metro_m4/examples/adc.rs b/boards/metro_m4/examples/adc.rs index 8af58dc94ef4..79f1675e1d1b 100644 --- a/boards/metro_m4/examples/adc.rs +++ b/boards/metro_m4/examples/adc.rs @@ -2,4 +2,4 @@ #![no_main] use metro_m4 as bsp; -include!("../../examples/m4-adc.rs"); \ No newline at end of file +include!("../../examples/m4-adc.rs"); diff --git a/hal/src/clock/v2.rs b/hal/src/clock/v2.rs index 3095055a5b80..cbd0a036a94c 100644 --- a/hal/src/clock/v2.rs +++ b/hal/src/clock/v2.rs @@ -220,8 +220,8 @@ //! registers are accessed relative to the [PAC]. //! //! Each of the PAC clocking structs (which vary between targets, including -//! `OSCCTRL`, `SYSCTRL`, `OSC32KCTRL`, [`GCLK`] and `MCLK`) is a singleton object -//! that controls a set of MMIO registers. It is impossible to create two +//! `OSCCTRL`, `SYSCTRL`, `OSC32KCTRL`, [`GCLK`] and `MCLK`) is a singleton +//! object that controls a set of MMIO registers. It is impossible to create two //! instances of any PAC object without `unsafe`. However, each object controls //! a large set of registers that can be further sub-divided into smaller sets //! for individual clocks. For example, the [`GCLK`] object controls registers diff --git a/hal/src/clock/v2/osculp32k.rs b/hal/src/clock/v2/osculp32k.rs index 57b7f4d584ed..e580bc18c561 100644 --- a/hal/src/clock/v2/osculp32k.rs +++ b/hal/src/clock/v2/osculp32k.rs @@ -490,7 +490,8 @@ impl OscUlp32k { (Enabled::new(Self { token }), base.inc()) } - /// The OSCULP32K 32.768kHz output is always enabled on the documented target + /// The OSCULP32K 32.768kHz output is always enabled on the documented + /// target #[cfg(doc)] #[hal_cfg(not("clock-d5x"))] pub fn enable(_token: OscUlp32kToken) {} diff --git a/hal/src/clock/v2/xosc.rs b/hal/src/clock/v2/xosc.rs index 5bc7a41424bb..49af41688882 100644 --- a/hal/src/clock/v2/xosc.rs +++ b/hal/src/clock/v2/xosc.rs @@ -1051,12 +1051,14 @@ where self.0.token.is_ready() } - /// XOSC failure detection is not supported by the currently-documented target + /// XOSC failure detection is not supported by the currently-documented + /// target #[cfg(doc)] #[hal_cfg(not("clock-d5x"))] pub fn has_failed(&self) {} - /// XOSC failure detection is not supported by the currently-documented target + /// XOSC failure detection is not supported by the currently-documented + /// target #[cfg(doc)] #[hal_cfg(not("clock-d5x"))] pub fn switch_back(&self) {} diff --git a/rustfmt.sh b/rustfmt.sh index 83555c8b3b6e..12a1d195bf45 100755 --- a/rustfmt.sh +++ b/rustfmt.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + RET=0 # first, all boards & their examples From b1c04c9c2d7a109d898ecd51239b3f531493b447 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Sat, 17 Jan 2026 18:02:33 -0500 Subject: [PATCH 73/75] PCLK source ID can be either type-checked or runtime-checked --- boards/atsame54_xpro/examples/mcan.rs | 2 +- boards/examples/m4-adc.rs | 8 +- boards/metro_m4/examples/async_adc.rs | 8 +- hal/src/clock/v2/gclk.rs | 27 +++++ hal/src/clock/v2/pclk.rs | 148 +++++++++++++++++++++++--- hal/src/clock/v2/reset_thumbv6m.rs | 9 +- hal/src/peripherals/adc/builder.rs | 4 +- hal/src/peripherals/adc/mod.rs | 29 +++-- 8 files changed, 202 insertions(+), 33 deletions(-) diff --git a/boards/atsame54_xpro/examples/mcan.rs b/boards/atsame54_xpro/examples/mcan.rs index d79541b3561c..d2f9ad8fb671 100644 --- a/boards/atsame54_xpro/examples/mcan.rs +++ b/boards/atsame54_xpro/examples/mcan.rs @@ -83,7 +83,7 @@ type Aux = mcan::bus::Aux< clock::types::Can1, hal::can::Dependencies< clock::types::Can1, - clock::gclk::Gclk0Id, + clock::pclk::PclkSource, bsp::Ata6561Rx, bsp::Ata6561Tx, bsp::pac::Can1, diff --git a/boards/examples/m4-adc.rs b/boards/examples/m4-adc.rs index f6278c5fadf7..91cc17d6505f 100644 --- a/boards/examples/m4-adc.rs +++ b/boards/examples/m4-adc.rs @@ -44,20 +44,20 @@ fn main() -> ! { let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); // ...and enable the ADC0 PCLK. Both of these are required for the // ADC to run. - let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); + let (pclk_adc0, _gclk0) = Pclk::enable_dyn(tokens.pclks.adc0, clocks.gclk0); let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) .with_clock_cycles_per_sample(5) // Overruns if clock divider < 32 in debug mode .with_clock_divider(Prescaler::Div32) .with_vref(atsamd_hal::adc::Reference::Arefa) - .enable(peripherals.adc0, apb_adc0, &pclk_adc0) + .enable(peripherals.adc0, apb_adc0, pclk_adc0) .unwrap(); let mut adc_pin = pins.a0.into_alternate(); loop { - let res = adc.read(&mut adc_pin); + let _res = adc.read(&mut adc_pin); #[cfg(feature = "use_semihosting")] - let _ = cortex_m_semihosting::hprintln!("ADC value: {}", res); + let _ = cortex_m_semihosting::hprintln!("ADC value: {}", _res); } } diff --git a/boards/metro_m4/examples/async_adc.rs b/boards/metro_m4/examples/async_adc.rs index a9fe0763369f..a4121ba277bf 100644 --- a/boards/metro_m4/examples/async_adc.rs +++ b/boards/metro_m4/examples/async_adc.rs @@ -42,21 +42,21 @@ async fn main(_s: embassy_executor::Spawner) -> ! { let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); // ...and enable the ADC0 PCLK. Both of these are required for the // ADC to run. - let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); + let (pclk_adc0, _gclk0) = Pclk::enable_dyn(tokens.pclks.adc0, clocks.gclk0); let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) .with_clock_cycles_per_sample(5) .with_clock_divider(Prescaler::Div32) .with_vref(atsamd_hal::adc::Reference::Arefa) - .enable(peripherals.adc0, apb_adc0, &pclk_adc0) + .enable(peripherals.adc0, apb_adc0, pclk_adc0) .unwrap() .into_future(Irqs); let mut adc_pin = pins.a0.into_alternate(); loop { - let res = adc.read(&mut adc_pin).await; + let _res = adc.read(&mut adc_pin).await; #[cfg(feature = "use_semihosting")] - cortex_m_semihosting::hprintln!("ADC Result: {}", res).unwrap(); + cortex_m_semihosting::hprintln!("ADC Result: {}", _res).unwrap(); } } diff --git a/hal/src/clock/v2/gclk.rs b/hal/src/clock/v2/gclk.rs index 09037dd0f24e..af07992cd9b6 100644 --- a/hal/src/clock/v2/gclk.rs +++ b/hal/src/clock/v2/gclk.rs @@ -462,6 +462,7 @@ impl GclkToken { /// The variants of this enum identify one generic clock generator. /// /// `DynGclkId` is the value-level equivalent of [`GclkId`]. +#[derive(Clone, Copy, PartialEq, Eq)] #[hal_macro_helper] pub enum DynGclkId { Gclk0, @@ -484,6 +485,32 @@ pub enum DynGclkId { Gclk11, } +impl core::fmt::Debug for DynGclkId { + #[hal_macro_helper] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Gclk0 => write!(f, "Gclk0"), + Self::Gclk1 => write!(f, "Gclk1"), + Self::Gclk2 => write!(f, "Gclk2"), + Self::Gclk3 => write!(f, "Gclk3"), + Self::Gclk4 => write!(f, "Gclk4"), + Self::Gclk5 => write!(f, "Gclk5"), + #[hal_cfg("gclk6")] + Self::Gclk6 => write!(f, "Gclk6"), + #[hal_cfg("gclk7")] + Self::Gclk7 => write!(f, "Gclk7"), + #[hal_cfg("gclk8")] + Self::Gclk8 => write!(f, "Gclk8"), + #[hal_cfg("gclk9")] + Self::Gclk9 => write!(f, "Gclk9"), + #[hal_cfg("gclk10")] + Self::Gclk10 => write!(f, "Gclk10"), + #[hal_cfg("gclk11")] + Self::Gclk11 => write!(f, "Gclk11"), + } + } +} + //============================================================================== // GclkId //============================================================================== diff --git a/hal/src/clock/v2/pclk.rs b/hal/src/clock/v2/pclk.rs index ace79da62e7a..02a04286dd95 100644 --- a/hal/src/clock/v2/pclk.rs +++ b/hal/src/clock/v2/pclk.rs @@ -547,6 +547,28 @@ impl From for Genselect { } } +impl PclkSourceId for DynPclkSourceId { + fn source_id(&self) -> DynGclkId { + *self + } +} + +impl Sealed for DynPclkSourceId {} + +//============================================================================== +// PclkSourceId +//============================================================================== + +pub struct PclkSource { + _src: PhantomData, +} + +impl GclkId for PclkSource { + const DYN: DynGclkId = G::DYN; + const NUM: usize = G::NUM; + type Divider = G::Divider; +} + //============================================================================== // PclkSourceId //============================================================================== @@ -566,9 +588,19 @@ impl From for Genselect { /// [`Gclk`]: super::gclk::Gclk /// [type-level programming]: crate::typelevel /// [type-level enums]: crate::typelevel#type-level-enums -pub trait PclkSourceId: GclkId {} +pub trait PclkSourceId: Sealed { + fn source_id(&self) -> DynGclkId; +} -impl PclkSourceId for G {} +// PclkSource implements PclkSourceId via its GclkId implementation +impl PclkSourceId for G { + #[inline] + fn source_id(&self) -> DynGclkId { + Self::DYN + } +} + +impl Sealed for PclkSource {} //============================================================================== // Pclk @@ -606,24 +638,41 @@ where I: PclkSourceId, { token: PclkToken

, - src: PhantomData, + src: I, freq: Hertz, } -impl Pclk +/// [`Pclk`] with a dynamic source ID ([`DynPclkSourceId`]). +pub type DynPclk

= Pclk; + +impl From>> for DynPclk

where P: PclkId, - I: PclkSourceId, + G: GclkId, +{ + fn from(value: Pclk>) -> Self { + Pclk { + token: value.token, + freq: value.freq, + src: G::DYN, + } + } +} + +impl Pclk> +where + P: PclkId, + G: GclkId, { pub(super) fn new(token: PclkToken

, freq: Hertz) -> Self { Self { token, - src: PhantomData, + src: PclkSource { _src: PhantomData }, freq, } } - /// Create and enable a [`Pclk`] + /// Create and enable a [`Pclk`] with a type-checked source ID. /// /// Creating a [`Pclk`] immediately enables the corresponding peripheral /// channel clock. It also [`Increment`]s the [`Source`]'s [`Enabled`] @@ -636,15 +685,15 @@ where #[inline] pub fn enable(mut token: PclkToken

, gclk: S) -> (Self, S::Inc) where - S: Source + Increment, + S: Source + Increment, { let freq = gclk.freq(); - token.enable(I::DYN); - let pclk = Pclk::new(token, freq); + token.enable(G::DYN); + let pclk = Self::new(token, freq); (pclk, gclk.inc()) } - /// Disable and destroy a [`Pclk`] + /// Disable and destroy a [`Pclk`]. /// /// Consume the [`Pclk`], release the [`PclkToken`], and [`Decrement`] the /// [`EnabledGclk`]'s counter @@ -654,12 +703,87 @@ where #[inline] pub fn disable(mut self, gclk: S) -> (PclkToken

, S::Dec) where - S: Source + Decrement, + S: Source + Decrement, + { + self.token.disable(); + (self.token, gclk.dec()) + } +} + +impl

DynPclk

+where + P: PclkId, +{ + pub(super) fn new(token: PclkToken

, freq: Hertz) -> Self { + Self { + token, + src: G::DYN, + freq, + } + } + + /// Create and enable a [`Pclk`] with an underlying [`DynPclkSourceId`] + /// source ID type. + /// + /// Some peripherals require a dynamic PCLK source ID type parameter; use + /// this method to create a [`Pclk`] where this type parameter is + /// type-erased. + /// + /// Creating a [`Pclk`] immediately enables the corresponding peripheral + /// channel clock. It also [`Increment`]s the [`Source`]'s [`Enabled`] + /// counter. + /// + /// Note that the [`Source`] will always be an [`EnabledGclk`]. + /// + /// [`Enabled`]: super::Enabled + /// [`EnabledGclk`]: super::gclk::EnabledGclk + #[inline] + pub fn enable_dyn(mut token: PclkToken

, gclk: S) -> (Self, S::Inc) + where + S: Source + Increment, + { + let freq = gclk.freq(); + token.enable(G::DYN); + let pclk = Self::new::(token, freq); + (pclk, gclk.inc()) + } + + /// Disable and destroy a [`Pclk`]. + /// + /// Consume the [`Pclk`], release the [`PclkToken`], and [`Decrement`] the + /// [`EnabledGclk`]'s counter. + /// + /// # Panics + /// + /// Panics if the [`Pclk`]'s underlying GCLK source ID does not match the ID + /// of the provided [`Source`]. + /// + /// [`Enabled`]: super::Enabled + /// [`EnabledGclk`]: super::gclk::EnabledGclk + #[inline] + pub fn disable(mut self, gclk: S) -> (PclkToken

, S::Dec) + where + S: Source + Decrement, { + // Make sure that we can only decrement the source we are actually using + assert_eq!( + G::DYN, + self.src, + "Expected GCLK ID {:?}, found {:?}", + G::DYN, + self.src + ); + self.token.disable(); (self.token, gclk.dec()) } +} +impl Pclk +where + P: PclkId, + I: PclkSourceId, +{ /// Return the [`Pclk`] frequency #[inline] pub fn freq(&self) -> Hertz { diff --git a/hal/src/clock/v2/reset_thumbv6m.rs b/hal/src/clock/v2/reset_thumbv6m.rs index 1c44f83f3268..a9831beadbcb 100644 --- a/hal/src/clock/v2/reset_thumbv6m.rs +++ b/hal/src/clock/v2/reset_thumbv6m.rs @@ -6,7 +6,10 @@ use atsamd_hal_macros::hal_macro_helper; use typenum::U1; -use crate::pac::{Gclk, Pm, Sysctrl}; +use crate::{ + clock::v2::pclk::PclkSource, + pac::{Gclk, Pm, Sysctrl}, +}; use super::*; @@ -97,7 +100,7 @@ pub struct Clocks { /// Always-enabled OSCULP oscillators pub osculp: OscUlpClocks, /// [`Pclk`](pclk::Pclk) for the watchdog timer, sourced from [`Gclk2`](gclk::Gclk2) - pub wdt: pclk::Pclk, + pub wdt: pclk::Pclk>, } /// Type-level tokens for unused clocks at power-on reset @@ -155,7 +158,7 @@ pub fn clock_system_at_reset(gclk: Gclk, pm: Pm, sysctrl: Sysctrl) -> (Buses, Cl let osculp32k = Enabled::<_, U0>::new(osculp32k::OscUlp32k::new()); let (gclk2, osculp32k) = gclk::Gclk2::from_source(gclk::GclkToken::new(), osculp32k); let gclk2 = Enabled::new(gclk2); - let wdt = pclk::Pclk::new(pclk::PclkToken::new(), gclk2.freq()); + let wdt = pclk::Pclk::<_, PclkSource<_>>::new(pclk::PclkToken::new(), gclk2.freq()); let osculp = OscUlpClocks { base, osculp1k, diff --git a/hal/src/peripherals/adc/builder.rs b/hal/src/peripherals/adc/builder.rs index baaa62e74b83..41c97148d99c 100644 --- a/hal/src/peripherals/adc/builder.rs +++ b/hal/src/peripherals/adc/builder.rs @@ -247,11 +247,11 @@ impl AdcBuilder { /// Turn the builder into an ADC #[hal_cfg("adc-d5x")] #[inline] - pub fn enable( + pub fn enable( self, adc: I::Instance, clk: crate::clock::v2::apb::ApbClk, - pclk: &crate::clock::v2::pclk::Pclk, + pclk: crate::clock::v2::pclk::Pclk, ) -> Result, BuilderError> { let settings = self.to_settings()?; Adc::new(adc, settings, clk, pclk).map_err(|e| e.into()) diff --git a/hal/src/peripherals/adc/mod.rs b/hal/src/peripherals/adc/mod.rs index c34b560ad113..0f337a3416c5 100644 --- a/hal/src/peripherals/adc/mod.rs +++ b/hal/src/peripherals/adc/mod.rs @@ -48,7 +48,13 @@ pub use builder::*; #[hal_cfg(any("adc-d11", "adc-d21"))] use crate::pac::adc as adc0; #[hal_cfg("adc-d5x")] -use crate::pac::adc0; +use crate::{ + clock::v2::{ + apb::ApbClk, + pclk::{DynPclkSourceId, Pclk}, + }, + pac::adc0, +}; pub use adc0::refctrl::Refselselect as Reference; @@ -174,7 +180,8 @@ pub struct Adc { #[hal_cfg("adc-d5x")] pub struct Adc { adc: I::Instance, - _apbclk: crate::clock::v2::apb::ApbClk, + _apbclk: ApbClk, + _pclk: Pclk, cfg: AdcSettings, discard: bool, } @@ -203,11 +210,11 @@ impl Adc { /// frequency for the ADC is restricted to 90Mhz for stable performance. #[hal_cfg("adc-d5x")] #[inline] - pub(crate) fn new( + pub(crate) fn new( adc: I::Instance, settings: AdcSettings, - clk: crate::clock::v2::apb::ApbClk, - pclk: &crate::clock::v2::pclk::Pclk, + clk: ApbClk, + pclk: Pclk, ) -> Result { // TODO: Ideally, the ADC struct would take ownership of the Pclk type here. // However, since clock::v2 is not implemented for all chips yet, the @@ -226,6 +233,7 @@ impl Adc { let mut new_adc = Self { adc, _apbclk: clk, + _pclk: pclk, cfg: settings, discard: true, }; @@ -422,10 +430,17 @@ impl Adc { /// Return the underlying ADC PAC object and the enabled APB ADC clock. #[hal_cfg("adc-d5x")] + #[allow(clippy::type_complexity)] #[inline] - pub fn free(mut self) -> (I::Instance, crate::clock::v2::apb::ApbClk) { + pub fn free( + mut self, + ) -> ( + I::Instance, + ApbClk, + Pclk, + ) { self.software_reset(); - (self.adc, self._apbclk) + (self.adc, self._apbclk, self._pclk) } /// Reset the peripheral. From 2b91312a22c508189d176ea72bb512142b57d76c Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Sat, 17 Jan 2026 19:14:49 -0500 Subject: [PATCH 74/75] ADC takes impl Into --- boards/examples/m4-adc.rs | 2 +- hal/src/peripherals/adc/builder.rs | 9 ++++++--- hal/src/peripherals/adc/mod.rs | 18 ++++-------------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/boards/examples/m4-adc.rs b/boards/examples/m4-adc.rs index 91cc17d6505f..0afcc86f8238 100644 --- a/boards/examples/m4-adc.rs +++ b/boards/examples/m4-adc.rs @@ -44,7 +44,7 @@ fn main() -> ! { let apb_adc0 = buses.apb.enable(tokens.apbs.adc0); // ...and enable the ADC0 PCLK. Both of these are required for the // ADC to run. - let (pclk_adc0, _gclk0) = Pclk::enable_dyn(tokens.pclks.adc0, clocks.gclk0); + let (pclk_adc0, _gclk0) = Pclk::enable(tokens.pclks.adc0, clocks.gclk0); let mut adc = AdcBuilder::new(Accumulation::single(atsamd_hal::adc::AdcResolution::_12)) .with_clock_cycles_per_sample(5) diff --git a/hal/src/peripherals/adc/builder.rs b/hal/src/peripherals/adc/builder.rs index 41c97148d99c..343ebf0301a4 100644 --- a/hal/src/peripherals/adc/builder.rs +++ b/hal/src/peripherals/adc/builder.rs @@ -244,17 +244,20 @@ impl AdcBuilder { Ok(adc_clk_freq / clocks_per_sample) } - /// Turn the builder into an ADC + /// Turn the builder into an ADC. + /// + /// This function will convert the provided + /// [`Pclk`](crate::clock::v2::pclk::Pclk) into a [`DynPclk`]. #[hal_cfg("adc-d5x")] #[inline] pub fn enable( self, adc: I::Instance, clk: crate::clock::v2::apb::ApbClk, - pclk: crate::clock::v2::pclk::Pclk, + pclk: impl Into>, ) -> Result, BuilderError> { let settings = self.to_settings()?; - Adc::new(adc, settings, clk, pclk).map_err(|e| e.into()) + Adc::new(adc, settings, clk, pclk.into()).map_err(|e| e.into()) } #[hal_cfg(any("adc-d11", "adc-d21"))] diff --git a/hal/src/peripherals/adc/mod.rs b/hal/src/peripherals/adc/mod.rs index 0f337a3416c5..f00e0f1c2bdc 100644 --- a/hal/src/peripherals/adc/mod.rs +++ b/hal/src/peripherals/adc/mod.rs @@ -49,10 +49,7 @@ pub use builder::*; use crate::pac::adc as adc0; #[hal_cfg("adc-d5x")] use crate::{ - clock::v2::{ - apb::ApbClk, - pclk::{DynPclkSourceId, Pclk}, - }, + clock::v2::{apb::ApbClk, pclk::DynPclk}, pac::adc0, }; @@ -181,7 +178,7 @@ pub struct Adc { pub struct Adc { adc: I::Instance, _apbclk: ApbClk, - _pclk: Pclk, + _pclk: DynPclk, cfg: AdcSettings, discard: bool, } @@ -214,7 +211,7 @@ impl Adc { adc: I::Instance, settings: AdcSettings, clk: ApbClk, - pclk: Pclk, + pclk: DynPclk, ) -> Result { // TODO: Ideally, the ADC struct would take ownership of the Pclk type here. // However, since clock::v2 is not implemented for all chips yet, the @@ -430,15 +427,8 @@ impl Adc { /// Return the underlying ADC PAC object and the enabled APB ADC clock. #[hal_cfg("adc-d5x")] - #[allow(clippy::type_complexity)] #[inline] - pub fn free( - mut self, - ) -> ( - I::Instance, - ApbClk, - Pclk, - ) { + pub fn free(mut self) -> (I::Instance, ApbClk, DynPclk) { self.software_reset(); (self.adc, self._apbclk, self._pclk) } From 774784af3d5b7dfa1321b1c3fa67188430251ebc Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Sat, 24 Jan 2026 22:57:46 -0500 Subject: [PATCH 75/75] Fix docs Signed-off-by: Justin Beaurivage --- hal/src/peripherals/adc/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/src/peripherals/adc/builder.rs b/hal/src/peripherals/adc/builder.rs index 343ebf0301a4..34441bf5e01a 100644 --- a/hal/src/peripherals/adc/builder.rs +++ b/hal/src/peripherals/adc/builder.rs @@ -247,7 +247,7 @@ impl AdcBuilder { /// Turn the builder into an ADC. /// /// This function will convert the provided - /// [`Pclk`](crate::clock::v2::pclk::Pclk) into a [`DynPclk`]. + /// [`Pclk`](crate::clock::v2::pclk::Pclk) into a [`DynPclk`](crate::clock::v2::pclk::DynPclk). #[hal_cfg("adc-d5x")] #[inline] pub fn enable(