Skip to content

Commit 45817ee

Browse files
grodinomvertescher
authored andcommitted
Better pll configuration and adjust flash wait state before pll on
1 parent 10c4256 commit 45817ee

File tree

1 file changed

+122
-105
lines changed

1 file changed

+122
-105
lines changed

src/rcc.rs

Lines changed: 122 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl CFGR {
222222
/// wherever it is possible.
223223
pub fn freeze(self) -> Clocks {
224224
let flash = unsafe { &(*FLASH::ptr()) };
225-
let rcc = unsafe { &*RCC::ptr() };
225+
let rcc = unsafe { &(*RCC::ptr()) };
226226

227227
// If HSE is provided by the user
228228
let hse_freq: u32 = self.hse.as_ref().map_or(0, |c| c.freq);
@@ -233,131 +233,130 @@ impl CFGR {
233233
_ => hse_freq
234234
};
235235

236-
if sysclk <= base_clk { // We can use the base clock directly
237-
match &self.hse {
238-
// If HSE clock is provided, we use it
239-
Some(_) => rcc.cfgr.modify(|_, w| w.sw().hse() ),
240-
// If HSE is not provided, we use HSI
241-
None => rcc.cfgr.modify(|_, w| w.sw().hsi() )
242-
};
236+
// Configure HSE if provided
237+
if self.hse.is_some() {
238+
// Configure the HSE mode
239+
match self.hse.as_ref().unwrap().mode {
240+
HSEClockMode::Bypass => { rcc.cr.modify(
241+
|_, w| w.hsebyp().bypassed()
242+
)},
243+
HSEClockMode::Oscillator => { rcc.cr.modify(
244+
|_, w| w.hsebyp().not_bypassed()
245+
)}
246+
}
247+
// Start HSE
248+
rcc.cr.modify(|_, w| w.hseon().on());
249+
while rcc.cr.read().hserdy().is_not_ready() {}
250+
}
243251

244-
} else { // A PLL is needed to multiply the frequence
252+
let mut use_pll = false;
253+
254+
if sysclk != base_clk { // A PLL is needed to multiply / divide the frequence
245255
// Input divisor from HSI/HSE clock, must result in less than 2MHz, and
246256
// must be between 2 and 63. In this case, the condition is always
247257
// respected. We set it at 2MHz as recommanded by the user manual.
248-
let pllm = base_clk / 2_000_000;
249-
let pllp_val: u32;
250-
let vco_clkin = base_clk / pllm;
251-
252-
// Sysclk output divisor, must result in >= 24MHz and <= 216MHz
253-
// needs to be the equivalent of 2, 4, 6 or 8
254-
// We can calculate that:
255-
// * PLLP = 2 => SYSCLK \in [25*vco_clkin ; 216*vco_clkin]
256-
// * PLLP = 4 => SYSCLK \in [12,5*vco_clkin ; 108*vco_clkin]
257-
// * PLLP = 6 => SYSCLK \in [8,33*vco_clkin ; 72*vco_clkin ]
258-
// * PLLP = 8 => SYSCLK \in [6,25*vco_clkin ; 54*vco_clkin ]
259-
let pllp = if sysclk >= 25*vco_clkin {
260-
pllp_val = 2;
261-
0b00
262-
} else if sysclk >= 13*vco_clkin {
263-
pllp_val = 4;
264-
0b01
265-
} else if sysclk >= 9*vco_clkin {
266-
pllp_val = 6;
267-
0b10
268-
} else {
269-
pllp_val = 8;
270-
0b11
271-
};
258+
let pllm = ((base_clk as f32) / (2_000_000 as f32)).ceil() as u8;
259+
let vco_clkin_mhz = (base_clk as f32 / pllm as f32) / 1_000_000.0;
260+
let mut sysclk_mhz: f32 = sysclk as f32 / 1_000_000.0;
272261

273262
// PLLN, main scaler, must result in >= 192MHz and <= 432MHz, min
274263
// 50, max 432, this constraint is allways respected when vco_clkin
275-
// = 2 MHz
276-
let plln = (sysclk / vco_clkin) * pllp_val;
277-
// Check that the desired SYSCLK is physically feasible. /1000 is to
278-
// avoid u32 overflow
279-
assert!((base_clk / 1_000) * plln >= sysclk / 1_000);
280-
// Update sysclk with the real value
281-
sysclk = (vco_clkin * plln) / pllp_val;
282-
283-
match &self.hse {
284-
// If HSE is provided
285-
Some(hse) => {
286-
// Configure the HSE mode
287-
match hse.mode {
288-
HSEClockMode::Bypass => { rcc.cr.modify(
289-
|_, w| w.hsebyp().bypassed()
290-
)},
291-
HSEClockMode::Oscillator => { rcc.cr.modify(
292-
|_, w| w.hsebyp().not_bypassed()
293-
)}
294-
}
295-
296-
// Configure PLL from HSI
297-
rcc.pllcfgr.write(|w| unsafe {
298-
w
299-
.pllsrc().hse()
300-
.pllm().bits(pllm as u8)
301-
.plln().bits(plln as u16)
302-
.pllp().bits(pllp)
303-
});
304-
},
305-
// If HSE is not provided
306-
None => {
307-
// configure PLL from HSI
308-
rcc.pllcfgr.write(|w| unsafe {
309-
w
310-
.pllsrc().hsi()
311-
.pllm().bits(pllm as u8)
312-
.plln().bits(plln as u16)
313-
.pllp().bits(pllp)
314-
});
315-
316-
},
264+
// <= 2 MHz
265+
let mut plln: f32 = 100.0;
266+
let allowed_pllp: [u8; 4] = [2, 4, 6, 8];
267+
let pllp_val = *allowed_pllp.iter().min_by_key(|&pllp| {
268+
plln = ((sysclk_mhz * (*pllp as f32)) / vco_clkin_mhz).floor();
269+
let error = sysclk_mhz - ((plln/(*pllp as f32)) * vco_clkin_mhz);
270+
271+
if error < 0.0
272+
|| plln * vco_clkin_mhz > 432.0
273+
|| plln > 432.0 || plln < 100.0 { core::u32::MAX }
274+
else { (error*1_000.0) as u32 }
275+
}).unwrap();
276+
277+
// PLLN coresponding to the best pllp_val
278+
plln = ((sysclk_mhz * (pllp_val as f32)) / vco_clkin_mhz).floor();
279+
280+
// Pllp bits to be written in the register
281+
let pllp = match pllp_val {
282+
2 => 0b00,
283+
4 => 0b01,
284+
6 => 0b10,
285+
8 => 0b11,
286+
_ => unreachable!()
317287
};
318288

289+
// Update the real sysclk value
290+
sysclk_mhz = (vco_clkin_mhz * plln) / (pllp_val as f32);
291+
sysclk = (sysclk_mhz * 1_000_000.0) as u32;
292+
293+
294+
// Turn PLL off
295+
rcc.cr.modify(|_, w| w.pllon().off());
296+
// Wait till PLL is disabled
297+
while ! rcc.cr.read().pllrdy().is_not_ready() {}
298+
299+
if self.hse.is_some() { // If HSE is provided
300+
// Configure PLL from HSE
301+
rcc.pllcfgr.write(|w| unsafe {
302+
w
303+
.pllsrc().hse()
304+
.pllm().bits(pllm as u8)
305+
.plln().bits(plln as u16)
306+
.pllp().bits(pllp)
307+
.pllq().bits(9)
308+
});
309+
} else { // If HSE is not provided
310+
// configure PLL from HSI
311+
rcc.pllcfgr.modify(|_, w| unsafe {
312+
w
313+
.pllsrc().hsi()
314+
.pllm().bits(pllm as u8)
315+
.plln().bits(plln as u16)
316+
.pllp().bits(pllp)
317+
});
318+
}
319+
319320
// Enable PLL
320-
rcc.cr.modify(|_, w| w.pllon().set_bit());
321-
// Wait for PLL to stabilise
322-
while rcc.cr.read().pllrdy().bit_is_set() {}
321+
rcc.cr.modify(|_, w| w.pllon().on());
322+
// // Wait for PLL to stabilise
323+
while rcc.cr.read().pllrdy().is_not_ready() {}
323324

324-
// Use PLL as SYSCLK
325-
// rcc.cfgr.modify(|_, w| unsafe { w.sw().bits(0b10 as u8) });
326-
rcc.cfgr.modify(|_, w| w.sw().pll() );
325+
use_pll = true;
327326
}
328327

329328
// HCLK. By default, SYSCLK frequence is chosen. Because of the method
330329
// of clock multiplication and division, even if `sysclk` is set to be
331330
// the same as `hclk`, it can be slighly inferior to `sysclk` after
332-
// pllm, pllp... calculations
333-
let mut hclk: u32 = min(sysclk, self.hclk.unwrap_or(sysclk));
331+
// pllm, pllp... calculations
332+
let mut hclk: u32 = sysclk; // min(sysclk, self.hclk.unwrap_or(sysclk));
334333

335334
// Configure HPRE.
336-
let mut hpre_val: u32 = sysclk / hclk;
335+
let hpre_val: f32 = (sysclk as f32/ hclk as f32).ceil();
337336

338337
// The real value of hpre is computed to be as near as possible to the
339338
// desired value, this leads to a quantization error
340-
let hpre = match hpre_val {
339+
let (hpre_val, hpre): (f32, u8) = match hpre_val as u32 {
341340
0 => unreachable!(),
342-
1 => { hpre_val = 1; 0b000},
343-
2 => { hpre_val = 2; 0b1000},
344-
3..=5 => { hpre_val = 4; 0b1001},
345-
6..=11 => { hpre_val = 8; 0b1010},
346-
12..=39 => { hpre_val = 16; 0b1011},
347-
40..=95 => { hpre_val = 64; 0b1100},
348-
96..=191 => { hpre_val = 128; 0b1101},
349-
192..=383 => { hpre_val = 256; 0b1110},
350-
_ => { hpre_val = 256; 0b1111},
341+
1 => (1.0, 0b000),
342+
2 => (2.0, 0b1000),
343+
3..=5 => (4.0, 0b1001),
344+
6..=11 => (8.0, 0b1010),
345+
12..=39 => (16.0, 0b1011),
346+
40..=95 => (64.0, 0b1100),
347+
96..=191 => (128.0, 0b1101),
348+
192..=383 => (256.0, 0b1110),
349+
_ => (512.0, 0b1111)
351350
};
352351
// update hclk with the real value
353-
hclk = sysclk / hpre_val;
352+
hclk = (sysclk as f32 / hpre_val).floor() as u32;
354353

355354
// PCLK1 (APB1). Must be <= 54 Mhz. By default, min(hclk, 54Mhz) is
356355
// chosen
357-
let mut pclk1: u32 = self.pclk1.unwrap_or(min(54_000_000, hclk));
356+
let mut pclk1: u32 = min(54_000_000, self.pclk1.unwrap_or(hclk));
358357
// PCLK2 (APB2). Must be <= 108 Mhz. By default, min(hclk, 108Mhz) is
359358
// chosen
360-
let mut pclk2: u32 = self.pclk2.unwrap_or(min(108_000_000, hclk));
359+
let mut pclk2: u32 = min(108_000_000, self.pclk2.unwrap_or(hclk));
361360

362361
// Configure PPRE1
363362
let mut ppre1_val: u32 = (hclk as f32 / pclk1 as f32).ceil() as u32;
@@ -385,14 +384,6 @@ impl CFGR {
385384
// update pclk2 with the real value
386385
pclk2 = hclk / ppre2_val;
387386

388-
// Configure HCLK, PCLK1, PCLK2
389-
rcc.cfgr.modify(|_, w| unsafe {
390-
w
391-
.ppre1().bits(ppre1 as u8)
392-
.ppre2().bits(ppre2 as u8)
393-
.hpre().bits(hpre as u8)
394-
});
395-
396387
// Assumes TIMPRE bit of RCC_DCKCFGR1 is reset (0)
397388
let timclk1 = if ppre1_val == 1 {pclk1} else {2 * pclk1};
398389
let timclk2 = if ppre2_val == 1 {pclk2} else {2 * pclk2};
@@ -418,6 +409,32 @@ impl CFGR {
418409
})
419410
});
420411

412+
// Select SYSCLK source
413+
if use_pll {
414+
rcc.cfgr.modify(|_, w| w.sw().pll());
415+
while ! rcc.cfgr.read().sws().is_pll() {}
416+
417+
} else if self.hse.is_some() {
418+
rcc.cfgr.modify(|_, w| w.sw().hse());
419+
while ! rcc.cfgr.read().sws().is_hse() {}
420+
421+
} else {
422+
rcc.cfgr.modify(|_, w| w.sw().hsi());
423+
while ! rcc.cfgr.read().sws().is_hsi() {}
424+
}
425+
426+
// Configure HCLK, PCLK1, PCLK2
427+
rcc.cfgr.modify(|_, w| unsafe {
428+
w
429+
.ppre1().bits(ppre1 as u8)
430+
.ppre2().bits(ppre2 as u8)
431+
.hpre().bits(hpre as u8)
432+
});
433+
434+
// As requested by user manual we need to wit 16 ticks before the right
435+
// predivision is applied
436+
cortex_m::asm::delay(16);
437+
421438
Clocks {
422439
hclk: Hertz(hclk),
423440
pclk1: Hertz(pclk1),

0 commit comments

Comments
 (0)