stm32: add initial adc f3 impl
This commit is contained in:
parent
e2f8bf19ea
commit
f502271940
8 changed files with 331 additions and 23 deletions
|
@ -309,14 +309,17 @@ fn main() {
|
||||||
// Generate RccPeripheral impls
|
// Generate RccPeripheral impls
|
||||||
|
|
||||||
// TODO: maybe get this from peripheral kind? Not sure
|
// TODO: maybe get this from peripheral kind? Not sure
|
||||||
let refcounted_peripherals = HashSet::from(["USART"]);
|
let mut refcounted_peripherals = HashSet::from(["usart"]);
|
||||||
let mut refcount_statics = HashSet::new();
|
let mut refcount_statics = HashSet::new();
|
||||||
|
|
||||||
|
if chip_name.starts_with("stm32f3") {
|
||||||
|
refcounted_peripherals.insert("adc");
|
||||||
|
}
|
||||||
|
|
||||||
for p in METADATA.peripherals {
|
for p in METADATA.peripherals {
|
||||||
// generating RccPeripheral impl for H7 ADC3 would result in bad frequency
|
// generating RccPeripheral impl for H7 ADC3 would result in bad frequency
|
||||||
if !singletons.contains(&p.name.to_string())
|
if !singletons.contains(&p.name.to_string())
|
||||||
|| (p.name == "ADC3" && METADATA.line.starts_with("STM32H7"))
|
|| (p.name == "ADC3" && METADATA.line.starts_with("STM32H7"))
|
||||||
|| (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "f3"))
|
|
||||||
|| (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4"))
|
|| (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4"))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -348,13 +351,13 @@ fn main() {
|
||||||
TokenStream::new()
|
TokenStream::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let ptype = (if let Some(reg) = &p.registers { reg.kind } else { "" }).to_ascii_uppercase();
|
let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
|
||||||
let pname = format_ident!("{}", p.name);
|
let pname = format_ident!("{}", p.name);
|
||||||
let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase());
|
let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase());
|
||||||
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
||||||
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
|
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
|
||||||
|
|
||||||
let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype.as_str()) {
|
let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) {
|
||||||
let refcount_static =
|
let refcount_static =
|
||||||
format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
|
format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
|
||||||
|
|
||||||
|
|
126
embassy-stm32/src/adc/f3.rs
Normal file
126
embassy-stm32/src/adc/f3.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
use embassy_hal_internal::into_ref;
|
||||||
|
use embedded_hal_02::blocking::delay::DelayUs;
|
||||||
|
|
||||||
|
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||||
|
use crate::time::Hertz;
|
||||||
|
use crate::Peripheral;
|
||||||
|
|
||||||
|
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||||
|
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
||||||
|
// No calibration data for F103, voltage should be 1.2v
|
||||||
|
pub const VREF_INT: u32 = 1200;
|
||||||
|
|
||||||
|
pub struct Vref;
|
||||||
|
impl<T: Instance> AdcPin<T> for Vref {}
|
||||||
|
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Temperature;
|
||||||
|
impl<T: Instance> AdcPin<T> for Temperature {}
|
||||||
|
impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> Adc<'d, T> {
|
||||||
|
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||||
|
use crate::pac::adc::vals;
|
||||||
|
|
||||||
|
into_ref!(adc);
|
||||||
|
|
||||||
|
T::enable();
|
||||||
|
T::reset();
|
||||||
|
|
||||||
|
// Enable the adc regulator
|
||||||
|
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
|
||||||
|
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED));
|
||||||
|
|
||||||
|
// Wait for the regulator to stabilize
|
||||||
|
delay.delay_us(10);
|
||||||
|
|
||||||
|
assert!(!T::regs().cr().read().aden());
|
||||||
|
|
||||||
|
// Begin calibration
|
||||||
|
T::regs().cr().modify(|w| w.set_adcaldif(false));
|
||||||
|
T::regs().cr().modify(|w| w.set_adcal(true));
|
||||||
|
|
||||||
|
while T::regs().cr().read().adcal() {}
|
||||||
|
|
||||||
|
// Enable the adc
|
||||||
|
T::regs().cr().modify(|w| w.set_aden(true));
|
||||||
|
|
||||||
|
// Wait until the adc is ready
|
||||||
|
while !T::regs().isr().read().adrdy() {}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
adc,
|
||||||
|
sample_time: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freq() -> Hertz {
|
||||||
|
<T as crate::adc::sealed::Instance>::frequency()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
|
||||||
|
match us * Self::freq().0 / 1_000_000 {
|
||||||
|
0..=1 => SampleTime::Cycles1_5,
|
||||||
|
2..=4 => SampleTime::Cycles4_5,
|
||||||
|
5..=7 => SampleTime::Cycles7_5,
|
||||||
|
8..=19 => SampleTime::Cycles19_5,
|
||||||
|
20..=61 => SampleTime::Cycles61_5,
|
||||||
|
62..=181 => SampleTime::Cycles181_5,
|
||||||
|
_ => SampleTime::Cycles601_5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
|
||||||
|
T::common_regs().ccr().modify(|w| w.set_vrefen(true));
|
||||||
|
|
||||||
|
Vref {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_temperature(&self) -> Temperature {
|
||||||
|
T::common_regs().ccr().modify(|w| w.set_tsen(true));
|
||||||
|
|
||||||
|
Temperature {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
|
||||||
|
self.sample_time = sample_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform a single conversion.
|
||||||
|
fn convert(&mut self) -> u16 {
|
||||||
|
T::regs().isr().write(|_| {});
|
||||||
|
T::regs().cr().modify(|w| w.set_adstart(true));
|
||||||
|
|
||||||
|
while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {}
|
||||||
|
T::regs().isr().write(|_| {});
|
||||||
|
|
||||||
|
T::regs().dr().read().0 as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
|
// pin.set_as_analog();
|
||||||
|
|
||||||
|
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
||||||
|
|
||||||
|
// Configure the channel to sample
|
||||||
|
T::regs().sqr3().write(|w| w.set_sq(0, pin.channel()));
|
||||||
|
self.convert()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
|
let sample_time = sample_time.into();
|
||||||
|
if ch <= 9 {
|
||||||
|
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||||
|
} else {
|
||||||
|
T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +1,24 @@
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
#[cfg(not(any(adc_f3, adc_f3_v2)))]
|
#[cfg(not(adc_f3_v2))]
|
||||||
#[cfg_attr(adc_f1, path = "f1.rs")]
|
#[cfg_attr(adc_f1, path = "f1.rs")]
|
||||||
|
#[cfg_attr(adc_f3, path = "f3.rs")]
|
||||||
#[cfg_attr(adc_v1, path = "v1.rs")]
|
#[cfg_attr(adc_v1, path = "v1.rs")]
|
||||||
#[cfg_attr(adc_v2, path = "v2.rs")]
|
#[cfg_attr(adc_v2, path = "v2.rs")]
|
||||||
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
|
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
|
||||||
#[cfg_attr(adc_v4, path = "v4.rs")]
|
#[cfg_attr(adc_v4, path = "v4.rs")]
|
||||||
mod _version;
|
mod _version;
|
||||||
|
|
||||||
#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
|
#[cfg(not(any(adc_f1, adc_f3_v2)))]
|
||||||
mod resolution;
|
mod resolution;
|
||||||
mod sample_time;
|
mod sample_time;
|
||||||
|
|
||||||
#[cfg(not(any(adc_f3, adc_f3_v2)))]
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
#[cfg(not(adc_f3_v2))]
|
||||||
pub use _version::*;
|
pub use _version::*;
|
||||||
#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
|
#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
|
||||||
pub use resolution::Resolution;
|
pub use resolution::Resolution;
|
||||||
#[cfg(not(any(adc_f3, adc_f3_v2)))]
|
#[cfg(not(adc_f3_v2))]
|
||||||
pub use sample_time::SampleTime;
|
pub use sample_time::SampleTime;
|
||||||
|
|
||||||
use crate::peripherals;
|
use crate::peripherals;
|
||||||
|
@ -25,15 +26,17 @@ use crate::peripherals;
|
||||||
pub struct Adc<'d, T: Instance> {
|
pub struct Adc<'d, T: Instance> {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
adc: crate::PeripheralRef<'d, T>,
|
adc: crate::PeripheralRef<'d, T>,
|
||||||
#[cfg(not(any(adc_f3, adc_f3_v2)))]
|
#[cfg(not(adc_f3_v2))]
|
||||||
sample_time: SampleTime,
|
sample_time: SampleTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
fn regs() -> crate::pac::adc::Adc;
|
fn regs() -> crate::pac::adc::Adc;
|
||||||
#[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))]
|
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))]
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
||||||
|
#[cfg(adc_f3)]
|
||||||
|
fn frequency() -> crate::time::Hertz;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AdcPin<T: Instance> {
|
pub trait AdcPin<T: Instance> {
|
||||||
|
@ -45,22 +48,22 @@ pub(crate) mod sealed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))]
|
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))]
|
||||||
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
|
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
|
||||||
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))]
|
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))]
|
||||||
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
|
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
|
||||||
|
|
||||||
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
|
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
|
||||||
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
|
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
|
||||||
|
|
||||||
#[cfg(not(stm32h7))]
|
#[cfg(not(any(stm32h7, adc_f3)))]
|
||||||
foreach_peripheral!(
|
foreach_peripheral!(
|
||||||
(adc, $inst:ident) => {
|
(adc, $inst:ident) => {
|
||||||
impl crate::adc::sealed::Instance for peripherals::$inst {
|
impl crate::adc::sealed::Instance for peripherals::$inst {
|
||||||
fn regs() -> crate::pac::adc::Adc {
|
fn regs() -> crate::pac::adc::Adc {
|
||||||
crate::pac::$inst
|
crate::pac::$inst
|
||||||
}
|
}
|
||||||
#[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))]
|
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))]
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||||
foreach_peripheral!{
|
foreach_peripheral!{
|
||||||
(adccommon, $common_inst:ident) => {
|
(adccommon, $common_inst:ident) => {
|
||||||
|
@ -74,7 +77,7 @@ foreach_peripheral!(
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(stm32h7)]
|
#[cfg(any(stm32h7, adc_f3))]
|
||||||
foreach_peripheral!(
|
foreach_peripheral!(
|
||||||
(adc, ADC3) => {
|
(adc, ADC3) => {
|
||||||
impl crate::adc::sealed::Instance for peripherals::ADC3 {
|
impl crate::adc::sealed::Instance for peripherals::ADC3 {
|
||||||
|
@ -89,16 +92,43 @@ foreach_peripheral!(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(adc_f3)]
|
||||||
|
fn frequency() -> crate::time::Hertz {
|
||||||
|
unsafe { crate::rcc::get_freqs() }.adc34.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::adc::Instance for peripherals::ADC3 {}
|
impl crate::adc::Instance for peripherals::ADC3 {}
|
||||||
};
|
};
|
||||||
|
(adc, ADC4) => {
|
||||||
|
impl crate::adc::sealed::Instance for peripherals::ADC4 {
|
||||||
|
fn regs() -> crate::pac::adc::Adc {
|
||||||
|
crate::pac::ADC4
|
||||||
|
}
|
||||||
|
#[cfg(not(any(adc_f1, adc_v1)))]
|
||||||
|
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||||
|
foreach_peripheral!{
|
||||||
|
(adccommon, ADC3_COMMON) => {
|
||||||
|
return crate::pac::ADC3_COMMON
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(adc_f3)]
|
||||||
|
fn frequency() -> crate::time::Hertz {
|
||||||
|
unsafe { crate::rcc::get_freqs() }.adc34.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::adc::Instance for peripherals::ADC4 {}
|
||||||
|
};
|
||||||
(adc, $inst:ident) => {
|
(adc, $inst:ident) => {
|
||||||
impl crate::adc::sealed::Instance for peripherals::$inst {
|
impl crate::adc::sealed::Instance for peripherals::$inst {
|
||||||
fn regs() -> crate::pac::adc::Adc {
|
fn regs() -> crate::pac::adc::Adc {
|
||||||
crate::pac::$inst
|
crate::pac::$inst
|
||||||
}
|
}
|
||||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
#[cfg(not(any(adc_f1, adc_v1)))]
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||||
foreach_peripheral!{
|
foreach_peripheral!{
|
||||||
(adccommon, ADC_COMMON) => {
|
(adccommon, ADC_COMMON) => {
|
||||||
|
@ -106,6 +136,11 @@ foreach_peripheral!(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(adc_f3)]
|
||||||
|
fn frequency() -> crate::time::Hertz {
|
||||||
|
unsafe { crate::rcc::get_freqs() }.adc.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::adc::Instance for peripherals::$inst {}
|
impl crate::adc::Instance for peripherals::$inst {}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
|
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum Resolution {
|
pub enum Resolution {
|
||||||
TwelveBit,
|
TwelveBit,
|
||||||
|
@ -19,7 +19,7 @@ pub enum Resolution {
|
||||||
|
|
||||||
impl Default for Resolution {
|
impl Default for Resolution {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
|
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
|
||||||
{
|
{
|
||||||
Self::TwelveBit
|
Self::TwelveBit
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
|
||||||
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
|
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
|
||||||
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
|
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
|
||||||
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
|
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
|
||||||
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
|
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
|
||||||
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
|
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ impl Resolution {
|
||||||
Resolution::TwelveBit => (1 << 12) - 1,
|
Resolution::TwelveBit => (1 << 12) - 1,
|
||||||
Resolution::TenBit => (1 << 10) - 1,
|
Resolution::TenBit => (1 << 10) - 1,
|
||||||
Resolution::EightBit => (1 << 8) - 1,
|
Resolution::EightBit => (1 << 8) - 1,
|
||||||
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
|
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))]
|
||||||
Resolution::SixBit => (1 << 6) - 1,
|
Resolution::SixBit => (1 << 6) - 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#[cfg(not(any(adc_f3, adc_f3_v2)))]
|
#[cfg(not(adc_f3_v2))]
|
||||||
macro_rules! impl_sample_time {
|
macro_rules! impl_sample_time {
|
||||||
($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
|
($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
|
||||||
#[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
|
#[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
|
||||||
|
@ -105,3 +105,19 @@ impl_sample_time!(
|
||||||
("810.5", Cycles810_5, CYCLES810_5)
|
("810.5", Cycles810_5, CYCLES810_5)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(adc_f3)]
|
||||||
|
impl_sample_time!(
|
||||||
|
"1.5",
|
||||||
|
Cycles1_5,
|
||||||
|
(
|
||||||
|
("1.5", Cycles1_5, CYCLES1_5),
|
||||||
|
("2.5", Cycles2_5, CYCLES2_5),
|
||||||
|
("4.5", Cycles4_5, CYCLES4_5),
|
||||||
|
("7.5", Cycles7_5, CYCLES7_5),
|
||||||
|
("19.5", Cycles19_5, CYCLES19_5),
|
||||||
|
("61.5", Cycles61_5, CYCLES61_5),
|
||||||
|
("181.5", Cycles181_5, CYCLES181_5),
|
||||||
|
("601.5", Cycles601_5, CYCLES601_5)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::pac::flash::vals::Latency;
|
use crate::pac::flash::vals::Latency;
|
||||||
use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
|
use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
|
||||||
use crate::pac::{FLASH, RCC};
|
use crate::pac::{FLASH, RCC};
|
||||||
use crate::rcc::{set_freqs, Clocks};
|
use crate::rcc::{set_freqs, Clocks};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
|
@ -10,6 +10,46 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000);
|
||||||
/// LSI speed
|
/// LSI speed
|
||||||
pub const LSI_FREQ: Hertz = Hertz(40_000);
|
pub const LSI_FREQ: Hertz = Hertz(40_000);
|
||||||
|
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum ADCPrescaler {
|
||||||
|
Div1 = 1,
|
||||||
|
Div2 = 2,
|
||||||
|
Div4 = 4,
|
||||||
|
Div6 = 6,
|
||||||
|
Div8 = 8,
|
||||||
|
Div12 = 12,
|
||||||
|
Div16 = 16,
|
||||||
|
Div32 = 32,
|
||||||
|
Div64 = 64,
|
||||||
|
Div128 = 128,
|
||||||
|
Div256 = 256,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ADCPrescaler> for Adcpres {
|
||||||
|
fn from(value: ADCPrescaler) -> Self {
|
||||||
|
match value {
|
||||||
|
ADCPrescaler::Div1 => Adcpres::DIV1,
|
||||||
|
ADCPrescaler::Div2 => Adcpres::DIV2,
|
||||||
|
ADCPrescaler::Div4 => Adcpres::DIV4,
|
||||||
|
ADCPrescaler::Div6 => Adcpres::DIV6,
|
||||||
|
ADCPrescaler::Div8 => Adcpres::DIV8,
|
||||||
|
ADCPrescaler::Div12 => Adcpres::DIV12,
|
||||||
|
ADCPrescaler::Div16 => Adcpres::DIV16,
|
||||||
|
ADCPrescaler::Div32 => Adcpres::DIV32,
|
||||||
|
ADCPrescaler::Div64 => Adcpres::DIV64,
|
||||||
|
ADCPrescaler::Div128 => Adcpres::DIV128,
|
||||||
|
ADCPrescaler::Div256 => Adcpres::DIV256,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum ADCClock {
|
||||||
|
AHB(ADCPrescaler),
|
||||||
|
PLL(ADCPrescaler),
|
||||||
|
}
|
||||||
|
|
||||||
/// Clocks configutation
|
/// Clocks configutation
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -36,9 +76,18 @@ pub struct Config {
|
||||||
/// - The System clock frequency is either 48MHz or 72MHz
|
/// - The System clock frequency is either 48MHz or 72MHz
|
||||||
/// - APB1 clock has a minimum frequency of 10MHz
|
/// - APB1 clock has a minimum frequency of 10MHz
|
||||||
pub pll48: bool,
|
pub pll48: bool,
|
||||||
|
#[cfg(rcc_f3)]
|
||||||
|
/// ADC clock setup
|
||||||
|
/// - For AHB, a psc of 4 or less must be used
|
||||||
|
pub adc: Option<ADCClock>,
|
||||||
|
#[cfg(rcc_f3)]
|
||||||
|
/// ADC clock setup
|
||||||
|
/// - For AHB, a psc of 4 or less must be used
|
||||||
|
pub adc34: Option<ADCClock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information required to setup the PLL clock
|
// Information required to setup the PLL clock
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
struct PllConfig {
|
struct PllConfig {
|
||||||
pll_src: Pllsrc,
|
pll_src: Pllsrc,
|
||||||
pll_mul: Pllmul,
|
pll_mul: Pllmul,
|
||||||
|
@ -148,6 +197,44 @@ pub(crate) unsafe fn init(config: Config) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(rcc_f3)]
|
||||||
|
let adc = config.adc.map(|adc| match adc {
|
||||||
|
ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| {
|
||||||
|
// Make sure that we're using the PLL
|
||||||
|
pll_config.unwrap();
|
||||||
|
w.set_adc12pres(psc.into());
|
||||||
|
|
||||||
|
Hertz(sysclk / psc as u32)
|
||||||
|
}),
|
||||||
|
ADCClock::AHB(psc) => {
|
||||||
|
assert!(psc as u16 <= 4);
|
||||||
|
assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1));
|
||||||
|
|
||||||
|
// To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be
|
||||||
|
// different from “00”.
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(rcc_f3)]
|
||||||
|
let adc34 = config.adc34.map(|adc| match adc {
|
||||||
|
ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| {
|
||||||
|
// Make sure that we're using the PLL
|
||||||
|
pll_config.unwrap();
|
||||||
|
w.set_adc34pres(psc.into());
|
||||||
|
|
||||||
|
Hertz(sysclk / psc as u32)
|
||||||
|
}),
|
||||||
|
ADCClock::AHB(psc) => {
|
||||||
|
assert!(psc as u16 <= 4);
|
||||||
|
assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1));
|
||||||
|
|
||||||
|
// To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be
|
||||||
|
// different from “00”.
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Set prescalers
|
// Set prescalers
|
||||||
// CFGR has been written before (PLL, PLL48) don't overwrite these settings
|
// CFGR has been written before (PLL, PLL48) don't overwrite these settings
|
||||||
RCC.cfgr().modify(|w| {
|
RCC.cfgr().modify(|w| {
|
||||||
|
@ -177,6 +264,10 @@ pub(crate) unsafe fn init(config: Config) {
|
||||||
apb1_tim: Hertz(pclk1 * timer_mul1),
|
apb1_tim: Hertz(pclk1 * timer_mul1),
|
||||||
apb2_tim: Hertz(pclk2 * timer_mul2),
|
apb2_tim: Hertz(pclk2 * timer_mul2),
|
||||||
ahb1: Hertz(hclk),
|
ahb1: Hertz(hclk),
|
||||||
|
#[cfg(rcc_f3)]
|
||||||
|
adc: adc,
|
||||||
|
#[cfg(rcc_f3)]
|
||||||
|
adc34: adc34,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,12 @@ pub struct Clocks {
|
||||||
#[cfg(stm32f1)]
|
#[cfg(stm32f1)]
|
||||||
pub adc: Hertz,
|
pub adc: Hertz,
|
||||||
|
|
||||||
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
|
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3))]
|
||||||
pub adc: Option<Hertz>,
|
pub adc: Option<Hertz>,
|
||||||
|
|
||||||
|
#[cfg(rcc_f3)]
|
||||||
|
pub adc34: 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>,
|
||||||
|
|
34
examples/stm32f334/src/bin/adc.rs
Normal file
34
examples/stm32f334/src/bin/adc.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::info;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::adc::Adc;
|
||||||
|
use embassy_stm32::rcc::{ADCClock, ADCPrescaler};
|
||||||
|
use embassy_stm32::time::Hertz;
|
||||||
|
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.hse = Some(Hertz(8_000_000));
|
||||||
|
config.rcc.sysclk = Some(Hertz(16_000_000));
|
||||||
|
config.rcc.adc = Some(ADCClock::PLL(ADCPrescaler::Div1));
|
||||||
|
|
||||||
|
let mut p = embassy_stm32::init(config);
|
||||||
|
|
||||||
|
let mut adc = Adc::new(p.ADC1, &mut Delay);
|
||||||
|
|
||||||
|
let mut vrefint = adc.enable_vref(&mut Delay);
|
||||||
|
|
||||||
|
let _vref = adc.read(&mut vrefint);
|
||||||
|
let _pin = adc.read(&mut p.PA0);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
info!("Hello World!");
|
||||||
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue