Merge branch 'stm32g4_adc' of https://github.com/daehyeok/embassy into adc-g4
This commit is contained in:
commit
7e18e5e0c1
@ -58,7 +58,7 @@ sdio-host = "0.5.0"
|
|||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9a61a1f090462df8bd1751f89951f04934fdceb3" }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0" }
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -70,6 +70,7 @@ embedded-io-async = { version = "0.5.0", optional = true }
|
|||||||
chrono = { version = "^0.4", default-features = false, optional = true}
|
chrono = { version = "^0.4", default-features = false, optional = true}
|
||||||
bit_field = "0.10.2"
|
bit_field = "0.10.2"
|
||||||
document-features = "0.2.7"
|
document-features = "0.2.7"
|
||||||
|
paste = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
critical-section = { version = "1.1", features = ["std"] }
|
critical-section = { version = "1.1", features = ["std"] }
|
||||||
@ -77,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9a61a1f090462df8bd1751f89951f04934fdceb3", default-features = false, features = ["metadata"]}
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use core::sync::atomic::{AtomicU8, Ordering};
|
use core::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
|
||||||
use embedded_hal_02::blocking::delay::DelayUs;
|
use embedded_hal_02::blocking::delay::DelayUs;
|
||||||
|
#[allow(unused)]
|
||||||
use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
|
use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
|
||||||
use pac::adccommon::vals::Presc;
|
use pac::adccommon::vals::Presc;
|
||||||
|
use paste::paste;
|
||||||
|
|
||||||
use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
|
use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
@ -13,12 +15,31 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
|
|||||||
/// VREF voltage used for factory calibration of VREFINTCAL register.
|
/// VREF voltage used for factory calibration of VREFINTCAL register.
|
||||||
pub const VREF_CALIB_MV: u32 = 3300;
|
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;
|
pub struct VrefInt;
|
||||||
impl<T: Instance> InternalChannel<T> for VrefInt {}
|
impl<T: Instance> InternalChannel<T> for VrefInt {}
|
||||||
impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
|
impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
19
|
VREF_CHANNEL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +47,7 @@ pub struct Temperature;
|
|||||||
impl<T: Instance> InternalChannel<T> for Temperature {}
|
impl<T: Instance> InternalChannel<T> for Temperature {}
|
||||||
impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
|
impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
18
|
TEMP_CHANNEL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,126 +55,79 @@ pub struct Vbat;
|
|||||||
impl<T: Instance> InternalChannel<T> for Vbat {}
|
impl<T: Instance> InternalChannel<T> for Vbat {}
|
||||||
impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
|
impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
// TODO this should be 14 for H7a/b/35
|
VBAT_CHANNEL
|
||||||
17
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
|
static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
|
||||||
|
#[cfg(any(stm32g4x3, stm32g4x4))]
|
||||||
|
static ADC345_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
macro_rules! rcc_peripheral {
|
||||||
|
($adc_name:ident, $freqs:ident, $ahb:ident, $reg:ident $(, $counter:ident )? ) => {
|
||||||
|
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::$adc_name {
|
||||||
|
fn frequency() -> crate::time::Hertz {
|
||||||
|
critical_section::with(|_| {
|
||||||
|
match unsafe { crate::rcc::get_freqs() }.$freqs {
|
||||||
|
Some(ck) => ck,
|
||||||
|
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable() {
|
||||||
|
critical_section::with(|_| {
|
||||||
|
paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](true))}
|
||||||
|
});
|
||||||
|
$ ( $counter.fetch_add(1, Ordering::SeqCst); )?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable() {
|
||||||
|
$ ( if $counter.load(Ordering::SeqCst) == 1 )? {
|
||||||
|
critical_section::with(|_| {
|
||||||
|
paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](false))}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$ ( $counter.fetch_sub(1, Ordering::SeqCst); )?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset() {
|
||||||
|
$ ( if $counter.load(Ordering::SeqCst) == 1 )? {
|
||||||
|
critical_section::with(|_| {
|
||||||
|
paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](true))}
|
||||||
|
paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](false))}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::rcc::RccPeripheral for crate::peripherals::$adc_name {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(stm32g4)]
|
||||||
|
foreach_peripheral!(
|
||||||
|
(adc, ADC1) => { rcc_peripheral!(ADC1, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); };
|
||||||
|
(adc, ADC2) => { rcc_peripheral!(ADC2, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); };
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(stm32g4x1)]
|
||||||
|
foreach_peripheral!(
|
||||||
|
(adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345); };
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(any(stm32g4x3, stm32g4x4))]
|
||||||
|
foreach_peripheral!(
|
||||||
|
(adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); };
|
||||||
|
(adc, ADC4) => { rcc_peripheral!(ADC4, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); };
|
||||||
|
(adc, ADC5) => { rcc_peripheral!(ADC5, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); };
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(stm32h7)]
|
#[cfg(stm32h7)]
|
||||||
foreach_peripheral!(
|
foreach_peripheral!(
|
||||||
(adc, ADC1) => {
|
(adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); };
|
||||||
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
|
(adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); };
|
||||||
fn frequency() -> crate::time::Hertz {
|
(adc, ADC3) => { rcc_peripheral!(ADC3, adc, ahb4, adc3); };
|
||||||
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,
|
// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
|
||||||
@ -176,7 +150,7 @@ enum Prescaler {
|
|||||||
|
|
||||||
impl Prescaler {
|
impl Prescaler {
|
||||||
fn from_ker_ck(frequency: Hertz) -> Self {
|
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 {
|
match raw_prescaler {
|
||||||
0 => Self::NotDivided,
|
0 => Self::NotDivided,
|
||||||
1 => Self::DividedBy2,
|
1 => Self::DividedBy2,
|
||||||
@ -237,20 +211,23 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
let frequency = Hertz(T::frequency().0 / prescaler.divisor());
|
let frequency = Hertz(T::frequency().0 / prescaler.divisor());
|
||||||
info!("ADC frequency set to {} Hz", frequency.0);
|
info!("ADC frequency set to {} Hz", frequency.0);
|
||||||
|
|
||||||
if frequency > Hertz::mhz(50) {
|
if frequency > MAX_ADC_CLK_FREQ {
|
||||||
panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information.");
|
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 {
|
let mut s = Self {
|
||||||
adc,
|
adc,
|
||||||
sample_time: Default::default(),
|
sample_time: Default::default(),
|
||||||
@ -379,10 +356,14 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
// Configure channel
|
// Configure channel
|
||||||
Self::set_channel_sample_time(channel, self.sample_time);
|
Self::set_channel_sample_time(channel, self.sample_time);
|
||||||
|
|
||||||
T::regs().cfgr2().modify(|w| w.set_lshift(0));
|
#[cfg(stm32h7)]
|
||||||
T::regs()
|
{
|
||||||
.pcsel()
|
T::regs().cfgr2().modify(|w| w.set_lshift(0));
|
||||||
.write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
|
T::regs()
|
||||||
|
.pcsel()
|
||||||
|
.write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
|
||||||
|
}
|
||||||
|
|
||||||
T::regs().sqr1().write(|reg| {
|
T::regs().sqr1().write(|reg| {
|
||||||
reg.set_sq(0, channel);
|
reg.set_sq(0, channel);
|
||||||
reg.set_l(0);
|
reg.set_l(0);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use stm32_metapac::flash::vals::Latency;
|
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;
|
use stm32_metapac::FLASH;
|
||||||
|
|
||||||
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
||||||
@ -14,6 +14,29 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
|||||||
/// LSI speed
|
/// LSI speed
|
||||||
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
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
|
/// System clock mux source
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ClockSrc {
|
pub enum ClockSrc {
|
||||||
@ -327,6 +350,8 @@ pub struct Config {
|
|||||||
pub pll: Option<Pll>,
|
pub pll: Option<Pll>,
|
||||||
/// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
|
/// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
|
||||||
pub clock_48mhz_src: Option<Clock48MhzSrc>,
|
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.
|
/// 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,
|
low_power_run: false,
|
||||||
pll: None,
|
pll: None,
|
||||||
clock_48mhz_src: 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_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 {
|
if config.low_power_run {
|
||||||
assert!(sys_clk <= 2_000_000);
|
assert!(sys_clk <= 2_000_000);
|
||||||
PWR.cr1().modify(|w| w.set_lpr(true));
|
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),
|
apb1_tim: Hertz(apb1_tim_freq),
|
||||||
apb2: Hertz(apb2_freq),
|
apb2: Hertz(apb2_freq),
|
||||||
apb2_tim: Hertz(apb2_tim_freq),
|
apb2_tim: Hertz(apb2_tim_freq),
|
||||||
|
adc12: adc12_ck,
|
||||||
|
adc345: adc345_ck,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,12 @@ pub struct Clocks {
|
|||||||
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
|
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
|
||||||
pub adc: Option<Hertz>,
|
pub adc: Option<Hertz>,
|
||||||
|
|
||||||
|
#[cfg(any(rcc_g4))]
|
||||||
|
pub adc12: Option<Hertz>,
|
||||||
|
|
||||||
|
#[cfg(any(rcc_g4))]
|
||||||
|
pub adc345: Option<Hertz>,
|
||||||
|
|
||||||
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
||||||
/// Set only if the lsi or lse is configured, indicates stop is supported
|
/// Set only if the lsi or lse is configured, indicates stop is supported
|
||||||
pub rtc: Option<Hertz>,
|
pub rtc: Option<Hertz>,
|
||||||
|
@ -11,6 +11,8 @@ embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["de
|
|||||||
embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
usbd-hid = "0.6.0"
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
defmt-rtt = "0.4"
|
defmt-rtt = "0.4"
|
||||||
|
41
examples/stm32g4/src/bin/adc.rs
Normal file
41
examples/stm32g4/src/bin/adc.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::*;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::adc::{Adc, SampleTime};
|
||||||
|
use embassy_stm32::rcc::{AdcClockSource, ClockSrc, Pll, PllM, PllN, PllR, PllSrc};
|
||||||
|
use embassy_stm32::Config;
|
||||||
|
use embassy_time::{Delay, Duration, Timer};
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let mut config = Config::default();
|
||||||
|
|
||||||
|
config.rcc.pll = Some(Pll {
|
||||||
|
source: PllSrc::HSI16,
|
||||||
|
prediv_m: PllM::Div4,
|
||||||
|
mul_n: PllN::Mul85,
|
||||||
|
div_p: None,
|
||||||
|
div_q: None,
|
||||||
|
// Main system clock at 170 MHz
|
||||||
|
div_r: Some(PllR::Div2),
|
||||||
|
});
|
||||||
|
|
||||||
|
config.rcc.adc12_clock_source = AdcClockSource::SysClk;
|
||||||
|
config.rcc.mux = ClockSrc::PLL;
|
||||||
|
|
||||||
|
let mut p = embassy_stm32::init(config);
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let mut adc = Adc::new(p.ADC2, &mut Delay);
|
||||||
|
adc.set_sample_time(SampleTime::Cycles32_5);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let measured = adc.read(&mut p.PA7);
|
||||||
|
info!("measured: {}", measured);
|
||||||
|
Timer::after(Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user