aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author1-rafael-1 <[email protected]>2025-05-11 17:26:36 +0200
committer1-rafael-1 <[email protected]>2025-05-11 17:26:36 +0200
commit4567beda7b7773c8cb11f19f0f4f146c1243508d (patch)
treea01a9fe7649508c846dd772a47650bb271430acb
parent4621c8aa7a1ee1b55f2f0bf80fc48eddf76af320 (diff)
rp235x overclocking
-rw-r--r--embassy-rp/src/clocks.rs329
-rw-r--r--examples/rp/src/bin/overclock.rs8
-rw-r--r--examples/rp/src/bin/overclock_manual.rs10
-rw-r--r--examples/rp235x/src/bin/overclock.rs74
-rw-r--r--tests/rp/src/bin/overclock.rs49
5 files changed, 405 insertions, 65 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 6694aab66..ea5e9362b 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//! ```
@@ -136,43 +136,152 @@ pub enum PeriClkSrc {
136 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , 136 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
137} 137}
138 138
139/// Core voltage regulator settings for RP2040. 139/// Core voltage regulator settings.
140/// 140///
141/// The RP2040 voltage regulator can be configured for different output voltages. 141/// The voltage regulator can be configured for different output voltages.
142/// Higher voltages allow for higher clock frequencies but increase power consumption and heat. 142/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
143#[cfg(feature = "rp2040")]
144#[derive(Clone, Copy, Debug, PartialEq, Eq)] 143#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145#[repr(u8)] 144#[repr(u8)]
146pub enum CoreVoltage { 145pub enum CoreVoltage {
147 /// 0.80V - Suitable for lower frequencies 146 // RP2040 voltage levels
147 #[cfg(feature = "rp2040")]
148 /// RP2040: 0.80V
148 V0_80 = 0b0000, 149 V0_80 = 0b0000,
149 /// 0.85V 150 #[cfg(feature = "rp2040")]
151 /// RP2040: 0.85V
150 V0_85 = 0b0110, 152 V0_85 = 0b0110,
151 /// 0.90V 153 #[cfg(feature = "rp2040")]
154 /// RP2040: 0.90V
152 V0_90 = 0b0111, 155 V0_90 = 0b0111,
153 /// 0.95V 156 #[cfg(feature = "rp2040")]
157 /// RP2040: 0.95V
154 V0_95 = 0b1000, 158 V0_95 = 0b1000,
155 /// 1.00V 159 #[cfg(feature = "rp2040")]
160 /// RP2040: 1.00V
156 V1_00 = 0b1001, 161 V1_00 = 0b1001,
157 /// 1.05V 162 #[cfg(feature = "rp2040")]
163 /// RP2040: 1.05V
158 V1_05 = 0b1010, 164 V1_05 = 0b1010,
159 /// 1.10V - Default voltage level 165 #[cfg(feature = "rp2040")]
166 /// RP2040: 1.10V - Default voltage level
160 V1_10 = 0b1011, 167 V1_10 = 0b1011,
161 /// 1.15V - Required for overclocking to 133-200MHz 168 #[cfg(feature = "rp2040")]
169 /// RP2040: 1.15V - Required for overclocking to 133-200MHz
162 V1_15 = 0b1100, 170 V1_15 = 0b1100,
163 /// 1.20V 171 #[cfg(feature = "rp2040")]
172 /// RP2040: 1.20V
164 V1_20 = 0b1101, 173 V1_20 = 0b1101,
165 /// 1.25V 174 #[cfg(feature = "rp2040")]
175 /// RP2040: 1.25V
166 V1_25 = 0b1110, 176 V1_25 = 0b1110,
167 /// 1.30V 177 #[cfg(feature = "rp2040")]
178 /// RP2040: 1.30V
168 V1_30 = 0b1111, 179 V1_30 = 0b1111,
180
181 // RP235x voltage levels
182 #[cfg(feature = "_rp235x")]
183 /// RP235x: 0.55V
184 V0_55 = 0b00000,
185 #[cfg(feature = "_rp235x")]
186 /// RP235x: 0.60V
187 V0_60 = 0b00001,
188 #[cfg(feature = "_rp235x")]
189 /// RP235x: 0.65V
190 V0_65 = 0b00010,
191 #[cfg(feature = "_rp235x")]
192 /// RP235x: 0.70V
193 V0_70 = 0b00011,
194 #[cfg(feature = "_rp235x")]
195 /// RP235x: 0.75V
196 V0_75 = 0b00100,
197 #[cfg(feature = "_rp235x")]
198 /// RP235x: 0.80V
199 V0_80 = 0b00101,
200 #[cfg(feature = "_rp235x")]
201 /// RP235x: 0.85V
202 V0_85 = 0b00110,
203 #[cfg(feature = "_rp235x")]
204 /// RP235x: 0.90V
205 V0_90 = 0b00111,
206 #[cfg(feature = "_rp235x")]
207 /// RP235x: 0.95V
208 V0_95 = 0b01000,
209 #[cfg(feature = "_rp235x")]
210 /// RP235x: 1.00V
211 V1_00 = 0b01001,
212 #[cfg(feature = "_rp235x")]
213 /// RP235x: 1.05V
214 V1_05 = 0b01010,
215 #[cfg(feature = "_rp235x")]
216 /// RP235x: 1.10V - Default voltage level
217 V1_10 = 0b01011,
218 #[cfg(feature = "_rp235x")]
219 /// RP235x: 1.15V
220 V1_15 = 0b01100,
221 #[cfg(feature = "_rp235x")]
222 /// RP235x: 1.20V
223 V1_20 = 0b01101,
224 #[cfg(feature = "_rp235x")]
225 /// RP235x: 1.25V
226 V1_25 = 0b01110,
227 #[cfg(feature = "_rp235x")]
228 /// RP235x: 1.30V
229 V1_30 = 0b01111,
230 #[cfg(feature = "_rp235x")]
231 /// RP235x: 1.35V
232 V1_35 = 0b10000,
233 #[cfg(feature = "_rp235x")]
234 /// RP235x: 1.40V
235 V1_40 = 0b10001,
236 #[cfg(feature = "_rp235x")]
237 /// RP235x: 1.50V
238 V1_50 = 0b10010,
239 #[cfg(feature = "_rp235x")]
240 /// RP235x: 1.60V
241 V1_60 = 0b10011,
242 #[cfg(feature = "_rp235x")]
243 /// RP235x: 1.65V
244 V1_65 = 0b10100,
245 #[cfg(feature = "_rp235x")]
246 /// RP235x: 1.70V
247 V1_70 = 0b10101,
248 #[cfg(feature = "_rp235x")]
249 /// RP235x: 1.80V
250 V1_80 = 0b10110,
251 #[cfg(feature = "_rp235x")]
252 /// RP235x: 1.90V
253 V1_90 = 0b10111,
254 #[cfg(feature = "_rp235x")]
255 /// RP235x: 2.00V
256 V2_00 = 0b11000,
257 #[cfg(feature = "_rp235x")]
258 /// RP235x: 2.35V
259 V2_35 = 0b11001,
260 #[cfg(feature = "_rp235x")]
261 /// RP235x: 2.50V
262 V2_50 = 0b11010,
263 #[cfg(feature = "_rp235x")]
264 /// RP235x: 2.65V
265 V2_65 = 0b11011,
266 #[cfg(feature = "_rp235x")]
267 /// RP235x: 2.80V
268 V2_80 = 0b11100,
269 #[cfg(feature = "_rp235x")]
270 /// RP235x: 3.00V
271 V3_00 = 0b11101,
272 #[cfg(feature = "_rp235x")]
273 /// RP235x: 3.15V
274 V3_15 = 0b11110,
275 #[cfg(feature = "_rp235x")]
276 /// RP235x: 3.30V
277 V3_30 = 0b11111,
169} 278}
170 279
171#[cfg(feature = "rp2040")]
172impl CoreVoltage { 280impl CoreVoltage {
173 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. 281 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage.
174 /// Sets the BOD threshold to approximately 80% of the core voltage. 282 /// Sets the BOD threshold to approximately 80% of the core voltage.
175 fn recommended_bod(self) -> u8 { 283 fn recommended_bod(self) -> u8 {
284 #[cfg(feature = "rp2040")]
176 match self { 285 match self {
177 CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V) 286 CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V)
178 CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V) 287 CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V)
@@ -180,12 +289,38 @@ impl CoreVoltage {
180 CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V) 289 CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V)
181 CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V) 290 CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V)
182 CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V) 291 CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V)
183 CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V) 292 CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V), the default
184 CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V) 293 CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V)
185 CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V) 294 CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V)
186 CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V) 295 CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V)
187 CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V) 296 CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V)
188 } 297 }
298 #[cfg(feature = "_rp235x")]
299 match self {
300 CoreVoltage::V0_55 => 0b00001, // 0.516V (~94% of 0.55V)
301 CoreVoltage::V0_60 => 0b00010, // 0.559V (~93% of 0.60V)
302 CoreVoltage::V0_65 => 0b00011, // 0.602V (~93% of 0.65V)
303 CoreVoltage::V0_70 => 0b00011, // 0.602V (~86% of 0.70V)
304 CoreVoltage::V0_75 => 0b00100, // 0.645V (~86% of 0.75V)
305 CoreVoltage::V0_80 => 0b00101, // 0.688V (~86% of 0.80V)
306 CoreVoltage::V0_85 => 0b00110, // 0.731V (~86% of 0.85V)
307 CoreVoltage::V0_90 => 0b00110, // 0.731V (~81% of 0.90V)
308 CoreVoltage::V0_95 => 0b00111, // 0.774V (~81% of 0.95V)
309 CoreVoltage::V1_00 => 0b01000, // 0.817V (~82% of 1.00V)
310 CoreVoltage::V1_05 => 0b01000, // 0.817V (~78% of 1.05V)
311 CoreVoltage::V1_10 => 0b01001, // 0.860V (~78% of 1.10V), the default
312 CoreVoltage::V1_15 => 0b01001, // 0.860V (~75% of 1.15V)
313 CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V)
314 CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V)
315 CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V)
316 CoreVoltage::V1_35 => 0b01011, // 0.946V (~70% of 1.35V)
317 CoreVoltage::V1_40 => 0b01100, // 0.989V (~71% of 1.40V)
318 CoreVoltage::V1_50 => 0b01101, // 1.032V (~69% of 1.50V)
319 CoreVoltage::V1_60 => 0b01110, // 1.075V (~67% of 1.60V)
320 CoreVoltage::V1_65 => 0b01110, // 1.075V (~65% of 1.65V)
321 CoreVoltage::V1_70 => 0b01111, // 1.118V (~66% of 1.70V)
322 _ => 0b10000, // the rp2350 datasheet repeats this value for all other core voltages
323 }
189 } 324 }
190} 325}
191 326
@@ -209,12 +344,10 @@ pub struct ClockConfig {
209 /// RTC clock configuration. 344 /// RTC clock configuration.
210 #[cfg(feature = "rp2040")] 345 #[cfg(feature = "rp2040")]
211 pub rtc_clk: Option<RtcClkConfig>, 346 pub rtc_clk: Option<RtcClkConfig>,
212 /// Core voltage scaling (RP2040 only). Defaults to 1.10V. 347 /// Core voltage scaling. Defaults to 1.10V.
213 #[cfg(feature = "rp2040")]
214 pub core_voltage: CoreVoltage, 348 pub core_voltage: CoreVoltage,
215 /// Voltage stabilization delay in microseconds. 349 /// Voltage stabilization delay in microseconds.
216 /// If not set, defaults will be used based on voltage level. 350 /// If not set, defaults will be used based on voltage level.
217 #[cfg(feature = "rp2040")]
218 pub voltage_stabilization_delay_us: Option<u32>, 351 pub voltage_stabilization_delay_us: Option<u32>,
219 // See above re gpin handling being commented out 352 // See above re gpin handling being commented out
220 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 353 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
@@ -250,9 +383,7 @@ impl Default for ClockConfig {
250 adc_clk: None, 383 adc_clk: None,
251 #[cfg(feature = "rp2040")] 384 #[cfg(feature = "rp2040")]
252 rtc_clk: None, 385 rtc_clk: None,
253 #[cfg(feature = "rp2040")]
254 core_voltage: CoreVoltage::V1_10, 386 core_voltage: CoreVoltage::V1_10,
255 #[cfg(feature = "rp2040")]
256 voltage_stabilization_delay_us: None, 387 voltage_stabilization_delay_us: None,
257 // See above re gpin handling being commented out 388 // See above re gpin handling being commented out
258 // gpin0: None, 389 // gpin0: None,
@@ -323,9 +454,7 @@ impl ClockConfig {
323 div_frac: 0, 454 div_frac: 0,
324 phase: 0, 455 phase: 0,
325 }), 456 }),
326 #[cfg(feature = "rp2040")]
327 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) 457 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
328 #[cfg(feature = "rp2040")]
329 voltage_stabilization_delay_us: None, 458 voltage_stabilization_delay_us: None,
330 // See above re gpin handling being commented out 459 // See above re gpin handling being commented out
331 // gpin0: None, 460 // gpin0: None,
@@ -368,9 +497,7 @@ impl ClockConfig {
368 div_frac: 171, 497 div_frac: 171,
369 phase: 0, 498 phase: 0,
370 }), 499 }),
371 #[cfg(feature = "rp2040")]
372 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) 500 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
373 #[cfg(feature = "rp2040")]
374 voltage_stabilization_delay_us: None, 501 voltage_stabilization_delay_us: None,
375 // See above re gpin handling being commented out 502 // See above re gpin handling being commented out
376 // gpin0: None, 503 // gpin0: None,
@@ -394,12 +521,17 @@ impl ClockConfig {
394 /// the usual 12Mhz crystal, or panic if no valid parameters can be found. 521 /// the usual 12Mhz crystal, or panic if no valid parameters can be found.
395 /// 522 ///
396 /// # Note on core voltage: 523 /// # Note on core voltage:
524 ///
525 /// **For RP2040**:
397 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are: 526 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are:
398 /// - Up to 133MHz: V1_10 (default) 527 /// - Up to 133MHz: V1_10 (default)
399 /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz 528 /// - 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. 529 /// 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. 530 /// 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")] 531 ///
532 /// **For RP235x**:
533 /// 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.
534 /// Using this function is experimental and may not work as expected or even damage the chip.
403 pub fn system_freq(hz: u32) -> Self { 535 pub fn system_freq(hz: u32) -> Self {
404 // Start with the standard configuration from crystal() 536 // Start with the standard configuration from crystal()
405 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; 537 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000;
@@ -407,9 +539,14 @@ impl ClockConfig {
407 539
408 // No need to modify anything if target frequency is already 125MHz 540 // No need to modify anything if target frequency is already 125MHz
409 // (which is what crystal() configures by default) 541 // (which is what crystal() configures by default)
542 #[cfg(feature = "rp2040")]
410 if hz == 125_000_000 { 543 if hz == 125_000_000 {
411 return config; 544 return config;
412 } 545 }
546 #[cfg(feature = "_rp235x")]
547 if hz == 150_000_000 {
548 return config;
549 }
413 550
414 // Find optimal PLL parameters for the requested frequency 551 // Find optimal PLL parameters for the requested frequency
415 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) 552 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz)
@@ -429,6 +566,14 @@ impl ClockConfig {
429 _ => CoreVoltage::V1_10, // Use default voltage (V1_10) 566 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
430 }; 567 };
431 } 568 }
569 #[cfg(feature = "_rp235x")]
570 {
571 config.core_voltage = match hz {
572 // There is no official support for running the chip on other core voltages and/or other clock speeds than the defaults.
573 // So for now we have not way of knowing what the voltage should be. Change this if the manufacturer provides more information.
574 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
575 };
576 }
432 577
433 config 578 config
434 } 579 }
@@ -791,7 +936,6 @@ pub struct RtcClkConfig {
791/// // Find parameters for 133MHz system clock from 12MHz crystal 936/// // Find parameters for 133MHz system clock from 12MHz crystal
792/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap(); 937/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap();
793/// ``` 938/// ```
794#[cfg(feature = "rp2040")]
795fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> { 939fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> {
796 // Fixed reference divider for system PLL 940 // Fixed reference divider for system PLL
797 const PLL_SYS_REFDIV: u8 = 1; 941 const PLL_SYS_REFDIV: u8 = 1;
@@ -925,18 +1069,59 @@ pub(crate) unsafe fn init(config: ClockConfig) {
925 }; 1069 };
926 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); 1070 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed);
927 1071
928 // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default 1072 // Set Core Voltage, if we have config for it and we're not using the default
929 #[cfg(feature = "rp2040")]
930 { 1073 {
931 let voltage = config.core_voltage; 1074 let voltage = config.core_voltage;
1075
1076 #[cfg(feature = "rp2040")]
932 let vreg = pac::VREG_AND_CHIP_RESET; 1077 let vreg = pac::VREG_AND_CHIP_RESET;
1078 #[cfg(feature = "_rp235x")]
1079 let vreg = pac::POWMAN;
1080
933 let current_vsel = vreg.vreg().read().vsel(); 1081 let current_vsel = vreg.vreg().read().vsel();
934 let target_vsel = voltage as u8; 1082 let target_vsel = voltage as u8;
935 1083
936 // If the target voltage is different from the current one, we need to change it 1084 // If the target voltage is different from the current one, we need to change it
937 if target_vsel != current_vsel { 1085 if target_vsel != current_vsel {
938 // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage 1086 #[cfg(feature = "rp2040")]
939 vreg.vreg().modify(|w| w.set_vsel(target_vsel)); 1087 {
1088 // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage
1089 vreg.vreg().modify(|w| w.set_vsel(target_vsel));
1090 }
1091 #[cfg(feature = "_rp235x")]
1092 {
1093 // The rp235x has a different way of controlling the voltage regulator
1094 // Changes to the voltage regulator are protected by a password, see datasheet section 6.4
1095 // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register
1096
1097 // The rp235x by default locks the voltage regulator control, so we need to unlock it first
1098 // See datasheet section 6.3.2. Software Control
1099 vreg.vreg_ctrl().modify(|w| {
1100 // Add password to top 16 bits, preserving the rest, repeat below for other registers
1101 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16);
1102 w.set_unlock(true);
1103 *w
1104 });
1105
1106 // Set the voltage
1107 vreg.vreg().modify(|w| {
1108 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16);
1109 w.set_vsel(target_vsel);
1110 *w
1111 });
1112
1113 // The rp235x has two more registers to set the voltage for low power mode
1114 vreg.vreg_lp_entry().modify(|w| {
1115 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16);
1116 w.set_vsel(target_vsel);
1117 *w
1118 });
1119 vreg.vreg_lp_exit().modify(|w| {
1120 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16);
1121 w.set_vsel(target_vsel);
1122 *w
1123 });
1124 }
940 1125
941 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage 1126 // 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(|| { 1127 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| {
@@ -959,6 +1144,19 @@ pub(crate) unsafe fn init(config: ClockConfig) {
959 w.set_vsel(voltage.recommended_bod()); 1144 w.set_vsel(voltage.recommended_bod());
960 w.set_en(true); // Enable brownout detection 1145 w.set_en(true); // Enable brownout detection
961 }); 1146 });
1147
1148 #[cfg(feature = "_rp235x")]
1149 {
1150 // The rp235x has a separate register for the BOD level in low power mode
1151 vreg.bod_lp_entry().write(|w| {
1152 w.set_vsel(voltage.recommended_bod());
1153 w.set_en(true); // Enable brownout detection
1154 });
1155 vreg.bod_lp_exit().write(|w| {
1156 w.set_vsel(voltage.recommended_bod());
1157 w.set_en(true); // Enable brownout detection
1158 });
1159 }
962 } 1160 }
963 } 1161 }
964 1162
@@ -1283,6 +1481,73 @@ pub fn clk_rtc_freq() -> u16 {
1283 CLOCKS.rtc.load(Ordering::Relaxed) 1481 CLOCKS.rtc.load(Ordering::Relaxed)
1284} 1482}
1285 1483
1484/// The core voltage of the chip.
1485///
1486/// Returns the current core voltage or an error if the voltage register
1487/// contains an unknown value.
1488pub fn core_voltage() -> Result<CoreVoltage, &'static str> {
1489 #[cfg(feature = "rp2040")]
1490 {
1491 let vreg = pac::VREG_AND_CHIP_RESET;
1492 let vsel = vreg.vreg().read().vsel();
1493 match vsel {
1494 0b0000 => Ok(CoreVoltage::V0_80),
1495 0b0110 => Ok(CoreVoltage::V0_85),
1496 0b0111 => Ok(CoreVoltage::V0_90),
1497 0b1000 => Ok(CoreVoltage::V0_95),
1498 0b1001 => Ok(CoreVoltage::V1_00),
1499 0b1010 => Ok(CoreVoltage::V1_05),
1500 0b1011 => Ok(CoreVoltage::V1_10),
1501 0b1100 => Ok(CoreVoltage::V1_15),
1502 0b1101 => Ok(CoreVoltage::V1_20),
1503 0b1110 => Ok(CoreVoltage::V1_25),
1504 0b1111 => Ok(CoreVoltage::V1_30),
1505 _ => Err("Unexpected value in register"),
1506 }
1507 }
1508
1509 #[cfg(feature = "_rp235x")]
1510 {
1511 let vreg = pac::POWMAN;
1512 let vsel = vreg.vreg().read().vsel();
1513 match vsel {
1514 0b00000 => Ok(CoreVoltage::V0_55),
1515 0b00001 => Ok(CoreVoltage::V0_60),
1516 0b00010 => Ok(CoreVoltage::V0_65),
1517 0b00011 => Ok(CoreVoltage::V0_70),
1518 0b00100 => Ok(CoreVoltage::V0_75),
1519 0b00101 => Ok(CoreVoltage::V0_80),
1520 0b00110 => Ok(CoreVoltage::V0_85),
1521 0b00111 => Ok(CoreVoltage::V0_90),
1522 0b01000 => Ok(CoreVoltage::V0_95),
1523 0b01001 => Ok(CoreVoltage::V1_00),
1524 0b01010 => Ok(CoreVoltage::V1_05),
1525 0b01011 => Ok(CoreVoltage::V1_10),
1526 0b01100 => Ok(CoreVoltage::V1_15),
1527 0b01101 => Ok(CoreVoltage::V1_20),
1528 0b01110 => Ok(CoreVoltage::V1_25),
1529 0b01111 => Ok(CoreVoltage::V1_30),
1530 0b10000 => Ok(CoreVoltage::V1_35),
1531 0b10001 => Ok(CoreVoltage::V1_40),
1532 0b10010 => Ok(CoreVoltage::V1_50),
1533 0b10011 => Ok(CoreVoltage::V1_60),
1534 0b10100 => Ok(CoreVoltage::V1_65),
1535 0b10101 => Ok(CoreVoltage::V1_70),
1536 0b10110 => Ok(CoreVoltage::V1_80),
1537 0b10111 => Ok(CoreVoltage::V1_90),
1538 0b11000 => Ok(CoreVoltage::V2_00),
1539 0b11001 => Ok(CoreVoltage::V2_35),
1540 0b11010 => Ok(CoreVoltage::V2_50),
1541 0b11011 => Ok(CoreVoltage::V2_65),
1542 0b11100 => Ok(CoreVoltage::V2_80),
1543 0b11101 => Ok(CoreVoltage::V3_00),
1544 0b11110 => Ok(CoreVoltage::V3_15),
1545 0b11111 => Ok(CoreVoltage::V3_30),
1546 _ => Err("Unexpected value in register"),
1547 }
1548 }
1549}
1550
1286fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { 1551fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
1287 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256; 1552 let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256;
1288 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); 1553 pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16));
diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs
index 9c78e0c9d..89147ba42 100644
--- a/examples/rp/src/bin/overclock.rs
+++ b/examples/rp/src/bin/overclock.rs
@@ -7,7 +7,7 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; 10use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig};
11use embassy_rp::config::Config; 11use embassy_rp::config::Config;
12use embassy_rp::gpio::{Level, Output}; 12use embassy_rp::gpio::{Level, Output};
13use embassy_time::{Duration, Instant, Timer}; 13use embassy_time::{Duration, Instant, Timer};
@@ -20,15 +20,15 @@ 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));
22 22
23 // Show the voltage scale for verification
24 info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage));
25
26 // Initialize the peripherals 23 // Initialize the peripherals
27 let p = embassy_rp::init(config); 24 let p = embassy_rp::init(config);
28 25
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: {}", Debug2Format(&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..88ef26a7a 100644
--- a/examples/rp/src/bin/overclock_manual.rs
+++ b/examples/rp/src/bin/overclock_manual.rs
@@ -7,8 +7,7 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::clocks; 10use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig};
11use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig};
12use embassy_rp::config::Config; 11use embassy_rp::config::Config;
13use embassy_rp::gpio::{Level, Output}; 12use embassy_rp::gpio::{Level, Output};
14use embassy_time::{Duration, Instant, Timer}; 13use 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: {}", Debug2Format(&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..8713df688
--- /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
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage};
16use embassy_rp::config::Config;
17use embassy_rp::gpio::{Level, Output};
18use embassy_time::{Duration, Instant, Timer};
19use {defmt_rtt as _, panic_probe as _};
20
21const COUNT_TO: i64 = 10_000_000;
22
23#[embassy_executor::main]
24async 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));
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: {}", Debug2Format(&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..a568d7fed 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");
7teleprobe_meta::target!(b"pimoroni-pico-plus-2"); 7teleprobe_meta::target!(b"pimoroni-pico-plus-2");
8 8
9use defmt::info; 9use defmt::info;
10#[cfg(feature = "rp2040")]
11use defmt::{assert, assert_eq};
12use embassy_executor::Spawner; 10use embassy_executor::Spawner;
13use embassy_rp::clocks; 11use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage};
14#[cfg(feature = "rp2040")]
15use embassy_rp::clocks::ClockConfig;
16#[cfg(feature = "rp2040")]
17use embassy_rp::clocks::CoreVoltage;
18use embassy_rp::config::Config; 12use embassy_rp::config::Config;
19use embassy_time::Instant; 13use embassy_time::Instant;
20use {defmt_rtt as _, panic_probe as _}; 14use {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]
25async fn main(_spawner: Spawner) { 19async 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);
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}