diff options
| -rw-r--r-- | embassy-rp/src/clocks.rs | 244 | ||||
| -rw-r--r-- | examples/rp/src/bin/overclock.rs | 10 | ||||
| -rw-r--r-- | examples/rp/src/bin/overclock_manual.rs | 10 | ||||
| -rw-r--r-- | examples/rp235x/src/bin/overclock.rs | 74 | ||||
| -rw-r--r-- | tests/rp/src/bin/overclock.rs | 49 |
5 files changed, 316 insertions, 71 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))] | ||
| 88 | pub 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 | |||
| 85 | struct Clocks { | 97 | struct 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))] | ||
| 146 | pub enum CoreVoltage { | 159 | pub 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))] | ||
| 196 | pub 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 | |||
| 172 | impl CoreVoltage { | 231 | impl 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))] | ||
| 528 | pub enum RoscRange { | 622 | pub 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))] | ||
| 634 | pub enum RefClkSrc { | 729 | pub 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))] | ||
| 649 | pub enum SysClkSrc { | 745 | pub 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))] | ||
| 687 | pub enum UsbClkSrc { | 784 | pub 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))] | ||
| 715 | pub enum AdcClkSrc { | 813 | pub 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")] |
| 744 | pub enum RtcClkSrc { | 843 | pub 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")] | ||
| 795 | fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> { | 893 | fn 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. | ||
| 1408 | pub 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 | |||
| 1286 | fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { | 1456 | fn 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)] |
| 1298 | fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, &'static str> { | 1468 | fn 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 | } |
diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 9c78e0c9d..83b17308b 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; | 10 | use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig}; |
| 11 | use embassy_rp::config::Config; | 11 | use embassy_rp::config::Config; |
| 12 | use embassy_rp::gpio::{Level, Output}; | 12 | use embassy_rp::gpio::{Level, Output}; |
| 13 | use embassy_time::{Duration, Instant, Timer}; | 13 | use embassy_time::{Duration, Instant, Timer}; |
| @@ -18,10 +18,7 @@ const COUNT_TO: i64 = 10_000_000; | |||
| 18 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 19 | async fn main(_spawner: Spawner) -> ! { | 19 | async fn main(_spawner: Spawner) -> ! { |
| 20 | // Set up for clock frequency of 200 MHz, setting all necessary defaults. | 20 | // Set up for clock frequency of 200 MHz, setting all necessary defaults. |
| 21 | let config = Config::new(ClockConfig::system_freq(200_000_000)); | 21 | let config = Config::new(ClockConfig::system_freq(200_000_000).unwrap()); |
| 22 | |||
| 23 | // Show the voltage scale for verification | ||
| 24 | info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage)); | ||
| 25 | 22 | ||
| 26 | // Initialize the peripherals | 23 | // Initialize the peripherals |
| 27 | let p = embassy_rp::init(config); | 24 | let p = embassy_rp::init(config); |
| @@ -29,6 +26,9 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 29 | // Show CPU frequency for verification | 26 | // Show CPU frequency for verification |
| 30 | let sys_freq = clk_sys_freq(); | 27 | let sys_freq = clk_sys_freq(); |
| 31 | info!("System clock frequency: {} MHz", sys_freq / 1_000_000); | 28 | info!("System clock frequency: {} MHz", sys_freq / 1_000_000); |
| 29 | // Show core voltage for verification | ||
| 30 | let core_voltage = core_voltage().unwrap(); | ||
| 31 | info!("Core voltage: {}", core_voltage); | ||
| 32 | 32 | ||
| 33 | // LED to indicate the system is running | 33 | // LED to indicate the system is running |
| 34 | 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 35160b250..dea5cfb3c 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs | |||
| @@ -7,8 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_rp::clocks; | 10 | use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig}; |
| 11 | use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig}; | ||
| 12 | use embassy_rp::config::Config; | 11 | use embassy_rp::config::Config; |
| 13 | use embassy_rp::gpio::{Level, Output}; | 12 | use embassy_rp::gpio::{Level, Output}; |
| 14 | use embassy_time::{Duration, Instant, Timer}; | 13 | use embassy_time::{Duration, Instant, Timer}; |
| @@ -41,9 +40,12 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 41 | // Initialize with our manual overclock configuration | 40 | // Initialize with our manual overclock configuration |
| 42 | let p = embassy_rp::init(configure_manual_overclock()); | 41 | let p = embassy_rp::init(configure_manual_overclock()); |
| 43 | 42 | ||
| 44 | // Verify the actual system clock frequency | 43 | // Show CPU frequency for verification |
| 45 | let sys_freq = clocks::clk_sys_freq(); | 44 | let sys_freq = clk_sys_freq(); |
| 46 | info!("System clock frequency: {} MHz", sys_freq / 1_000_000); | 45 | info!("System clock frequency: {} MHz", sys_freq / 1_000_000); |
| 46 | // Show core voltage for verification | ||
| 47 | let core_voltage = core_voltage().unwrap(); | ||
| 48 | info!("Core voltage: {}", core_voltage); | ||
| 47 | 49 | ||
| 48 | // LED to indicate the system is running | 50 | // LED to indicate the system is running |
| 49 | let mut led = Output::new(p.PIN_25, Level::Low); | 51 | let mut led = Output::new(p.PIN_25, Level::Low); |
diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs new file mode 100644 index 000000000..5fd97ef97 --- /dev/null +++ b/examples/rp235x/src/bin/overclock.rs | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | //! # Overclocking the RP2350 to 200 MHz | ||
| 2 | //! | ||
| 3 | //! This example demonstrates how to configure the RP2350 to run at 200 MHz instead of the default 150 MHz. | ||
| 4 | //! | ||
| 5 | //! ## Note | ||
| 6 | //! | ||
| 7 | //! As of yet there is no official support for running the RP235x at higher clock frequencies and/or other core voltages than the default. | ||
| 8 | //! Doing so may cause unexpected behavior and/or damage the chip. | ||
| 9 | |||
| 10 | #![no_std] | ||
| 11 | #![no_main] | ||
| 12 | |||
| 13 | use defmt::*; | ||
| 14 | use embassy_executor::Spawner; | ||
| 15 | use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; | ||
| 16 | use embassy_rp::config::Config; | ||
| 17 | use embassy_rp::gpio::{Level, Output}; | ||
| 18 | use embassy_time::{Duration, Instant, Timer}; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | const COUNT_TO: i64 = 10_000_000; | ||
| 22 | |||
| 23 | #[embassy_executor::main] | ||
| 24 | async fn main(_spawner: Spawner) -> ! { | ||
| 25 | // Set up for clock frequency of 200 MHz, setting all necessary defaults. | ||
| 26 | let mut config = Config::new(ClockConfig::system_freq(200_000_000).unwrap()); | ||
| 27 | |||
| 28 | // since for the rp235x there is no official support for higher clock frequencies, `system_freq()` will not set a voltage for us. | ||
| 29 | // We need to guess the core voltage, that is needed for the higher clock frequency. Going with a small increase from the default 1.1V here, based on | ||
| 30 | // what we know about the RP2040. This is not guaranteed to be correct. | ||
| 31 | config.clocks.core_voltage = CoreVoltage::V1_15; | ||
| 32 | |||
| 33 | // Initialize the peripherals | ||
| 34 | let p = embassy_rp::init(config); | ||
| 35 | |||
| 36 | // Show CPU frequency for verification | ||
| 37 | let sys_freq = clk_sys_freq(); | ||
| 38 | info!("System clock frequency: {} MHz", sys_freq / 1_000_000); | ||
| 39 | // Show core voltage for verification | ||
| 40 | let core_voltage = core_voltage().unwrap(); | ||
| 41 | info!("Core voltage: {}", core_voltage); | ||
| 42 | |||
| 43 | // LED to indicate the system is running | ||
| 44 | let mut led = Output::new(p.PIN_25, Level::Low); | ||
| 45 | |||
| 46 | loop { | ||
| 47 | // Reset the counter at the start of measurement period | ||
| 48 | let mut counter = 0; | ||
| 49 | |||
| 50 | // Turn LED on while counting | ||
| 51 | led.set_high(); | ||
| 52 | |||
| 53 | let start = Instant::now(); | ||
| 54 | |||
| 55 | // This is a busy loop that will take some time to complete | ||
| 56 | while counter < COUNT_TO { | ||
| 57 | counter += 1; | ||
| 58 | } | ||
| 59 | |||
| 60 | let elapsed = Instant::now() - start; | ||
| 61 | |||
| 62 | // Report the elapsed time | ||
| 63 | led.set_low(); | ||
| 64 | info!( | ||
| 65 | "At {}Mhz: Elapsed time to count to {}: {}ms", | ||
| 66 | sys_freq / 1_000_000, | ||
| 67 | counter, | ||
| 68 | elapsed.as_millis() | ||
| 69 | ); | ||
| 70 | |||
| 71 | // Wait 2 seconds before starting the next measurement | ||
| 72 | Timer::after(Duration::from_secs(2)).await; | ||
| 73 | } | ||
| 74 | } | ||
diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index be8e85a3f..167a26eb2 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs | |||
| @@ -7,14 +7,8 @@ teleprobe_meta::target!(b"rpi-pico"); | |||
| 7 | teleprobe_meta::target!(b"pimoroni-pico-plus-2"); | 7 | teleprobe_meta::target!(b"pimoroni-pico-plus-2"); |
| 8 | 8 | ||
| 9 | use defmt::info; | 9 | use defmt::info; |
| 10 | #[cfg(feature = "rp2040")] | ||
| 11 | use defmt::{assert, assert_eq}; | ||
| 12 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| 13 | use embassy_rp::clocks; | 11 | use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; |
| 14 | #[cfg(feature = "rp2040")] | ||
| 15 | use embassy_rp::clocks::ClockConfig; | ||
| 16 | #[cfg(feature = "rp2040")] | ||
| 17 | use embassy_rp::clocks::CoreVoltage; | ||
| 18 | use embassy_rp::config::Config; | 12 | use embassy_rp::config::Config; |
| 19 | use embassy_time::Instant; | 13 | use embassy_time::Instant; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -23,23 +17,26 @@ const COUNT_TO: i64 = 10_000_000; | |||
| 23 | 17 | ||
| 24 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
| 25 | async fn main(_spawner: Spawner) { | 19 | async fn main(_spawner: Spawner) { |
| 26 | #[cfg(feature = "rp2040")] | ||
| 27 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| 28 | #[cfg(not(feature = "rp2040"))] | ||
| 29 | let config = Config::default(); | ||
| 30 | 21 | ||
| 31 | // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock | 22 | // Initialize with 200MHz clock configuration |
| 32 | #[cfg(feature = "rp2040")] | 23 | config.clocks = ClockConfig::system_freq(200_000_000).unwrap(); |
| 24 | |||
| 25 | // if we are rp235x, we need to manually set the core voltage. rp2040 should do this automatically | ||
| 26 | #[cfg(feature = "rp235xb")] | ||
| 33 | { | 27 | { |
| 34 | config.clocks = ClockConfig::system_freq(200_000_000); | 28 | config.clocks.core_voltage = CoreVoltage::V1_15; |
| 35 | let voltage = config.clocks.core_voltage; | ||
| 36 | assert!(matches!(voltage, CoreVoltage::V1_15), "Expected voltage scale V1_15"); | ||
| 37 | } | 29 | } |
| 38 | 30 | ||
| 39 | let _p = embassy_rp::init(config); | 31 | let _p = embassy_rp::init(config); |
| 40 | 32 | ||
| 33 | // We should be at core voltage of 1.15V | ||
| 34 | assert_eq!(core_voltage().unwrap(), CoreVoltage::V1_15, "Core voltage is not 1.15V"); | ||
| 35 | // We should be at 200MHz | ||
| 36 | assert_eq!(clk_sys_freq(), 200_000_000, "System clock frequency is not 200MHz"); | ||
| 37 | |||
| 41 | // Test the system speed | 38 | // Test the system speed |
| 42 | let (time_elapsed, clk_sys_freq) = { | 39 | let time_elapsed = { |
| 43 | let mut counter = 0; | 40 | let mut counter = 0; |
| 44 | let start = Instant::now(); | 41 | let start = Instant::now(); |
| 45 | while counter < COUNT_TO { | 42 | while counter < COUNT_TO { |
| @@ -47,24 +44,26 @@ async fn main(_spawner: Spawner) { | |||
| 47 | } | 44 | } |
| 48 | let elapsed = Instant::now() - start; | 45 | let elapsed = Instant::now() - start; |
| 49 | 46 | ||
| 50 | (elapsed.as_millis(), clocks::clk_sys_freq()) | 47 | elapsed.as_millis() |
| 51 | }; | 48 | }; |
| 52 | 49 | ||
| 53 | // Report the elapsed time, so that the compiler doesn't optimize it away for chips other than RP2040 | 50 | // Tests will fail if unused variables are detected: |
| 51 | // Report the elapsed time, so that the compiler doesn't optimize it away for the chip not on test | ||
| 54 | info!( | 52 | info!( |
| 55 | "At {}Mhz: Elapsed time to count to {}: {}ms", | 53 | "At {}Mhz: Elapsed time to count to {}: {}ms", |
| 56 | clk_sys_freq / 1_000_000, | 54 | clk_sys_freq() / 1_000_000, |
| 57 | COUNT_TO, | 55 | COUNT_TO, |
| 58 | time_elapsed | 56 | time_elapsed |
| 59 | ); | 57 | ); |
| 60 | 58 | ||
| 59 | // Check if the elapsed time is within expected limits | ||
| 60 | // for rp2040 we expect about 600ms | ||
| 61 | #[cfg(feature = "rp2040")] | 61 | #[cfg(feature = "rp2040")] |
| 62 | { | 62 | // allow 1% error |
| 63 | // we should be at 200MHz | 63 | assert!(time_elapsed < 606, "Elapsed time is too long"); |
| 64 | assert_eq!(clk_sys_freq, 200_000_000, "System clock frequency is not 200MHz"); | 64 | // for rp235x we expect about 450ms |
| 65 | // At 200MHz, the time to count to 10_000_000 should be at 600ms, testing with 1% margin | 65 | #[cfg(feature = "rp235xb")] |
| 66 | assert!(time_elapsed <= 606, "Elapsed time is too long"); | 66 | assert!(time_elapsed < 455, "Elapsed time is too long"); |
| 67 | } | ||
| 68 | 67 | ||
| 69 | cortex_m::asm::bkpt(); | 68 | cortex_m::asm::bkpt(); |
| 70 | } | 69 | } |
