From ab8f25fd78582aab68c9820e4b4dd9771a1ded65 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 10:47:26 +0100 Subject: [PATCH 1/7] added support for ADC of L0s --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/mod.rs | 23 ++++++++++++----------- embassy-stm32/src/adc/resolution.rs | 8 ++++---- embassy-stm32/src/adc/sample_time.rs | 2 +- embassy-stm32/src/adc/v1.rs | 21 +++++++++++++++++++++ 5 files changed, 40 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8f0fc1c59..61d70b732 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #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" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } proc-macro2 = "1.0.36" quote = "1.0.15" #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] diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index d21c3053f..51b4b5fcc 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -8,6 +8,7 @@ #[cfg_attr(adc_f3, path = "f3.rs")] #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] #[cfg_attr(adc_v1, path = "v1.rs")] +#[cfg_attr(adc_l0, path = "v1.rs")] #[cfg_attr(adc_v2, path = "v2.rs")] #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] #[cfg_attr(adc_v4, path = "v4.rs")] @@ -36,15 +37,15 @@ pub struct Adc<'d, T: Instance> { } 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; - #[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 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 { pub const fn new() -> Self { Self { @@ -59,14 +60,14 @@ pub(crate) mod sealed { pub trait Instance: InterruptableInstance { 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; - #[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; } pub trait AdcPin { - #[cfg(any(adc_v1, adc_v2))] + #[cfg(any(adc_v1, adc_l0, adc_v2))] fn set_as_analog(&mut self) {} fn channel(&self) -> u8; @@ -78,10 +79,10 @@ pub(crate) mod sealed { } /// 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

{} /// 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

+ crate::rcc::RccPeripheral {} /// ADC pin. @@ -96,12 +97,12 @@ foreach_adc!( 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 { 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 { static STATE: sealed::State = sealed::State::new(); &STATE @@ -125,7 +126,7 @@ macro_rules! impl_adc_pin { impl crate::adc::AdcPin for crate::peripherals::$pin {} impl crate::adc::sealed::AdcPin for crate::peripherals::$pin { - #[cfg(any(adc_v1, adc_v2))] + #[cfg(any(adc_v1, adc_l0, adc_v2))] fn set_as_analog(&mut self) { ::set_as_analog(self); } diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 9513e1df7..0e6c45c65 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -1,6 +1,6 @@ /// ADC resolution #[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)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Resolution { @@ -25,7 +25,7 @@ pub enum Resolution { impl Default for Resolution { 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 } @@ -46,7 +46,7 @@ impl From for crate::pac::adc::vals::Res { Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, 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, } } @@ -65,7 +65,7 @@ impl Resolution { Resolution::TwelveBit => (1 << 12) - 1, Resolution::TenBit => (1 << 10) - 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, } } diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index 5a06f1a5a..f4b22b462 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs @@ -83,7 +83,7 @@ impl_sample_time!( ) ); -#[cfg(adc_g0)] +#[cfg(any(adc_l0, adc_g0))] impl_sample_time!( "1.5", Cycles1_5, diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 852b027df..13a7ead3e 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -6,6 +6,10 @@ use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; + +#[cfg(adc_l0)] +use stm32_metapac::adc::vals::Ckmode; + use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; @@ -30,8 +34,13 @@ impl interrupt::typelevel::Handler for InterruptHandl } } +#[cfg(not(adc_l0))] pub struct Vbat; + +#[cfg(not(adc_l0))] impl AdcPin for Vbat {} + +#[cfg(not(adc_l0))] impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { 18 @@ -72,6 +81,11 @@ impl<'d, T: Instance> Adc<'d, T> { // A.7.1 ADC calibration code example T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); 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() {} // A.7.2 ADC enable sequence code example @@ -97,6 +111,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } + #[cfg(not(adc_l0))] pub fn enable_vbat(&self, _delay: &mut impl DelayUs) -> Vbat { // SMP must be ≥ 56 ADC clock cycles when using HSI14. // @@ -133,6 +148,12 @@ impl<'d, T: Instance> Adc<'d, T> { 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) -> u16 { let channel = pin.channel(); pin.set_as_analog(); From 8dff89bfd99140bc7de48bb5de600a2aeb920681 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:07:30 +0100 Subject: [PATCH 2/7] added ADC example running on L0 --- examples/stm32l0/src/bin/adc.rs | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 examples/stm32l0/src/bin/adc.rs diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs new file mode 100644 index 000000000..93bf5adc6 --- /dev/null +++ b/examples/stm32l0/src/bin/adc.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::Config; +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; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // enable HSI because default is MSI but ADC doesn't support + // this as clock source on L0s and uses HSI by default + let mut config = Config::default(); + config.rcc.hsi = true; + let p = embassy_stm32::init(config); + + 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; + } +} From 158d7dbc8f4714c94cf58e48942543726d717f57 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:11:13 +0100 Subject: [PATCH 3/7] cargo fmt --- examples/stm32l0/src/bin/adc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index 93bf5adc6..f94bf907f 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -2,10 +2,10 @@ #![no_main] use defmt::*; -use embassy_stm32::Config; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; +use embassy_stm32::Config; use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; From 8d0a9bbefb29cab54ba37106a54e5e1f1f04a383 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:14:14 +0100 Subject: [PATCH 4/7] clippy --- embassy-stm32/src/adc/v1.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 13a7ead3e..92529b036 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -5,11 +5,10 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; - #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; +use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; From b2b2abeb333f9bacaa43910d1b75308a3f1c5c4e Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:14:29 +0100 Subject: [PATCH 5/7] clippy --- examples/stm32l0/src/bin/adc.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index f94bf907f..eee69211c 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -5,8 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; -use embassy_stm32::Config; -use embassy_stm32::{adc, bind_interrupts}; +use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; From dabe48c3bd647f13d62d15bbb17983be541f7583 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:15:28 +0100 Subject: [PATCH 6/7] fmt --- embassy-stm32/src/adc/v1.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 92529b036..83bf5aece 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -4,7 +4,6 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; - #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; From 34c71b58cf281e7a0d5517a3f3939477dadb5575 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:28:53 +0100 Subject: [PATCH 7/7] made adc example working with default clock configuration and switched in `v1` to PCLK/2 per default --- embassy-stm32/src/adc/v1.rs | 4 ++++ examples/stm32l0/src/bin/adc.rs | 9 ++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 83bf5aece..37115dfab 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -76,6 +76,10 @@ impl<'d, T: Instance> Adc<'d, T> { // tstab = 14 * 1/fadc 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 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); T::regs().cr().modify(|reg| reg.set_adcal(true)); diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index eee69211c..adeaa208a 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; -use embassy_stm32::{adc, bind_interrupts, Config}; +use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -15,12 +15,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - // enable HSI because default is MSI but ADC doesn't support - // this as clock source on L0s and uses HSI by default - let mut config = Config::default(); - config.rcc.hsi = true; - let p = embassy_stm32::init(config); - + let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);