add manual overclock example, finalize API, cleanup
This commit is contained in:
parent
d44b945235
commit
22b5f73811
@ -147,56 +147,30 @@ pub enum PeriClkSrc {
|
||||
/// Core voltage scaling options for RP2040.
|
||||
///
|
||||
/// The RP2040 voltage regulator can be configured for different output voltages.
|
||||
/// Higher voltages allow for higher clock frequencies but increase power consumption.
|
||||
///
|
||||
/// # Typical Use Cases
|
||||
///
|
||||
/// - `V0_85` to `V1_05`: Power saving for lower frequencies (below 100MHz)
|
||||
/// - `V1_10`: Default voltage, safe for standard 125MHz operation
|
||||
/// - `V1_15`: Required for frequencies above 133MHz (e.g., 200MHz overclocking)
|
||||
/// - `V1_20`: For more extreme overclocking (200MHz+)
|
||||
/// - `V1_25` and `V1_30`: Highest voltage settings, use with caution
|
||||
///
|
||||
/// # Overclocking Notes
|
||||
///
|
||||
/// When overclocking:
|
||||
/// - Frequencies up to 133MHz are typically stable at default voltage (`V1_10`)
|
||||
/// - Frequencies from 133MHz to 200MHz generally require `V1_15`
|
||||
/// - Frequencies above 200MHz typically require `V1_20` or higher
|
||||
///
|
||||
/// # Power Consumption
|
||||
///
|
||||
/// Higher voltages increase power consumption and heat generation. In battery-powered
|
||||
/// applications, consider using lower voltages when maximum performance is not required.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Increased voltage can reduce the lifespan of the chip if used for extended periods,
|
||||
/// especially at `V1_25` and `V1_30`. These higher voltages should be used with
|
||||
/// consideration of thermal management.
|
||||
/// 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 VoltageScale {
|
||||
/// 0.85V - Lowest power consumption, suitable for low frequencies
|
||||
/// 0.85V
|
||||
V0_85 = 0b0110,
|
||||
/// 0.90V - Low power consumption
|
||||
/// 0.90V
|
||||
V0_90 = 0b0111,
|
||||
/// 0.95V - Low power consumption
|
||||
/// 0.95V
|
||||
V0_95 = 0b1000,
|
||||
/// 1.00V - Medium power consumption
|
||||
/// 1.00V
|
||||
V1_00 = 0b1001,
|
||||
/// 1.05V - Medium power consumption
|
||||
/// 1.05V
|
||||
V1_05 = 0b1010,
|
||||
/// 1.10V (Default) - Standard voltage for 125MHz operation
|
||||
/// 1.10V
|
||||
V1_10 = 0b1011,
|
||||
/// 1.15V - Required for frequencies above 133MHz
|
||||
/// 1.15V
|
||||
V1_15 = 0b1100,
|
||||
/// 1.20V - For higher overclocking (200MHz+)
|
||||
/// 1.20V
|
||||
V1_20 = 0b1101,
|
||||
/// 1.25V - High voltage, use with caution
|
||||
/// 1.25V
|
||||
V1_25 = 0b1110,
|
||||
/// 1.30V - Maximum voltage, use with extreme caution
|
||||
/// 1.30V
|
||||
V1_30 = 0b1111,
|
||||
}
|
||||
|
||||
@ -204,10 +178,8 @@ pub enum VoltageScale {
|
||||
impl VoltageScale {
|
||||
/// Get the recommended Brown-Out Detection (BOD) setting for this voltage.
|
||||
/// Sets the BOD threshold to approximately 90% of the core voltage.
|
||||
/// See RP2040 Datasheet, Table 190, BOD Register
|
||||
fn recommended_bod(self) -> u8 {
|
||||
match self {
|
||||
// ~90% of voltage setting based on Table 190 values
|
||||
VoltageScale::V0_85 => 0b0111, // 0.774V (~91% of 0.85V)
|
||||
VoltageScale::V0_90 => 0b1000, // 0.817V (~91% of 0.90V)
|
||||
VoltageScale::V0_95 => 0b1001, // 0.860V (~91% of 0.95V)
|
||||
@ -246,7 +218,7 @@ pub struct ClockConfig {
|
||||
#[cfg(feature = "rp2040")]
|
||||
pub voltage_scale: Option<VoltageScale>,
|
||||
/// Voltage stabilization delay in microseconds.
|
||||
/// If not set, appropriate defaults will be used based on voltage level.
|
||||
/// If not set, defaults will be used based on voltage level.
|
||||
#[cfg(feature = "rp2040")]
|
||||
pub voltage_stabilization_delay_us: Option<u32>,
|
||||
// gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
|
||||
@ -409,7 +381,7 @@ impl ClockConfig {
|
||||
|
||||
/// Configure the system clock to a specific frequency in MHz.
|
||||
///
|
||||
/// This is a more user-friendly way to configure the system clock, similar to
|
||||
/// This is a user-friendly way to configure the system clock, similar to
|
||||
/// the Pico SDK's approach. It automatically handles voltage scaling based on the
|
||||
/// requested frequency and uses the standard 12MHz crystal found on most RP2040 boards.
|
||||
///
|
||||
@ -420,9 +392,6 @@ impl ClockConfig {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// // Configure for standard 125MHz clock
|
||||
/// let config = ClockConfig::at_sys_frequency_mhz(125);
|
||||
///
|
||||
/// // Overclock to 200MHz
|
||||
/// let config = ClockConfig::at_sys_frequency_mhz(200);
|
||||
/// ```
|
||||
@ -551,6 +520,98 @@ impl ClockConfig {
|
||||
voltage_stabilization_delay_us: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure with manual PLL settings for full control over system clock
|
||||
///
|
||||
/// This method provides a simple way to configure the system with custom PLL parameters
|
||||
/// without needing to understand the full nested configuration structure.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `xosc_hz` - The frequency of the external crystal in Hz
|
||||
/// * `pll_config` - The PLL configuration parameters to achieve desired frequency
|
||||
/// * `voltage_scale` - Optional voltage scaling for overclocking (required for >133MHz)
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A ClockConfig configured with the specified PLL parameters
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// // Configure for 200MHz operation
|
||||
/// let config = Config::default();
|
||||
/// config.clocks = ClockConfig::manual_pll(
|
||||
/// 12_000_000,
|
||||
/// PllConfig {
|
||||
/// refdiv: 1, // Reference divider (12 MHz / 1 = 12 MHz)
|
||||
/// fbdiv: 100, // Feedback divider (12 MHz * 100 = 1200 MHz VCO)
|
||||
/// post_div1: 3, // First post divider (1200 MHz / 3 = 400 MHz)
|
||||
/// post_div2: 2, // Second post divider (400 MHz / 2 = 200 MHz)
|
||||
/// },
|
||||
/// Some(VoltageScale::V1_15)
|
||||
/// );
|
||||
/// ```
|
||||
#[cfg(feature = "rp2040")]
|
||||
pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, voltage_scale: Option<VoltageScale>) -> Self {
|
||||
// Calculate the actual output frequency for documentation
|
||||
// let ref_freq = xosc_hz / pll_config.refdiv as u32;
|
||||
// let vco_freq = ref_freq * pll_config.fbdiv as u32;
|
||||
// let sys_freq = vco_freq / ((pll_config.post_div1 * pll_config.post_div2) as u32);
|
||||
|
||||
// Validate PLL parameters
|
||||
assert!(pll_config.is_valid(xosc_hz), "Invalid PLL parameters");
|
||||
|
||||
let mut config = Self::default();
|
||||
|
||||
config.xosc = Some(XoscConfig {
|
||||
hz: xosc_hz,
|
||||
sys_pll: Some(pll_config),
|
||||
usb_pll: Some(PllConfig {
|
||||
refdiv: 1,
|
||||
fbdiv: 120,
|
||||
post_div1: 6,
|
||||
post_div2: 5,
|
||||
}),
|
||||
delay_multiplier: 128,
|
||||
});
|
||||
|
||||
config.ref_clk = RefClkConfig {
|
||||
src: RefClkSrc::Xosc,
|
||||
div: 1,
|
||||
};
|
||||
|
||||
config.sys_clk = SysClkConfig {
|
||||
src: SysClkSrc::PllSys,
|
||||
div_int: 1,
|
||||
div_frac: 0,
|
||||
};
|
||||
|
||||
config.voltage_scale = voltage_scale;
|
||||
config.peri_clk_src = Some(PeriClkSrc::Sys);
|
||||
|
||||
// Set reasonable defaults for other clocks
|
||||
config.usb_clk = Some(UsbClkConfig {
|
||||
src: UsbClkSrc::PllUsb,
|
||||
div: 1,
|
||||
phase: 0,
|
||||
});
|
||||
|
||||
config.adc_clk = Some(AdcClkConfig {
|
||||
src: AdcClkSrc::PllUsb,
|
||||
div: 1,
|
||||
phase: 0,
|
||||
});
|
||||
|
||||
config.rtc_clk = Some(RtcClkConfig {
|
||||
src: RtcClkSrc::PllUsb,
|
||||
div_int: 1024,
|
||||
div_frac: 0,
|
||||
phase: 0,
|
||||
});
|
||||
|
||||
config
|
||||
}
|
||||
}
|
||||
|
||||
/// ROSC freq range.
|
||||
@ -596,30 +657,6 @@ pub struct XoscConfig {
|
||||
}
|
||||
|
||||
/// PLL configuration.
|
||||
///
|
||||
/// This struct defines the parameters used to configure the Phase-Locked Loop (PLL)
|
||||
/// in the RP2040. The parameters follow the definitions from the RP2040 datasheet,
|
||||
/// section 2.18.3.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `refdiv` - Reference divider (1-63)
|
||||
/// * `fbdiv` - VCO feedback divider (16-320)
|
||||
/// * `post_div1` - First post divider (1-7)
|
||||
/// * `post_div2` - Second post divider (1-7) - must be less than or equal to post_div1
|
||||
///
|
||||
/// # Constraints
|
||||
///
|
||||
/// * VCO frequency (input_hz / refdiv * fbdiv) must be between 750MHz and 1800MHz
|
||||
/// * post_div2 must be less than or equal to post_div1
|
||||
///
|
||||
/// # Calculation
|
||||
///
|
||||
/// The output frequency of the PLL is calculated as:
|
||||
///
|
||||
/// `output_hz = (input_hz / refdiv * fbdiv) / (post_div1 * post_div2)`
|
||||
///
|
||||
/// Where input_hz is typically the crystal frequency (e.g., 12MHz).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct PllConfig {
|
||||
/// Reference divisor.
|
||||
@ -836,35 +873,17 @@ pub struct RtcClkConfig {
|
||||
/// * `Some(PllConfig)` if valid parameters were found
|
||||
/// * `None` if no valid parameters could be found for the requested combination
|
||||
///
|
||||
/// # Algorithm
|
||||
///
|
||||
/// 1. Set reference divider to 1 (fixed for simplicity)
|
||||
/// 2. Try different feedback divisors (fbdiv) starting from highest to lowest
|
||||
/// 3. For each fbdiv value, check if the resulting VCO frequency is valid (750-1800MHz)
|
||||
/// 4. Find post-divider combinations that give the exact requested frequency
|
||||
/// 5. If no exact match, return the closest approximation
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// // Find parameters for 133MHz system clock from 12MHz crystal
|
||||
/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// Similar to the Pico SDK's parameter selection approach, prioritizing stability.
|
||||
/// See RP2040 Datasheet section 2.16.3. Reference Clock (ref) and 2.18.3. PLL
|
||||
#[cfg(feature = "rp2040")]
|
||||
fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> {
|
||||
// Fixed reference divider for system PLL
|
||||
const PLL_SYS_REFDIV: u8 = 1;
|
||||
|
||||
// Constraints from datasheet:
|
||||
// REFDIV: 1..=63
|
||||
// FBDIV: 16..=320
|
||||
// POSTDIV1: 1..=7
|
||||
// POSTDIV2: 1..=7 (must be <= POSTDIV1)
|
||||
// VCO frequency (input_hz / refdiv * fbdiv): 750MHz ..= 1800MHz
|
||||
|
||||
// Calculate reference frequency
|
||||
let reference_freq = input_hz / PLL_SYS_REFDIV as u32;
|
||||
|
||||
@ -969,8 +988,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
#[cfg(feature = "_rp235x")]
|
||||
while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {}
|
||||
|
||||
// Set Core Voltage (RP2040 only) BEFORE doing anything with PLLs
|
||||
// This is critical for overclocking - must be done before PLL setup
|
||||
// Set Core Voltage (RP2040 only), if we have config for it and we're not using the default
|
||||
#[cfg(feature = "rp2040")]
|
||||
if let Some(voltage) = config.voltage_scale {
|
||||
let vreg = pac::VREG_AND_CHIP_RESET;
|
||||
@ -978,17 +996,15 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
let target_vsel = voltage as u8;
|
||||
|
||||
if target_vsel != current_vsel {
|
||||
// IMPORTANT: Use modify() instead of write() to preserve the HIZ and EN bits
|
||||
// This is critical - otherwise we might disable the regulator when changing voltage
|
||||
// Use modify() instead of write() 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));
|
||||
|
||||
// For higher voltage settings (overclocking), we need a longer stabilization time
|
||||
// Default to 1000 µs (1ms) like the SDK, but allow user override
|
||||
// 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(|| {
|
||||
match voltage {
|
||||
VoltageScale::V1_15 => 1000, // 1ms for 1.15V (matches SDK default)
|
||||
VoltageScale::V1_15 => 1000, // 1ms for 1.15V
|
||||
VoltageScale::V1_20 | VoltageScale::V1_25 | VoltageScale::V1_30 => 2000, // 2ms for higher voltages
|
||||
_ => 500, // 500 µs for standard voltages
|
||||
_ => 0, // no delay for all others
|
||||
}
|
||||
});
|
||||
|
||||
@ -1001,7 +1017,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
// Wait for voltage to stabilize
|
||||
cortex_m::asm::delay(delay_cycles);
|
||||
|
||||
// Only NOW set the BOD level after voltage has stabilized
|
||||
// Only now set the BOD level after voltage has stabilized
|
||||
vreg.bod().write(|w| w.set_vsel(voltage.recommended_bod()));
|
||||
}
|
||||
}
|
||||
@ -1026,9 +1042,9 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
// SETUP TEMPORARY STABLE CLOCKS FIRST
|
||||
// Configure USB PLL for our stable temporary clock
|
||||
// This follows the SDK's approach of using USB PLL as a stable intermediate clock
|
||||
let usb_pll_freq = match &config.xosc {
|
||||
let pll_usb_freq = match &config.xosc {
|
||||
Some(config) => match &config.usb_pll {
|
||||
Some(usb_pll_config) => {
|
||||
Some(pll_usb_config) => {
|
||||
// Reset USB PLL
|
||||
let mut peris = reset::Peripherals(0);
|
||||
peris.set_pll_usb(true);
|
||||
@ -1036,7 +1052,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
reset::unreset_wait(peris);
|
||||
|
||||
// Configure the USB PLL - this should give us 48MHz
|
||||
let usb_pll_freq = configure_pll(pac::PLL_USB, xosc_freq, *usb_pll_config);
|
||||
let usb_pll_freq = configure_pll(pac::PLL_USB, xosc_freq, *pll_usb_config);
|
||||
CLOCKS.pll_usb.store(usb_pll_freq, Ordering::Relaxed);
|
||||
usb_pll_freq
|
||||
}
|
||||
@ -1122,7 +1138,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
let (src, aux, freq) = match config.sys_clk.src {
|
||||
SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS, clk_ref_freq),
|
||||
SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS, pll_sys_freq),
|
||||
SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, usb_pll_freq),
|
||||
SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq),
|
||||
SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq),
|
||||
SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq),
|
||||
// SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq),
|
||||
@ -1185,7 +1201,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
let peri_freq = match src {
|
||||
PeriClkSrc::Sys => clk_sys_freq,
|
||||
PeriClkSrc::PllSys => pll_sys_freq,
|
||||
PeriClkSrc::PllUsb => usb_pll_freq,
|
||||
PeriClkSrc::PllUsb => pll_usb_freq,
|
||||
PeriClkSrc::Rosc => rosc_freq,
|
||||
PeriClkSrc::Xosc => xosc_freq,
|
||||
// PeriClkSrc::Gpin0 => gpin0_freq,
|
||||
@ -1210,7 +1226,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
w.set_auxsrc(ClkUsbCtrlAuxsrc::from_bits(conf.src as _));
|
||||
});
|
||||
let usb_freq = match conf.src {
|
||||
UsbClkSrc::PllUsb => usb_pll_freq,
|
||||
UsbClkSrc::PllUsb => pll_usb_freq,
|
||||
UsbClkSrc::PllSys => pll_sys_freq,
|
||||
UsbClkSrc::Rosc => rosc_freq,
|
||||
UsbClkSrc::Xosc => xosc_freq,
|
||||
@ -1234,7 +1250,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
w.set_auxsrc(ClkAdcCtrlAuxsrc::from_bits(conf.src as _));
|
||||
});
|
||||
let adc_in_freq = match conf.src {
|
||||
AdcClkSrc::PllUsb => usb_pll_freq,
|
||||
AdcClkSrc::PllUsb => pll_usb_freq,
|
||||
AdcClkSrc::PllSys => pll_sys_freq,
|
||||
AdcClkSrc::Rosc => rosc_freq,
|
||||
AdcClkSrc::Xosc => xosc_freq,
|
||||
@ -1262,7 +1278,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
||||
w.set_auxsrc(ClkRtcCtrlAuxsrc::from_bits(conf.src as _));
|
||||
});
|
||||
let rtc_in_freq = match conf.src {
|
||||
RtcClkSrc::PllUsb => usb_pll_freq,
|
||||
RtcClkSrc::PllUsb => pll_usb_freq,
|
||||
RtcClkSrc::PllSys => pll_sys_freq,
|
||||
RtcClkSrc::Rosc => rosc_freq,
|
||||
RtcClkSrc::Xosc => xosc_freq,
|
||||
@ -1390,40 +1406,36 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
|
||||
while !pac::XOSC.status().read().stable() {}
|
||||
}
|
||||
|
||||
/// PLL (Phase-Locked Loop) configuration
|
||||
#[inline(always)]
|
||||
fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
|
||||
// Calculate reference frequency
|
||||
let ref_freq = input_freq / config.refdiv as u32;
|
||||
|
||||
// Validate PLL parameters
|
||||
assert!(
|
||||
config.fbdiv >= 16 && config.fbdiv <= 320,
|
||||
"fbdiv must be between 16 and 320"
|
||||
);
|
||||
assert!(
|
||||
config.post_div1 >= 1 && config.post_div1 <= 7,
|
||||
"post_div1 must be between 1 and 7"
|
||||
);
|
||||
assert!(
|
||||
config.post_div2 >= 1 && config.post_div2 <= 7,
|
||||
"post_div2 must be between 1 and 7"
|
||||
);
|
||||
assert!(config.post_div2 <= config.post_div1, "post_div2 must be <= post_div1");
|
||||
assert!(
|
||||
config.refdiv >= 1 && config.refdiv <= 63,
|
||||
"refdiv must be between 1 and 63"
|
||||
);
|
||||
assert!(
|
||||
ref_freq >= 5_000_000 && ref_freq <= 800_000_000,
|
||||
"ref_freq must be between 5MHz and 800MHz"
|
||||
);
|
||||
// Feedback divider (FBDIV) must be between 16 and 320
|
||||
assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
|
||||
|
||||
// Post divider 1 (POSTDIV1) must be between 1 and 7
|
||||
assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
|
||||
|
||||
// Post divider 2 (POSTDIV2) must be between 1 and 7
|
||||
assert!(config.post_div2 >= 1 && config.post_div2 <= 7);
|
||||
|
||||
// Post divider 2 (POSTDIV2) must be less than or equal to post divider 1 (POSTDIV1)
|
||||
assert!(config.post_div2 <= config.post_div1);
|
||||
|
||||
// Reference divider (REFDIV) must be between 1 and 63
|
||||
assert!(config.refdiv >= 1 && config.refdiv <= 63);
|
||||
|
||||
// Reference frequency (REF_FREQ) must be between 5MHz and 800MHz
|
||||
assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000);
|
||||
|
||||
// Calculate VCO frequency
|
||||
let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32);
|
||||
assert!(
|
||||
vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000,
|
||||
"VCO frequency must be between 750MHz and 1800MHz"
|
||||
);
|
||||
|
||||
// VCO (Voltage Controlled Oscillator) frequency must be between 750MHz and 1800MHz
|
||||
assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000);
|
||||
|
||||
// We follow the SDK's approach to PLL configuration which is:
|
||||
// 1. Power down PLL
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
//! # Overclocking the RP2040 to 200 MHz
|
||||
//!
|
||||
//! This example demonstrates how to configure the RP2040 to run at 200 MHz using a higher level API.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::clocks::{clk_sys_freq, ClockConfig, VoltageScale};
|
||||
use embassy_rp::clocks::{clk_sys_freq, ClockConfig};
|
||||
use embassy_rp::config::Config;
|
||||
use embassy_rp::gpio::{Level, Output};
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
@ -15,15 +19,10 @@ const COUNT_TO: i64 = 10_000_000;
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
// Set up for clock frequency of 200 MHz
|
||||
// This will set all the necessary defaults including slightly raised voltage
|
||||
// See embassy_rp::clocks::ClockConfig for more options, including full manual control
|
||||
let config = Config::new(ClockConfig::at_sys_frequency_mhz(200));
|
||||
|
||||
// Show the voltage scale and brownout-detection for verification
|
||||
// Show the voltage scale for verification
|
||||
info!("System core voltage: {}", Debug2Format(&config.clocks.voltage_scale));
|
||||
// info!(
|
||||
// "Brownout detection: {}",
|
||||
// Debug2Format(&config.clocks.brownout_detection)
|
||||
// );
|
||||
|
||||
// Initialize the peripherals
|
||||
let p = embassy_rp::init(config);
|
||||
@ -64,14 +63,3 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
}
|
||||
}
|
||||
|
||||
// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage(125, Some(VoltageScale::V1_10)));
|
||||
// let config = Config::default();
|
||||
// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage_extended_delay(
|
||||
// 200, // Standard 125MHz clock
|
||||
// Some(VoltageScale::V1_15), // 1.15V voltage
|
||||
// Some(1000), // 1000μs (1ms) stabilization delay - significantly longer than default
|
||||
// ));
|
||||
// Initialize the peripherals
|
||||
|
||||
// let p = embassy_rp::init(Default::default()); //testing the bog standard
|
||||
|
||||
81
examples/rp/src/bin/overclock_manual.rs
Normal file
81
examples/rp/src/bin/overclock_manual.rs
Normal file
@ -0,0 +1,81 @@
|
||||
//! # Overclocking the RP2040 to 200 MHz manually
|
||||
//!
|
||||
//! This example demonstrates how to manually configure the RP2040 to run at 200 MHz.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::clocks;
|
||||
use embassy_rp::clocks::{ClockConfig, PllConfig, VoltageScale};
|
||||
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;
|
||||
|
||||
/// Configure the RP2040 for 200 MHz operation by manually specifying
|
||||
/// all the required parameters instead of using higher-level APIs.
|
||||
fn configure_manual_overclock() -> Config {
|
||||
// Set the PLL configuration manually, starting from default values
|
||||
let mut config = Config::default();
|
||||
|
||||
// Set the system clock to 200 MHz using a PLL with a reference frequency of 12 MHz
|
||||
config.clocks = ClockConfig::manual_pll(
|
||||
12_000_000,
|
||||
PllConfig {
|
||||
refdiv: 1,
|
||||
fbdiv: 100,
|
||||
post_div1: 3,
|
||||
post_div2: 2,
|
||||
},
|
||||
// For 200 MHz, we need a voltage scale of 1.15V
|
||||
Some(VoltageScale::V1_15),
|
||||
);
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
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();
|
||||
info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user