1
1
use core:: cmp;
2
2
3
3
use cast:: u32;
4
+ use stm32f103xx:: rcc:: cfgr:: { PLLSRCW , SWW , USBPREW } ;
4
5
use stm32f103xx:: { rcc, RCC } ;
5
6
6
7
use flash:: ACR ;
@@ -19,6 +20,7 @@ impl RccExt for RCC {
19
20
apb1 : APB1 { _0 : ( ) } ,
20
21
apb2 : APB2 { _0 : ( ) } ,
21
22
cfgr : CFGR {
23
+ hse : None ,
22
24
hclk : None ,
23
25
pclk1 : None ,
24
26
pclk2 : None ,
@@ -88,13 +90,25 @@ impl APB2 {
88
90
const HSI : u32 = 8_000_000 ; // Hz
89
91
90
92
pub struct CFGR {
93
+ hse : Option < u32 > ,
91
94
hclk : Option < u32 > ,
92
95
pclk1 : Option < u32 > ,
93
96
pclk2 : Option < u32 > ,
94
97
sysclk : Option < u32 > ,
95
98
}
96
99
97
100
impl CFGR {
101
+ /// Uses HSE (external oscillator) instead of HSI (internal RC oscillator) as the clock source.
102
+ /// Will result in a hang if an external oscillator is not connected or it fails to start.
103
+ pub fn use_hse < F > ( mut self , freq : F ) -> Self
104
+ where
105
+ F : Into < Hertz > ,
106
+ {
107
+ self . hse = Some ( freq. into ( ) . 0 ) ;
108
+ self
109
+ }
110
+
111
+ /// Sets the desired frequency for the HCLK clock
98
112
pub fn hclk < F > ( mut self , freq : F ) -> Self
99
113
where
100
114
F : Into < Hertz > ,
@@ -103,6 +117,7 @@ impl CFGR {
103
117
self
104
118
}
105
119
120
+ /// Sets the desired frequency for the PCKL1 clock
106
121
pub fn pclk1 < F > ( mut self , freq : F ) -> Self
107
122
where
108
123
F : Into < Hertz > ,
@@ -111,6 +126,7 @@ impl CFGR {
111
126
self
112
127
}
113
128
129
+ /// Sets the desired frequency for the PCLK2 clock
114
130
pub fn pclk2 < F > ( mut self , freq : F ) -> Self
115
131
where
116
132
F : Into < Hertz > ,
@@ -119,6 +135,7 @@ impl CFGR {
119
135
self
120
136
}
121
137
138
+ /// Sets the desired frequency for the SYSCLK clock
122
139
pub fn sysclk < F > ( mut self , freq : F ) -> Self
123
140
where
124
141
F : Into < Hertz > ,
@@ -128,19 +145,20 @@ impl CFGR {
128
145
}
129
146
130
147
pub fn freeze ( self , acr : & mut ACR ) -> Clocks {
131
- // TODO ADC & USB clocks
148
+ // TODO ADC clock
149
+
150
+ let pllsrcclk = self . hse . unwrap_or ( HSI / 2 ) ;
132
151
133
- let pllmul = ( 4 * self . sysclk . unwrap_or ( HSI ) + HSI ) / HSI / 2 ;
134
- let pllmul = cmp:: min ( cmp:: max ( pllmul, 2 ) , 16 ) ;
135
- let pllmul_bits = if pllmul == 2 {
136
- None
152
+ let pllmul = self . sysclk . unwrap_or ( pllsrcclk) / pllsrcclk;
153
+ let pllmul = cmp:: min ( cmp:: max ( pllmul, 1 ) , 16 ) ;
154
+
155
+ let ( pllmul_bits, sysclk) = if pllmul == 1 {
156
+ ( None , self . hse . unwrap_or ( HSI ) )
137
157
} else {
138
- Some ( pllmul as u8 - 2 )
158
+ ( Some ( pllmul as u8 - 2 ) , pllsrcclk * pllmul )
139
159
} ;
140
160
141
- let sysclk = pllmul * HSI / 2 ;
142
-
143
- assert ! ( sysclk < 72_000_000 ) ;
161
+ assert ! ( sysclk <= 72_000_000 ) ;
144
162
145
163
let hpre_bits = self . hclk
146
164
. map ( |hclk| match sysclk / hclk {
@@ -159,7 +177,7 @@ impl CFGR {
159
177
160
178
let hclk = sysclk / ( 1 << ( hpre_bits - 0b0111 ) ) ;
161
179
162
- assert ! ( hclk < 72_000_000 ) ;
180
+ assert ! ( hclk <= 72_000_000 ) ;
163
181
164
182
let ppre1_bits = self . pclk1
165
183
. map ( |pclk1| match hclk / pclk1 {
@@ -191,7 +209,7 @@ impl CFGR {
191
209
let ppre2 = 1 << ( ppre2_bits - 0b011 ) ;
192
210
let pclk2 = hclk / u32 ( ppre2) ;
193
211
194
- assert ! ( pclk2 < 72_000_000 ) ;
212
+ assert ! ( pclk2 <= 72_000_000 ) ;
195
213
196
214
// adjust flash wait states
197
215
unsafe {
@@ -206,48 +224,71 @@ impl CFGR {
206
224
} )
207
225
}
208
226
227
+ // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
228
+ // PLL output frequency is a supported one.
229
+ let ( usbpre, usbclk_valid) = match ( self . hse , pllmul_bits, sysclk) {
230
+ ( Some ( _) , Some ( _) , 72_000_000 ) => ( USBPREW :: DIV15 , true ) ,
231
+ ( Some ( _) , Some ( _) , 48_000_000 ) => ( USBPREW :: NODIV , true ) ,
232
+ _ => ( USBPREW :: NODIV , false ) ,
233
+ } ;
234
+
209
235
let rcc = unsafe { & * RCC :: ptr ( ) } ;
210
- if let Some ( pllmul_bits) = pllmul_bits {
211
- // use PLL as source
212
236
213
- rcc. cfgr . write ( |w| unsafe { w. pllmul ( ) . bits ( pllmul_bits) } ) ;
237
+ if self . hse . is_some ( ) {
238
+ // enable HSE and wait for it to be ready
214
239
215
- rcc. cr . write ( | w| w. pllon ( ) . enabled ( ) ) ;
240
+ rcc. cr . modify ( |_ , w| w. hseon ( ) . enabled ( ) ) ;
216
241
217
- while rcc. cr . read ( ) . pllrdy ( ) . is_unlocked ( ) { }
242
+ while rcc. cr . read ( ) . hserdy ( ) . is_notready ( ) { }
243
+ }
244
+
245
+ if let Some ( pllmul_bits) = pllmul_bits {
246
+ // enable PLL and wait for it to be ready
218
247
219
248
rcc. cfgr . modify ( |_, w| unsafe {
220
- w. ppre2 ( )
221
- . bits ( ppre2_bits)
222
- . ppre1 ( )
223
- . bits ( ppre1_bits)
224
- . hpre ( )
225
- . bits ( hpre_bits)
226
- . sw ( )
227
- . pll ( )
228
- } ) ;
229
- } else {
230
- // use HSI as source
231
-
232
- rcc. cfgr . write ( |w| unsafe {
233
- w. ppre2 ( )
234
- . bits ( ppre2_bits)
235
- . ppre1 ( )
236
- . bits ( ppre1_bits)
237
- . hpre ( )
238
- . bits ( hpre_bits)
239
- . sw ( )
240
- . hsi ( )
249
+ w. pllmul ( )
250
+ . bits ( pllmul_bits)
251
+ . pllsrc ( )
252
+ . variant ( if self . hse . is_some ( ) {
253
+ PLLSRCW :: EXTERNAL
254
+ } else {
255
+ PLLSRCW :: INTERNAL
256
+ } )
241
257
} ) ;
258
+
259
+ rcc. cr . modify ( |_, w| w. pllon ( ) . enabled ( ) ) ;
260
+
261
+ while rcc. cr . read ( ) . pllrdy ( ) . is_unlocked ( ) { }
242
262
}
243
263
264
+ // set prescalers and clock source
265
+ rcc. cfgr . modify ( |_, w| unsafe {
266
+ w. ppre2 ( )
267
+ . bits ( ppre2_bits)
268
+ . ppre1 ( )
269
+ . bits ( ppre1_bits)
270
+ . hpre ( )
271
+ . bits ( hpre_bits)
272
+ . usbpre ( )
273
+ . variant ( usbpre)
274
+ . sw ( )
275
+ . variant ( if pllmul_bits. is_some ( ) {
276
+ SWW :: PLL
277
+ } else if self . hse . is_some ( ) {
278
+ SWW :: HSE
279
+ } else {
280
+ SWW :: HSI
281
+ } )
282
+ } ) ;
283
+
244
284
Clocks {
245
285
hclk : Hertz ( hclk) ,
246
286
pclk1 : Hertz ( pclk1) ,
247
287
pclk2 : Hertz ( pclk2) ,
248
288
ppre1,
249
289
ppre2,
250
290
sysclk : Hertz ( sysclk) ,
291
+ usbclk_valid,
251
292
}
252
293
}
253
294
}
@@ -263,6 +304,7 @@ pub struct Clocks {
263
304
ppre1 : u8 ,
264
305
ppre2 : u8 ,
265
306
sysclk : Hertz ,
307
+ usbclk_valid : bool ,
266
308
}
267
309
268
310
impl Clocks {
@@ -295,4 +337,9 @@ impl Clocks {
295
337
pub fn sysclk ( & self ) -> Hertz {
296
338
self . sysclk
297
339
}
340
+
341
+ /// Returns whether the USBCLK clock frequency is valid for the USB peripheral
342
+ pub fn usbclk_valid ( & self ) -> bool {
343
+ self . usbclk_valid
344
+ }
298
345
}
0 commit comments