diff options
Diffstat (limited to 'embassy-stm32/src/adc/v3.rs')
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 874 |
1 files changed, 402 insertions, 472 deletions
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 16063ce4d..9cc44aa9a 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -1,19 +1,19 @@ | |||
| 1 | use cfg_if::cfg_if; | 1 | use cfg_if::cfg_if; |
| 2 | #[cfg(adc_g0)] | 2 | #[cfg(adc_g0)] |
| 3 | use heapless::Vec; | 3 | use heapless::Vec; |
| 4 | use pac::adc::vals::Dmacfg; | ||
| 5 | #[cfg(adc_g0)] | 4 | #[cfg(adc_g0)] |
| 6 | use pac::adc::vals::{Ckmode, Smpsel}; | 5 | use pac::adc::vals::Ckmode; |
| 6 | use pac::adc::vals::Dmacfg; | ||
| 7 | #[cfg(adc_v3)] | 7 | #[cfg(adc_v3)] |
| 8 | use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; | 8 | use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; |
| 9 | #[cfg(adc_g0)] | 9 | #[cfg(adc_g0)] |
| 10 | pub use pac::adc::vals::{Ovsr, Ovss, Presc}; | 10 | pub use pac::adc::vals::{Ovsr, Ovss, Presc}; |
| 11 | 11 | ||
| 12 | use super::{ | 12 | #[allow(unused_imports)] |
| 13 | blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, | 13 | use super::SealedAdcChannel; |
| 14 | }; | 14 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 15 | use crate::dma::Transfer; | 15 | use crate::adc::ConversionMode; |
| 16 | use crate::{pac, rcc, Peri}; | 16 | use crate::{Peri, pac, rcc}; |
| 17 | 17 | ||
| 18 | /// Default VREF voltage used for sample conversion to millivolts. | 18 | /// Default VREF voltage used for sample conversion to millivolts. |
| 19 | pub const VREF_DEFAULT_MV: u32 = 3300; | 19 | pub const VREF_DEFAULT_MV: u32 = 3300; |
| @@ -25,70 +25,64 @@ pub const VREF_CALIB_MV: u32 = 3000; | |||
| 25 | // TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable | 25 | // TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable |
| 26 | const SAMPLE_TIMES_CAPACITY: usize = 2; | 26 | const SAMPLE_TIMES_CAPACITY: usize = 2; |
| 27 | 27 | ||
| 28 | pub struct VrefInt; | 28 | #[cfg(adc_g0)] |
| 29 | impl<T: Instance> AdcChannel<T> for VrefInt {} | 29 | impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T { |
| 30 | impl<T: Instance> SealedAdcChannel<T> for VrefInt { | 30 | const CHANNEL: u8 = 13; |
| 31 | fn channel(&self) -> u8 { | 31 | } |
| 32 | cfg_if! { | 32 | #[cfg(any(adc_h5, adc_h7rs))] |
| 33 | if #[cfg(adc_g0)] { | 33 | impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T { |
| 34 | let val = 13; | 34 | const CHANNEL: u8 = 17; |
| 35 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | 35 | } |
| 36 | let val = 17; | 36 | #[cfg(adc_u0)] |
| 37 | } else if #[cfg(adc_u0)] { | 37 | impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T { |
| 38 | let val = 12; | 38 | const CHANNEL: u8 = 12; |
| 39 | } else { | 39 | } |
| 40 | let val = 0; | 40 | #[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] |
| 41 | } | 41 | impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T { |
| 42 | } | 42 | const CHANNEL: u8 = 0; |
| 43 | val | ||
| 44 | } | ||
| 45 | } | 43 | } |
| 46 | 44 | ||
| 47 | pub struct Temperature; | 45 | #[cfg(adc_g0)] |
| 48 | impl<T: Instance> AdcChannel<T> for Temperature {} | 46 | impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { |
| 49 | impl<T: Instance> SealedAdcChannel<T> for Temperature { | 47 | const CHANNEL: u8 = 12; |
| 50 | fn channel(&self) -> u8 { | 48 | } |
| 51 | cfg_if! { | 49 | #[cfg(any(adc_h5, adc_h7rs))] |
| 52 | if #[cfg(adc_g0)] { | 50 | impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { |
| 53 | let val = 12; | 51 | const CHANNEL: u8 = 16; |
| 54 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | 52 | } |
| 55 | let val = 16; | 53 | #[cfg(adc_u0)] |
| 56 | } else if #[cfg(adc_u0)] { | 54 | impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { |
| 57 | let val = 11; | 55 | const CHANNEL: u8 = 11; |
| 58 | } else { | 56 | } |
| 59 | let val = 17; | 57 | #[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] |
| 60 | } | 58 | impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { |
| 61 | } | 59 | const CHANNEL: u8 = 17; |
| 62 | val | ||
| 63 | } | ||
| 64 | } | 60 | } |
| 65 | 61 | ||
| 66 | pub struct Vbat; | 62 | #[cfg(adc_g0)] |
| 67 | impl<T: Instance> AdcChannel<T> for Vbat {} | 63 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { |
| 68 | impl<T: Instance> SealedAdcChannel<T> for Vbat { | 64 | const CHANNEL: u8 = 14; |
| 69 | fn channel(&self) -> u8 { | 65 | } |
| 70 | cfg_if! { | 66 | #[cfg(any(adc_h5, adc_h7rs))] |
| 71 | if #[cfg(adc_g0)] { | 67 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { |
| 72 | let val = 14; | 68 | const CHANNEL: u8 = 16; |
| 73 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | 69 | } |
| 74 | let val = 2; | 70 | #[cfg(adc_u0)] |
| 75 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | 71 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { |
| 76 | let val = 13; | 72 | const CHANNEL: u8 = 13; |
| 77 | } else { | 73 | } |
| 78 | let val = 18; | 74 | #[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] |
| 79 | } | 75 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { |
| 80 | } | 76 | const CHANNEL: u8 = 18; |
| 81 | val | ||
| 82 | } | ||
| 83 | } | 77 | } |
| 84 | 78 | ||
| 85 | cfg_if! { | 79 | cfg_if! { |
| 86 | if #[cfg(any(adc_h5, adc_h7rs))] { | 80 | if #[cfg(any(adc_h5, adc_h7rs))] { |
| 87 | pub struct VddCore; | 81 | pub struct VddCore; |
| 88 | impl<T: Instance> AdcChannel<T> for VddCore {} | 82 | impl<T: Instance> super::AdcChannel<T> for VddCore {} |
| 89 | impl<T: Instance> super::SealedAdcChannel<T> for VddCore { | 83 | impl<T: Instance> super::SealedAdcChannel<T> for VddCore { |
| 90 | fn channel(&self) -> u8 { | 84 | fn channel(&self) -> u8 { |
| 91 | 6 | 85 | 17 |
| 92 | } | 86 | } |
| 93 | } | 87 | } |
| 94 | } | 88 | } |
| @@ -97,7 +91,7 @@ cfg_if! { | |||
| 97 | cfg_if! { | 91 | cfg_if! { |
| 98 | if #[cfg(adc_u0)] { | 92 | if #[cfg(adc_u0)] { |
| 99 | pub struct DacOut; | 93 | pub struct DacOut; |
| 100 | impl<T: Instance> AdcChannel<T> for DacOut {} | 94 | impl<T: Instance> super::AdcChannel<T> for DacOut {} |
| 101 | impl<T: Instance> super::SealedAdcChannel<T> for DacOut { | 95 | impl<T: Instance> super::SealedAdcChannel<T> for DacOut { |
| 102 | fn channel(&self) -> u8 { | 96 | fn channel(&self) -> u8 { |
| 103 | 19 | 97 | 19 |
| @@ -106,21 +100,6 @@ cfg_if! { | |||
| 106 | } | 100 | } |
| 107 | } | 101 | } |
| 108 | 102 | ||
| 109 | /// Number of samples used for averaging. | ||
| 110 | #[derive(Copy, Clone, Debug)] | ||
| 111 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 112 | pub enum Averaging { | ||
| 113 | Disabled, | ||
| 114 | Samples2, | ||
| 115 | Samples4, | ||
| 116 | Samples8, | ||
| 117 | Samples16, | ||
| 118 | Samples32, | ||
| 119 | Samples64, | ||
| 120 | Samples128, | ||
| 121 | Samples256, | ||
| 122 | } | ||
| 123 | |||
| 124 | cfg_if! { if #[cfg(adc_g0)] { | 103 | cfg_if! { if #[cfg(adc_g0)] { |
| 125 | 104 | ||
| 126 | /// Synchronous PCLK prescaler | 105 | /// Synchronous PCLK prescaler |
| @@ -141,295 +120,150 @@ pub enum Clock { | |||
| 141 | 120 | ||
| 142 | }} | 121 | }} |
| 143 | 122 | ||
| 144 | impl<'d, T: Instance> Adc<'d, T> { | 123 | #[cfg(adc_u0)] |
| 145 | /// Enable the voltage regulator | 124 | type Ovss = u8; |
| 146 | fn init_regulator() { | 125 | #[cfg(adc_u0)] |
| 147 | rcc::enable_and_reset::<T>(); | 126 | type Ovsr = u8; |
| 148 | T::regs().cr().modify(|reg| { | 127 | #[cfg(adc_v3)] |
| 149 | #[cfg(not(any(adc_g0, adc_u0)))] | 128 | type Ovss = OversamplingShift; |
| 150 | reg.set_deeppwd(false); | 129 | #[cfg(adc_v3)] |
| 151 | reg.set_advregen(true); | 130 | type Ovsr = OversamplingRatio; |
| 152 | }); | 131 | |
| 153 | 132 | /// Adc configuration | |
| 154 | // If this is false then each ADC_CHSELR bit enables an input channel. | 133 | #[derive(Default)] |
| 155 | // This is the reset value, so has no effect. | 134 | pub struct AdcConfig { |
| 156 | #[cfg(any(adc_g0, adc_u0))] | 135 | #[cfg(any(adc_u0, adc_g0, adc_v3))] |
| 157 | T::regs().cfgr1().modify(|reg| { | 136 | pub oversampling_shift: Option<Ovss>, |
| 158 | reg.set_chselrmod(false); | 137 | #[cfg(any(adc_u0, adc_g0, adc_v3))] |
| 159 | }); | 138 | pub oversampling_ratio: Option<Ovsr>, |
| 160 | 139 | #[cfg(any(adc_u0, adc_g0))] | |
| 161 | blocking_delay_us(20); | 140 | pub oversampling_enable: Option<bool>, |
| 162 | } | 141 | #[cfg(adc_v3)] |
| 163 | 142 | pub oversampling_mode: Option<(Rovsm, Trovs, bool)>, | |
| 164 | /// Calibrate to remove conversion offset | ||
| 165 | fn init_calibrate() { | ||
| 166 | T::regs().cr().modify(|reg| { | ||
| 167 | reg.set_adcal(true); | ||
| 168 | }); | ||
| 169 | |||
| 170 | while T::regs().cr().read().adcal() { | ||
| 171 | // spin | ||
| 172 | } | ||
| 173 | |||
| 174 | blocking_delay_us(1); | ||
| 175 | } | ||
| 176 | |||
| 177 | /// Initialize the ADC leaving any analog clock at reset value. | ||
| 178 | /// For G0 and WL, this is the async clock without prescaler. | ||
| 179 | pub fn new(adc: Peri<'d, T>) -> Self { | ||
| 180 | Self::init_regulator(); | ||
| 181 | Self::init_calibrate(); | ||
| 182 | Self { | ||
| 183 | adc, | ||
| 184 | sample_time: SampleTime::from_bits(0), | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | #[cfg(adc_g0)] | 143 | #[cfg(adc_g0)] |
| 189 | /// Initialize ADC with explicit clock for the analog ADC | 144 | pub clock: Option<Clock>, |
| 190 | pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { | 145 | pub resolution: Option<Resolution>, |
| 191 | Self::init_regulator(); | 146 | pub averaging: Option<Averaging>, |
| 192 | 147 | } | |
| 193 | #[cfg(any(stm32wl5x))] | ||
| 194 | { | ||
| 195 | // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual | ||
| 196 | let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0; | ||
| 197 | match clock { | ||
| 198 | Clock::Async { div: _ } => { | ||
| 199 | assert!(async_clock_available); | ||
| 200 | } | ||
| 201 | Clock::Sync { div: _ } => { | ||
| 202 | if async_clock_available { | ||
| 203 | warn!("Not using configured ADC clock"); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | match clock { | ||
| 209 | Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)), | ||
| 210 | Clock::Sync { div } => T::regs().cfgr2().modify(|reg| { | ||
| 211 | reg.set_ckmode(match div { | ||
| 212 | CkModePclk::DIV1 => Ckmode::PCLK, | ||
| 213 | CkModePclk::DIV2 => Ckmode::PCLK_DIV2, | ||
| 214 | CkModePclk::DIV4 => Ckmode::PCLK_DIV4, | ||
| 215 | }) | ||
| 216 | }), | ||
| 217 | } | ||
| 218 | |||
| 219 | Self::init_calibrate(); | ||
| 220 | 148 | ||
| 221 | Self { | 149 | impl super::AdcRegs for crate::pac::adc::Adc { |
| 222 | adc, | 150 | fn data(&self) -> *mut u16 { |
| 223 | sample_time: SampleTime::from_bits(0), | 151 | crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 |
| 224 | } | ||
| 225 | } | 152 | } |
| 226 | 153 | ||
| 227 | // Enable ADC only when it is not already running. | 154 | // Enable ADC only when it is not already running. |
| 228 | fn enable(&mut self) { | 155 | fn enable(&self) { |
| 229 | // Make sure bits are off | 156 | // Make sure bits are off |
| 230 | while T::regs().cr().read().addis() { | 157 | while self.cr().read().addis() { |
| 231 | // spin | 158 | // spin |
| 232 | } | 159 | } |
| 233 | 160 | ||
| 234 | if !T::regs().cr().read().aden() { | 161 | if !self.cr().read().aden() { |
| 235 | // Enable ADC | 162 | // Enable ADC |
| 236 | T::regs().isr().modify(|reg| { | 163 | self.isr().modify(|reg| { |
| 237 | reg.set_adrdy(true); | 164 | reg.set_adrdy(true); |
| 238 | }); | 165 | }); |
| 239 | T::regs().cr().modify(|reg| { | 166 | self.cr().modify(|reg| { |
| 240 | reg.set_aden(true); | 167 | reg.set_aden(true); |
| 241 | }); | 168 | }); |
| 242 | 169 | ||
| 243 | while !T::regs().isr().read().adrdy() { | 170 | while !self.isr().read().adrdy() { |
| 244 | // spin | 171 | // spin |
| 245 | } | 172 | } |
| 246 | } | 173 | } |
| 247 | } | 174 | } |
| 248 | 175 | ||
| 249 | pub fn enable_vrefint(&self) -> VrefInt { | 176 | fn start(&self) { |
| 177 | self.cr().modify(|reg| { | ||
| 178 | reg.set_adstart(true); | ||
| 179 | }); | ||
| 180 | } | ||
| 181 | |||
| 182 | fn stop(&self) { | ||
| 183 | // Ensure conversions are finished. | ||
| 184 | if self.cr().read().adstart() && !self.cr().read().addis() { | ||
| 185 | self.cr().modify(|reg| { | ||
| 186 | reg.set_adstp(true); | ||
| 187 | }); | ||
| 188 | while self.cr().read().adstart() {} | ||
| 189 | } | ||
| 190 | |||
| 191 | // Reset configuration. | ||
| 250 | #[cfg(not(any(adc_g0, adc_u0)))] | 192 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 251 | T::common_regs().ccr().modify(|reg| { | 193 | self.cfgr().modify(|reg| { |
| 252 | reg.set_vrefen(true); | 194 | reg.set_cont(false); |
| 195 | reg.set_dmaen(false); | ||
| 253 | }); | 196 | }); |
| 254 | #[cfg(any(adc_g0, adc_u0))] | 197 | #[cfg(any(adc_g0, adc_u0))] |
| 255 | T::regs().ccr().modify(|reg| { | 198 | self.cfgr1().modify(|reg| { |
| 256 | reg.set_vrefen(true); | 199 | reg.set_cont(false); |
| 200 | reg.set_dmaen(false); | ||
| 257 | }); | 201 | }); |
| 202 | } | ||
| 258 | 203 | ||
| 259 | // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us | 204 | /// Perform a single conversion. |
| 260 | // to stabilize the internal voltage reference. | 205 | fn convert(&self) { |
| 261 | blocking_delay_us(15); | 206 | // Some models are affected by an erratum: |
| 207 | // If we perform conversions slower than 1 kHz, the first read ADC value can be | ||
| 208 | // corrupted, so we discard it and measure again. | ||
| 209 | // | ||
| 210 | // STM32L471xx: Section 2.7.3 | ||
| 211 | // STM32G4: Section 2.7.3 | ||
| 212 | #[cfg(any(rcc_l4, rcc_g4))] | ||
| 213 | let len = 2; | ||
| 262 | 214 | ||
| 263 | VrefInt {} | 215 | #[cfg(not(any(rcc_l4, rcc_g4)))] |
| 264 | } | 216 | let len = 1; |
| 265 | 217 | ||
| 266 | pub fn enable_temperature(&self) -> Temperature { | 218 | for _ in 0..len { |
| 267 | cfg_if! { | 219 | self.isr().modify(|reg| { |
| 268 | if #[cfg(any(adc_g0, adc_u0))] { | 220 | reg.set_eos(true); |
| 269 | T::regs().ccr().modify(|reg| { | 221 | reg.set_eoc(true); |
| 270 | reg.set_tsen(true); | 222 | }); |
| 271 | }); | ||
| 272 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | ||
| 273 | T::common_regs().ccr().modify(|reg| { | ||
| 274 | reg.set_tsen(true); | ||
| 275 | }); | ||
| 276 | } else { | ||
| 277 | T::common_regs().ccr().modify(|reg| { | ||
| 278 | reg.set_ch17sel(true); | ||
| 279 | }); | ||
| 280 | } | ||
| 281 | } | ||
| 282 | 223 | ||
| 283 | Temperature {} | 224 | // Start conversion |
| 284 | } | 225 | self.cr().modify(|reg| { |
| 226 | reg.set_adstart(true); | ||
| 227 | }); | ||
| 285 | 228 | ||
| 286 | pub fn enable_vbat(&self) -> Vbat { | 229 | while !self.isr().read().eos() { |
| 287 | cfg_if! { | 230 | // spin |
| 288 | if #[cfg(any(adc_g0, adc_u0))] { | ||
| 289 | T::regs().ccr().modify(|reg| { | ||
| 290 | reg.set_vbaten(true); | ||
| 291 | }); | ||
| 292 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | ||
| 293 | T::common_regs().ccr().modify(|reg| { | ||
| 294 | reg.set_vbaten(true); | ||
| 295 | }); | ||
| 296 | } else { | ||
| 297 | T::common_regs().ccr().modify(|reg| { | ||
| 298 | reg.set_ch18sel(true); | ||
| 299 | }); | ||
| 300 | } | 231 | } |
| 301 | } | 232 | } |
| 302 | |||
| 303 | Vbat {} | ||
| 304 | } | 233 | } |
| 305 | 234 | ||
| 306 | /// Set the ADC sample time. | 235 | fn configure_dma(&self, conversion_mode: ConversionMode) { |
| 307 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | 236 | // Set continuous mode with oneshot dma. |
| 308 | self.sample_time = sample_time; | 237 | // Clear overrun flag before starting transfer. |
| 309 | } | 238 | self.isr().modify(|reg| { |
| 310 | 239 | reg.set_ovr(true); | |
| 311 | /// Get the ADC sample time. | 240 | }); |
| 312 | pub fn sample_time(&self) -> SampleTime { | ||
| 313 | self.sample_time | ||
| 314 | } | ||
| 315 | 241 | ||
| 316 | /// Set the ADC resolution. | ||
| 317 | pub fn set_resolution(&mut self, resolution: Resolution) { | ||
| 318 | #[cfg(not(any(adc_g0, adc_u0)))] | 242 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 319 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | 243 | let regs = self.cfgr(); |
| 320 | #[cfg(any(adc_g0, adc_u0))] | ||
| 321 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 322 | } | ||
| 323 | 244 | ||
| 324 | pub fn set_averaging(&mut self, averaging: Averaging) { | 245 | #[cfg(any(adc_g0, adc_u0))] |
| 325 | let (enable, samples, right_shift) = match averaging { | 246 | let regs = self.cfgr1(); |
| 326 | Averaging::Disabled => (false, 0, 0), | ||
| 327 | Averaging::Samples2 => (true, 0, 1), | ||
| 328 | Averaging::Samples4 => (true, 1, 2), | ||
| 329 | Averaging::Samples8 => (true, 2, 3), | ||
| 330 | Averaging::Samples16 => (true, 3, 4), | ||
| 331 | Averaging::Samples32 => (true, 4, 5), | ||
| 332 | Averaging::Samples64 => (true, 5, 6), | ||
| 333 | Averaging::Samples128 => (true, 6, 7), | ||
| 334 | Averaging::Samples256 => (true, 7, 8), | ||
| 335 | }; | ||
| 336 | T::regs().cfgr2().modify(|reg| { | ||
| 337 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 338 | reg.set_rovse(enable); | ||
| 339 | #[cfg(any(adc_g0, adc_u0))] | ||
| 340 | reg.set_ovse(enable); | ||
| 341 | #[cfg(any(adc_h5, adc_h7rs))] | ||
| 342 | reg.set_ovsr(samples.into()); | ||
| 343 | #[cfg(not(any(adc_h5, adc_h7rs)))] | ||
| 344 | reg.set_ovsr(samples.into()); | ||
| 345 | reg.set_ovss(right_shift.into()); | ||
| 346 | }) | ||
| 347 | } | ||
| 348 | /* | ||
| 349 | /// Convert a raw sample from the `Temperature` to deg C | ||
| 350 | pub fn to_degrees_centigrade(sample: u16) -> f32 { | ||
| 351 | (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32) | ||
| 352 | * (sample as f32 - VtempCal30::get().read() as f32) | ||
| 353 | + 30.0 | ||
| 354 | } | ||
| 355 | */ | ||
| 356 | |||
| 357 | /// Perform a single conversion. | ||
| 358 | fn convert(&mut self) -> u16 { | ||
| 359 | T::regs().isr().modify(|reg| { | ||
| 360 | reg.set_eos(true); | ||
| 361 | reg.set_eoc(true); | ||
| 362 | }); | ||
| 363 | 247 | ||
| 364 | // Start conversion | 248 | regs.modify(|reg| { |
| 365 | T::regs().cr().modify(|reg| { | 249 | reg.set_discen(false); |
| 366 | reg.set_adstart(true); | 250 | reg.set_cont(true); |
| 251 | reg.set_dmacfg(match conversion_mode { | ||
| 252 | ConversionMode::Singular => Dmacfg::ONE_SHOT, | ||
| 253 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 254 | ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, | ||
| 255 | }); | ||
| 256 | reg.set_dmaen(true); | ||
| 367 | }); | 257 | }); |
| 368 | |||
| 369 | while !T::regs().isr().read().eos() { | ||
| 370 | // spin | ||
| 371 | } | ||
| 372 | |||
| 373 | T::regs().dr().read().0 as u16 | ||
| 374 | } | 258 | } |
| 375 | 259 | ||
| 376 | /// Read an ADC channel. | 260 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 377 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { | 261 | #[cfg(adc_h5)] |
| 378 | self.read_channel(channel) | 262 | self.cr().modify(|w| w.set_aden(false)); |
| 379 | } | ||
| 380 | |||
| 381 | /// Read one or multiple ADC channels using DMA. | ||
| 382 | /// | ||
| 383 | /// `readings` must have a length that is a multiple of the length of the | ||
| 384 | /// `sequence` iterator. | ||
| 385 | /// | ||
| 386 | /// Note: The order of values in `readings` is defined by the pin ADC | ||
| 387 | /// channel number and not the pin order in `sequence`. | ||
| 388 | /// | ||
| 389 | /// Example | ||
| 390 | /// ```rust,ignore | ||
| 391 | /// use embassy_stm32::adc::{Adc, AdcChannel} | ||
| 392 | /// | ||
| 393 | /// let mut adc = Adc::new(p.ADC1); | ||
| 394 | /// let mut adc_pin0 = p.PA0.degrade_adc(); | ||
| 395 | /// let mut adc_pin1 = p.PA1.degrade_adc(); | ||
| 396 | /// let mut measurements = [0u16; 2]; | ||
| 397 | /// | ||
| 398 | /// adc.read( | ||
| 399 | /// p.DMA1_CH2.reborrow(), | ||
| 400 | /// [ | ||
| 401 | /// (&mut *adc_pin0, SampleTime::CYCLES160_5), | ||
| 402 | /// (&mut *adc_pin1, SampleTime::CYCLES160_5), | ||
| 403 | /// ] | ||
| 404 | /// .into_iter(), | ||
| 405 | /// &mut measurements, | ||
| 406 | /// ) | ||
| 407 | /// .await; | ||
| 408 | /// defmt::info!("measurements: {}", measurements); | ||
| 409 | /// ``` | ||
| 410 | pub async fn read( | ||
| 411 | &mut self, | ||
| 412 | rx_dma: Peri<'_, impl RxDma<T>>, | ||
| 413 | sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, | ||
| 414 | readings: &mut [u16], | ||
| 415 | ) { | ||
| 416 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | ||
| 417 | assert!( | ||
| 418 | readings.len() % sequence.len() == 0, | ||
| 419 | "Readings length must be a multiple of sequence length" | ||
| 420 | ); | ||
| 421 | assert!( | ||
| 422 | sequence.len() <= 16, | ||
| 423 | "Asynchronous read sequence cannot be more than 16 in length" | ||
| 424 | ); | ||
| 425 | |||
| 426 | // Ensure no conversions are ongoing and ADC is enabled. | ||
| 427 | Self::cancel_conversions(); | ||
| 428 | self.enable(); | ||
| 429 | 263 | ||
| 430 | // Set sequence length | 264 | // Set sequence length |
| 431 | #[cfg(not(any(adc_g0, adc_u0)))] | 265 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 432 | T::regs().sqr1().modify(|w| { | 266 | self.sqr1().modify(|w| { |
| 433 | w.set_l(sequence.len() as u8 - 1); | 267 | w.set_l(sequence.len() as u8 - 1); |
| 434 | }); | 268 | }); |
| 435 | 269 | ||
| @@ -437,12 +271,12 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 437 | { | 271 | { |
| 438 | let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new(); | 272 | let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new(); |
| 439 | 273 | ||
| 440 | T::regs().chselr().write(|chselr| { | 274 | self.chselr().write(|chselr| { |
| 441 | T::regs().smpr().write(|smpr| { | 275 | self.smpr().write(|smpr| { |
| 442 | for (channel, sample_time) in sequence { | 276 | for ((channel, _), sample_time) in sequence { |
| 443 | chselr.set_chsel(channel.channel.into(), true); | 277 | chselr.set_chsel(channel.into(), true); |
| 444 | if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { | 278 | if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { |
| 445 | smpr.set_smpsel(channel.channel.into(), (i as u8).into()); | 279 | smpr.set_smpsel(channel.into(), (i as u8).into()); |
| 446 | } else { | 280 | } else { |
| 447 | smpr.set_sample_time(sample_times.len(), sample_time); | 281 | smpr.set_sample_time(sample_times.len(), sample_time); |
| 448 | if let Err(_) = sample_times.push(sample_time) { | 282 | if let Err(_) = sample_times.push(sample_time) { |
| @@ -461,225 +295,321 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 461 | #[cfg(adc_u0)] | 295 | #[cfg(adc_u0)] |
| 462 | let mut channel_mask = 0; | 296 | let mut channel_mask = 0; |
| 463 | 297 | ||
| 298 | #[cfg(adc_h5)] | ||
| 299 | let mut difsel = 0u32; | ||
| 300 | |||
| 464 | // Configure channels and ranks | 301 | // Configure channels and ranks |
| 465 | for (_i, (channel, sample_time)) in sequence.enumerate() { | 302 | for (_i, ((channel, _is_differential), sample_time)) in sequence.enumerate() { |
| 466 | Self::configure_channel(channel, sample_time); | 303 | // RM0492, RM0481, etc. |
| 304 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." | ||
| 305 | #[cfg(any(adc_h5, adc_h7rs))] | ||
| 306 | if channel == 0 { | ||
| 307 | self.or().modify(|reg| reg.set_op0(true)); | ||
| 308 | } | ||
| 309 | |||
| 310 | // Configure channel | ||
| 311 | cfg_if! { | ||
| 312 | if #[cfg(adc_u0)] { | ||
| 313 | // On G0 and U6 all channels use the same sampling time. | ||
| 314 | self.smpr().modify(|reg| reg.set_smp1(sample_time.into())); | ||
| 315 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | ||
| 316 | match channel { | ||
| 317 | 0..=9 => self.smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), | ||
| 318 | _ => self.smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())), | ||
| 319 | } | ||
| 320 | } else { | ||
| 321 | let sample_time = sample_time.into(); | ||
| 322 | self | ||
| 323 | .smpr(channel as usize / 10) | ||
| 324 | .modify(|reg| reg.set_smp(channel as usize % 10, sample_time)); | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | #[cfg(stm32h7)] | ||
| 329 | { | ||
| 330 | use crate::pac::adc::vals::Pcsel; | ||
| 331 | |||
| 332 | self.cfgr2().modify(|w| w.set_lshift(0)); | ||
| 333 | self.pcsel() | ||
| 334 | .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); | ||
| 335 | } | ||
| 467 | 336 | ||
| 468 | // Each channel is sampled according to sequence | 337 | // Each channel is sampled according to sequence |
| 469 | #[cfg(not(any(adc_g0, adc_u0)))] | 338 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 470 | match _i { | 339 | match _i { |
| 471 | 0..=3 => { | 340 | 0..=3 => { |
| 472 | T::regs().sqr1().modify(|w| { | 341 | self.sqr1().modify(|w| { |
| 473 | w.set_sq(_i, channel.channel()); | 342 | w.set_sq(_i, channel); |
| 474 | }); | 343 | }); |
| 475 | } | 344 | } |
| 476 | 4..=8 => { | 345 | 4..=8 => { |
| 477 | T::regs().sqr2().modify(|w| { | 346 | self.sqr2().modify(|w| { |
| 478 | w.set_sq(_i - 4, channel.channel()); | 347 | w.set_sq(_i - 4, channel); |
| 479 | }); | 348 | }); |
| 480 | } | 349 | } |
| 481 | 9..=13 => { | 350 | 9..=13 => { |
| 482 | T::regs().sqr3().modify(|w| { | 351 | self.sqr3().modify(|w| { |
| 483 | w.set_sq(_i - 9, channel.channel()); | 352 | w.set_sq(_i - 9, channel); |
| 484 | }); | 353 | }); |
| 485 | } | 354 | } |
| 486 | 14..=15 => { | 355 | 14..=15 => { |
| 487 | T::regs().sqr4().modify(|w| { | 356 | self.sqr4().modify(|w| { |
| 488 | w.set_sq(_i - 14, channel.channel()); | 357 | w.set_sq(_i - 14, channel); |
| 489 | }); | 358 | }); |
| 490 | } | 359 | } |
| 491 | _ => unreachable!(), | 360 | _ => unreachable!(), |
| 492 | } | 361 | } |
| 493 | 362 | ||
| 363 | #[cfg(adc_h5)] | ||
| 364 | { | ||
| 365 | difsel |= (_is_differential as u32) << channel; | ||
| 366 | } | ||
| 367 | |||
| 494 | #[cfg(adc_u0)] | 368 | #[cfg(adc_u0)] |
| 495 | { | 369 | { |
| 496 | channel_mask |= 1 << channel.channel(); | 370 | channel_mask |= 1 << channel; |
| 497 | } | 371 | } |
| 498 | } | 372 | } |
| 499 | 373 | ||
| 374 | #[cfg(adc_h5)] | ||
| 375 | self.difsel().write(|w| w.set_difsel(difsel)); | ||
| 376 | |||
| 500 | // On G0 and U0 enabled channels are sampled from 0 to last channel. | 377 | // On G0 and U0 enabled channels are sampled from 0 to last channel. |
| 501 | // It is possible to add up to 8 sequences if CHSELRMOD = 1. | 378 | // It is possible to add up to 8 sequences if CHSELRMOD = 1. |
| 502 | // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. | 379 | // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. |
| 503 | #[cfg(adc_u0)] | 380 | #[cfg(adc_u0)] |
| 504 | T::regs().chselr().modify(|reg| { | 381 | self.chselr().modify(|reg| { |
| 505 | reg.set_chsel(channel_mask); | 382 | reg.set_chsel(channel_mask); |
| 506 | }); | 383 | }); |
| 507 | } | 384 | } |
| 508 | // Set continuous mode with oneshot dma. | 385 | } |
| 509 | // Clear overrun flag before starting transfer. | 386 | } |
| 510 | T::regs().isr().modify(|reg| { | ||
| 511 | reg.set_ovr(true); | ||
| 512 | }); | ||
| 513 | 387 | ||
| 514 | #[cfg(not(any(adc_g0, adc_u0)))] | 388 | impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> { |
| 515 | T::regs().cfgr().modify(|reg| { | 389 | /// Enable the voltage regulator |
| 516 | reg.set_discen(false); | 390 | fn init_regulator() { |
| 517 | reg.set_cont(true); | 391 | rcc::enable_and_reset::<T>(); |
| 518 | reg.set_dmacfg(Dmacfg::ONE_SHOT); | 392 | T::regs().cr().modify(|reg| { |
| 519 | reg.set_dmaen(true); | 393 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 394 | reg.set_deeppwd(false); | ||
| 395 | reg.set_advregen(true); | ||
| 520 | }); | 396 | }); |
| 397 | |||
| 398 | // If this is false then each ADC_CHSELR bit enables an input channel. | ||
| 399 | // This is the reset value, so has no effect. | ||
| 521 | #[cfg(any(adc_g0, adc_u0))] | 400 | #[cfg(any(adc_g0, adc_u0))] |
| 522 | T::regs().cfgr1().modify(|reg| { | 401 | T::regs().cfgr1().modify(|reg| { |
| 523 | reg.set_discen(false); | 402 | reg.set_chselrmod(false); |
| 524 | reg.set_cont(true); | ||
| 525 | reg.set_dmacfg(Dmacfg::ONE_SHOT); | ||
| 526 | reg.set_dmaen(true); | ||
| 527 | }); | 403 | }); |
| 528 | 404 | ||
| 529 | let request = rx_dma.request(); | 405 | blocking_delay_us(20); |
| 530 | let transfer = unsafe { | 406 | } |
| 531 | Transfer::new_read( | ||
| 532 | rx_dma, | ||
| 533 | request, | ||
| 534 | T::regs().dr().as_ptr() as *mut u16, | ||
| 535 | readings, | ||
| 536 | Default::default(), | ||
| 537 | ) | ||
| 538 | }; | ||
| 539 | 407 | ||
| 540 | // Start conversion | 408 | /// Calibrate to remove conversion offset |
| 409 | fn init_calibrate() { | ||
| 541 | T::regs().cr().modify(|reg| { | 410 | T::regs().cr().modify(|reg| { |
| 542 | reg.set_adstart(true); | 411 | reg.set_adcal(true); |
| 543 | }); | 412 | }); |
| 544 | 413 | ||
| 545 | // Wait for conversion sequence to finish. | 414 | while T::regs().cr().read().adcal() { |
| 546 | transfer.await; | 415 | // spin |
| 547 | 416 | } | |
| 548 | // Ensure conversions are finished. | ||
| 549 | Self::cancel_conversions(); | ||
| 550 | 417 | ||
| 551 | // Reset configuration. | 418 | blocking_delay_us(1); |
| 552 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 553 | T::regs().cfgr().modify(|reg| { | ||
| 554 | reg.set_cont(false); | ||
| 555 | }); | ||
| 556 | #[cfg(any(adc_g0, adc_u0))] | ||
| 557 | T::regs().cfgr1().modify(|reg| { | ||
| 558 | reg.set_cont(false); | ||
| 559 | }); | ||
| 560 | } | 419 | } |
| 561 | 420 | ||
| 562 | #[cfg(not(adc_g0))] | 421 | /// Initialize the ADC leaving any analog clock at reset value. |
| 563 | fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { | 422 | /// For G0 and WL, this is the async clock without prescaler. |
| 564 | // RM0492, RM0481, etc. | 423 | pub fn new(adc: Peri<'d, T>) -> Self { |
| 565 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." | 424 | Self::init_regulator(); |
| 566 | #[cfg(any(adc_h5, adc_h7rs))] | 425 | Self::init_calibrate(); |
| 567 | if channel.channel() == 0 { | 426 | Self { adc } |
| 568 | T::regs().or().modify(|reg| reg.set_op0(true)); | ||
| 569 | } | ||
| 570 | |||
| 571 | // Configure channel | ||
| 572 | Self::set_channel_sample_time(channel.channel(), sample_time); | ||
| 573 | } | 427 | } |
| 574 | 428 | ||
| 575 | fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { | 429 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { |
| 576 | self.enable(); | ||
| 577 | #[cfg(not(adc_g0))] | 430 | #[cfg(not(adc_g0))] |
| 578 | Self::configure_channel(channel, self.sample_time); | 431 | let s = Self::new(adc); |
| 432 | |||
| 579 | #[cfg(adc_g0)] | 433 | #[cfg(adc_g0)] |
| 580 | T::regs().smpr().write(|reg| { | 434 | let s = match config.clock { |
| 581 | reg.set_sample_time(0, self.sample_time); | 435 | Some(clock) => Self::new_with_clock(adc, clock), |
| 582 | reg.set_smpsel(channel.channel().into(), Smpsel::SMP1); | 436 | None => Self::new(adc), |
| 583 | }); | 437 | }; |
| 584 | // Select channel | 438 | |
| 585 | #[cfg(not(any(adc_g0, adc_u0)))] | 439 | #[cfg(any(adc_g0, adc_u0, adc_v3))] |
| 586 | T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel())); | 440 | if let Some(shift) = config.oversampling_shift { |
| 441 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 442 | } | ||
| 443 | |||
| 444 | #[cfg(any(adc_g0, adc_u0, adc_v3))] | ||
| 445 | if let Some(ratio) = config.oversampling_ratio { | ||
| 446 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | ||
| 447 | } | ||
| 448 | |||
| 587 | #[cfg(any(adc_g0, adc_u0))] | 449 | #[cfg(any(adc_g0, adc_u0))] |
| 588 | T::regs().chselr().write(|reg| { | 450 | if let Some(enable) = config.oversampling_enable { |
| 589 | #[cfg(adc_g0)] | 451 | T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); |
| 590 | reg.set_chsel(channel.channel().into(), true); | 452 | } |
| 591 | #[cfg(adc_u0)] | ||
| 592 | reg.set_chsel(1 << channel.channel()); | ||
| 593 | }); | ||
| 594 | 453 | ||
| 595 | // Some models are affected by an erratum: | 454 | #[cfg(adc_v3)] |
| 596 | // If we perform conversions slower than 1 kHz, the first read ADC value can be | 455 | if let Some((mode, trig_mode, enable)) = config.oversampling_mode { |
| 597 | // corrupted, so we discard it and measure again. | 456 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); |
| 598 | // | 457 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); |
| 599 | // STM32L471xx: Section 2.7.3 | 458 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); |
| 600 | // STM32G4: Section 2.7.3 | 459 | } |
| 601 | #[cfg(any(rcc_l4, rcc_g4))] | ||
| 602 | let _ = self.convert(); | ||
| 603 | let val = self.convert(); | ||
| 604 | 460 | ||
| 605 | T::regs().cr().modify(|reg| reg.set_addis(true)); | 461 | if let Some(resolution) = config.resolution { |
| 462 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 463 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 464 | #[cfg(any(adc_g0, adc_u0))] | ||
| 465 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 466 | } | ||
| 606 | 467 | ||
| 607 | // RM0492, RM0481, etc. | 468 | if let Some(averaging) = config.averaging { |
| 608 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." | 469 | let (enable, samples, right_shift) = match averaging { |
| 609 | #[cfg(any(adc_h5, adc_h7rs))] | 470 | Averaging::Disabled => (false, 0, 0), |
| 610 | if channel.channel() == 0 { | 471 | Averaging::Samples2 => (true, 0, 1), |
| 611 | T::regs().or().modify(|reg| reg.set_op0(false)); | 472 | Averaging::Samples4 => (true, 1, 2), |
| 473 | Averaging::Samples8 => (true, 2, 3), | ||
| 474 | Averaging::Samples16 => (true, 3, 4), | ||
| 475 | Averaging::Samples32 => (true, 4, 5), | ||
| 476 | Averaging::Samples64 => (true, 5, 6), | ||
| 477 | Averaging::Samples128 => (true, 6, 7), | ||
| 478 | Averaging::Samples256 => (true, 7, 8), | ||
| 479 | }; | ||
| 480 | T::regs().cfgr2().modify(|reg| { | ||
| 481 | #[cfg(not(any(adc_g0, adc_u0)))] | ||
| 482 | reg.set_rovse(enable); | ||
| 483 | #[cfg(any(adc_g0, adc_u0))] | ||
| 484 | reg.set_ovse(enable); | ||
| 485 | #[cfg(any(adc_h5, adc_h7rs))] | ||
| 486 | reg.set_ovsr(samples.into()); | ||
| 487 | #[cfg(not(any(adc_h5, adc_h7rs)))] | ||
| 488 | reg.set_ovsr(samples.into()); | ||
| 489 | reg.set_ovss(right_shift.into()); | ||
| 490 | }) | ||
| 612 | } | 491 | } |
| 613 | 492 | ||
| 614 | val | 493 | s |
| 615 | } | 494 | } |
| 616 | 495 | ||
| 617 | #[cfg(adc_g0)] | 496 | #[cfg(adc_g0)] |
| 618 | pub fn set_oversampling_shift(&mut self, shift: Ovss) { | 497 | /// Initialize ADC with explicit clock for the analog ADC |
| 619 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | 498 | pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { |
| 620 | } | 499 | Self::init_regulator(); |
| 621 | #[cfg(adc_u0)] | ||
| 622 | pub fn set_oversampling_shift(&mut self, shift: u8) { | ||
| 623 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 624 | } | ||
| 625 | 500 | ||
| 626 | #[cfg(adc_g0)] | 501 | #[cfg(any(stm32wl5x))] |
| 627 | pub fn set_oversampling_ratio(&mut self, ratio: Ovsr) { | 502 | { |
| 628 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | 503 | // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual |
| 629 | } | 504 | let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0; |
| 630 | #[cfg(adc_u0)] | 505 | match clock { |
| 631 | pub fn set_oversampling_ratio(&mut self, ratio: u8) { | 506 | Clock::Async { div: _ } => { |
| 632 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | 507 | assert!(async_clock_available); |
| 633 | } | 508 | } |
| 509 | Clock::Sync { div: _ } => { | ||
| 510 | if async_clock_available { | ||
| 511 | warn!("Not using configured ADC clock"); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | } | ||
| 515 | } | ||
| 516 | match clock { | ||
| 517 | Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)), | ||
| 518 | Clock::Sync { div } => T::regs().cfgr2().modify(|reg| { | ||
| 519 | reg.set_ckmode(match div { | ||
| 520 | CkModePclk::DIV1 => Ckmode::PCLK, | ||
| 521 | CkModePclk::DIV2 => Ckmode::PCLK_DIV2, | ||
| 522 | CkModePclk::DIV4 => Ckmode::PCLK_DIV4, | ||
| 523 | }) | ||
| 524 | }), | ||
| 525 | } | ||
| 634 | 526 | ||
| 635 | #[cfg(any(adc_g0, adc_u0))] | 527 | Self::init_calibrate(); |
| 636 | pub fn oversampling_enable(&mut self, enable: bool) { | ||
| 637 | T::regs().cfgr2().modify(|reg| reg.set_ovse(enable)); | ||
| 638 | } | ||
| 639 | 528 | ||
| 640 | #[cfg(adc_v3)] | 529 | Self { adc } |
| 641 | pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) { | ||
| 642 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); | ||
| 643 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); | ||
| 644 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); | ||
| 645 | } | 530 | } |
| 646 | 531 | ||
| 647 | #[cfg(adc_v3)] | 532 | pub fn enable_vrefint(&self) -> VrefInt { |
| 648 | pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) { | 533 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 649 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | 534 | T::common_regs().ccr().modify(|reg| { |
| 535 | reg.set_vrefen(true); | ||
| 536 | }); | ||
| 537 | #[cfg(any(adc_g0, adc_u0))] | ||
| 538 | T::regs().ccr().modify(|reg| { | ||
| 539 | reg.set_vrefen(true); | ||
| 540 | }); | ||
| 541 | |||
| 542 | // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us | ||
| 543 | // to stabilize the internal voltage reference. | ||
| 544 | blocking_delay_us(15); | ||
| 545 | |||
| 546 | VrefInt {} | ||
| 650 | } | 547 | } |
| 651 | 548 | ||
| 652 | #[cfg(adc_v3)] | 549 | pub fn enable_temperature(&self) -> Temperature { |
| 653 | pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) { | 550 | cfg_if! { |
| 654 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | 551 | if #[cfg(any(adc_g0, adc_u0))] { |
| 552 | T::regs().ccr().modify(|reg| { | ||
| 553 | reg.set_tsen(true); | ||
| 554 | }); | ||
| 555 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | ||
| 556 | T::common_regs().ccr().modify(|reg| { | ||
| 557 | reg.set_tsen(true); | ||
| 558 | }); | ||
| 559 | } else { | ||
| 560 | T::common_regs().ccr().modify(|reg| { | ||
| 561 | reg.set_ch17sel(true); | ||
| 562 | }); | ||
| 563 | } | ||
| 564 | } | ||
| 565 | |||
| 566 | Temperature {} | ||
| 655 | } | 567 | } |
| 656 | 568 | ||
| 657 | #[cfg(not(adc_g0))] | 569 | pub fn enable_vbat(&self) -> Vbat { |
| 658 | fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | ||
| 659 | cfg_if! { | 570 | cfg_if! { |
| 660 | if #[cfg(adc_u0)] { | 571 | if #[cfg(any(adc_g0, adc_u0))] { |
| 661 | // On G0 and U6 all channels use the same sampling time. | 572 | T::regs().ccr().modify(|reg| { |
| 662 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | 573 | reg.set_vbaten(true); |
| 574 | }); | ||
| 663 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | 575 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 664 | match _ch { | 576 | T::common_regs().ccr().modify(|reg| { |
| 665 | 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), | 577 | reg.set_vbaten(true); |
| 666 | _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), | 578 | }); |
| 667 | } | ||
| 668 | } else { | 579 | } else { |
| 669 | let sample_time = sample_time.into(); | 580 | T::common_regs().ccr().modify(|reg| { |
| 670 | T::regs() | 581 | reg.set_ch18sel(true); |
| 671 | .smpr(_ch as usize / 10) | 582 | }); |
| 672 | .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time)); | ||
| 673 | } | 583 | } |
| 674 | } | 584 | } |
| 585 | |||
| 586 | Vbat {} | ||
| 675 | } | 587 | } |
| 676 | 588 | ||
| 677 | fn cancel_conversions() { | 589 | pub fn disable_vbat(&self) { |
| 678 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 590 | cfg_if! { |
| 679 | T::regs().cr().modify(|reg| { | 591 | if #[cfg(any(adc_g0, adc_u0))] { |
| 680 | reg.set_adstp(true); | 592 | T::regs().ccr().modify(|reg| { |
| 681 | }); | 593 | reg.set_vbaten(false); |
| 682 | while T::regs().cr().read().adstart() {} | 594 | }); |
| 595 | } else if #[cfg(any(adc_h5, adc_h7rs))] { | ||
| 596 | T::common_regs().ccr().modify(|reg| { | ||
| 597 | reg.set_vbaten(false); | ||
| 598 | }); | ||
| 599 | } else { | ||
| 600 | T::common_regs().ccr().modify(|reg| { | ||
| 601 | reg.set_ch18sel(false); | ||
| 602 | }); | ||
| 603 | } | ||
| 683 | } | 604 | } |
| 684 | } | 605 | } |
| 606 | |||
| 607 | /* | ||
| 608 | /// Convert a raw sample from the `Temperature` to deg C | ||
| 609 | pub fn to_degrees_centigrade(sample: u16) -> f32 { | ||
| 610 | (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32) | ||
| 611 | * (sample as f32 - VtempCal30::get().read() as f32) | ||
| 612 | + 30.0 | ||
| 613 | } | ||
| 614 | */ | ||
| 685 | } | 615 | } |
