diff options
| -rw-r--r-- | embassy-stm32/src/adc/v1.rs | 116 |
1 files changed, 62 insertions, 54 deletions
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 224d17178..f787f72ac 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs | |||
| @@ -48,25 +48,33 @@ impl Resolution { | |||
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | pub trait InternalChannel<T>: sealed::InternalChannel<T> {} | ||
| 52 | |||
| 53 | mod sealed { | ||
| 54 | pub trait InternalChannel<T> { | ||
| 55 | fn channel(&self) -> u8; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 51 | pub struct Vbat; | 59 | pub struct Vbat; |
| 52 | impl<T: Instance> AdcPin<T> for Vbat {} | 60 | impl<T: Instance> InternalChannel<T> for Vbat {} |
| 53 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { | 61 | impl<T: Instance> sealed::InternalChannel<T> for Vbat { |
| 54 | fn channel(&self) -> u8 { | 62 | fn channel(&self) -> u8 { |
| 55 | 18 | 63 | 18 |
| 56 | } | 64 | } |
| 57 | } | 65 | } |
| 58 | 66 | ||
| 59 | pub struct Vref; | 67 | pub struct Vref; |
| 60 | impl<T: Instance> AdcPin<T> for Vref {} | 68 | impl<T: Instance> InternalChannel<T> for Vref {} |
| 61 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | 69 | impl<T: Instance> sealed::InternalChannel<T> for Vref { |
| 62 | fn channel(&self) -> u8 { | 70 | fn channel(&self) -> u8 { |
| 63 | 17 | 71 | 17 |
| 64 | } | 72 | } |
| 65 | } | 73 | } |
| 66 | 74 | ||
| 67 | pub struct Temperature; | 75 | pub struct Temperature; |
| 68 | impl<T: Instance> AdcPin<T> for Temperature {} | 76 | impl<T: Instance> InternalChannel<T> for Temperature {} |
| 69 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | 77 | impl<T: Instance> sealed::InternalChannel<T> for Temperature { |
| 70 | fn channel(&self) -> u8 { | 78 | fn channel(&self) -> u8 { |
| 71 | 16 | 79 | 16 |
| 72 | } | 80 | } |
| @@ -219,64 +227,64 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 219 | ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 | 227 | ((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16 |
| 220 | } | 228 | } |
| 221 | 229 | ||
| 222 | fn convert(&mut self) -> u16 { | ||
| 223 | unsafe { | ||
| 224 | T::regs().isr().modify(|reg| { | ||
| 225 | reg.set_eoc(true); | ||
| 226 | reg.set_eosmp(true); | ||
| 227 | }); | ||
| 228 | |||
| 229 | // A.7.5 Single conversion sequence code example - Software trigger | ||
| 230 | T::regs().cr().modify(|reg| reg.set_adstart(true)); | ||
| 231 | while !T::regs().isr().read().eoc() { | ||
| 232 | // spin | ||
| 233 | } | ||
| 234 | |||
| 235 | T::regs().dr().read().0 as u16 | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 230 | pub fn read<P>(&mut self, pin: &mut P) -> u16 |
| 240 | where | 231 | where |
| 241 | P: AdcPin<T> + crate::gpio::sealed::Pin, | 232 | P: AdcPin<T> + crate::gpio::sealed::Pin, |
| 242 | { | 233 | { |
| 234 | let channel = pin.channel(); | ||
| 243 | unsafe { | 235 | unsafe { |
| 244 | // A.7.2 ADC enable sequence code example | ||
| 245 | if T::regs().isr().read().adrdy() { | ||
| 246 | T::regs().isr().modify(|reg| reg.set_adrdy(true)); | ||
| 247 | } | ||
| 248 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 249 | while !T::regs().isr().read().adrdy() { | ||
| 250 | // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration | ||
| 251 | // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the | ||
| 252 | // ADEN bit until the ADRDY flag goes high. | ||
| 253 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 254 | } | ||
| 255 | |||
| 256 | T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res())); | ||
| 257 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||
| 258 | pin.set_as_analog(); | 236 | pin.set_as_analog(); |
| 259 | T::regs() | 237 | self.read_channel(channel) |
| 260 | .chselr() | 238 | } |
| 261 | .write(|reg| reg.set_chselx(pin.channel() as usize, true)); | 239 | } |
| 262 | 240 | ||
| 263 | let value = self.convert(); | 241 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { |
| 242 | let channel = channel.channel(); | ||
| 243 | unsafe { | ||
| 244 | self.read_channel(channel) | ||
| 245 | } | ||
| 246 | } | ||
| 264 | 247 | ||
| 265 | // A.7.3 ADC disable code example | 248 | unsafe fn read_channel(&mut self, channel: u8) -> u16 { |
| 266 | T::regs().cr().modify(|reg| reg.set_adstp(true)); | 249 | // A.7.2 ADC enable sequence code example |
| 267 | while T::regs().cr().read().adstp() { | 250 | if T::regs().isr().read().adrdy() { |
| 268 | // spin | 251 | T::regs().isr().modify(|reg| reg.set_adrdy(true)); |
| 269 | } | 252 | } |
| 270 | T::regs().cr().modify(|reg| reg.set_addis(true)); | 253 | T::regs().cr().modify(|reg| reg.set_aden(true)); |
| 271 | while T::regs().cr().read().aden() { | 254 | while !T::regs().isr().read().adrdy() { |
| 272 | // spin | 255 | // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration |
| 273 | } | 256 | // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the |
| 257 | // ADEN bit until the ADRDY flag goes high. | ||
| 258 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 259 | } | ||
| 274 | 260 | ||
| 275 | value | 261 | T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res())); |
| 262 | T::regs().isr().modify(|reg| { | ||
| 263 | reg.set_eoc(true); | ||
| 264 | reg.set_eosmp(true); | ||
| 265 | }); | ||
| 266 | |||
| 267 | // A.7.5 Single conversion sequence code example - Software trigger | ||
| 268 | T::regs() | ||
| 269 | .chselr() | ||
| 270 | .write(|reg| reg.set_chselx(channel as usize, true)); | ||
| 271 | T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.sample_time())); | ||
| 272 | T::regs().cr().modify(|reg| reg.set_adstart(true)); | ||
| 273 | while !T::regs().isr().read().eoc() { | ||
| 274 | // spin | ||
| 275 | } | ||
| 276 | let value = T::regs().dr().read().0 as u16; | ||
| 277 | |||
| 278 | // A.7.3 ADC disable code example | ||
| 279 | T::regs().cr().modify(|reg| reg.set_adstp(true)); | ||
| 280 | while T::regs().cr().read().adstp() { | ||
| 281 | // spin | ||
| 282 | } | ||
| 283 | T::regs().cr().modify(|reg| reg.set_addis(true)); | ||
| 284 | while T::regs().cr().read().aden() { | ||
| 285 | // spin | ||
| 276 | } | 286 | } |
| 277 | } | ||
| 278 | 287 | ||
| 279 | unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | 288 | value |
| 280 | T::regs().smpr().modify(|reg| reg.set_smp(sample_time.sample_time())); | ||
| 281 | } | 289 | } |
| 282 | } | 290 | } |
