11//! Power management
22
3- use crate :: rcc:: { Enable , APB1R1 } ;
3+ use crate :: rcc:: { Clocks , Enable , APB1R1 } ;
44use crate :: stm32:: { pwr, PWR } ;
5+ use bitfield:: { bitfield, BitRange } ;
6+ use cortex_m:: peripheral:: SCB ;
7+ use fugit:: RateExtU32 ;
8+
9+ /// PWR error
10+ #[ non_exhaustive]
11+ #[ derive( Debug ) ]
12+ pub enum Error {
13+ /// Power regulator con not be switched to the low-power voltage due to the system clock frequency being higher than 26MHz
14+ SysClkTooHighVos ,
15+ /// System can not be switched to the low-power run mode due to the system clock frequency being higher than 2MHz
16+ SysClkTooHighLpr ,
17+ }
18+
19+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
20+ pub enum VosRange {
21+ #[ doc = "High-Performance range, 1.2V, up to 80 MHz" ]
22+ HighPerformance = 0b01 ,
23+ #[ doc = "Low-power range, 1.0V, up to 26MHz" ]
24+ LowPower = 0b10 ,
25+ }
26+
27+ bitfield ! {
28+ pub struct WakeUpSource ( u16 ) ;
29+ impl Debug ;
30+ // The fields default to u16
31+ pub wkup1, set_wkup1: 0 ;
32+ pub wkup2, set_wkup2: 1 ;
33+ pub wkup3, set_wkup3: 2 ;
34+ pub wkup4, set_wkup4: 3 ;
35+ pub wkup5, set_wkup5: 4 ;
36+ pub internal_wkup, set_internal_wkup: 15 ;
37+ }
538
639pub struct Pwr {
740 pub cr1 : CR1 ,
841 pub cr2 : CR2 ,
942 pub cr3 : CR3 ,
1043 pub cr4 : CR4 ,
44+ pub scr : SCR ,
45+ pub sr1 : SR1 ,
46+ }
47+
48+ impl Pwr {
49+ /// Configures dynamic voltage regulator range
50+ ///
51+ /// Will panic if low-power range is selected for higher system clock
52+ pub fn set_power_range ( & mut self , range : VosRange , clocks : & Clocks ) -> Result < ( ) , Error > {
53+ match range {
54+ VosRange :: HighPerformance => unsafe {
55+ {
56+ self . cr1
57+ . reg ( )
58+ . modify ( |_, w| w. vos ( ) . bits ( VosRange :: HighPerformance as u8 ) )
59+ }
60+ Ok ( ( ) )
61+ } ,
62+ VosRange :: LowPower => {
63+ if clocks. sysclk ( ) > 26 . MHz :: < 1 , 1 > ( ) {
64+ Err ( Error :: SysClkTooHighVos )
65+ } else {
66+ unsafe {
67+ self . cr1
68+ . reg ( )
69+ . modify ( |_, w| w. vos ( ) . bits ( VosRange :: LowPower as u8 ) )
70+ }
71+ Ok ( ( ) )
72+ }
73+ }
74+ }
75+ }
76+
77+ /// Switches the system into low power run mode
78+ pub fn low_power_run ( & mut self , clocks : & Clocks ) -> Result < ( ) , Error > {
79+ if clocks. sysclk ( ) > 2 . MHz :: < 1 , 1 > ( ) {
80+ Err ( Error :: SysClkTooHighLpr )
81+ } else {
82+ self . cr1 . reg ( ) . modify ( |_, w| w. lpr ( ) . set_bit ( ) ) ;
83+ Ok ( ( ) )
84+ }
85+ }
86+
87+ /// Enters 'Shutdown' low power mode.
88+ pub fn shutdown ( & mut self , wkup : & WakeUpSource , scb : & mut SCB ) -> ! {
89+ unsafe {
90+ self . cr3 . reg ( ) . modify ( |_, w| w. bits ( wkup. bit_range ( 0 , 7 ) ) ) ;
91+ }
92+
93+ if wkup. internal_wkup ( ) {
94+ // Can't apply directly due to the APC and RPS bits
95+ self . cr3 . reg ( ) . modify ( |_, w| w. ewf ( ) . set_bit ( ) )
96+ }
97+ scb. set_sleepdeep ( ) ;
98+ self . scr . reg ( ) . write ( |w| {
99+ w. wuf1 ( )
100+ . set_bit ( )
101+ . wuf2 ( )
102+ . set_bit ( )
103+ . wuf3 ( )
104+ . set_bit ( )
105+ . wuf4 ( )
106+ . set_bit ( )
107+ . wuf5 ( )
108+ . set_bit ( )
109+ . sbf ( )
110+ . set_bit ( )
111+ } ) ;
112+ unsafe { self . cr1 . reg ( ) . modify ( |_, w| w. lpms ( ) . bits ( 0b111 ) ) } ;
113+ cortex_m:: asm:: dsb ( ) ;
114+ cortex_m:: asm:: wfi ( ) ;
115+ loop { }
116+ }
117+
118+ /// Returns the reason, why wakeup from shutdown happened. In case there is more then one,
119+ /// a single random reason will be returned
120+ pub fn read_wakeup_reason ( & mut self ) -> WakeUpSource {
121+ WakeUpSource ( self . sr1 . reg ( ) . read ( ) . bits ( ) as u16 )
122+ }
11123}
12124
13125/// Extension trait that constrains the `PWR` peripheral
@@ -25,6 +137,8 @@ impl PwrExt for PWR {
25137 cr2 : CR2 { _0 : ( ) } ,
26138 cr3 : CR3 { _0 : ( ) } ,
27139 cr4 : CR4 { _0 : ( ) } ,
140+ scr : SCR { _0 : ( ) } ,
141+ sr1 : SR1 { _0 : ( ) } ,
28142 }
29143 }
30144}
@@ -35,8 +149,6 @@ pub struct CR1 {
35149}
36150
37151impl CR1 {
38- // TODO remove `allow`
39- #[ allow( dead_code) ]
40152 pub ( crate ) fn reg ( & mut self ) -> & pwr:: CR1 {
41153 // NOTE(unsafe) this proxy grants exclusive access to this register
42154 unsafe { & ( * PWR :: ptr ( ) ) . cr1 }
@@ -61,8 +173,6 @@ pub struct CR3 {
61173}
62174
63175impl CR3 {
64- // TODO remove `allow`
65- #[ allow( dead_code) ]
66176 pub ( crate ) fn reg ( & mut self ) -> & pwr:: CR3 {
67177 // NOTE(unsafe) this proxy grants exclusive access to this register
68178 unsafe { & ( * PWR :: ptr ( ) ) . cr3 }
@@ -81,3 +191,27 @@ impl CR4 {
81191 unsafe { & ( * PWR :: ptr ( ) ) . cr4 }
82192 }
83193}
194+
195+ /// SCR
196+ pub struct SCR {
197+ _0 : ( ) ,
198+ }
199+
200+ impl SCR {
201+ pub ( crate ) fn reg ( & mut self ) -> & pwr:: SCR {
202+ // NOTE(unsafe) this proxy grants exclusive access to this register
203+ unsafe { & ( * PWR :: ptr ( ) ) . scr }
204+ }
205+ }
206+
207+ /// SCR
208+ pub struct SR1 {
209+ _0 : ( ) ,
210+ }
211+
212+ impl SR1 {
213+ pub ( crate ) fn reg ( & mut self ) -> & pwr:: SR1 {
214+ // NOTE(unsafe) this proxy grants exclusive access to this register
215+ unsafe { & ( * PWR :: ptr ( ) ) . sr1 }
216+ }
217+ }
0 commit comments