aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/adc/mod.rs11
-rw-r--r--embassy-stm32/src/adc/resolution.rs8
-rw-r--r--embassy-stm32/src/adc/sample_time.rs2
-rw-r--r--embassy-stm32/src/adc/v1.rs170
-rw-r--r--examples/stm32f0/src/bin/adc.rs35
5 files changed, 214 insertions, 12 deletions
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index ec49dace7..56ecd63ca 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -7,21 +7,18 @@
7#[cfg_attr(adc_v4, path = "v4.rs")] 7#[cfg_attr(adc_v4, path = "v4.rs")]
8mod _version; 8mod _version;
9 9
10#[cfg(not(any(adc_f1, adc_v1)))] 10#[cfg(not(adc_f1))]
11mod resolution; 11mod resolution;
12#[cfg(not(adc_v1))]
13mod sample_time; 12mod sample_time;
14 13
15#[allow(unused)] 14#[allow(unused)]
16pub use _version::*; 15pub use _version::*;
17#[cfg(not(any(adc_f1, adc_v1)))] 16#[cfg(not(adc_f1))]
18pub use resolution::Resolution; 17pub use resolution::Resolution;
19#[cfg(not(adc_v1))]
20pub use sample_time::SampleTime; 18pub use sample_time::SampleTime;
21 19
22use crate::peripherals; 20use crate::peripherals;
23 21
24#[cfg(not(adc_v1))]
25pub struct Adc<'d, T: Instance> { 22pub struct Adc<'d, T: Instance> {
26 #[allow(unused)] 23 #[allow(unused)]
27 adc: crate::PeripheralRef<'d, T>, 24 adc: crate::PeripheralRef<'d, T>,
@@ -44,9 +41,9 @@ pub(crate) mod sealed {
44 } 41 }
45} 42}
46 43
47#[cfg(not(any(adc_f1, adc_v2, adc_v4)))] 44#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))]
48pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} 45pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
49#[cfg(any(adc_f1, adc_v2, adc_v4))] 46#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))]
50pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} 47pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
51 48
52pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 49pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs
index 62b52a46c..67fb9b8c0 100644
--- a/embassy-stm32/src/adc/resolution.rs
+++ b/embassy-stm32/src/adc/resolution.rs
@@ -1,4 +1,4 @@
1#[cfg(any(adc_v2, adc_v3, adc_g0))] 1#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
2#[derive(Clone, Copy, Debug, Eq, PartialEq)] 2#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3pub enum Resolution { 3pub enum Resolution {
4 TwelveBit, 4 TwelveBit,
@@ -19,7 +19,7 @@ pub enum Resolution {
19 19
20impl Default for Resolution { 20impl Default for Resolution {
21 fn default() -> Self { 21 fn default() -> Self {
22 #[cfg(any(adc_v2, adc_v3, adc_g0))] 22 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
23 { 23 {
24 Self::TwelveBit 24 Self::TwelveBit
25 } 25 }
@@ -40,7 +40,7 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
40 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, 40 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
41 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, 41 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
42 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, 42 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
43 #[cfg(any(adc_v2, adc_v3, adc_g0))] 43 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
44 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, 44 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
45 } 45 }
46 } 46 }
@@ -56,7 +56,7 @@ impl Resolution {
56 Resolution::TwelveBit => (1 << 12) - 1, 56 Resolution::TwelveBit => (1 << 12) - 1,
57 Resolution::TenBit => (1 << 10) - 1, 57 Resolution::TenBit => (1 << 10) - 1,
58 Resolution::EightBit => (1 << 8) - 1, 58 Resolution::EightBit => (1 << 8) - 1,
59 #[cfg(any(adc_v2, adc_v3, adc_g0))] 59 #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))]
60 Resolution::SixBit => (1 << 6) - 1, 60 Resolution::SixBit => (1 << 6) - 1,
61 } 61 }
62 } 62 }
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index bc5fb1d6f..0faa1e3c0 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -25,7 +25,7 @@ macro_rules! impl_sample_time {
25 }; 25 };
26} 26}
27 27
28#[cfg(adc_f1)] 28#[cfg(any(adc_f1, adc_v1))]
29impl_sample_time!( 29impl_sample_time!(
30 "1.5", 30 "1.5",
31 Cycles1_5, 31 Cycles1_5,
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 8b1378917..82a8c3efb 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -1 +1,171 @@
1use embassy_hal_common::into_ref;
2use embedded_hal_02::blocking::delay::DelayUs;
1 3
4use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
5use crate::peripherals::ADC;
6use crate::Peripheral;
7
8pub const VDDA_CALIB_MV: u32 = 3300;
9pub const VREF_INT: u32 = 1230;
10
11pub struct Vbat;
12impl InternalChannel<ADC> for Vbat {}
13impl super::sealed::InternalChannel<ADC> for Vbat {
14 fn channel(&self) -> u8 {
15 18
16 }
17}
18
19pub struct Vref;
20impl InternalChannel<ADC> for Vref {}
21impl super::sealed::InternalChannel<ADC> for Vref {
22 fn channel(&self) -> u8 {
23 17
24 }
25}
26
27pub struct Temperature;
28impl InternalChannel<ADC> for Temperature {}
29impl super::sealed::InternalChannel<ADC> for Temperature {
30 fn channel(&self) -> u8 {
31 16
32 }
33}
34
35impl<'d, T: Instance> Adc<'d, T> {
36 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
37 into_ref!(adc);
38 T::enable();
39 T::reset();
40
41 // Delay 1μs when using HSI14 as the ADC clock.
42 //
43 // Table 57. ADC characteristics
44 // tstab = 14 * 1/fadc
45 delay.delay_us(1);
46
47 let s = Self {
48 adc,
49 sample_time: Default::default(),
50 };
51 s.calibrate();
52 s
53 }
54
55 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
56 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
57 //
58 // 6.3.20 Vbat monitoring characteristics
59 // ts_vbat ≥ 4μs
60 unsafe {
61 T::regs().ccr().modify(|reg| reg.set_vbaten(true));
62 }
63 Vbat
64 }
65
66 pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
67 // Table 28. Embedded internal reference voltage
68 // tstart = 10μs
69 unsafe {
70 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
71 }
72 delay.delay_us(10);
73 Vref
74 }
75
76 pub fn enable_temperature(&self, delay: &mut impl DelayUs<u32>) -> Temperature {
77 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
78 //
79 // 6.3.19 Temperature sensor characteristics
80 // tstart ≤ 10μs
81 // ts_temp ≥ 4μs
82 unsafe {
83 T::regs().ccr().modify(|reg| reg.set_tsen(true));
84 }
85 delay.delay_us(10);
86 Temperature
87 }
88
89 fn calibrate(&self) {
90 unsafe {
91 // A.7.1 ADC calibration code example
92 if T::regs().cr().read().aden() {
93 T::regs().cr().modify(|reg| reg.set_addis(true));
94 }
95 while T::regs().cr().read().aden() {
96 // spin
97 }
98 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
99 T::regs().cr().modify(|reg| reg.set_adcal(true));
100 while T::regs().cr().read().adcal() {
101 // spin
102 }
103 }
104 }
105
106 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
107 self.sample_time = sample_time;
108 }
109
110 pub fn set_resolution(&mut self, resolution: Resolution) {
111 unsafe {
112 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
113 }
114 }
115
116 pub fn read<P>(&mut self, pin: &mut P) -> u16
117 where
118 P: AdcPin<T> + crate::gpio::sealed::Pin,
119 {
120 let channel = pin.channel();
121 unsafe {
122 pin.set_as_analog();
123 self.read_channel(channel)
124 }
125 }
126
127 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
128 let channel = channel.channel();
129 unsafe { self.read_channel(channel) }
130 }
131
132 unsafe fn read_channel(&mut self, channel: u8) -> u16 {
133 // A.7.2 ADC enable sequence code example
134 if T::regs().isr().read().adrdy() {
135 T::regs().isr().modify(|reg| reg.set_adrdy(true));
136 }
137 T::regs().cr().modify(|reg| reg.set_aden(true));
138 while !T::regs().isr().read().adrdy() {
139 // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
140 // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
141 // ADEN bit until the ADRDY flag goes high.
142 T::regs().cr().modify(|reg| reg.set_aden(true));
143 }
144
145 T::regs().isr().modify(|reg| {
146 reg.set_eoc(true);
147 reg.set_eosmp(true);
148 });
149
150 // A.7.5 Single conversion sequence code example - Software trigger
151 T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
152 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
153 T::regs().cr().modify(|reg| reg.set_adstart(true));
154 while !T::regs().isr().read().eoc() {
155 // spin
156 }
157 let value = T::regs().dr().read().0 as u16;
158
159 // A.7.3 ADC disable code example
160 T::regs().cr().modify(|reg| reg.set_adstp(true));
161 while T::regs().cr().read().adstp() {
162 // spin
163 }
164 T::regs().cr().modify(|reg| reg.set_addis(true));
165 while T::regs().cr().read().aden() {
166 // spin
167 }
168
169 value
170 }
171}
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
new file mode 100644
index 000000000..8ed9f98f8
--- /dev/null
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_time::{Delay, Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let mut adc = Adc::new(p.ADC, &mut Delay);
17 adc.set_sample_time(SampleTime::Cycles71_5);
18 let mut pin = p.PA1;
19
20 let mut vrefint = adc.enable_vref(&mut Delay);
21 let vrefint_sample = adc.read_internal(&mut vrefint);
22 let convert_to_millivolts = |sample| {
23 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
24 // 6.3.4 Embedded reference voltage
25 const VREFINT_MV: u32 = 1230; // mV
26
27 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
28 };
29
30 loop {
31 let v = adc.read(&mut pin);
32 info!("--> {} - {} mV", v, convert_to_millivolts(v));
33 Timer::after(Duration::from_millis(100)).await;
34 }
35}