Automatically set ADC clock prescaler on v2 ADC to respect max frequency
This commit is contained in:
parent
b7a27113f0
commit
53f65d8b09
2 changed files with 70 additions and 2 deletions
|
@ -1,4 +1,5 @@
|
||||||
use crate::adc::{AdcPin, Instance};
|
use crate::adc::{AdcPin, Instance};
|
||||||
|
use crate::time::Hertz;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy_hal_common::unborrow;
|
use embassy_hal_common::unborrow;
|
||||||
|
@ -6,12 +7,12 @@ use embedded_hal_02::blocking::delay::DelayUs;
|
||||||
|
|
||||||
pub const VDDA_CALIB_MV: u32 = 3000;
|
pub const VDDA_CALIB_MV: u32 = 3000;
|
||||||
|
|
||||||
#[cfg(not(rcc_f4))]
|
#[cfg(not(any(rcc_f4, rcc_f7)))]
|
||||||
fn enable() {
|
fn enable() {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(rcc_f4)]
|
#[cfg(any(rcc_f4, rcc_f7))]
|
||||||
fn enable() {
|
fn enable() {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| unsafe {
|
||||||
// TODO do not enable all adc clocks if not needed
|
// TODO do not enable all adc clocks if not needed
|
||||||
|
@ -114,6 +115,39 @@ impl Default for SampleTime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Prescaler {
|
||||||
|
Div2,
|
||||||
|
Div4,
|
||||||
|
Div6,
|
||||||
|
Div8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Prescaler {
|
||||||
|
fn from_pclk2(freq: Hertz) -> Self {
|
||||||
|
// Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
|
||||||
|
const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
|
||||||
|
let raw_div = freq.0 / MAX_FREQUENCY.0;
|
||||||
|
match raw_div {
|
||||||
|
0..=1 => Self::Div2,
|
||||||
|
2..=3 => Self::Div4,
|
||||||
|
4..=5 => Self::Div6,
|
||||||
|
6..=7 => Self::Div8,
|
||||||
|
_ => panic!(
|
||||||
|
"Selected PCLK2 frequency is too high for ADC with largest possible prescaler."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adcpre(&self) -> crate::pac::adccommon::vals::Adcpre {
|
||||||
|
match self {
|
||||||
|
Prescaler::Div2 => crate::pac::adccommon::vals::Adcpre::DIV2,
|
||||||
|
Prescaler::Div4 => crate::pac::adccommon::vals::Adcpre::DIV4,
|
||||||
|
Prescaler::Div6 => crate::pac::adccommon::vals::Adcpre::DIV6,
|
||||||
|
Prescaler::Div8 => crate::pac::adccommon::vals::Adcpre::DIV8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Adc<'d, T: Instance> {
|
pub struct Adc<'d, T: Instance> {
|
||||||
sample_time: SampleTime,
|
sample_time: SampleTime,
|
||||||
calibrated_vdda: u32,
|
calibrated_vdda: u32,
|
||||||
|
@ -128,6 +162,14 @@ where
|
||||||
pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||||
unborrow!(_peri);
|
unborrow!(_peri);
|
||||||
enable();
|
enable();
|
||||||
|
|
||||||
|
let presc = unsafe { Prescaler::from_pclk2(crate::rcc::get_freqs().apb2) };
|
||||||
|
unsafe {
|
||||||
|
T::common_regs()
|
||||||
|
.ccr()
|
||||||
|
.modify(|w| w.set_adcpre(presc.adcpre()));
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// disable before config is set
|
// disable before config is set
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
|
|
26
examples/stm32f7/src/bin/adc.rs
Normal file
26
examples/stm32f7/src/bin/adc.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt_rtt as _; // global logger
|
||||||
|
use panic_probe as _;
|
||||||
|
|
||||||
|
use defmt::*;
|
||||||
|
use embassy::executor::Spawner;
|
||||||
|
use embassy::time::{Delay, Duration, Timer};
|
||||||
|
use embassy_stm32::adc::Adc;
|
||||||
|
use embassy_stm32::Peripherals;
|
||||||
|
|
||||||
|
#[embassy::main]
|
||||||
|
async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let mut adc = Adc::new(p.ADC1, &mut Delay);
|
||||||
|
let mut pin = p.PA3;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let v = adc.read(&mut pin);
|
||||||
|
info!("--> {} - {} mV", v, adc.to_millivolts(v));
|
||||||
|
Timer::after(Duration::from_millis(100)).await;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue