Skip to content
This repository was archived by the owner on Feb 13, 2019. It is now read-only.

Commit d1bfbbf

Browse files
authored
Merge pull request #93 from mvirkkunen/rcc-hse-usb-support
Add support for HSE and USB clocks
2 parents 45ff868 + 0dd491d commit d1bfbbf

File tree

1 file changed

+84
-37
lines changed

1 file changed

+84
-37
lines changed

src/rcc.rs

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use core::cmp;
22

33
use cast::u32;
4+
use stm32f103xx::rcc::cfgr::{PLLSRCW, SWW, USBPREW};
45
use stm32f103xx::{rcc, RCC};
56

67
use flash::ACR;
@@ -19,6 +20,7 @@ impl RccExt for RCC {
1920
apb1: APB1 { _0: () },
2021
apb2: APB2 { _0: () },
2122
cfgr: CFGR {
23+
hse: None,
2224
hclk: None,
2325
pclk1: None,
2426
pclk2: None,
@@ -88,13 +90,25 @@ impl APB2 {
8890
const HSI: u32 = 8_000_000; // Hz
8991

9092
pub struct CFGR {
93+
hse: Option<u32>,
9194
hclk: Option<u32>,
9295
pclk1: Option<u32>,
9396
pclk2: Option<u32>,
9497
sysclk: Option<u32>,
9598
}
9699

97100
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
98112
pub fn hclk<F>(mut self, freq: F) -> Self
99113
where
100114
F: Into<Hertz>,
@@ -103,6 +117,7 @@ impl CFGR {
103117
self
104118
}
105119

120+
/// Sets the desired frequency for the PCKL1 clock
106121
pub fn pclk1<F>(mut self, freq: F) -> Self
107122
where
108123
F: Into<Hertz>,
@@ -111,6 +126,7 @@ impl CFGR {
111126
self
112127
}
113128

129+
/// Sets the desired frequency for the PCLK2 clock
114130
pub fn pclk2<F>(mut self, freq: F) -> Self
115131
where
116132
F: Into<Hertz>,
@@ -119,6 +135,7 @@ impl CFGR {
119135
self
120136
}
121137

138+
/// Sets the desired frequency for the SYSCLK clock
122139
pub fn sysclk<F>(mut self, freq: F) -> Self
123140
where
124141
F: Into<Hertz>,
@@ -128,19 +145,20 @@ impl CFGR {
128145
}
129146

130147
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);
132151

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))
137157
} else {
138-
Some(pllmul as u8 - 2)
158+
(Some(pllmul as u8 - 2), pllsrcclk * pllmul)
139159
};
140160

141-
let sysclk = pllmul * HSI / 2;
142-
143-
assert!(sysclk < 72_000_000);
161+
assert!(sysclk <= 72_000_000);
144162

145163
let hpre_bits = self.hclk
146164
.map(|hclk| match sysclk / hclk {
@@ -159,7 +177,7 @@ impl CFGR {
159177

160178
let hclk = sysclk / (1 << (hpre_bits - 0b0111));
161179

162-
assert!(hclk < 72_000_000);
180+
assert!(hclk <= 72_000_000);
163181

164182
let ppre1_bits = self.pclk1
165183
.map(|pclk1| match hclk / pclk1 {
@@ -191,7 +209,7 @@ impl CFGR {
191209
let ppre2 = 1 << (ppre2_bits - 0b011);
192210
let pclk2 = hclk / u32(ppre2);
193211

194-
assert!(pclk2 < 72_000_000);
212+
assert!(pclk2 <= 72_000_000);
195213

196214
// adjust flash wait states
197215
unsafe {
@@ -206,48 +224,71 @@ impl CFGR {
206224
})
207225
}
208226

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+
209235
let rcc = unsafe { &*RCC::ptr() };
210-
if let Some(pllmul_bits) = pllmul_bits {
211-
// use PLL as source
212236

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
214239

215-
rcc.cr.write(|w| w.pllon().enabled());
240+
rcc.cr.modify(|_, w| w.hseon().enabled());
216241

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
218247

219248
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+
})
241257
});
258+
259+
rcc.cr.modify(|_, w| w.pllon().enabled());
260+
261+
while rcc.cr.read().pllrdy().is_unlocked() {}
242262
}
243263

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+
244284
Clocks {
245285
hclk: Hertz(hclk),
246286
pclk1: Hertz(pclk1),
247287
pclk2: Hertz(pclk2),
248288
ppre1,
249289
ppre2,
250290
sysclk: Hertz(sysclk),
291+
usbclk_valid,
251292
}
252293
}
253294
}
@@ -263,6 +304,7 @@ pub struct Clocks {
263304
ppre1: u8,
264305
ppre2: u8,
265306
sysclk: Hertz,
307+
usbclk_valid: bool,
266308
}
267309

268310
impl Clocks {
@@ -295,4 +337,9 @@ impl Clocks {
295337
pub fn sysclk(&self) -> Hertz {
296338
self.sysclk
297339
}
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+
}
298345
}

0 commit comments

Comments
 (0)