diff options
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 23 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/resolution.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/sample_time.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v1.rs | 23 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/adc.rs | 40 |
6 files changed, 82 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" | |||
| 68 | sdio-host = "0.5.0" | 68 | sdio-host = "0.5.0" |
| 69 | critical-section = "1.1" | 69 | critical-section = "1.1" |
| 70 | #stm32-metapac = { version = "15" } | 70 | #stm32-metapac = { version = "15" } |
| 71 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24" } | 71 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7c933984fe0cbd120b6aaa7742bd585f89fa786" } |
| 72 | vcell = "0.1.3" | 72 | vcell = "0.1.3" |
| 73 | bxcan = "0.7.0" | 73 | bxcan = "0.7.0" |
| 74 | nb = "1.0.0" | 74 | nb = "1.0.0" |
| @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 89 | proc-macro2 = "1.0.36" | 89 | proc-macro2 = "1.0.36" |
| 90 | quote = "1.0.15" | 90 | quote = "1.0.15" |
| 91 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | 91 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} |
| 92 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24", default-features = false, features = ["metadata"]} | 92 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7c933984fe0cbd120b6aaa7742bd585f89fa786", default-features = false, features = ["metadata"]} |
| 93 | 93 | ||
| 94 | 94 | ||
| 95 | [features] | 95 | [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 @@ | |||
| 8 | #[cfg_attr(adc_f3, path = "f3.rs")] | 8 | #[cfg_attr(adc_f3, path = "f3.rs")] |
| 9 | #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] | 9 | #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] |
| 10 | #[cfg_attr(adc_v1, path = "v1.rs")] | 10 | #[cfg_attr(adc_v1, path = "v1.rs")] |
| 11 | #[cfg_attr(adc_l0, path = "v1.rs")] | ||
| 11 | #[cfg_attr(adc_v2, path = "v2.rs")] | 12 | #[cfg_attr(adc_v2, path = "v2.rs")] |
| 12 | #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] | 13 | #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] |
| 13 | #[cfg_attr(adc_v4, path = "v4.rs")] | 14 | #[cfg_attr(adc_v4, path = "v4.rs")] |
| @@ -36,15 +37,15 @@ pub struct Adc<'d, T: Instance> { | |||
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | pub(crate) mod sealed { | 39 | pub(crate) mod sealed { |
| 39 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] | 40 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 40 | use embassy_sync::waitqueue::AtomicWaker; | 41 | use embassy_sync::waitqueue::AtomicWaker; |
| 41 | 42 | ||
| 42 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] | 43 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 43 | pub struct State { | 44 | pub struct State { |
| 44 | pub waker: AtomicWaker, | 45 | pub waker: AtomicWaker, |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] | 48 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 48 | impl State { | 49 | impl State { |
| 49 | pub const fn new() -> Self { | 50 | pub const fn new() -> Self { |
| 50 | Self { | 51 | Self { |
| @@ -59,14 +60,14 @@ pub(crate) mod sealed { | |||
| 59 | 60 | ||
| 60 | pub trait Instance: InterruptableInstance { | 61 | pub trait Instance: InterruptableInstance { |
| 61 | fn regs() -> crate::pac::adc::Adc; | 62 | fn regs() -> crate::pac::adc::Adc; |
| 62 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] | 63 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] |
| 63 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 64 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 64 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] | 65 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 65 | fn state() -> &'static State; | 66 | fn state() -> &'static State; |
| 66 | } | 67 | } |
| 67 | 68 | ||
| 68 | pub trait AdcPin<T: Instance> { | 69 | pub trait AdcPin<T: Instance> { |
| 69 | #[cfg(any(adc_v1, adc_v2))] | 70 | #[cfg(any(adc_v1, adc_l0, adc_v2))] |
| 70 | fn set_as_analog(&mut self) {} | 71 | fn set_as_analog(&mut self) {} |
| 71 | 72 | ||
| 72 | fn channel(&self) -> u8; | 73 | fn channel(&self) -> u8; |
| @@ -78,10 +79,10 @@ pub(crate) mod sealed { | |||
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | /// ADC instance. | 81 | /// ADC instance. |
| 81 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] | 82 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] |
| 82 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} | 83 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} |
| 83 | /// ADC instance. | 84 | /// ADC instance. |
| 84 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] | 85 | #[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] |
| 85 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 86 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} |
| 86 | 87 | ||
| 87 | /// ADC pin. | 88 | /// ADC pin. |
| @@ -96,12 +97,12 @@ foreach_adc!( | |||
| 96 | crate::pac::$inst | 97 | crate::pac::$inst |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))] | 100 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] |
| 100 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 101 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 101 | return crate::pac::$common_inst | 102 | return crate::pac::$common_inst |
| 102 | } | 103 | } |
| 103 | 104 | ||
| 104 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))] | 105 | #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] |
| 105 | fn state() -> &'static sealed::State { | 106 | fn state() -> &'static sealed::State { |
| 106 | static STATE: sealed::State = sealed::State::new(); | 107 | static STATE: sealed::State = sealed::State::new(); |
| 107 | &STATE | 108 | &STATE |
| @@ -125,7 +126,7 @@ macro_rules! impl_adc_pin { | |||
| 125 | impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} | 126 | impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {} |
| 126 | 127 | ||
| 127 | impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { | 128 | impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin { |
| 128 | #[cfg(any(adc_v1, adc_v2))] | 129 | #[cfg(any(adc_v1, adc_l0, adc_v2))] |
| 129 | fn set_as_analog(&mut self) { | 130 | fn set_as_analog(&mut self) { |
| 130 | <Self as crate::gpio::sealed::Pin>::set_as_analog(self); | 131 | <Self as crate::gpio::sealed::Pin>::set_as_analog(self); |
| 131 | } | 132 | } |
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 @@ | |||
| 1 | /// ADC resolution | 1 | /// ADC resolution |
| 2 | #[allow(missing_docs)] | 2 | #[allow(missing_docs)] |
| 3 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] | 3 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] |
| 4 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | 4 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
| 5 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 5 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 6 | pub enum Resolution { | 6 | pub enum Resolution { |
| @@ -25,7 +25,7 @@ pub enum Resolution { | |||
| 25 | 25 | ||
| 26 | impl Default for Resolution { | 26 | impl Default for Resolution { |
| 27 | fn default() -> Self { | 27 | fn default() -> Self { |
| 28 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] | 28 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] |
| 29 | { | 29 | { |
| 30 | Self::TwelveBit | 30 | Self::TwelveBit |
| 31 | } | 31 | } |
| @@ -46,7 +46,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res { | |||
| 46 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, | 46 | Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, |
| 47 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, | 47 | Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, |
| 48 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, | 48 | Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, |
| 49 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] | 49 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] |
| 50 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, | 50 | Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, |
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| @@ -65,7 +65,7 @@ impl Resolution { | |||
| 65 | Resolution::TwelveBit => (1 << 12) - 1, | 65 | Resolution::TwelveBit => (1 << 12) - 1, |
| 66 | Resolution::TenBit => (1 << 10) - 1, | 66 | Resolution::TenBit => (1 << 10) - 1, |
| 67 | Resolution::EightBit => (1 << 8) - 1, | 67 | Resolution::EightBit => (1 << 8) - 1, |
| 68 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] | 68 | #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))] |
| 69 | Resolution::SixBit => (1 << 6) - 1, | 69 | Resolution::SixBit => (1 << 6) - 1, |
| 70 | } | 70 | } |
| 71 | } | 71 | } |
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!( | |||
| 83 | ) | 83 | ) |
| 84 | ); | 84 | ); |
| 85 | 85 | ||
| 86 | #[cfg(adc_g0)] | 86 | #[cfg(any(adc_l0, adc_g0))] |
| 87 | impl_sample_time!( | 87 | impl_sample_time!( |
| 88 | "1.5", | 88 | "1.5", |
| 89 | Cycles1_5, | 89 | Cycles1_5, |
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 852b027df..37115dfab 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs | |||
| @@ -4,6 +4,8 @@ use core::task::Poll; | |||
| 4 | 4 | ||
| 5 | use embassy_hal_internal::into_ref; | 5 | use embassy_hal_internal::into_ref; |
| 6 | use embedded_hal_02::blocking::delay::DelayUs; | 6 | use embedded_hal_02::blocking::delay::DelayUs; |
| 7 | #[cfg(adc_l0)] | ||
| 8 | use stm32_metapac::adc::vals::Ckmode; | ||
| 7 | 9 | ||
| 8 | use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; | 10 | use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; |
| 9 | use crate::interrupt::typelevel::Interrupt; | 11 | use crate::interrupt::typelevel::Interrupt; |
| @@ -30,8 +32,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 30 | } | 32 | } |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 35 | #[cfg(not(adc_l0))] | ||
| 33 | pub struct Vbat; | 36 | pub struct Vbat; |
| 37 | |||
| 38 | #[cfg(not(adc_l0))] | ||
| 34 | impl AdcPin<ADC> for Vbat {} | 39 | impl AdcPin<ADC> for Vbat {} |
| 40 | |||
| 41 | #[cfg(not(adc_l0))] | ||
| 35 | impl super::sealed::AdcPin<ADC> for Vbat { | 42 | impl super::sealed::AdcPin<ADC> for Vbat { |
| 36 | fn channel(&self) -> u8 { | 43 | fn channel(&self) -> u8 { |
| 37 | 18 | 44 | 18 |
| @@ -69,9 +76,18 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 69 | // tstab = 14 * 1/fadc | 76 | // tstab = 14 * 1/fadc |
| 70 | delay.delay_us(1); | 77 | delay.delay_us(1); |
| 71 | 78 | ||
| 79 | // set default PCKL/2 on L0s because HSI is disabled in the default clock config | ||
| 80 | #[cfg(adc_l0)] | ||
| 81 | T::regs().cfgr2().modify(|reg| reg.set_ckmode(Ckmode::PCLK_DIV2)); | ||
| 82 | |||
| 72 | // A.7.1 ADC calibration code example | 83 | // A.7.1 ADC calibration code example |
| 73 | T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); | 84 | T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); |
| 74 | T::regs().cr().modify(|reg| reg.set_adcal(true)); | 85 | T::regs().cr().modify(|reg| reg.set_adcal(true)); |
| 86 | |||
| 87 | #[cfg(adc_l0)] | ||
| 88 | while !T::regs().isr().read().eocal() {} | ||
| 89 | |||
| 90 | #[cfg(not(adc_l0))] | ||
| 75 | while T::regs().cr().read().adcal() {} | 91 | while T::regs().cr().read().adcal() {} |
| 76 | 92 | ||
| 77 | // A.7.2 ADC enable sequence code example | 93 | // A.7.2 ADC enable sequence code example |
| @@ -97,6 +113,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 97 | } | 113 | } |
| 98 | } | 114 | } |
| 99 | 115 | ||
| 116 | #[cfg(not(adc_l0))] | ||
| 100 | pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { | 117 | pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { |
| 101 | // SMP must be ≥ 56 ADC clock cycles when using HSI14. | 118 | // SMP must be ≥ 56 ADC clock cycles when using HSI14. |
| 102 | // | 119 | // |
| @@ -133,6 +150,12 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 133 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | 150 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); |
| 134 | } | 151 | } |
| 135 | 152 | ||
| 153 | #[cfg(adc_l0)] | ||
| 154 | pub fn set_ckmode(&mut self, ckmode: Ckmode) { | ||
| 155 | // set ADC clock mode | ||
| 156 | T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode)); | ||
| 157 | } | ||
| 158 | |||
| 136 | pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | 159 | pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { |
| 137 | let channel = pin.channel(); | 160 | let channel = pin.channel(); |
| 138 | pin.set_as_analog(); | 161 | pin.set_as_analog(); |
diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs new file mode 100644 index 000000000..adeaa208a --- /dev/null +++ b/examples/stm32l0/src/bin/adc.rs | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::adc::{Adc, SampleTime}; | ||
| 7 | use embassy_stm32::peripherals::ADC; | ||
| 8 | use embassy_stm32::{adc, bind_interrupts}; | ||
| 9 | use embassy_time::{Delay, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | ADC1_COMP => adc::InterruptHandler<ADC>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let p = embassy_stm32::init(Default::default()); | ||
| 19 | info!("Hello World!"); | ||
| 20 | |||
| 21 | let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); | ||
| 22 | adc.set_sample_time(SampleTime::Cycles79_5); | ||
| 23 | let mut pin = p.PA1; | ||
| 24 | |||
| 25 | let mut vrefint = adc.enable_vref(&mut Delay); | ||
| 26 | let vrefint_sample = adc.read(&mut vrefint).await; | ||
| 27 | let convert_to_millivolts = |sample| { | ||
| 28 | // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf | ||
| 29 | // 6.3.3 Embedded internal reference voltage | ||
| 30 | const VREFINT_MV: u32 = 1224; // mV | ||
| 31 | |||
| 32 | (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16 | ||
| 33 | }; | ||
| 34 | |||
| 35 | loop { | ||
| 36 | let v = adc.read(&mut pin).await; | ||
| 37 | info!("--> {} - {} mV", v, convert_to_millivolts(v)); | ||
| 38 | Timer::after_millis(100).await; | ||
| 39 | } | ||
| 40 | } | ||
