From e1e87fef25e4a8f3ac21bcb4a9cb9bf41ddfd0d2 Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 13 May 2023 18:45:14 +0200 Subject: [PATCH 01/13] rp/clocks: always inline configure_pll this is always advantageous, except *maybe* in O0. nothing really works as expected in O0, so we may as well always inline for constant propagation. --- embassy-rp/src/clocks.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 1354ccd27..0972cb215 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -576,6 +576,7 @@ unsafe fn start_xosc(crystal_hz: u32) { while !pac::XOSC.status().read().stable() {} } +#[inline(always)] unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { let ref_freq = input_freq / config.refdiv; From 2f2860b09697845029b4827462fdf98b515e8898 Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 13 May 2023 18:45:40 +0200 Subject: [PATCH 02/13] rp/clocks: always reconfigure pll this is only really useful for runtime *re*configuration, which we don't currently support. even runtime reconfig probably won't need it, unless we keep taking the sledgehammer approach of reconfiguring everything all the time. --- embassy-rp/src/clocks.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 0972cb215..d34082716 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -587,18 +587,6 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { assert!(config.post_div2 <= config.post_div1); assert!(ref_freq <= (config.vco_freq / 16)); - // do not disrupt PLL that is already correctly configured and operating - let cs = p.cs().read(); - let prim = p.prim().read(); - if cs.lock() - && cs.refdiv() == config.refdiv as u8 - && p.fbdiv_int().read().fbdiv_int() == fbdiv as u16 - && prim.postdiv1() == config.post_div1 - && prim.postdiv2() == config.post_div2 - { - return; - } - // Reset it let mut peris = reset::Peripherals(0); match p { From d3494a4bdf513d5b61210180fa227a9bd99935ca Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 13 May 2023 18:55:40 +0200 Subject: [PATCH 03/13] rp/clocks: reset all plls at once we might not configure both, so we should put the others into reset state. leaving them fully as is might leave them running, which might not be the goal for runtime reconfig (when it comes around). this now mirrors how we reset all clock-using peripherals and only unreset those that are properly clocked. --- embassy-rp/src/clocks.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index d34082716..bfca3f02e 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -203,6 +203,13 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); while c.clk_ref_selected().read() != 1 {} + // Reset the PLLs + let mut peris = reset::Peripherals(0); + peris.set_pll_sys(true); + peris.set_pll_usb(true); + reset::reset(peris); + reset::unreset_wait(peris); + if let Some(config) = config.rosc { configure_rosc(config); } @@ -587,16 +594,6 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { assert!(config.post_div2 <= config.post_div1); assert!(ref_freq <= (config.vco_freq / 16)); - // Reset it - let mut peris = reset::Peripherals(0); - match p { - pac::PLL_SYS => peris.set_pll_sys(true), - pac::PLL_USB => peris.set_pll_usb(true), - _ => unreachable!(), - } - reset::reset(peris); - reset::unreset_wait(peris); - // Load VCO-related dividers before starting VCO p.cs().write(|w| w.set_refdiv(config.refdiv as _)); p.fbdiv_int().write(|w| w.set_fbdiv_int(fbdiv as _)); From 5bbed315131991745efacbaa5c384e11f704923b Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 13 May 2023 19:07:36 +0200 Subject: [PATCH 04/13] rp/clocks: provide fbdiv, not vco_freq solvers usually output fbdiv directly, using vco_freq to get back to fbdiv is not all that necessary or useful. both vco_freq and fbdiv have hidden constraints, but vco_freq is a lot less accurate because the fbdiv value resulting from the division may be off by almost a full ref_freq's worth of frequency. also fixes the usb pll config, which ran the pll vco way out of (below) spec. --- embassy-rp/src/clocks.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index bfca3f02e..63f70cec4 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -37,15 +37,15 @@ impl ClockConfig { clock_type: ExternalClock::Crystal, sys_pll: Some(PllConfig { refdiv: 1, - vco_freq: 1500_000_000, + fbdiv: 125, post_div1: 6, post_div2: 2, }), usb_pll: Some(PllConfig { refdiv: 1, - vco_freq: 480_000_000, - post_div1: 5, - post_div2: 2, + fbdiv: 120, + post_div1: 6, + post_div2: 5, }), }), ref_clk: RefClkConfig { @@ -126,7 +126,7 @@ pub struct XoscConfig { pub struct PllConfig { pub refdiv: u32, - pub vco_freq: u32, + pub fbdiv: u16, pub post_div1: u8, pub post_div2: u8, } @@ -587,16 +587,15 @@ unsafe fn start_xosc(crystal_hz: u32) { unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { let ref_freq = input_freq / config.refdiv; - let fbdiv = config.vco_freq / ref_freq; - assert!(fbdiv >= 16 && fbdiv <= 320); + assert!(config.fbdiv >= 16 && config.fbdiv <= 320); assert!(config.post_div1 >= 1 && config.post_div1 <= 7); assert!(config.post_div2 >= 1 && config.post_div2 <= 7); assert!(config.post_div2 <= config.post_div1); - assert!(ref_freq <= (config.vco_freq / 16)); + assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); // Load VCO-related dividers before starting VCO p.cs().write(|w| w.set_refdiv(config.refdiv as _)); - p.fbdiv_int().write(|w| w.set_fbdiv_int(fbdiv as _)); + p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv)); // Turn on PLL p.pwr().modify(|w| { From d97a77147927b8ea6b245ec88a52de92db33813b Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 16 May 2023 17:13:09 +0200 Subject: [PATCH 05/13] rp/clocks: remove unsupported xosc config input the datasheet says that the xosc may be run by feeding a square wave into the XIN pin of the chip, but requires that the oscillator be set to pass through XIN in that case. it does not mention how, the xosc peripheral does not seem to have any config bits that could be set to this effect, and pico-sdk seems to have no (or at least no special) handling for this configuration at all. it can thus be assumed to either be not supported even by the reference sdk or to not need different handling. --- embassy-rp/src/clocks.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 63f70cec4..dc8505987 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -34,7 +34,6 @@ impl ClockConfig { }), xosc: Some(XoscConfig { hz: crystal_hz, - clock_type: ExternalClock::Crystal, sys_pll: Some(PllConfig { refdiv: 1, fbdiv: 125, @@ -119,7 +118,6 @@ pub struct RoscConfig { pub struct XoscConfig { pub hz: u32, - pub clock_type: ExternalClock, pub sys_pll: Option, pub usb_pll: Option, } @@ -131,10 +129,6 @@ pub struct PllConfig { pub post_div2: u8, } -pub enum ExternalClock { - Crystal, - Clock, -} pub struct RefClkConfig { pub src: RefClkSrc, pub div: u8, @@ -223,12 +217,9 @@ pub(crate) unsafe fn init(config: ClockConfig) { }); // start XOSC - match config.clock_type { - ExternalClock::Crystal => start_xosc(config.hz), - // TODO The datasheet says the xosc needs to be put into a bypass mode to use an - // external clock, but is mum about how to do that. - ExternalClock::Clock => todo!(), - } + // datasheet mentions support for clock inputs into XIN, but doesn't go into + // how this is achieved. pico-sdk doesn't support this at all. + start_xosc(config.hz); if let Some(sys_pll_config) = config.sys_pll { configure_pll(pac::PLL_SYS, config.hz, sys_pll_config); From f97b591831cab5ec29cfdb7cb98bc93debfdb57e Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 16 May 2023 18:13:15 +0200 Subject: [PATCH 06/13] rp/clocks: don't expose unstable pac items exposing pac items kind of undermines the unstable-pac feature. directly exposing register structure is also pretty inconvenient since the clock switching code takes care of the src/aux difference in behavior, so a user needn't really be forced to write down decomposed register values. --- embassy-rp/src/clocks.rs | 214 ++++++++++++++++++++++++----------- examples/rp/src/bin/gpout.rs | 4 +- 2 files changed, 148 insertions(+), 70 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index dc8505987..6d389cace 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -6,11 +6,18 @@ use crate::{pac, reset, Peripheral}; // TODO fix terrible use of global here static mut XIN_HZ: u32 = 0; -pub use rp_pac::clocks::vals::{ - ClkAdcCtrlAuxsrc as AdcAuxsrc, ClkGpoutCtrlAuxsrc as GpoutSrc, ClkPeriCtrlAuxsrc as PeriClkAuxsrc, - ClkRefCtrlAuxsrc as RefAuxsrc, ClkRtcCtrlAuxsrc as RtcAuxsrc, ClkSysCtrlAuxsrc as SysAuxsrc, - ClkUsbCtrlAuxsrc as UsbAuxsrc, -}; +#[repr(u8)] +#[non_exhaustive] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum PeriClkSrc { + Sys = ClkPeriCtrlAuxsrc::CLK_SYS.0, + PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS.0, + PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB.0, + Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH.0, + Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC.0, + Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0, + Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0, +} #[non_exhaustive] pub struct ClockConfig { @@ -18,7 +25,7 @@ pub struct ClockConfig { pub xosc: Option, pub ref_clk: RefClkConfig, pub sys_clk: SysClkConfig, - pub peri_clk_src: Option, + pub peri_clk_src: Option, pub usb_clk: Option, pub adc_clk: Option, pub rtc_clk: Option, @@ -28,7 +35,7 @@ impl ClockConfig { pub fn crystal(crystal_hz: u32) -> Self { Self { rosc: Some(RoscConfig { - range: pac::rosc::vals::FreqRange::MEDIUM, + range: RoscRange::Medium, drive_strength: [0; 8], div: 16, }), @@ -52,23 +59,23 @@ impl ClockConfig { div: 1, }, sys_clk: SysClkConfig { - src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS), + src: SysClkSrc::PllSys, div_int: 1, div_frac: 0, }, - peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS), + peri_clk_src: Some(PeriClkSrc::Sys), usb_clk: Some(UsbClkConfig { - src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, + src: UsbClkSrc::PllUsb, div: 1, phase: 0, }), adc_clk: Some(AdcClkConfig { - src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, + src: AdcClkSrc::PllUsb, div: 1, phase: 0, }), rtc_clk: Some(RtcClkConfig { - src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, + src: RtcClkSrc::PllUsb, div_int: 1024, div_frac: 0, phase: 0, @@ -79,7 +86,7 @@ impl ClockConfig { pub fn rosc() -> Self { Self { rosc: Some(RoscConfig { - range: pac::rosc::vals::FreqRange::HIGH, + range: RoscRange::High, drive_strength: [0; 8], div: 1, }), @@ -89,19 +96,19 @@ impl ClockConfig { div: 1, }, sys_clk: SysClkConfig { - src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC), + src: SysClkSrc::Rosc, div_int: 1, div_frac: 0, }, - peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH), + peri_clk_src: Some(PeriClkSrc::Rosc), usb_clk: None, adc_clk: Some(AdcClkConfig { - src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, + src: AdcClkSrc::Rosc, div: 1, phase: 0, }), rtc_clk: Some(RtcClkConfig { - src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, + src: RtcClkSrc::Rosc, div_int: 1024, div_frac: 0, phase: 0, @@ -110,8 +117,18 @@ impl ClockConfig { } } +#[repr(u16)] +#[non_exhaustive] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RoscRange { + Low = pac::rosc::vals::FreqRange::LOW.0, + Medium = pac::rosc::vals::FreqRange::MEDIUM.0, + High = pac::rosc::vals::FreqRange::HIGH.0, + TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0, +} + pub struct RoscConfig { - pub range: pac::rosc::vals::FreqRange, + pub range: RoscRange, pub drive_strength: [u8; 8], pub div: u16, } @@ -134,15 +151,30 @@ pub struct RefClkConfig { pub div: u8, } +#[non_exhaustive] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RefClkSrc { + // main sources Xosc, Rosc, - Aux(ClkRefCtrlAuxsrc), + // aux sources + PllUsb, + Gpin0, + Gpin1, } +#[non_exhaustive] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum SysClkSrc { + // main sources Ref, - Aux(ClkSysCtrlAuxsrc), + // aux sources + PllSys, + PllUsb, + Rosc, + Xosc, + Gpin0, + Gpin1, } pub struct SysClkConfig { @@ -151,20 +183,56 @@ pub struct SysClkConfig { pub div_frac: u8, } +#[repr(u8)] +#[non_exhaustive] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum UsbClkSrc { + PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB.0, + PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS.0, + Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH.0, + Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC.0, + Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0, + Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0, +} + pub struct UsbClkConfig { - pub src: ClkUsbCtrlAuxsrc, + pub src: UsbClkSrc, pub div: u8, pub phase: u8, } +#[repr(u8)] +#[non_exhaustive] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum AdcClkSrc { + PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB.0, + PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS.0, + Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH.0, + Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC.0, + Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0, + Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0, +} + pub struct AdcClkConfig { - pub src: ClkAdcCtrlAuxsrc, + pub src: AdcClkSrc, pub div: u8, pub phase: u8, } +#[repr(u8)] +#[non_exhaustive] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum RtcClkSrc { + PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB.0, + PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS.0, + Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH.0, + Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC.0, + Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0, + Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0, +} + pub struct RtcClkConfig { - pub src: ClkRtcCtrlAuxsrc, + pub src: RtcClkSrc, pub div_int: u32, pub div_frac: u8, pub phase: u8, @@ -229,27 +297,21 @@ pub(crate) unsafe fn init(config: ClockConfig) { } } - match config.ref_clk.src { - RefClkSrc::Xosc => { - c.clk_ref_ctrl().write(|w| { - w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC); - }); - while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {} + let (ref_src, ref_aux) = { + use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src}; + match config.ref_clk.src { + RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB), + RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB), + RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB), + RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0), + RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1), } - RefClkSrc::Rosc => { - c.clk_ref_ctrl().write(|w| { - w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH); - }); - while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::ROSC_CLKSRC_PH.0 {} - } - RefClkSrc::Aux(src) => { - c.clk_ref_ctrl().write(|w| { - w.set_auxsrc(src); - w.set_src(ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX); - }); - while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX.0 {} - } - } + }; + c.clk_ref_ctrl().write(|w| { + w.set_src(ref_src); + w.set_auxsrc(ref_aux); + }); + while c.clk_ref_selected().read() != 1 << ref_src.0 {} c.clk_ref_div().write(|w| { w.set_int(config.ref_clk.div); }); @@ -259,26 +321,27 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_enable(true); }); - match config.sys_clk.src { - SysClkSrc::Ref => { - c.clk_sys_ctrl().write(|w| { - w.set_src(ClkSysCtrlSrc::CLK_REF); - }); - while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} - } - SysClkSrc::Aux(src) => { - c.clk_sys_ctrl().write(|w| { - w.set_src(ClkSysCtrlSrc::CLK_REF); - }); - while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} - - c.clk_sys_ctrl().write(|w| { - w.set_auxsrc(src); - w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); - }); - while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {} + let (sys_src, sys_aux) = { + use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; + match config.sys_clk.src { + SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS), + SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS), + SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB), + SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC), + SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC), + SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0), + SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1), } + }; + if sys_src != ClkSysCtrlSrc::CLK_REF { + c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); + while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} } + c.clk_sys_ctrl().write(|w| { + w.set_auxsrc(sys_aux); + w.set_src(sys_src); + }); + while c.clk_sys_selected().read() != 1 << sys_src.0 {} c.clk_sys_div().write(|w| { w.set_int(config.sys_clk.div_int); w.set_frac(config.sys_clk.div_frac); @@ -289,7 +352,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { if let Some(src) = config.peri_clk_src { c.clk_peri_ctrl().write(|w| { w.set_enable(true); - w.set_auxsrc(src); + w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _)); }); } else { peris.set_spi0(false); @@ -304,7 +367,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_usb_ctrl().write(|w| { w.set_phase(conf.phase); w.set_enable(true); - w.set_auxsrc(conf.src); + w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _)); }); } else { peris.set_usbctrl(false); @@ -316,7 +379,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_adc_ctrl().write(|w| { w.set_phase(conf.phase); w.set_enable(true); - w.set_auxsrc(conf.src); + w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _)); }); } else { peris.set_adc(false); @@ -334,7 +397,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_rtc_ctrl().write(|w| { w.set_phase(conf.phase); w.set_enable(true); - w.set_auxsrc(conf.src); + w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _)); }); } else { peris.set_rtc(false); @@ -369,7 +432,7 @@ unsafe fn configure_rosc(config: RoscConfig) { p.ctrl().write(|w| { w.set_enable(pac::rosc::vals::Enable::ENABLE); - w.set_freq_range(config.range); + w.set_freq_range(pac::rosc::vals::FreqRange(config.range as u16)); }); } @@ -671,6 +734,21 @@ impl_gpoutpin!(PIN_23, 1); impl_gpoutpin!(PIN_24, 2); impl_gpoutpin!(PIN_25, 3); +#[repr(u8)] +pub enum GpoutSrc { + PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS.0, + Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0, + Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0, + PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB.0, + Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC.0, + Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC.0, + Sys = ClkGpoutCtrlAuxsrc::CLK_SYS.0, + Usb = ClkGpoutCtrlAuxsrc::CLK_USB.0, + Adc = ClkGpoutCtrlAuxsrc::CLK_ADC.0, + Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC.0, + Ref = ClkGpoutCtrlAuxsrc::CLK_REF.0, +} + pub struct Gpout<'d, T: GpoutPin> { gpout: PeripheralRef<'d, T>, } @@ -696,11 +774,11 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { } } - pub fn set_src(&self, src: ClkGpoutCtrlAuxsrc) { + pub fn set_src(&self, src: GpoutSrc) { unsafe { let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { - w.set_auxsrc(src); + w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); }); } } diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs index 236a653ac..64461fc5f 100644 --- a/examples/rp/src/bin/gpout.rs +++ b/examples/rp/src/bin/gpout.rs @@ -17,14 +17,14 @@ async fn main(_spawner: Spawner) { gpout3.enable(); loop { - gpout3.set_src(clocks::GpoutSrc::CLK_SYS); + gpout3.set_src(clocks::GpoutSrc::Sys); info!( "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}", gpout3.get_freq() ); Timer::after(Duration::from_secs(2)).await; - gpout3.set_src(clocks::GpoutSrc::CLK_REF); + gpout3.set_src(clocks::GpoutSrc::Ref); info!( "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}", gpout3.get_freq() From 1379eb4e707e2b60b381a7288a586657dc539dfc Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 17 May 2023 02:46:38 +0200 Subject: [PATCH 07/13] rp/clocks: handle fractional gpout dividers --- embassy-rp/src/clocks.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 6d389cace..85d4d289b 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -821,11 +821,10 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { }; let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() }; - let int = if div.int() == 0 { 65536 } else { div.int() }; - // TODO handle fractional clock div - let _frac = div.frac(); + let int = if div.int() == 0 { 65536 } else { div.int() } as u64; + let frac = div.frac() as u64; - base / int + ((base as u64 * 256) / (int * 256 + frac)) as u32 } } From 0d4ab559a717cef0b9a86186142f403252f38a9b Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 13 May 2023 19:14:27 +0200 Subject: [PATCH 08/13] rp/clocks: fix comments and rosc defaults if rosc really does run at 140MHz in high at div=1 then these values were not correct and would've exceeded the chip spec. the HIL test device seems to run fast (150MHz) so they're still not quite correct, but rosc has high variance anyway so it's probably fine. --- embassy-rp/src/clocks.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 85d4d289b..2305a1e34 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -64,16 +64,19 @@ impl ClockConfig { div_frac: 0, }, peri_clk_src: Some(PeriClkSrc::Sys), + // CLK USB = PLL USB (48MHz) / 1 = 48MHz usb_clk: Some(UsbClkConfig { src: UsbClkSrc::PllUsb, div: 1, phase: 0, }), + // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz adc_clk: Some(AdcClkConfig { src: AdcClkSrc::PllUsb, div: 1, phase: 0, }), + // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz rtc_clk: Some(RtcClkConfig { src: RtcClkSrc::PllUsb, div_int: 1024, @@ -102,15 +105,17 @@ impl ClockConfig { }, peri_clk_src: Some(PeriClkSrc::Rosc), usb_clk: None, + // CLK ADC = ROSC (140MHz) / 3 ≅ 48MHz adc_clk: Some(AdcClkConfig { src: AdcClkSrc::Rosc, - div: 1, + div: 3, phase: 0, }), + // CLK RTC = ROSC (140MHz) / 2986.667969 ≅ 46875Hz rtc_clk: Some(RtcClkConfig { src: RtcClkSrc::Rosc, - div_int: 1024, - div_frac: 0, + div_int: 2986, + div_frac: 171, phase: 0, }), } @@ -362,7 +367,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { } if let Some(conf) = config.usb_clk { - // CLK USB = PLL USB (48MHz) / 1 = 48MHz c.clk_usb_div().write(|w| w.set_int(conf.div)); c.clk_usb_ctrl().write(|w| { w.set_phase(conf.phase); @@ -374,7 +378,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { } if let Some(conf) = config.adc_clk { - // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz c.clk_adc_div().write(|w| w.set_int(conf.div)); c.clk_adc_ctrl().write(|w| { w.set_phase(conf.phase); @@ -386,7 +389,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { } if let Some(conf) = config.rtc_clk { - // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz c.clk_rtc_ctrl().modify(|w| { w.set_enable(false); }); @@ -661,7 +663,7 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { // Wait for PLL to lock while !p.cs().read().lock() {} - // Wait for PLL to lock + // Set post-dividers p.prim().write(|w| { w.set_postdiv1(config.post_div1); w.set_postdiv2(config.post_div2); From f79d8cb2d3998662eb4555d424cc75f3899a3151 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 16 May 2023 22:45:50 +0200 Subject: [PATCH 09/13] rp/clocks: store clock frequencies in ram don't recalculate clock frequencies every time they are asked for. while this is not very often in practice it does consume a bunch of flash space that cannot be optimized away, and was pulled in unconditionally previously. while we technically only need the configured rosc, xosc and gpin frequencies it is easier to store all frequencies (and much cheaper at runtime too). --- embassy-rp/src/clocks.rs | 382 ++++++++++++++++++-------------------- embassy-rp/src/rtc/mod.rs | 7 +- 2 files changed, 183 insertions(+), 206 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 2305a1e34..9e581f105 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1,10 +1,39 @@ +use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; + use embassy_hal_common::{into_ref, PeripheralRef}; use pac::clocks::vals::*; use crate::{pac, reset, Peripheral}; -// TODO fix terrible use of global here -static mut XIN_HZ: u32 = 0; +struct Clocks { + xosc: AtomicU32, + sys: AtomicU32, + reference: AtomicU32, + pll_sys: AtomicU32, + pll_usb: AtomicU32, + usb: AtomicU32, + adc: AtomicU32, + gpin0: AtomicU32, + gpin1: AtomicU32, + rosc: AtomicU32, + peri: AtomicU32, + rtc: AtomicU16, +} + +static CLOCKS: Clocks = Clocks { + xosc: AtomicU32::new(0), + sys: AtomicU32::new(0), + reference: AtomicU32::new(0), + pll_sys: AtomicU32::new(0), + pll_usb: AtomicU32::new(0), + usb: AtomicU32::new(0), + adc: AtomicU32::new(0), + gpin0: AtomicU32::new(0), + gpin1: AtomicU32::new(0), + rosc: AtomicU32::new(0), + peri: AtomicU32::new(0), + rtc: AtomicU16::new(0), +}; #[repr(u8)] #[non_exhaustive] @@ -29,12 +58,15 @@ pub struct ClockConfig { pub usb_clk: Option, pub adc_clk: Option, pub rtc_clk: Option, + pub gpin0_hz: Option, + pub gpin1_hz: Option, } impl ClockConfig { pub fn crystal(crystal_hz: u32) -> Self { Self { rosc: Some(RoscConfig { + hz: 6_500_000, range: RoscRange::Medium, drive_strength: [0; 8], div: 16, @@ -83,12 +115,15 @@ impl ClockConfig { div_frac: 0, phase: 0, }), + gpin0_hz: None, + gpin1_hz: None, } } pub fn rosc() -> Self { Self { rosc: Some(RoscConfig { + hz: 140_000_000, range: RoscRange::High, drive_strength: [0; 8], div: 1, @@ -118,6 +153,8 @@ impl ClockConfig { div_frac: 171, phase: 0, }), + gpin0_hz: None, + gpin1_hz: None, } } } @@ -133,6 +170,11 @@ pub enum RoscRange { } pub struct RoscConfig { + /// Final frequency of the oscillator, after the divider has been applied. + /// The oscillator has a nominal frequency of 6.5MHz at medium range with + /// divider 16 and all drive strengths set to 0, other values should be + /// measured in situ. + pub hz: u32, pub range: RoscRange, pub drive_strength: [u8; 8], pub div: u16, @@ -145,7 +187,7 @@ pub struct XoscConfig { } pub struct PllConfig { - pub refdiv: u32, + pub refdiv: u8, pub fbdiv: u16, pub post_div1: u8, pub post_div2: u8, @@ -277,41 +319,60 @@ pub(crate) unsafe fn init(config: ClockConfig) { reset::reset(peris); reset::unreset_wait(peris); - if let Some(config) = config.rosc { - configure_rosc(config); - } + let gpin0_freq = config.gpin0_hz.unwrap_or(0); + CLOCKS.gpin0.store(gpin0_freq, Ordering::Relaxed); + let gpin1_freq = config.gpin1_hz.unwrap_or(0); + CLOCKS.gpin1.store(gpin1_freq, Ordering::Relaxed); - if let Some(config) = config.xosc { - XIN_HZ = config.hz; + let rosc_freq = match config.rosc { + Some(config) => configure_rosc(config), + None => 0, + }; + CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); - pac::WATCHDOG.tick().write(|w| { - w.set_cycles((config.hz / 1_000_000) as u16); - w.set_enable(true); - }); + let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc { + Some(config) => { + pac::WATCHDOG.tick().write(|w| { + w.set_cycles((config.hz / 1_000_000) as u16); + w.set_enable(true); + }); - // start XOSC - // datasheet mentions support for clock inputs into XIN, but doesn't go into - // how this is achieved. pico-sdk doesn't support this at all. - start_xosc(config.hz); + // start XOSC + // datasheet mentions support for clock inputs into XIN, but doesn't go into + // how this is achieved. pico-sdk doesn't support this at all. + start_xosc(config.hz); - if let Some(sys_pll_config) = config.sys_pll { - configure_pll(pac::PLL_SYS, config.hz, sys_pll_config); + let pll_sys_freq = match config.sys_pll { + Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config), + None => 0, + }; + let pll_usb_freq = match config.usb_pll { + Some(usb_pll_config) => configure_pll(pac::PLL_USB, config.hz, usb_pll_config), + None => 0, + }; + + (config.hz, pll_sys_freq, pll_usb_freq) } - if let Some(usb_pll_config) = config.usb_pll { - configure_pll(pac::PLL_USB, config.hz, usb_pll_config); - } - } + None => (0, 0, 0), + }; + CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed); + CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed); + CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed); - let (ref_src, ref_aux) = { + let (ref_src, ref_aux, clk_ref_freq) = { use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src}; + let div = config.ref_clk.div as u32; + assert!(div >= 1 && div <= 4); match config.ref_clk.src { - RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB), - RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB), - RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB), - RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0), - RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1), + RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div), + RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div), + RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div), + RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div), + RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div), } }; + assert!(clk_ref_freq != 0); + CLOCKS.reference.store(clk_ref_freq, Ordering::Relaxed); c.clk_ref_ctrl().write(|w| { w.set_src(ref_src); w.set_auxsrc(ref_aux); @@ -322,22 +383,27 @@ pub(crate) unsafe fn init(config: ClockConfig) { }); pac::WATCHDOG.tick().write(|w| { - w.set_cycles((clk_ref_freq() / 1_000_000) as u16); + w.set_cycles((clk_ref_freq / 1_000_000) as u16); w.set_enable(true); }); - let (sys_src, sys_aux) = { + let (sys_src, sys_aux, clk_sys_freq) = { use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; - match config.sys_clk.src { - SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS), - SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS), - SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB), - SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC), - SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC), - SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0), - SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1), - } + let (src, aux, freq) = match config.sys_clk.src { + SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS, clk_ref_freq), + SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS, pll_sys_freq), + SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq), + SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq), + SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq), + SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), + SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), + }; + assert!(config.sys_clk.div_int <= 0x1000000); + let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64; + (src, aux, ((freq as u64 * 256) / div) as u32) }; + assert!(clk_sys_freq != 0); + CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); if sys_src != ClkSysCtrlSrc::CLK_REF { c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} @@ -359,11 +425,23 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_enable(true); w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _)); }); + let peri_freq = match src { + PeriClkSrc::Sys => clk_sys_freq, + PeriClkSrc::PllSys => pll_sys_freq, + PeriClkSrc::PllUsb => pll_usb_freq, + PeriClkSrc::Rosc => rosc_freq, + PeriClkSrc::Xosc => xosc_freq, + PeriClkSrc::Gpin0 => gpin0_freq, + PeriClkSrc::Gpin1 => gpin1_freq, + }; + assert!(peri_freq != 0); + CLOCKS.peri.store(peri_freq, Ordering::Relaxed); } else { peris.set_spi0(false); peris.set_spi1(false); peris.set_uart0(false); peris.set_uart1(false); + CLOCKS.peri.store(0, Ordering::Relaxed); } if let Some(conf) = config.usb_clk { @@ -373,8 +451,20 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_enable(true); w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _)); }); + let usb_freq = match conf.src { + UsbClkSrc::PllUsb => pll_usb_freq, + UsbClkSrc::PllSys => pll_sys_freq, + UsbClkSrc::Rosc => rosc_freq, + UsbClkSrc::Xosc => xosc_freq, + UsbClkSrc::Gpin0 => gpin0_freq, + UsbClkSrc::Gpin1 => gpin1_freq, + }; + assert!(usb_freq != 0); + assert!(conf.div >= 1 && conf.div <= 4); + CLOCKS.usb.store(usb_freq / conf.div as u32, Ordering::Relaxed); } else { peris.set_usbctrl(false); + CLOCKS.usb.store(0, Ordering::Relaxed); } if let Some(conf) = config.adc_clk { @@ -384,8 +474,20 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_enable(true); w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _)); }); + let adc_in_freq = match conf.src { + AdcClkSrc::PllUsb => pll_usb_freq, + AdcClkSrc::PllSys => pll_sys_freq, + AdcClkSrc::Rosc => rosc_freq, + AdcClkSrc::Xosc => xosc_freq, + AdcClkSrc::Gpin0 => gpin0_freq, + AdcClkSrc::Gpin1 => gpin1_freq, + }; + assert!(adc_in_freq != 0); + assert!(conf.div >= 1 && conf.div <= 4); + CLOCKS.adc.store(adc_in_freq / conf.div as u32, Ordering::Relaxed); } else { peris.set_adc(false); + CLOCKS.adc.store(0, Ordering::Relaxed); } if let Some(conf) = config.rtc_clk { @@ -401,15 +503,30 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_enable(true); w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _)); }); + let rtc_in_freq = match conf.src { + RtcClkSrc::PllUsb => pll_usb_freq, + RtcClkSrc::PllSys => pll_sys_freq, + RtcClkSrc::Rosc => rosc_freq, + RtcClkSrc::Xosc => xosc_freq, + RtcClkSrc::Gpin0 => gpin0_freq, + RtcClkSrc::Gpin1 => gpin1_freq, + }; + assert!(rtc_in_freq != 0); + assert!(config.sys_clk.div_int <= 0x1000000); + CLOCKS.rtc.store( + ((rtc_in_freq as u64 * 256) / (conf.div_int as u64 * 256 + conf.div_frac as u64)) as u16, + Ordering::Relaxed, + ); } else { peris.set_rtc(false); + CLOCKS.rtc.store(0, Ordering::Relaxed); } // Peripheral clocks should now all be running reset::unreset_wait(peris); } -unsafe fn configure_rosc(config: RoscConfig) { +unsafe fn configure_rosc(config: RoscConfig) -> u32 { let p = pac::ROSC; p.freqa().write(|w| { @@ -436,193 +553,55 @@ unsafe fn configure_rosc(config: RoscConfig) { w.set_enable(pac::rosc::vals::Enable::ENABLE); w.set_freq_range(pac::rosc::vals::FreqRange(config.range as u16)); }); + + config.hz } -pub fn estimate_rosc_freq() -> u32 { - let p = pac::ROSC; - - let base = match unsafe { p.ctrl().read().freq_range() } { - pac::rosc::vals::FreqRange::LOW => 84_000_000, - pac::rosc::vals::FreqRange::MEDIUM => 104_000_000, - pac::rosc::vals::FreqRange::HIGH => 140_000_000, - pac::rosc::vals::FreqRange::TOOHIGH => 208_000_000, - _ => unreachable!(), - }; - let mut div = unsafe { p.div().read().0 - pac::rosc::vals::Div::PASS.0 as u32 }; - if div == 0 { - div = 32 - } - - base / div +pub fn rosc_freq() -> u32 { + CLOCKS.rosc.load(Ordering::Relaxed) } pub fn xosc_freq() -> u32 { - unsafe { XIN_HZ } + CLOCKS.xosc.load(Ordering::Relaxed) } pub fn gpin0_freq() -> u32 { - todo!() + CLOCKS.gpin0.load(Ordering::Relaxed) } pub fn gpin1_freq() -> u32 { - todo!() + CLOCKS.gpin1.load(Ordering::Relaxed) } pub fn pll_sys_freq() -> u32 { - let p = pac::PLL_SYS; - - let input_freq = xosc_freq(); - let cs = unsafe { p.cs().read() }; - - let refdiv = cs.refdiv() as u32; - let fbdiv = unsafe { p.fbdiv_int().read().fbdiv_int() } as u32; - let (postdiv1, postdiv2) = unsafe { - let prim = p.prim().read(); - (prim.postdiv1() as u32, prim.postdiv2() as u32) - }; - - (((input_freq / refdiv) * fbdiv) / postdiv1) / postdiv2 + CLOCKS.pll_sys.load(Ordering::Relaxed) } pub fn pll_usb_freq() -> u32 { - let p = pac::PLL_USB; - - let input_freq = xosc_freq(); - let cs = unsafe { p.cs().read() }; - - let refdiv = cs.refdiv() as u32; - let fbdiv = unsafe { p.fbdiv_int().read().fbdiv_int() } as u32; - let (postdiv1, postdiv2) = unsafe { - let prim = p.prim().read(); - (prim.postdiv1() as u32, prim.postdiv2() as u32) - }; - - (((input_freq / refdiv) * fbdiv) / postdiv1) / postdiv2 + CLOCKS.pll_usb.load(Ordering::Relaxed) } pub fn clk_sys_freq() -> u32 { - let c = pac::CLOCKS; - let ctrl = unsafe { c.clk_sys_ctrl().read() }; - - let base = match ctrl.src() { - ClkSysCtrlSrc::CLK_REF => clk_ref_freq(), - ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX => match ctrl.auxsrc() { - ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkSysCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkSysCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), - ClkSysCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), - ClkSysCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkSysCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - _ => unreachable!(), - }, - _ => unreachable!(), - }; - - let div = unsafe { c.clk_sys_div().read() }; - let int = if div.int() == 0 { 65536 } else { div.int() }; - // TODO handle fractional clock div - let _frac = div.frac(); - - base / int + CLOCKS.sys.load(Ordering::Relaxed) } pub fn clk_ref_freq() -> u32 { - let c = pac::CLOCKS; - let ctrl = unsafe { c.clk_ref_ctrl().read() }; - - let base = match ctrl.src() { - ClkRefCtrlSrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), - ClkRefCtrlSrc::XOSC_CLKSRC => xosc_freq(), - ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX => match ctrl.auxsrc() { - ClkRefCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkRefCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkRefCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - _ => unreachable!(), - }, - _ => unreachable!(), - }; - - let div = unsafe { c.clk_ref_div().read() }; - let int = if div.int() == 0 { 4 } else { div.int() as u32 }; - - base / int + CLOCKS.reference.load(Ordering::Relaxed) } pub fn clk_peri_freq() -> u32 { - let c = pac::CLOCKS; - let src = unsafe { c.clk_peri_ctrl().read().auxsrc() }; - - match src { - ClkPeriCtrlAuxsrc::CLK_SYS => clk_sys_freq(), - ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), - ClkPeriCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), - ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - _ => unreachable!(), - } + CLOCKS.peri.load(Ordering::Relaxed) } pub fn clk_usb_freq() -> u32 { - let c = pac::CLOCKS; - let ctrl = unsafe { c.clk_usb_ctrl().read() }; - - let base = match ctrl.auxsrc() { - ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), - ClkUsbCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), - ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - _ => unreachable!(), - }; - - let div = unsafe { c.clk_ref_div().read() }; - let int = if div.int() == 0 { 4 } else { div.int() as u32 }; - - base / int + CLOCKS.usb.load(Ordering::Relaxed) } pub fn clk_adc_freq() -> u32 { - let c = pac::CLOCKS; - let ctrl = unsafe { c.clk_adc_ctrl().read() }; - - let base = match ctrl.auxsrc() { - ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), - ClkAdcCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), - ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - _ => unreachable!(), - }; - - let div = unsafe { c.clk_adc_div().read() }; - let int = if div.int() == 0 { 4 } else { div.int() as u32 }; - - base / int + CLOCKS.adc.load(Ordering::Relaxed) } -pub fn clk_rtc_freq() -> u32 { - let c = pac::CLOCKS; - let src = unsafe { c.clk_rtc_ctrl().read().auxsrc() }; - - let base = match src { - ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), - ClkRtcCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), - ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - _ => unreachable!(), - }; - - let div = unsafe { c.clk_rtc_div().read() }; - let int = if div.int() == 0 { 65536 } else { div.int() }; - // TODO handle fractional clock div - let _frac = div.frac(); - - base / int +pub fn clk_rtc_freq() -> u16 { + CLOCKS.rtc.load(Ordering::Relaxed) } unsafe fn start_xosc(crystal_hz: u32) { @@ -640,14 +619,15 @@ unsafe fn start_xosc(crystal_hz: u32) { } #[inline(always)] -unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { - let ref_freq = input_freq / config.refdiv; - +unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { + let ref_freq = input_freq / config.refdiv as u32; assert!(config.fbdiv >= 16 && config.fbdiv <= 320); assert!(config.post_div1 >= 1 && config.post_div1 <= 7); assert!(config.post_div2 >= 1 && config.post_div2 <= 7); - assert!(config.post_div2 <= config.post_div1); + assert!(config.refdiv >= 1 && config.refdiv <= 63); assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); + let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32); + assert!(vco_freq >= 750_000_000 && vco_freq <= 1800_000_000); // Load VCO-related dividers before starting VCO p.cs().write(|w| w.set_refdiv(config.refdiv as _)); @@ -671,6 +651,8 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { // Turn on post divider p.pwr().modify(|w| w.set_postdivpd(false)); + + vco_freq / ((config.post_div1 * config.post_div2) as u32) } pub trait GpinPin: crate::gpio::Pin { @@ -812,12 +794,12 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), + ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => rosc_freq(), ClkGpoutCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), - ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq(), + ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _, ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), _ => unreachable!(), }; diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index c173909c7..c213ad174 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -26,12 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> { into_ref!(inner); // Set the RTC divider - unsafe { - inner - .regs() - .clkdiv_m1() - .write(|w| w.set_clkdiv_m1(clk_rtc_freq() as u16 - 1)) - }; + unsafe { inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)) }; let mut result = Self { inner }; result.set_leap_year_check(true); // should be on by default, make sure this is the case. From 1b3d9a0aeffd9e0619126c3b2dc42520cc2b4209 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 17 May 2023 02:25:28 +0200 Subject: [PATCH 10/13] rp/clocks: compactify pll setup we don't need to preserve existing bits of the pll pwr register, so let's only write and save a few instructions. --- embassy-rp/src/clocks.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 9e581f105..cfc94f844 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -634,10 +634,12 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv)); // Turn on PLL - p.pwr().modify(|w| { + let pwr = p.pwr().write(|w| { + w.set_dsmpd(true); // "nothing is achieved by setting this low" w.set_pd(false); w.set_vcopd(false); w.set_postdivpd(true); + *w }); // Wait for PLL to lock @@ -650,7 +652,10 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> }); // Turn on post divider - p.pwr().modify(|w| w.set_postdivpd(false)); + p.pwr().write(|w| { + *w = pwr; + w.set_postdivpd(false); + }); vco_freq / ((config.post_div1 * config.post_div2) as u32) } From 053d5629ba88a67f4b126bd7ac4b478fbe00d17f Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 17 May 2023 02:52:29 +0200 Subject: [PATCH 11/13] rp/clocks: require GpinPin for gpin config we'll take static ownership of an entire pin (not just a limited reference), otherwise we cannot at all guarantee that the pin will not be reused for something else while still in use. in theory we could limit the liftime of this use, but that would require attaching lifetimes to ClockConfig (and subsequently the main config), passing those through init(), and returning an object that undoes the gpin configuration on drop. that's a lot unnecessary support code while we don't have runtime clock reconfig. --- embassy-rp/src/clocks.rs | 61 ++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index cfc94f844..7ab0ecd11 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1,8 +1,11 @@ +use core::marker::PhantomData; use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; use embassy_hal_common::{into_ref, PeripheralRef}; use pac::clocks::vals::*; +use crate::gpio::sealed::Pin; +use crate::gpio::AnyPin; use crate::{pac, reset, Peripheral}; struct Clocks { @@ -58,8 +61,8 @@ pub struct ClockConfig { pub usb_clk: Option, pub adc_clk: Option, pub rtc_clk: Option, - pub gpin0_hz: Option, - pub gpin1_hz: Option, + gpin0: Option<(u32, Gpin<'static, AnyPin>)>, + gpin1: Option<(u32, Gpin<'static, AnyPin>)>, } impl ClockConfig { @@ -115,8 +118,8 @@ impl ClockConfig { div_frac: 0, phase: 0, }), - gpin0_hz: None, - gpin1_hz: None, + gpin0: None, + gpin1: None, } } @@ -153,10 +156,20 @@ impl ClockConfig { div_frac: 171, phase: 0, }), - gpin0_hz: None, - gpin1_hz: None, + gpin0: None, + gpin1: None, } } + + pub fn bind_gpin(&mut self, gpin: Gpin<'static, P>, hz: u32) { + match P::NR { + 0 => self.gpin0 = Some((hz, gpin.map_into())), + 1 => self.gpin1 = Some((hz, gpin.map_into())), + _ => unreachable!(), + } + // pin is now provisionally bound. if the config is applied it must be forgotten, + // or Gpin::drop will deconfigure the clock input. + } } #[repr(u16)] @@ -319,9 +332,15 @@ pub(crate) unsafe fn init(config: ClockConfig) { reset::reset(peris); reset::unreset_wait(peris); - let gpin0_freq = config.gpin0_hz.unwrap_or(0); + let gpin0_freq = config.gpin0.map_or(0, |p| { + core::mem::forget(p.1); + p.0 + }); CLOCKS.gpin0.store(gpin0_freq, Ordering::Relaxed); - let gpin1_freq = config.gpin1_hz.unwrap_or(0); + let gpin1_freq = config.gpin1.map_or(0, |p| { + core::mem::forget(p.1); + p.0 + }); CLOCKS.gpin1.store(gpin1_freq, Ordering::Relaxed); let rosc_freq = match config.rosc { @@ -661,15 +680,13 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> } pub trait GpinPin: crate::gpio::Pin { - fn number(&self) -> usize; + const NR: usize; } macro_rules! impl_gpinpin { ($name:ident, $pin_num:expr, $gpin_num:expr) => { impl GpinPin for crate::peripherals::$name { - fn number(&self) -> usize { - $gpin_num - } + const NR: usize = $gpin_num; } }; } @@ -677,23 +694,31 @@ macro_rules! impl_gpinpin { impl_gpinpin!(PIN_20, 20, 0); impl_gpinpin!(PIN_22, 22, 1); -pub struct Gpin<'d, T: GpinPin> { - gpin: PeripheralRef<'d, T>, +pub struct Gpin<'d, T: Pin> { + gpin: PeripheralRef<'d, AnyPin>, + _phantom: PhantomData, } -impl<'d, T: GpinPin> Gpin<'d, T> { - pub fn new(gpin: impl Peripheral

+ 'd) -> Self { +impl<'d, T: Pin> Gpin<'d, T> { + pub fn new(gpin: impl Peripheral

+ 'd) -> Gpin<'d, P> { into_ref!(gpin); unsafe { gpin.io().ctrl().write(|w| w.set_funcsel(0x08)); } - Self { gpin } + Gpin { + gpin: gpin.map_into(), + _phantom: PhantomData, + } + } + + fn map_into(self) -> Gpin<'d, AnyPin> { + unsafe { core::mem::transmute(self) } } } -impl<'d, T: GpinPin> Drop for Gpin<'d, T> { +impl<'d, T: Pin> Drop for Gpin<'d, T> { fn drop(&mut self) { unsafe { self.gpin From 1e029a9e66f0a9621c2911e4147bb7a838190577 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 17 May 2023 03:21:07 +0200 Subject: [PATCH 12/13] rp/clocks: remove superfluous clock actions the rtc doesn't have to be disabled since it's always clocked from ref, and the watchdog doesn't need to be configured twice. --- embassy-rp/src/clocks.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 7ab0ecd11..c70436695 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -351,11 +351,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc { Some(config) => { - pac::WATCHDOG.tick().write(|w| { - w.set_cycles((config.hz / 1_000_000) as u16); - w.set_enable(true); - }); - // start XOSC // datasheet mentions support for clock inputs into XIN, but doesn't go into // how this is achieved. pico-sdk doesn't support this at all. @@ -510,9 +505,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { } if let Some(conf) = config.rtc_clk { - c.clk_rtc_ctrl().modify(|w| { - w.set_enable(false); - }); c.clk_rtc_div().write(|w| { w.set_int(conf.div_int); w.set_frac(conf.div_frac); From fc746a88b50f2d57a573d7a9ec8b8f3fbc0c9b08 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 17 May 2023 23:25:49 +0200 Subject: [PATCH 13/13] rp/clocks: comment out all gpin handling for now gpin clock sources aren't going to be very useful during cold boot and thus require runtime clock reconfig. once we get there we can use this for reference. or maybe we can't, only time will tell. --- embassy-rp/src/clocks.rs | 137 ++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index c70436695..67439fda3 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -8,6 +8,10 @@ use crate::gpio::sealed::Pin; use crate::gpio::AnyPin; use crate::{pac, reset, Peripheral}; +// NOTE: all gpin handling is commented out for future reference. +// gpin is not usually safe to use during the boot init() call, so it won't +// be very useful until we have runtime clock reconfiguration. once this +// happens we can resurrect the commented-out gpin bits. struct Clocks { xosc: AtomicU32, sys: AtomicU32, @@ -16,8 +20,8 @@ struct Clocks { pll_usb: AtomicU32, usb: AtomicU32, adc: AtomicU32, - gpin0: AtomicU32, - gpin1: AtomicU32, + // gpin0: AtomicU32, + // gpin1: AtomicU32, rosc: AtomicU32, peri: AtomicU32, rtc: AtomicU16, @@ -31,8 +35,8 @@ static CLOCKS: Clocks = Clocks { pll_usb: AtomicU32::new(0), usb: AtomicU32::new(0), adc: AtomicU32::new(0), - gpin0: AtomicU32::new(0), - gpin1: AtomicU32::new(0), + // gpin0: AtomicU32::new(0), + // gpin1: AtomicU32::new(0), rosc: AtomicU32::new(0), peri: AtomicU32::new(0), rtc: AtomicU16::new(0), @@ -47,8 +51,8 @@ pub enum PeriClkSrc { PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB.0, Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH.0, Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC.0, - Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0, - Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0, + // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0, + // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0, } #[non_exhaustive] @@ -61,8 +65,8 @@ pub struct ClockConfig { pub usb_clk: Option, pub adc_clk: Option, pub rtc_clk: Option, - gpin0: Option<(u32, Gpin<'static, AnyPin>)>, - gpin1: Option<(u32, Gpin<'static, AnyPin>)>, + // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, + // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, } impl ClockConfig { @@ -118,8 +122,8 @@ impl ClockConfig { div_frac: 0, phase: 0, }), - gpin0: None, - gpin1: None, + // gpin0: None, + // gpin1: None, } } @@ -156,20 +160,20 @@ impl ClockConfig { div_frac: 171, phase: 0, }), - gpin0: None, - gpin1: None, + // gpin0: None, + // gpin1: None, } } - pub fn bind_gpin(&mut self, gpin: Gpin<'static, P>, hz: u32) { - match P::NR { - 0 => self.gpin0 = Some((hz, gpin.map_into())), - 1 => self.gpin1 = Some((hz, gpin.map_into())), - _ => unreachable!(), - } - // pin is now provisionally bound. if the config is applied it must be forgotten, - // or Gpin::drop will deconfigure the clock input. - } + // pub fn bind_gpin(&mut self, gpin: Gpin<'static, P>, hz: u32) { + // match P::NR { + // 0 => self.gpin0 = Some((hz, gpin.map_into())), + // 1 => self.gpin1 = Some((hz, gpin.map_into())), + // _ => unreachable!(), + // } + // // pin is now provisionally bound. if the config is applied it must be forgotten, + // // or Gpin::drop will deconfigure the clock input. + // } } #[repr(u16)] @@ -219,8 +223,8 @@ pub enum RefClkSrc { Rosc, // aux sources PllUsb, - Gpin0, - Gpin1, + // Gpin0, + // Gpin1, } #[non_exhaustive] @@ -233,8 +237,8 @@ pub enum SysClkSrc { PllUsb, Rosc, Xosc, - Gpin0, - Gpin1, + // Gpin0, + // Gpin1, } pub struct SysClkConfig { @@ -251,8 +255,8 @@ pub enum UsbClkSrc { PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS.0, Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH.0, Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC.0, - Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0, - Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0, + // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0, + // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0, } pub struct UsbClkConfig { @@ -269,8 +273,8 @@ pub enum AdcClkSrc { PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS.0, Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH.0, Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC.0, - Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0, - Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0, + // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0, + // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0, } pub struct AdcClkConfig { @@ -287,8 +291,8 @@ pub enum RtcClkSrc { PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS.0, Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH.0, Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC.0, - Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0, - Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0, + // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0, + // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0, } pub struct RtcClkConfig { @@ -306,6 +310,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { // - USB, SYSCFG (breaks usb-to-swd on core1) let mut peris = reset::ALL_PERIPHERALS; peris.set_io_qspi(false); + // peris.set_io_bank0(false); // might be suicide if we're clocked from gpin peris.set_pads_qspi(false); peris.set_pll_sys(false); peris.set_pll_usb(false); @@ -332,16 +337,16 @@ pub(crate) unsafe fn init(config: ClockConfig) { reset::reset(peris); reset::unreset_wait(peris); - let gpin0_freq = config.gpin0.map_or(0, |p| { - core::mem::forget(p.1); - p.0 - }); - CLOCKS.gpin0.store(gpin0_freq, Ordering::Relaxed); - let gpin1_freq = config.gpin1.map_or(0, |p| { - core::mem::forget(p.1); - p.0 - }); - CLOCKS.gpin1.store(gpin1_freq, Ordering::Relaxed); + // let gpin0_freq = config.gpin0.map_or(0, |p| { + // core::mem::forget(p.1); + // p.0 + // }); + // CLOCKS.gpin0.store(gpin0_freq, Ordering::Relaxed); + // let gpin1_freq = config.gpin1.map_or(0, |p| { + // core::mem::forget(p.1); + // p.0 + // }); + // CLOCKS.gpin1.store(gpin1_freq, Ordering::Relaxed); let rosc_freq = match config.rosc { Some(config) => configure_rosc(config), @@ -381,8 +386,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div), RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div), RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div), - RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div), - RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div), + // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div), + // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div), } }; assert!(clk_ref_freq != 0); @@ -409,8 +414,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq), SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq), SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq), - SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), - SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), + // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), + // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), }; assert!(config.sys_clk.div_int <= 0x1000000); let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64; @@ -445,8 +450,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { PeriClkSrc::PllUsb => pll_usb_freq, PeriClkSrc::Rosc => rosc_freq, PeriClkSrc::Xosc => xosc_freq, - PeriClkSrc::Gpin0 => gpin0_freq, - PeriClkSrc::Gpin1 => gpin1_freq, + // PeriClkSrc::Gpin0 => gpin0_freq, + // PeriClkSrc::Gpin1 => gpin1_freq, }; assert!(peri_freq != 0); CLOCKS.peri.store(peri_freq, Ordering::Relaxed); @@ -470,8 +475,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { UsbClkSrc::PllSys => pll_sys_freq, UsbClkSrc::Rosc => rosc_freq, UsbClkSrc::Xosc => xosc_freq, - UsbClkSrc::Gpin0 => gpin0_freq, - UsbClkSrc::Gpin1 => gpin1_freq, + // UsbClkSrc::Gpin0 => gpin0_freq, + // UsbClkSrc::Gpin1 => gpin1_freq, }; assert!(usb_freq != 0); assert!(conf.div >= 1 && conf.div <= 4); @@ -493,8 +498,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { AdcClkSrc::PllSys => pll_sys_freq, AdcClkSrc::Rosc => rosc_freq, AdcClkSrc::Xosc => xosc_freq, - AdcClkSrc::Gpin0 => gpin0_freq, - AdcClkSrc::Gpin1 => gpin1_freq, + // AdcClkSrc::Gpin0 => gpin0_freq, + // AdcClkSrc::Gpin1 => gpin1_freq, }; assert!(adc_in_freq != 0); assert!(conf.div >= 1 && conf.div <= 4); @@ -519,8 +524,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { RtcClkSrc::PllSys => pll_sys_freq, RtcClkSrc::Rosc => rosc_freq, RtcClkSrc::Xosc => xosc_freq, - RtcClkSrc::Gpin0 => gpin0_freq, - RtcClkSrc::Gpin1 => gpin1_freq, + // RtcClkSrc::Gpin0 => gpin0_freq, + // RtcClkSrc::Gpin1 => gpin1_freq, }; assert!(rtc_in_freq != 0); assert!(config.sys_clk.div_int <= 0x1000000); @@ -576,12 +581,12 @@ pub fn xosc_freq() -> u32 { CLOCKS.xosc.load(Ordering::Relaxed) } -pub fn gpin0_freq() -> u32 { - CLOCKS.gpin0.load(Ordering::Relaxed) -} -pub fn gpin1_freq() -> u32 { - CLOCKS.gpin1.load(Ordering::Relaxed) -} +// pub fn gpin0_freq() -> u32 { +// CLOCKS.gpin0.load(Ordering::Relaxed) +// } +// pub fn gpin1_freq() -> u32 { +// CLOCKS.gpin1.load(Ordering::Relaxed) +// } pub fn pll_sys_freq() -> u32 { CLOCKS.pll_sys.load(Ordering::Relaxed) @@ -705,9 +710,9 @@ impl<'d, T: Pin> Gpin<'d, T> { } } - fn map_into(self) -> Gpin<'d, AnyPin> { - unsafe { core::mem::transmute(self) } - } + // fn map_into(self) -> Gpin<'d, AnyPin> { + // unsafe { core::mem::transmute(self) } + // } } impl<'d, T: Pin> Drop for Gpin<'d, T> { @@ -743,8 +748,8 @@ impl_gpoutpin!(PIN_25, 3); #[repr(u8)] pub enum GpoutSrc { PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS.0, - Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0, - Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0, + // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0, + // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0, PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB.0, Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC.0, Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC.0, @@ -813,8 +818,8 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { let base = match src { ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), + // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), + // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => rosc_freq(), ClkGpoutCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(),