aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-05-13 21:45:22 +0000
committerGitHub <[email protected]>2025-05-13 21:45:22 +0000
commit5a19b64fec396db1ababa6d3e7a71f4b3c6bab18 (patch)
tree897805aa66eb7997ea24f6ab3e7b817f45e5a7e6 /embassy-rp
parent5caa4ac51bacb8444ca6b3caafb7d0ba66e39310 (diff)
parent981ef20f83ec88601818d8c55f69a1037d57b0cb (diff)
Merge pull request #4187 from 1-rafael-1/rp235x-overclocking
RP235x overclocking
Diffstat (limited to 'embassy-rp')
-rw-r--r--embassy-rp/src/clocks.rs244
1 files changed, 207 insertions, 37 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 6694aab66..857877680 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -38,7 +38,7 @@
38//! 38//!
39//! ## Examples 39//! ## Examples
40//! 40//!
41//! ### Standard 125MHz configuration 41//! ### Standard 125MHz (rp2040) or 150Mhz (rp235x) configuration
42//! ```rust,ignore 42//! ```rust,ignore
43//! let config = ClockConfig::crystal(12_000_000); 43//! let config = ClockConfig::crystal(12_000_000);
44//! ``` 44//! ```
@@ -82,6 +82,18 @@ use crate::{pac, reset, Peri};
82// be very useful until we have runtime clock reconfiguration. once this 82// be very useful until we have runtime clock reconfiguration. once this
83// happens we can resurrect the commented-out gpin bits. 83// happens we can resurrect the commented-out gpin bits.
84 84
85/// Clock error types.
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub enum ClockError {
89 /// PLL failed to lock within the timeout period.
90 PllLockTimedOut,
91 /// Could not find valid PLL parameters for system clock.
92 InvalidPllParameters,
93 /// Reading the core voltage failed due to an unexpected value in the register.
94 UnexpectedCoreVoltageRead,
95}
96
85struct Clocks { 97struct Clocks {
86 xosc: AtomicU32, 98 xosc: AtomicU32,
87 sys: AtomicU32, 99 sys: AtomicU32,
@@ -136,15 +148,16 @@ pub enum PeriClkSrc {
136 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , 148 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
137} 149}
138 150
139/// Core voltage regulator settings for RP2040. 151/// Core voltage regulator settings.
140/// 152///
141/// The RP2040 voltage regulator can be configured for different output voltages. 153/// The voltage regulator can be configured for different output voltages.
142/// Higher voltages allow for higher clock frequencies but increase power consumption and heat. 154/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
143#[cfg(feature = "rp2040")] 155#[cfg(feature = "rp2040")]
144#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145#[repr(u8)] 156#[repr(u8)]
157#[derive(Clone, Copy, Debug, PartialEq, Eq)]
158#[cfg_attr(feature = "defmt", derive(defmt::Format))]
146pub enum CoreVoltage { 159pub enum CoreVoltage {
147 /// 0.80V - Suitable for lower frequencies 160 /// 0.80V
148 V0_80 = 0b0000, 161 V0_80 = 0b0000,
149 /// 0.85V 162 /// 0.85V
150 V0_85 = 0b0110, 163 V0_85 = 0b0110,
@@ -168,11 +181,58 @@ pub enum CoreVoltage {
168 V1_30 = 0b1111, 181 V1_30 = 0b1111,
169} 182}
170 183
171#[cfg(feature = "rp2040")] 184/// Core voltage regulator settings.
185///
186/// The voltage regulator can be configured for different output voltages.
187/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
188///
189/// **Note**: The maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit
190/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this
191/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now.
192#[cfg(feature = "_rp235x")]
193#[repr(u8)]
194#[derive(Clone, Copy, Debug, PartialEq, Eq)]
195#[cfg_attr(feature = "defmt", derive(defmt::Format))]
196pub enum CoreVoltage {
197 /// 0.55V
198 V0_55 = 0b00000,
199 /// 0.60V
200 V0_60 = 0b00001,
201 /// 0.65V
202 V0_65 = 0b00010,
203 /// 0.70V
204 V0_70 = 0b00011,
205 /// 0.75V
206 V0_75 = 0b00100,
207 /// 0.80V
208 V0_80 = 0b00101,
209 /// 0.85V
210 V0_85 = 0b00110,
211 /// 0.90V
212 V0_90 = 0b00111,
213 /// 0.95V
214 V0_95 = 0b01000,
215 /// 1.00V
216 V1_00 = 0b01001,
217 /// 1.05V
218 V1_05 = 0b01010,
219 /// 1.10V - Default voltage level
220 V1_10 = 0b01011,
221 /// 1.15V
222 V1_15 = 0b01100,
223 /// 1.20V
224 V1_20 = 0b01101,
225 /// 1.25V
226 V1_25 = 0b01110,
227 /// 1.30V
228 V1_30 = 0b01111,
229}
230
172impl CoreVoltage { 231impl CoreVoltage {
173 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. 232 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage.
174 /// Sets the BOD threshold to approximately 80% of the core voltage. 233 /// Sets the BOD threshold to approximately 80% of the core voltage.
175 fn recommended_bod(self) -> u8 { 234 fn recommended_bod(self) -> u8 {
235 #[cfg(feature = "rp2040")]
176 match self { 236 match self {
177 CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V) 237 CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V)
178 CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V) 238 CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V)
@@ -180,12 +240,32 @@ impl CoreVoltage {
180 CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V) 240 CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V)
181 CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V) 241 CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V)
182 CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V) 242 CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V)
183 CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V) 243 CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V), the default
184 CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V) 244 CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V)
185 CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V) 245 CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V)
186 CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V) 246 CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V)
187 CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V) 247 CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V)
188 } 248 }
249 #[cfg(feature = "_rp235x")]
250 match self {
251 CoreVoltage::V0_55 => 0b00001, // 0.516V (~94% of 0.55V)
252 CoreVoltage::V0_60 => 0b00010, // 0.559V (~93% of 0.60V)
253 CoreVoltage::V0_65 => 0b00011, // 0.602V (~93% of 0.65V)
254 CoreVoltage::V0_70 => 0b00011, // 0.602V (~86% of 0.70V)
255 CoreVoltage::V0_75 => 0b00100, // 0.645V (~86% of 0.75V)
256 CoreVoltage::V0_80 => 0b00101, // 0.688V (~86% of 0.80V)
257 CoreVoltage::V0_85 => 0b00110, // 0.731V (~86% of 0.85V)
258 CoreVoltage::V0_90 => 0b00110, // 0.731V (~81% of 0.90V)
259 CoreVoltage::V0_95 => 0b00111, // 0.774V (~81% of 0.95V)
260 CoreVoltage::V1_00 => 0b01000, // 0.817V (~82% of 1.00V)
261 CoreVoltage::V1_05 => 0b01000, // 0.817V (~78% of 1.05V)
262 CoreVoltage::V1_10 => 0b01001, // 0.860V (~78% of 1.10V), the default
263 CoreVoltage::V1_15 => 0b01001, // 0.860V (~75% of 1.15V)
264 CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V)
265 CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V)
266 CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V)
267 // all others: 0.946V (see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point)
268 }
189 } 269 }
190} 270}
191 271
@@ -209,12 +289,10 @@ pub struct ClockConfig {
209 /// RTC clock configuration. 289 /// RTC clock configuration.
210 #[cfg(feature = "rp2040")] 290 #[cfg(feature = "rp2040")]
211 pub rtc_clk: Option<RtcClkConfig>, 291 pub rtc_clk: Option<RtcClkConfig>,
212 /// Core voltage scaling (RP2040 only). Defaults to 1.10V. 292 /// Core voltage scaling. Defaults to 1.10V.
213 #[cfg(feature = "rp2040")]
214 pub core_voltage: CoreVoltage, 293 pub core_voltage: CoreVoltage,
215 /// Voltage stabilization delay in microseconds. 294 /// Voltage stabilization delay in microseconds.
216 /// If not set, defaults will be used based on voltage level. 295 /// If not set, defaults will be used based on voltage level.
217 #[cfg(feature = "rp2040")]
218 pub voltage_stabilization_delay_us: Option<u32>, 296 pub voltage_stabilization_delay_us: Option<u32>,
219 // See above re gpin handling being commented out 297 // See above re gpin handling being commented out
220 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 298 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
@@ -250,9 +328,7 @@ impl Default for ClockConfig {
250 adc_clk: None, 328 adc_clk: None,
251 #[cfg(feature = "rp2040")] 329 #[cfg(feature = "rp2040")]
252 rtc_clk: None, 330 rtc_clk: None,
253 #[cfg(feature = "rp2040")]
254 core_voltage: CoreVoltage::V1_10, 331 core_voltage: CoreVoltage::V1_10,
255 #[cfg(feature = "rp2040")]
256 voltage_stabilization_delay_us: None, 332 voltage_stabilization_delay_us: None,
257 // See above re gpin handling being commented out 333 // See above re gpin handling being commented out
258 // gpin0: None, 334 // gpin0: None,
@@ -323,9 +399,7 @@ impl ClockConfig {
323 div_frac: 0, 399 div_frac: 0,
324 phase: 0, 400 phase: 0,
325 }), 401 }),
326 #[cfg(feature = "rp2040")]
327 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) 402 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
328 #[cfg(feature = "rp2040")]
329 voltage_stabilization_delay_us: None, 403 voltage_stabilization_delay_us: None,
330 // See above re gpin handling being commented out 404 // See above re gpin handling being commented out
331 // gpin0: None, 405 // gpin0: None,
@@ -368,9 +442,7 @@ impl ClockConfig {
368 div_frac: 171, 442 div_frac: 171,
369 phase: 0, 443 phase: 0,
370 }), 444 }),
371 #[cfg(feature = "rp2040")]
372 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) 445 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
373 #[cfg(feature = "rp2040")]
374 voltage_stabilization_delay_us: None, 446 voltage_stabilization_delay_us: None,
375 // See above re gpin handling being commented out 447 // See above re gpin handling being commented out
376 // gpin0: None, 448 // gpin0: None,
@@ -391,29 +463,42 @@ impl ClockConfig {
391 /// # Returns 463 /// # Returns
392 /// 464 ///
393 /// A ClockConfig configured to achieve the requested system frequency using the 465 /// A ClockConfig configured to achieve the requested system frequency using the
394 /// the usual 12Mhz crystal, or panic if no valid parameters can be found. 466 /// the usual 12Mhz crystal, or an error if no valid parameters can be found.
395 /// 467 ///
396 /// # Note on core voltage: 468 /// # Note on core voltage:
469 ///
470 /// **For RP2040**:
397 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are: 471 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are:
398 /// - Up to 133MHz: V1_10 (default) 472 /// - Up to 133MHz: V1_10 (default)
399 /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz 473 /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz
400 /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here. 474 /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here.
401 /// 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. 475 /// 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.
402 #[cfg(feature = "rp2040")] 476 ///
403 pub fn system_freq(hz: u32) -> Self { 477 /// **For RP235x**:
478 /// 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.
479 /// Using this function is experimental and may not work as expected or even damage the chip.
480 ///
481 /// # Returns
482 ///
483 /// A Result containing either the configured ClockConfig or a ClockError.
484 pub fn system_freq(hz: u32) -> Result<Self, ClockError> {
404 // Start with the standard configuration from crystal() 485 // Start with the standard configuration from crystal()
405 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; 486 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000;
406 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ); 487 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ);
407 488
408 // No need to modify anything if target frequency is already 125MHz 489 // No need to modify anything if target frequency is already 125MHz
409 // (which is what crystal() configures by default) 490 // (which is what crystal() configures by default)
491 #[cfg(feature = "rp2040")]
410 if hz == 125_000_000 { 492 if hz == 125_000_000 {
411 return config; 493 return Ok(config);
494 }
495 #[cfg(feature = "_rp235x")]
496 if hz == 150_000_000 {
497 return Ok(config);
412 } 498 }
413 499
414 // Find optimal PLL parameters for the requested frequency 500 // Find optimal PLL parameters for the requested frequency
415 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) 501 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz).ok_or(ClockError::InvalidPllParameters)?;
416 .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock"));
417 502
418 // Replace the sys_pll configuration with our custom parameters 503 // Replace the sys_pll configuration with our custom parameters
419 if let Some(xosc) = &mut config.xosc { 504 if let Some(xosc) = &mut config.xosc {
@@ -429,8 +514,16 @@ impl ClockConfig {
429 _ => CoreVoltage::V1_10, // Use default voltage (V1_10) 514 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
430 }; 515 };
431 } 516 }
517 #[cfg(feature = "_rp235x")]
518 {
519 config.core_voltage = match hz {
520 // There is no official support for running the chip on other core voltages and/or other clock speeds than the defaults.
521 // So for now we have not way of knowing what the voltage should be. Change this if the manufacturer provides more information.
522 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
523 };
524 }
432 525
433 config 526 Ok(config)
434 } 527 }
435 528
436 /// Configure with manual PLL settings for full control over system clock 529 /// Configure with manual PLL settings for full control over system clock
@@ -525,6 +618,7 @@ impl ClockConfig {
525#[repr(u16)] 618#[repr(u16)]
526#[non_exhaustive] 619#[non_exhaustive]
527#[derive(Clone, Copy, Debug, PartialEq, Eq)] 620#[derive(Clone, Copy, Debug, PartialEq, Eq)]
621#[cfg_attr(feature = "defmt", derive(defmt::Format))]
528pub enum RoscRange { 622pub enum RoscRange {
529 /// Low range. 623 /// Low range.
530 Low = pac::rosc::vals::FreqRange::LOW.0, 624 Low = pac::rosc::vals::FreqRange::LOW.0,
@@ -631,6 +725,7 @@ pub struct RefClkConfig {
631/// Reference clock source. 725/// Reference clock source.
632#[non_exhaustive] 726#[non_exhaustive]
633#[derive(Clone, Copy, Debug, PartialEq, Eq)] 727#[derive(Clone, Copy, Debug, PartialEq, Eq)]
728#[cfg_attr(feature = "defmt", derive(defmt::Format))]
634pub enum RefClkSrc { 729pub enum RefClkSrc {
635 /// XOSC. 730 /// XOSC.
636 Xosc, 731 Xosc,
@@ -646,6 +741,7 @@ pub enum RefClkSrc {
646/// SYS clock source. 741/// SYS clock source.
647#[non_exhaustive] 742#[non_exhaustive]
648#[derive(Clone, Copy, Debug, PartialEq, Eq)] 743#[derive(Clone, Copy, Debug, PartialEq, Eq)]
744#[cfg_attr(feature = "defmt", derive(defmt::Format))]
649pub enum SysClkSrc { 745pub enum SysClkSrc {
650 /// REF. 746 /// REF.
651 Ref, 747 Ref,
@@ -684,6 +780,7 @@ pub struct SysClkConfig {
684#[repr(u8)] 780#[repr(u8)]
685#[non_exhaustive] 781#[non_exhaustive]
686#[derive(Clone, Copy, Debug, PartialEq, Eq)] 782#[derive(Clone, Copy, Debug, PartialEq, Eq)]
783#[cfg_attr(feature = "defmt", derive(defmt::Format))]
687pub enum UsbClkSrc { 784pub enum UsbClkSrc {
688 /// PLL USB. 785 /// PLL USB.
689 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, 786 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -712,6 +809,7 @@ pub struct UsbClkConfig {
712#[repr(u8)] 809#[repr(u8)]
713#[non_exhaustive] 810#[non_exhaustive]
714#[derive(Clone, Copy, Debug, PartialEq, Eq)] 811#[derive(Clone, Copy, Debug, PartialEq, Eq)]
812#[cfg_attr(feature = "defmt", derive(defmt::Format))]
715pub enum AdcClkSrc { 813pub enum AdcClkSrc {
716 /// PLL USB. 814 /// PLL USB.
717 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, 815 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -740,6 +838,7 @@ pub struct AdcClkConfig {
740#[repr(u8)] 838#[repr(u8)]
741#[non_exhaustive] 839#[non_exhaustive]
742#[derive(Clone, Copy, Debug, PartialEq, Eq)] 840#[derive(Clone, Copy, Debug, PartialEq, Eq)]
841#[cfg_attr(feature = "defmt", derive(defmt::Format))]
743#[cfg(feature = "rp2040")] 842#[cfg(feature = "rp2040")]
744pub enum RtcClkSrc { 843pub enum RtcClkSrc {
745 /// PLL USB. 844 /// PLL USB.
@@ -791,7 +890,6 @@ pub struct RtcClkConfig {
791/// // Find parameters for 133MHz system clock from 12MHz crystal 890/// // Find parameters for 133MHz system clock from 12MHz crystal
792/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap(); 891/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap();
793/// ``` 892/// ```
794#[cfg(feature = "rp2040")]
795fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> { 893fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> {
796 // Fixed reference divider for system PLL 894 // Fixed reference divider for system PLL
797 const PLL_SYS_REFDIV: u8 = 1; 895 const PLL_SYS_REFDIV: u8 = 1;
@@ -925,18 +1023,31 @@ pub(crate) unsafe fn init(config: ClockConfig) {
925 }; 1023 };
926 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); 1024 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed);
927 1025
928 // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default 1026 // Set Core Voltage, if we have config for it and we're not using the default
929 #[cfg(feature = "rp2040")]
930 { 1027 {
931 let voltage = config.core_voltage; 1028 let voltage = config.core_voltage;
1029
1030 #[cfg(feature = "rp2040")]
932 let vreg = pac::VREG_AND_CHIP_RESET; 1031 let vreg = pac::VREG_AND_CHIP_RESET;
1032 #[cfg(feature = "_rp235x")]
1033 let vreg = pac::POWMAN;
1034
933 let current_vsel = vreg.vreg().read().vsel(); 1035 let current_vsel = vreg.vreg().read().vsel();
934 let target_vsel = voltage as u8; 1036 let target_vsel = voltage as u8;
935 1037
936 // If the target voltage is different from the current one, we need to change it 1038 // If the target voltage is different from the current one, we need to change it
937 if target_vsel != current_vsel { 1039 if target_vsel != current_vsel {
938 // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage 1040 // Set the voltage regulator to the target voltage
1041 #[cfg(feature = "rp2040")]
939 vreg.vreg().modify(|w| w.set_vsel(target_vsel)); 1042 vreg.vreg().modify(|w| w.set_vsel(target_vsel));
1043 #[cfg(feature = "_rp235x")]
1044 // For rp235x changes to the voltage regulator are protected by a password, see datasheet section 6.4 Power Management (POWMAN) Registers
1045 // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register
1046 vreg.vreg().modify(|w| {
1047 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
1048 w.set_vsel(target_vsel);
1049 *w
1050 });
940 1051
941 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage 1052 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage
942 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { 1053 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| {
@@ -955,7 +1066,14 @@ pub(crate) unsafe fn init(config: ClockConfig) {
955 } 1066 }
956 1067
957 // Only now set the BOD level. At this point the voltage is considered stable. 1068 // Only now set the BOD level. At this point the voltage is considered stable.
1069 #[cfg(feature = "rp2040")]
1070 vreg.bod().write(|w| {
1071 w.set_vsel(voltage.recommended_bod());
1072 w.set_en(true); // Enable brownout detection
1073 });
1074 #[cfg(feature = "_rp235x")]
958 vreg.bod().write(|w| { 1075 vreg.bod().write(|w| {
1076 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
959 w.set_vsel(voltage.recommended_bod()); 1077 w.set_vsel(voltage.recommended_bod());
960 w.set_en(true); // Enable brownout detection 1078 w.set_en(true); // Enable brownout detection
961 }); 1079 });
@@ -970,14 +1088,14 @@ pub(crate) unsafe fn init(config: ClockConfig) {
970 let pll_sys_freq = match config.sys_pll { 1088 let pll_sys_freq = match config.sys_pll {
971 Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) { 1089 Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) {
972 Ok(freq) => freq, 1090 Ok(freq) => freq,
973 Err(e) => panic!("Failed to configure PLL_SYS: {}", e), 1091 Err(e) => panic!("Failed to configure PLL_SYS: {:?}", e),
974 }, 1092 },
975 None => 0, 1093 None => 0,
976 }; 1094 };
977 let pll_usb_freq = match config.usb_pll { 1095 let pll_usb_freq = match config.usb_pll {
978 Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) { 1096 Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) {
979 Ok(freq) => freq, 1097 Ok(freq) => freq,
980 Err(e) => panic!("Failed to configure PLL_USB: {}", e), 1098 Err(e) => panic!("Failed to configure PLL_USB: {:?}", e),
981 }, 1099 },
982 None => 0, 1100 None => 0,
983 }; 1101 };
@@ -1283,6 +1401,58 @@ pub fn clk_rtc_freq() -> u16 {
1283 CLOCKS.rtc.load(Ordering::Relaxed) 1401 CLOCKS.rtc.load(Ordering::Relaxed)
1284} 1402}
1285 1403
1404/// The core voltage of the chip.
1405///
1406/// Returns the current core voltage or an error if the voltage register
1407/// contains an unknown value.
1408pub fn core_voltage() -> Result<CoreVoltage, ClockError> {
1409 #[cfg(feature = "rp2040")]
1410 {
1411 let vreg = pac::VREG_AND_CHIP_RESET;
1412 let vsel = vreg.vreg().read().vsel();
1413 match vsel {
1414 0b0000 => Ok(CoreVoltage::V0_80),
1415 0b0110 => Ok(CoreVoltage::V0_85),
1416 0b0111 => Ok(CoreVoltage::V0_90),
1417 0b1000 => Ok(CoreVoltage::V0_95),
1418 0b1001 => Ok(CoreVoltage::V1_00),
1419 0b1010 => Ok(CoreVoltage::V1_05),
1420 0b1011 => Ok(CoreVoltage::V1_10),
1421 0b1100 => Ok(CoreVoltage::V1_15),
1422 0b1101 => Ok(CoreVoltage::V1_20),
1423 0b1110 => Ok(CoreVoltage::V1_25),
1424 0b1111 => Ok(CoreVoltage::V1_30),
1425 _ => Err(ClockError::UnexpectedCoreVoltageRead),
1426 }
1427 }
1428
1429 #[cfg(feature = "_rp235x")]
1430 {
1431 let vreg = pac::POWMAN;
1432 let vsel = vreg.vreg().read().vsel();
1433 match vsel {
1434 0b00000 => Ok(CoreVoltage::V0_55),
1435 0b00001 => Ok(CoreVoltage::V0_60),
1436 0b00010 => Ok(CoreVoltage::V0_65),
1437 0b00011 => Ok(CoreVoltage::V0_70),
1438 0b00100 => Ok(CoreVoltage::V0_75),
1439 0b00101 => Ok(CoreVoltage::V0_80),
1440 0b00110 => Ok(CoreVoltage::V0_85),
1441 0b00111 => Ok(CoreVoltage::V0_90),
1442 0b01000 => Ok(CoreVoltage::V0_95),
1443 0b01001 => Ok(CoreVoltage::V1_00),
1444 0b01010 => Ok(CoreVoltage::V1_05),
1445 0b01011 => Ok(CoreVoltage::V1_10),
1446 0b01100 => Ok(CoreVoltage::V1_15),
1447 0b01101 => Ok(CoreVoltage::V1_20),
1448 0b01110 => Ok(CoreVoltage::V1_25),
1449 0b01111 => Ok(CoreVoltage::V1_30),
1450 _ => Err(ClockError::UnexpectedCoreVoltageRead),
1451 // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point
1452 }
1453 }
1454}
1455
1286fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { 1456fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
1287 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256; 1457 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256;
1288 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); 1458 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16));
@@ -1295,7 +1465,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
1295 1465
1296/// PLL (Phase-Locked Loop) configuration 1466/// PLL (Phase-Locked Loop) configuration
1297#[inline(always)] 1467#[inline(always)]
1298fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, &'static str> { 1468fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, ClockError> {
1299 // Calculate reference frequency 1469 // Calculate reference frequency
1300 let ref_freq = input_freq / config.refdiv as u32; 1470 let ref_freq = input_freq / config.refdiv as u32;
1301 1471
@@ -1366,7 +1536,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result
1366 timeout -= 1; 1536 timeout -= 1;
1367 if timeout == 0 { 1537 if timeout == 0 {
1368 // PLL failed to lock, return 0 to indicate failure 1538 // PLL failed to lock, return 0 to indicate failure
1369 return Err("PLL failed to lock"); 1539 return Err(ClockError::PllLockTimedOut);
1370 } 1540 }
1371 } 1541 }
1372 1542
@@ -1937,21 +2107,21 @@ mod tests {
1937 { 2107 {
1938 // Test automatic voltage scaling based on frequency 2108 // Test automatic voltage scaling based on frequency
1939 // Under 133 MHz should use default voltage (V1_10) 2109 // Under 133 MHz should use default voltage (V1_10)
1940 let config = ClockConfig::system_freq(125_000_000); 2110 let config = ClockConfig::system_freq(125_000_000).unwrap();
1941 assert_eq!(config.core_voltage, CoreVoltage::V1_10); 2111 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
1942 2112
1943 // 133-200 MHz should use V1_15 2113 // 133-200 MHz should use V1_15
1944 let config = ClockConfig::system_freq(150_000_000); 2114 let config = ClockConfig::system_freq(150_000_000).unwrap();
1945 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2115 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1946 let config = ClockConfig::system_freq(200_000_000); 2116 let config = ClockConfig::system_freq(200_000_000).unwrap();
1947 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2117 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1948 2118
1949 // Above 200 MHz should use V1_25 2119 // Above 200 MHz should use V1_15
1950 let config = ClockConfig::system_freq(250_000_000); 2120 let config = ClockConfig::system_freq(250_000_000).unwrap();
1951 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2121 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1952 2122
1953 // Below 125 MHz should use V1_10 2123 // Below 125 MHz should use V1_10
1954 let config = ClockConfig::system_freq(100_000_000); 2124 let config = ClockConfig::system_freq(100_000_000).unwrap();
1955 assert_eq!(config.core_voltage, CoreVoltage::V1_10); 2125 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
1956 } 2126 }
1957 } 2127 }