1
1
//! Power management
2
2
3
- use crate :: rcc:: { Enable , APB1R1 } ;
3
+ use crate :: rcc:: { Clocks , Enable , APB1R1 } ;
4
4
use 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
+ }
5
38
6
39
pub struct Pwr {
7
40
pub cr1 : CR1 ,
8
41
pub cr2 : CR2 ,
9
42
pub cr3 : CR3 ,
10
43
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
+ }
11
123
}
12
124
13
125
/// Extension trait that constrains the `PWR` peripheral
@@ -25,6 +137,8 @@ impl PwrExt for PWR {
25
137
cr2 : CR2 { _0 : ( ) } ,
26
138
cr3 : CR3 { _0 : ( ) } ,
27
139
cr4 : CR4 { _0 : ( ) } ,
140
+ scr : SCR { _0 : ( ) } ,
141
+ sr1 : SR1 { _0 : ( ) } ,
28
142
}
29
143
}
30
144
}
@@ -35,8 +149,6 @@ pub struct CR1 {
35
149
}
36
150
37
151
impl CR1 {
38
- // TODO remove `allow`
39
- #[ allow( dead_code) ]
40
152
pub ( crate ) fn reg ( & mut self ) -> & pwr:: CR1 {
41
153
// NOTE(unsafe) this proxy grants exclusive access to this register
42
154
unsafe { & ( * PWR :: ptr ( ) ) . cr1 }
@@ -61,8 +173,6 @@ pub struct CR3 {
61
173
}
62
174
63
175
impl CR3 {
64
- // TODO remove `allow`
65
- #[ allow( dead_code) ]
66
176
pub ( crate ) fn reg ( & mut self ) -> & pwr:: CR3 {
67
177
// NOTE(unsafe) this proxy grants exclusive access to this register
68
178
unsafe { & ( * PWR :: ptr ( ) ) . cr3 }
@@ -81,3 +191,27 @@ impl CR4 {
81
191
unsafe { & ( * PWR :: ptr ( ) ) . cr4 }
82
192
}
83
193
}
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