aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew W. Samsonoff <[email protected]>2022-09-13 23:08:03 -0400
committerGrant Miller <[email protected]>2023-04-05 14:34:24 -0500
commit5d9ae3dbdbfe8ba6e1008cd2eadc09743cfc6284 (patch)
tree7c3be1449c664af291cb7eebcaf5372d10745f5e
parenteed2b123253380d67f76bf1d0272688e8053bc9a (diff)
Add implementation of STM32 v1 ADC
-rw-r--r--embassy-stm32/src/adc/v1.rs277
1 files changed, 277 insertions, 0 deletions
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 8b1378917..923a1d97a 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -1 +1,278 @@
1use core::marker::PhantomData;
1 2
3use embassy_hal_common::into_ref;
4use embedded_hal_02::blocking::delay::DelayUs;
5
6use crate::adc::{AdcPin, Instance};
7use crate::{pac, Peripheral};
8
9pub const VDDA_CALIB_MV: u32 = 3300;
10pub const VREF_INT: u32 = 1230;
11
12fn enable() {
13 critical_section::with(|_| unsafe {
14 crate::pac::RCC.apb2enr().modify(|reg| reg.set_adcen(true));
15 });
16}
17
18pub enum Resolution {
19 TwelveBit,
20 TenBit,
21 EightBit,
22 SixBit,
23}
24
25impl Default for Resolution {
26 fn default() -> Self {
27 Self::TwelveBit
28 }
29}
30
31impl Resolution {
32 fn res(&self) -> pac::adc::vals::Res {
33 match self {
34 Resolution::TwelveBit => pac::adc::vals::Res::TWELVEBIT,
35 Resolution::TenBit => pac::adc::vals::Res::TENBIT,
36 Resolution::EightBit => pac::adc::vals::Res::EIGHTBIT,
37 Resolution::SixBit => pac::adc::vals::Res::SIXBIT,
38 }
39 }
40
41 pub fn to_max_count(&self) -> u32 {
42 match self {
43 Resolution::TwelveBit => (1 << 12) - 1,
44 Resolution::TenBit => (1 << 10) - 1,
45 Resolution::EightBit => (1 << 8) - 1,
46 Resolution::SixBit => (1 << 6) - 1,
47 }
48 }
49}
50
51pub struct Vbat;
52impl<T: Instance> AdcPin<T> for Vbat {}
53impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
54 fn channel(&self) -> u8 {
55 18
56 }
57}
58
59pub struct Vref;
60impl<T: Instance> AdcPin<T> for Vref {}
61impl<T: Instance> super::sealed::AdcPin<T> for Vref {
62 fn channel(&self) -> u8 {
63 17
64 }
65}
66
67pub struct Temperature;
68impl<T: Instance> AdcPin<T> for Temperature {}
69impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
70 fn channel(&self) -> u8 {
71 16
72 }
73}
74
75mod sample_time {
76 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
77 pub enum SampleTime {
78 /// 1.5 ADC clock cycles
79 Cycles1_5 = 0b000,
80
81 /// 7.5 ADC clock cycles
82 Cycles7_5 = 0b001,
83
84 /// 13.5 ADC clock cycles
85 Cycles13_5 = 0b010,
86
87 /// 28.5 ADC clock cycles
88 Cycles28_5 = 0b011,
89
90 /// 41.5 ADC clock cycles
91 Cycles41_5 = 0b100,
92
93 /// 55.5 ADC clock cycles
94 Cycles55_5 = 0b101,
95
96 /// 71.5 ADC clock cycles
97 Cycles71_5 = 0b110,
98
99 /// 239.5 ADC clock cycles
100 Cycles239_5 = 0b111,
101 }
102
103 impl SampleTime {
104 pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::Smp {
105 match self {
106 SampleTime::Cycles1_5 => crate::pac::adc::vals::Smp::CYCLES1_5,
107 SampleTime::Cycles7_5 => crate::pac::adc::vals::Smp::CYCLES7_5,
108 SampleTime::Cycles13_5 => crate::pac::adc::vals::Smp::CYCLES13_5,
109 SampleTime::Cycles28_5 => crate::pac::adc::vals::Smp::CYCLES28_5,
110 SampleTime::Cycles41_5 => crate::pac::adc::vals::Smp::CYCLES41_5,
111 SampleTime::Cycles55_5 => crate::pac::adc::vals::Smp::CYCLES55_5,
112 SampleTime::Cycles71_5 => crate::pac::adc::vals::Smp::CYCLES71_5,
113 SampleTime::Cycles239_5 => crate::pac::adc::vals::Smp::CYCLES239_5,
114 }
115 }
116 }
117
118 impl Default for SampleTime {
119 fn default() -> Self {
120 Self::Cycles1_5
121 }
122 }
123}
124
125pub use sample_time::SampleTime;
126
127pub struct Adc<'d, T: Instance> {
128 sample_time: SampleTime,
129 vref_mv: u32,
130 resolution: Resolution,
131 phantom: PhantomData<&'d mut T>,
132}
133
134impl<'d, T: Instance> Adc<'d, T> {
135 pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
136 into_ref!(_peri);
137 enable();
138
139 // Delay 1μs when using HSI14 as the ADC clock.
140 //
141 // Table 57. ADC characteristics
142 // tstab = 14 * 1/fadc
143 delay.delay_us(1);
144
145 let s = Self {
146 sample_time: Default::default(),
147 vref_mv: VDDA_CALIB_MV,
148 resolution: Resolution::default(),
149 phantom: PhantomData,
150 };
151 s.calibrate();
152 s
153 }
154
155 pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
156 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
157 //
158 // 6.3.20 Vbat monitoring characteristics
159 // ts_vbat ≥ 4μs
160 unsafe {
161 T::regs().ccr().modify(|reg| reg.set_vbaten(true));
162 }
163 Vbat
164 }
165
166 pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
167 // Table 28. Embedded internal reference voltage
168 // tstart = 10μs
169 unsafe {
170 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
171 }
172 delay.delay_us(10);
173 Vref
174 }
175
176 pub fn enable_temperature(&self, delay: &mut impl DelayUs<u32>) -> Temperature {
177 // SMP must be ≥ 56 ADC clock cycles when using HSI14.
178 //
179 // 6.3.19 Temperature sensor characteristics
180 // tstart ≤ 10μs
181 // ts_temp ≥ 4μs
182 unsafe {
183 T::regs().ccr().modify(|reg| reg.set_tsen(true));
184 }
185 delay.delay_us(10);
186 Temperature
187 }
188
189 fn calibrate(&self) {
190 unsafe {
191 // A.7.1 ADC calibration code example
192 if T::regs().cr().read().aden() {
193 T::regs().cr().modify(|reg| reg.set_addis(true));
194 }
195 while T::regs().cr().read().aden() {
196 // spin
197 }
198 T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
199 T::regs().cr().modify(|reg| reg.set_adcal(true));
200 while T::regs().cr().read().adcal() {
201 // spin
202 }
203 }
204 }
205
206 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
207 self.sample_time = sample_time;
208 }
209
210 pub fn set_vref_mv(&mut self, vref_mv: u32) {
211 self.vref_mv = vref_mv;
212 }
213
214 pub fn set_resolution(&mut self, resolution: Resolution) {
215 self.resolution = resolution;
216 }
217
218 pub fn to_millivolts(&self, sample: u16) -> u16 {
219 ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
220 }
221
222 fn convert(&mut self) -> u16 {
223 unsafe {
224 T::regs().isr().modify(|reg| {
225 reg.set_eoc(true);
226 reg.set_eosmp(true);
227 });
228
229 // A.7.5 Single conversion sequence code example - Software trigger
230 T::regs().cr().modify(|reg| reg.set_adstart(true));
231 while !T::regs().isr().read().eoc() {
232 // spin
233 }
234
235 T::regs().dr().read().0 as u16
236 }
237 }
238
239 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
240 unsafe {
241 // A.7.2 ADC enable sequence code example
242 if T::regs().isr().read().adrdy() {
243 T::regs().isr().modify(|reg| reg.set_adrdy(true));
244 }
245 T::regs().cr().modify(|reg| reg.set_aden(true));
246 while !T::regs().isr().read().adrdy() {
247 // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
248 // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
249 // ADEN bit until the ADRDY flag goes high.
250 T::regs().cr().modify(|reg| reg.set_aden(true));
251 }
252
253 T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res()));
254 Self::set_channel_sample_time(pin.channel(), self.sample_time);
255 T::regs()
256 .chselr()
257 .write(|reg| reg.set_chselx(pin.channel() as usize, true));
258
259 let value = self.convert();
260
261 // A.7.3 ADC disable code example
262 T::regs().cr().modify(|reg| reg.set_adstp(true));
263 while T::regs().cr().read().adstp() {
264 // spin
265 }
266 T::regs().cr().modify(|reg| reg.set_addis(true));
267 while T::regs().cr().read().aden() {
268 // spin
269 }
270
271 value
272 }
273 }
274
275 unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
276 T::regs().smpr().modify(|reg| reg.set_smp(sample_time.sample_time()));
277 }
278}