Skip to content

Commit b45501e

Browse files
committed
Improve f247 PLL output frequency calculation precision
This will produce the correct result for all integer output frequencies and a truncated result for all non-integer output frequencies instead of accumulating an error. The Hertz(1) * ... / Hertz(1) trick is necessary because the values do not implement multiplication by each-other so must be coerced into Hertz. Afterwards, if they remain as Hertz the final division becomes Hertz / Hertz i.e. u32 which is not what we want. So dividing by Hertz early ensures the final division becomes Hertz / u32 which is just Hertz. Unfortunately, avoiding this trickery is non-trivial. I believe this may be the cleanest solution.
1 parent 25e0ebf commit b45501e

File tree

2 files changed

+13
-4
lines changed

2 files changed

+13
-4
lines changed

embassy-stm32/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Add I2S support for STM32F1, STM32C0, STM32F0, STM32F3, STM32F7, STM32G0, STM32WL, STM32H5, STM32H7RS
1616
- fix: STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577))
1717
- feat: Added support for more OctoSPI configurations (e.g. APS6408 RAM) ([#4581](https://github.com/embassy-rs/embassy/pull/4581))
18+
- Improve the PLL output frequency calculation precision for the F2, F4, and F7
19+
series.
1820

1921
## 0.4.0 - 2025-08-26
2022

embassy-stm32/src/rcc/f247.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,8 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll
393393

394394
let in_freq = pll_src / pll.prediv;
395395
assert!(max::PLL_IN.contains(&in_freq));
396-
let vco_freq = in_freq * pll.mul;
396+
let pll_mulsrc = pll_src * pll.mul;
397+
let vco_freq = pll_mulsrc / pll.prediv;
397398
assert!(max::PLL_VCO.contains(&vco_freq));
398399

399400
// stm32f2 plls are like swiss cheese
@@ -408,9 +409,15 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll
408409
}
409410
}
410411

411-
let p = pll.divp.map(|div| vco_freq / div);
412-
let q = pll.divq.map(|div| vco_freq / div);
413-
let r = pll.divr.map(|div| vco_freq / div);
412+
let p = pll
413+
.divp
414+
.map(|div| pll_mulsrc / (Hertz(1) * pll.prediv * div / Hertz(1)));
415+
let q = pll
416+
.divq
417+
.map(|div| pll_mulsrc / (Hertz(1) * pll.prediv * div / Hertz(1)));
418+
let r = pll
419+
.divr
420+
.map(|div| pll_mulsrc / (Hertz(1) * pll.prediv * div / Hertz(1)));
414421

415422
macro_rules! write_fields {
416423
($w:ident) => {

0 commit comments

Comments
 (0)