diff options
Diffstat (limited to 'embassy-stm32/src/adc/g4.rs')
| -rw-r--r-- | embassy-stm32/src/adc/g4.rs | 788 |
1 files changed, 401 insertions, 387 deletions
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 43498966f..e93ed945f 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -1,175 +1,275 @@ | |||
| 1 | #[cfg(stm32g4)] | ||
| 2 | use pac::adc::regs::Difsel as DifselReg; | ||
| 3 | #[allow(unused)] | ||
| 4 | #[cfg(stm32g4)] | ||
| 5 | pub use pac::adc::vals::{Adcaldif, Adstp, Difsel, Dmacfg, Dmaen, Exten, Rovsm, Trovs}; | ||
| 1 | #[allow(unused)] | 6 | #[allow(unused)] |
| 2 | #[cfg(stm32h7)] | 7 | #[cfg(stm32h7)] |
| 3 | use pac::adc::vals::{Adcaldif, Difsel, Exten}; | 8 | use pac::adc::vals::{Adcaldif, Difsel, Exten}; |
| 4 | #[allow(unused)] | 9 | pub use pac::adccommon::vals::{Dual, Presc}; |
| 5 | #[cfg(stm32g4)] | 10 | |
| 6 | use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; | 11 | use super::{ |
| 7 | use pac::adccommon::vals::Presc; | 12 | Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime, |
| 8 | use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; | 13 | blocking_delay_us, |
| 9 | 14 | }; | |
| 10 | use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; | 15 | use crate::adc::{AdcRegs, BasicAdcRegs, SealedAdcChannel}; |
| 11 | use crate::adc::SealedAdcChannel; | 16 | use crate::pac::adc::regs::{Smpr, Smpr2, Sqr1, Sqr2, Sqr3, Sqr4}; |
| 12 | use crate::dma::Transfer; | ||
| 13 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| 14 | use crate::{pac, rcc, Peri}; | 18 | use crate::{Peri, pac, rcc}; |
| 19 | |||
| 20 | mod injected; | ||
| 21 | pub use injected::InjectedAdc; | ||
| 15 | 22 | ||
| 16 | /// Default VREF voltage used for sample conversion to millivolts. | 23 | /// Default VREF voltage used for sample conversion to millivolts. |
| 17 | pub const VREF_DEFAULT_MV: u32 = 3300; | 24 | pub const VREF_DEFAULT_MV: u32 = 3300; |
| 18 | /// VREF voltage used for factory calibration of VREFINTCAL register. | 25 | /// VREF voltage used for factory calibration of VREFINTCAL register. |
| 19 | pub const VREF_CALIB_MV: u32 = 3300; | 26 | pub const VREF_CALIB_MV: u32 = 3300; |
| 20 | 27 | ||
| 28 | const NR_INJECTED_RANKS: usize = 4; | ||
| 29 | |||
| 21 | /// Max single ADC operation clock frequency | 30 | /// Max single ADC operation clock frequency |
| 22 | #[cfg(stm32g4)] | 31 | #[cfg(stm32g4)] |
| 23 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); | 32 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); |
| 24 | #[cfg(stm32h7)] | 33 | #[cfg(stm32h7)] |
| 25 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); | 34 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); |
| 26 | 35 | ||
| 27 | // 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 | 36 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 28 | /// Internal voltage reference channel. | 37 | let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0); |
| 29 | pub struct VrefInt; | 38 | match raw_prescaler { |
| 30 | impl<T: Instance + VrefChannel> AdcChannel<T> for VrefInt {} | 39 | 0 => Presc::DIV1, |
| 31 | impl<T: Instance + VrefChannel> super::SealedAdcChannel<T> for VrefInt { | 40 | 1 => Presc::DIV2, |
| 32 | fn channel(&self) -> u8 { | 41 | 2..=3 => Presc::DIV4, |
| 33 | T::CHANNEL | 42 | 4..=5 => Presc::DIV6, |
| 43 | 6..=7 => Presc::DIV8, | ||
| 44 | 8..=9 => Presc::DIV10, | ||
| 45 | 10..=11 => Presc::DIV12, | ||
| 46 | _ => unimplemented!(), | ||
| 34 | } | 47 | } |
| 35 | } | 48 | } |
| 36 | 49 | ||
| 37 | /// Internal temperature channel. | 50 | /// ADC configuration |
| 38 | pub struct Temperature; | 51 | #[derive(Default)] |
| 39 | impl<T: Instance + TemperatureChannel> AdcChannel<T> for Temperature {} | 52 | pub struct AdcConfig { |
| 40 | impl<T: Instance + TemperatureChannel> super::SealedAdcChannel<T> for Temperature { | 53 | pub dual_mode: Option<Dual>, |
| 41 | fn channel(&self) -> u8 { | 54 | pub resolution: Option<Resolution>, |
| 42 | T::CHANNEL | 55 | #[cfg(stm32g4)] |
| 43 | } | 56 | pub oversampling_shift: Option<u8>, |
| 57 | #[cfg(stm32g4)] | ||
| 58 | pub oversampling_ratio: Option<u8>, | ||
| 59 | #[cfg(stm32g4)] | ||
| 60 | pub oversampling_mode: Option<(Rovsm, Trovs, bool)>, | ||
| 44 | } | 61 | } |
| 45 | 62 | ||
| 46 | /// Internal battery voltage channel. | 63 | // Trigger source for ADC conversions¨ |
| 47 | pub struct Vbat; | 64 | #[derive(Copy, Clone)] |
| 48 | impl<T: Instance + VBatChannel> AdcChannel<T> for Vbat {} | 65 | pub struct ConversionTrigger { |
| 49 | impl<T: Instance + VBatChannel> super::SealedAdcChannel<T> for Vbat { | 66 | // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers |
| 50 | fn channel(&self) -> u8 { | 67 | // Note that Injected and Regular channels uses different mappings |
| 51 | T::CHANNEL | 68 | pub channel: u8, |
| 52 | } | 69 | pub edge: Exten, |
| 53 | } | 70 | } |
| 54 | 71 | ||
| 55 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, | 72 | impl super::AdcRegs for crate::pac::adc::Adc { |
| 56 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. | 73 | fn data(&self) -> *mut u16 { |
| 57 | #[allow(unused)] | 74 | crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 |
| 58 | enum Prescaler { | 75 | } |
| 59 | NotDivided, | 76 | |
| 60 | DividedBy2, | 77 | fn enable(&self) { |
| 61 | DividedBy4, | 78 | // Make sure bits are off |
| 62 | DividedBy6, | 79 | while self.cr().read().addis() { |
| 63 | DividedBy8, | 80 | // spin |
| 64 | DividedBy10, | 81 | } |
| 65 | DividedBy12, | 82 | |
| 66 | DividedBy16, | 83 | if !self.cr().read().aden() { |
| 67 | DividedBy32, | 84 | // Enable ADC |
| 68 | DividedBy64, | 85 | self.isr().modify(|reg| { |
| 69 | DividedBy128, | 86 | reg.set_adrdy(true); |
| 70 | DividedBy256, | 87 | }); |
| 71 | } | 88 | self.cr().modify(|reg| { |
| 89 | reg.set_aden(true); | ||
| 90 | }); | ||
| 72 | 91 | ||
| 73 | impl Prescaler { | 92 | while !self.isr().read().adrdy() { |
| 74 | fn from_ker_ck(frequency: Hertz) -> Self { | 93 | // spin |
| 75 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | 94 | } |
| 76 | match raw_prescaler { | ||
| 77 | 0 => Self::NotDivided, | ||
| 78 | 1 => Self::DividedBy2, | ||
| 79 | 2..=3 => Self::DividedBy4, | ||
| 80 | 4..=5 => Self::DividedBy6, | ||
| 81 | 6..=7 => Self::DividedBy8, | ||
| 82 | 8..=9 => Self::DividedBy10, | ||
| 83 | 10..=11 => Self::DividedBy12, | ||
| 84 | _ => unimplemented!(), | ||
| 85 | } | 95 | } |
| 86 | } | 96 | } |
| 87 | 97 | ||
| 88 | fn divisor(&self) -> u32 { | 98 | fn start(&self) { |
| 89 | match self { | 99 | self.cr().modify(|reg| { |
| 90 | Prescaler::NotDivided => 1, | 100 | reg.set_adstart(true); |
| 91 | Prescaler::DividedBy2 => 2, | 101 | }); |
| 92 | Prescaler::DividedBy4 => 4, | 102 | } |
| 93 | Prescaler::DividedBy6 => 6, | 103 | |
| 94 | Prescaler::DividedBy8 => 8, | 104 | fn stop(&self) { |
| 95 | Prescaler::DividedBy10 => 10, | 105 | if self.cr().read().adstart() && !self.cr().read().addis() { |
| 96 | Prescaler::DividedBy12 => 12, | 106 | self.cr().modify(|reg| { |
| 97 | Prescaler::DividedBy16 => 16, | 107 | reg.set_adstp(Adstp::STOP); |
| 98 | Prescaler::DividedBy32 => 32, | 108 | }); |
| 99 | Prescaler::DividedBy64 => 64, | 109 | // The software must poll ADSTART until the bit is reset before assuming the |
| 100 | Prescaler::DividedBy128 => 128, | 110 | // ADC is completely stopped |
| 101 | Prescaler::DividedBy256 => 256, | 111 | while self.cr().read().adstart() {} |
| 102 | } | 112 | } |
| 113 | |||
| 114 | // Disable dma control and continuous conversion, if enabled | ||
| 115 | self.cfgr().modify(|reg| { | ||
| 116 | reg.set_cont(false); | ||
| 117 | reg.set_dmaen(Dmaen::DISABLE); | ||
| 118 | }); | ||
| 103 | } | 119 | } |
| 104 | 120 | ||
| 105 | fn presc(&self) -> Presc { | 121 | fn convert(&self) { |
| 106 | match self { | 122 | self.isr().modify(|reg| { |
| 107 | Prescaler::NotDivided => Presc::DIV1, | 123 | reg.set_eos(true); |
| 108 | Prescaler::DividedBy2 => Presc::DIV2, | 124 | reg.set_eoc(true); |
| 109 | Prescaler::DividedBy4 => Presc::DIV4, | 125 | }); |
| 110 | Prescaler::DividedBy6 => Presc::DIV6, | 126 | |
| 111 | Prescaler::DividedBy8 => Presc::DIV8, | 127 | // Start conversion |
| 112 | Prescaler::DividedBy10 => Presc::DIV10, | 128 | self.cr().modify(|reg| { |
| 113 | Prescaler::DividedBy12 => Presc::DIV12, | 129 | reg.set_adstart(true); |
| 114 | Prescaler::DividedBy16 => Presc::DIV16, | 130 | }); |
| 115 | Prescaler::DividedBy32 => Presc::DIV32, | 131 | |
| 116 | Prescaler::DividedBy64 => Presc::DIV64, | 132 | while !self.isr().read().eos() { |
| 117 | Prescaler::DividedBy128 => Presc::DIV128, | 133 | // spin |
| 118 | Prescaler::DividedBy256 => Presc::DIV256, | ||
| 119 | } | 134 | } |
| 120 | } | 135 | } |
| 121 | } | ||
| 122 | 136 | ||
| 123 | impl<'d, T: Instance> Adc<'d, T> { | 137 | fn configure_dma(&self, conversion_mode: ConversionMode) { |
| 124 | /// Create a new ADC driver. | 138 | self.isr().modify(|reg| { |
| 125 | pub fn new(adc: Peri<'d, T>) -> Self { | 139 | reg.set_ovr(true); |
| 126 | rcc::enable_and_reset::<T>(); | 140 | }); |
| 127 | 141 | ||
| 128 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 142 | self.cfgr().modify(|reg| { |
| 143 | reg.set_discen(false); // Convert all channels for each trigger | ||
| 144 | reg.set_dmacfg(match conversion_mode { | ||
| 145 | ConversionMode::Singular => Dmacfg::ONE_SHOT, | ||
| 146 | ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, | ||
| 147 | }); | ||
| 148 | reg.set_dmaen(Dmaen::ENABLE); | ||
| 149 | }); | ||
| 129 | 150 | ||
| 130 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 151 | if let ConversionMode::Repeated(mode) = conversion_mode { |
| 152 | match mode { | ||
| 153 | RegularConversionMode::Continuous => { | ||
| 154 | self.cfgr().modify(|reg| { | ||
| 155 | reg.set_cont(true); | ||
| 156 | }); | ||
| 157 | } | ||
| 158 | RegularConversionMode::Triggered(trigger) => { | ||
| 159 | self.cfgr().modify(|r| { | ||
| 160 | r.set_cont(false); // New trigger is neede for each sample to be read | ||
| 161 | }); | ||
| 131 | 162 | ||
| 132 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 163 | self.cfgr().modify(|r| { |
| 133 | trace!("ADC frequency set to {}", frequency); | 164 | r.set_extsel(trigger.channel); |
| 165 | r.set_exten(trigger.edge); | ||
| 166 | }); | ||
| 134 | 167 | ||
| 135 | if frequency > MAX_ADC_CLK_FREQ { | 168 | // Regular conversions uses DMA so no need to generate interrupt |
| 136 | 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 ); | 169 | self.ier().modify(|r| r.set_eosie(false)); |
| 170 | } | ||
| 171 | } | ||
| 137 | } | 172 | } |
| 173 | } | ||
| 138 | 174 | ||
| 139 | let mut s = Self { | 175 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) { |
| 140 | adc, | 176 | self.cr().modify(|w| w.set_aden(false)); |
| 141 | sample_time: SampleTime::from_bits(0), | ||
| 142 | }; | ||
| 143 | s.power_up(); | ||
| 144 | s.configure_differential_inputs(); | ||
| 145 | 177 | ||
| 146 | s.calibrate(); | 178 | #[cfg(stm32g4)] |
| 147 | blocking_delay_us(1); | 179 | let mut difsel = DifselReg::default(); |
| 180 | let mut smpr = Smpr::default(); | ||
| 181 | let mut smpr2 = Smpr2::default(); | ||
| 182 | let mut sqr1 = Sqr1::default(); | ||
| 183 | let mut sqr2 = Sqr2::default(); | ||
| 184 | let mut sqr3 = Sqr3::default(); | ||
| 185 | let mut sqr4 = Sqr4::default(); | ||
| 186 | |||
| 187 | // Set sequence length | ||
| 188 | sqr1.set_l(sequence.len() as u8 - 1); | ||
| 189 | |||
| 190 | // Configure channels and ranks | ||
| 191 | for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() { | ||
| 192 | let sample_time = sample_time.into(); | ||
| 193 | if ch <= 9 { | ||
| 194 | smpr.set_smp(ch as _, sample_time); | ||
| 195 | } else { | ||
| 196 | smpr2.set_smp((ch - 10) as _, sample_time); | ||
| 197 | } | ||
| 198 | |||
| 199 | match _i { | ||
| 200 | 0..=3 => { | ||
| 201 | sqr1.set_sq(_i, ch); | ||
| 202 | } | ||
| 203 | 4..=8 => { | ||
| 204 | sqr2.set_sq(_i - 4, ch); | ||
| 205 | } | ||
| 206 | 9..=13 => { | ||
| 207 | sqr3.set_sq(_i - 9, ch); | ||
| 208 | } | ||
| 209 | 14..=15 => { | ||
| 210 | sqr4.set_sq(_i - 14, ch); | ||
| 211 | } | ||
| 212 | _ => unreachable!(), | ||
| 213 | } | ||
| 148 | 214 | ||
| 149 | s.enable(); | 215 | #[cfg(stm32g4)] |
| 150 | s.configure(); | 216 | { |
| 217 | if ch < 18 { | ||
| 218 | difsel.set_difsel( | ||
| 219 | ch.into(), | ||
| 220 | if is_differential { | ||
| 221 | Difsel::DIFFERENTIAL | ||
| 222 | } else { | ||
| 223 | Difsel::SINGLE_ENDED | ||
| 224 | }, | ||
| 225 | ); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| 151 | 229 | ||
| 152 | s | 230 | self.smpr().write_value(smpr); |
| 231 | self.smpr2().write_value(smpr2); | ||
| 232 | self.sqr1().write_value(sqr1); | ||
| 233 | self.sqr2().write_value(sqr2); | ||
| 234 | self.sqr3().write_value(sqr3); | ||
| 235 | self.sqr4().write_value(sqr4); | ||
| 236 | #[cfg(stm32g4)] | ||
| 237 | self.difsel().write_value(difsel); | ||
| 153 | } | 238 | } |
| 239 | } | ||
| 240 | |||
| 241 | impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> { | ||
| 242 | /// Create a new ADC driver. | ||
| 243 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { | ||
| 244 | rcc::enable_and_reset::<T>(); | ||
| 245 | |||
| 246 | let prescaler = from_ker_ck(T::frequency()); | ||
| 247 | |||
| 248 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); | ||
| 249 | |||
| 250 | let frequency = T::frequency() / prescaler; | ||
| 251 | trace!("ADC frequency set to {}", frequency); | ||
| 252 | |||
| 253 | if frequency > MAX_ADC_CLK_FREQ { | ||
| 254 | panic!( | ||
| 255 | "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", | ||
| 256 | MAX_ADC_CLK_FREQ.0 / 1_000_000 | ||
| 257 | ); | ||
| 258 | } | ||
| 154 | 259 | ||
| 155 | fn power_up(&mut self) { | ||
| 156 | T::regs().cr().modify(|reg| { | 260 | T::regs().cr().modify(|reg| { |
| 157 | reg.set_deeppwd(false); | 261 | reg.set_deeppwd(false); |
| 158 | reg.set_advregen(true); | 262 | reg.set_advregen(true); |
| 159 | }); | 263 | }); |
| 160 | 264 | ||
| 161 | blocking_delay_us(20); | 265 | blocking_delay_us(20); |
| 162 | } | ||
| 163 | 266 | ||
| 164 | fn configure_differential_inputs(&mut self) { | ||
| 165 | T::regs().difsel().modify(|w| { | 267 | T::regs().difsel().modify(|w| { |
| 166 | for n in 0..18 { | 268 | for n in 0..18 { |
| 167 | w.set_difsel(n, Difsel::SINGLE_ENDED); | 269 | w.set_difsel(n, Difsel::SINGLE_ENDED); |
| 168 | } | 270 | } |
| 169 | }); | 271 | }); |
| 170 | } | ||
| 171 | 272 | ||
| 172 | fn calibrate(&mut self) { | ||
| 173 | T::regs().cr().modify(|w| { | 273 | T::regs().cr().modify(|w| { |
| 174 | w.set_adcaldif(Adcaldif::SINGLE_ENDED); | 274 | w.set_adcaldif(Adcaldif::SINGLE_ENDED); |
| 175 | }); | 275 | }); |
| @@ -189,120 +289,79 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 189 | while T::regs().cr().read().adcal() {} | 289 | while T::regs().cr().read().adcal() {} |
| 190 | 290 | ||
| 191 | blocking_delay_us(20); | 291 | blocking_delay_us(20); |
| 192 | } | ||
| 193 | 292 | ||
| 194 | fn enable(&mut self) { | 293 | T::regs().enable(); |
| 195 | // Make sure bits are off | ||
| 196 | while T::regs().cr().read().addis() { | ||
| 197 | // spin | ||
| 198 | } | ||
| 199 | |||
| 200 | if !T::regs().cr().read().aden() { | ||
| 201 | // Enable ADC | ||
| 202 | T::regs().isr().modify(|reg| { | ||
| 203 | reg.set_adrdy(true); | ||
| 204 | }); | ||
| 205 | T::regs().cr().modify(|reg| { | ||
| 206 | reg.set_aden(true); | ||
| 207 | }); | ||
| 208 | |||
| 209 | while !T::regs().isr().read().adrdy() { | ||
| 210 | // spin | ||
| 211 | } | ||
| 212 | } | ||
| 213 | } | ||
| 214 | 294 | ||
| 215 | fn configure(&mut self) { | ||
| 216 | // single conversion mode, software trigger | 295 | // single conversion mode, software trigger |
| 217 | T::regs().cfgr().modify(|w| { | 296 | T::regs().cfgr().modify(|w| { |
| 218 | w.set_cont(false); | 297 | w.set_cont(false); |
| 219 | w.set_exten(Exten::DISABLED); | 298 | w.set_exten(Exten::DISABLED); |
| 220 | }); | 299 | }); |
| 300 | |||
| 301 | if let Some(dual) = config.dual_mode { | ||
| 302 | T::common_regs().ccr().modify(|reg| { | ||
| 303 | reg.set_dual(dual); | ||
| 304 | }) | ||
| 305 | } | ||
| 306 | |||
| 307 | if let Some(resolution) = config.resolution { | ||
| 308 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 309 | } | ||
| 310 | |||
| 311 | #[cfg(stm32g4)] | ||
| 312 | if let Some(shift) = config.oversampling_shift { | ||
| 313 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 314 | } | ||
| 315 | |||
| 316 | #[cfg(stm32g4)] | ||
| 317 | if let Some(ratio) = config.oversampling_ratio { | ||
| 318 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | ||
| 319 | } | ||
| 320 | |||
| 321 | #[cfg(stm32g4)] | ||
| 322 | if let Some((mode, trig_mode, enable)) = config.oversampling_mode { | ||
| 323 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); | ||
| 324 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); | ||
| 325 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); | ||
| 326 | } | ||
| 327 | |||
| 328 | Self { adc } | ||
| 221 | } | 329 | } |
| 222 | 330 | ||
| 223 | /// Enable reading the voltage reference internal channel. | 331 | /// Enable reading the voltage reference internal channel. |
| 224 | pub fn enable_vrefint(&self) -> VrefInt | 332 | pub fn enable_vrefint(&self) -> super::VrefInt |
| 225 | where | 333 | where |
| 226 | T: VrefChannel, | 334 | T: super::SpecialConverter<super::VrefInt>, |
| 227 | { | 335 | { |
| 228 | T::common_regs().ccr().modify(|reg| { | 336 | T::common_regs().ccr().modify(|reg| { |
| 229 | reg.set_vrefen(true); | 337 | reg.set_vrefen(true); |
| 230 | }); | 338 | }); |
| 231 | 339 | ||
| 232 | VrefInt {} | 340 | super::VrefInt {} |
| 233 | } | 341 | } |
| 234 | 342 | ||
| 235 | /// Enable reading the temperature internal channel. | 343 | /// Enable reading the temperature internal channel. |
| 236 | pub fn enable_temperature(&self) -> Temperature | 344 | pub fn enable_temperature(&self) -> super::Temperature |
| 237 | where | 345 | where |
| 238 | T: TemperatureChannel, | 346 | T: super::SpecialConverter<super::Temperature>, |
| 239 | { | 347 | { |
| 240 | T::common_regs().ccr().modify(|reg| { | 348 | T::common_regs().ccr().modify(|reg| { |
| 241 | reg.set_vsenseen(true); | 349 | reg.set_vsenseen(true); |
| 242 | }); | 350 | }); |
| 243 | 351 | ||
| 244 | Temperature {} | 352 | super::Temperature {} |
| 245 | } | 353 | } |
| 246 | 354 | ||
| 247 | /// Enable reading the vbat internal channel. | 355 | /// Enable reading the vbat internal channel. |
| 248 | pub fn enable_vbat(&self) -> Vbat | 356 | pub fn enable_vbat(&self) -> super::Vbat |
| 249 | where | 357 | where |
| 250 | T: VBatChannel, | 358 | T: super::SpecialConverter<super::Vbat>, |
| 251 | { | 359 | { |
| 252 | T::common_regs().ccr().modify(|reg| { | 360 | T::common_regs().ccr().modify(|reg| { |
| 253 | reg.set_vbaten(true); | 361 | reg.set_vbaten(true); |
| 254 | }); | 362 | }); |
| 255 | 363 | ||
| 256 | Vbat {} | 364 | super::Vbat {} |
| 257 | } | ||
| 258 | |||
| 259 | /// Enable differential channel. | ||
| 260 | /// Caution: | ||
| 261 | /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i] | ||
| 262 | /// is connected to another channel. As a consequence, this channel is no longer usable in | ||
| 263 | /// single-ended mode or in differential mode and must never be configured to be converted. | ||
| 264 | /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the | ||
| 265 | /// channel on the other ADC unusable. The only exception is when ADC master and the slave | ||
| 266 | /// operate in interleaved mode. | ||
| 267 | #[cfg(stm32g4)] | ||
| 268 | pub fn set_differential_channel(&mut self, ch: usize, enable: bool) { | ||
| 269 | T::regs().cr().modify(|w| w.set_aden(false)); // disable adc | ||
| 270 | T::regs().difsel().modify(|w| { | ||
| 271 | w.set_difsel( | ||
| 272 | ch, | ||
| 273 | if enable { | ||
| 274 | Difsel::DIFFERENTIAL | ||
| 275 | } else { | ||
| 276 | Difsel::SINGLE_ENDED | ||
| 277 | }, | ||
| 278 | ); | ||
| 279 | }); | ||
| 280 | T::regs().cr().modify(|w| w.set_aden(true)); | ||
| 281 | } | ||
| 282 | |||
| 283 | #[cfg(stm32g4)] | ||
| 284 | pub fn set_differential(&mut self, channel: &mut impl AdcChannel<T>, enable: bool) { | ||
| 285 | self.set_differential_channel(channel.channel() as usize, enable); | ||
| 286 | } | ||
| 287 | |||
| 288 | /// Set oversampling shift. | ||
| 289 | #[cfg(stm32g4)] | ||
| 290 | pub fn set_oversampling_shift(&mut self, shift: u8) { | ||
| 291 | T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Set oversampling ratio. | ||
| 295 | #[cfg(stm32g4)] | ||
| 296 | pub fn set_oversampling_ratio(&mut self, ratio: u8) { | ||
| 297 | T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); | ||
| 298 | } | ||
| 299 | |||
| 300 | /// Enable oversampling in regular mode. | ||
| 301 | #[cfg(stm32g4)] | ||
| 302 | pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) { | ||
| 303 | T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); | ||
| 304 | T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); | ||
| 305 | T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); | ||
| 306 | } | 365 | } |
| 307 | 366 | ||
| 308 | // Reads that are not implemented as INJECTED in "blocking_read" | 367 | // Reads that are not implemented as INJECTED in "blocking_read" |
| @@ -318,260 +377,215 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 318 | // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); | 377 | // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); |
| 319 | // } | 378 | // } |
| 320 | 379 | ||
| 321 | /// Set the ADC sample time. | 380 | /// Configures the ADC for injected conversions. |
| 322 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | ||
| 323 | self.sample_time = sample_time; | ||
| 324 | } | ||
| 325 | |||
| 326 | /// Set the ADC resolution. | ||
| 327 | pub fn set_resolution(&mut self, resolution: Resolution) { | ||
| 328 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Perform a single conversion. | ||
| 332 | fn convert(&mut self) -> u16 { | ||
| 333 | T::regs().isr().modify(|reg| { | ||
| 334 | reg.set_eos(true); | ||
| 335 | reg.set_eoc(true); | ||
| 336 | }); | ||
| 337 | |||
| 338 | // Start conversion | ||
| 339 | T::regs().cr().modify(|reg| { | ||
| 340 | reg.set_adstart(true); | ||
| 341 | }); | ||
| 342 | |||
| 343 | while !T::regs().isr().read().eos() { | ||
| 344 | // spin | ||
| 345 | } | ||
| 346 | |||
| 347 | T::regs().dr().read().0 as u16 | ||
| 348 | } | ||
| 349 | |||
| 350 | /// Read an ADC pin. | ||
| 351 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { | ||
| 352 | channel.setup(); | ||
| 353 | |||
| 354 | self.read_channel(channel) | ||
| 355 | } | ||
| 356 | |||
| 357 | /// Read one or multiple ADC channels using DMA. | ||
| 358 | /// | 381 | /// |
| 359 | /// `sequence` iterator and `readings` must have the same length. | 382 | /// Injected conversions are separate from the regular conversion sequence and are typically |
| 383 | /// triggered by software or an external event. This method sets up a fixed-length sequence of | ||
| 384 | /// injected channels with specified sample times, the trigger source, and whether the end-of-sequence | ||
| 385 | /// interrupt should be enabled. | ||
| 360 | /// | 386 | /// |
| 361 | /// Example | 387 | /// # Parameters |
| 362 | /// ```rust,ignore | 388 | /// - `sequence`: An array of tuples containing the ADC channels and their sample times. The length |
| 363 | /// use embassy_stm32::adc::{Adc, AdcChannel} | 389 | /// `N` determines the number of injected ranks to configure (maximum 4 for STM32). |
| 390 | /// - `trigger`: The trigger source that starts the injected conversion sequence. | ||
| 391 | /// - `interrupt`: If `true`, enables the end-of-sequence (JEOS) interrupt for injected conversions. | ||
| 364 | /// | 392 | /// |
| 365 | /// let mut adc = Adc::new(p.ADC1); | 393 | /// # Returns |
| 366 | /// let mut adc_pin0 = p.PA0.into(); | 394 | /// An `InjectedAdc<T, N>` instance that represents the configured injected sequence. The returned |
| 367 | /// let mut adc_pin1 = p.PA1.into(); | 395 | /// type encodes the sequence length `N` in its type, ensuring that reads return exactly `N` samples. |
| 368 | /// let mut measurements = [0u16; 2]; | ||
| 369 | /// | 396 | /// |
| 370 | /// adc.read( | 397 | /// # Panics |
| 371 | /// p.DMA1_CH2.reborrow(), | 398 | /// This function will panic if: |
| 372 | /// [ | 399 | /// - `sequence` is empty. |
| 373 | /// (&mut *adc_pin0, SampleTime::CYCLES160_5), | 400 | /// - `sequence` length exceeds the maximum number of injected ranks (`NR_INJECTED_RANKS`). |
| 374 | /// (&mut *adc_pin1, SampleTime::CYCLES160_5), | 401 | /// |
| 375 | /// ] | 402 | /// # Notes |
| 376 | /// .into_iter(), | 403 | /// - Injected conversions can run independently of regular ADC conversions. |
| 377 | /// &mut measurements, | 404 | /// - The order of channels in `sequence` determines the rank order in the injected sequence. |
| 378 | /// ) | 405 | /// - Accessing samples beyond `N` will result in a panic; use the returned type |
| 379 | /// .await; | 406 | /// `InjectedAdc<T, N>` to enforce bounds at compile time. |
| 380 | /// defmt::info!("measurements: {}", measurements); | 407 | pub fn setup_injected_conversions<'a, const N: usize>( |
| 381 | /// ``` | 408 | self, |
| 382 | pub async fn read( | 409 | sequence: [(AnyAdcChannel<'a, T>, SampleTime); N], |
| 383 | &mut self, | 410 | trigger: ConversionTrigger, |
| 384 | rx_dma: Peri<'_, impl RxDma<T>>, | 411 | interrupt: bool, |
| 385 | sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, | 412 | ) -> InjectedAdc<'a, T, N> { |
| 386 | readings: &mut [u16], | 413 | assert!(N != 0, "Read sequence cannot be empty"); |
| 387 | ) { | ||
| 388 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | ||
| 389 | assert!( | ||
| 390 | sequence.len() == readings.len(), | ||
| 391 | "Sequence length must be equal to readings length" | ||
| 392 | ); | ||
| 393 | assert!( | 414 | assert!( |
| 394 | sequence.len() <= 16, | 415 | N <= NR_INJECTED_RANKS, |
| 395 | "Asynchronous read sequence cannot be more than 16 in length" | 416 | "Read sequence cannot be more than {} in length", |
| 417 | NR_INJECTED_RANKS | ||
| 396 | ); | 418 | ); |
| 397 | 419 | ||
| 398 | // Ensure no conversions are ongoing and ADC is enabled. | 420 | T::regs().enable(); |
| 399 | Self::cancel_conversions(); | ||
| 400 | self.enable(); | ||
| 401 | 421 | ||
| 402 | // Set sequence length | 422 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); |
| 403 | T::regs().sqr1().modify(|w| { | ||
| 404 | w.set_l(sequence.len() as u8 - 1); | ||
| 405 | }); | ||
| 406 | |||
| 407 | // Configure channels and ranks | ||
| 408 | for (_i, (channel, sample_time)) in sequence.enumerate() { | ||
| 409 | Self::configure_channel(channel, sample_time); | ||
| 410 | 423 | ||
| 411 | match _i { | 424 | for (n, (channel, sample_time)) in sequence.iter().enumerate() { |
| 412 | 0..=3 => { | 425 | let sample_time = sample_time.clone().into(); |
| 413 | T::regs().sqr1().modify(|w| { | 426 | if channel.channel() <= 9 { |
| 414 | w.set_sq(_i, channel.channel()); | 427 | T::regs() |
| 415 | }); | 428 | .smpr() |
| 416 | } | 429 | .modify(|reg| reg.set_smp(channel.channel() as _, sample_time)); |
| 417 | 4..=8 => { | 430 | } else { |
| 418 | T::regs().sqr2().modify(|w| { | 431 | T::regs() |
| 419 | w.set_sq(_i - 4, channel.channel()); | 432 | .smpr2() |
| 420 | }); | 433 | .modify(|reg| reg.set_smp((channel.channel() - 10) as _, sample_time)); |
| 421 | } | ||
| 422 | 9..=13 => { | ||
| 423 | T::regs().sqr3().modify(|w| { | ||
| 424 | w.set_sq(_i - 9, channel.channel()); | ||
| 425 | }); | ||
| 426 | } | ||
| 427 | 14..=15 => { | ||
| 428 | T::regs().sqr4().modify(|w| { | ||
| 429 | w.set_sq(_i - 14, channel.channel()); | ||
| 430 | }); | ||
| 431 | } | ||
| 432 | _ => unreachable!(), | ||
| 433 | } | 434 | } |
| 434 | } | ||
| 435 | |||
| 436 | // Set continuous mode with oneshot dma. | ||
| 437 | // Clear overrun flag before starting transfer. | ||
| 438 | T::regs().isr().modify(|reg| { | ||
| 439 | reg.set_ovr(true); | ||
| 440 | }); | ||
| 441 | 435 | ||
| 442 | T::regs().cfgr().modify(|reg| { | 436 | let idx = match n { |
| 443 | reg.set_discen(false); | 437 | 0..=3 => n, |
| 444 | reg.set_cont(true); | 438 | 4..=8 => n - 4, |
| 445 | reg.set_dmacfg(Dmacfg::ONE_SHOT); | 439 | 9..=13 => n - 9, |
| 446 | reg.set_dmaen(Dmaen::ENABLE); | 440 | 14..=15 => n - 14, |
| 447 | }); | 441 | _ => unreachable!(), |
| 448 | 442 | }; | |
| 449 | let request = rx_dma.request(); | ||
| 450 | let transfer = unsafe { | ||
| 451 | Transfer::new_read( | ||
| 452 | rx_dma, | ||
| 453 | request, | ||
| 454 | T::regs().dr().as_ptr() as *mut u16, | ||
| 455 | readings, | ||
| 456 | Default::default(), | ||
| 457 | ) | ||
| 458 | }; | ||
| 459 | |||
| 460 | // Start conversion | ||
| 461 | T::regs().cr().modify(|reg| { | ||
| 462 | reg.set_adstart(true); | ||
| 463 | }); | ||
| 464 | 443 | ||
| 465 | // Wait for conversion sequence to finish. | 444 | T::regs().jsqr().modify(|w| w.set_jsq(idx, channel.channel())); |
| 466 | transfer.await; | 445 | } |
| 467 | 446 | ||
| 468 | // Ensure conversions are finished. | 447 | T::regs().cfgr().modify(|reg| reg.set_jdiscen(false)); |
| 469 | Self::cancel_conversions(); | ||
| 470 | 448 | ||
| 471 | // Reset configuration. | 449 | // Set external trigger for injected conversion sequence |
| 472 | T::regs().cfgr().modify(|reg| { | 450 | // Possible trigger values are seen in Table 167 in RM0440 Rev 9 |
| 473 | reg.set_cont(false); | 451 | T::regs().jsqr().modify(|r| { |
| 452 | r.set_jextsel(trigger.channel); | ||
| 453 | r.set_jexten(trigger.edge); | ||
| 474 | }); | 454 | }); |
| 475 | } | ||
| 476 | |||
| 477 | fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { | ||
| 478 | // Configure channel | ||
| 479 | Self::set_channel_sample_time(channel.channel(), sample_time); | ||
| 480 | } | ||
| 481 | 455 | ||
| 482 | fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { | 456 | // Enable end of injected sequence interrupt |
| 483 | Self::configure_channel(channel, self.sample_time); | 457 | T::regs().ier().modify(|r| r.set_jeosie(interrupt)); |
| 484 | #[cfg(stm32h7)] | ||
| 485 | { | ||
| 486 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); | ||
| 487 | T::regs() | ||
| 488 | .pcsel() | ||
| 489 | .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); | ||
| 490 | } | ||
| 491 | 458 | ||
| 492 | T::regs().sqr1().write(|reg| { | 459 | Self::start_injected_conversions(); |
| 493 | reg.set_sq(0, channel.channel()); | ||
| 494 | reg.set_l(0); | ||
| 495 | }); | ||
| 496 | 460 | ||
| 497 | self.convert() | 461 | InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels |
| 498 | } | 462 | } |
| 499 | 463 | ||
| 500 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 464 | /// Configures ADC for both regular conversions with a ring-buffered DMA and injected conversions. |
| 501 | let sample_time = sample_time.into(); | 465 | /// |
| 502 | if ch <= 9 { | 466 | /// # Parameters |
| 503 | T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); | 467 | /// - `dma`: The DMA peripheral to use for the ring-buffered ADC transfers. |
| 504 | } else { | 468 | /// - `dma_buf`: The buffer to store DMA-transferred samples for regular conversions. |
| 505 | T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | 469 | /// - `regular_sequence`: The sequence of channels and their sample times for regular conversions. |
| 470 | /// - `regular_conversion_mode`: The mode for regular conversions (e.g., continuous or triggered). | ||
| 471 | /// - `injected_sequence`: An array of channels and sample times for injected conversions (length `N`). | ||
| 472 | /// - `injected_trigger`: The trigger source for injected conversions. | ||
| 473 | /// - `injected_interrupt`: Whether to enable the end-of-sequence interrupt for injected conversions. | ||
| 474 | /// | ||
| 475 | /// Injected conversions are typically used with interrupts. If ADC1 and ADC2 are used in dual mode, | ||
| 476 | /// it is recommended to enable interrupts only for the ADC whose sequence takes the longest to complete. | ||
| 477 | /// | ||
| 478 | /// # Returns | ||
| 479 | /// A tuple containing: | ||
| 480 | /// 1. `RingBufferedAdc<'a, T>` — the configured ADC for regular conversions using DMA. | ||
| 481 | /// 2. `InjectedAdc<T, N>` — the configured ADC for injected conversions. | ||
| 482 | /// | ||
| 483 | /// # Safety | ||
| 484 | /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the | ||
| 485 | /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently. | ||
| 486 | /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way. | ||
| 487 | pub fn into_ring_buffered_and_injected<'a, 'b, const N: usize>( | ||
| 488 | self, | ||
| 489 | dma: Peri<'a, impl RxDma<T>>, | ||
| 490 | dma_buf: &'a mut [u16], | ||
| 491 | regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>, | ||
| 492 | regular_conversion_mode: RegularConversionMode, | ||
| 493 | injected_sequence: [(AnyAdcChannel<'b, T>, SampleTime); N], | ||
| 494 | injected_trigger: ConversionTrigger, | ||
| 495 | injected_interrupt: bool, | ||
| 496 | ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<'b, T, N>) { | ||
| 497 | unsafe { | ||
| 498 | ( | ||
| 499 | Self { | ||
| 500 | adc: self.adc.clone_unchecked(), | ||
| 501 | } | ||
| 502 | .into_ring_buffered(dma, dma_buf, regular_sequence, regular_conversion_mode), | ||
| 503 | Self { | ||
| 504 | adc: self.adc.clone_unchecked(), | ||
| 505 | } | ||
| 506 | .setup_injected_conversions(injected_sequence, injected_trigger, injected_interrupt), | ||
| 507 | ) | ||
| 506 | } | 508 | } |
| 507 | } | 509 | } |
| 508 | 510 | ||
| 509 | fn cancel_conversions() { | 511 | /// Stop injected conversions |
| 512 | pub(super) fn stop_injected_conversions() { | ||
| 510 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | 513 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { |
| 511 | T::regs().cr().modify(|reg| { | 514 | T::regs().cr().modify(|reg| { |
| 512 | reg.set_adstp(Adstp::STOP); | 515 | reg.set_jadstp(Adstp::STOP); |
| 513 | }); | 516 | }); |
| 514 | while T::regs().cr().read().adstart() {} | 517 | // The software must poll JADSTART until the bit is reset before assuming the |
| 518 | // ADC is completely stopped | ||
| 519 | while T::regs().cr().read().jadstart() {} | ||
| 515 | } | 520 | } |
| 516 | } | 521 | } |
| 517 | } | ||
| 518 | 522 | ||
| 519 | /// Implemented for ADCs that have a Temperature channel | 523 | /// Start injected ADC conversion |
| 520 | pub trait TemperatureChannel { | 524 | pub(super) fn start_injected_conversions() { |
| 521 | const CHANNEL: u8; | 525 | T::regs().cr().modify(|reg| { |
| 522 | } | 526 | reg.set_jadstart(true); |
| 523 | /// Implemented for ADCs that have a Vref channel | 527 | }); |
| 524 | pub trait VrefChannel { | 528 | } |
| 525 | const CHANNEL: u8; | ||
| 526 | } | 529 | } |
| 527 | /// Implemented for ADCs that have a VBat channel | 530 | |
| 528 | pub trait VBatChannel { | 531 | impl<'a, T: Instance<Regs = crate::pac::adc::Adc>, const N: usize> InjectedAdc<'a, T, N> { |
| 529 | const CHANNEL: u8; | 532 | /// Read sampled data from all injected ADC injected ranks |
| 533 | /// Clear the JEOS flag to allow a new injected sequence | ||
| 534 | pub(super) fn read_injected_data() -> [u16; N] { | ||
| 535 | let mut data = [0u16; N]; | ||
| 536 | for i in 0..N { | ||
| 537 | data[i] = T::regs().jdr(i).read().jdata(); | ||
| 538 | } | ||
| 539 | |||
| 540 | // Clear JEOS by writing 1 | ||
| 541 | T::regs().isr().modify(|r| r.set_jeos(true)); | ||
| 542 | data | ||
| 543 | } | ||
| 530 | } | 544 | } |
| 531 | 545 | ||
| 532 | #[cfg(stm32g4)] | 546 | #[cfg(stm32g4)] |
| 533 | mod g4 { | 547 | mod g4 { |
| 534 | pub use super::*; | 548 | use crate::adc::{SealedSpecialConverter, Temperature, Vbat, VrefInt}; |
| 535 | 549 | ||
| 536 | impl TemperatureChannel for crate::peripherals::ADC1 { | 550 | impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC1 { |
| 537 | const CHANNEL: u8 = 16; | 551 | const CHANNEL: u8 = 16; |
| 538 | } | 552 | } |
| 539 | 553 | ||
| 540 | impl VrefChannel for crate::peripherals::ADC1 { | 554 | impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC1 { |
| 541 | const CHANNEL: u8 = 18; | 555 | const CHANNEL: u8 = 18; |
| 542 | } | 556 | } |
| 543 | 557 | ||
| 544 | impl VBatChannel for crate::peripherals::ADC1 { | 558 | impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC1 { |
| 545 | const CHANNEL: u8 = 17; | 559 | const CHANNEL: u8 = 17; |
| 546 | } | 560 | } |
| 547 | 561 | ||
| 548 | #[cfg(peri_adc3_common)] | 562 | #[cfg(peri_adc3_common)] |
| 549 | impl VrefChannel for crate::peripherals::ADC3 { | 563 | impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC3 { |
| 550 | const CHANNEL: u8 = 18; | 564 | const CHANNEL: u8 = 18; |
| 551 | } | 565 | } |
| 552 | 566 | ||
| 553 | #[cfg(peri_adc3_common)] | 567 | #[cfg(peri_adc3_common)] |
| 554 | impl VBatChannel for crate::peripherals::ADC3 { | 568 | impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC3 { |
| 555 | const CHANNEL: u8 = 17; | 569 | const CHANNEL: u8 = 17; |
| 556 | } | 570 | } |
| 557 | 571 | ||
| 558 | #[cfg(not(stm32g4x1))] | 572 | #[cfg(not(stm32g4x1))] |
| 559 | impl VrefChannel for crate::peripherals::ADC4 { | 573 | impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC4 { |
| 560 | const CHANNEL: u8 = 18; | 574 | const CHANNEL: u8 = 18; |
| 561 | } | 575 | } |
| 562 | 576 | ||
| 563 | #[cfg(not(stm32g4x1))] | 577 | #[cfg(not(stm32g4x1))] |
| 564 | impl TemperatureChannel for crate::peripherals::ADC5 { | 578 | impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC5 { |
| 565 | const CHANNEL: u8 = 4; | 579 | const CHANNEL: u8 = 4; |
| 566 | } | 580 | } |
| 567 | 581 | ||
| 568 | #[cfg(not(stm32g4x1))] | 582 | #[cfg(not(stm32g4x1))] |
| 569 | impl VrefChannel for crate::peripherals::ADC5 { | 583 | impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC5 { |
| 570 | const CHANNEL: u8 = 18; | 584 | const CHANNEL: u8 = 18; |
| 571 | } | 585 | } |
| 572 | 586 | ||
| 573 | #[cfg(not(stm32g4x1))] | 587 | #[cfg(not(stm32g4x1))] |
| 574 | impl VBatChannel for crate::peripherals::ADC5 { | 588 | impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC5 { |
| 575 | const CHANNEL: u8 = 17; | 589 | const CHANNEL: u8 = 17; |
| 576 | } | 590 | } |
| 577 | } | 591 | } |
| @@ -579,13 +593,13 @@ mod g4 { | |||
| 579 | // TODO this should look at each ADC individually and impl the correct channels | 593 | // TODO this should look at each ADC individually and impl the correct channels |
| 580 | #[cfg(stm32h7)] | 594 | #[cfg(stm32h7)] |
| 581 | mod h7 { | 595 | mod h7 { |
| 582 | impl<T: Instance> TemperatureChannel for T { | 596 | impl<T: Instance> SealedSpecialConverter<Temperature> for T { |
| 583 | const CHANNEL: u8 = 18; | 597 | const CHANNEL: u8 = 18; |
| 584 | } | 598 | } |
| 585 | impl<T: Instance> VrefChannel for T { | 599 | impl<T: Instance> SealedSpecialConverter<VrefInt> for T { |
| 586 | const CHANNEL: u8 = 19; | 600 | const CHANNEL: u8 = 19; |
| 587 | } | 601 | } |
| 588 | impl<T: Instance> VBatChannel for T { | 602 | impl<T: Instance> SealedSpecialConverter<Vbat> for T { |
| 589 | // TODO this should be 14 for H7a/b/35 | 603 | // TODO this should be 14 for H7a/b/35 |
| 590 | const CHANNEL: u8 = 17; | 604 | const CHANNEL: u8 = 17; |
| 591 | } | 605 | } |
