From 4567beda7b7773c8cb11f19f0f4f146c1243508d Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sun, 11 May 2025 17:26:36 +0200 Subject: rp235x overclocking --- embassy-rp/src/clocks.rs | 329 ++++++++++++++++++++++++++++---- examples/rp/src/bin/overclock.rs | 8 +- examples/rp/src/bin/overclock_manual.rs | 10 +- examples/rp235x/src/bin/overclock.rs | 74 +++++++ tests/rp/src/bin/overclock.rs | 49 +++-- 5 files changed, 405 insertions(+), 65 deletions(-) create mode 100644 examples/rp235x/src/bin/overclock.rs diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 6694aab66..ea5e9362b 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -38,7 +38,7 @@ //! //! ## Examples //! -//! ### Standard 125MHz configuration +//! ### Standard 125MHz (rp2040) or 150Mhz (rp235x) configuration //! ```rust,ignore //! let config = ClockConfig::crystal(12_000_000); //! ``` @@ -136,43 +136,152 @@ pub enum PeriClkSrc { // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , } -/// Core voltage regulator settings for RP2040. +/// Core voltage regulator settings. /// -/// The RP2040 voltage regulator can be configured for different output voltages. +/// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. -#[cfg(feature = "rp2040")] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum CoreVoltage { - /// 0.80V - Suitable for lower frequencies + // RP2040 voltage levels + #[cfg(feature = "rp2040")] + /// RP2040: 0.80V V0_80 = 0b0000, - /// 0.85V + #[cfg(feature = "rp2040")] + /// RP2040: 0.85V V0_85 = 0b0110, - /// 0.90V + #[cfg(feature = "rp2040")] + /// RP2040: 0.90V V0_90 = 0b0111, - /// 0.95V + #[cfg(feature = "rp2040")] + /// RP2040: 0.95V V0_95 = 0b1000, - /// 1.00V + #[cfg(feature = "rp2040")] + /// RP2040: 1.00V V1_00 = 0b1001, - /// 1.05V + #[cfg(feature = "rp2040")] + /// RP2040: 1.05V V1_05 = 0b1010, - /// 1.10V - Default voltage level + #[cfg(feature = "rp2040")] + /// RP2040: 1.10V - Default voltage level V1_10 = 0b1011, - /// 1.15V - Required for overclocking to 133-200MHz + #[cfg(feature = "rp2040")] + /// RP2040: 1.15V - Required for overclocking to 133-200MHz V1_15 = 0b1100, - /// 1.20V + #[cfg(feature = "rp2040")] + /// RP2040: 1.20V V1_20 = 0b1101, - /// 1.25V + #[cfg(feature = "rp2040")] + /// RP2040: 1.25V V1_25 = 0b1110, - /// 1.30V + #[cfg(feature = "rp2040")] + /// RP2040: 1.30V V1_30 = 0b1111, + + // RP235x voltage levels + #[cfg(feature = "_rp235x")] + /// RP235x: 0.55V + V0_55 = 0b00000, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.60V + V0_60 = 0b00001, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.65V + V0_65 = 0b00010, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.70V + V0_70 = 0b00011, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.75V + V0_75 = 0b00100, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.80V + V0_80 = 0b00101, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.85V + V0_85 = 0b00110, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.90V + V0_90 = 0b00111, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.95V + V0_95 = 0b01000, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.00V + V1_00 = 0b01001, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.05V + V1_05 = 0b01010, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.10V - Default voltage level + V1_10 = 0b01011, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.15V + V1_15 = 0b01100, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.20V + V1_20 = 0b01101, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.25V + V1_25 = 0b01110, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.30V + V1_30 = 0b01111, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.35V + V1_35 = 0b10000, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.40V + V1_40 = 0b10001, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.50V + V1_50 = 0b10010, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.60V + V1_60 = 0b10011, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.65V + V1_65 = 0b10100, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.70V + V1_70 = 0b10101, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.80V + V1_80 = 0b10110, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.90V + V1_90 = 0b10111, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.00V + V2_00 = 0b11000, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.35V + V2_35 = 0b11001, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.50V + V2_50 = 0b11010, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.65V + V2_65 = 0b11011, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.80V + V2_80 = 0b11100, + #[cfg(feature = "_rp235x")] + /// RP235x: 3.00V + V3_00 = 0b11101, + #[cfg(feature = "_rp235x")] + /// RP235x: 3.15V + V3_15 = 0b11110, + #[cfg(feature = "_rp235x")] + /// RP235x: 3.30V + V3_30 = 0b11111, } -#[cfg(feature = "rp2040")] impl CoreVoltage { /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. /// Sets the BOD threshold to approximately 80% of the core voltage. fn recommended_bod(self) -> u8 { + #[cfg(feature = "rp2040")] match self { CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V) CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V) @@ -180,12 +289,38 @@ impl CoreVoltage { CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V) CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V) CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V) - CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V) + CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V), the default CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V) CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V) CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V) CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V) } + #[cfg(feature = "_rp235x")] + match self { + CoreVoltage::V0_55 => 0b00001, // 0.516V (~94% of 0.55V) + CoreVoltage::V0_60 => 0b00010, // 0.559V (~93% of 0.60V) + CoreVoltage::V0_65 => 0b00011, // 0.602V (~93% of 0.65V) + CoreVoltage::V0_70 => 0b00011, // 0.602V (~86% of 0.70V) + CoreVoltage::V0_75 => 0b00100, // 0.645V (~86% of 0.75V) + CoreVoltage::V0_80 => 0b00101, // 0.688V (~86% of 0.80V) + CoreVoltage::V0_85 => 0b00110, // 0.731V (~86% of 0.85V) + CoreVoltage::V0_90 => 0b00110, // 0.731V (~81% of 0.90V) + CoreVoltage::V0_95 => 0b00111, // 0.774V (~81% of 0.95V) + CoreVoltage::V1_00 => 0b01000, // 0.817V (~82% of 1.00V) + CoreVoltage::V1_05 => 0b01000, // 0.817V (~78% of 1.05V) + CoreVoltage::V1_10 => 0b01001, // 0.860V (~78% of 1.10V), the default + CoreVoltage::V1_15 => 0b01001, // 0.860V (~75% of 1.15V) + CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V) + CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V) + CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V) + CoreVoltage::V1_35 => 0b01011, // 0.946V (~70% of 1.35V) + CoreVoltage::V1_40 => 0b01100, // 0.989V (~71% of 1.40V) + CoreVoltage::V1_50 => 0b01101, // 1.032V (~69% of 1.50V) + CoreVoltage::V1_60 => 0b01110, // 1.075V (~67% of 1.60V) + CoreVoltage::V1_65 => 0b01110, // 1.075V (~65% of 1.65V) + CoreVoltage::V1_70 => 0b01111, // 1.118V (~66% of 1.70V) + _ => 0b10000, // the rp2350 datasheet repeats this value for all other core voltages + } } } @@ -209,12 +344,10 @@ pub struct ClockConfig { /// RTC clock configuration. #[cfg(feature = "rp2040")] pub rtc_clk: Option, - /// Core voltage scaling (RP2040 only). Defaults to 1.10V. - #[cfg(feature = "rp2040")] + /// Core voltage scaling. Defaults to 1.10V. pub core_voltage: CoreVoltage, /// Voltage stabilization delay in microseconds. /// If not set, defaults will be used based on voltage level. - #[cfg(feature = "rp2040")] pub voltage_stabilization_delay_us: Option, // See above re gpin handling being commented out // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, @@ -250,9 +383,7 @@ impl Default for ClockConfig { adc_clk: None, #[cfg(feature = "rp2040")] rtc_clk: None, - #[cfg(feature = "rp2040")] core_voltage: CoreVoltage::V1_10, - #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // See above re gpin handling being commented out // gpin0: None, @@ -323,9 +454,7 @@ impl ClockConfig { div_frac: 0, phase: 0, }), - #[cfg(feature = "rp2040")] core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) - #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // See above re gpin handling being commented out // gpin0: None, @@ -368,9 +497,7 @@ impl ClockConfig { div_frac: 171, phase: 0, }), - #[cfg(feature = "rp2040")] core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) - #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // See above re gpin handling being commented out // gpin0: None, @@ -394,12 +521,17 @@ impl ClockConfig { /// the usual 12Mhz crystal, or panic if no valid parameters can be found. /// /// # Note on core voltage: + /// + /// **For RP2040**: /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are: /// - Up to 133MHz: V1_10 (default) /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here. /// In case You want to go below 133MHz or above 200MHz and want a different voltage, You will have to set that manually and with caution. - #[cfg(feature = "rp2040")] + /// + /// **For RP235x**: + /// At this point in time there is no official manufacturer endorsement for running the chip on other core voltages and/or other clock speeds than the defaults. + /// Using this function is experimental and may not work as expected or even damage the chip. pub fn system_freq(hz: u32) -> Self { // Start with the standard configuration from crystal() const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; @@ -407,9 +539,14 @@ impl ClockConfig { // No need to modify anything if target frequency is already 125MHz // (which is what crystal() configures by default) + #[cfg(feature = "rp2040")] if hz == 125_000_000 { return config; } + #[cfg(feature = "_rp235x")] + if hz == 150_000_000 { + return config; + } // Find optimal PLL parameters for the requested frequency let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) @@ -429,6 +566,14 @@ impl ClockConfig { _ => CoreVoltage::V1_10, // Use default voltage (V1_10) }; } + #[cfg(feature = "_rp235x")] + { + config.core_voltage = match hz { + // There is no official support for running the chip on other core voltages and/or other clock speeds than the defaults. + // So for now we have not way of knowing what the voltage should be. Change this if the manufacturer provides more information. + _ => CoreVoltage::V1_10, // Use default voltage (V1_10) + }; + } config } @@ -791,7 +936,6 @@ pub struct RtcClkConfig { /// // Find parameters for 133MHz system clock from 12MHz crystal /// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap(); /// ``` -#[cfg(feature = "rp2040")] fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { // Fixed reference divider for system PLL const PLL_SYS_REFDIV: u8 = 1; @@ -925,18 +1069,59 @@ pub(crate) unsafe fn init(config: ClockConfig) { }; CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); - // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default - #[cfg(feature = "rp2040")] + // Set Core Voltage, if we have config for it and we're not using the default { let voltage = config.core_voltage; + + #[cfg(feature = "rp2040")] let vreg = pac::VREG_AND_CHIP_RESET; + #[cfg(feature = "_rp235x")] + let vreg = pac::POWMAN; + let current_vsel = vreg.vreg().read().vsel(); let target_vsel = voltage as u8; // If the target voltage is different from the current one, we need to change it if target_vsel != current_vsel { - // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage - vreg.vreg().modify(|w| w.set_vsel(target_vsel)); + #[cfg(feature = "rp2040")] + { + // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage + vreg.vreg().modify(|w| w.set_vsel(target_vsel)); + } + #[cfg(feature = "_rp235x")] + { + // The rp235x has a different way of controlling the voltage regulator + // Changes to the voltage regulator are protected by a password, see datasheet section 6.4 + // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register + + // The rp235x by default locks the voltage regulator control, so we need to unlock it first + // See datasheet section 6.3.2. Software Control + vreg.vreg_ctrl().modify(|w| { + // Add password to top 16 bits, preserving the rest, repeat below for other registers + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); + w.set_unlock(true); + *w + }); + + // Set the voltage + vreg.vreg().modify(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); + w.set_vsel(target_vsel); + *w + }); + + // The rp235x has two more registers to set the voltage for low power mode + vreg.vreg_lp_entry().modify(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); + w.set_vsel(target_vsel); + *w + }); + vreg.vreg_lp_exit().modify(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); + w.set_vsel(target_vsel); + *w + }); + } // Wait for the voltage to stabilize. Use the provided delay or default based on voltage let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { @@ -959,6 +1144,19 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_vsel(voltage.recommended_bod()); w.set_en(true); // Enable brownout detection }); + + #[cfg(feature = "_rp235x")] + { + // The rp235x has a separate register for the BOD level in low power mode + vreg.bod_lp_entry().write(|w| { + w.set_vsel(voltage.recommended_bod()); + w.set_en(true); // Enable brownout detection + }); + vreg.bod_lp_exit().write(|w| { + w.set_vsel(voltage.recommended_bod()); + w.set_en(true); // Enable brownout detection + }); + } } } @@ -1283,6 +1481,73 @@ pub fn clk_rtc_freq() -> u16 { CLOCKS.rtc.load(Ordering::Relaxed) } +/// The core voltage of the chip. +/// +/// Returns the current core voltage or an error if the voltage register +/// contains an unknown value. +pub fn core_voltage() -> Result { + #[cfg(feature = "rp2040")] + { + let vreg = pac::VREG_AND_CHIP_RESET; + let vsel = vreg.vreg().read().vsel(); + match vsel { + 0b0000 => Ok(CoreVoltage::V0_80), + 0b0110 => Ok(CoreVoltage::V0_85), + 0b0111 => Ok(CoreVoltage::V0_90), + 0b1000 => Ok(CoreVoltage::V0_95), + 0b1001 => Ok(CoreVoltage::V1_00), + 0b1010 => Ok(CoreVoltage::V1_05), + 0b1011 => Ok(CoreVoltage::V1_10), + 0b1100 => Ok(CoreVoltage::V1_15), + 0b1101 => Ok(CoreVoltage::V1_20), + 0b1110 => Ok(CoreVoltage::V1_25), + 0b1111 => Ok(CoreVoltage::V1_30), + _ => Err("Unexpected value in register"), + } + } + + #[cfg(feature = "_rp235x")] + { + let vreg = pac::POWMAN; + let vsel = vreg.vreg().read().vsel(); + match vsel { + 0b00000 => Ok(CoreVoltage::V0_55), + 0b00001 => Ok(CoreVoltage::V0_60), + 0b00010 => Ok(CoreVoltage::V0_65), + 0b00011 => Ok(CoreVoltage::V0_70), + 0b00100 => Ok(CoreVoltage::V0_75), + 0b00101 => Ok(CoreVoltage::V0_80), + 0b00110 => Ok(CoreVoltage::V0_85), + 0b00111 => Ok(CoreVoltage::V0_90), + 0b01000 => Ok(CoreVoltage::V0_95), + 0b01001 => Ok(CoreVoltage::V1_00), + 0b01010 => Ok(CoreVoltage::V1_05), + 0b01011 => Ok(CoreVoltage::V1_10), + 0b01100 => Ok(CoreVoltage::V1_15), + 0b01101 => Ok(CoreVoltage::V1_20), + 0b01110 => Ok(CoreVoltage::V1_25), + 0b01111 => Ok(CoreVoltage::V1_30), + 0b10000 => Ok(CoreVoltage::V1_35), + 0b10001 => Ok(CoreVoltage::V1_40), + 0b10010 => Ok(CoreVoltage::V1_50), + 0b10011 => Ok(CoreVoltage::V1_60), + 0b10100 => Ok(CoreVoltage::V1_65), + 0b10101 => Ok(CoreVoltage::V1_70), + 0b10110 => Ok(CoreVoltage::V1_80), + 0b10111 => Ok(CoreVoltage::V1_90), + 0b11000 => Ok(CoreVoltage::V2_00), + 0b11001 => Ok(CoreVoltage::V2_35), + 0b11010 => Ok(CoreVoltage::V2_50), + 0b11011 => Ok(CoreVoltage::V2_65), + 0b11100 => Ok(CoreVoltage::V2_80), + 0b11101 => Ok(CoreVoltage::V3_00), + 0b11110 => Ok(CoreVoltage::V3_15), + 0b11111 => Ok(CoreVoltage::V3_30), + _ => Err("Unexpected value in register"), + } + } +} + fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256; pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 9c78e0c9d..89147ba42 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -20,15 +20,15 @@ async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. let config = Config::new(ClockConfig::system_freq(200_000_000)); - // Show the voltage scale for verification - info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage)); - // Initialize the peripherals let p = embassy_rp::init(config); // Show CPU frequency for verification let sys_freq = clk_sys_freq(); info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + // Show core voltage for verification + let core_voltage = core_voltage().unwrap(); + info!("Core voltage: {}", Debug2Format(&core_voltage)); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index 35160b250..88ef26a7a 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -7,8 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks; -use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig}; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -41,9 +40,12 @@ async fn main(_spawner: Spawner) -> ! { // Initialize with our manual overclock configuration let p = embassy_rp::init(configure_manual_overclock()); - // Verify the actual system clock frequency - let sys_freq = clocks::clk_sys_freq(); + // Show CPU frequency for verification + let sys_freq = clk_sys_freq(); info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + // Show core voltage for verification + let core_voltage = core_voltage().unwrap(); + info!("Core voltage: {}", Debug2Format(&core_voltage)); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs new file mode 100644 index 000000000..8713df688 --- /dev/null +++ b/examples/rp235x/src/bin/overclock.rs @@ -0,0 +1,74 @@ +//! # Overclocking the RP2350 to 200 MHz +//! +//! This example demonstrates how to configure the RP2350 to run at 200 MHz instead of the default 150 MHz. +//! +//! ## Note +//! +//! As of yet there is no official support for running the RP235x at higher clock frequencies and/or other core voltages than the default. +//! Doing so may cause unexpected behavior and/or damage the chip. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; +use embassy_rp::config::Config; +use embassy_rp::gpio::{Level, Output}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +const COUNT_TO: i64 = 10_000_000; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + // Set up for clock frequency of 200 MHz, setting all necessary defaults. + let mut config = Config::new(ClockConfig::system_freq(200_000_000)); + + // since for the rp235x there is no official support for higher clock frequencies, `system_freq()` will not set a voltage for us. + // We need to guess the core voltage, that is needed for the higher clock frequency. Going with a small increase from the default 1.1V here, based on + // what we know about the RP2040. This is not guaranteed to be correct. + config.clocks.core_voltage = CoreVoltage::V1_15; + + // Initialize the peripherals + let p = embassy_rp::init(config); + + // Show CPU frequency for verification + let sys_freq = clk_sys_freq(); + info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + // Show core voltage for verification + let core_voltage = core_voltage().unwrap(); + info!("Core voltage: {}", Debug2Format(&core_voltage)); + + // LED to indicate the system is running + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + // Reset the counter at the start of measurement period + let mut counter = 0; + + // Turn LED on while counting + led.set_high(); + + let start = Instant::now(); + + // This is a busy loop that will take some time to complete + while counter < COUNT_TO { + counter += 1; + } + + let elapsed = Instant::now() - start; + + // Report the elapsed time + led.set_low(); + info!( + "At {}Mhz: Elapsed time to count to {}: {}ms", + sys_freq / 1_000_000, + counter, + elapsed.as_millis() + ); + + // Wait 2 seconds before starting the next measurement + Timer::after(Duration::from_secs(2)).await; + } +} diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index be8e85a3f..a568d7fed 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -7,14 +7,8 @@ teleprobe_meta::target!(b"rpi-pico"); teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::info; -#[cfg(feature = "rp2040")] -use defmt::{assert, assert_eq}; use embassy_executor::Spawner; -use embassy_rp::clocks; -#[cfg(feature = "rp2040")] -use embassy_rp::clocks::ClockConfig; -#[cfg(feature = "rp2040")] -use embassy_rp::clocks::CoreVoltage; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; use embassy_rp::config::Config; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; @@ -23,23 +17,26 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) { - #[cfg(feature = "rp2040")] let mut config = Config::default(); - #[cfg(not(feature = "rp2040"))] - let config = Config::default(); - // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock - #[cfg(feature = "rp2040")] + // Initialize with 200MHz clock configuration + config.clocks = ClockConfig::system_freq(200_000_000); + + // if we are rp235x, we need to manually set the core voltage. rp2040 should do this automatically + #[cfg(feature = "rp235xb")] { - config.clocks = ClockConfig::system_freq(200_000_000); - let voltage = config.clocks.core_voltage; - assert!(matches!(voltage, CoreVoltage::V1_15), "Expected voltage scale V1_15"); + config.clocks.core_voltage = CoreVoltage::V1_15; } let _p = embassy_rp::init(config); + // We should be at core voltage of 1.15V + assert_eq!(core_voltage().unwrap(), CoreVoltage::V1_15, "Core voltage is not 1.15V"); + // We should be at 200MHz + assert_eq!(clk_sys_freq(), 200_000_000, "System clock frequency is not 200MHz"); + // Test the system speed - let (time_elapsed, clk_sys_freq) = { + let time_elapsed = { let mut counter = 0; let start = Instant::now(); while counter < COUNT_TO { @@ -47,24 +44,26 @@ async fn main(_spawner: Spawner) { } let elapsed = Instant::now() - start; - (elapsed.as_millis(), clocks::clk_sys_freq()) + elapsed.as_millis() }; - // Report the elapsed time, so that the compiler doesn't optimize it away for chips other than RP2040 + // Tests will fail if unused variables are detected: + // Report the elapsed time, so that the compiler doesn't optimize it away for the chip not on test info!( "At {}Mhz: Elapsed time to count to {}: {}ms", - clk_sys_freq / 1_000_000, + clk_sys_freq() / 1_000_000, COUNT_TO, time_elapsed ); + // Check if the elapsed time is within expected limits + // for rp2040 we expect about 600ms #[cfg(feature = "rp2040")] - { - // we should be at 200MHz - assert_eq!(clk_sys_freq, 200_000_000, "System clock frequency is not 200MHz"); - // At 200MHz, the time to count to 10_000_000 should be at 600ms, testing with 1% margin - assert!(time_elapsed <= 606, "Elapsed time is too long"); - } + // allow 1% error + assert!(time_elapsed < 606, "Elapsed time is too long"); + // for rp235x we expect about 450ms + #[cfg(feature = "rp235xb")] + assert!(time_elapsed < 455, "Elapsed time is too long"); cortex_m::asm::bkpt(); } -- cgit From 133500167ca53cfbc5e9268356753bc0e3f8c209 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 09:45:05 +0200 Subject: limit CoreVoltage eum to values up to 1.30V, because we do not support unlocking higher voltages --- embassy-rp/src/clocks.rs | 141 +++++++---------------------------------------- 1 file changed, 21 insertions(+), 120 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index ea5e9362b..bcd08c204 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -140,6 +140,10 @@ pub enum PeriClkSrc { /// /// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. +/// +/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit +/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this +/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum CoreVoltage { @@ -227,54 +231,6 @@ pub enum CoreVoltage { #[cfg(feature = "_rp235x")] /// RP235x: 1.30V V1_30 = 0b01111, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.35V - V1_35 = 0b10000, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.40V - V1_40 = 0b10001, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.50V - V1_50 = 0b10010, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.60V - V1_60 = 0b10011, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.65V - V1_65 = 0b10100, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.70V - V1_70 = 0b10101, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.80V - V1_80 = 0b10110, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.90V - V1_90 = 0b10111, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.00V - V2_00 = 0b11000, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.35V - V2_35 = 0b11001, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.50V - V2_50 = 0b11010, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.65V - V2_65 = 0b11011, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.80V - V2_80 = 0b11100, - #[cfg(feature = "_rp235x")] - /// RP235x: 3.00V - V3_00 = 0b11101, - #[cfg(feature = "_rp235x")] - /// RP235x: 3.15V - V3_15 = 0b11110, - #[cfg(feature = "_rp235x")] - /// RP235x: 3.30V - V3_30 = 0b11111, } impl CoreVoltage { @@ -313,13 +269,7 @@ impl CoreVoltage { CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V) CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V) CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V) - CoreVoltage::V1_35 => 0b01011, // 0.946V (~70% of 1.35V) - CoreVoltage::V1_40 => 0b01100, // 0.989V (~71% of 1.40V) - CoreVoltage::V1_50 => 0b01101, // 1.032V (~69% of 1.50V) - CoreVoltage::V1_60 => 0b01110, // 1.075V (~67% of 1.60V) - CoreVoltage::V1_65 => 0b01110, // 1.075V (~65% of 1.65V) - CoreVoltage::V1_70 => 0b01111, // 1.118V (~66% of 1.70V) - _ => 0b10000, // the rp2350 datasheet repeats this value for all other core voltages + // all others: 0.946V (see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point) } } } @@ -1083,45 +1033,17 @@ pub(crate) unsafe fn init(config: ClockConfig) { // If the target voltage is different from the current one, we need to change it if target_vsel != current_vsel { + // Set the voltage regulator to the target voltage #[cfg(feature = "rp2040")] - { - // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage - vreg.vreg().modify(|w| w.set_vsel(target_vsel)); - } + vreg.vreg().modify(|w| w.set_vsel(target_vsel)); #[cfg(feature = "_rp235x")] - { - // The rp235x has a different way of controlling the voltage regulator - // Changes to the voltage regulator are protected by a password, see datasheet section 6.4 - // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register - - // The rp235x by default locks the voltage regulator control, so we need to unlock it first - // See datasheet section 6.3.2. Software Control - vreg.vreg_ctrl().modify(|w| { - // Add password to top 16 bits, preserving the rest, repeat below for other registers - w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); - w.set_unlock(true); - *w - }); - - // Set the voltage - vreg.vreg().modify(|w| { - w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); - w.set_vsel(target_vsel); - *w - }); - - // The rp235x has two more registers to set the voltage for low power mode - vreg.vreg_lp_entry().modify(|w| { - w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); - w.set_vsel(target_vsel); - *w - }); - vreg.vreg_lp_exit().modify(|w| { - w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); - w.set_vsel(target_vsel); - *w - }); - } + // For rp235x changes to the voltage regulator are protected by a password, see datasheet section 6.4 Power Management (POWMAN) Registers + // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register + vreg.vreg().modify(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password + w.set_vsel(target_vsel); + *w + }); // Wait for the voltage to stabilize. Use the provided delay or default based on voltage let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { @@ -1140,23 +1062,17 @@ pub(crate) unsafe fn init(config: ClockConfig) { } // Only now set the BOD level. At this point the voltage is considered stable. + #[cfg(feature = "rp2040")] vreg.bod().write(|w| { w.set_vsel(voltage.recommended_bod()); w.set_en(true); // Enable brownout detection }); - #[cfg(feature = "_rp235x")] - { - // The rp235x has a separate register for the BOD level in low power mode - vreg.bod_lp_entry().write(|w| { - w.set_vsel(voltage.recommended_bod()); - w.set_en(true); // Enable brownout detection - }); - vreg.bod_lp_exit().write(|w| { - w.set_vsel(voltage.recommended_bod()); - w.set_en(true); // Enable brownout detection - }); - } + vreg.bod().write(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password + w.set_vsel(voltage.recommended_bod()); + w.set_en(true); // Enable brownout detection + }); } } @@ -1527,23 +1443,8 @@ pub fn core_voltage() -> Result { 0b01101 => Ok(CoreVoltage::V1_20), 0b01110 => Ok(CoreVoltage::V1_25), 0b01111 => Ok(CoreVoltage::V1_30), - 0b10000 => Ok(CoreVoltage::V1_35), - 0b10001 => Ok(CoreVoltage::V1_40), - 0b10010 => Ok(CoreVoltage::V1_50), - 0b10011 => Ok(CoreVoltage::V1_60), - 0b10100 => Ok(CoreVoltage::V1_65), - 0b10101 => Ok(CoreVoltage::V1_70), - 0b10110 => Ok(CoreVoltage::V1_80), - 0b10111 => Ok(CoreVoltage::V1_90), - 0b11000 => Ok(CoreVoltage::V2_00), - 0b11001 => Ok(CoreVoltage::V2_35), - 0b11010 => Ok(CoreVoltage::V2_50), - 0b11011 => Ok(CoreVoltage::V2_65), - 0b11100 => Ok(CoreVoltage::V2_80), - 0b11101 => Ok(CoreVoltage::V3_00), - 0b11110 => Ok(CoreVoltage::V3_15), - 0b11111 => Ok(CoreVoltage::V3_30), _ => Err("Unexpected value in register"), + // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point } } } -- cgit From 79e452922a6b467f2e8547a6b28698ed5f409705 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 21:33:47 +0200 Subject: Add ClockError enum and update system_freq to return Result for error handling --- embassy-rp/src/clocks.rs | 66 +++++++++++++++++++++++++----------- examples/rp/src/bin/overclock.rs | 2 +- examples/rp235x/src/bin/overclock.rs | 2 +- tests/rp/src/bin/overclock.rs | 2 +- 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index bcd08c204..5872ef789 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -82,6 +82,18 @@ use crate::{pac, reset, Peri}; // be very useful until we have runtime clock reconfiguration. once this // happens we can resurrect the commented-out gpin bits. +/// Clock error types. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ClockError { + /// PLL failed to lock within the timeout period. + PllLockTimedOut, + /// Could not find valid PLL parameters for system clock. + InvalidPllParameters, + /// Reading the core voltage failed due to an unexpected value in the register. + UnexpectedCoreVoltageRead, +} + struct Clocks { xosc: AtomicU32, sys: AtomicU32, @@ -144,8 +156,9 @@ pub enum PeriClkSrc { /// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit /// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this /// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CoreVoltage { // RP2040 voltage levels #[cfg(feature = "rp2040")] @@ -468,7 +481,7 @@ impl ClockConfig { /// # Returns /// /// A ClockConfig configured to achieve the requested system frequency using the - /// the usual 12Mhz crystal, or panic if no valid parameters can be found. + /// the usual 12Mhz crystal, or an error if no valid parameters can be found. /// /// # Note on core voltage: /// @@ -482,7 +495,11 @@ impl ClockConfig { /// **For RP235x**: /// At this point in time there is no official manufacturer endorsement for running the chip on other core voltages and/or other clock speeds than the defaults. /// Using this function is experimental and may not work as expected or even damage the chip. - pub fn system_freq(hz: u32) -> Self { + /// + /// # Returns + /// + /// A Result containing either the configured ClockConfig or a ClockError. + pub fn system_freq(hz: u32) -> Result { // Start with the standard configuration from crystal() const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ); @@ -491,16 +508,15 @@ impl ClockConfig { // (which is what crystal() configures by default) #[cfg(feature = "rp2040")] if hz == 125_000_000 { - return config; + return Ok(config); } #[cfg(feature = "_rp235x")] if hz == 150_000_000 { - return config; + return Ok(config); } // Find optimal PLL parameters for the requested frequency - let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) - .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock")); + let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz).ok_or(ClockError::InvalidPllParameters)?; // Replace the sys_pll configuration with our custom parameters if let Some(xosc) = &mut config.xosc { @@ -525,7 +541,7 @@ impl ClockConfig { }; } - config + Ok(config) } /// Configure with manual PLL settings for full control over system clock @@ -620,6 +636,7 @@ impl ClockConfig { #[repr(u16)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RoscRange { /// Low range. Low = pac::rosc::vals::FreqRange::LOW.0, @@ -726,6 +743,7 @@ pub struct RefClkConfig { /// Reference clock source. #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RefClkSrc { /// XOSC. Xosc, @@ -741,6 +759,7 @@ pub enum RefClkSrc { /// SYS clock source. #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SysClkSrc { /// REF. Ref, @@ -779,6 +798,7 @@ pub struct SysClkConfig { #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum UsbClkSrc { /// PLL USB. PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, @@ -807,6 +827,7 @@ pub struct UsbClkConfig { #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AdcClkSrc { /// PLL USB. PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, @@ -835,6 +856,7 @@ pub struct AdcClkConfig { #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg(feature = "rp2040")] pub enum RtcClkSrc { /// PLL USB. @@ -1084,14 +1106,20 @@ pub(crate) unsafe fn init(config: ClockConfig) { let pll_sys_freq = match config.sys_pll { Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) { Ok(freq) => freq, + #[cfg(feature = "defmt")] Err(e) => panic!("Failed to configure PLL_SYS: {}", e), + #[cfg(not(feature = "defmt"))] + Err(_e) => panic!("Failed to configure PLL_SYS"), }, None => 0, }; let pll_usb_freq = match config.usb_pll { Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) { Ok(freq) => freq, + #[cfg(feature = "defmt")] Err(e) => panic!("Failed to configure PLL_USB: {}", e), + #[cfg(not(feature = "defmt"))] + Err(_e) => panic!("Failed to configure PLL_USB"), }, None => 0, }; @@ -1401,7 +1429,7 @@ pub fn clk_rtc_freq() -> u16 { /// /// Returns the current core voltage or an error if the voltage register /// contains an unknown value. -pub fn core_voltage() -> Result { +pub fn core_voltage() -> Result { #[cfg(feature = "rp2040")] { let vreg = pac::VREG_AND_CHIP_RESET; @@ -1418,7 +1446,7 @@ pub fn core_voltage() -> Result { 0b1101 => Ok(CoreVoltage::V1_20), 0b1110 => Ok(CoreVoltage::V1_25), 0b1111 => Ok(CoreVoltage::V1_30), - _ => Err("Unexpected value in register"), + _ => Err(ClockError::UnexpectedCoreVoltageRead), } } @@ -1443,7 +1471,7 @@ pub fn core_voltage() -> Result { 0b01101 => Ok(CoreVoltage::V1_20), 0b01110 => Ok(CoreVoltage::V1_25), 0b01111 => Ok(CoreVoltage::V1_30), - _ => Err("Unexpected value in register"), + _ => Err(ClockError::UnexpectedCoreVoltageRead), // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point } } @@ -1461,7 +1489,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { /// PLL (Phase-Locked Loop) configuration #[inline(always)] -fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result { +fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result { // Calculate reference frequency let ref_freq = input_freq / config.refdiv as u32; @@ -1532,7 +1560,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result timeout -= 1; if timeout == 0 { // PLL failed to lock, return 0 to indicate failure - return Err("PLL failed to lock"); + return Err(ClockError::PllLockTimedOut); } } @@ -2103,21 +2131,21 @@ mod tests { { // Test automatic voltage scaling based on frequency // Under 133 MHz should use default voltage (V1_10) - let config = ClockConfig::system_freq(125_000_000); + let config = ClockConfig::system_freq(125_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_10); // 133-200 MHz should use V1_15 - let config = ClockConfig::system_freq(150_000_000); + let config = ClockConfig::system_freq(150_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_15); - let config = ClockConfig::system_freq(200_000_000); + let config = ClockConfig::system_freq(200_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_15); - // Above 200 MHz should use V1_25 - let config = ClockConfig::system_freq(250_000_000); + // Above 200 MHz should use V1_15 + let config = ClockConfig::system_freq(250_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_15); // Below 125 MHz should use V1_10 - let config = ClockConfig::system_freq(100_000_000); + let config = ClockConfig::system_freq(100_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_10); } } diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 89147ba42..2706399af 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -18,7 +18,7 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. - let config = Config::new(ClockConfig::system_freq(200_000_000)); + let config = Config::new(ClockConfig::system_freq(200_000_000).unwrap()); // Initialize the peripherals let p = embassy_rp::init(config); diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs index 8713df688..178fd62ca 100644 --- a/examples/rp235x/src/bin/overclock.rs +++ b/examples/rp235x/src/bin/overclock.rs @@ -23,7 +23,7 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. - let mut config = Config::new(ClockConfig::system_freq(200_000_000)); + let mut config = Config::new(ClockConfig::system_freq(200_000_000).unwrap()); // since for the rp235x there is no official support for higher clock frequencies, `system_freq()` will not set a voltage for us. // We need to guess the core voltage, that is needed for the higher clock frequency. Going with a small increase from the default 1.1V here, based on diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index a568d7fed..167a26eb2 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); // Initialize with 200MHz clock configuration - config.clocks = ClockConfig::system_freq(200_000_000); + config.clocks = ClockConfig::system_freq(200_000_000).unwrap(); // if we are rp235x, we need to manually set the core voltage. rp2040 should do this automatically #[cfg(feature = "rp235xb")] -- cgit From be1b679d48b5d781f888fb97c1fed7479235019b Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 21:42:03 +0200 Subject: Refactor CoreVoltage enum, separate for rp2040 and rp235x --- embassy-rp/src/clocks.rs | 98 +++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 5872ef789..3975e7e79 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -156,93 +156,79 @@ pub enum PeriClkSrc { /// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit /// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this /// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. +#[cfg(feature = "rp2040")] #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CoreVoltage { - // RP2040 voltage levels - #[cfg(feature = "rp2040")] - /// RP2040: 0.80V + /// 0.80V V0_80 = 0b0000, - #[cfg(feature = "rp2040")] - /// RP2040: 0.85V + /// 0.85V V0_85 = 0b0110, - #[cfg(feature = "rp2040")] - /// RP2040: 0.90V + /// 0.90V V0_90 = 0b0111, - #[cfg(feature = "rp2040")] - /// RP2040: 0.95V + /// 0.95V V0_95 = 0b1000, - #[cfg(feature = "rp2040")] - /// RP2040: 1.00V + /// 1.00V V1_00 = 0b1001, - #[cfg(feature = "rp2040")] - /// RP2040: 1.05V + /// 1.05V V1_05 = 0b1010, - #[cfg(feature = "rp2040")] - /// RP2040: 1.10V - Default voltage level + /// 1.10V - Default voltage level V1_10 = 0b1011, - #[cfg(feature = "rp2040")] - /// RP2040: 1.15V - Required for overclocking to 133-200MHz + /// 1.15V - Required for overclocking to 133-200MHz V1_15 = 0b1100, - #[cfg(feature = "rp2040")] - /// RP2040: 1.20V + /// 1.20V V1_20 = 0b1101, - #[cfg(feature = "rp2040")] - /// RP2040: 1.25V + /// 1.25V V1_25 = 0b1110, - #[cfg(feature = "rp2040")] - /// RP2040: 1.30V + /// 1.30V V1_30 = 0b1111, +} - // RP235x voltage levels - #[cfg(feature = "_rp235x")] - /// RP235x: 0.55V +/// Core voltage regulator settings. +/// +/// The voltage regulator can be configured for different output voltages. +/// Higher voltages allow for higher clock frequencies but increase power consumption and heat. +/// +/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit +/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this +/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. +#[cfg(feature = "_rp235x")] +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum CoreVoltage { + /// 0.55V V0_55 = 0b00000, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.60V + /// 0.60V V0_60 = 0b00001, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.65V + /// 0.65V V0_65 = 0b00010, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.70V + /// 0.70V V0_70 = 0b00011, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.75V + /// 0.75V V0_75 = 0b00100, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.80V + /// 0.80V V0_80 = 0b00101, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.85V + /// 0.85V V0_85 = 0b00110, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.90V + /// 0.90V V0_90 = 0b00111, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.95V + /// 0.95V V0_95 = 0b01000, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.00V + /// 1.00V V1_00 = 0b01001, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.05V + /// 1.05V V1_05 = 0b01010, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.10V - Default voltage level + /// 1.10V - Default voltage level V1_10 = 0b01011, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.15V + /// 1.15V V1_15 = 0b01100, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.20V + /// 1.20V V1_20 = 0b01101, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.25V + /// 1.25V V1_25 = 0b01110, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.30V + /// 1.30V V1_30 = 0b01111, } -- cgit From abafbed0d5fba70ab5d0096b9d381577d2f880c8 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 21:43:17 +0200 Subject: remove Debug2Fmt from examples --- examples/rp/src/bin/overclock.rs | 2 +- examples/rp/src/bin/overclock_manual.rs | 2 +- examples/rp235x/src/bin/overclock.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 2706399af..83b17308b 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) -> ! { info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // Show core voltage for verification let core_voltage = core_voltage().unwrap(); - info!("Core voltage: {}", Debug2Format(&core_voltage)); + info!("Core voltage: {}", core_voltage); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index 88ef26a7a..dea5cfb3c 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) -> ! { info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // Show core voltage for verification let core_voltage = core_voltage().unwrap(); - info!("Core voltage: {}", Debug2Format(&core_voltage)); + info!("Core voltage: {}", core_voltage); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs index 178fd62ca..5fd97ef97 100644 --- a/examples/rp235x/src/bin/overclock.rs +++ b/examples/rp235x/src/bin/overclock.rs @@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) -> ! { info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // Show core voltage for verification let core_voltage = core_voltage().unwrap(); - info!("Core voltage: {}", Debug2Format(&core_voltage)); + info!("Core voltage: {}", core_voltage); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); -- cgit From 1314808b3a39d856d33655504db00d799914c440 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 13 May 2025 10:49:23 +0200 Subject: Changes after review: copypasted doc comment fixed and no cfg gates to panic on failing pll config in init() --- embassy-rp/src/clocks.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 3975e7e79..47e71c448 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -152,11 +152,6 @@ pub enum PeriClkSrc { /// /// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. -/// -/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit -/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this -/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. -#[cfg(feature = "rp2040")] #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -190,7 +185,7 @@ pub enum CoreVoltage { /// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. /// -/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit +/// **Note**: The maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit /// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this /// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. #[cfg(feature = "_rp235x")] @@ -1092,20 +1087,14 @@ pub(crate) unsafe fn init(config: ClockConfig) { let pll_sys_freq = match config.sys_pll { Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) { Ok(freq) => freq, - #[cfg(feature = "defmt")] - Err(e) => panic!("Failed to configure PLL_SYS: {}", e), - #[cfg(not(feature = "defmt"))] - Err(_e) => panic!("Failed to configure PLL_SYS"), + Err(e) => panic!("Failed to configure PLL_SYS: {:?}", e), }, None => 0, }; let pll_usb_freq = match config.usb_pll { Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) { Ok(freq) => freq, - #[cfg(feature = "defmt")] - Err(e) => panic!("Failed to configure PLL_USB: {}", e), - #[cfg(not(feature = "defmt"))] - Err(_e) => panic!("Failed to configure PLL_USB"), + Err(e) => panic!("Failed to configure PLL_USB: {:?}", e), }, None => 0, }; -- cgit From 981ef20f83ec88601818d8c55f69a1037d57b0cb Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 13 May 2025 10:59:11 +0200 Subject: removed one line too many --- 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 47e71c448..857877680 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -152,6 +152,7 @@ pub enum PeriClkSrc { /// /// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. +#[cfg(feature = "rp2040")] #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -- cgit