aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src/clocks.rs
diff options
context:
space:
mode:
author1-rafael-1 <[email protected]>2025-09-15 20:07:18 +0200
committer1-rafael-1 <[email protected]>2025-09-15 20:07:18 +0200
commit6bb3d2c0720fa082f27d3cdb70f516058497ec87 (patch)
tree5a1e255cff999b00800f203b91a759c720c973e5 /embassy-rp/src/clocks.rs
parenteb685574601d98c44faed9a3534d056199b46e20 (diff)
parent92a6fd2946f2cbb15359290f68aa360953da2ff7 (diff)
Merge branch 'main' into rp2040-rtc-alarm
Diffstat (limited to 'embassy-rp/src/clocks.rs')
-rw-r--r--embassy-rp/src/clocks.rs297
1 files changed, 250 insertions, 47 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 6694aab66..2eddc0bcc 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//! ```
@@ -63,7 +63,6 @@
63//! // Set other parameters as needed... 63//! // Set other parameters as needed...
64//! ``` 64//! ```
65 65
66#[cfg(feature = "rp2040")]
67use core::arch::asm; 66use core::arch::asm;
68use core::marker::PhantomData; 67use core::marker::PhantomData;
69#[cfg(feature = "rp2040")] 68#[cfg(feature = "rp2040")]
@@ -73,7 +72,6 @@ use core::sync::atomic::{AtomicU32, Ordering};
73use pac::clocks::vals::*; 72use pac::clocks::vals::*;
74 73
75use crate::gpio::{AnyPin, SealedPin}; 74use crate::gpio::{AnyPin, SealedPin};
76#[cfg(feature = "rp2040")]
77use crate::pac::common::{Reg, RW}; 75use crate::pac::common::{Reg, RW};
78use crate::{pac, reset, Peri}; 76use crate::{pac, reset, Peri};
79 77
@@ -82,6 +80,18 @@ use crate::{pac, reset, Peri};
82// be very useful until we have runtime clock reconfiguration. once this 80// be very useful until we have runtime clock reconfiguration. once this
83// happens we can resurrect the commented-out gpin bits. 81// happens we can resurrect the commented-out gpin bits.
84 82
83/// Clock error types.
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub enum ClockError {
87 /// PLL failed to lock within the timeout period.
88 PllLockTimedOut,
89 /// Could not find valid PLL parameters for system clock.
90 InvalidPllParameters,
91 /// Reading the core voltage failed due to an unexpected value in the register.
92 UnexpectedCoreVoltageRead,
93}
94
85struct Clocks { 95struct Clocks {
86 xosc: AtomicU32, 96 xosc: AtomicU32,
87 sys: AtomicU32, 97 sys: AtomicU32,
@@ -136,15 +146,16 @@ pub enum PeriClkSrc {
136 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , 146 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
137} 147}
138 148
139/// Core voltage regulator settings for RP2040. 149/// Core voltage regulator settings.
140/// 150///
141/// The RP2040 voltage regulator can be configured for different output voltages. 151/// The voltage regulator can be configured for different output voltages.
142/// Higher voltages allow for higher clock frequencies but increase power consumption and heat. 152/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
143#[cfg(feature = "rp2040")] 153#[cfg(feature = "rp2040")]
144#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145#[repr(u8)] 154#[repr(u8)]
155#[derive(Clone, Copy, Debug, PartialEq, Eq)]
156#[cfg_attr(feature = "defmt", derive(defmt::Format))]
146pub enum CoreVoltage { 157pub enum CoreVoltage {
147 /// 0.80V - Suitable for lower frequencies 158 /// 0.80V
148 V0_80 = 0b0000, 159 V0_80 = 0b0000,
149 /// 0.85V 160 /// 0.85V
150 V0_85 = 0b0110, 161 V0_85 = 0b0110,
@@ -168,11 +179,58 @@ pub enum CoreVoltage {
168 V1_30 = 0b1111, 179 V1_30 = 0b1111,
169} 180}
170 181
171#[cfg(feature = "rp2040")] 182/// Core voltage regulator settings.
183///
184/// The voltage regulator can be configured for different output voltages.
185/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
186///
187/// **Note**: The maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit
188/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this
189/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now.
190#[cfg(feature = "_rp235x")]
191#[repr(u8)]
192#[derive(Clone, Copy, Debug, PartialEq, Eq)]
193#[cfg_attr(feature = "defmt", derive(defmt::Format))]
194pub enum CoreVoltage {
195 /// 0.55V
196 V0_55 = 0b00000,
197 /// 0.60V
198 V0_60 = 0b00001,
199 /// 0.65V
200 V0_65 = 0b00010,
201 /// 0.70V
202 V0_70 = 0b00011,
203 /// 0.75V
204 V0_75 = 0b00100,
205 /// 0.80V
206 V0_80 = 0b00101,
207 /// 0.85V
208 V0_85 = 0b00110,
209 /// 0.90V
210 V0_90 = 0b00111,
211 /// 0.95V
212 V0_95 = 0b01000,
213 /// 1.00V
214 V1_00 = 0b01001,
215 /// 1.05V
216 V1_05 = 0b01010,
217 /// 1.10V - Default voltage level
218 V1_10 = 0b01011,
219 /// 1.15V
220 V1_15 = 0b01100,
221 /// 1.20V
222 V1_20 = 0b01101,
223 /// 1.25V
224 V1_25 = 0b01110,
225 /// 1.30V
226 V1_30 = 0b01111,
227}
228
172impl CoreVoltage { 229impl CoreVoltage {
173 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. 230 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage.
174 /// Sets the BOD threshold to approximately 80% of the core voltage. 231 /// Sets the BOD threshold to approximately 80% of the core voltage.
175 fn recommended_bod(self) -> u8 { 232 fn recommended_bod(self) -> u8 {
233 #[cfg(feature = "rp2040")]
176 match self { 234 match self {
177 CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V) 235 CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V)
178 CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V) 236 CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V)
@@ -180,12 +238,32 @@ impl CoreVoltage {
180 CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V) 238 CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V)
181 CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V) 239 CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V)
182 CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V) 240 CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V)
183 CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V) 241 CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V), the default
184 CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V) 242 CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V)
185 CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V) 243 CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V)
186 CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V) 244 CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V)
187 CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V) 245 CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V)
188 } 246 }
247 #[cfg(feature = "_rp235x")]
248 match self {
249 CoreVoltage::V0_55 => 0b00001, // 0.516V (~94% of 0.55V)
250 CoreVoltage::V0_60 => 0b00010, // 0.559V (~93% of 0.60V)
251 CoreVoltage::V0_65 => 0b00011, // 0.602V (~93% of 0.65V)
252 CoreVoltage::V0_70 => 0b00011, // 0.602V (~86% of 0.70V)
253 CoreVoltage::V0_75 => 0b00100, // 0.645V (~86% of 0.75V)
254 CoreVoltage::V0_80 => 0b00101, // 0.688V (~86% of 0.80V)
255 CoreVoltage::V0_85 => 0b00110, // 0.731V (~86% of 0.85V)
256 CoreVoltage::V0_90 => 0b00110, // 0.731V (~81% of 0.90V)
257 CoreVoltage::V0_95 => 0b00111, // 0.774V (~81% of 0.95V)
258 CoreVoltage::V1_00 => 0b01000, // 0.817V (~82% of 1.00V)
259 CoreVoltage::V1_05 => 0b01000, // 0.817V (~78% of 1.05V)
260 CoreVoltage::V1_10 => 0b01001, // 0.860V (~78% of 1.10V), the default
261 CoreVoltage::V1_15 => 0b01001, // 0.860V (~75% of 1.15V)
262 CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V)
263 CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V)
264 CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V)
265 // all others: 0.946V (see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point)
266 }
189 } 267 }
190} 268}
191 269
@@ -209,12 +287,10 @@ pub struct ClockConfig {
209 /// RTC clock configuration. 287 /// RTC clock configuration.
210 #[cfg(feature = "rp2040")] 288 #[cfg(feature = "rp2040")]
211 pub rtc_clk: Option<RtcClkConfig>, 289 pub rtc_clk: Option<RtcClkConfig>,
212 /// Core voltage scaling (RP2040 only). Defaults to 1.10V. 290 /// Core voltage scaling. Defaults to 1.10V.
213 #[cfg(feature = "rp2040")]
214 pub core_voltage: CoreVoltage, 291 pub core_voltage: CoreVoltage,
215 /// Voltage stabilization delay in microseconds. 292 /// Voltage stabilization delay in microseconds.
216 /// If not set, defaults will be used based on voltage level. 293 /// If not set, defaults will be used based on voltage level.
217 #[cfg(feature = "rp2040")]
218 pub voltage_stabilization_delay_us: Option<u32>, 294 pub voltage_stabilization_delay_us: Option<u32>,
219 // See above re gpin handling being commented out 295 // See above re gpin handling being commented out
220 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 296 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
@@ -250,9 +326,7 @@ impl Default for ClockConfig {
250 adc_clk: None, 326 adc_clk: None,
251 #[cfg(feature = "rp2040")] 327 #[cfg(feature = "rp2040")]
252 rtc_clk: None, 328 rtc_clk: None,
253 #[cfg(feature = "rp2040")]
254 core_voltage: CoreVoltage::V1_10, 329 core_voltage: CoreVoltage::V1_10,
255 #[cfg(feature = "rp2040")]
256 voltage_stabilization_delay_us: None, 330 voltage_stabilization_delay_us: None,
257 // See above re gpin handling being commented out 331 // See above re gpin handling being commented out
258 // gpin0: None, 332 // gpin0: None,
@@ -323,9 +397,7 @@ impl ClockConfig {
323 div_frac: 0, 397 div_frac: 0,
324 phase: 0, 398 phase: 0,
325 }), 399 }),
326 #[cfg(feature = "rp2040")]
327 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) 400 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
328 #[cfg(feature = "rp2040")]
329 voltage_stabilization_delay_us: None, 401 voltage_stabilization_delay_us: None,
330 // See above re gpin handling being commented out 402 // See above re gpin handling being commented out
331 // gpin0: None, 403 // gpin0: None,
@@ -368,9 +440,7 @@ impl ClockConfig {
368 div_frac: 171, 440 div_frac: 171,
369 phase: 0, 441 phase: 0,
370 }), 442 }),
371 #[cfg(feature = "rp2040")]
372 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) 443 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
373 #[cfg(feature = "rp2040")]
374 voltage_stabilization_delay_us: None, 444 voltage_stabilization_delay_us: None,
375 // See above re gpin handling being commented out 445 // See above re gpin handling being commented out
376 // gpin0: None, 446 // gpin0: None,
@@ -391,29 +461,42 @@ impl ClockConfig {
391 /// # Returns 461 /// # Returns
392 /// 462 ///
393 /// A ClockConfig configured to achieve the requested system frequency using the 463 /// 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. 464 /// the usual 12Mhz crystal, or an error if no valid parameters can be found.
395 /// 465 ///
396 /// # Note on core voltage: 466 /// # Note on core voltage:
467 ///
468 /// **For RP2040**:
397 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are: 469 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are:
398 /// - Up to 133MHz: V1_10 (default) 470 /// - Up to 133MHz: V1_10 (default)
399 /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz 471 /// - 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. 472 /// 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. 473 /// 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")] 474 ///
403 pub fn system_freq(hz: u32) -> Self { 475 /// **For RP235x**:
476 /// 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.
477 /// Using this function is experimental and may not work as expected or even damage the chip.
478 ///
479 /// # Returns
480 ///
481 /// A Result containing either the configured ClockConfig or a ClockError.
482 pub fn system_freq(hz: u32) -> Result<Self, ClockError> {
404 // Start with the standard configuration from crystal() 483 // Start with the standard configuration from crystal()
405 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; 484 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000;
406 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ); 485 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ);
407 486
408 // No need to modify anything if target frequency is already 125MHz 487 // No need to modify anything if target frequency is already 125MHz
409 // (which is what crystal() configures by default) 488 // (which is what crystal() configures by default)
489 #[cfg(feature = "rp2040")]
410 if hz == 125_000_000 { 490 if hz == 125_000_000 {
411 return config; 491 return Ok(config);
492 }
493 #[cfg(feature = "_rp235x")]
494 if hz == 150_000_000 {
495 return Ok(config);
412 } 496 }
413 497
414 // Find optimal PLL parameters for the requested frequency 498 // Find optimal PLL parameters for the requested frequency
415 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) 499 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 500
418 // Replace the sys_pll configuration with our custom parameters 501 // Replace the sys_pll configuration with our custom parameters
419 if let Some(xosc) = &mut config.xosc { 502 if let Some(xosc) = &mut config.xosc {
@@ -429,8 +512,16 @@ impl ClockConfig {
429 _ => CoreVoltage::V1_10, // Use default voltage (V1_10) 512 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
430 }; 513 };
431 } 514 }
515 #[cfg(feature = "_rp235x")]
516 {
517 config.core_voltage = match hz {
518 // There is no official support for running the chip on other core voltages and/or other clock speeds than the defaults.
519 // So for now we have not way of knowing what the voltage should be. Change this if the manufacturer provides more information.
520 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
521 };
522 }
432 523
433 config 524 Ok(config)
434 } 525 }
435 526
436 /// Configure with manual PLL settings for full control over system clock 527 /// Configure with manual PLL settings for full control over system clock
@@ -525,6 +616,7 @@ impl ClockConfig {
525#[repr(u16)] 616#[repr(u16)]
526#[non_exhaustive] 617#[non_exhaustive]
527#[derive(Clone, Copy, Debug, PartialEq, Eq)] 618#[derive(Clone, Copy, Debug, PartialEq, Eq)]
619#[cfg_attr(feature = "defmt", derive(defmt::Format))]
528pub enum RoscRange { 620pub enum RoscRange {
529 /// Low range. 621 /// Low range.
530 Low = pac::rosc::vals::FreqRange::LOW.0, 622 Low = pac::rosc::vals::FreqRange::LOW.0,
@@ -631,6 +723,7 @@ pub struct RefClkConfig {
631/// Reference clock source. 723/// Reference clock source.
632#[non_exhaustive] 724#[non_exhaustive]
633#[derive(Clone, Copy, Debug, PartialEq, Eq)] 725#[derive(Clone, Copy, Debug, PartialEq, Eq)]
726#[cfg_attr(feature = "defmt", derive(defmt::Format))]
634pub enum RefClkSrc { 727pub enum RefClkSrc {
635 /// XOSC. 728 /// XOSC.
636 Xosc, 729 Xosc,
@@ -646,6 +739,7 @@ pub enum RefClkSrc {
646/// SYS clock source. 739/// SYS clock source.
647#[non_exhaustive] 740#[non_exhaustive]
648#[derive(Clone, Copy, Debug, PartialEq, Eq)] 741#[derive(Clone, Copy, Debug, PartialEq, Eq)]
742#[cfg_attr(feature = "defmt", derive(defmt::Format))]
649pub enum SysClkSrc { 743pub enum SysClkSrc {
650 /// REF. 744 /// REF.
651 Ref, 745 Ref,
@@ -684,6 +778,7 @@ pub struct SysClkConfig {
684#[repr(u8)] 778#[repr(u8)]
685#[non_exhaustive] 779#[non_exhaustive]
686#[derive(Clone, Copy, Debug, PartialEq, Eq)] 780#[derive(Clone, Copy, Debug, PartialEq, Eq)]
781#[cfg_attr(feature = "defmt", derive(defmt::Format))]
687pub enum UsbClkSrc { 782pub enum UsbClkSrc {
688 /// PLL USB. 783 /// PLL USB.
689 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, 784 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -712,6 +807,7 @@ pub struct UsbClkConfig {
712#[repr(u8)] 807#[repr(u8)]
713#[non_exhaustive] 808#[non_exhaustive]
714#[derive(Clone, Copy, Debug, PartialEq, Eq)] 809#[derive(Clone, Copy, Debug, PartialEq, Eq)]
810#[cfg_attr(feature = "defmt", derive(defmt::Format))]
715pub enum AdcClkSrc { 811pub enum AdcClkSrc {
716 /// PLL USB. 812 /// PLL USB.
717 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, 813 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -740,6 +836,7 @@ pub struct AdcClkConfig {
740#[repr(u8)] 836#[repr(u8)]
741#[non_exhaustive] 837#[non_exhaustive]
742#[derive(Clone, Copy, Debug, PartialEq, Eq)] 838#[derive(Clone, Copy, Debug, PartialEq, Eq)]
839#[cfg_attr(feature = "defmt", derive(defmt::Format))]
743#[cfg(feature = "rp2040")] 840#[cfg(feature = "rp2040")]
744pub enum RtcClkSrc { 841pub enum RtcClkSrc {
745 /// PLL USB. 842 /// PLL USB.
@@ -791,7 +888,6 @@ pub struct RtcClkConfig {
791/// // Find parameters for 133MHz system clock from 12MHz crystal 888/// // Find parameters for 133MHz system clock from 12MHz crystal
792/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap(); 889/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap();
793/// ``` 890/// ```
794#[cfg(feature = "rp2040")]
795fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> { 891fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> {
796 // Fixed reference divider for system PLL 892 // Fixed reference divider for system PLL
797 const PLL_SYS_REFDIV: u8 = 1; 893 const PLL_SYS_REFDIV: u8 = 1;
@@ -925,18 +1021,31 @@ pub(crate) unsafe fn init(config: ClockConfig) {
925 }; 1021 };
926 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); 1022 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed);
927 1023
928 // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default 1024 // Set Core Voltage, if we have config for it and we're not using the default
929 #[cfg(feature = "rp2040")]
930 { 1025 {
931 let voltage = config.core_voltage; 1026 let voltage = config.core_voltage;
1027
1028 #[cfg(feature = "rp2040")]
932 let vreg = pac::VREG_AND_CHIP_RESET; 1029 let vreg = pac::VREG_AND_CHIP_RESET;
1030 #[cfg(feature = "_rp235x")]
1031 let vreg = pac::POWMAN;
1032
933 let current_vsel = vreg.vreg().read().vsel(); 1033 let current_vsel = vreg.vreg().read().vsel();
934 let target_vsel = voltage as u8; 1034 let target_vsel = voltage as u8;
935 1035
936 // If the target voltage is different from the current one, we need to change it 1036 // If the target voltage is different from the current one, we need to change it
937 if target_vsel != current_vsel { 1037 if target_vsel != current_vsel {
938 // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage 1038 // Set the voltage regulator to the target voltage
1039 #[cfg(feature = "rp2040")]
939 vreg.vreg().modify(|w| w.set_vsel(target_vsel)); 1040 vreg.vreg().modify(|w| w.set_vsel(target_vsel));
1041 #[cfg(feature = "_rp235x")]
1042 // For rp235x changes to the voltage regulator are protected by a password, see datasheet section 6.4 Power Management (POWMAN) Registers
1043 // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register
1044 vreg.vreg().modify(|w| {
1045 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
1046 w.set_vsel(target_vsel);
1047 *w
1048 });
940 1049
941 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage 1050 // 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(|| { 1051 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| {
@@ -955,10 +1064,17 @@ pub(crate) unsafe fn init(config: ClockConfig) {
955 } 1064 }
956 1065
957 // Only now set the BOD level. At this point the voltage is considered stable. 1066 // Only now set the BOD level. At this point the voltage is considered stable.
1067 #[cfg(feature = "rp2040")]
958 vreg.bod().write(|w| { 1068 vreg.bod().write(|w| {
959 w.set_vsel(voltage.recommended_bod()); 1069 w.set_vsel(voltage.recommended_bod());
960 w.set_en(true); // Enable brownout detection 1070 w.set_en(true); // Enable brownout detection
961 }); 1071 });
1072 #[cfg(feature = "_rp235x")]
1073 vreg.bod().write(|w| {
1074 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
1075 w.set_vsel(voltage.recommended_bod());
1076 w.set_en(true); // Enable brownout detection
1077 });
962 } 1078 }
963 } 1079 }
964 1080
@@ -970,14 +1086,14 @@ pub(crate) unsafe fn init(config: ClockConfig) {
970 let pll_sys_freq = match config.sys_pll { 1086 let pll_sys_freq = match config.sys_pll {
971 Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) { 1087 Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) {
972 Ok(freq) => freq, 1088 Ok(freq) => freq,
973 Err(e) => panic!("Failed to configure PLL_SYS: {}", e), 1089 Err(e) => panic!("Failed to configure PLL_SYS: {:?}", e),
974 }, 1090 },
975 None => 0, 1091 None => 0,
976 }; 1092 };
977 let pll_usb_freq = match config.usb_pll { 1093 let pll_usb_freq = match config.usb_pll {
978 Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) { 1094 Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) {
979 Ok(freq) => freq, 1095 Ok(freq) => freq,
980 Err(e) => panic!("Failed to configure PLL_USB: {}", e), 1096 Err(e) => panic!("Failed to configure PLL_USB: {:?}", e),
981 }, 1097 },
982 None => 0, 1098 None => 0,
983 }; 1099 };
@@ -1283,6 +1399,58 @@ pub fn clk_rtc_freq() -> u16 {
1283 CLOCKS.rtc.load(Ordering::Relaxed) 1399 CLOCKS.rtc.load(Ordering::Relaxed)
1284} 1400}
1285 1401
1402/// The core voltage of the chip.
1403///
1404/// Returns the current core voltage or an error if the voltage register
1405/// contains an unknown value.
1406pub fn core_voltage() -> Result<CoreVoltage, ClockError> {
1407 #[cfg(feature = "rp2040")]
1408 {
1409 let vreg = pac::VREG_AND_CHIP_RESET;
1410 let vsel = vreg.vreg().read().vsel();
1411 match vsel {
1412 0b0000 => Ok(CoreVoltage::V0_80),
1413 0b0110 => Ok(CoreVoltage::V0_85),
1414 0b0111 => Ok(CoreVoltage::V0_90),
1415 0b1000 => Ok(CoreVoltage::V0_95),
1416 0b1001 => Ok(CoreVoltage::V1_00),
1417 0b1010 => Ok(CoreVoltage::V1_05),
1418 0b1011 => Ok(CoreVoltage::V1_10),
1419 0b1100 => Ok(CoreVoltage::V1_15),
1420 0b1101 => Ok(CoreVoltage::V1_20),
1421 0b1110 => Ok(CoreVoltage::V1_25),
1422 0b1111 => Ok(CoreVoltage::V1_30),
1423 _ => Err(ClockError::UnexpectedCoreVoltageRead),
1424 }
1425 }
1426
1427 #[cfg(feature = "_rp235x")]
1428 {
1429 let vreg = pac::POWMAN;
1430 let vsel = vreg.vreg().read().vsel();
1431 match vsel {
1432 0b00000 => Ok(CoreVoltage::V0_55),
1433 0b00001 => Ok(CoreVoltage::V0_60),
1434 0b00010 => Ok(CoreVoltage::V0_65),
1435 0b00011 => Ok(CoreVoltage::V0_70),
1436 0b00100 => Ok(CoreVoltage::V0_75),
1437 0b00101 => Ok(CoreVoltage::V0_80),
1438 0b00110 => Ok(CoreVoltage::V0_85),
1439 0b00111 => Ok(CoreVoltage::V0_90),
1440 0b01000 => Ok(CoreVoltage::V0_95),
1441 0b01001 => Ok(CoreVoltage::V1_00),
1442 0b01010 => Ok(CoreVoltage::V1_05),
1443 0b01011 => Ok(CoreVoltage::V1_10),
1444 0b01100 => Ok(CoreVoltage::V1_15),
1445 0b01101 => Ok(CoreVoltage::V1_20),
1446 0b01110 => Ok(CoreVoltage::V1_25),
1447 0b01111 => Ok(CoreVoltage::V1_30),
1448 _ => Err(ClockError::UnexpectedCoreVoltageRead),
1449 // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point
1450 }
1451 }
1452}
1453
1286fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { 1454fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
1287 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256; 1455 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256;
1288 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); 1456 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16));
@@ -1295,7 +1463,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
1295 1463
1296/// PLL (Phase-Locked Loop) configuration 1464/// PLL (Phase-Locked Loop) configuration
1297#[inline(always)] 1465#[inline(always)]
1298fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, &'static str> { 1466fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, ClockError> {
1299 // Calculate reference frequency 1467 // Calculate reference frequency
1300 let ref_freq = input_freq / config.refdiv as u32; 1468 let ref_freq = input_freq / config.refdiv as u32;
1301 1469
@@ -1366,7 +1534,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result
1366 timeout -= 1; 1534 timeout -= 1;
1367 if timeout == 0 { 1535 if timeout == 0 {
1368 // PLL failed to lock, return 0 to indicate failure 1536 // PLL failed to lock, return 0 to indicate failure
1369 return Err("PLL failed to lock"); 1537 return Err(ClockError::PllLockTimedOut);
1370 } 1538 }
1371 } 1539 }
1372 1540
@@ -1606,7 +1774,8 @@ impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
1606pub struct RoscRng; 1774pub struct RoscRng;
1607 1775
1608impl RoscRng { 1776impl RoscRng {
1609 fn next_u8() -> u8 { 1777 /// Get a random u8
1778 pub fn next_u8() -> u8 {
1610 let random_reg = pac::ROSC.randombit(); 1779 let random_reg = pac::ROSC.randombit();
1611 let mut acc = 0; 1780 let mut acc = 0;
1612 for _ in 0..u8::BITS { 1781 for _ in 0..u8::BITS {
@@ -1615,31 +1784,65 @@ impl RoscRng {
1615 } 1784 }
1616 acc 1785 acc
1617 } 1786 }
1787
1788 /// Get a random u32
1789 pub fn next_u32(&mut self) -> u32 {
1790 rand_core_09::impls::next_u32_via_fill(self)
1791 }
1792
1793 /// Get a random u64
1794 pub fn next_u64(&mut self) -> u64 {
1795 rand_core_09::impls::next_u64_via_fill(self)
1796 }
1797
1798 /// Fill a slice with random bytes
1799 pub fn fill_bytes(&mut self, dest: &mut [u8]) {
1800 dest.fill_with(Self::next_u8)
1801 }
1618} 1802}
1619 1803
1620impl rand_core::RngCore for RoscRng { 1804impl rand_core_06::RngCore for RoscRng {
1621 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 1805 fn next_u32(&mut self) -> u32 {
1622 Ok(self.fill_bytes(dest)) 1806 self.next_u32()
1807 }
1808
1809 fn next_u64(&mut self) -> u64 {
1810 self.next_u64()
1811 }
1812
1813 fn fill_bytes(&mut self, dest: &mut [u8]) {
1814 self.fill_bytes(dest);
1815 }
1816
1817 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
1818 self.fill_bytes(dest);
1819 Ok(())
1623 } 1820 }
1821}
1624 1822
1823impl rand_core_06::CryptoRng for RoscRng {}
1824
1825impl rand_core_09::RngCore for RoscRng {
1625 fn next_u32(&mut self) -> u32 { 1826 fn next_u32(&mut self) -> u32 {
1626 rand_core::impls::next_u32_via_fill(self) 1827 self.next_u32()
1627 } 1828 }
1628 1829
1629 fn next_u64(&mut self) -> u64 { 1830 fn next_u64(&mut self) -> u64 {
1630 rand_core::impls::next_u64_via_fill(self) 1831 self.next_u64()
1631 } 1832 }
1632 1833
1633 fn fill_bytes(&mut self, dest: &mut [u8]) { 1834 fn fill_bytes(&mut self, dest: &mut [u8]) {
1634 dest.fill_with(Self::next_u8) 1835 self.fill_bytes(dest);
1635 } 1836 }
1636} 1837}
1637 1838
1839impl rand_core_09::CryptoRng for RoscRng {}
1840
1638/// Enter the `DORMANT` sleep state. This will stop *all* internal clocks 1841/// Enter the `DORMANT` sleep state. This will stop *all* internal clocks
1639/// and can only be exited through resets, dormant-wake GPIO interrupts, 1842/// and can only be exited through resets, dormant-wake GPIO interrupts,
1640/// and RTC interrupts. If RTC is clocked from an internal clock source 1843/// and RTC interrupts. If RTC is clocked from an internal clock source
1641/// it will be stopped and not function as a wakeup source. 1844/// it will be stopped and not function as a wakeup source.
1642#[cfg(all(target_arch = "arm", feature = "rp2040"))] 1845#[cfg(all(target_arch = "arm"))]
1643pub fn dormant_sleep() { 1846pub fn dormant_sleep() {
1644 struct Set<T: Copy, F: Fn()>(Reg<T, RW>, T, F); 1847 struct Set<T: Copy, F: Fn()>(Reg<T, RW>, T, F);
1645 1848
@@ -1937,21 +2140,21 @@ mod tests {
1937 { 2140 {
1938 // Test automatic voltage scaling based on frequency 2141 // Test automatic voltage scaling based on frequency
1939 // Under 133 MHz should use default voltage (V1_10) 2142 // Under 133 MHz should use default voltage (V1_10)
1940 let config = ClockConfig::system_freq(125_000_000); 2143 let config = ClockConfig::system_freq(125_000_000).unwrap();
1941 assert_eq!(config.core_voltage, CoreVoltage::V1_10); 2144 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
1942 2145
1943 // 133-200 MHz should use V1_15 2146 // 133-200 MHz should use V1_15
1944 let config = ClockConfig::system_freq(150_000_000); 2147 let config = ClockConfig::system_freq(150_000_000).unwrap();
1945 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2148 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1946 let config = ClockConfig::system_freq(200_000_000); 2149 let config = ClockConfig::system_freq(200_000_000).unwrap();
1947 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2150 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1948 2151
1949 // Above 200 MHz should use V1_25 2152 // Above 200 MHz should use V1_15
1950 let config = ClockConfig::system_freq(250_000_000); 2153 let config = ClockConfig::system_freq(250_000_000).unwrap();
1951 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2154 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1952 2155
1953 // Below 125 MHz should use V1_10 2156 // Below 125 MHz should use V1_10
1954 let config = ClockConfig::system_freq(100_000_000); 2157 let config = ClockConfig::system_freq(100_000_000).unwrap();
1955 assert_eq!(config.core_voltage, CoreVoltage::V1_10); 2158 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
1956 } 2159 }
1957 } 2160 }