aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/adc
diff options
context:
space:
mode:
authorklownfish <[email protected]>2024-09-25 01:01:19 +0200
committerklownfish <[email protected]>2024-09-25 01:01:19 +0200
commit8c1b4faae1bd39594e2c331fa4bf9eea3ad22c9e (patch)
treea989fb690c365ae791551c7faaece0c28515aa59 /embassy-stm32/src/adc
parent60347976b2e56eb8484e10d4aec5fa12534457f7 (diff)
resuse adc v4 for u5
Diffstat (limited to 'embassy-stm32/src/adc')
-rw-r--r--embassy-stm32/src/adc/mod.rs3
-rw-r--r--embassy-stm32/src/adc/u5.rs350
-rw-r--r--embassy-stm32/src/adc/v4.rs19
3 files changed, 19 insertions, 353 deletions
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 80c942816..3cf2ca72e 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -12,9 +12,8 @@
12#[cfg_attr(adc_l0, path = "v1.rs")] 12#[cfg_attr(adc_l0, path = "v1.rs")]
13#[cfg_attr(adc_v2, path = "v2.rs")] 13#[cfg_attr(adc_v2, path = "v2.rs")]
14#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] 14#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")]
15#[cfg_attr(adc_v4, path = "v4.rs")] 15#[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")]
16#[cfg_attr(adc_g4, path = "g4.rs")] 16#[cfg_attr(adc_g4, path = "g4.rs")]
17#[cfg_attr(adc_u5, path = "u5.rs")]
18mod _version; 17mod _version;
19 18
20use core::marker::PhantomData; 19use core::marker::PhantomData;
diff --git a/embassy-stm32/src/adc/u5.rs b/embassy-stm32/src/adc/u5.rs
deleted file mode 100644
index 314cb02e2..000000000
--- a/embassy-stm32/src/adc/u5.rs
+++ /dev/null
@@ -1,350 +0,0 @@
1#[allow(unused)]
2use pac::adc::vals::{Difsel, Exten, Pcsel};
3use pac::adccommon::vals::Presc;
4use pac::PWR;
5
6use super::{
7 blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime, SealedAdcChannel
8};
9use crate::time::Hertz;
10use crate::{pac, rcc, Peripheral};
11
12const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
13
14const VREF_CHANNEL: u8 = 0;
15const VBAT_CHANNEL: u8 = 18;
16const TEMP_CHANNEL: u8 = 19;
17
18/// Default VREF voltage used for sample conversion to millivolts.
19pub const VREF_DEFAULT_MV: u32 = 3300;
20/// VREF voltage used for factory calibration of VREFINTCAL register.
21pub const VREF_CALIB_MV: u32 = 3300;
22
23
24// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
25/// Internal voltage reference channel.
26pub struct VrefInt;
27impl<T: Instance> AdcChannel<T> for VrefInt {}
28impl<T: Instance> SealedAdcChannel<T> for VrefInt {
29 fn channel(&self) -> u8 {
30 VREF_CHANNEL
31 }
32}
33
34/// Internal temperature channel.
35pub struct Temperature;
36impl<T: Instance> AdcChannel<T> for Temperature {}
37impl<T: Instance> SealedAdcChannel<T> for Temperature {
38 fn channel(&self) -> u8 {
39 TEMP_CHANNEL
40 }
41}
42
43/// Internal battery voltage channel.
44pub struct Vbat;
45impl<T: Instance> AdcChannel<T> for Vbat {}
46impl<T: Instance> SealedAdcChannel<T> for Vbat {
47 fn channel(&self) -> u8 {
48 VBAT_CHANNEL
49 }
50}
51
52// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
53// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
54#[allow(unused)]
55enum Prescaler {
56 NotDivided,
57 DividedBy2,
58 DividedBy4,
59 DividedBy6,
60 DividedBy8,
61 DividedBy10,
62 DividedBy12,
63 DividedBy16,
64 DividedBy32,
65 DividedBy64,
66 DividedBy128,
67 DividedBy256,
68}
69
70impl Prescaler {
71 fn from_ker_ck(frequency: Hertz) -> Self {
72 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
73 match raw_prescaler {
74 0 => Self::NotDivided,
75 1 => Self::DividedBy2,
76 2..=3 => Self::DividedBy4,
77 4..=5 => Self::DividedBy6,
78 6..=7 => Self::DividedBy8,
79 8..=9 => Self::DividedBy10,
80 10..=11 => Self::DividedBy12,
81 _ => unimplemented!(),
82 }
83 }
84
85 fn divisor(&self) -> u32 {
86 match self {
87 Prescaler::NotDivided => 1,
88 Prescaler::DividedBy2 => 2,
89 Prescaler::DividedBy4 => 4,
90 Prescaler::DividedBy6 => 6,
91 Prescaler::DividedBy8 => 8,
92 Prescaler::DividedBy10 => 10,
93 Prescaler::DividedBy12 => 12,
94 Prescaler::DividedBy16 => 16,
95 Prescaler::DividedBy32 => 32,
96 Prescaler::DividedBy64 => 64,
97 Prescaler::DividedBy128 => 128,
98 Prescaler::DividedBy256 => 256,
99 }
100 }
101
102 fn presc(&self) -> Presc {
103 match self {
104 Prescaler::NotDivided => Presc::DIV1,
105 Prescaler::DividedBy2 => Presc::DIV2,
106 Prescaler::DividedBy4 => Presc::DIV4,
107 Prescaler::DividedBy6 => Presc::DIV6,
108 Prescaler::DividedBy8 => Presc::DIV8,
109 Prescaler::DividedBy10 => Presc::DIV10,
110 Prescaler::DividedBy12 => Presc::DIV12,
111 Prescaler::DividedBy16 => Presc::DIV16,
112 Prescaler::DividedBy32 => Presc::DIV32,
113 Prescaler::DividedBy64 => Presc::DIV64,
114 Prescaler::DividedBy128 => Presc::DIV128,
115 Prescaler::DividedBy256 => Presc::DIV256,
116 }
117 }
118}
119
120/// Number of samples used for averaging.
121pub enum Averaging {
122 Disabled,
123 Samples2,
124 Samples4,
125 Samples8,
126 Samples16,
127 Samples32,
128 Samples64,
129 Samples128,
130 Samples256,
131 Samples512,
132 Samples1024,
133}
134
135impl<'d, T: Instance> Adc<'d, T> {
136 /// Create a new ADC driver.
137 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
138 embassy_hal_internal::into_ref!(adc);
139 rcc::enable_and_reset::<T>();
140 let prescaler = Prescaler::from_ker_ck(T::frequency());
141
142 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
143
144 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
145 info!("ADC frequency set to {} Hz", frequency.0);
146
147 if frequency > MAX_ADC_CLK_FREQ {
148 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
149 }
150
151 let mut s = Self {
152 adc,
153 sample_time: SampleTime::from_bits(0),
154 };
155
156 s.power_up();
157 s.configure_differential_inputs();
158
159 s.calibrate();
160 blocking_delay_us(1);
161
162 s.enable();
163 s.configure();
164
165 s
166 }
167
168 fn power_up(&mut self) {
169 T::regs().isr().modify(|reg| {
170 reg.set_ldordy(true);
171 });
172 T::regs().cr().modify(|reg| {
173 reg.set_deeppwd(false);
174 reg.set_advregen(true);
175 });
176 while !T::regs().isr().read().ldordy() { };
177
178 T::regs().isr().modify(|reg| {
179 reg.set_ldordy(true);
180 });
181 }
182
183 fn configure_differential_inputs(&mut self) {
184 T::regs().difsel().modify(|w| {
185 for n in 0..20 {
186 w.set_difsel(n, Difsel::SINGLEENDED);
187 }
188 });
189 }
190
191 fn calibrate(&mut self) {
192 T::regs().cr().modify(|w| {
193 w.set_adcallin(true);
194 w.set_aden(false)
195 });
196 T::regs().calfact().modify(|w| {
197 w.set_capture_coef(false);
198 w.set_latch_coef(false)
199 });
200
201 T::regs().cr().modify(|w| w.set_adcal(true));
202 while T::regs().cr().read().adcal() {}
203 }
204
205 fn enable(&mut self) {
206 T::regs().isr().write(|w| w.set_adrdy(true));
207 T::regs().cr().modify(|w| w.set_aden(true));
208 while !T::regs().isr().read().adrdy() {}
209 T::regs().isr().write(|w| w.set_adrdy(true));
210 }
211
212 fn configure(&mut self) {
213 // single conversion mode, software trigger
214 T::regs().cfgr().modify(|w| {
215 w.set_cont(false);
216 w.set_exten(Exten::DISABLED);
217 });
218 }
219
220 /// Enable reading the voltage reference internal channel.
221 pub fn enable_vrefint(&self) -> VrefInt {
222 T::common_regs().ccr().modify(|reg| {
223 reg.set_vrefen(true);
224 });
225
226 VrefInt {}
227 }
228
229 /// Enable reading the temperature internal channel.
230 pub fn enable_temperature(&self) -> Temperature {
231 T::common_regs().ccr().modify(|reg| {
232 reg.set_vsenseen(true);
233 });
234
235 Temperature {}
236 }
237
238 /// Enable reading the vbat internal channel.
239 pub fn enable_vbat(&self) -> Vbat {
240 T::common_regs().ccr().modify(|reg| {
241 reg.set_vbaten(true);
242 });
243
244 Vbat {}
245 }
246
247 /// Set the ADC sample time.
248 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
249 self.sample_time = sample_time;
250 }
251
252 /// Get the ADC sample time.
253 pub fn sample_time(&self) -> SampleTime {
254 self.sample_time
255 }
256
257 /// Set the ADC resolution.
258 pub fn set_resolution(&mut self, resolution: Resolution) {
259 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
260 }
261
262 /// Set hardware averaging.
263 pub fn set_averaging(&mut self, averaging: Averaging) {
264 let (enable, samples, right_shift) = match averaging {
265 Averaging::Disabled => (false, 0, 0),
266 Averaging::Samples2 => (true, 1, 1),
267 Averaging::Samples4 => (true, 3, 2),
268 Averaging::Samples8 => (true, 7, 3),
269 Averaging::Samples16 => (true, 15, 4),
270 Averaging::Samples32 => (true, 31, 5),
271 Averaging::Samples64 => (true, 63, 6),
272 Averaging::Samples128 => (true, 127, 7),
273 Averaging::Samples256 => (true, 255, 8),
274 Averaging::Samples512 => (true, 511, 9),
275 Averaging::Samples1024 => (true, 1023, 10),
276 };
277
278 T::regs().cfgr2().modify(|reg| {
279 reg.set_rovse(enable);
280 reg.set_osvr(samples);
281 reg.set_ovss(right_shift);
282 })
283 }
284
285 /// Perform a single conversion.
286 fn convert(&mut self) -> u16 {
287 T::regs().isr().modify(|reg| {
288 reg.set_eos(true);
289 reg.set_eoc(true);
290 });
291
292 // Start conversion
293 T::regs().cr().modify(|reg| {
294 reg.set_adstart(true);
295 });
296
297 while !T::regs().isr().read().eos() {
298 // spin
299 }
300
301 T::regs().dr().read().0 as u16
302 }
303
304 /// Read an ADC channel.
305 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
306 self.read_channel(channel)
307 }
308
309 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
310 channel.setup();
311
312 let channel = channel.channel();
313
314 Self::set_channel_sample_time(channel, sample_time);
315
316 T::regs().cfgr2().modify(|w| w.set_lshift(0));
317 T::regs()
318 .pcsel()
319 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
320 }
321
322 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
323 Self::configure_channel(channel, self.sample_time);
324
325 T::regs().sqr1().modify(|reg| {
326 reg.set_sq(0, channel.channel());
327 reg.set_l(0);
328 });
329
330 self.convert()
331 }
332
333 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
334 let sample_time = sample_time.into();
335 if ch <= 9 {
336 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
337 } else {
338 T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
339 }
340 }
341
342 fn cancel_conversions() {
343 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
344 T::regs().cr().modify(|reg| {
345 reg.set_adstp(true);
346 });
347 while T::regs().cr().read().adstart() {}
348 }
349 }
350} \ No newline at end of file
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 63b5b58ea..d73bdb226 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -1,5 +1,9 @@
1#[allow(unused)] 1#[allow(unused)]
2use pac::adc::vals::{Adcaldif, Adstp, Boost, Difsel, Dmngt, Exten, Pcsel}; 2use pac::adc::vals::{Adstp, Difsel, Exten, Pcsel, Dmngt};
3
4#[cfg(not(stm32u5))]
5use pac::adc::vals::{Adcaldif, Boost};
6
3use pac::adccommon::vals::Presc; 7use pac::adccommon::vals::Presc;
4 8
5use super::{ 9use super::{
@@ -19,6 +23,9 @@ pub const VREF_CALIB_MV: u32 = 3300;
19const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); 23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
20#[cfg(stm32h7)] 24#[cfg(stm32h7)]
21const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
26#[cfg(stm32u5)]
27const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
28
22 29
23#[cfg(stm32g4)] 30#[cfg(stm32g4)]
24const VREF_CHANNEL: u8 = 18; 31const VREF_CHANNEL: u8 = 18;
@@ -31,8 +38,17 @@ const VREF_CHANNEL: u8 = 19;
31const TEMP_CHANNEL: u8 = 18; 38const TEMP_CHANNEL: u8 = 18;
32 39
33// TODO this should be 14 for H7a/b/35 40// TODO this should be 14 for H7a/b/35
41#[cfg(not(stm32u5))]
34const VBAT_CHANNEL: u8 = 17; 42const VBAT_CHANNEL: u8 = 17;
35 43
44
45#[cfg(stm32u5)]
46const VREF_CHANNEL: u8 = 0;
47#[cfg(stm32u5)]
48const TEMP_CHANNEL: u8 = 19;
49#[cfg(stm32u5)]
50const VBAT_CHANNEL: u8 = 18;
51
36// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 52// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
37/// Internal voltage reference channel. 53/// Internal voltage reference channel.
38pub struct VrefInt; 54pub struct VrefInt;
@@ -209,6 +225,7 @@ impl<'d, T: Instance> Adc<'d, T> {
209 225
210 fn calibrate(&mut self) { 226 fn calibrate(&mut self) {
211 T::regs().cr().modify(|w| { 227 T::regs().cr().modify(|w| {
228 #[cfg(not(adc_u5))]
212 w.set_adcaldif(Adcaldif::SINGLEENDED); 229 w.set_adcaldif(Adcaldif::SINGLEENDED);
213 w.set_adcallin(true); 230 w.set_adcallin(true);
214 }); 231 });