Merge pull request #2544 from shufps/feat/adc-l0

Feat/adc l0
This commit is contained in:
Dario Nieuwenhuis 2024-02-09 22:48:57 +00:00 committed by GitHub
commit 04147b4147
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 82 additions and 18 deletions

View File

@ -68,7 +68,7 @@ rand_core = "0.6.3"
sdio-host = "0.5.0" sdio-host = "0.5.0"
critical-section = "1.1" critical-section = "1.1"
#stm32-metapac = { version = "15" } #stm32-metapac = { version = "15" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7c933984fe0cbd120b6aaa7742bd585f89fa786" }
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] }
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24", default-features = false, features = ["metadata"]} stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7c933984fe0cbd120b6aaa7742bd585f89fa786", default-features = false, features = ["metadata"]}
[features] [features]

View File

@ -8,6 +8,7 @@
#[cfg_attr(adc_f3, path = "f3.rs")] #[cfg_attr(adc_f3, path = "f3.rs")]
#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
#[cfg_attr(adc_v1, path = "v1.rs")] #[cfg_attr(adc_v1, path = "v1.rs")]
#[cfg_attr(adc_l0, 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")]
@ -36,15 +37,15 @@ pub struct Adc<'d, T: Instance> {
} }
pub(crate) mod sealed { pub(crate) mod sealed {
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
pub struct State { pub struct State {
pub waker: AtomicWaker, pub waker: AtomicWaker,
} }
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
impl State { impl State {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
@ -59,14 +60,14 @@ pub(crate) mod sealed {
pub trait Instance: InterruptableInstance { pub trait Instance: InterruptableInstance {
fn regs() -> crate::pac::adc::Adc; fn regs() -> crate::pac::adc::Adc;
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon; fn common_regs() -> crate::pac::adccommon::AdcCommon;
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
fn state() -> &'static State; fn state() -> &'static State;
} }
pub trait AdcPin<T: Instance> { pub trait AdcPin<T: Instance> {
#[cfg(any(adc_v1, adc_v2))] #[cfg(any(adc_v1, adc_l0, adc_v2))]
fn set_as_analog(&mut self) {} fn set_as_analog(&mut self) {}
fn channel(&self) -> u8; fn channel(&self) -> u8;
@ -78,10 +79,10 @@ pub(crate) mod sealed {
} }
/// ADC instance. /// ADC instance.
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
/// ADC instance. /// ADC instance.
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] #[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
/// ADC pin. /// ADC pin.
@ -96,12 +97,12 @@ foreach_adc!(
crate::pac::$inst crate::pac::$inst
} }
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon { fn common_regs() -> crate::pac::adccommon::AdcCommon {
return crate::pac::$common_inst return crate::pac::$common_inst
} }
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
fn state() -> &'static sealed::State { fn state() -> &'static sealed::State {
static STATE: sealed::State = sealed::State::new(); static STATE: sealed::State = sealed::State::new();
&STATE &STATE
@ -125,7 +126,7 @@ macro_rules! impl_adc_pin {
impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin {
#[cfg(any(adc_v1, adc_v2))] #[cfg(any(adc_v1, adc_l0, adc_v2))]
fn set_as_analog(&mut self) { fn set_as_analog(&mut self) {
<Self as crate::gpio::sealed::Pin>::set_as_analog(self); <Self as crate::gpio::sealed::Pin>::set_as_analog(self);
} }

View File

@ -1,6 +1,6 @@
/// ADC resolution /// ADC resolution
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Resolution { pub enum Resolution {
@ -25,7 +25,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, adc_f3, adc_f3_v1_1))] #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
{ {
Self::TwelveBit Self::TwelveBit
} }
@ -46,7 +46,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, adc_f3, adc_f3_v1_1))] #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
} }
} }
@ -65,7 +65,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, adc_f3, adc_f3_v1_1))] #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
Resolution::SixBit => (1 << 6) - 1, Resolution::SixBit => (1 << 6) - 1,
} }
} }

View File

@ -83,7 +83,7 @@ impl_sample_time!(
) )
); );
#[cfg(adc_g0)] #[cfg(any(adc_l0, adc_g0))]
impl_sample_time!( impl_sample_time!(
"1.5", "1.5",
Cycles1_5, Cycles1_5,

View File

@ -4,6 +4,8 @@ use core::task::Poll;
use embassy_hal_internal::into_ref; use embassy_hal_internal::into_ref;
use embedded_hal_02::blocking::delay::DelayUs; use embedded_hal_02::blocking::delay::DelayUs;
#[cfg(adc_l0)]
use stm32_metapac::adc::vals::Ckmode;
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::interrupt::typelevel::Interrupt; use crate::interrupt::typelevel::Interrupt;
@ -30,8 +32,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
} }
} }
#[cfg(not(adc_l0))]
pub struct Vbat; pub struct Vbat;
#[cfg(not(adc_l0))]
impl AdcPin<ADC> for Vbat {} impl AdcPin<ADC> for Vbat {}
#[cfg(not(adc_l0))]
impl super::sealed::AdcPin<ADC> for Vbat { impl super::sealed::AdcPin<ADC> for Vbat {
fn channel(&self) -> u8 { fn channel(&self) -> u8 {
18 18
@ -69,9 +76,18 @@ impl<'d, T: Instance> Adc<'d, T> {
// tstab = 14 * 1/fadc // tstab = 14 * 1/fadc
delay.delay_us(1); delay.delay_us(1);
// set default PCKL/2 on L0s because HSI is disabled in the default clock config
#[cfg(adc_l0)]
T::regs().cfgr2().modify(|reg| reg.set_ckmode(Ckmode::PCLK_DIV2));
// A.7.1 ADC calibration code example // A.7.1 ADC calibration code example
T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
T::regs().cr().modify(|reg| reg.set_adcal(true)); T::regs().cr().modify(|reg| reg.set_adcal(true));
#[cfg(adc_l0)]
while !T::regs().isr().read().eocal() {}
#[cfg(not(adc_l0))]
while T::regs().cr().read().adcal() {} while T::regs().cr().read().adcal() {}
// A.7.2 ADC enable sequence code example // A.7.2 ADC enable sequence code example
@ -97,6 +113,7 @@ impl<'d, T: Instance> Adc<'d, T> {
} }
} }
#[cfg(not(adc_l0))]
pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
// SMP must be ≥ 56 ADC clock cycles when using HSI14. // SMP must be ≥ 56 ADC clock cycles when using HSI14.
// //
@ -133,6 +150,12 @@ impl<'d, T: Instance> Adc<'d, T> {
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
} }
#[cfg(adc_l0)]
pub fn set_ckmode(&mut self, ckmode: Ckmode) {
// set ADC clock mode
T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode));
}
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
let channel = pin.channel(); let channel = pin.channel();
pin.set_as_analog(); pin.set_as_analog();

View File

@ -0,0 +1,40 @@
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::peripherals::ADC;
use embassy_stm32::{adc, bind_interrupts};
use embassy_time::{Delay, Timer};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
ADC1_COMP => adc::InterruptHandler<ADC>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
info!("Hello World!");
let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
adc.set_sample_time(SampleTime::Cycles79_5);
let mut pin = p.PA1;
let mut vrefint = adc.enable_vref(&mut Delay);
let vrefint_sample = adc.read(&mut vrefint).await;
let convert_to_millivolts = |sample| {
// From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf
// 6.3.3 Embedded internal reference voltage
const VREFINT_MV: u32 = 1224; // mV
(u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
};
loop {
let v = adc.read(&mut pin).await;
info!("--> {} - {} mV", v, convert_to_millivolts(v));
Timer::after_millis(100).await;
}
}