1
+ use core:: cmp;
1
2
use crate :: time:: Hertz ;
2
3
3
4
/// Extension trait that constrains the `RCC` peripheral
@@ -14,6 +15,8 @@ impl RccExt for crate::stm32::RCC {
14
15
hclk : None ,
15
16
pclk : None ,
16
17
sysclk : None ,
18
+ enable_hsi : true ,
19
+ enable_hsi48 : false ,
17
20
} ,
18
21
}
19
22
}
@@ -26,12 +29,32 @@ pub struct Rcc {
26
29
27
30
#[ allow( unused) ]
28
31
const HSI : u32 = 8_000_000 ; // Hz
32
+ #[ allow( unused) ]
33
+ const HSI48 : u32 = 48_000_000 ; // Hz - (available on STM32F04x, STM32F07x and STM32F09x devices only)
34
+
35
+ #[ allow( unused) ]
36
+ enum SysClkSource {
37
+ HSI = 0b00 ,
38
+ HSE = 0b01 ,
39
+ PLL = 0b10 ,
40
+ HSI48 = 0b11 ,
41
+ }
42
+
43
+ #[ allow( unused) ]
44
+ enum PllSource {
45
+ HSI_DIV2 = 0b00 ,
46
+ HSI = 0b01 ,
47
+ HSE = 0b10 ,
48
+ HSI48 = 0b11 ,
49
+ }
29
50
30
51
#[ allow( unused) ]
31
52
pub struct CFGR {
32
53
hclk : Option < u32 > ,
33
54
pclk : Option < u32 > ,
34
55
sysclk : Option < u32 > ,
56
+ enable_hsi : bool ,
57
+ enable_hsi48 : bool ,
35
58
}
36
59
37
60
#[ cfg( feature = "device-selected" ) ]
@@ -60,20 +83,58 @@ impl CFGR {
60
83
self
61
84
}
62
85
86
+ pub fn enable_hsi ( mut self , is_enabled : bool ) -> Self {
87
+ self . enable_hsi = is_enabled;
88
+ self
89
+ }
90
+
91
+ #[ cfg( feature = "stm32f042" ) ]
92
+ pub fn enable_hsi48 ( mut self , is_enabled : bool ) -> Self {
93
+ self . enable_hsi48 = is_enabled;
94
+ self
95
+ }
96
+
63
97
pub fn freeze ( self ) -> Clocks {
64
- let pllmul = ( 4 * self . sysclk . unwrap_or ( HSI ) + HSI ) / HSI / 2 ;
65
- let pllmul = core:: cmp:: min ( core:: cmp:: max ( pllmul, 2 ) , 16 ) ;
66
- let sysclk = pllmul * HSI / 2 ;
98
+ // Default to lowest frequency clock on all systems.
99
+ let sysclk = self . sysclk . unwrap_or ( HSI ) ;
100
+
101
+ let r_sysclk; // The "real" sysclock value, calculated below
102
+ let src_clk_freq; // Frequency of source clock for PLL and etc, HSI, or HSI48 on supported systems.
103
+ let pllmul_bits;
67
104
68
- let pllmul_bits = if pllmul == 2 {
69
- None
105
+ // Select clock source based on user input and capability
106
+ // Highest selected frequency source available takes precedent.
107
+ // For F04x, F07x, F09x parts, use HSI48 if requested.
108
+ if self . enable_hsi48 {
109
+ src_clk_freq = HSI48 ; // Use HSI48 if requested and available.
110
+ } else if self . enable_hsi {
111
+ src_clk_freq = HSI ; // HSI if requested
70
112
} else {
71
- Some ( pllmul as u8 - 2 )
72
- } ;
113
+ src_clk_freq = HSI ; // If no clock source is selected use HSI.
114
+ }
115
+
116
+ // Pll check
117
+ if sysclk == src_clk_freq {
118
+ // Bypass pll if src clk and requested sysclk are the same, to save power.
119
+ // The only reason to override this behaviour is if the sysclk source were HSI, and you
120
+ // were running the USB off the PLL...
121
+ pllmul_bits = None ;
122
+ r_sysclk = src_clk_freq;
123
+ } else {
124
+ let pllmul = ( 4 * self . sysclk . unwrap_or ( src_clk_freq) + src_clk_freq) / src_clk_freq / 2 ;
125
+ let pllmul = cmp:: min ( cmp:: max ( pllmul, 2 ) , 16 ) ;
126
+ r_sysclk = pllmul * src_clk_freq / 2 ;
127
+
128
+ pllmul_bits = if pllmul == 2 {
129
+ None
130
+ } else {
131
+ Some ( pllmul as u8 - 2 )
132
+ } ;
133
+ }
73
134
74
135
let hpre_bits = self
75
136
. hclk
76
- . map ( |hclk| match sysclk / hclk {
137
+ . map ( |hclk| match r_sysclk / hclk {
77
138
0 => unreachable ! ( ) ,
78
139
1 => 0b0111 ,
79
140
2 => 0b1000 ,
@@ -119,24 +180,69 @@ impl CFGR {
119
180
}
120
181
121
182
let rcc = unsafe { & * crate :: stm32:: RCC :: ptr ( ) } ;
122
- if let Some ( pllmul_bits) = pllmul_bits {
123
- // use PLL as source
124
183
184
+ // Set up rcc based on above calculated configuration.
185
+
186
+ // Enable requested clock sources
187
+ // HSI
188
+ if self . enable_hsi {
189
+ rcc. cr . write ( |w| w. hsion ( ) . set_bit ( ) ) ;
190
+ while rcc. cr . read ( ) . hsirdy ( ) . bit_is_clear ( ) { }
191
+ }
192
+ // HSI48
193
+ if self . enable_hsi48 {
194
+ rcc. cr2 . modify ( |_, w| w. hsi48on ( ) . set_bit ( ) ) ;
195
+ while rcc. cr2 . read ( ) . hsi48rdy ( ) . bit_is_clear ( ) { }
196
+ }
197
+
198
+ // Enable PLL
199
+ if let Some ( pllmul_bits) = pllmul_bits {
125
200
rcc. cfgr . write ( |w| unsafe { w. pllmul ( ) . bits ( pllmul_bits) } ) ;
126
201
127
- rcc. cr . write ( |w| w. pllon ( ) . set_bit ( ) ) ;
202
+ // Set PLL source based on configuration.
203
+ if self . enable_hsi48 {
204
+ rcc. cfgr . modify ( |_, w| w. pllsrc ( ) . bits ( PllSource :: HSI48 as u8 ) ) ;
205
+ } else if self . enable_hsi {
206
+ rcc. cfgr . modify ( |_, w| w. pllsrc ( ) . bits ( PllSource :: HSI_DIV2 as u8 ) ) ;
207
+ } else {
208
+ rcc. cfgr . modify ( |_, w| w. pllsrc ( ) . bits ( PllSource :: HSI_DIV2 as u8 ) ) ;
209
+ }
128
210
129
- while rcc. cr . read ( ) . pllrdy ( ) . bit_is_clear ( ) { }
211
+ rcc. cr . write ( |w| w. pllon ( ) . set_bit ( ) ) ;
212
+ while rcc. cr . read ( ) . pllrdy ( ) . bit_is_clear ( ) { }
130
213
131
214
rcc. cfgr . modify ( |_, w| unsafe {
132
- w. ppre ( ) . bits ( ppre_bits) . hpre ( ) . bits ( hpre_bits) . sw ( ) . bits ( 2 )
215
+ w. ppre ( )
216
+ . bits ( ppre_bits)
217
+ . hpre ( )
218
+ . bits ( hpre_bits)
219
+ . sw ( )
220
+ . bits ( SysClkSource :: PLL as u8 )
133
221
} ) ;
134
- } else {
135
- // use HSI as source
136
- rcc. cfgr
137
- . write ( |w| unsafe { w. ppre ( ) . bits ( ppre_bits) . hpre ( ) . bits ( hpre_bits) . sw ( ) . bits ( 0 ) } ) ;
138
- }
139
222
223
+ } else { // No PLL required.
224
+ // Setup requested clocks.
225
+ if self . enable_hsi48 {
226
+ rcc. cfgr . modify ( |_, w| unsafe {
227
+ w. ppre ( ) . bits ( ppre_bits)
228
+ . hpre ( ) . bits ( hpre_bits)
229
+ . sw ( ) . bits ( SysClkSource :: HSI48 as u8 )
230
+ } ) ;
231
+ } else if self . enable_hsi {
232
+ rcc. cfgr . modify ( |_, w| unsafe {
233
+ w. ppre ( ) . bits ( ppre_bits)
234
+ . hpre ( ) . bits ( hpre_bits)
235
+ . sw ( ) . bits ( SysClkSource :: HSI as u8 )
236
+ } ) ;
237
+ } else { // Default to HSI
238
+ rcc. cfgr . modify ( |_, w| unsafe {
239
+ w. ppre ( ) . bits ( ppre_bits)
240
+ . hpre ( ) . bits ( hpre_bits)
241
+ . sw ( ) . bits ( SysClkSource :: HSI as u8 )
242
+ } ) ;
243
+ }
244
+ }
245
+
140
246
Clocks {
141
247
hclk : Hertz ( hclk) ,
142
248
pclk : Hertz ( pclk) ,
0 commit comments