From 1a96eae22c38afbd0c1c15d1d5dcc43bc639369b Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sun, 7 May 2023 13:49:48 -0400 Subject: [PATCH 1/7] rp clock configuration --- embassy-rp/src/clocks.rs | 515 ++++++++++++++++++++++++++++++++------- embassy-rp/src/lib.rs | 20 +- 2 files changed, 438 insertions(+), 97 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 8a34b293..4ae967aa 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -2,10 +2,138 @@ use pac::clocks::vals::*; use crate::{pac, reset}; -const XOSC_MHZ: u32 = 12; +static mut EXTERNAL_HZ: u32 = 0; + +pub struct ClockConfig { + rosc_config: Option, + xosc_config: Option, + ref_clk_config: (RefClkSrc, u8), + sys_clk_config: (SysClkSrc, u32), + peri_clk_src: Option, + usb_clk_config: Option<(ClkUsbCtrlAuxsrc, u8)>, + adc_clk_config: Option<(ClkAdcCtrlAuxsrc, u8)>, + rtc_clk_config: Option<(ClkRtcCtrlAuxsrc, u32)>, +} + +impl ClockConfig { + pub fn crystal(crystal_hz: u32) -> Self { + Self { + rosc_config: Some(RoscConfig { + range: pac::rosc::vals::FreqRange::MEDIUM, + drive_strength_0: 0, + drive_strength_1: 0, + drive_strength_2: 0, + drive_strength_3: 0, + drive_strength_4: 0, + drive_strength_5: 0, + drive_strength_6: 0, + drive_strength_7: 0, + div: 16, + }), + xosc_config: Some(XoscConfig { + hz: crystal_hz, + clock_type: ExternalClock::Crystal, + sys_pll: Some(PllConfig { + refdiv: 1, + vco_freq: 1500_000_000, + post_div1: 6, + post_div2: 2, + }), + usb_pll: Some(PllConfig { + refdiv: 1, + vco_freq: 480_000_000, + post_div1: 5, + post_div2: 2, + }), + }), + ref_clk_config: (RefClkSrc::Xosc, 1), + sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS), 1), + peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS), + usb_clk_config: Some((ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS, 1)), + adc_clk_config: Some((ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, 1)), + rtc_clk_config: Some((ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, 1024)), + } + } + + pub fn rosc() -> Self { + Self { + rosc_config: Some(RoscConfig { + range: pac::rosc::vals::FreqRange::HIGH, + drive_strength_0: 0, + drive_strength_1: 0, + drive_strength_2: 0, + drive_strength_3: 0, + drive_strength_4: 0, + drive_strength_5: 0, + drive_strength_6: 0, + drive_strength_7: 0, + div: 1, + }), + xosc_config: None, + ref_clk_config: (RefClkSrc::Rosc, 4), + sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC), 1), + peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH), + usb_clk_config: None, + adc_clk_config: Some((ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, 1)), + rtc_clk_config: Some((ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, 1024)), + } + } +} +pub enum ExternalClock { + Crystal, + Clock, +} + +pub struct XoscConfig { + hz: u32, + clock_type: ExternalClock, + sys_pll: Option, + usb_pll: Option, +} + +pub struct RoscConfig { + range: pac::rosc::vals::FreqRange, + drive_strength_0: u8, + drive_strength_1: u8, + drive_strength_2: u8, + drive_strength_3: u8, + drive_strength_4: u8, + drive_strength_5: u8, + drive_strength_6: u8, + drive_strength_7: u8, + div: u16, +} + +pub struct PllConfig { + pub refdiv: u32, + pub vco_freq: u32, + pub post_div1: u8, + pub post_div2: u8, +} + +pub struct RefClkConfig { + pub src: RefClkSrc, + pub div: u8, +} + +pub enum RefClkSrc { + Xosc, + Rosc, + Aux(ClkRefCtrlAuxsrc), +} + +pub struct SysClkConfig { + pub src: SysClkSrc, + pub div: u32, +} + +pub enum SysClkSrc { + Ref, + Aux(ClkSysCtrlAuxsrc), +} /// safety: must be called exactly once at bootup -pub(crate) unsafe fn init() { +pub(crate) unsafe fn init(config: ClockConfig) { // Reset everything except: // - QSPI (we're using it to run this code!) // - PLLs (it may be suicide if that's what's clocking us) @@ -15,124 +143,325 @@ pub(crate) unsafe fn init() { peris.set_pads_qspi(false); peris.set_pll_sys(false); peris.set_pll_usb(false); + // TODO investigate if usb should be unreset here peris.set_usbctrl(false); peris.set_syscfg(false); reset::reset(peris); - // Remove reset from peripherals which are clocked only by clk_sys and - // clk_ref. Other peripherals stay in reset until we've configured clocks. - let mut peris = reset::ALL_PERIPHERALS; - peris.set_adc(false); - peris.set_rtc(false); - peris.set_spi0(false); - peris.set_spi1(false); - peris.set_uart0(false); - peris.set_uart1(false); - peris.set_usbctrl(false); - reset::unreset_wait(peris); - - // Start tick in watchdog - // xosc 12 mhz - pac::WATCHDOG.tick().write(|w| { - w.set_cycles(XOSC_MHZ as u16); - w.set_enable(true); - }); - // Disable resus that may be enabled from previous software let c = pac::CLOCKS; c.clk_sys_resus_ctrl() .write_value(pac::clocks::regs::ClkSysResusCtrl(0)); - // start XOSC - start_xosc(); - // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. c.clk_sys_ctrl().modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); while c.clk_sys_selected().read() != 1 {} c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); while c.clk_ref_selected().read() != 1 {} - // Configure PLLs - // REF FBDIV VCO POSTDIV - // PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz - // PLL USB: 12 / 1 = 12MHz * 40 = 480 MHz / 5 / 2 = 48MHz - configure_pll(pac::PLL_SYS, 1, 1500_000_000, 6, 2); - configure_pll(pac::PLL_USB, 1, 480_000_000, 5, 2); + if let Some(config) = config.rosc_config { + configure_rosc(config); + } - // CLK_REF = XOSC (12MHz) / 1 = 12MHz2Mhz - c.clk_ref_ctrl().write(|w| { - w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC); - }); - while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {} - c.clk_ref_div().write(|w| w.set_int(1)); + if let Some(config) = config.xosc_config { + EXTERNAL_HZ = config.hz; - // CLK SYS = PLL SYS (125MHz) / 1 = 125MHz - 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_div().write(|w| w.set_int(1)); - c.clk_sys_ctrl().write(|w| { - w.set_auxsrc(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS); - w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); - }); - while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {} + pac::WATCHDOG.tick().write(|w| { + w.set_cycles((config.hz / 1_000_000) as u16); + w.set_enable(true); + }); - // CLK USB = PLL USB (48MHz) / 1 = 48MHz - c.clk_usb_div().write(|w| w.set_int(1)); - c.clk_usb_ctrl().write(|w| { + // 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!(), + } + + if let Some(sys_pll_config) = config.sys_pll { + configure_pll(pac::PLL_SYS, config.hz, sys_pll_config); + } + if let Some(usb_pll_config) = config.usb_pll { + configure_pll(pac::PLL_USB, config.hz, usb_pll_config); + } + } + + let (src, div) = config.ref_clk_config; + match 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 {} + c.clk_ref_div().write(|w| w.set_int(div)); + } + 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 {} + c.clk_ref_div().write(|w| w.set_int(div)); + } + 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_div().write(|w| w.set_int(div)); + } + } + + pac::WATCHDOG.tick().write(|w| { + w.set_cycles((clk_ref_freq() / 1_000_000) as u16); w.set_enable(true); - w.set_auxsrc(ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB); }); - // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz - c.clk_adc_div().write(|w| w.set_int(1)); - c.clk_adc_ctrl().write(|w| { - w.set_enable(true); - w.set_auxsrc(ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB); - }); + let (src, div) = config.sys_clk_config; + match 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 {} + c.clk_sys_div().write(|w| w.set_int(div)); + } + 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 {} - // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz - c.clk_rtc_ctrl().modify(|w| { - w.set_enable(false); - }); - c.clk_rtc_div().write(|w| w.set_int(1024)); - c.clk_rtc_ctrl().write(|w| { - w.set_enable(true); - w.set_auxsrc(ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB); - }); + c.clk_sys_div().write(|w| w.set_int(div)); + 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 {} + } + } - // CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable - // Normally choose clk_sys or clk_usb - c.clk_peri_ctrl().write(|w| { - w.set_enable(true); - w.set_auxsrc(ClkPeriCtrlAuxsrc::CLK_SYS); - }); + let mut peris = reset::ALL_PERIPHERALS; + + if let Some(src) = config.peri_clk_src { + c.clk_peri_ctrl().write(|w| { + w.set_enable(true); + w.set_auxsrc(src); + }); + } else { + peris.set_spi0(false); + peris.set_spi1(false); + peris.set_uart0(false); + peris.set_uart1(false); + } + + if let Some((src, div)) = config.usb_clk_config { + // CLK USB = PLL USB (48MHz) / 1 = 48MHz + c.clk_usb_div().write(|w| w.set_int(div)); + c.clk_usb_ctrl().write(|w| { + w.set_enable(true); + w.set_auxsrc(src); + }); + } else { + peris.set_usbctrl(false); + } + + if let Some((src, div)) = config.adc_clk_config { + // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz + c.clk_adc_div().write(|w| w.set_int(div)); + c.clk_adc_ctrl().write(|w| { + w.set_enable(true); + w.set_auxsrc(src); + }); + } else { + peris.set_adc(false); + } + + if let Some((src, div)) = config.rtc_clk_config { + // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz + c.clk_rtc_ctrl().modify(|w| { + w.set_enable(false); + }); + c.clk_rtc_div().write(|w| w.set_int(div)); + c.clk_rtc_ctrl().write(|w| { + w.set_enable(true); + w.set_auxsrc(src); + }); + } else { + peris.set_rtc(false); + } // Peripheral clocks should now all be running - let peris = reset::ALL_PERIPHERALS; reset::unreset_wait(peris); } -pub(crate) fn _clk_sys_freq() -> u32 { - 125_000_000 +unsafe fn configure_rosc(config: RoscConfig) { + let p = pac::ROSC; + + p.freqa().write(|w| { + w.set_passwd(pac::rosc::vals::Passwd::PASS); + w.set_ds0(config.drive_strength_0); + w.set_ds1(config.drive_strength_1); + w.set_ds2(config.drive_strength_2); + w.set_ds3(config.drive_strength_3); + }); + + p.freqb().write(|w| { + w.set_passwd(pac::rosc::vals::Passwd::PASS); + w.set_ds4(config.drive_strength_4); + w.set_ds5(config.drive_strength_5); + w.set_ds6(config.drive_strength_6); + w.set_ds7(config.drive_strength_7); + }); + + p.div().write(|w| { + w.set_div(pac::rosc::vals::Div(config.div + pac::rosc::vals::Div::PASS.0)); + }); + + p.ctrl().write(|w| { + w.set_enable(pac::rosc::vals::Enable::ENABLE); + w.set_freq_range(config.range); + }); +} + +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(crate) 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 => clk_sys_pll_freq(), + ClkSysCtrlAuxsrc::CLKSRC_PLL_USB => clk_usb_pll_freq(), + ClkSysCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), + ClkSysCtrlAuxsrc::XOSC_CLKSRC => unsafe { EXTERNAL_HZ }, + // TODO not sure how to handle clkin sources + _ => todo!(), + } + } + _ => 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 +} + +pub(crate) fn clk_sys_pll_freq() -> u32 { + let p = pac::PLL_SYS; + + let input_freq = unsafe { EXTERNAL_HZ }; + 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 +} + +pub(crate) fn clk_usb_pll_freq() -> u32 { + let p = pac::PLL_USB; + + let input_freq = unsafe { EXTERNAL_HZ }; + 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 } pub(crate) fn clk_peri_freq() -> u32 { - 125_000_000 + 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 => clk_sys_pll_freq(), + ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), + ClkPeriCtrlAuxsrc::XOSC_CLKSRC => unsafe { EXTERNAL_HZ }, + // TODO not sure how to handle clkin sources + _ => todo!(), + } +} + +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 => unsafe { EXTERNAL_HZ }, + ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX => todo!(), + _ => unreachable!(), + }; + + let mut div = unsafe { c.clk_ref_div().read().int() } as u32; + if div == 0 { + div = 4; + } + + base / div } pub(crate) fn clk_rtc_freq() -> u32 { - 46875 + let c = pac::CLOCKS; + let src = unsafe { c.clk_rtc_ctrl().read().auxsrc() }; + + let base = match src { + ClkRtcCtrlAuxsrc::XOSC_CLKSRC => unsafe { EXTERNAL_HZ }, + ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), + ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB => clk_usb_pll_freq(), + ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS => clk_sys_pll_freq(), + // TODO not sure how to handle clkin sources + _ => todo!(), + }; + + 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 } -unsafe fn start_xosc() { - const XOSC_MHZ: u32 = 12; +unsafe fn start_xosc(crystal_hz: u32) { pac::XOSC .ctrl() .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); - let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256; + let startup_delay = ((crystal_hz / 1000) + 128) / 256; pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); pac::XOSC.ctrl().write(|w| { w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); @@ -141,24 +470,24 @@ unsafe fn start_xosc() { while !pac::XOSC.status().read().stable() {} } -unsafe fn configure_pll(p: pac::pll::Pll, refdiv: u32, vco_freq: u32, post_div1: u8, post_div2: u8) { - let ref_freq = XOSC_MHZ * 1_000_000 / refdiv; +unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { + let ref_freq = input_freq / config.refdiv; - let fbdiv = vco_freq / ref_freq; + let fbdiv = config.vco_freq / ref_freq; assert!(fbdiv >= 16 && fbdiv <= 320); - assert!(post_div1 >= 1 && post_div1 <= 7); - assert!(post_div2 >= 1 && post_div2 <= 7); - assert!(post_div2 <= post_div1); - assert!(ref_freq <= (vco_freq / 16)); + 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)); // 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() == refdiv as u8 + && cs.refdiv() == config.refdiv as u8 && p.fbdiv_int().read().fbdiv_int() == fbdiv as u16 - && prim.postdiv1() == post_div1 - && prim.postdiv2() == post_div2 + && prim.postdiv1() == config.post_div1 + && prim.postdiv2() == config.post_div2 { return; } @@ -174,7 +503,7 @@ unsafe fn configure_pll(p: pac::pll::Pll, refdiv: u32, vco_freq: u32, post_div1: reset::unreset_wait(peris); // Load VCO-related dividers before starting VCO - p.cs().write(|w| w.set_refdiv(refdiv as _)); + p.cs().write(|w| w.set_refdiv(config.refdiv as _)); p.fbdiv_int().write(|w| w.set_fbdiv_int(fbdiv as _)); // Turn on PLL @@ -189,8 +518,8 @@ unsafe fn configure_pll(p: pac::pll::Pll, refdiv: u32, vco_freq: u32, post_div1: // Wait for PLL to lock p.prim().write(|w| { - w.set_postdiv1(post_div1); - w.set_postdiv2(post_div2); + w.set_postdiv1(config.post_div1); + w.set_postdiv2(config.post_div2); }); // Turn on post divider diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index cba7559d..118ce523 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -136,23 +136,35 @@ embassy_hal_common::peripherals! { static BOOT2: [u8; 256] = *include_bytes!("boot2.bin"); pub mod config { + use crate::clocks::ClockConfig; + #[non_exhaustive] - pub struct Config {} + pub struct Config { + pub clocks: ClockConfig, + } impl Default for Config { fn default() -> Self { - Self {} + Self { + clocks: ClockConfig::crystal(12_000_000), + } + } + } + + impl Config { + pub fn new(clocks: ClockConfig) -> Self { + Self { clocks } } } } -pub fn init(_config: config::Config) -> Peripherals { +pub fn init(config: config::Config) -> Peripherals { // Do this first, so that it panics if user is calling `init` a second time // before doing anything important. let peripherals = Peripherals::take(); unsafe { - clocks::init(); + clocks::init(config.clocks); #[cfg(feature = "time-driver")] timer::init(); dma::init(); From 59132514cfd04709bffb119642baf9d0dcf4733a Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 8 May 2023 09:43:58 -0400 Subject: [PATCH 2/7] Add missing functions, Cleanup, Gpout example --- embassy-rp/src/clocks.rs | 299 ++++++++++++++++++++++++++--------- examples/rp/src/bin/gpout.rs | 21 +++ 2 files changed, 247 insertions(+), 73 deletions(-) create mode 100644 examples/rp/src/bin/gpout.rs diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 4ae967aa..5d344444 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -2,7 +2,8 @@ use pac::clocks::vals::*; use crate::{pac, reset}; -static mut EXTERNAL_HZ: u32 = 0; +// TODO fix terrible use of global here +static mut XIN_HZ: u32 = 0; pub struct ClockConfig { rosc_config: Option, @@ -49,7 +50,7 @@ impl ClockConfig { ref_clk_config: (RefClkSrc::Xosc, 1), sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS), 1), peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS), - usb_clk_config: Some((ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS, 1)), + usb_clk_config: Some((ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, 1)), adc_clk_config: Some((ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, 1)), rtc_clk_config: Some((ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, 1024)), } @@ -164,7 +165,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { } if let Some(config) = config.xosc_config { - EXTERNAL_HZ = config.hz; + XIN_HZ = config.hz; pac::WATCHDOG.tick().write(|w| { w.set_cycles((config.hz / 1_000_000) as u16); @@ -343,22 +344,64 @@ pub fn estimate_rosc_freq() -> u32 { base / div } -pub(crate) fn clk_sys_freq() -> u32 { +pub fn xosc_freq() -> u32 { + unsafe { XIN_HZ } +} + +pub fn gpin0_freq() -> u32 { + todo!() +} +pub fn gpin1_freq() -> u32 { + todo!() +} + +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 +} + +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 +} + +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 => clk_sys_pll_freq(), - ClkSysCtrlAuxsrc::CLKSRC_PLL_USB => clk_usb_pll_freq(), - ClkSysCtrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), - ClkSysCtrlAuxsrc::XOSC_CLKSRC => unsafe { EXTERNAL_HZ }, - // TODO not sure how to handle clkin sources - _ => todo!(), - } - } + 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!(), }; @@ -370,82 +413,96 @@ pub(crate) fn clk_sys_freq() -> u32 { base / int } -pub(crate) fn clk_sys_pll_freq() -> u32 { - let p = pac::PLL_SYS; - - let input_freq = unsafe { EXTERNAL_HZ }; - 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 -} - -pub(crate) fn clk_usb_pll_freq() -> u32 { - let p = pac::PLL_USB; - - let input_freq = unsafe { EXTERNAL_HZ }; - 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 -} - -pub(crate) 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 => clk_sys_pll_freq(), - ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), - ClkPeriCtrlAuxsrc::XOSC_CLKSRC => unsafe { EXTERNAL_HZ }, - // TODO not sure how to handle clkin sources - _ => todo!(), - } -} - 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 => unsafe { EXTERNAL_HZ }, - ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX => todo!(), + 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 mut div = unsafe { c.clk_ref_div().read().int() } as u32; - if div == 0 { - div = 4; - } + let div = unsafe { c.clk_ref_div().read() }; + let int = if div.int() == 0 { 4 } else { div.int() as u32 }; - base / div + base / int } -pub(crate) fn clk_rtc_freq() -> u32 { +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!(), + } +} + +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 +} + +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 +} + +pub fn clk_rtc_freq() -> u32 { let c = pac::CLOCKS; let src = unsafe { c.clk_rtc_ctrl().read().auxsrc() }; let base = match src { - ClkRtcCtrlAuxsrc::XOSC_CLKSRC => unsafe { EXTERNAL_HZ }, + ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), + ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH => estimate_rosc_freq(), - ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB => clk_usb_pll_freq(), - ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS => clk_sys_pll_freq(), - // TODO not sure how to handle clkin sources - _ => todo!(), + ClkRtcCtrlAuxsrc::XOSC_CLKSRC => xosc_freq(), + ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), + ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), + _ => unreachable!(), }; let div = unsafe { c.clk_rtc_div().read() }; @@ -456,6 +513,60 @@ pub(crate) fn clk_rtc_freq() -> u32 { base / int } +pub fn clk_gpout0_freq() -> u32 { + let c = pac::CLOCKS; + let src = unsafe { c.clk_gpout0_ctrl().read().auxsrc() }; + + let base = match src { + ClkGpout0ctrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), + ClkGpout0ctrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), + ClkGpout0ctrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), + ClkGpout0ctrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), + ClkGpout0ctrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), + ClkGpout0ctrlAuxsrc::XOSC_CLKSRC => xosc_freq(), + ClkGpout0ctrlAuxsrc::CLK_SYS => clk_sys_freq(), + ClkGpout0ctrlAuxsrc::CLK_USB => clk_usb_freq(), + ClkGpout0ctrlAuxsrc::CLK_ADC => clk_adc_freq(), + ClkGpout0ctrlAuxsrc::CLK_RTC => clk_rtc_freq(), + ClkGpout0ctrlAuxsrc::CLK_REF => clk_ref_freq(), + _ => unreachable!(), + }; + + let div = unsafe { c.clk_gpout0_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_gpout1_freq() -> u32 { + let c = pac::CLOCKS; + let src = unsafe { c.clk_gpout1_ctrl().read().auxsrc() }; + + let base = match src { + ClkGpout1ctrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), + ClkGpout1ctrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), + ClkGpout1ctrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), + ClkGpout1ctrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), + ClkGpout1ctrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), + ClkGpout1ctrlAuxsrc::XOSC_CLKSRC => xosc_freq(), + ClkGpout1ctrlAuxsrc::CLK_SYS => clk_sys_freq(), + ClkGpout1ctrlAuxsrc::CLK_USB => clk_usb_freq(), + ClkGpout1ctrlAuxsrc::CLK_ADC => clk_adc_freq(), + ClkGpout1ctrlAuxsrc::CLK_RTC => clk_rtc_freq(), + ClkGpout1ctrlAuxsrc::CLK_REF => clk_ref_freq(), + _ => unreachable!(), + }; + + let div = unsafe { c.clk_gpout1_div().read() }; + let int = if div.int() == 0 { 65536 } else { div.int() }; + // TODO handle fractional clock div + let _frac = div.frac(); + + base / int +} + unsafe fn start_xosc(crystal_hz: u32) { pac::XOSC .ctrl() @@ -526,6 +637,48 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { p.pwr().modify(|w| w.set_postdivpd(false)); } +pub struct Gpout0 { + _pin: crate::peripherals::PIN_21, +} + +impl Gpout0 { + pub fn new(pin: crate::peripherals::PIN_21) -> Self { + unsafe { + let p = pac::IO_BANK0.gpio(21).ctrl(); + p.write(|w| w.set_funcsel(pac::io::vals::Gpio21ctrlFuncsel::CLOCKS_GPOUT_0.0)) + } + Self { _pin: pin } + } + + pub fn set_div(&self, int: u32, frac: u8) { + unsafe { + let c = pac::CLOCKS; + c.clk_gpout0_div().write(|w| { + w.set_int(int); + w.set_frac(frac); + }); + } + } + + pub fn set_src(&self, src: ClkGpout0ctrlAuxsrc) { + unsafe { + let c = pac::CLOCKS; + c.clk_gpout0_ctrl().modify(|w| { + w.set_auxsrc(src); + }); + } + } + + pub fn enable(&self) { + unsafe { + let c = pac::CLOCKS; + c.clk_gpout0_ctrl().modify(|w| { + w.set_enable(true); + }); + } + } +} + /// Random number generator based on the ROSC RANDOMBIT register. /// /// This will not produce random values if the ROSC is stopped or run at some diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs new file mode 100644 index 00000000..0503212e --- /dev/null +++ b/examples/rp/src/bin/gpout.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::{clocks, pac}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + //let mut led = Output::new(p.PIN_25, Level::Low); + + let gpout0 = clocks::Gpout0::new(p.PIN_21); + gpout0.set_src(pac::clocks::vals::ClkGpout0ctrlAuxsrc::CLK_SYS); + gpout0.set_div(1000, 0); + gpout0.enable(); + + info!("Pin 21 should be toggling at {} hz", clocks::clk_gpout0_freq()); +} From 14eecf2fc44d9894e7e053280f771a0e98c255ef Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 8 May 2023 19:13:50 -0400 Subject: [PATCH 3/7] Address Dirbaio comments Gpout still incomplete. --- embassy-rp/src/clocks.rs | 241 ++++++++++++++++++++++++--------------- 1 file changed, 147 insertions(+), 94 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 5d344444..def34fc7 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -6,32 +6,25 @@ use crate::{pac, reset}; static mut XIN_HZ: u32 = 0; pub struct ClockConfig { - rosc_config: Option, - xosc_config: Option, - ref_clk_config: (RefClkSrc, u8), - sys_clk_config: (SysClkSrc, u32), + rosc: Option, + xosc: Option, + ref_clk: RefClkConfig, + sys_clk: SysClkConfig, peri_clk_src: Option, - usb_clk_config: Option<(ClkUsbCtrlAuxsrc, u8)>, - adc_clk_config: Option<(ClkAdcCtrlAuxsrc, u8)>, - rtc_clk_config: Option<(ClkRtcCtrlAuxsrc, u32)>, + usb_clk: Option, + adc_clk: Option, + rtc_clk: Option, } impl ClockConfig { pub fn crystal(crystal_hz: u32) -> Self { Self { - rosc_config: Some(RoscConfig { + rosc: Some(RoscConfig { range: pac::rosc::vals::FreqRange::MEDIUM, - drive_strength_0: 0, - drive_strength_1: 0, - drive_strength_2: 0, - drive_strength_3: 0, - drive_strength_4: 0, - drive_strength_5: 0, - drive_strength_6: 0, - drive_strength_7: 0, + drive_strength: [0; 8], div: 16, }), - xosc_config: Some(XoscConfig { + xosc: Some(XoscConfig { hz: crystal_hz, clock_type: ExternalClock::Crystal, sys_pll: Some(PllConfig { @@ -47,42 +40,68 @@ impl ClockConfig { post_div2: 2, }), }), - ref_clk_config: (RefClkSrc::Xosc, 1), - sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS), 1), + ref_clk: RefClkConfig { + src: RefClkSrc::Xosc, + div: 1, + }, + sys_clk: SysClkConfig { + src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS), + div_int: 1, + div_frac: 0, + }, peri_clk_src: Some(ClkPeriCtrlAuxsrc::CLK_SYS), - usb_clk_config: Some((ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, 1)), - adc_clk_config: Some((ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, 1)), - rtc_clk_config: Some((ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, 1024)), + usb_clk: Some(UsbClkConfig { + src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, + div: 1, + }), + adc_clk: Some(AdcClkConfig { + src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, + div: 1, + }), + rtc_clk: Some(RtcClkConfig { + src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, + div_int: 1024, + div_frac: 0, + }), } } pub fn rosc() -> Self { Self { - rosc_config: Some(RoscConfig { + rosc: Some(RoscConfig { range: pac::rosc::vals::FreqRange::HIGH, - drive_strength_0: 0, - drive_strength_1: 0, - drive_strength_2: 0, - drive_strength_3: 0, - drive_strength_4: 0, - drive_strength_5: 0, - drive_strength_6: 0, - drive_strength_7: 0, + drive_strength: [0; 8], div: 1, }), - xosc_config: None, - ref_clk_config: (RefClkSrc::Rosc, 4), - sys_clk_config: (SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC), 1), + xosc: None, + ref_clk: RefClkConfig { + src: RefClkSrc::Rosc, + div: 1, + }, + sys_clk: SysClkConfig { + src: SysClkSrc::Aux(ClkSysCtrlAuxsrc::ROSC_CLKSRC), + div_int: 1, + div_frac: 0, + }, peri_clk_src: Some(ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH), - usb_clk_config: None, - adc_clk_config: Some((ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, 1)), - rtc_clk_config: Some((ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, 1024)), + usb_clk: None, + adc_clk: Some(AdcClkConfig { + src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, + div: 1, + }), + rtc_clk: Some(RtcClkConfig { + src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, + div_int: 1024, + div_frac: 0, + }), } } } -pub enum ExternalClock { - Crystal, - Clock, + +pub struct RoscConfig { + range: pac::rosc::vals::FreqRange, + drive_strength: [u8; 8], + div: u16, } pub struct XoscConfig { @@ -92,19 +111,6 @@ pub struct XoscConfig { usb_pll: Option, } -pub struct RoscConfig { - range: pac::rosc::vals::FreqRange, - drive_strength_0: u8, - drive_strength_1: u8, - drive_strength_2: u8, - drive_strength_3: u8, - drive_strength_4: u8, - drive_strength_5: u8, - drive_strength_6: u8, - drive_strength_7: u8, - div: u16, -} - pub struct PllConfig { pub refdiv: u32, pub vco_freq: u32, @@ -112,9 +118,13 @@ pub struct PllConfig { pub post_div2: u8, } +pub enum ExternalClock { + Crystal, + Clock, +} pub struct RefClkConfig { - pub src: RefClkSrc, - pub div: u8, + src: RefClkSrc, + div: u8, } pub enum RefClkSrc { @@ -123,16 +133,33 @@ pub enum RefClkSrc { Aux(ClkRefCtrlAuxsrc), } -pub struct SysClkConfig { - pub src: SysClkSrc, - pub div: u32, -} - pub enum SysClkSrc { Ref, Aux(ClkSysCtrlAuxsrc), } +pub struct SysClkConfig { + src: SysClkSrc, + div_int: u32, + div_frac: u8, +} + +pub struct UsbClkConfig { + src: ClkUsbCtrlAuxsrc, + div: u8, +} + +pub struct AdcClkConfig { + src: ClkAdcCtrlAuxsrc, + div: u8, +} + +pub struct RtcClkConfig { + src: ClkRtcCtrlAuxsrc, + div_int: u32, + div_frac: u8, +} + /// safety: must be called exactly once at bootup pub(crate) unsafe fn init(config: ClockConfig) { // Reset everything except: @@ -160,11 +187,11 @@ 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 {} - if let Some(config) = config.rosc_config { + if let Some(config) = config.rosc { configure_rosc(config); } - if let Some(config) = config.xosc_config { + if let Some(config) = config.xosc { XIN_HZ = config.hz; pac::WATCHDOG.tick().write(|w| { @@ -188,21 +215,18 @@ pub(crate) unsafe fn init(config: ClockConfig) { } } - let (src, div) = config.ref_clk_config; - match src { + 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 {} - c.clk_ref_div().write(|w| w.set_int(div)); } 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 {} - c.clk_ref_div().write(|w| w.set_int(div)); } RefClkSrc::Aux(src) => { c.clk_ref_ctrl().write(|w| { @@ -210,23 +234,23 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_src(ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX); }); while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::CLKSRC_CLK_REF_AUX.0 {} - c.clk_ref_div().write(|w| w.set_int(div)); } } + c.clk_ref_div().write(|w| { + w.set_int(config.ref_clk.div); + }); pac::WATCHDOG.tick().write(|w| { w.set_cycles((clk_ref_freq() / 1_000_000) as u16); w.set_enable(true); }); - let (src, div) = config.sys_clk_config; - match src { + 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 {} - c.clk_sys_div().write(|w| w.set_int(div)); } SysClkSrc::Aux(src) => { c.clk_sys_ctrl().write(|w| { @@ -234,7 +258,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { }); while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} - c.clk_sys_div().write(|w| w.set_int(div)); c.clk_sys_ctrl().write(|w| { w.set_auxsrc(src); w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); @@ -242,6 +265,10 @@ pub(crate) unsafe fn init(config: ClockConfig) { while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {} } } + c.clk_sys_div().write(|w| { + w.set_int(config.sys_clk.div_int); + w.set_frac(config.sys_clk.div_frac); + }); let mut peris = reset::ALL_PERIPHERALS; @@ -257,37 +284,40 @@ pub(crate) unsafe fn init(config: ClockConfig) { peris.set_uart1(false); } - if let Some((src, div)) = config.usb_clk_config { + if let Some(conf) = config.usb_clk { // CLK USB = PLL USB (48MHz) / 1 = 48MHz - c.clk_usb_div().write(|w| w.set_int(div)); + c.clk_usb_div().write(|w| w.set_int(conf.div)); c.clk_usb_ctrl().write(|w| { w.set_enable(true); - w.set_auxsrc(src); + w.set_auxsrc(conf.src); }); } else { peris.set_usbctrl(false); } - if let Some((src, div)) = config.adc_clk_config { + if let Some(conf) = config.adc_clk { // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz - c.clk_adc_div().write(|w| w.set_int(div)); + c.clk_adc_div().write(|w| w.set_int(conf.div)); c.clk_adc_ctrl().write(|w| { w.set_enable(true); - w.set_auxsrc(src); + w.set_auxsrc(conf.src); }); } else { peris.set_adc(false); } - if let Some((src, div)) = config.rtc_clk_config { + if let Some(conf) = config.rtc_clk { // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz c.clk_rtc_ctrl().modify(|w| { w.set_enable(false); }); - c.clk_rtc_div().write(|w| w.set_int(div)); + c.clk_rtc_div().write(|w| { + w.set_int(conf.div_int); + w.set_frac(conf.div_frac); + }); c.clk_rtc_ctrl().write(|w| { w.set_enable(true); - w.set_auxsrc(src); + w.set_auxsrc(conf.src); }); } else { peris.set_rtc(false); @@ -302,18 +332,18 @@ unsafe fn configure_rosc(config: RoscConfig) { p.freqa().write(|w| { w.set_passwd(pac::rosc::vals::Passwd::PASS); - w.set_ds0(config.drive_strength_0); - w.set_ds1(config.drive_strength_1); - w.set_ds2(config.drive_strength_2); - w.set_ds3(config.drive_strength_3); + w.set_ds0(config.drive_strength[0]); + w.set_ds1(config.drive_strength[1]); + w.set_ds2(config.drive_strength[2]); + w.set_ds3(config.drive_strength[3]); }); p.freqb().write(|w| { w.set_passwd(pac::rosc::vals::Passwd::PASS); - w.set_ds4(config.drive_strength_4); - w.set_ds5(config.drive_strength_5); - w.set_ds6(config.drive_strength_6); - w.set_ds7(config.drive_strength_7); + w.set_ds4(config.drive_strength[4]); + w.set_ds5(config.drive_strength[5]); + w.set_ds6(config.drive_strength[6]); + w.set_ds7(config.drive_strength[7]); }); p.div().write(|w| { @@ -637,17 +667,31 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { p.pwr().modify(|w| w.set_postdivpd(false)); } -pub struct Gpout0 { - _pin: crate::peripherals::PIN_21, +pub trait GpoutPin {} + +impl GpoutPin for crate::peripherals::PIN_21 {} +impl GpoutPin for crate::peripherals::PIN_23 {} +impl GpoutPin for crate::peripherals::PIN_24 {} +impl GpoutPin for crate::peripherals::PIN_25 {} + +use embassy_hal_common::{into_ref, PeripheralRef}; + +use crate::Peripheral; + +pub struct Gpout<'d, T: GpoutPin> { + _pin: PeripheralRef<'d, T>, } -impl Gpout0 { - pub fn new(pin: crate::peripherals::PIN_21) -> Self { +impl<'d, T: GpoutPin> Gpout<'d, T> { + pub fn new(_pin: impl Peripheral

+ 'd) -> Self { + into_ref!(_pin); + unsafe { let p = pac::IO_BANK0.gpio(21).ctrl(); - p.write(|w| w.set_funcsel(pac::io::vals::Gpio21ctrlFuncsel::CLOCKS_GPOUT_0.0)) + p.write(|w| w.set_funcsel(pac::io::vals::Gpio21ctrlFuncsel::CLOCKS_GPOUT_0.0)); } - Self { _pin: pin } + + Self { _pin } } pub fn set_div(&self, int: u32, frac: u8) { @@ -677,6 +721,15 @@ impl Gpout0 { }); } } + + pub fn disable(&self) { + unsafe { + let c = pac::CLOCKS; + c.clk_gpout0_ctrl().modify(|w| { + w.set_enable(true); + }); + } + } } /// Random number generator based on the ROSC RANDOMBIT register. From c1eaad41f30d0b712b94e05f62dc7bb90fe8cc6d Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 9 May 2023 11:46:25 -0400 Subject: [PATCH 4/7] Gpout cleanup, basic Gpin support Requires rp-pac #3 --- embassy-rp/Cargo.toml | 5 +- embassy-rp/src/clocks.rs | 162 ++++++++++++++++++++++++--------------- 2 files changed, 106 insertions(+), 61 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 59d0bf33..0d0e6fff 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -61,7 +61,7 @@ embedded-storage = { version = "0.3" } rand_core = "0.6.4" fixed = "1.23.1" -rp-pac = { version = "2", features = ["rt"] } +rp-pac = { version = "3", features = ["rt"] } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} @@ -71,3 +71,6 @@ embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} paste = "1.0" pio-proc = {version= "0.2" } pio = {version= "0.2.1" } + +[patch.crates-io] +rp-pac = {git = "https://github.com/CBJamo/rp-pac.git"} diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index def34fc7..743a3fd5 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1,6 +1,7 @@ +use embassy_hal_common::{into_ref, PeripheralRef}; use pac::clocks::vals::*; -use crate::{pac, reset}; +use crate::{pac, reset, Peripheral}; // TODO fix terrible use of global here static mut XIN_HZ: u32 = 0; @@ -543,53 +544,26 @@ pub fn clk_rtc_freq() -> u32 { base / int } -pub fn clk_gpout0_freq() -> u32 { +pub fn clk_gpout_freq(num: usize) -> u32 { let c = pac::CLOCKS; - let src = unsafe { c.clk_gpout0_ctrl().read().auxsrc() }; + let src = unsafe { c.clk_gpout_ctrl(num).read().auxsrc() }; let base = match src { - ClkGpout0ctrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkGpout0ctrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkGpout0ctrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - ClkGpout0ctrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkGpout0ctrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), - ClkGpout0ctrlAuxsrc::XOSC_CLKSRC => xosc_freq(), - ClkGpout0ctrlAuxsrc::CLK_SYS => clk_sys_freq(), - ClkGpout0ctrlAuxsrc::CLK_USB => clk_usb_freq(), - ClkGpout0ctrlAuxsrc::CLK_ADC => clk_adc_freq(), - ClkGpout0ctrlAuxsrc::CLK_RTC => clk_rtc_freq(), - ClkGpout0ctrlAuxsrc::CLK_REF => clk_ref_freq(), + ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), + ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), + ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), + ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), + ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => estimate_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_REF => clk_ref_freq(), _ => unreachable!(), }; - let div = unsafe { c.clk_gpout0_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_gpout1_freq() -> u32 { - let c = pac::CLOCKS; - let src = unsafe { c.clk_gpout1_ctrl().read().auxsrc() }; - - let base = match src { - ClkGpout1ctrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkGpout1ctrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkGpout1ctrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - ClkGpout1ctrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkGpout1ctrlAuxsrc::ROSC_CLKSRC => estimate_rosc_freq(), - ClkGpout1ctrlAuxsrc::XOSC_CLKSRC => xosc_freq(), - ClkGpout1ctrlAuxsrc::CLK_SYS => clk_sys_freq(), - ClkGpout1ctrlAuxsrc::CLK_USB => clk_usb_freq(), - ClkGpout1ctrlAuxsrc::CLK_ADC => clk_adc_freq(), - ClkGpout1ctrlAuxsrc::CLK_RTC => clk_rtc_freq(), - ClkGpout1ctrlAuxsrc::CLK_REF => clk_ref_freq(), - _ => unreachable!(), - }; - - let div = unsafe { c.clk_gpout1_div().read() }; + let div = unsafe { c.clk_gpout_div(num).read() }; let int = if div.int() == 0 { 65536 } else { div.int() }; // TODO handle fractional clock div let _frac = div.frac(); @@ -667,47 +641,106 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { p.pwr().modify(|w| w.set_postdivpd(false)); } -pub trait GpoutPin {} +pub trait GpinPin { + fn gpin_number(&self) -> usize; + fn pin_number(&self) -> usize; +} -impl GpoutPin for crate::peripherals::PIN_21 {} -impl GpoutPin for crate::peripherals::PIN_23 {} -impl GpoutPin for crate::peripherals::PIN_24 {} -impl GpoutPin for crate::peripherals::PIN_25 {} +macro_rules! impl_gpinpin { + ($name:ident, $pin_num:expr, $gpin_num:expr) => { + impl GpinPin for crate::peripherals::$name { + fn gpin_number(&self) -> usize { + $gpin_num + } + fn pin_number(&self) -> usize { + $pin_num + } + } + }; +} -use embassy_hal_common::{into_ref, PeripheralRef}; +impl_gpinpin!(PIN_20, 20, 0); +impl_gpinpin!(PIN_22, 22, 1); -use crate::Peripheral; +pub struct Gpin<'d, T: GpinPin> { + gpout: PeripheralRef<'d, T>, +} + +impl<'d, T: GpinPin> Gpin<'d, T> { + pub fn new(gpout: impl Peripheral

+ 'd) -> Self { + into_ref!(gpout); + + unsafe { + let p = pac::IO_BANK0.gpio(gpout.pin_number()).ctrl(); + p.write(|w| w.set_funcsel(0x08)); + } + + Self { gpout } + } +} + +impl<'d, T: GpinPin> Drop for Gpin<'d, T> { + fn drop(&mut self) { + unsafe { + let p = pac::IO_BANK0.gpio(self.gpout.pin_number()).ctrl(); + p.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); + } + } +} + +pub trait GpoutPin { + fn gpout_number(&self) -> usize; + fn pin_number(&self) -> usize; +} + +macro_rules! impl_gpoutpin { + ($name:ident, $pin_num:expr, $gpout_num:expr) => { + impl GpoutPin for crate::peripherals::$name { + fn gpout_number(&self) -> usize { + $gpout_num + } + fn pin_number(&self) -> usize { + $pin_num + } + } + }; +} + +impl_gpoutpin!(PIN_21, 21, 0); +impl_gpoutpin!(PIN_23, 23, 1); +impl_gpoutpin!(PIN_24, 24, 2); +impl_gpoutpin!(PIN_25, 25, 3); pub struct Gpout<'d, T: GpoutPin> { - _pin: PeripheralRef<'d, T>, + gpout: PeripheralRef<'d, T>, } impl<'d, T: GpoutPin> Gpout<'d, T> { - pub fn new(_pin: impl Peripheral

+ 'd) -> Self { - into_ref!(_pin); + pub fn new(gpout: impl Peripheral

+ 'd) -> Self { + into_ref!(gpout); unsafe { - let p = pac::IO_BANK0.gpio(21).ctrl(); - p.write(|w| w.set_funcsel(pac::io::vals::Gpio21ctrlFuncsel::CLOCKS_GPOUT_0.0)); + let p = pac::IO_BANK0.gpio(gpout.pin_number()).ctrl(); + p.write(|w| w.set_funcsel(0x08)); } - Self { _pin } + Self { gpout } } pub fn set_div(&self, int: u32, frac: u8) { unsafe { let c = pac::CLOCKS; - c.clk_gpout0_div().write(|w| { + c.clk_gpout_div(self.gpout.gpout_number()).write(|w| { w.set_int(int); w.set_frac(frac); }); } } - pub fn set_src(&self, src: ClkGpout0ctrlAuxsrc) { + pub fn set_src(&self, src: ClkGpoutCtrlAuxsrc) { unsafe { let c = pac::CLOCKS; - c.clk_gpout0_ctrl().modify(|w| { + c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { w.set_auxsrc(src); }); } @@ -716,7 +749,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { pub fn enable(&self) { unsafe { let c = pac::CLOCKS; - c.clk_gpout0_ctrl().modify(|w| { + c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { w.set_enable(true); }); } @@ -725,13 +758,22 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { pub fn disable(&self) { unsafe { let c = pac::CLOCKS; - c.clk_gpout0_ctrl().modify(|w| { + c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { w.set_enable(true); }); } } } +impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { + fn drop(&mut self) { + unsafe { + let p = pac::IO_BANK0.gpio(self.gpout.pin_number()).ctrl(); + p.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); + } + } +} + /// Random number generator based on the ROSC RANDOMBIT register. /// /// This will not produce random values if the ROSC is stopped or run at some From 5015c845c59e8769d404dce5ca618cdf6fd16aeb Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 9 May 2023 12:10:24 -0400 Subject: [PATCH 5/7] Improve gpout example, clk_gpout_freq --- embassy-rp/src/clocks.rs | 8 ++++---- examples/rp/Cargo.toml | 3 +++ examples/rp/src/bin/gpout.rs | 25 +++++++++++++++++++------ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 743a3fd5..b919b98a 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -544,9 +544,9 @@ pub fn clk_rtc_freq() -> u32 { base / int } -pub fn clk_gpout_freq(num: usize) -> u32 { +pub fn clk_gpout_freq(gpout: &Gpout) -> u32 { let c = pac::CLOCKS; - let src = unsafe { c.clk_gpout_ctrl(num).read().auxsrc() }; + let src = unsafe { c.clk_gpout_ctrl(gpout.gpout.gpout_number()).read().auxsrc() }; let base = match src { ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), @@ -563,7 +563,7 @@ pub fn clk_gpout_freq(num: usize) -> u32 { _ => unreachable!(), }; - let div = unsafe { c.clk_gpout_div(num).read() }; + let div = unsafe { c.clk_gpout_div(gpout.gpout.gpout_number()).read() }; let int = if div.int() == 0 { 65536 } else { div.int() }; // TODO handle fractional clock div let _frac = div.frac(); @@ -759,7 +759,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { unsafe { let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { - w.set_enable(true); + w.set_enable(false); }); } } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index d2829df9..7d5473f2 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -48,3 +48,6 @@ pio = "0.2.1" [profile.release] debug = true + +[patch.crates-io] +rp-pac = {git = "https://github.com/CBJamo/rp-pac.git"} diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs index 0503212e..ea0efb85 100644 --- a/examples/rp/src/bin/gpout.rs +++ b/examples/rp/src/bin/gpout.rs @@ -5,17 +5,30 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::{clocks, pac}; +use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); - //let mut led = Output::new(p.PIN_25, Level::Low); - let gpout0 = clocks::Gpout0::new(p.PIN_21); - gpout0.set_src(pac::clocks::vals::ClkGpout0ctrlAuxsrc::CLK_SYS); - gpout0.set_div(1000, 0); - gpout0.enable(); + let gpout3 = clocks::Gpout::new(p.PIN_25); + gpout3.set_div(1000, 0); + gpout3.enable(); - info!("Pin 21 should be toggling at {} hz", clocks::clk_gpout0_freq()); + loop { + gpout3.set_src(pac::clocks::vals::ClkGpoutCtrlAuxsrc::CLK_SYS); + info!( + "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}", + clocks::clk_gpout_freq(&gpout3) + ); + Timer::after(Duration::from_secs(2)).await; + + gpout3.set_src(pac::clocks::vals::ClkGpoutCtrlAuxsrc::CLK_REF); + info!( + "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}", + clocks::clk_gpout_freq(&gpout3) + ); + Timer::after(Duration::from_secs(2)).await; + } } From 6bea07848717857659c737a3bb3eab7c2cd8abdb Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 9 May 2023 12:20:23 -0400 Subject: [PATCH 6/7] Remove patches, bump rp-pac version --- embassy-rp/Cargo.toml | 5 +---- examples/rp/Cargo.toml | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 0d0e6fff..a2eb6c58 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -61,7 +61,7 @@ embedded-storage = { version = "0.3" } rand_core = "0.6.4" fixed = "1.23.1" -rp-pac = { version = "3", features = ["rt"] } +rp-pac = { version = "4", features = ["rt"] } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} @@ -71,6 +71,3 @@ embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} paste = "1.0" pio-proc = {version= "0.2" } pio = {version= "0.2.1" } - -[patch.crates-io] -rp-pac = {git = "https://github.com/CBJamo/rp-pac.git"} diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 7d5473f2..d2829df9 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -48,6 +48,3 @@ pio = "0.2.1" [profile.release] debug = true - -[patch.crates-io] -rp-pac = {git = "https://github.com/CBJamo/rp-pac.git"} From 5cfe1a1fb40470dfaf256fc87989fd67884113f1 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 9 May 2023 17:45:24 -0400 Subject: [PATCH 7/7] Dirbaio comments round 2 --- embassy-rp/src/clocks.rs | 191 +++++++++++++++++++---------------- examples/rp/src/bin/gpout.rs | 10 +- 2 files changed, 107 insertions(+), 94 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index b919b98a..1354ccd2 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -6,15 +6,22 @@ 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, +}; + +#[non_exhaustive] pub struct ClockConfig { - rosc: Option, - xosc: Option, - ref_clk: RefClkConfig, - sys_clk: SysClkConfig, - peri_clk_src: Option, - usb_clk: Option, - adc_clk: Option, - rtc_clk: Option, + pub rosc: Option, + pub xosc: Option, + pub ref_clk: RefClkConfig, + pub sys_clk: SysClkConfig, + pub peri_clk_src: Option, + pub usb_clk: Option, + pub adc_clk: Option, + pub rtc_clk: Option, } impl ClockConfig { @@ -54,15 +61,18 @@ impl ClockConfig { usb_clk: Some(UsbClkConfig { src: ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB, div: 1, + phase: 0, }), adc_clk: Some(AdcClkConfig { src: ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB, div: 1, + phase: 0, }), rtc_clk: Some(RtcClkConfig { src: ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB, div_int: 1024, div_frac: 0, + phase: 0, }), } } @@ -89,27 +99,29 @@ impl ClockConfig { adc_clk: Some(AdcClkConfig { src: ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH, div: 1, + phase: 0, }), rtc_clk: Some(RtcClkConfig { src: ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH, div_int: 1024, div_frac: 0, + phase: 0, }), } } } pub struct RoscConfig { - range: pac::rosc::vals::FreqRange, - drive_strength: [u8; 8], - div: u16, + pub range: pac::rosc::vals::FreqRange, + pub drive_strength: [u8; 8], + pub div: u16, } pub struct XoscConfig { - hz: u32, - clock_type: ExternalClock, - sys_pll: Option, - usb_pll: Option, + pub hz: u32, + pub clock_type: ExternalClock, + pub sys_pll: Option, + pub usb_pll: Option, } pub struct PllConfig { @@ -124,8 +136,8 @@ pub enum ExternalClock { Clock, } pub struct RefClkConfig { - src: RefClkSrc, - div: u8, + pub src: RefClkSrc, + pub div: u8, } pub enum RefClkSrc { @@ -140,25 +152,28 @@ pub enum SysClkSrc { } pub struct SysClkConfig { - src: SysClkSrc, - div_int: u32, - div_frac: u8, + pub src: SysClkSrc, + pub div_int: u32, + pub div_frac: u8, } pub struct UsbClkConfig { - src: ClkUsbCtrlAuxsrc, - div: u8, + pub src: ClkUsbCtrlAuxsrc, + pub div: u8, + pub phase: u8, } pub struct AdcClkConfig { - src: ClkAdcCtrlAuxsrc, - div: u8, + pub src: ClkAdcCtrlAuxsrc, + pub div: u8, + pub phase: u8, } pub struct RtcClkConfig { - src: ClkRtcCtrlAuxsrc, - div_int: u32, - div_frac: u8, + pub src: ClkRtcCtrlAuxsrc, + pub div_int: u32, + pub div_frac: u8, + pub phase: u8, } /// safety: must be called exactly once at bootup @@ -289,6 +304,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { // 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); w.set_enable(true); w.set_auxsrc(conf.src); }); @@ -300,6 +316,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { // 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); w.set_enable(true); w.set_auxsrc(conf.src); }); @@ -317,6 +334,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_frac(conf.div_frac); }); c.clk_rtc_ctrl().write(|w| { + w.set_phase(conf.phase); w.set_enable(true); w.set_auxsrc(conf.src); }); @@ -544,33 +562,6 @@ pub fn clk_rtc_freq() -> u32 { base / int } -pub fn clk_gpout_freq(gpout: &Gpout) -> u32 { - let c = pac::CLOCKS; - let src = unsafe { c.clk_gpout_ctrl(gpout.gpout.gpout_number()).read().auxsrc() }; - - let base = match src { - ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), - ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), - ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), - ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), - ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => estimate_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_REF => clk_ref_freq(), - _ => unreachable!(), - }; - - let div = unsafe { c.clk_gpout_div(gpout.gpout.gpout_number()).read() }; - let int = if div.int() == 0 { 65536 } else { div.int() }; - // TODO handle fractional clock div - let _frac = div.frac(); - - base / int -} - unsafe fn start_xosc(crystal_hz: u32) { pac::XOSC .ctrl() @@ -641,20 +632,16 @@ unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) { p.pwr().modify(|w| w.set_postdivpd(false)); } -pub trait GpinPin { - fn gpin_number(&self) -> usize; - fn pin_number(&self) -> usize; +pub trait GpinPin: crate::gpio::Pin { + fn number(&self) -> usize; } macro_rules! impl_gpinpin { ($name:ident, $pin_num:expr, $gpin_num:expr) => { impl GpinPin for crate::peripherals::$name { - fn gpin_number(&self) -> usize { + fn number(&self) -> usize { $gpin_num } - fn pin_number(&self) -> usize { - $pin_num - } } }; } @@ -663,53 +650,50 @@ impl_gpinpin!(PIN_20, 20, 0); impl_gpinpin!(PIN_22, 22, 1); pub struct Gpin<'d, T: GpinPin> { - gpout: PeripheralRef<'d, T>, + gpin: PeripheralRef<'d, T>, } impl<'d, T: GpinPin> Gpin<'d, T> { - pub fn new(gpout: impl Peripheral

+ 'd) -> Self { - into_ref!(gpout); + pub fn new(gpin: impl Peripheral

+ 'd) -> Self { + into_ref!(gpin); unsafe { - let p = pac::IO_BANK0.gpio(gpout.pin_number()).ctrl(); - p.write(|w| w.set_funcsel(0x08)); + gpin.io().ctrl().write(|w| w.set_funcsel(0x08)); } - Self { gpout } + Self { gpin } } } impl<'d, T: GpinPin> Drop for Gpin<'d, T> { fn drop(&mut self) { unsafe { - let p = pac::IO_BANK0.gpio(self.gpout.pin_number()).ctrl(); - p.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); + self.gpin + .io() + .ctrl() + .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); } } } -pub trait GpoutPin { - fn gpout_number(&self) -> usize; - fn pin_number(&self) -> usize; +pub trait GpoutPin: crate::gpio::Pin { + fn number(&self) -> usize; } macro_rules! impl_gpoutpin { - ($name:ident, $pin_num:expr, $gpout_num:expr) => { + ($name:ident, $gpout_num:expr) => { impl GpoutPin for crate::peripherals::$name { - fn gpout_number(&self) -> usize { + fn number(&self) -> usize { $gpout_num } - fn pin_number(&self) -> usize { - $pin_num - } } }; } -impl_gpoutpin!(PIN_21, 21, 0); -impl_gpoutpin!(PIN_23, 23, 1); -impl_gpoutpin!(PIN_24, 24, 2); -impl_gpoutpin!(PIN_25, 25, 3); +impl_gpoutpin!(PIN_21, 0); +impl_gpoutpin!(PIN_23, 1); +impl_gpoutpin!(PIN_24, 2); +impl_gpoutpin!(PIN_25, 3); pub struct Gpout<'d, T: GpoutPin> { gpout: PeripheralRef<'d, T>, @@ -720,8 +704,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { into_ref!(gpout); unsafe { - let p = pac::IO_BANK0.gpio(gpout.pin_number()).ctrl(); - p.write(|w| w.set_funcsel(0x08)); + gpout.io().ctrl().write(|w| w.set_funcsel(0x08)); } Self { gpout } @@ -730,7 +713,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { pub fn set_div(&self, int: u32, frac: u8) { unsafe { let c = pac::CLOCKS; - c.clk_gpout_div(self.gpout.gpout_number()).write(|w| { + c.clk_gpout_div(self.gpout.number()).write(|w| { w.set_int(int); w.set_frac(frac); }); @@ -740,7 +723,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { pub fn set_src(&self, src: ClkGpoutCtrlAuxsrc) { unsafe { let c = pac::CLOCKS; - c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { + c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { w.set_auxsrc(src); }); } @@ -749,7 +732,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { pub fn enable(&self) { unsafe { let c = pac::CLOCKS; - c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { + c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { w.set_enable(true); }); } @@ -758,18 +741,48 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { pub fn disable(&self) { unsafe { let c = pac::CLOCKS; - c.clk_gpout_ctrl(self.gpout.gpout_number()).modify(|w| { + c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { w.set_enable(false); }); } } + + pub fn get_freq(&self) -> u32 { + let c = pac::CLOCKS; + let src = unsafe { c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc() }; + + let base = match src { + ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), + ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), + ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), + ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), + ClkGpoutCtrlAuxsrc::ROSC_CLKSRC => estimate_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_REF => clk_ref_freq(), + _ => unreachable!(), + }; + + 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(); + + base / int + } } impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { fn drop(&mut self) { + self.disable(); unsafe { - let p = pac::IO_BANK0.gpio(self.gpout.pin_number()).ctrl(); - p.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); + self.gpout + .io() + .ctrl() + .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); } } } diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs index ea0efb85..236a653a 100644 --- a/examples/rp/src/bin/gpout.rs +++ b/examples/rp/src/bin/gpout.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::{clocks, pac}; +use embassy_rp::clocks; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -17,17 +17,17 @@ async fn main(_spawner: Spawner) { gpout3.enable(); loop { - gpout3.set_src(pac::clocks::vals::ClkGpoutCtrlAuxsrc::CLK_SYS); + gpout3.set_src(clocks::GpoutSrc::CLK_SYS); info!( "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}", - clocks::clk_gpout_freq(&gpout3) + gpout3.get_freq() ); Timer::after(Duration::from_secs(2)).await; - gpout3.set_src(pac::clocks::vals::ClkGpoutCtrlAuxsrc::CLK_REF); + gpout3.set_src(clocks::GpoutSrc::CLK_REF); info!( "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}", - clocks::clk_gpout_freq(&gpout3) + gpout3.get_freq() ); Timer::after(Duration::from_secs(2)).await; }