aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/clocks.rs324
-rw-r--r--examples/rp/src/bin/overclock.rs11
-rw-r--r--examples/rp/src/bin/overclock_manual.rs20
-rw-r--r--tests/rp/src/bin/overclock.rs10
4 files changed, 134 insertions, 231 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 005564b8b..107e499b7 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -9,9 +9,8 @@
9//! 9//!
10//! For most users, these functions provide an easy way to configure clocks: 10//! For most users, these functions provide an easy way to configure clocks:
11//! 11//!
12//! - `ClockConfig::crystal(12_000_000)` - Default configuration with 12MHz crystal giving 125MHz system clock
13//! - `ClockConfig::at_sys_frequency_mhz(200)` - Set system clock to a specific frequency with automatic voltage scaling 12//! - `ClockConfig::at_sys_frequency_mhz(200)` - Set system clock to a specific frequency with automatic voltage scaling
14//! - `ClockConfig::with_external_crystal(16_000_000)` - Configure with a non-standard crystal frequency 13//! - `ClockConfig::crystal(12_000_000)` - Default configuration with 12MHz crystal giving 125MHz system clock
15//! 14//!
16//! ## Manual Configuration 15//! ## Manual Configuration
17//! 16//!
@@ -34,19 +33,9 @@
34//! }); 33//! });
35//! 34//!
36//! // Set voltage for overclocking 35//! // Set voltage for overclocking
37//! config.voltage_scale = Some(VoltageScale::V1_15); 36//! config.core_voltage = CoreVoltage::V1_15;
38//! ``` 37//! ```
39//! 38//!
40//! ## Voltage Scaling for Overclocking (RP2040 only)
41//!
42//! When overclocking beyond 133MHz, higher core voltages are needed:
43//!
44//! - Up to 133MHz: `VoltageScale::V1_10` (default)
45//! - 133-200MHz: `VoltageScale::V1_15`
46//! - Above 200MHz: `VoltageScale::V1_20` or higher
47//!
48//! The `at_sys_frequency_mhz()` function automatically sets appropriate voltages.
49//!
50//! ## Examples 39//! ## Examples
51//! 40//!
52//! ### Standard 125MHz configuration 41//! ### Standard 125MHz configuration
@@ -61,16 +50,16 @@
61//! 50//!
62//! ### Overclock to 200MHz 51//! ### Overclock to 200MHz
63//! ```rust,ignore 52//! ```rust,ignore
64//! let config = ClockConfig::at_sys_frequency_mhz(200); 53//! let config = ClockConfig::crystal_freq(200_000_000);
65//! ``` 54//! ```
66//! 55//!
67//! ### Manual configuration for advanced scenarios 56//! ### Manual configuration for advanced scenarios
68//! ```rust,ignore 57//! ```rust,ignore
69//! use embassy_rp::clocks::{ClockConfig, XoscConfig, PllConfig, VoltageScale}; 58//! use embassy_rp::clocks::{ClockConfig, XoscConfig, PllConfig, CoreVoltage};
70//! 59//!
71//! // Start with defaults and customize 60//! // Start with defaults and customize
72//! let mut config = ClockConfig::default(); 61//! let mut config = ClockConfig::default();
73//! config.voltage_scale = Some(VoltageScale::V1_15); 62//! config.core_voltage = CoreVoltage::V1_15;
74//! // Set other parameters as needed... 63//! // Set other parameters as needed...
75//! ``` 64//! ```
76 65
@@ -144,14 +133,16 @@ pub enum PeriClkSrc {
144 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , 133 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
145} 134}
146 135
147/// Core voltage scaling options for RP2040. 136/// Core voltage regulator settings for RP2040.
148/// 137///
149/// The RP2040 voltage regulator can be configured for different output voltages. 138/// The RP2040 voltage regulator can be configured for different output voltages.
150/// Higher voltages allow for higher clock frequencies but increase power consumption and heat. 139/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
151#[cfg(feature = "rp2040")] 140#[cfg(feature = "rp2040")]
152#[derive(Clone, Copy, Debug, PartialEq, Eq)] 141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
153#[repr(u8)] 142#[repr(u8)]
154pub enum VoltageScale { 143pub enum CoreVoltage {
144 /// 0.80V - Suitable for lower frequencies
145 V0_80 = 0b0000,
155 /// 0.85V 146 /// 0.85V
156 V0_85 = 0b0110, 147 V0_85 = 0b0110,
157 /// 0.90V 148 /// 0.90V
@@ -162,11 +153,11 @@ pub enum VoltageScale {
162 V1_00 = 0b1001, 153 V1_00 = 0b1001,
163 /// 1.05V 154 /// 1.05V
164 V1_05 = 0b1010, 155 V1_05 = 0b1010,
165 /// 1.10V 156 /// 1.10V - Default voltage level
166 V1_10 = 0b1011, 157 V1_10 = 0b1011,
167 /// 1.15V 158 /// 1.15V - Required for overclocking to 133-200MHz
168 V1_15 = 0b1100, 159 V1_15 = 0b1100,
169 /// 1.20V 160 /// 1.20V - Required for overclocking above 200MHz
170 V1_20 = 0b1101, 161 V1_20 = 0b1101,
171 /// 1.25V 162 /// 1.25V
172 V1_25 = 0b1110, 163 V1_25 = 0b1110,
@@ -175,21 +166,22 @@ pub enum VoltageScale {
175} 166}
176 167
177#[cfg(feature = "rp2040")] 168#[cfg(feature = "rp2040")]
178impl VoltageScale { 169impl CoreVoltage {
179 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. 170 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage.
180 /// Sets the BOD threshold to approximately 90% of the core voltage. 171 /// Sets the BOD threshold to approximately 90% of the core voltage.
181 fn recommended_bod(self) -> u8 { 172 fn recommended_bod(self) -> u8 {
182 match self { 173 match self {
183 VoltageScale::V0_85 => 0b0111, // 0.774V (~91% of 0.85V) 174 CoreVoltage::V0_80 => 0b0110, // 0.720V (~90% of 0.80V)
184 VoltageScale::V0_90 => 0b1000, // 0.817V (~91% of 0.90V) 175 CoreVoltage::V0_85 => 0b0111, // 0.774V (~91% of 0.85V)
185 VoltageScale::V0_95 => 0b1001, // 0.860V (~91% of 0.95V) 176 CoreVoltage::V0_90 => 0b1000, // 0.817V (~91% of 0.90V)
186 VoltageScale::V1_00 => 0b1010, // 0.903V (~90% of 1.00V) 177 CoreVoltage::V0_95 => 0b1001, // 0.860V (~91% of 0.95V)
187 VoltageScale::V1_05 => 0b1011, // 0.946V (~90% of 1.05V) 178 CoreVoltage::V1_00 => 0b1010, // 0.903V (~90% of 1.00V)
188 VoltageScale::V1_10 => 0b1100, // 0.989V (~90% of 1.10V) 179 CoreVoltage::V1_05 => 0b1011, // 0.946V (~90% of 1.05V)
189 VoltageScale::V1_15 => 0b1101, // 1.032V (~90% of 1.15V) 180 CoreVoltage::V1_10 => 0b1100, // 0.989V (~90% of 1.10V)
190 VoltageScale::V1_20 => 0b1110, // 1.075V (~90% of 1.20V) 181 CoreVoltage::V1_15 => 0b1101, // 1.032V (~90% of 1.15V)
191 VoltageScale::V1_25 => 0b1111, // 1.118V (~89% of 1.25V) 182 CoreVoltage::V1_20 => 0b1110, // 1.075V (~90% of 1.20V)
192 VoltageScale::V1_30 => 0b1111, // 1.118V (~86% of 1.30V) - using max available threshold 183 CoreVoltage::V1_25 => 0b1111, // 1.118V (~89% of 1.25V)
184 CoreVoltage::V1_30 => 0b1111, // 1.118V (~86% of 1.30V) - using max available threshold
193 } 185 }
194 } 186 }
195} 187}
@@ -214,9 +206,9 @@ pub struct ClockConfig {
214 /// RTC clock configuration. 206 /// RTC clock configuration.
215 #[cfg(feature = "rp2040")] 207 #[cfg(feature = "rp2040")]
216 pub rtc_clk: Option<RtcClkConfig>, 208 pub rtc_clk: Option<RtcClkConfig>,
217 /// Core voltage scaling (RP2040 only). Defaults to 1.10V if None. 209 /// Core voltage scaling (RP2040 only). Defaults to 1.10V.
218 #[cfg(feature = "rp2040")] 210 #[cfg(feature = "rp2040")]
219 pub voltage_scale: Option<VoltageScale>, 211 pub core_voltage: CoreVoltage,
220 /// Voltage stabilization delay in microseconds. 212 /// Voltage stabilization delay in microseconds.
221 /// If not set, defaults will be used based on voltage level. 213 /// If not set, defaults will be used based on voltage level.
222 #[cfg(feature = "rp2040")] 214 #[cfg(feature = "rp2040")]
@@ -255,7 +247,7 @@ impl Default for ClockConfig {
255 #[cfg(feature = "rp2040")] 247 #[cfg(feature = "rp2040")]
256 rtc_clk: None, 248 rtc_clk: None,
257 #[cfg(feature = "rp2040")] 249 #[cfg(feature = "rp2040")]
258 voltage_scale: None, 250 core_voltage: CoreVoltage::V1_10,
259 #[cfg(feature = "rp2040")] 251 #[cfg(feature = "rp2040")]
260 voltage_stabilization_delay_us: None, 252 voltage_stabilization_delay_us: None,
261 // gpin0: None, 253 // gpin0: None,
@@ -327,7 +319,7 @@ impl ClockConfig {
327 phase: 0, 319 phase: 0,
328 }), 320 }),
329 #[cfg(feature = "rp2040")] 321 #[cfg(feature = "rp2040")]
330 voltage_scale: None, // Use hardware default (1.10V) 322 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
331 #[cfg(feature = "rp2040")] 323 #[cfg(feature = "rp2040")]
332 voltage_stabilization_delay_us: None, 324 voltage_stabilization_delay_us: None,
333 // gpin0: None, 325 // gpin0: None,
@@ -371,7 +363,7 @@ impl ClockConfig {
371 phase: 0, 363 phase: 0,
372 }), 364 }),
373 #[cfg(feature = "rp2040")] 365 #[cfg(feature = "rp2040")]
374 voltage_scale: None, // Use hardware default (1.10V) 366 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
375 #[cfg(feature = "rp2040")] 367 #[cfg(feature = "rp2040")]
376 voltage_stabilization_delay_us: None, 368 voltage_stabilization_delay_us: None,
377 // gpin0: None, 369 // gpin0: None,
@@ -379,146 +371,59 @@ impl ClockConfig {
379 } 371 }
380 } 372 }
381 373
382 /// Configure the system clock to a specific frequency in MHz.
383 ///
384 /// This is a user-friendly way to configure the system clock, similar to
385 /// the Pico SDK's approach. It automatically handles voltage scaling based on the
386 /// requested frequency and uses the standard 12MHz crystal found on most RP2040 boards.
387 ///
388 /// # Arguments
389 ///
390 /// * `sys_freq_mhz` - The target system clock frequency in MHz
391 ///
392 /// # Example
393 ///
394 /// ```rust,ignore
395 /// // Overclock to 200MHz
396 /// let config = ClockConfig::at_sys_frequency_mhz(200);
397 /// ```
398 #[cfg(feature = "rp2040")]
399 pub fn at_sys_frequency_mhz(sys_freq_mhz: u32) -> Self {
400 // For 125MHz, use exactly the same config as the default to avoid any differences
401 if sys_freq_mhz == 125 {
402 return Self::crystal(12_000_000);
403 }
404
405 // For other frequencies, provide appropriate voltage scaling and PLL configuration
406 // Standard crystal on Raspberry Pi Pico boards is 12MHz
407 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000;
408
409 let sys_freq_hz = sys_freq_mhz * 1_000_000;
410 let config = Self::crystal_freq(DEFAULT_CRYSTAL_HZ, sys_freq_hz);
411
412 config
413 }
414
415 /// Configure the system clock to a specific frequency in Hz, using a custom crystal frequency.
416 ///
417 /// This more flexible version allows specifying both the crystal frequency and target
418 /// system frequency for boards with non-standard crystals.
419 ///
420 /// # Arguments
421 ///
422 /// * `crystal_hz` - The frequency of the external crystal in Hz
423 /// * `sys_freq_hz` - The target system clock frequency in Hz
424 ///
425 /// # Example
426 ///
427 /// ```rust,ignore
428 /// // Use a non-standard 16MHz crystal to achieve 250MHz
429 /// let config = ClockConfig::with_custom_crystal(16_000_000, 250_000_000);
430 /// ```
431 #[cfg(feature = "rp2040")]
432 pub fn with_custom_crystal(crystal_hz: u32, sys_freq_hz: u32) -> Self {
433 Self::crystal_freq(crystal_hz, sys_freq_hz)
434 }
435
436 /// Configure clocks derived from an external crystal with specific system frequency. 374 /// Configure clocks derived from an external crystal with specific system frequency.
437 /// 375 ///
438 /// This function calculates optimal PLL parameters to achieve the requested system 376 /// This function calculates optimal PLL parameters to achieve the requested system
439 /// frequency from the given crystal frequency. It's used internally by higher-level 377 /// frequency. This only works for the usual 12MHz crystal. In case a different crystal is used,
440 /// configuration functions. 378 /// You will have to set the PLL parameters manually.
441 /// 379 ///
442 /// # Arguments 380 /// # Arguments
443 /// 381 ///
444 /// * `crystal_hz` - The frequency of the external crystal in Hz
445 /// * `sys_freq_hz` - The desired system clock frequency in Hz 382 /// * `sys_freq_hz` - The desired system clock frequency in Hz
446 /// 383 ///
447 /// # Returns 384 /// # Returns
448 /// 385 ///
449 /// A ClockConfig configured to achieve the requested system frequency using the 386 /// A ClockConfig configured to achieve the requested system frequency using the
450 /// specified crystal, or panic if no valid parameters can be found. 387 /// the usual 12Mhz crystal, or panic if no valid parameters can be found.
388 ///
389 /// # Note on core voltage:
390 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are:
391 /// - Up to 133MHz: V1_10 (default)
392 /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz
393 /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here.
394 /// 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.
451 #[cfg(feature = "rp2040")] 395 #[cfg(feature = "rp2040")]
452 fn crystal_freq(crystal_hz: u32, sys_freq_hz: u32) -> Self { 396 pub fn crystal_freq(sys_freq_hz: u32) -> Self {
397 // Start with the standard configuration from crystal()
398 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000;
399 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ);
400
401 // No need to modify anything if target frequency is already 125MHz
402 // (which is what crystal() configures by default)
403 if sys_freq_hz == 125_000_000 {
404 return config;
405 }
406
453 // Find optimal PLL parameters for the requested frequency 407 // Find optimal PLL parameters for the requested frequency
454 let sys_pll_params = find_pll_params(crystal_hz, sys_freq_hz) 408 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, sys_freq_hz)
455 .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock")); 409 .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock"));
456 410
411 // Replace the sys_pll configuration with our custom parameters
412 if let Some(xosc) = &mut config.xosc {
413 xosc.sys_pll = Some(sys_pll_params);
414 }
415
457 // Set the voltage scale based on the target frequency 416 // Set the voltage scale based on the target frequency
458 // Higher frequencies require higher voltage 417 // Higher frequencies require higher voltage
459 let voltage_scale = match sys_freq_hz { 418 #[cfg(feature = "rp2040")]
460 freq if freq > 200_000_000 => Some(VoltageScale::V1_20), 419 {
461 freq if freq > 133_000_000 => Some(VoltageScale::V1_15), 420 config.core_voltage = match sys_freq_hz {
462 _ => None, // Use default voltage (V1_10) 421 freq if freq > 133_000_000 => CoreVoltage::V1_15,
463 }; 422 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
464 423 };
465 // For USB PLL, we always want 48MHz for USB
466 let usb_pll_params = if crystal_hz == 12_000_000 {
467 // For standard 12MHz crystal, use the default parameters
468 PllConfig {
469 refdiv: 1,
470 fbdiv: 120,
471 post_div1: 6,
472 post_div2: 5,
473 }
474 } else {
475 // For other crystals, calculate parameters to get 48MHz
476 find_pll_params(crystal_hz, 48_000_000)
477 .unwrap_or_else(|| panic!("Could not find valid PLL parameters for USB clock"))
478 };
479
480 Self {
481 rosc: Some(RoscConfig {
482 hz: 6_500_000,
483 range: RoscRange::Medium,
484 drive_strength: [0; 8],
485 div: 16,
486 }),
487 xosc: Some(XoscConfig {
488 hz: crystal_hz,
489 sys_pll: Some(sys_pll_params),
490 usb_pll: Some(usb_pll_params),
491 delay_multiplier: 128,
492 }),
493 ref_clk: RefClkConfig {
494 src: RefClkSrc::Xosc,
495 div: 1,
496 },
497 sys_clk: SysClkConfig {
498 src: SysClkSrc::PllSys,
499 div_int: 1,
500 div_frac: 0,
501 },
502 peri_clk_src: Some(PeriClkSrc::Sys),
503 usb_clk: Some(UsbClkConfig {
504 src: UsbClkSrc::PllUsb,
505 div: 1,
506 phase: 0,
507 }),
508 adc_clk: Some(AdcClkConfig {
509 src: AdcClkSrc::PllUsb,
510 div: 1,
511 phase: 0,
512 }),
513 rtc_clk: Some(RtcClkConfig {
514 src: RtcClkSrc::PllUsb,
515 div_int: 1024,
516 div_frac: 0,
517 phase: 0,
518 }),
519 voltage_scale,
520 voltage_stabilization_delay_us: None,
521 } 424 }
425
426 config
522 } 427 }
523 428
524 /// Configure with manual PLL settings for full control over system clock 429 /// Configure with manual PLL settings for full control over system clock
@@ -530,7 +435,7 @@ impl ClockConfig {
530 /// 435 ///
531 /// * `xosc_hz` - The frequency of the external crystal in Hz 436 /// * `xosc_hz` - The frequency of the external crystal in Hz
532 /// * `pll_config` - The PLL configuration parameters to achieve desired frequency 437 /// * `pll_config` - The PLL configuration parameters to achieve desired frequency
533 /// * `voltage_scale` - Optional voltage scaling for overclocking (required for >133MHz) 438 /// * `core_voltage` - Voltage scaling for overclocking (required for >133MHz)
534 /// 439 ///
535 /// # Returns 440 /// # Returns
536 /// 441 ///
@@ -549,11 +454,11 @@ impl ClockConfig {
549 /// post_div1: 3, // First post divider (1200 MHz / 3 = 400 MHz) 454 /// post_div1: 3, // First post divider (1200 MHz / 3 = 400 MHz)
550 /// post_div2: 2, // Second post divider (400 MHz / 2 = 200 MHz) 455 /// post_div2: 2, // Second post divider (400 MHz / 2 = 200 MHz)
551 /// }, 456 /// },
552 /// Some(VoltageScale::V1_15) 457 /// CoreVoltage::V1_15
553 /// ); 458 /// );
554 /// ``` 459 /// ```
555 #[cfg(feature = "rp2040")] 460 #[cfg(feature = "rp2040")]
556 pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, voltage_scale: Option<VoltageScale>) -> Self { 461 pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, core_voltage: CoreVoltage) -> Self {
557 // Calculate the actual output frequency for documentation 462 // Calculate the actual output frequency for documentation
558 // let ref_freq = xosc_hz / pll_config.refdiv as u32; 463 // let ref_freq = xosc_hz / pll_config.refdiv as u32;
559 // let vco_freq = ref_freq * pll_config.fbdiv as u32; 464 // let vco_freq = ref_freq * pll_config.fbdiv as u32;
@@ -587,7 +492,7 @@ impl ClockConfig {
587 div_frac: 0, 492 div_frac: 0,
588 }; 493 };
589 494
590 config.voltage_scale = voltage_scale; 495 config.core_voltage = core_voltage;
591 config.peri_clk_src = Some(PeriClkSrc::Sys); 496 config.peri_clk_src = Some(PeriClkSrc::Sys);
592 497
593 // Set reasonable defaults for other clocks 498 // Set reasonable defaults for other clocks
@@ -865,7 +770,7 @@ pub struct RtcClkConfig {
865/// 770///
866/// # Parameters 771/// # Parameters
867/// 772///
868/// * `input_hz`: The input frequency in Hz (typically the crystal frequency, e.g. 12MHz) 773/// * `input_hz`: The input frequency in Hz (typically the crystal frequency, e.g. 12MHz for th most common one used on rp2040 boards)
869/// * `target_hz`: The desired output frequency in Hz (e.g. 125MHz for standard RP2040 operation) 774/// * `target_hz`: The desired output frequency in Hz (e.g. 125MHz for standard RP2040 operation)
870/// 775///
871/// # Returns 776/// # Returns
@@ -990,7 +895,8 @@ pub(crate) unsafe fn init(config: ClockConfig) {
990 895
991 // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default 896 // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default
992 #[cfg(feature = "rp2040")] 897 #[cfg(feature = "rp2040")]
993 if let Some(voltage) = config.voltage_scale { 898 {
899 let voltage = config.core_voltage;
994 let vreg = pac::VREG_AND_CHIP_RESET; 900 let vreg = pac::VREG_AND_CHIP_RESET;
995 let current_vsel = vreg.vreg().read().vsel(); 901 let current_vsel = vreg.vreg().read().vsel();
996 let target_vsel = voltage as u8; 902 let target_vsel = voltage as u8;
@@ -1002,9 +908,9 @@ pub(crate) unsafe fn init(config: ClockConfig) {
1002 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage 908 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage
1003 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { 909 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| {
1004 match voltage { 910 match voltage {
1005 VoltageScale::V1_15 => 1000, // 1ms for 1.15V 911 CoreVoltage::V1_15 => 1000, // 1ms for 1.15V
1006 VoltageScale::V1_20 | VoltageScale::V1_25 | VoltageScale::V1_30 => 2000, // 2ms for higher voltages 912 CoreVoltage::V1_20 | CoreVoltage::V1_25 | CoreVoltage::V1_30 => 2000, // 2ms for higher voltages
1007 _ => 0, // no delay for all others 913 _ => 0, // no delay for all others
1008 } 914 }
1009 }); 915 });
1010 916
@@ -1042,9 +948,8 @@ pub(crate) unsafe fn init(config: ClockConfig) {
1042 }; 948 };
1043 CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed); 949 CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed);
1044 950
1045 // SETUP TEMPORARY STABLE CLOCKS FIRST 951 // Setup temporary stable clocks first
1046 // Configure USB PLL for our stable temporary clock 952 // Configure USB PLL for our stable temporary clock
1047 // This follows the SDK's approach of using USB PLL as a stable intermediate clock
1048 let pll_usb_freq = match &config.xosc { 953 let pll_usb_freq = match &config.xosc {
1049 Some(config) => match &config.usb_pll { 954 Some(config) => match &config.usb_pll {
1050 Some(pll_usb_config) => { 955 Some(pll_usb_config) => {
@@ -1055,7 +960,13 @@ pub(crate) unsafe fn init(config: ClockConfig) {
1055 reset::unreset_wait(peris); 960 reset::unreset_wait(peris);
1056 961
1057 // Configure the USB PLL - this should give us 48MHz 962 // Configure the USB PLL - this should give us 48MHz
1058 let usb_pll_freq = configure_pll(pac::PLL_USB, xosc_freq, *pll_usb_config); 963 let usb_pll_freq = match configure_pll(pac::PLL_USB, xosc_freq, *pll_usb_config) {
964 Ok(freq) => freq,
965 Err(_) => {
966 panic!("Failed to configure USB PLL");
967 }
968 };
969
1059 CLOCKS.pll_usb.store(usb_pll_freq, Ordering::Relaxed); 970 CLOCKS.pll_usb.store(usb_pll_freq, Ordering::Relaxed);
1060 usb_pll_freq 971 usb_pll_freq
1061 } 972 }
@@ -1074,7 +985,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
1074 while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ClkRefCtrlSrc::XOSC_CLKSRC as u32) {} 985 while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ClkRefCtrlSrc::XOSC_CLKSRC as u32) {}
1075 986
1076 // First switch the system clock to a stable source (USB PLL at 48MHz) 987 // First switch the system clock to a stable source (USB PLL at 48MHz)
1077 // This follows the Pico SDK's approach to ensure stability during reconfiguration 988 // This follows the official Pico SDK's approach to ensure stability during reconfiguration
1078 c.clk_sys_ctrl().write(|w| { 989 c.clk_sys_ctrl().write(|w| {
1079 w.set_auxsrc(ClkSysCtrlAuxsrc::CLKSRC_PLL_USB); 990 w.set_auxsrc(ClkSysCtrlAuxsrc::CLKSRC_PLL_USB);
1080 w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); 991 w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX);
@@ -1101,7 +1012,12 @@ pub(crate) unsafe fn init(config: ClockConfig) {
1101 reset::unreset_wait(peris); 1012 reset::unreset_wait(peris);
1102 1013
1103 // Configure the SYS PLL 1014 // Configure the SYS PLL
1104 let pll_sys_freq = configure_pll(pac::PLL_SYS, xosc_freq, *sys_pll_config); 1015 let pll_sys_freq = match configure_pll(pac::PLL_SYS, xosc_freq, *sys_pll_config) {
1016 Ok(freq) => freq,
1017 Err(_) => {
1018 panic!("Failed to configure system PLL");
1019 }
1020 };
1105 1021
1106 // Ensure PLL is locked and stable 1022 // Ensure PLL is locked and stable
1107 cortex_m::asm::delay(100); 1023 cortex_m::asm::delay(100);
@@ -1411,7 +1327,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
1411 1327
1412/// PLL (Phase-Locked Loop) configuration 1328/// PLL (Phase-Locked Loop) configuration
1413#[inline(always)] 1329#[inline(always)]
1414fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { 1330fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, &'static str> {
1415 // Calculate reference frequency 1331 // Calculate reference frequency
1416 let ref_freq = input_freq / config.refdiv as u32; 1332 let ref_freq = input_freq / config.refdiv as u32;
1417 1333
@@ -1482,7 +1398,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
1482 timeout -= 1; 1398 timeout -= 1;
1483 if timeout == 0 { 1399 if timeout == 0 {
1484 // PLL failed to lock, return 0 to indicate failure 1400 // PLL failed to lock, return 0 to indicate failure
1485 return 0; 1401 return Err("PLL failed to lock");
1486 } 1402 }
1487 } 1403 }
1488 1404
@@ -1502,7 +1418,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
1502 cortex_m::asm::delay(100); 1418 cortex_m::asm::delay(100);
1503 1419
1504 // Calculate and return actual output frequency 1420 // Calculate and return actual output frequency
1505 vco_freq / ((config.post_div1 * config.post_div2) as u32) 1421 Ok(vco_freq / ((config.post_div1 * config.post_div2) as u32))
1506} 1422}
1507 1423
1508/// General purpose input clock pin. 1424/// General purpose input clock pin.
@@ -1885,25 +1801,6 @@ mod tests {
1885 1801
1886 #[cfg(feature = "rp2040")] 1802 #[cfg(feature = "rp2040")]
1887 #[test] 1803 #[test]
1888 fn test_voltage_scale_bod_values() {
1889 // Test that each voltage level maps to the correct BOD threshold (approx. 90% of VDD)
1890 // This verifies our BOD settings match our documentation
1891 {
1892 assert_eq!(VoltageScale::V0_85.recommended_bod(), 0b0111); // ~0.774V (91% of 0.85V)
1893 assert_eq!(VoltageScale::V0_90.recommended_bod(), 0b1000); // ~0.817V (91% of 0.90V)
1894 assert_eq!(VoltageScale::V0_95.recommended_bod(), 0b1001); // ~0.860V (91% of 0.95V)
1895 assert_eq!(VoltageScale::V1_00.recommended_bod(), 0b1010); // ~0.903V (90% of 1.00V)
1896 assert_eq!(VoltageScale::V1_05.recommended_bod(), 0b1011); // ~0.946V (90% of 1.05V)
1897 assert_eq!(VoltageScale::V1_10.recommended_bod(), 0b1100); // ~0.989V (90% of 1.10V)
1898 assert_eq!(VoltageScale::V1_15.recommended_bod(), 0b1101); // ~1.032V (90% of 1.15V)
1899 assert_eq!(VoltageScale::V1_20.recommended_bod(), 0b1110); // ~1.075V (90% of 1.20V)
1900 assert_eq!(VoltageScale::V1_25.recommended_bod(), 0b1111); // ~1.118V (89% of 1.25V)
1901 assert_eq!(VoltageScale::V1_30.recommended_bod(), 0b1111); // ~1.118V (86% of 1.30V) - using max available
1902 }
1903 }
1904
1905 #[cfg(feature = "rp2040")]
1906 #[test]
1907 fn test_find_pll_params() { 1804 fn test_find_pll_params() {
1908 #[cfg(feature = "rp2040")] 1805 #[cfg(feature = "rp2040")]
1909 { 1806 {
@@ -1942,7 +1839,12 @@ mod tests {
1942 let vco_freq = (16_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64; 1839 let vco_freq = (16_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64;
1943 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32; 1840 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1944 1841
1945 // With a 16 MHz crystal, we might not get exactly 125 MHz 1842 // Test non-standard crystal with 15 MHz
1843 let params = find_pll_params(15_000_000, 125_000_000).unwrap();
1844 let vco_freq = (15_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64;
1845 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1846
1847 // With a 15 MHz crystal, we might not get exactly 125 MHz
1946 // Check that it's close enough (within 0.2% margin) 1848 // Check that it's close enough (within 0.2% margin)
1947 let freq_diff = if output_freq > 125_000_000 { 1849 let freq_diff = if output_freq > 125_000_000 {
1948 output_freq - 125_000_000 1850 output_freq - 125_000_000
@@ -2033,11 +1935,11 @@ mod tests {
2033 post_div1: 3, 1935 post_div1: 3,
2034 post_div2: 2, 1936 post_div2: 2,
2035 }, 1937 },
2036 Some(VoltageScale::V1_15), 1938 CoreVoltage::V1_15,
2037 ); 1939 );
2038 1940
2039 // Check voltage scale was set correctly 1941 // Check voltage scale was set correctly
2040 assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); 1942 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2041 1943
2042 // Check PLL config was set correctly 1944 // Check PLL config was set correctly
2043 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().refdiv, 1); 1945 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().refdiv, 1);
@@ -2065,19 +1967,23 @@ mod tests {
2065 fn test_auto_voltage_scaling() { 1967 fn test_auto_voltage_scaling() {
2066 { 1968 {
2067 // Test automatic voltage scaling based on frequency 1969 // Test automatic voltage scaling based on frequency
2068 // Under 133 MHz should use default voltage (None) 1970 // Under 133 MHz should use default voltage (V1_10)
2069 let config = ClockConfig::at_sys_frequency_mhz(125); 1971 let config = ClockConfig::crystal_freq(125_000_000);
2070 assert_eq!(config.voltage_scale, None); 1972 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
2071 1973
2072 // 133-200 MHz should use V1_15 1974 // 133-200 MHz should use V1_15
2073 let config = ClockConfig::at_sys_frequency_mhz(150); 1975 let config = ClockConfig::crystal_freq(150_000_000);
2074 assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); 1976 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2075 let config = ClockConfig::at_sys_frequency_mhz(200); 1977 let config = ClockConfig::crystal_freq(200_000_000);
2076 assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); 1978 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2077 1979
2078 // Above 200 MHz should use V1_20 1980 // Above 200 MHz should use V1_25
2079 let config = ClockConfig::at_sys_frequency_mhz(250); 1981 let config = ClockConfig::crystal_freq(250_000_000);
2080 assert_eq!(config.voltage_scale, Some(VoltageScale::V1_20)); 1982 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1983
1984 // Below 125 MHz should use V1_10
1985 let config = ClockConfig::crystal_freq(100_000_000);
1986 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
2081 } 1987 }
2082 } 1988 }
2083} 1989}
diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs
index e3ac77340..f9a8c94d0 100644
--- a/examples/rp/src/bin/overclock.rs
+++ b/examples/rp/src/bin/overclock.rs
@@ -1,6 +1,6 @@
1//! # Overclocking the RP2040 to 200 MHz 1//! # Overclocking the RP2040 to 200 MHz
2//! 2//!
3//! This example demonstrates how to configure the RP2040 to run at 200 MHz using a higher level API. 3//! This example demonstrates how to configure the RP2040 to run at 200 MHz.
4 4
5#![no_std] 5#![no_std]
6#![no_main] 6#![no_main]
@@ -17,19 +17,18 @@ const COUNT_TO: i64 = 10_000_000;
17 17
18#[embassy_executor::main] 18#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! { 19async fn main(_spawner: Spawner) -> ! {
20 // Set up for clock frequency of 200 MHz 20 // Set up for clock frequency of 200 MHz, setting all necessary defaults.
21 // This will set all the necessary defaults including slightly raised voltage 21 let config = Config::new(ClockConfig::crystal_freq(200_000_000));
22 let config = Config::new(ClockConfig::at_sys_frequency_mhz(200));
23 22
24 // Show the voltage scale for verification 23 // Show the voltage scale for verification
25 info!("System core voltage: {}", Debug2Format(&config.clocks.voltage_scale)); 24 info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage));
26 25
27 // Initialize the peripherals 26 // Initialize the peripherals
28 let p = embassy_rp::init(config); 27 let p = embassy_rp::init(config);
29 28
30 // Show CPU frequency for verification 29 // Show CPU frequency for verification
31 let sys_freq = clk_sys_freq(); 30 let sys_freq = clk_sys_freq();
32 info!("System clock frequency: {} Hz", sys_freq); 31 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
33 32
34 // LED to indicate the system is running 33 // LED to indicate the system is running
35 let mut led = Output::new(p.PIN_25, Level::Low); 34 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 ad6abf0e7..35160b250 100644
--- a/examples/rp/src/bin/overclock_manual.rs
+++ b/examples/rp/src/bin/overclock_manual.rs
@@ -8,7 +8,7 @@
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::clocks; 10use embassy_rp::clocks;
11use embassy_rp::clocks::{ClockConfig, PllConfig, VoltageScale}; 11use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig};
12use embassy_rp::config::Config; 12use embassy_rp::config::Config;
13use embassy_rp::gpio::{Level, Output}; 13use embassy_rp::gpio::{Level, Output};
14use embassy_time::{Duration, Instant, Timer}; 14use embassy_time::{Duration, Instant, Timer};
@@ -16,23 +16,21 @@ use {defmt_rtt as _, panic_probe as _};
16 16
17const COUNT_TO: i64 = 10_000_000; 17const COUNT_TO: i64 = 10_000_000;
18 18
19/// Configure the RP2040 for 200 MHz operation by manually specifying 19/// Configure the RP2040 for 200 MHz operation by manually specifying the PLL settings.
20/// all the required parameters instead of using higher-level APIs.
21fn configure_manual_overclock() -> Config { 20fn configure_manual_overclock() -> Config {
22 // Set the PLL configuration manually, starting from default values 21 // Set the PLL configuration manually, starting from default values
23 let mut config = Config::default(); 22 let mut config = Config::default();
24 23
25 // Set the system clock to 200 MHz using a PLL with a reference frequency of 12 MHz 24 // Set the system clock to 200 MHz
26 config.clocks = ClockConfig::manual_pll( 25 config.clocks = ClockConfig::manual_pll(
27 12_000_000, 26 12_000_000, // Crystal frequency, 12 MHz is common. If using custom, set to your value.
28 PllConfig { 27 PllConfig {
29 refdiv: 1, 28 refdiv: 1, // Reference divider
30 fbdiv: 100, 29 fbdiv: 100, // Feedback divider
31 post_div1: 3, 30 post_div1: 3, // Post divider 1
32 post_div2: 2, 31 post_div2: 2, // Post divider 2
33 }, 32 },
34 // For 200 MHz, we need a voltage scale of 1.15V 33 CoreVoltage::V1_15, // Core voltage, should be set to V1_15 for 200 MHz
35 Some(VoltageScale::V1_15),
36 ); 34 );
37 35
38 config 36 config
diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs
index e4845a55f..6c58a6b90 100644
--- a/tests/rp/src/bin/overclock.rs
+++ b/tests/rp/src/bin/overclock.rs
@@ -14,7 +14,7 @@ use embassy_rp::clocks;
14#[cfg(feature = "rp2040")] 14#[cfg(feature = "rp2040")]
15use embassy_rp::clocks::ClockConfig; 15use embassy_rp::clocks::ClockConfig;
16#[cfg(feature = "rp2040")] 16#[cfg(feature = "rp2040")]
17use embassy_rp::clocks::VoltageScale; 17use embassy_rp::clocks::CoreVoltage;
18use embassy_rp::config::Config; 18use embassy_rp::config::Config;
19use embassy_time::Instant; 19use embassy_time::Instant;
20use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
@@ -31,15 +31,15 @@ async fn main(_spawner: Spawner) {
31 // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock 31 // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock
32 #[cfg(feature = "rp2040")] 32 #[cfg(feature = "rp2040")]
33 { 33 {
34 config.clocks = ClockConfig::at_sys_frequency_mhz(200); 34 config.clocks = ClockConfig::crystal_freq(200_000_000);
35 let voltage = config.clocks.voltage_scale.unwrap(); 35 let voltage = config.clocks.core_voltage;
36 assert!(matches!(voltage, VoltageScale::V1_15), "Expected voltage scale V1_15"); 36 assert!(matches!(voltage, CoreVoltage::V1_15), "Expected voltage scale V1_15");
37 } 37 }
38 38
39 let _p = embassy_rp::init(config); 39 let _p = embassy_rp::init(config);
40 40
41 // Test the system speed
41 let (time_elapsed, clk_sys_freq) = { 42 let (time_elapsed, clk_sys_freq) = {
42 // Test the system speed
43 let mut counter = 0; 43 let mut counter = 0;
44 let start = Instant::now(); 44 let start = Instant::now();
45 while counter < COUNT_TO { 45 while counter < COUNT_TO {