Skip to content

Commit 11d753c

Browse files
authored
Merge pull request #4742 from esden/fix/adc-prescaler-calc
stm32/ADC: Fix prescaler calculation to include max frequency.
2 parents cf5ac49 + 5e0867f commit 11d753c

File tree

7 files changed

+36
-5
lines changed

7 files changed

+36
-5
lines changed

embassy-stm32/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4141
- feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668))
4242
- feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options
4343
- change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer
44+
- fix: stm32/adc: Calculate the ADC prescaler in a way that it allows for the max frequency to be reached
4445
- fix: Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696)
4546
- change: timer: added output compare values
4647
- feat: timer: add ability to set master mode

embassy-stm32/src/adc/adc4.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 {
7777
}
7878

7979
fn from_ker_ck(frequency: Hertz) -> Presc {
80-
let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
80+
let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
8181
match raw_prescaler {
8282
0 => Presc::DIV1,
8383
1 => Presc::DIV2,

embassy-stm32/src/adc/c0.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
3030
}
3131

3232
fn from_ker_ck(frequency: Hertz) -> Presc {
33-
let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
33+
let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
3434
match raw_prescaler {
3535
0 => Presc::DIV1,
3636
1 => Presc::DIV2,

embassy-stm32/src/adc/g4.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
3333
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
3434

3535
fn from_ker_ck(frequency: Hertz) -> Presc {
36-
let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
36+
let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
3737
match raw_prescaler {
3838
0 => Presc::DIV1,
3939
1 => Presc::DIV2,

embassy-stm32/src/adc/v2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn from_pclk2(freq: Hertz) -> Adcpre {
5858
// Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
5959
#[cfg(not(stm32f2))]
6060
const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
61-
let raw_div = freq.0 / MAX_FREQUENCY.0;
61+
let raw_div = rcc::raw_prescaler(freq.0, MAX_FREQUENCY.0);
6262
match raw_div {
6363
0..=1 => Adcpre::DIV2,
6464
2..=3 => Adcpre::DIV4,

embassy-stm32/src/adc/v4.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
6060
}
6161

6262
fn from_ker_ck(frequency: Hertz) -> Presc {
63-
let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
63+
let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
6464
match raw_prescaler {
6565
0 => Presc::DIV1,
6666
1 => Presc::DIV2,

embassy-stm32/src/rcc/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,33 @@ pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) {
413413
}
414414
}
415415
}
416+
417+
/// Calculate intermediate prescaler number used to calculate peripheral prescalers
418+
///
419+
/// This function is intended to calculate a number indicating a minimum division
420+
/// necessary to result in a frequency lower than the provided `freq_max`.
421+
///
422+
/// The returned value indicates the `val + 1` divider is necessary to result in
423+
/// the output frequency that is below the maximum provided.
424+
///
425+
/// For example:
426+
/// 0 = divider of 1 => no division necessary as the input frequency is below max
427+
/// 1 = divider of 2 => division by 2 necessary
428+
/// ...
429+
///
430+
/// The provided max frequency is inclusive. So if `freq_in == freq_max` the result
431+
/// will be 0, indicating that no division is necessary. To accomplish that we subtract
432+
/// 1 from the input frequency so that the integer rounding plays in our favor.
433+
///
434+
/// For example:
435+
/// Let the input frequency be 110 and the max frequency be 55.
436+
/// If we naiively do `110/55 = 2` the renult will indicate that we need a divider by 3
437+
/// which in reality will be rounded up to 4 as usually a 3 division is not available.
438+
/// In either case the resulting frequency will be either 36 or 27 which is lower than
439+
/// what we would want. The result should be 1.
440+
/// If we do the following instead `109/55 = 1` indicating that we need a divide by 2
441+
/// which will result in the correct 55.
442+
#[allow(unused)]
443+
pub(crate) fn raw_prescaler(freq_in: u32, freq_max: u32) -> u32 {
444+
freq_in.saturating_sub(1) / freq_max
445+
}

0 commit comments

Comments
 (0)