aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-02-13 11:44:59 +0000
committerGitHub <[email protected]>2022-02-13 11:44:59 +0000
commiteb922c4655db4b22acf808855e3bc003d3b8ba89 (patch)
tree996cc09254953299cb310285bf05195774be5441
parentb74ccf2d348e9bba1e201e196381f772197e3257 (diff)
parent7a3d34c1ed3db330c6db55b81cd535747181c3cb (diff)
Merge #608
608: stm32f4: add adc + example r=Dirbaio a=ain101 Example tested on stm32f407vg Discovery Board. minimal adc: no vref, dma, complex sequence Co-authored-by: Frederik <[email protected]>
-rw-r--r--embassy-stm32/src/adc/v2.rs239
-rw-r--r--examples/stm32f4/src/bin/adc.rs26
2 files changed, 265 insertions, 0 deletions
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 8b1378917..e79680493 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1 +1,240 @@
1use crate::adc::{AdcPin, Instance};
2use core::marker::PhantomData;
3use embassy::util::Unborrow;
4use embassy_hal_common::unborrow;
5use embedded_hal_02::blocking::delay::DelayUs;
1 6
7pub const VDDA_CALIB_MV: u32 = 3000;
8
9#[cfg(not(rcc_f4))]
10unsafe fn enable() {
11 todo!()
12}
13
14#[cfg(rcc_f4)]
15unsafe fn enable() {
16 // TODO do not enable all adc clocks if not needed
17 crate::pac::RCC.apb2enr().modify(|w| w.set_adc1en(true));
18 crate::pac::RCC.apb2enr().modify(|w| w.set_adc2en(true));
19 crate::pac::RCC.apb2enr().modify(|w| w.set_adc3en(true));
20}
21
22pub enum Resolution {
23 TwelveBit,
24 TenBit,
25 EightBit,
26 SixBit,
27}
28
29impl Default for Resolution {
30 fn default() -> Self {
31 Self::TwelveBit
32 }
33}
34
35impl Resolution {
36 fn res(&self) -> crate::pac::adc::vals::Res {
37 match self {
38 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
39 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
40 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
41 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
42 }
43 }
44
45 fn to_max_count(&self) -> u32 {
46 match self {
47 Resolution::TwelveBit => (1 << 12) - 1,
48 Resolution::TenBit => (1 << 10) - 1,
49 Resolution::EightBit => (1 << 8) - 1,
50 Resolution::SixBit => (1 << 6) - 1,
51 }
52 }
53}
54
55pub struct Vref;
56impl<T: Instance> AdcPin<T> for Vref {}
57impl<T: Instance> super::sealed::AdcPin<T> for Vref {
58 fn channel(&self) -> u8 {
59 17
60 }
61}
62
63pub struct Temperature;
64impl<T: Instance> AdcPin<T> for Temperature {}
65impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
66 fn channel(&self) -> u8 {
67 16
68 }
69}
70
71pub struct Vbat;
72impl<T: Instance> AdcPin<T> for Vbat {}
73impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
74 fn channel(&self) -> u8 {
75 18
76 }
77}
78
79/// ADC sample time
80///
81/// The default setting is 3 ADC clock cycles.
82#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
83pub enum SampleTime {
84 Cycles3 = 0b000,
85 Cycles15 = 0b001,
86 Cycles28 = 0b010,
87 Cycles56 = 0b011,
88 Cycles85 = 0b100,
89 Cycles112 = 0b101,
90 Cycles144 = 0b110,
91 Cycles480 = 0b111,
92}
93
94impl SampleTime {
95 pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::Smp {
96 match self {
97 SampleTime::Cycles3 => crate::pac::adc::vals::Smp::CYCLES3,
98 SampleTime::Cycles15 => crate::pac::adc::vals::Smp::CYCLES15,
99 SampleTime::Cycles28 => crate::pac::adc::vals::Smp::CYCLES28,
100 SampleTime::Cycles56 => crate::pac::adc::vals::Smp::CYCLES56,
101 SampleTime::Cycles85 => crate::pac::adc::vals::Smp::CYCLES84,
102 SampleTime::Cycles112 => crate::pac::adc::vals::Smp::CYCLES112,
103 SampleTime::Cycles144 => crate::pac::adc::vals::Smp::CYCLES144,
104 SampleTime::Cycles480 => crate::pac::adc::vals::Smp::CYCLES480,
105 }
106 }
107}
108
109impl Default for SampleTime {
110 fn default() -> Self {
111 Self::Cycles3
112 }
113}
114
115pub struct Adc<'d, T: Instance> {
116 sample_time: SampleTime,
117 calibrated_vdda: u32,
118 resolution: Resolution,
119 phantom: PhantomData<&'d mut T>,
120}
121
122impl<'d, T> Adc<'d, T>
123where
124 T: Instance,
125{
126 pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
127 unborrow!(_peri);
128 unsafe {
129 enable();
130 // disable before config is set
131 T::regs().cr2().modify(|reg| {
132 reg.set_adon(crate::pac::adc::vals::Adon::DISABLED);
133 });
134 }
135
136 delay.delay_us(20); // TODO?
137
138 Self {
139 sample_time: Default::default(),
140 resolution: Resolution::default(),
141 calibrated_vdda: VDDA_CALIB_MV,
142 phantom: PhantomData,
143 }
144 }
145
146 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
147 self.sample_time = sample_time;
148 }
149
150 pub fn set_resolution(&mut self, resolution: Resolution) {
151 self.resolution = resolution;
152 }
153
154 /// Convert a measurement to millivolts
155 pub fn to_millivolts(&self, sample: u16) -> u16 {
156 ((u32::from(sample) * self.calibrated_vdda) / self.resolution.to_max_count()) as u16
157 }
158
159 /// Perform a single conversion.
160 fn convert(&mut self) -> u16 {
161 unsafe {
162 // clear end of conversion flag
163 T::regs().sr().modify(|reg| {
164 reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE);
165 });
166
167 // Start conversion
168 T::regs().cr2().modify(|reg| {
169 reg.set_swstart(true);
170 });
171
172 while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED {
173 // spin //wait for actual start
174 }
175 while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE {
176 // spin //wait for finish
177 }
178
179 T::regs().dr().read().0 as u16
180 }
181 }
182
183 pub fn read<P>(&mut self, pin: &mut P) -> u16
184 where
185 P: AdcPin<T>,
186 P: crate::gpio::sealed::Pin,
187 {
188 unsafe {
189 // dissable ADC
190 T::regs().cr2().modify(|reg| {
191 reg.set_swstart(false);
192 });
193 T::regs().cr2().modify(|reg| {
194 reg.set_adon(crate::pac::adc::vals::Adon::DISABLED);
195 });
196
197 pin.set_as_analog();
198
199 // Configure ADC
200 T::regs()
201 .cr1()
202 .modify(|reg| reg.set_res(self.resolution.res()));
203
204 // Select channel
205 T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
206
207 // Configure channel
208 Self::set_channel_sample_time(pin.channel(), self.sample_time);
209
210 // enable adc
211 T::regs().cr2().modify(|reg| {
212 reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
213 });
214
215 let val = self.convert();
216
217 // dissable ADC
218 T::regs().cr2().modify(|reg| {
219 reg.set_swstart(false);
220 });
221 T::regs().cr2().modify(|reg| {
222 reg.set_adon(crate::pac::adc::vals::Adon::DISABLED);
223 });
224
225 val
226 }
227 }
228
229 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
230 if ch <= 9 {
231 T::regs()
232 .smpr2()
233 .modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
234 } else {
235 T::regs()
236 .smpr1()
237 .modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
238 }
239 }
240}
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
new file mode 100644
index 000000000..0a6ddbbca
--- /dev/null
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -0,0 +1,26 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7
8use embassy::executor::Spawner;
9use embassy::time::{Delay, Duration, Timer};
10use embassy_stm32::adc::Adc;
11use embassy_stm32::Peripherals;
12use example_common::*;
13
14#[embassy::main]
15async fn main(_spawner: Spawner, p: Peripherals) {
16 info!("Hello World!");
17
18 let mut adc = Adc::new(p.ADC1, &mut Delay);
19 let mut pin = p.PC1;
20
21 loop {
22 let v = adc.read(&mut pin);
23 info!("--> {} - {} mV", v, adc.to_millivolts(v));
24 Timer::after(Duration::from_millis(100)).await;
25 }
26}