aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/adc/f1.rs21
-rw-r--r--embassy-stm32/src/adc/v2.rs23
-rw-r--r--embassy-stm32/src/adc/v3.rs39
-rw-r--r--embassy-stm32/src/adc/v4.rs14
-rw-r--r--examples/stm32f1/src/bin/adc.rs14
-rw-r--r--examples/stm32f4/src/bin/adc.rs31
-rw-r--r--examples/stm32f7/src/bin/adc.rs12
7 files changed, 50 insertions, 104 deletions
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 50d4f9bf9..c5b317ce9 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -86,7 +86,6 @@ pub use sample_time::SampleTime;
86 86
87pub struct Adc<'d, T: Instance> { 87pub struct Adc<'d, T: Instance> {
88 sample_time: SampleTime, 88 sample_time: SampleTime,
89 calibrated_vdda: u32,
90 phantom: PhantomData<&'d mut T>, 89 phantom: PhantomData<&'d mut T>,
91} 90}
92 91
@@ -122,7 +121,6 @@ impl<'d, T: Instance> Adc<'d, T> {
122 121
123 Self { 122 Self {
124 sample_time: Default::default(), 123 sample_time: Default::default(),
125 calibrated_vdda: VDDA_CALIB_MV,
126 phantom: PhantomData, 124 phantom: PhantomData,
127 } 125 }
128 } 126 }
@@ -162,29 +160,10 @@ impl<'d, T: Instance> Adc<'d, T> {
162 Temperature {} 160 Temperature {}
163 } 161 }
164 162
165 /// Calculates the system VDDA by sampling the internal VREF channel and comparing
166 /// to the expected value. If the chip's VDDA is not stable, run this before each ADC
167 /// conversion.
168 pub fn calibrate(&mut self, vref: &mut Vref) -> u32 {
169 let old_sample_time = self.sample_time;
170 self.sample_time = SampleTime::Cycles239_5;
171
172 let vref_samp = self.read(vref);
173 self.sample_time = old_sample_time;
174
175 self.calibrated_vdda = (ADC_MAX * VREF_INT) / u32::from(vref_samp);
176 self.calibrated_vdda
177 }
178
179 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 163 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
180 self.sample_time = sample_time; 164 self.sample_time = sample_time;
181 } 165 }
182 166
183 /// Convert a measurement to millivolts
184 pub fn to_millivolts(&self, sample: u16) -> u16 {
185 ((u32::from(sample) * self.calibrated_vdda) / ADC_MAX) as u16
186 }
187
188 /// Perform a single conversion. 167 /// Perform a single conversion.
189 fn convert(&mut self) -> u16 { 168 fn convert(&mut self) -> u16 {
190 unsafe { 169 unsafe {
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 4fe4ad1f0..53419c7f2 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -80,15 +80,6 @@ impl super::sealed::InternalChannel<ADC1> for Temperature {
80} 80}
81 81
82impl Temperature { 82impl Temperature {
83 /// Converts temperature sensor reading in millivolts to degrees celcius
84 pub fn to_celcius(sample_mv: u16) -> f32 {
85 // From 6.3.22 Temperature sensor characteristics
86 const V25: i32 = 760; // mV
87 const AVG_SLOPE: f32 = 2.5; // mV/C
88
89 (sample_mv as i32 - V25) as f32 / AVG_SLOPE + 25.0
90 }
91
92 /// Time needed for temperature sensor readings to stabilize 83 /// Time needed for temperature sensor readings to stabilize
93 pub fn start_time_us() -> u32 { 84 pub fn start_time_us() -> u32 {
94 10 85 10
@@ -172,7 +163,6 @@ impl Prescaler {
172 163
173pub struct Adc<'d, T: Instance> { 164pub struct Adc<'d, T: Instance> {
174 sample_time: SampleTime, 165 sample_time: SampleTime,
175 vref_mv: u32,
176 resolution: Resolution, 166 resolution: Resolution,
177 phantom: PhantomData<&'d mut T>, 167 phantom: PhantomData<&'d mut T>,
178} 168}
@@ -200,7 +190,6 @@ where
200 Self { 190 Self {
201 sample_time: Default::default(), 191 sample_time: Default::default(),
202 resolution: Resolution::default(), 192 resolution: Resolution::default(),
203 vref_mv: VREF_DEFAULT_MV,
204 phantom: PhantomData, 193 phantom: PhantomData,
205 } 194 }
206 } 195 }
@@ -213,18 +202,6 @@ where
213 self.resolution = resolution; 202 self.resolution = resolution;
214 } 203 }
215 204
216 /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
217 ///
218 /// Use this if you have a known precise VREF (VDDA) pin reference voltage.
219 pub fn set_vref_mv(&mut self, vref_mv: u32) {
220 self.vref_mv = vref_mv;
221 }
222
223 /// Convert a measurement to millivolts
224 pub fn to_millivolts(&self, sample: u16) -> u16 {
225 ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
226 }
227
228 /// Enables internal voltage reference and returns [VrefInt], which can be used in 205 /// Enables internal voltage reference and returns [VrefInt], which can be used in
229 /// [Adc::read_internal()] to perform conversion. 206 /// [Adc::read_internal()] to perform conversion.
230 pub fn enable_vrefint(&self) -> VrefInt { 207 pub fn enable_vrefint(&self) -> VrefInt {
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 0f1090888..816feeac7 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -205,7 +205,6 @@ pub use sample_time::SampleTime;
205 205
206pub struct Adc<'d, T: Instance> { 206pub struct Adc<'d, T: Instance> {
207 sample_time: SampleTime, 207 sample_time: SampleTime,
208 vref_mv: u32,
209 resolution: Resolution, 208 resolution: Resolution,
210 phantom: PhantomData<&'d mut T>, 209 phantom: PhantomData<&'d mut T>,
211} 210}
@@ -244,7 +243,6 @@ impl<'d, T: Instance> Adc<'d, T> {
244 Self { 243 Self {
245 sample_time: Default::default(), 244 sample_time: Default::default(),
246 resolution: Resolution::default(), 245 resolution: Resolution::default(),
247 vref_mv: VREF_DEFAULT_MV,
248 phantom: PhantomData, 246 phantom: PhantomData,
249 } 247 }
250 } 248 }
@@ -285,31 +283,6 @@ impl<'d, T: Instance> Adc<'d, T> {
285 Vbat {} 283 Vbat {}
286 } 284 }
287 285
288 /// Calculates the system VDDA by sampling the internal VREFINT channel and comparing
289 /// the result with the value stored at the factory. If the chip's VDDA is not stable, run
290 /// this before each ADC conversion.
291 #[cfg(not(stm32g0))] // TODO is this supposed to be public?
292 #[allow(unused)] // TODO is this supposed to be public?
293 fn calibrate(&mut self, vrefint: &mut VrefInt) {
294 #[cfg(stm32l5)]
295 let vrefint_cal: u32 = todo!();
296 #[cfg(not(stm32l5))]
297 let vrefint_cal = unsafe { crate::pac::VREFINTCAL.data().read().value() };
298 let old_sample_time = self.sample_time;
299
300 // "Table 24. Embedded internal voltage reference" states that the sample time needs to be
301 // at a minimum 4 us. With 640.5 ADC cycles we have a minimum of 8 us at 80 MHz, leaving
302 // some headroom.
303 self.sample_time = SampleTime::Cycles640_5;
304
305 // This can't actually fail, it's just in a result to satisfy hal trait
306 let vrefint_samp = self.read(vrefint);
307
308 self.sample_time = old_sample_time;
309
310 self.vref_mv = (VREF_CALIB_MV * u32::from(vrefint_cal)) / u32::from(vrefint_samp);
311 }
312
313 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 286 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
314 self.sample_time = sample_time; 287 self.sample_time = sample_time;
315 } 288 }
@@ -318,18 +291,6 @@ impl<'d, T: Instance> Adc<'d, T> {
318 self.resolution = resolution; 291 self.resolution = resolution;
319 } 292 }
320 293
321 /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
322 ///
323 /// Use this if you have a known precise VREF (VDDA) pin reference voltage.
324 pub fn set_vref_mv(&mut self, vref_mv: u32) {
325 self.vref_mv = vref_mv;
326 }
327
328 /// Convert a measurement to millivolts
329 pub fn to_millivolts(&self, sample: u16) -> u16 {
330 ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
331 }
332
333 /* 294 /*
334 /// Convert a raw sample from the `Temperature` to deg C 295 /// Convert a raw sample from the `Temperature` to deg C
335 pub fn to_degrees_centigrade(sample: u16) -> f32 { 296 pub fn to_degrees_centigrade(sample: u16) -> f32 {
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index eda2b2a72..2b8f10533 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -314,7 +314,6 @@ impl Prescaler {
314 314
315pub struct Adc<'d, T: Instance> { 315pub struct Adc<'d, T: Instance> {
316 sample_time: SampleTime, 316 sample_time: SampleTime,
317 vref_mv: u32,
318 resolution: Resolution, 317 resolution: Resolution,
319 phantom: PhantomData<&'d mut T>, 318 phantom: PhantomData<&'d mut T>,
320} 319}
@@ -352,7 +351,6 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
352 351
353 let mut s = Self { 352 let mut s = Self {
354 sample_time: Default::default(), 353 sample_time: Default::default(),
355 vref_mv: VREF_DEFAULT_MV,
356 resolution: Resolution::default(), 354 resolution: Resolution::default(),
357 phantom: PhantomData, 355 phantom: PhantomData,
358 }; 356 };
@@ -459,18 +457,6 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
459 self.resolution = resolution; 457 self.resolution = resolution;
460 } 458 }
461 459
462 /// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
463 ///
464 /// Use this if you have a known precise VREF (VDDA) pin reference voltage.
465 pub fn set_vref_mv(&mut self, vref_mv: u32) {
466 self.vref_mv = vref_mv;
467 }
468
469 /// Convert a measurement to millivolts
470 pub fn to_millivolts(&self, sample: u16) -> u16 {
471 ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
472 }
473
474 /// Perform a single conversion. 460 /// Perform a single conversion.
475 fn convert(&mut self) -> u16 { 461 fn convert(&mut self) -> u16 {
476 unsafe { 462 unsafe {
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs
index 2d6b4a0e9..ed59e2799 100644
--- a/examples/stm32f1/src/bin/adc.rs
+++ b/examples/stm32f1/src/bin/adc.rs
@@ -16,11 +16,19 @@ async fn main(_spawner: Spawner) {
16 let mut adc = Adc::new(p.ADC1, &mut Delay); 16 let mut adc = Adc::new(p.ADC1, &mut Delay);
17 let mut pin = p.PB1; 17 let mut pin = p.PB1;
18 18
19 let mut vref = adc.enable_vref(&mut Delay); 19 let mut vrefint = adc.enable_vref(&mut Delay);
20 adc.calibrate(&mut vref); 20 let vrefint_sample = adc.read(&mut vrefint);
21 let convert_to_millivolts = |sample| {
22 // From http://www.st.com/resource/en/datasheet/CD00161566.pdf
23 // 5.3.4 Embedded reference voltage
24 const VREFINT_MV: u32 = 1200; // mV
25
26 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
27 };
28
21 loop { 29 loop {
22 let v = adc.read(&mut pin); 30 let v = adc.read(&mut pin);
23 info!("--> {} - {} mV", v, adc.to_millivolts(v)); 31 info!("--> {} - {} mV", v, convert_to_millivolts(v));
24 Timer::after(Duration::from_millis(100)).await; 32 Timer::after(Duration::from_millis(100)).await;
25 } 33 }
26} 34}
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 1d030f7dc..1c9a0b35d 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -24,19 +24,44 @@ async fn main(_spawner: Spawner) {
24 // Startup delay can be combined to the maximum of either 24 // Startup delay can be combined to the maximum of either
25 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); 25 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us()));
26 26
27 let vrefint_sample = adc.read_internal(&mut vrefint);
28
29 let convert_to_millivolts = |sample| {
30 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
31 // 6.3.24 Reference voltage
32 const VREFINT_MV: u32 = 1210; // mV
33
34 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
35 };
36
37 let convert_to_celcius = |sample| {
38 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
39 // 6.3.22 Temperature sensor characteristics
40 const V25: i32 = 760; // mV
41 const AVG_SLOPE: f32 = 2.5; // mV/C
42
43 let sample_mv = convert_to_millivolts(sample) as i32;
44
45 (sample_mv - V25) as f32 / AVG_SLOPE + 25.0
46 };
47
48 info!("VrefInt: {}", vrefint_sample);
49 const MAX_ADC_SAMPLE: u16 = (1 << 12) - 1;
50 info!("VCCA: {} mV", convert_to_millivolts(MAX_ADC_SAMPLE));
51
27 loop { 52 loop {
28 // Read pin 53 // Read pin
29 let v = adc.read(&mut pin); 54 let v = adc.read(&mut pin);
30 info!("PC1: {} ({} mV)", v, adc.to_millivolts(v)); 55 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v));
31 56
32 // Read internal temperature 57 // Read internal temperature
33 let v = adc.read_internal(&mut temp); 58 let v = adc.read_internal(&mut temp);
34 let celcius = Temperature::to_celcius(adc.to_millivolts(v)); 59 let celcius = convert_to_celcius(v);
35 info!("Internal temp: {} ({} C)", v, celcius); 60 info!("Internal temp: {} ({} C)", v, celcius);
36 61
37 // Read internal voltage reference 62 // Read internal voltage reference
38 let v = adc.read_internal(&mut vrefint); 63 let v = adc.read_internal(&mut vrefint);
39 info!("VrefInt: {} ({} mV)", v, adc.to_millivolts(v)); 64 info!("VrefInt: {}", v);
40 65
41 Timer::after(Duration::from_millis(100)).await; 66 Timer::after(Duration::from_millis(100)).await;
42 } 67 }
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index 80fad8c41..70b3b2a75 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -16,9 +16,19 @@ async fn main(_spawner: Spawner) {
16 let mut adc = Adc::new(p.ADC1, &mut Delay); 16 let mut adc = Adc::new(p.ADC1, &mut Delay);
17 let mut pin = p.PA3; 17 let mut pin = p.PA3;
18 18
19 let mut vrefint = adc.enable_vrefint();
20 let vrefint_sample = adc.read_internal(&mut vrefint);
21 let convert_to_millivolts = |sample| {
22 // From http://www.st.com/resource/en/datasheet/DM00273119.pdf
23 // 6.3.27 Reference voltage
24 const VREFINT_MV: u32 = 1210; // mV
25
26 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
27 };
28
19 loop { 29 loop {
20 let v = adc.read(&mut pin); 30 let v = adc.read(&mut pin);
21 info!("--> {} - {} mV", v, adc.to_millivolts(v)); 31 info!("--> {} - {} mV", v, convert_to_millivolts(v));
22 Timer::after(Duration::from_millis(100)).await; 32 Timer::after(Duration::from_millis(100)).await;
23 } 33 }
24} 34}