diff options
| -rw-r--r-- | embassy-stm32/src/adc/f1.rs | 21 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v2.rs | 23 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 39 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v4.rs | 14 | ||||
| -rw-r--r-- | examples/stm32f1/src/bin/adc.rs | 14 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/adc.rs | 31 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/adc.rs | 12 |
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 | ||
| 87 | pub struct Adc<'d, T: Instance> { | 87 | pub 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 | ||
| 82 | impl Temperature { | 82 | impl 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 | ||
| 173 | pub struct Adc<'d, T: Instance> { | 164 | pub 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 | ||
| 206 | pub struct Adc<'d, T: Instance> { | 206 | pub 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 | ||
| 315 | pub struct Adc<'d, T: Instance> { | 315 | pub 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 | } |
