diff options
Diffstat (limited to 'embassy-rp/src')
| -rw-r--r-- | embassy-rp/src/clocks.rs | 329 |
1 files changed, 297 insertions, 32 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)] |
| 146 | pub enum CoreVoltage { | 145 | pub 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")] | ||
| 172 | impl CoreVoltage { | 280 | impl 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")] | ||
| 795 | fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> { | 939 | fn 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. | ||
| 1488 | pub 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 | |||
| 1286 | fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { | 1551 | fn 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)); |
