#[cfg(not(stm32u3))]
use pac::adc::vals::Difsel;
#[cfg(not(any(stm32u5, stm32u3)))]
use pac::adc::vals::{Adcaldif, Boost};
#[allow(unused)]
use pac::adc::vals::{Adstp, Dmngt, Exten, Pcsel};
#[cfg(not(stm32u3))]
use pac::adccommon::vals::Presc;
use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
#[cfg(any(stm32u5, stm32u3))]
use crate::adc::DefaultInstance;
use crate::adc::{AdcRegs, ConversionMode};
use crate::time::Hertz;
use crate::{Peri, pac, rcc};
pub const VREF_DEFAULT_MV: u32 = 3300;
pub const VREF_CALIB_MV: u32 = 3300;
#[cfg(stm32g4)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
#[cfg(stm32h7)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
#[cfg(stm32u5)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
#[cfg(stm32u3)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(48);
#[cfg(stm32g4)]
impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
const CHANNEL: u8 = 18;
}
#[cfg(stm32g4)]
impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
const CHANNEL: u8 = 16;
}
#[cfg(stm32h7)]
impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
const CHANNEL: u8 = 19;
}
#[cfg(stm32h7)]
impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
const CHANNEL: u8 = 18;
}
#[cfg(not(any(stm32u5, stm32u3)))]
impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
const CHANNEL: u8 = 17;
}
#[cfg(any(stm32u5, stm32u3))]
impl<T: DefaultInstance> super::SealedSpecialConverter<super::VrefInt> for T {
const CHANNEL: u8 = 0;
}
#[cfg(stm32u5)]
impl<T: DefaultInstance> super::SealedSpecialConverter<super::Temperature> for T {
const CHANNEL: u8 = 19;
}
#[cfg(stm32u5)]
impl<T: DefaultInstance> super::SealedSpecialConverter<super::Vbat> for T {
const CHANNEL: u8 = 18;
}
#[cfg(stm32u3)]
impl<T: DefaultInstance> super::SealedSpecialConverter<super::Vbat> for T {
const CHANNEL: u8 = 16;
}
#[cfg(stm32u3)]
impl<T: DefaultInstance> super::SealedSpecialConverter<super::Temperature> for T {
const CHANNEL: u8 = 17;
}
#[cfg(not(stm32u3))]
fn from_ker_ck(frequency: Hertz) -> Presc {
let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
match raw_prescaler {
0 => Presc::DIV1,
1 => Presc::DIV2,
2..=3 => Presc::DIV4,
4..=5 => Presc::DIV6,
6..=7 => Presc::DIV8,
8..=9 => Presc::DIV10,
10..=11 => Presc::DIV12,
_ => unimplemented!(),
}
}
#[derive(Default)]
pub struct AdcConfig {
pub resolution: Option<Resolution>,
pub averaging: Option<Averaging>,
}
impl AdcRegs for crate::pac::adc::Adc {
fn data(&self) -> *mut u16 {
crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
}
fn enable(&self) {
if !self.cr().read().aden() {
self.isr().write(|w| w.set_adrdy(true));
self.cr().modify(|w| w.set_aden(true));
while !self.isr().read().adrdy() {}
self.isr().write(|w| w.set_adrdy(true));
}
}
fn start(&self) {
self.cr().modify(|reg| {
reg.set_adstart(true);
});
}
fn stop(&self) {
if self.cr().read().adstart() && !self.cr().read().addis() {
self.cr().modify(|reg| {
reg.set_adstp(Adstp::STOP);
});
while self.cr().read().adstart() {}
}
self.cfgr().modify(|reg| {
reg.set_cont(false);
reg.set_dmngt(Dmngt::from_bits(0));
});
}
fn convert(&self) {
self.isr().modify(|reg| {
reg.set_eos(true);
reg.set_eoc(true);
});
self.cr().modify(|reg| {
reg.set_adstart(true);
});
while !self.isr().read().eos() {
}
}
fn configure_dma(&self, conversion_mode: ConversionMode) {
match conversion_mode {
ConversionMode::Singular => {
self.isr().modify(|reg| {
reg.set_ovr(true);
});
self.cfgr().modify(|reg| {
reg.set_cont(true);
reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
});
}
#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
_ => unreachable!(),
}
}
fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
self.sqr1().modify(|w| {
w.set_l(sequence.len() as u8 - 1);
});
for (i, ((channel, _), sample_time)) in sequence.enumerate() {
let sample_time = sample_time.into();
if channel <= 9 {
self.smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time));
} else {
self.smpr(1).modify(|reg| reg.set_smp((channel - 10) as _, sample_time));
}
#[cfg(any(stm32h7, stm32u5, stm32u3))]
{
self.cfgr2().modify(|w| w.set_lshift(0));
self.pcsel().modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
}
match i {
0..=3 => {
self.sqr1().modify(|w| {
w.set_sq(i, channel);
});
}
4..=8 => {
self.sqr2().modify(|w| {
w.set_sq(i - 4, channel);
});
}
9..=13 => {
self.sqr3().modify(|w| {
w.set_sq(i - 9, channel);
});
}
14..=15 => {
self.sqr4().modify(|w| {
w.set_sq(i - 14, channel);
});
}
_ => unreachable!(),
}
}
}
}
impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
let s = Self::new(adc);
if let Some(resolution) = config.resolution {
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
}
if let Some(averaging) = config.averaging {
let (enable, samples, right_shift) = match averaging {
Averaging::Disabled => (false, 0, 0),
Averaging::Samples2 => (true, 1, 1),
Averaging::Samples4 => (true, 3, 2),
Averaging::Samples8 => (true, 7, 3),
Averaging::Samples16 => (true, 15, 4),
Averaging::Samples32 => (true, 31, 5),
Averaging::Samples64 => (true, 63, 6),
Averaging::Samples128 => (true, 127, 7),
Averaging::Samples256 => (true, 255, 8),
Averaging::Samples512 => (true, 511, 9),
Averaging::Samples1024 => (true, 1023, 10),
};
T::regs().cfgr2().modify(|reg| {
reg.set_rovse(enable);
reg.set_ovsr(samples);
reg.set_ovss(right_shift);
})
}
s
}
pub fn new(adc: Peri<'d, T>) -> Self {
rcc::enable_and_reset::<T>();
#[cfg(not(stm32u3))]
let prescaler = from_ker_ck(T::frequency());
#[cfg(not(stm32u3))]
T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
#[cfg(not(stm32u3))]
let frequency = T::frequency() / prescaler;
#[cfg(stm32u3)]
let frequency = T::frequency();
info!("ADC frequency set to {}", frequency);
if frequency > MAX_ADC_CLK_FREQ {
panic!(
"Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
MAX_ADC_CLK_FREQ.0 / 1_000_000
);
}
#[cfg(stm32h7)]
{
let boost = if frequency < Hertz::khz(6_250) {
Boost::LT6_25
} else if frequency < Hertz::khz(12_500) {
Boost::LT12_5
} else if frequency < Hertz::mhz(25) {
Boost::LT25
} else {
Boost::LT50
};
T::regs().cr().modify(|w| w.set_boost(boost));
}
T::regs().cr().modify(|reg| {
reg.set_deeppwd(false);
reg.set_advregen(true);
});
blocking_delay_us(10);
#[cfg(not(stm32u3))]
T::regs().difsel().modify(|w| {
for n in 0..20 {
w.set_difsel(n, Difsel::SINGLE_ENDED);
}
});
#[cfg(not(stm32u3))]
T::regs().cr().modify(|w| {
#[cfg(not(adc_u5))]
w.set_adcaldif(Adcaldif::SINGLE_ENDED);
w.set_adcallin(true);
});
T::regs().cr().modify(|w| w.set_adcal(true));
while T::regs().cr().read().adcal() {}
blocking_delay_us(1);
T::regs().enable();
T::regs().cfgr().modify(|w| {
w.set_cont(false);
w.set_exten(Exten::DISABLED);
});
Self { adc }
}
pub fn enable_vrefint(&self) -> VrefInt {
T::common_regs().ccr().modify(|reg| {
reg.set_vrefen(true);
});
VrefInt {}
}
pub fn enable_temperature(&self) -> Temperature {
T::common_regs().ccr().modify(|reg| {
reg.set_vsenseen(true);
});
Temperature {}
}
pub fn enable_vbat(&self) -> Vbat {
T::common_regs().ccr().modify(|reg| {
reg.set_vbaten(true);
});
Vbat {}
}
}