From a9727a17b593f7328f721e8905b7fc8dab9ae7ff Mon Sep 17 00:00:00 2001 From: Piotr Esden-Tempski Date: Sun, 5 Oct 2025 15:49:05 -0700 Subject: stm32/ADC: Fix prescaler calculation to include max frequency. Due to the integer rounding rules one has to subtract 1 from the numerator. For example: Let max clock be 55 and supplied clock be 110 110/55 = 2 which results in the divider being set to 4 and the clock after division ends up being 27 instead of 55 Subtracting 1 to the numerator get around the rounding issue 109/55 = 1 which results in the divider being set to 2 and the clock after division ends up being 55 which is exactly max clock --- embassy-stm32/src/adc/adc4.rs | 3 ++- embassy-stm32/src/adc/c0.rs | 3 ++- embassy-stm32/src/adc/g4.rs | 3 ++- embassy-stm32/src/adc/v2.rs | 3 ++- embassy-stm32/src/adc/v4.rs | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 255dc7956..1302dffb8 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -128,7 +128,8 @@ enum Prescaler { impl Prescaler { fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + // Calculate prescaler in a way where the clock can hit MAX CLK + let raw_prescaler = frequency.0.saturating_sub(1) / MAX_ADC_CLK_FREQ.0; match raw_prescaler { 0 => Self::NotDivided, 1 => Self::DividedBy2, diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index f2837a8f1..bd9a3e2c6 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -66,7 +66,8 @@ pub enum Prescaler { impl Prescaler { fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + // Calculate prescaler in a way where the clock can hit MAX CLK + let raw_prescaler = frequency.0.saturating_sub(1) / MAX_ADC_CLK_FREQ.0; match raw_prescaler { 0 => Self::NotDivided, 1 => Self::DividedBy2, diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 43498966f..ac0a6196f 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -72,7 +72,8 @@ enum Prescaler { impl Prescaler { fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + // Calculate prescaler in a way where the clock can hit MAX CLK + let raw_prescaler = frequency.0.saturating_sub(1) / MAX_ADC_CLK_FREQ.0; match raw_prescaler { 0 => Self::NotDivided, 1 => Self::DividedBy2, diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index e94a25b24..57f252e13 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -71,7 +71,8 @@ impl Prescaler { // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. #[cfg(not(stm32f2))] const MAX_FREQUENCY: Hertz = Hertz(36_000_000); - let raw_div = freq.0 / MAX_FREQUENCY.0; + // Calculate prescaler divider including MAX_FREQ + let raw_div = freq.0.saturating_sub(1) / MAX_FREQUENCY.0; match raw_div { 0..=1 => Self::Div2, 2..=3 => Self::Div4, diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index b66437e6e..c68684cb2 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -93,7 +93,8 @@ enum Prescaler { impl Prescaler { fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + // Calculate prescaler in a way where the clock can hit MAX CLK + let raw_prescaler = frequency.0.saturating_sub(1) / MAX_ADC_CLK_FREQ.0; match raw_prescaler { 0 => Self::NotDivided, 1 => Self::DividedBy2, -- cgit