| 1 | #[cfg (not(stm32u5))] |
| 2 | use pac::adc::vals::{Adcaldif, Boost}; |
| 3 | #[allow (unused)] |
| 4 | use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; |
| 5 | use pac::adccommon::vals::Presc; |
| 6 | |
| 7 | use super::{ |
| 8 | blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, |
| 9 | }; |
| 10 | use crate::dma::Transfer; |
| 11 | use crate::time::Hertz; |
| 12 | use crate::{pac, rcc, Peripheral}; |
| 13 | |
| 14 | /// Default VREF voltage used for sample conversion to millivolts. |
| 15 | pub const VREF_DEFAULT_MV: u32 = 3300; |
| 16 | /// VREF voltage used for factory calibration of VREFINTCAL register. |
| 17 | pub const VREF_CALIB_MV: u32 = 3300; |
| 18 | |
| 19 | /// Max single ADC operation clock frequency |
| 20 | #[cfg (stm32g4)] |
| 21 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); |
| 22 | #[cfg (stm32h7)] |
| 23 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); |
| 24 | #[cfg (stm32u5)] |
| 25 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(megahertz:55); |
| 26 | |
| 27 | #[cfg (stm32g4)] |
| 28 | const VREF_CHANNEL: u8 = 18; |
| 29 | #[cfg (stm32g4)] |
| 30 | const TEMP_CHANNEL: u8 = 16; |
| 31 | |
| 32 | #[cfg (stm32h7)] |
| 33 | const VREF_CHANNEL: u8 = 19; |
| 34 | #[cfg (stm32h7)] |
| 35 | const TEMP_CHANNEL: u8 = 18; |
| 36 | |
| 37 | // TODO this should be 14 for H7a/b/35 |
| 38 | #[cfg (not(stm32u5))] |
| 39 | const VBAT_CHANNEL: u8 = 17; |
| 40 | |
| 41 | #[cfg (stm32u5)] |
| 42 | const VREF_CHANNEL: u8 = 0; |
| 43 | #[cfg (stm32u5)] |
| 44 | const TEMP_CHANNEL: u8 = 19; |
| 45 | #[cfg (stm32u5)] |
| 46 | const VBAT_CHANNEL: u8 = 18; |
| 47 | |
| 48 | // 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 |
| 49 | /// Internal voltage reference channel. |
| 50 | pub struct VrefInt; |
| 51 | impl<T: Instance> AdcChannel<T> for VrefInt {} |
| 52 | impl<T: Instance> SealedAdcChannel<T> for VrefInt { |
| 53 | fn channel(&self) -> u8 { |
| 54 | VREF_CHANNEL |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | /// Internal temperature channel. |
| 59 | pub struct Temperature; |
| 60 | impl<T: Instance> AdcChannel<T> for Temperature {} |
| 61 | impl<T: Instance> SealedAdcChannel<T> for Temperature { |
| 62 | fn channel(&self) -> u8 { |
| 63 | TEMP_CHANNEL |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | /// Internal battery voltage channel. |
| 68 | pub struct Vbat; |
| 69 | impl<T: Instance> AdcChannel<T> for Vbat {} |
| 70 | impl<T: Instance> SealedAdcChannel<T> for Vbat { |
| 71 | fn channel(&self) -> u8 { |
| 72 | VBAT_CHANNEL |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, |
| 77 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. |
| 78 | #[allow (unused)] |
| 79 | enum Prescaler { |
| 80 | NotDivided, |
| 81 | DividedBy2, |
| 82 | DividedBy4, |
| 83 | DividedBy6, |
| 84 | DividedBy8, |
| 85 | DividedBy10, |
| 86 | DividedBy12, |
| 87 | DividedBy16, |
| 88 | DividedBy32, |
| 89 | DividedBy64, |
| 90 | DividedBy128, |
| 91 | DividedBy256, |
| 92 | } |
| 93 | |
| 94 | impl Prescaler { |
| 95 | fn from_ker_ck(frequency: Hertz) -> Self { |
| 96 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 97 | match raw_prescaler { |
| 98 | 0 => Self::NotDivided, |
| 99 | 1 => Self::DividedBy2, |
| 100 | 2..=3 => Self::DividedBy4, |
| 101 | 4..=5 => Self::DividedBy6, |
| 102 | 6..=7 => Self::DividedBy8, |
| 103 | 8..=9 => Self::DividedBy10, |
| 104 | 10..=11 => Self::DividedBy12, |
| 105 | _ => unimplemented!(), |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | fn divisor(&self) -> u32 { |
| 110 | match self { |
| 111 | Prescaler::NotDivided => 1, |
| 112 | Prescaler::DividedBy2 => 2, |
| 113 | Prescaler::DividedBy4 => 4, |
| 114 | Prescaler::DividedBy6 => 6, |
| 115 | Prescaler::DividedBy8 => 8, |
| 116 | Prescaler::DividedBy10 => 10, |
| 117 | Prescaler::DividedBy12 => 12, |
| 118 | Prescaler::DividedBy16 => 16, |
| 119 | Prescaler::DividedBy32 => 32, |
| 120 | Prescaler::DividedBy64 => 64, |
| 121 | Prescaler::DividedBy128 => 128, |
| 122 | Prescaler::DividedBy256 => 256, |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | fn presc(&self) -> Presc { |
| 127 | match self { |
| 128 | Prescaler::NotDivided => Presc::DIV1, |
| 129 | Prescaler::DividedBy2 => Presc::DIV2, |
| 130 | Prescaler::DividedBy4 => Presc::DIV4, |
| 131 | Prescaler::DividedBy6 => Presc::DIV6, |
| 132 | Prescaler::DividedBy8 => Presc::DIV8, |
| 133 | Prescaler::DividedBy10 => Presc::DIV10, |
| 134 | Prescaler::DividedBy12 => Presc::DIV12, |
| 135 | Prescaler::DividedBy16 => Presc::DIV16, |
| 136 | Prescaler::DividedBy32 => Presc::DIV32, |
| 137 | Prescaler::DividedBy64 => Presc::DIV64, |
| 138 | Prescaler::DividedBy128 => Presc::DIV128, |
| 139 | Prescaler::DividedBy256 => Presc::DIV256, |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | /// Number of samples used for averaging. |
| 145 | pub enum Averaging { |
| 146 | Disabled, |
| 147 | Samples2, |
| 148 | Samples4, |
| 149 | Samples8, |
| 150 | Samples16, |
| 151 | Samples32, |
| 152 | Samples64, |
| 153 | Samples128, |
| 154 | Samples256, |
| 155 | Samples512, |
| 156 | Samples1024, |
| 157 | } |
| 158 | |
| 159 | impl<'d, T: Instance> Adc<'d, T> { |
| 160 | /// Create a new ADC driver. |
| 161 | pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { |
| 162 | embassy_hal_internal::into_ref!(adc); |
| 163 | rcc::enable_and_reset::<T>(); |
| 164 | |
| 165 | let prescaler = Prescaler::from_ker_ck(T::frequency()); |
| 166 | |
| 167 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); |
| 168 | |
| 169 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); |
| 170 | info!("ADC frequency set to {} Hz" , frequency.0); |
| 171 | |
| 172 | if frequency > MAX_ADC_CLK_FREQ { |
| 173 | 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 ); |
| 174 | } |
| 175 | |
| 176 | #[cfg (stm32h7)] |
| 177 | { |
| 178 | let boost = if frequency < Hertz::khz(6_250) { |
| 179 | Boost::LT6_25 |
| 180 | } else if frequency < Hertz::khz(12_500) { |
| 181 | Boost::LT12_5 |
| 182 | } else if frequency < Hertz::mhz(25) { |
| 183 | Boost::LT25 |
| 184 | } else { |
| 185 | Boost::LT50 |
| 186 | }; |
| 187 | T::regs().cr().modify(|w| w.set_boost(boost)); |
| 188 | } |
| 189 | let mut s = Self { |
| 190 | adc, |
| 191 | sample_time: SampleTime::from_bits(0), |
| 192 | }; |
| 193 | s.power_up(); |
| 194 | s.configure_differential_inputs(); |
| 195 | |
| 196 | s.calibrate(); |
| 197 | blocking_delay_us(1); |
| 198 | |
| 199 | s.enable(); |
| 200 | s.configure(); |
| 201 | |
| 202 | s |
| 203 | } |
| 204 | |
| 205 | fn power_up(&mut self) { |
| 206 | T::regs().cr().modify(|reg| { |
| 207 | reg.set_deeppwd(false); |
| 208 | reg.set_advregen(true); |
| 209 | }); |
| 210 | |
| 211 | blocking_delay_us(10); |
| 212 | } |
| 213 | |
| 214 | fn configure_differential_inputs(&mut self) { |
| 215 | T::regs().difsel().modify(|w| { |
| 216 | for n in 0..20 { |
| 217 | w.set_difsel(n, Difsel::SINGLE_ENDED); |
| 218 | } |
| 219 | }); |
| 220 | } |
| 221 | |
| 222 | fn calibrate(&mut self) { |
| 223 | T::regs().cr().modify(|w| { |
| 224 | #[cfg (not(adc_u5))] |
| 225 | w.set_adcaldif(Adcaldif::SINGLE_ENDED); |
| 226 | w.set_adcallin(true); |
| 227 | }); |
| 228 | |
| 229 | T::regs().cr().modify(|w| w.set_adcal(true)); |
| 230 | |
| 231 | while T::regs().cr().read().adcal() {} |
| 232 | } |
| 233 | |
| 234 | fn enable(&mut self) { |
| 235 | T::regs().isr().write(|w| w.set_adrdy(true)); |
| 236 | T::regs().cr().modify(|w| w.set_aden(true)); |
| 237 | while !T::regs().isr().read().adrdy() {} |
| 238 | T::regs().isr().write(|w| w.set_adrdy(true)); |
| 239 | } |
| 240 | |
| 241 | fn configure(&mut self) { |
| 242 | // single conversion mode, software trigger |
| 243 | T::regs().cfgr().modify(|w| { |
| 244 | w.set_cont(false); |
| 245 | w.set_exten(Exten::DISABLED); |
| 246 | }); |
| 247 | } |
| 248 | |
| 249 | /// Enable reading the voltage reference internal channel. |
| 250 | pub fn enable_vrefint(&self) -> VrefInt { |
| 251 | T::common_regs().ccr().modify(|reg| { |
| 252 | reg.set_vrefen(true); |
| 253 | }); |
| 254 | |
| 255 | VrefInt {} |
| 256 | } |
| 257 | |
| 258 | /// Enable reading the temperature internal channel. |
| 259 | pub fn enable_temperature(&self) -> Temperature { |
| 260 | T::common_regs().ccr().modify(|reg| { |
| 261 | reg.set_vsenseen(true); |
| 262 | }); |
| 263 | |
| 264 | Temperature {} |
| 265 | } |
| 266 | |
| 267 | /// Enable reading the vbat internal channel. |
| 268 | pub fn enable_vbat(&self) -> Vbat { |
| 269 | T::common_regs().ccr().modify(|reg| { |
| 270 | reg.set_vbaten(true); |
| 271 | }); |
| 272 | |
| 273 | Vbat {} |
| 274 | } |
| 275 | |
| 276 | /// Set the ADC sample time. |
| 277 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { |
| 278 | self.sample_time = sample_time; |
| 279 | } |
| 280 | |
| 281 | /// Get the ADC sample time. |
| 282 | pub fn sample_time(&self) -> SampleTime { |
| 283 | self.sample_time |
| 284 | } |
| 285 | |
| 286 | /// Set the ADC resolution. |
| 287 | pub fn set_resolution(&mut self, resolution: Resolution) { |
| 288 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); |
| 289 | } |
| 290 | |
| 291 | /// Set hardware averaging. |
| 292 | pub fn set_averaging(&mut self, averaging: Averaging) { |
| 293 | let (enable, samples, right_shift) = match averaging { |
| 294 | Averaging::Disabled => (false, 0, 0), |
| 295 | Averaging::Samples2 => (true, 1, 1), |
| 296 | Averaging::Samples4 => (true, 3, 2), |
| 297 | Averaging::Samples8 => (true, 7, 3), |
| 298 | Averaging::Samples16 => (true, 15, 4), |
| 299 | Averaging::Samples32 => (true, 31, 5), |
| 300 | Averaging::Samples64 => (true, 63, 6), |
| 301 | Averaging::Samples128 => (true, 127, 7), |
| 302 | Averaging::Samples256 => (true, 255, 8), |
| 303 | Averaging::Samples512 => (true, 511, 9), |
| 304 | Averaging::Samples1024 => (true, 1023, 10), |
| 305 | }; |
| 306 | |
| 307 | T::regs().cfgr2().modify(|reg| { |
| 308 | reg.set_rovse(enable); |
| 309 | reg.set_osvr(samples); |
| 310 | reg.set_ovss(right_shift); |
| 311 | }) |
| 312 | } |
| 313 | |
| 314 | /// Perform a single conversion. |
| 315 | fn convert(&mut self) -> u16 { |
| 316 | T::regs().isr().modify(|reg| { |
| 317 | reg.set_eos(true); |
| 318 | reg.set_eoc(true); |
| 319 | }); |
| 320 | |
| 321 | // Start conversion |
| 322 | T::regs().cr().modify(|reg| { |
| 323 | reg.set_adstart(true); |
| 324 | }); |
| 325 | |
| 326 | while !T::regs().isr().read().eos() { |
| 327 | // spin |
| 328 | } |
| 329 | |
| 330 | T::regs().dr().read().0 as u16 |
| 331 | } |
| 332 | |
| 333 | /// Read an ADC channel. |
| 334 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { |
| 335 | self.read_channel(channel) |
| 336 | } |
| 337 | |
| 338 | /// Read one or multiple ADC channels using DMA. |
| 339 | /// |
| 340 | /// `sequence` iterator and `readings` must have the same length. |
| 341 | /// |
| 342 | /// Example |
| 343 | /// ```rust,ignore |
| 344 | /// use embassy_stm32::adc::{Adc, AdcChannel} |
| 345 | /// |
| 346 | /// let mut adc = Adc::new(p.ADC1); |
| 347 | /// let mut adc_pin0 = p.PA0.degrade_adc(); |
| 348 | /// let mut adc_pin2 = p.PA2.degrade_adc(); |
| 349 | /// let mut measurements = [0u16; 2]; |
| 350 | /// |
| 351 | /// adc.read_async( |
| 352 | /// p.DMA2_CH0, |
| 353 | /// [ |
| 354 | /// (&mut *adc_pin0, SampleTime::CYCLES112), |
| 355 | /// (&mut *adc_pin2, SampleTime::CYCLES112), |
| 356 | /// ] |
| 357 | /// .into_iter(), |
| 358 | /// &mut measurements, |
| 359 | /// ) |
| 360 | /// .await; |
| 361 | /// defmt::info!("measurements: {}" , measurements); |
| 362 | /// ``` |
| 363 | pub async fn read( |
| 364 | &mut self, |
| 365 | rx_dma: &mut impl RxDma<T>, |
| 366 | sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, |
| 367 | readings: &mut [u16], |
| 368 | ) { |
| 369 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty" ); |
| 370 | assert!( |
| 371 | sequence.len() == readings.len(), |
| 372 | "Sequence length must be equal to readings length" |
| 373 | ); |
| 374 | assert!( |
| 375 | sequence.len() <= 16, |
| 376 | "Asynchronous read sequence cannot be more than 16 in length" |
| 377 | ); |
| 378 | |
| 379 | // Ensure no conversions are ongoing |
| 380 | Self::cancel_conversions(); |
| 381 | |
| 382 | // Set sequence length |
| 383 | T::regs().sqr1().modify(|w| { |
| 384 | w.set_l(sequence.len() as u8 - 1); |
| 385 | }); |
| 386 | |
| 387 | // Configure channels and ranks |
| 388 | for (i, (channel, sample_time)) in sequence.enumerate() { |
| 389 | Self::configure_channel(channel, sample_time); |
| 390 | match i { |
| 391 | 0..=3 => { |
| 392 | T::regs().sqr1().modify(|w| { |
| 393 | w.set_sq(i, channel.channel()); |
| 394 | }); |
| 395 | } |
| 396 | 4..=8 => { |
| 397 | T::regs().sqr2().modify(|w| { |
| 398 | w.set_sq(i - 4, channel.channel()); |
| 399 | }); |
| 400 | } |
| 401 | 9..=13 => { |
| 402 | T::regs().sqr3().modify(|w| { |
| 403 | w.set_sq(i - 9, channel.channel()); |
| 404 | }); |
| 405 | } |
| 406 | 14..=15 => { |
| 407 | T::regs().sqr4().modify(|w| { |
| 408 | w.set_sq(i - 14, channel.channel()); |
| 409 | }); |
| 410 | } |
| 411 | _ => unreachable!(), |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | // Set continuous mode with oneshot dma. |
| 416 | // Clear overrun flag before starting transfer. |
| 417 | |
| 418 | T::regs().isr().modify(|reg| { |
| 419 | reg.set_ovr(true); |
| 420 | }); |
| 421 | T::regs().cfgr().modify(|reg| { |
| 422 | reg.set_cont(true); |
| 423 | reg.set_dmngt(Dmngt::DMA_ONE_SHOT); |
| 424 | }); |
| 425 | |
| 426 | let request = rx_dma.request(); |
| 427 | let transfer = unsafe { |
| 428 | Transfer::new_read( |
| 429 | rx_dma, |
| 430 | request, |
| 431 | T::regs().dr().as_ptr() as *mut u16, |
| 432 | readings, |
| 433 | Default::default(), |
| 434 | ) |
| 435 | }; |
| 436 | |
| 437 | // Start conversion |
| 438 | T::regs().cr().modify(|reg| { |
| 439 | reg.set_adstart(true); |
| 440 | }); |
| 441 | |
| 442 | // Wait for conversion sequence to finish. |
| 443 | transfer.await; |
| 444 | |
| 445 | // Ensure conversions are finished. |
| 446 | Self::cancel_conversions(); |
| 447 | |
| 448 | // Reset configuration. |
| 449 | T::regs().cfgr().modify(|reg| { |
| 450 | reg.set_cont(false); |
| 451 | reg.set_dmngt(Dmngt::from_bits(0)); |
| 452 | }); |
| 453 | } |
| 454 | |
| 455 | fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { |
| 456 | channel.setup(); |
| 457 | |
| 458 | let channel = channel.channel(); |
| 459 | |
| 460 | Self::set_channel_sample_time(channel, sample_time); |
| 461 | |
| 462 | #[cfg (any(stm32h7, stm32u5))] |
| 463 | { |
| 464 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); |
| 465 | T::regs() |
| 466 | .pcsel() |
| 467 | .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); |
| 468 | } |
| 469 | } |
| 470 | |
| 471 | fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { |
| 472 | Self::configure_channel(channel, self.sample_time); |
| 473 | |
| 474 | T::regs().sqr1().modify(|reg| { |
| 475 | reg.set_sq(0, channel.channel()); |
| 476 | reg.set_l(0); |
| 477 | }); |
| 478 | |
| 479 | self.convert() |
| 480 | } |
| 481 | |
| 482 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 483 | let sample_time = sample_time.into(); |
| 484 | if ch <= 9 { |
| 485 | T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); |
| 486 | } else { |
| 487 | T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); |
| 488 | } |
| 489 | } |
| 490 | |
| 491 | fn cancel_conversions() { |
| 492 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { |
| 493 | T::regs().cr().modify(|reg| { |
| 494 | reg.set_adstp(Adstp::STOP); |
| 495 | }); |
| 496 | while T::regs().cr().read().adstart() {} |
| 497 | } |
| 498 | } |
| 499 | } |
| 500 | |