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