Skip to content

Commit 35d3a65

Browse files
committed
pwr: Add power configuration module
1 parent 40a8637 commit 35d3a65

File tree

4 files changed

+188
-2
lines changed

4 files changed

+188
-2
lines changed

examples/blinky.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44
mod utilities;
55

66
use cortex_m_rt::entry;
7-
use stm32h5xx_hal::pac;
7+
use stm32h5xx_hal::{pac, prelude::*};
88

99
#[entry]
1010
fn main() -> ! {
1111
utilities::logger::init();
1212

1313
let dp = pac::Peripherals::take().unwrap();
1414

15-
// TODO: Power/clock config is required before blinky can... blink.
15+
let pwr = dp.PWR.constrain();
16+
let _pwrcfg = pwr.vos0().freeze();
1617

1718
dp.GPIOA.moder().write(|w| w.mode5().output()); // output
1819
dp.GPIOA.pupdr().write(|w| w.pupd5().pull_up()); // pull-up

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ pub use crate::stm32::interrupt;
3939

4040
#[cfg(feature = "device-selected")]
4141
pub mod prelude;
42+
43+
#[cfg(feature = "device-selected")]
44+
pub mod pwr;

src/prelude.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
//! Prelude
22
3+
pub use crate::pwr::PwrExt as _stm32h5xx_hal_pwr_PwrExt;
4+
35
pub use fugit::{ExtU32 as _, RateExtU32 as _};

src/pwr.rs

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
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

Comments
 (0)