Merge pull request #1867 from xoviat/adc-g4

Adc g4
This commit is contained in:
xoviat
2023-09-05 23:31:03 +00:00
committed by GitHub
8 changed files with 163 additions and 159 deletions

View File

@ -56,7 +56,7 @@ pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc:
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
#[cfg(not(any(stm32h7, adc_f3)))]
#[cfg(not(any(stm32h7, adc_f3, adc_v4)))]
foreach_peripheral!(
(adc, $inst:ident) => {
impl crate::adc::sealed::Instance for peripherals::$inst {
@ -77,9 +77,10 @@ foreach_peripheral!(
};
);
#[cfg(any(stm32h7, adc_f3))]
#[cfg(any(stm32h7, adc_f3, adc_v4))]
foreach_peripheral!(
(adc, ADC3) => {
#[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))]
impl crate::adc::sealed::Instance for peripherals::ADC3 {
fn regs() -> crate::pac::adc::Adc {
crate::pac::ADC3
@ -99,9 +100,11 @@ foreach_peripheral!(
}
}
#[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))]
impl crate::adc::Instance for peripherals::ADC3 {}
};
(adc, ADC4) => {
#[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))]
impl crate::adc::sealed::Instance for peripherals::ADC4 {
fn regs() -> crate::pac::adc::Adc {
crate::pac::ADC4
@ -121,7 +124,11 @@ foreach_peripheral!(
}
}
#[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))]
impl crate::adc::Instance for peripherals::ADC4 {}
};
(adc, ADC5) => {
};
(adc, $inst:ident) => {
impl crate::adc::sealed::Instance for peripherals::$inst {

View File

@ -1,6 +1,5 @@
use core::sync::atomic::{AtomicU8, Ordering};
use embedded_hal_02::blocking::delay::DelayUs;
#[allow(unused)]
use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
use pac::adccommon::vals::Presc;
@ -13,12 +12,31 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
/// VREF voltage used for factory calibration of VREFINTCAL register.
pub const VREF_CALIB_MV: u32 = 3300;
// NOTE: Vrefint/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
/// Max single ADC operation clock frequency
#[cfg(stm32g4)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
#[cfg(stm32h7)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
#[cfg(stm32g4)]
const VREF_CHANNEL: u8 = 18;
#[cfg(stm32g4)]
const TEMP_CHANNEL: u8 = 16;
#[cfg(stm32h7)]
const VREF_CHANNEL: u8 = 19;
#[cfg(stm32h7)]
const TEMP_CHANNEL: u8 = 18;
// TODO this should be 14 for H7a/b/35
const VBAT_CHANNEL: u8 = 17;
// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
pub struct VrefInt;
impl<T: Instance> InternalChannel<T> for VrefInt {}
impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
fn channel(&self) -> u8 {
19
VREF_CHANNEL
}
}
@ -26,7 +44,7 @@ pub struct Temperature;
impl<T: Instance> InternalChannel<T> for Temperature {}
impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
fn channel(&self) -> u8 {
18
TEMP_CHANNEL
}
}
@ -34,128 +52,10 @@ pub struct Vbat;
impl<T: Instance> InternalChannel<T> for Vbat {}
impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
fn channel(&self) -> u8 {
// TODO this should be 14 for H7a/b/35
17
VBAT_CHANNEL
}
}
static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
#[cfg(stm32h7)]
foreach_peripheral!(
(adc, ADC1) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
})
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
});
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
}
fn disable() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
})
}
ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
}
fn reset() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| {
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
});
}
}
}
impl crate::rcc::RccPeripheral for crate::peripherals::ADC1 {}
};
(adc, ADC2) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
})
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
});
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
}
fn disable() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
})
}
ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
}
fn reset() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| {
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
});
}
}
}
impl crate::rcc::RccPeripheral for crate::peripherals::ADC2 {}
};
(adc, ADC3) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
})
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
});
}
fn disable() {
critical_section::with(|_| {
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
})
}
fn reset() {
critical_section::with(|_| {
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
});
}
}
impl crate::rcc::RccPeripheral for crate::peripherals::ADC3 {}
};
);
// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
#[allow(unused)]
@ -176,7 +76,7 @@ enum Prescaler {
impl Prescaler {
fn from_ker_ck(frequency: Hertz) -> Self {
let raw_prescaler = frequency.0 / 50_000_000;
let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
match raw_prescaler {
0 => Self::NotDivided,
1 => Self::DividedBy2,
@ -237,20 +137,23 @@ impl<'d, T: Instance> Adc<'d, T> {
let frequency = Hertz(T::frequency().0 / prescaler.divisor());
info!("ADC frequency set to {} Hz", frequency.0);
if frequency > Hertz::mhz(50) {
panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information.");
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 );
}
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));
#[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));
}
let mut s = Self {
adc,
sample_time: Default::default(),
@ -379,10 +282,14 @@ impl<'d, T: Instance> Adc<'d, T> {
// Configure channel
Self::set_channel_sample_time(channel, self.sample_time);
T::regs().cfgr2().modify(|w| w.set_lshift(0));
T::regs()
.pcsel()
.write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
#[cfg(stm32h7)]
{
T::regs().cfgr2().modify(|w| w.set_lshift(0));
T::regs()
.pcsel()
.write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
}
T::regs().sqr1().write(|reg| {
reg.set_sq(0, channel);
reg.set_l(0);

View File

@ -1,5 +1,5 @@
use stm32_metapac::flash::vals::Latency;
use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
use stm32_metapac::rcc::vals::{Adcsel, Hpre, Pllsrc, Ppre, Sw};
use stm32_metapac::FLASH;
pub use super::bus::{AHBPrescaler, APBPrescaler};
@ -14,6 +14,29 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
#[derive(Clone, Copy)]
pub enum AdcClockSource {
NoClk,
SysClk,
PllP,
}
impl AdcClockSource {
pub fn adcsel(&self) -> Adcsel {
match self {
AdcClockSource::NoClk => Adcsel::NOCLK,
AdcClockSource::SysClk => Adcsel::SYSCLK,
AdcClockSource::PllP => Adcsel::PLLP,
}
}
}
impl Default for AdcClockSource {
fn default() -> Self {
Self::NoClk
}
}
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
@ -327,6 +350,8 @@ pub struct Config {
pub pll: Option<Pll>,
/// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
pub clock_48mhz_src: Option<Clock48MhzSrc>,
pub adc12_clock_source: AdcClockSource,
pub adc345_clock_source: AdcClockSource,
}
/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
@ -346,6 +371,8 @@ impl Default for Config {
low_power_run: false,
pll: None,
clock_48mhz_src: None,
adc12_clock_source: Default::default(),
adc345_clock_source: Default::default(),
}
}
}
@ -549,6 +576,29 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr().modify(|w| w.set_clk48sel(source));
}
RCC.ccipr()
.modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel()));
RCC.ccipr()
.modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel()));
let adc12_ck = match config.adc12_clock_source {
AdcClockSource::NoClk => None,
AdcClockSource::PllP => match &pll_freq {
Some(pll) => pll.pll_p,
None => None,
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
};
let adc345_ck = match config.adc345_clock_source {
AdcClockSource::NoClk => None,
AdcClockSource::PllP => match &pll_freq {
Some(pll) => pll.pll_p,
None => None,
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
};
if config.low_power_run {
assert!(sys_clk <= 2_000_000);
PWR.cr1().modify(|w| w.set_lpr(true));
@ -562,5 +612,7 @@ pub(crate) unsafe fn init(config: Config) {
apb1_tim: Hertz(apb1_tim_freq),
apb2: Hertz(apb2_freq),
apb2_tim: Hertz(apb2_tim_freq),
adc: adc12_ck,
adc34: adc345_ck,
});
}

View File

@ -74,10 +74,10 @@ pub struct Clocks {
#[cfg(stm32f1)]
pub adc: Hertz,
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3))]
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))]
pub adc: Option<Hertz>,
#[cfg(rcc_f3)]
#[cfg(any(rcc_f3, rcc_g4))]
pub adc34: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]