|
| 1 | +//! Power configuration |
| 2 | +//! |
| 3 | +//! This module configures the PWR unit to provide the core voltage `VCORE`. |
| 4 | +//! The processor supports multiple voltage scaling modes, from VOS3 (lowest |
| 5 | +//! performance, lowest power consumption) to VOS0 (highest performance, |
| 6 | +//! highest power consumption). |
| 7 | +//! |
| 8 | +//! After reset the system is in VOS3. This power configuration module allows |
| 9 | +//! modes VOS0 to VOS3 to be selected. |
| 10 | +//! |
| 11 | +//! ```rust |
| 12 | +//! let dp = pac::Peripherals::take().unwrap(); |
| 13 | +//! |
| 14 | +//! let pwr = dp.PWR.constrain(); |
| 15 | +//! let pwrcfg = pwr.vos3().freeze(); |
| 16 | +//! |
| 17 | +//! assert_eq!(pwrcfg.vos(), VoltageScale::Scale3); |
| 18 | +//! ``` |
| 19 | +//! |
| 20 | +//! If no mode is explicitly selected, it defaults to VOS0 after calling `freeze`. |
| 21 | +//! |
| 22 | +//! ```rust |
| 23 | +//! let dp = pac::Peripherals::take().unwrap(); |
| 24 | +//! |
| 25 | +//! let pwr = dp.PWR.constrain(); |
| 26 | +//! let pwrcfg = pwr.freeze(); |
| 27 | +//! |
| 28 | +//! assert_eq!(pwrcfg.vos(), VoltageScale::Scale0); |
| 29 | +//! ``` |
| 30 | +//! |
| 31 | +//! |
| 32 | +use crate::stm32::pwr::voscr::VOS; |
| 33 | +use crate::stm32::pwr::vossr::ACTVOSR; |
| 34 | +use crate::stm32::PWR; |
| 35 | + |
| 36 | +/// Extension trait that constrains the `PWR` peripheral |
| 37 | +pub trait PwrExt { |
| 38 | + fn constrain(self) -> Pwr; |
| 39 | +} |
| 40 | + |
| 41 | +impl PwrExt for PWR { |
| 42 | + fn constrain(self) -> Pwr { |
| 43 | + Pwr { |
| 44 | + rb: self, |
| 45 | + target_vos: VoltageScale::Scale0, |
| 46 | + } |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +/// Constrained PWR peripheral |
| 51 | +/// |
| 52 | +/// Generated by calling `constrain` on the PAC's PWR peripheral. |
| 53 | +pub struct Pwr { |
| 54 | + pub(crate) rb: PWR, |
| 55 | + target_vos: VoltageScale, |
| 56 | +} |
| 57 | + |
| 58 | +/// Voltage Scale |
| 59 | +/// |
| 60 | +/// Represents the voltage range feeding the CPU core. The maximum core |
| 61 | +/// clock frequency depends on this value. |
| 62 | +#[derive(Copy, Clone, PartialEq, Eq)] |
| 63 | +pub enum VoltageScale { |
| 64 | + /// VOS 0 range VCORE 1.30V - 1.40V |
| 65 | + Scale0, |
| 66 | + /// VOS 1 range VCORE 1.15V - 1.26V |
| 67 | + Scale1, |
| 68 | + /// VOS 2 range VCORE 1.05V - 1.15V |
| 69 | + Scale2, |
| 70 | + /// VOS 3 range VCORE 0.95V - 1.05V |
| 71 | + Scale3, |
| 72 | +} |
| 73 | + |
| 74 | +impl From<VoltageScale> for VOS { |
| 75 | + fn from(value: VoltageScale) -> Self { |
| 76 | + match value { |
| 77 | + VoltageScale::Scale3 => VOS::Vos3, |
| 78 | + VoltageScale::Scale2 => VOS::Vos2, |
| 79 | + VoltageScale::Scale1 => VOS::Vos1, |
| 80 | + VoltageScale::Scale0 => VOS::Vos0, |
| 81 | + } |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +impl From<ACTVOSR> for VoltageScale { |
| 86 | + fn from(value: ACTVOSR) -> Self { |
| 87 | + match value { |
| 88 | + ACTVOSR::Vos3 => VoltageScale::Scale3, |
| 89 | + ACTVOSR::Vos2 => VoltageScale::Scale2, |
| 90 | + ACTVOSR::Vos1 => VoltageScale::Scale1, |
| 91 | + ACTVOSR::Vos0 => VoltageScale::Scale0, |
| 92 | + } |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +/// Power Configuration |
| 97 | +/// |
| 98 | +/// Generated when the PWR peripheral is frozen. |
| 99 | +/// longer be changed. |
| 100 | +pub struct PowerConfiguration { |
| 101 | + pub(crate) vos: VoltageScale, |
| 102 | +} |
| 103 | + |
| 104 | +impl PowerConfiguration { |
| 105 | + /// Gets the `VoltageScale` which was configured by `Pwr::freeze()`. |
| 106 | + pub fn vos(&self) -> VoltageScale { |
| 107 | + self.vos |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +/// Internal power methods |
| 112 | +impl Pwr { |
| 113 | + /// Transition between voltage scaling levels |
| 114 | + fn voltage_scaling_transition(&self, new_scale: VoltageScale) { |
| 115 | + // ************************************ |
| 116 | + // Note: STM32H503 Errata 2.2.13 states that for Rev A, Z this transition should only |
| 117 | + // be executed from RAM. It's unclear if these silicon revisions saw wide release, so |
| 118 | + // this is left executed from flash. |
| 119 | + // ************************************ |
| 120 | + |
| 121 | + self.rb.voscr().write(|w| w.vos().variant(new_scale.into())); |
| 122 | + while self.rb.vossr().read().vosrdy().is_not_ready() {} |
| 123 | + } |
| 124 | + |
| 125 | + /// Returns a reference to the inner peripheral |
| 126 | + pub fn inner(&self) -> &PWR { |
| 127 | + &self.rb |
| 128 | + } |
| 129 | + |
| 130 | + /// Returns a mutable reference to the inner peripheral |
| 131 | + pub fn inner_mut(&mut self) -> &mut PWR { |
| 132 | + &mut self.rb |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +/// Builder methods |
| 137 | +impl Pwr { |
| 138 | + /// Configure Voltage Scale 0. This is the default configuration |
| 139 | + #[must_use] |
| 140 | + pub fn vos0(mut self) -> Self { |
| 141 | + self.target_vos = VoltageScale::Scale0; |
| 142 | + self |
| 143 | + } |
| 144 | + /// Configure Voltage Scale 1 |
| 145 | + #[must_use] |
| 146 | + pub fn vos1(mut self) -> Self { |
| 147 | + self.target_vos = VoltageScale::Scale1; |
| 148 | + self |
| 149 | + } |
| 150 | + /// Configure Voltage Scale 2 |
| 151 | + #[must_use] |
| 152 | + pub fn vos2(mut self) -> Self { |
| 153 | + self.target_vos = VoltageScale::Scale2; |
| 154 | + self |
| 155 | + } |
| 156 | + /// Configure Voltage Scale 3 |
| 157 | + #[must_use] |
| 158 | + pub fn vos3(mut self) -> Self { |
| 159 | + self.target_vos = VoltageScale::Scale3; |
| 160 | + self |
| 161 | + } |
| 162 | + |
| 163 | + pub fn freeze(self) -> PowerConfiguration { |
| 164 | + // Validate the supply configuration. If you are stuck here, it is |
| 165 | + // because the voltages on your board do not match those specified |
| 166 | + // in the VOSCR.VOS By default after reset VOS = Scale 3, so check |
| 167 | + // that the voltage on the VCAP pins = 1.0V. |
| 168 | + while self.rb.vossr().read().actvosrdy().is_not_ready() {} |
| 169 | + |
| 170 | + let current_scale = |
| 171 | + VoltageScale::from(self.rb.vossr().read().actvos().variant()); |
| 172 | + |
| 173 | + let vos = self.target_vos; |
| 174 | + if current_scale != vos { |
| 175 | + self.voltage_scaling_transition(vos); |
| 176 | + } |
| 177 | + |
| 178 | + PowerConfiguration { vos } |
| 179 | + } |
| 180 | +} |
0 commit comments