aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/clocks.rs141
1 files changed, 21 insertions, 120 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index ea5e9362b..bcd08c204 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -140,6 +140,10 @@ pub enum PeriClkSrc {
140/// 140///
141/// The 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///
144/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit
145/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this
146/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now.
143#[derive(Clone, Copy, Debug, PartialEq, Eq)] 147#[derive(Clone, Copy, Debug, PartialEq, Eq)]
144#[repr(u8)] 148#[repr(u8)]
145pub enum CoreVoltage { 149pub enum CoreVoltage {
@@ -227,54 +231,6 @@ pub enum CoreVoltage {
227 #[cfg(feature = "_rp235x")] 231 #[cfg(feature = "_rp235x")]
228 /// RP235x: 1.30V 232 /// RP235x: 1.30V
229 V1_30 = 0b01111, 233 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,
278} 234}
279 235
280impl CoreVoltage { 236impl CoreVoltage {
@@ -313,13 +269,7 @@ impl CoreVoltage {
313 CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V) 269 CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V)
314 CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V) 270 CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V)
315 CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V) 271 CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V)
316 CoreVoltage::V1_35 => 0b01011, // 0.946V (~70% of 1.35V) 272 // all others: 0.946V (see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point)
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 } 273 }
324 } 274 }
325} 275}
@@ -1083,45 +1033,17 @@ pub(crate) unsafe fn init(config: ClockConfig) {
1083 1033
1084 // If the target voltage is different from the current one, we need to change it 1034 // If the target voltage is different from the current one, we need to change it
1085 if target_vsel != current_vsel { 1035 if target_vsel != current_vsel {
1036 // Set the voltage regulator to the target voltage
1086 #[cfg(feature = "rp2040")] 1037 #[cfg(feature = "rp2040")]
1087 { 1038 vreg.vreg().modify(|w| w.set_vsel(target_vsel));
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")] 1039 #[cfg(feature = "_rp235x")]
1092 { 1040 // For rp235x changes to the voltage regulator are protected by a password, see datasheet section 6.4 Power Management (POWMAN) Registers
1093 // The rp235x has a different way of controlling the voltage regulator 1041 // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register
1094 // Changes to the voltage regulator are protected by a password, see datasheet section 6.4 1042 vreg.vreg().modify(|w| {
1095 // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register 1043 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
1096 1044 w.set_vsel(target_vsel);
1097 // The rp235x by default locks the voltage regulator control, so we need to unlock it first 1045 *w
1098 // See datasheet section 6.3.2. Software Control 1046 });
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 }
1125 1047
1126 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage 1048 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage
1127 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { 1049 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| {
@@ -1140,23 +1062,17 @@ pub(crate) unsafe fn init(config: ClockConfig) {
1140 } 1062 }
1141 1063
1142 // Only now set the BOD level. At this point the voltage is considered stable. 1064 // Only now set the BOD level. At this point the voltage is considered stable.
1065 #[cfg(feature = "rp2040")]
1143 vreg.bod().write(|w| { 1066 vreg.bod().write(|w| {
1144 w.set_vsel(voltage.recommended_bod()); 1067 w.set_vsel(voltage.recommended_bod());
1145 w.set_en(true); // Enable brownout detection 1068 w.set_en(true); // Enable brownout detection
1146 }); 1069 });
1147
1148 #[cfg(feature = "_rp235x")] 1070 #[cfg(feature = "_rp235x")]
1149 { 1071 vreg.bod().write(|w| {
1150 // The rp235x has a separate register for the BOD level in low power mode 1072 w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
1151 vreg.bod_lp_entry().write(|w| { 1073 w.set_vsel(voltage.recommended_bod());
1152 w.set_vsel(voltage.recommended_bod()); 1074 w.set_en(true); // Enable brownout detection
1153 w.set_en(true); // Enable brownout detection 1075 });
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 }
1160 } 1076 }
1161 } 1077 }
1162 1078
@@ -1527,23 +1443,8 @@ pub fn core_voltage() -> Result<CoreVoltage, &'static str> {
1527 0b01101 => Ok(CoreVoltage::V1_20), 1443 0b01101 => Ok(CoreVoltage::V1_20),
1528 0b01110 => Ok(CoreVoltage::V1_25), 1444 0b01110 => Ok(CoreVoltage::V1_25),
1529 0b01111 => Ok(CoreVoltage::V1_30), 1445 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"), 1446 _ => Err("Unexpected value in register"),
1447 // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point
1547 } 1448 }
1548 } 1449 }
1549} 1450}