mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 00:02:28 +00:00
commit
04147b4147
@ -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]
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
40
examples/stm32l0/src/bin/adc.rs
Normal file
40
examples/stm32l0/src/bin/adc.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user