aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src
diff options
context:
space:
mode:
author1-rafael-1 <[email protected]>2025-05-12 21:33:47 +0200
committer1-rafael-1 <[email protected]>2025-05-12 21:33:47 +0200
commit79e452922a6b467f2e8547a6b28698ed5f409705 (patch)
tree3c9344145e0eb8cfdd35549af940ef04cf25b3c3 /embassy-rp/src
parent133500167ca53cfbc5e9268356753bc0e3f8c209 (diff)
Add ClockError enum and update system_freq to return Result for error handling
Diffstat (limited to 'embassy-rp/src')
-rw-r--r--embassy-rp/src/clocks.rs66
1 files changed, 47 insertions, 19 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index bcd08c204..5872ef789 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -82,6 +82,18 @@ use crate::{pac, reset, Peri};
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,
@@ -144,8 +156,9 @@ pub enum PeriClkSrc {
144/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit 156/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit
145/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this 157/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this
146/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. 158/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now.
147#[derive(Clone, Copy, Debug, PartialEq, Eq)]
148#[repr(u8)] 159#[repr(u8)]
160#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161#[cfg_attr(feature = "defmt", derive(defmt::Format))]
149pub enum CoreVoltage { 162pub enum CoreVoltage {
150 // RP2040 voltage levels 163 // RP2040 voltage levels
151 #[cfg(feature = "rp2040")] 164 #[cfg(feature = "rp2040")]
@@ -468,7 +481,7 @@ impl ClockConfig {
468 /// # Returns 481 /// # Returns
469 /// 482 ///
470 /// A ClockConfig configured to achieve the requested system frequency using the 483 /// A ClockConfig configured to achieve the requested system frequency using the
471 /// the usual 12Mhz crystal, or panic if no valid parameters can be found. 484 /// the usual 12Mhz crystal, or an error if no valid parameters can be found.
472 /// 485 ///
473 /// # Note on core voltage: 486 /// # Note on core voltage:
474 /// 487 ///
@@ -482,7 +495,11 @@ impl ClockConfig {
482 /// **For RP235x**: 495 /// **For RP235x**:
483 /// 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. 496 /// 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.
484 /// Using this function is experimental and may not work as expected or even damage the chip. 497 /// Using this function is experimental and may not work as expected or even damage the chip.
485 pub fn system_freq(hz: u32) -> Self { 498 ///
499 /// # Returns
500 ///
501 /// A Result containing either the configured ClockConfig or a ClockError.
502 pub fn system_freq(hz: u32) -> Result<Self, ClockError> {
486 // Start with the standard configuration from crystal() 503 // Start with the standard configuration from crystal()
487 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; 504 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000;
488 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ); 505 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ);
@@ -491,16 +508,15 @@ impl ClockConfig {
491 // (which is what crystal() configures by default) 508 // (which is what crystal() configures by default)
492 #[cfg(feature = "rp2040")] 509 #[cfg(feature = "rp2040")]
493 if hz == 125_000_000 { 510 if hz == 125_000_000 {
494 return config; 511 return Ok(config);
495 } 512 }
496 #[cfg(feature = "_rp235x")] 513 #[cfg(feature = "_rp235x")]
497 if hz == 150_000_000 { 514 if hz == 150_000_000 {
498 return config; 515 return Ok(config);
499 } 516 }
500 517
501 // Find optimal PLL parameters for the requested frequency 518 // Find optimal PLL parameters for the requested frequency
502 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) 519 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz).ok_or(ClockError::InvalidPllParameters)?;
503 .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock"));
504 520
505 // Replace the sys_pll configuration with our custom parameters 521 // Replace the sys_pll configuration with our custom parameters
506 if let Some(xosc) = &mut config.xosc { 522 if let Some(xosc) = &mut config.xosc {
@@ -525,7 +541,7 @@ impl ClockConfig {
525 }; 541 };
526 } 542 }
527 543
528 config 544 Ok(config)
529 } 545 }
530 546
531 /// Configure with manual PLL settings for full control over system clock 547 /// Configure with manual PLL settings for full control over system clock
@@ -620,6 +636,7 @@ impl ClockConfig {
620#[repr(u16)] 636#[repr(u16)]
621#[non_exhaustive] 637#[non_exhaustive]
622#[derive(Clone, Copy, Debug, PartialEq, Eq)] 638#[derive(Clone, Copy, Debug, PartialEq, Eq)]
639#[cfg_attr(feature = "defmt", derive(defmt::Format))]
623pub enum RoscRange { 640pub enum RoscRange {
624 /// Low range. 641 /// Low range.
625 Low = pac::rosc::vals::FreqRange::LOW.0, 642 Low = pac::rosc::vals::FreqRange::LOW.0,
@@ -726,6 +743,7 @@ pub struct RefClkConfig {
726/// Reference clock source. 743/// Reference clock source.
727#[non_exhaustive] 744#[non_exhaustive]
728#[derive(Clone, Copy, Debug, PartialEq, Eq)] 745#[derive(Clone, Copy, Debug, PartialEq, Eq)]
746#[cfg_attr(feature = "defmt", derive(defmt::Format))]
729pub enum RefClkSrc { 747pub enum RefClkSrc {
730 /// XOSC. 748 /// XOSC.
731 Xosc, 749 Xosc,
@@ -741,6 +759,7 @@ pub enum RefClkSrc {
741/// SYS clock source. 759/// SYS clock source.
742#[non_exhaustive] 760#[non_exhaustive]
743#[derive(Clone, Copy, Debug, PartialEq, Eq)] 761#[derive(Clone, Copy, Debug, PartialEq, Eq)]
762#[cfg_attr(feature = "defmt", derive(defmt::Format))]
744pub enum SysClkSrc { 763pub enum SysClkSrc {
745 /// REF. 764 /// REF.
746 Ref, 765 Ref,
@@ -779,6 +798,7 @@ pub struct SysClkConfig {
779#[repr(u8)] 798#[repr(u8)]
780#[non_exhaustive] 799#[non_exhaustive]
781#[derive(Clone, Copy, Debug, PartialEq, Eq)] 800#[derive(Clone, Copy, Debug, PartialEq, Eq)]
801#[cfg_attr(feature = "defmt", derive(defmt::Format))]
782pub enum UsbClkSrc { 802pub enum UsbClkSrc {
783 /// PLL USB. 803 /// PLL USB.
784 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, 804 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -807,6 +827,7 @@ pub struct UsbClkConfig {
807#[repr(u8)] 827#[repr(u8)]
808#[non_exhaustive] 828#[non_exhaustive]
809#[derive(Clone, Copy, Debug, PartialEq, Eq)] 829#[derive(Clone, Copy, Debug, PartialEq, Eq)]
830#[cfg_attr(feature = "defmt", derive(defmt::Format))]
810pub enum AdcClkSrc { 831pub enum AdcClkSrc {
811 /// PLL USB. 832 /// PLL USB.
812 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, 833 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -835,6 +856,7 @@ pub struct AdcClkConfig {
835#[repr(u8)] 856#[repr(u8)]
836#[non_exhaustive] 857#[non_exhaustive]
837#[derive(Clone, Copy, Debug, PartialEq, Eq)] 858#[derive(Clone, Copy, Debug, PartialEq, Eq)]
859#[cfg_attr(feature = "defmt", derive(defmt::Format))]
838#[cfg(feature = "rp2040")] 860#[cfg(feature = "rp2040")]
839pub enum RtcClkSrc { 861pub enum RtcClkSrc {
840 /// PLL USB. 862 /// PLL USB.
@@ -1084,14 +1106,20 @@ pub(crate) unsafe fn init(config: ClockConfig) {
1084 let pll_sys_freq = match config.sys_pll { 1106 let pll_sys_freq = match config.sys_pll {
1085 Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) { 1107 Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) {
1086 Ok(freq) => freq, 1108 Ok(freq) => freq,
1109 #[cfg(feature = "defmt")]
1087 Err(e) => panic!("Failed to configure PLL_SYS: {}", e), 1110 Err(e) => panic!("Failed to configure PLL_SYS: {}", e),
1111 #[cfg(not(feature = "defmt"))]
1112 Err(_e) => panic!("Failed to configure PLL_SYS"),
1088 }, 1113 },
1089 None => 0, 1114 None => 0,
1090 }; 1115 };
1091 let pll_usb_freq = match config.usb_pll { 1116 let pll_usb_freq = match config.usb_pll {
1092 Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) { 1117 Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) {
1093 Ok(freq) => freq, 1118 Ok(freq) => freq,
1119 #[cfg(feature = "defmt")]
1094 Err(e) => panic!("Failed to configure PLL_USB: {}", e), 1120 Err(e) => panic!("Failed to configure PLL_USB: {}", e),
1121 #[cfg(not(feature = "defmt"))]
1122 Err(_e) => panic!("Failed to configure PLL_USB"),
1095 }, 1123 },
1096 None => 0, 1124 None => 0,
1097 }; 1125 };
@@ -1401,7 +1429,7 @@ pub fn clk_rtc_freq() -> u16 {
1401/// 1429///
1402/// Returns the current core voltage or an error if the voltage register 1430/// Returns the current core voltage or an error if the voltage register
1403/// contains an unknown value. 1431/// contains an unknown value.
1404pub fn core_voltage() -> Result<CoreVoltage, &'static str> { 1432pub fn core_voltage() -> Result<CoreVoltage, ClockError> {
1405 #[cfg(feature = "rp2040")] 1433 #[cfg(feature = "rp2040")]
1406 { 1434 {
1407 let vreg = pac::VREG_AND_CHIP_RESET; 1435 let vreg = pac::VREG_AND_CHIP_RESET;
@@ -1418,7 +1446,7 @@ pub fn core_voltage() -> Result<CoreVoltage, &'static str> {
1418 0b1101 => Ok(CoreVoltage::V1_20), 1446 0b1101 => Ok(CoreVoltage::V1_20),
1419 0b1110 => Ok(CoreVoltage::V1_25), 1447 0b1110 => Ok(CoreVoltage::V1_25),
1420 0b1111 => Ok(CoreVoltage::V1_30), 1448 0b1111 => Ok(CoreVoltage::V1_30),
1421 _ => Err("Unexpected value in register"), 1449 _ => Err(ClockError::UnexpectedCoreVoltageRead),
1422 } 1450 }
1423 } 1451 }
1424 1452
@@ -1443,7 +1471,7 @@ pub fn core_voltage() -> Result<CoreVoltage, &'static str> {
1443 0b01101 => Ok(CoreVoltage::V1_20), 1471 0b01101 => Ok(CoreVoltage::V1_20),
1444 0b01110 => Ok(CoreVoltage::V1_25), 1472 0b01110 => Ok(CoreVoltage::V1_25),
1445 0b01111 => Ok(CoreVoltage::V1_30), 1473 0b01111 => Ok(CoreVoltage::V1_30),
1446 _ => Err("Unexpected value in register"), 1474 _ => Err(ClockError::UnexpectedCoreVoltageRead),
1447 // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point 1475 // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point
1448 } 1476 }
1449 } 1477 }
@@ -1461,7 +1489,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
1461 1489
1462/// PLL (Phase-Locked Loop) configuration 1490/// PLL (Phase-Locked Loop) configuration
1463#[inline(always)] 1491#[inline(always)]
1464fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, &'static str> { 1492fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, ClockError> {
1465 // Calculate reference frequency 1493 // Calculate reference frequency
1466 let ref_freq = input_freq / config.refdiv as u32; 1494 let ref_freq = input_freq / config.refdiv as u32;
1467 1495
@@ -1532,7 +1560,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result
1532 timeout -= 1; 1560 timeout -= 1;
1533 if timeout == 0 { 1561 if timeout == 0 {
1534 // PLL failed to lock, return 0 to indicate failure 1562 // PLL failed to lock, return 0 to indicate failure
1535 return Err("PLL failed to lock"); 1563 return Err(ClockError::PllLockTimedOut);
1536 } 1564 }
1537 } 1565 }
1538 1566
@@ -2103,21 +2131,21 @@ mod tests {
2103 { 2131 {
2104 // Test automatic voltage scaling based on frequency 2132 // Test automatic voltage scaling based on frequency
2105 // Under 133 MHz should use default voltage (V1_10) 2133 // Under 133 MHz should use default voltage (V1_10)
2106 let config = ClockConfig::system_freq(125_000_000); 2134 let config = ClockConfig::system_freq(125_000_000).unwrap();
2107 assert_eq!(config.core_voltage, CoreVoltage::V1_10); 2135 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
2108 2136
2109 // 133-200 MHz should use V1_15 2137 // 133-200 MHz should use V1_15
2110 let config = ClockConfig::system_freq(150_000_000); 2138 let config = ClockConfig::system_freq(150_000_000).unwrap();
2111 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2139 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2112 let config = ClockConfig::system_freq(200_000_000); 2140 let config = ClockConfig::system_freq(200_000_000).unwrap();
2113 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2141 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2114 2142
2115 // Above 200 MHz should use V1_25 2143 // Above 200 MHz should use V1_15
2116 let config = ClockConfig::system_freq(250_000_000); 2144 let config = ClockConfig::system_freq(250_000_000).unwrap();
2117 assert_eq!(config.core_voltage, CoreVoltage::V1_15); 2145 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
2118 2146
2119 // Below 125 MHz should use V1_10 2147 // Below 125 MHz should use V1_10
2120 let config = ClockConfig::system_freq(100_000_000); 2148 let config = ClockConfig::system_freq(100_000_000).unwrap();
2121 assert_eq!(config.core_voltage, CoreVoltage::V1_10); 2149 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
2122 } 2150 }
2123 } 2151 }