diff options
| author | xoviat <[email protected]> | 2025-11-10 13:48:24 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-11-10 13:48:24 -0600 |
| commit | d89d8d9e2bb201fe5f1d8212d317abb12a91666f (patch) | |
| tree | 60e3c940864e57892b0007eeeb8cd295813bc538 /embassy-stm32/src | |
| parent | ff1fb2dd6b9ebc0dd3c7b642f70fbb80a1fd030d (diff) | |
adc: consolidate functions
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/adc/g4.rs | 125 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/injected.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/ringbuffered.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v2.rs | 164 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 2 |
5 files changed, 140 insertions, 155 deletions
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 2138a82b4..5d9c6ff74 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -147,7 +147,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 147 | s.calibrate(); | 147 | s.calibrate(); |
| 148 | blocking_delay_us(1); | 148 | blocking_delay_us(1); |
| 149 | 149 | ||
| 150 | s.enable(); | 150 | Self::enable(); |
| 151 | s.configure(); | 151 | s.configure(); |
| 152 | 152 | ||
| 153 | s | 153 | s |
| @@ -192,7 +192,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 192 | blocking_delay_us(20); | 192 | blocking_delay_us(20); |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | fn enable(&mut self) { | 195 | fn enable() { |
| 196 | // Make sure bits are off | 196 | // Make sure bits are off |
| 197 | while T::regs().cr().read().addis() { | 197 | while T::regs().cr().read().addis() { |
| 198 | // spin | 198 | // spin |
| @@ -363,7 +363,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | /// Teardown method for stopping regular ADC conversions | 365 | /// Teardown method for stopping regular ADC conversions |
| 366 | pub(super) fn teardown_adc() { | 366 | pub(super) fn teardown_dma() { |
| 367 | Self::stop_regular_conversions(); | 367 | Self::stop_regular_conversions(); |
| 368 | 368 | ||
| 369 | // Disable dma control | 369 | // Disable dma control |
| @@ -418,39 +418,13 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 418 | 418 | ||
| 419 | // Ensure no conversions are ongoing and ADC is enabled. | 419 | // Ensure no conversions are ongoing and ADC is enabled. |
| 420 | Self::stop_regular_conversions(); | 420 | Self::stop_regular_conversions(); |
| 421 | self.enable(); | 421 | Self::enable(); |
| 422 | 422 | ||
| 423 | // Set sequence length | 423 | Self::configure_sequence(sequence.map(|(channel, sample_time)| { |
| 424 | T::regs().sqr1().modify(|w| { | 424 | channel.setup(); |
| 425 | w.set_l(sequence.len() as u8 - 1); | 425 | |
| 426 | }); | 426 | (channel.channel, sample_time) |
| 427 | // Configure channels and ranks | 427 | })); |
| 428 | for (_i, (channel, sample_time)) in sequence.enumerate() { | ||
| 429 | Self::configure_channel(channel, sample_time); | ||
| 430 | match _i { | ||
| 431 | 0..=3 => { | ||
| 432 | T::regs().sqr1().modify(|w| { | ||
| 433 | w.set_sq(_i, channel.channel()); | ||
| 434 | }); | ||
| 435 | } | ||
| 436 | 4..=8 => { | ||
| 437 | T::regs().sqr2().modify(|w| { | ||
| 438 | w.set_sq(_i - 4, channel.channel()); | ||
| 439 | }); | ||
| 440 | } | ||
| 441 | 9..=13 => { | ||
| 442 | T::regs().sqr3().modify(|w| { | ||
| 443 | w.set_sq(_i - 9, channel.channel()); | ||
| 444 | }); | ||
| 445 | } | ||
| 446 | 14..=15 => { | ||
| 447 | T::regs().sqr4().modify(|w| { | ||
| 448 | w.set_sq(_i - 14, channel.channel()); | ||
| 449 | }); | ||
| 450 | } | ||
| 451 | _ => unreachable!(), | ||
| 452 | } | ||
| 453 | } | ||
| 454 | 428 | ||
| 455 | // Set continuous mode with oneshot dma. | 429 | // Set continuous mode with oneshot dma. |
| 456 | // Clear overrun flag before starting transfer. | 430 | // Clear overrun flag before starting transfer. |
| @@ -493,6 +467,47 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 493 | }); | 467 | }); |
| 494 | } | 468 | } |
| 495 | 469 | ||
| 470 | pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) { | ||
| 471 | // Set sequence length | ||
| 472 | T::regs().sqr1().modify(|w| { | ||
| 473 | w.set_l(sequence.len() as u8 - 1); | ||
| 474 | }); | ||
| 475 | |||
| 476 | // Configure channels and ranks | ||
| 477 | for (_i, (ch, sample_time)) in sequence.enumerate() { | ||
| 478 | let sample_time = sample_time.into(); | ||
| 479 | if ch <= 9 { | ||
| 480 | T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); | ||
| 481 | } else { | ||
| 482 | T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | ||
| 483 | } | ||
| 484 | |||
| 485 | match _i { | ||
| 486 | 0..=3 => { | ||
| 487 | T::regs().sqr1().modify(|w| { | ||
| 488 | w.set_sq(_i, ch); | ||
| 489 | }); | ||
| 490 | } | ||
| 491 | 4..=8 => { | ||
| 492 | T::regs().sqr2().modify(|w| { | ||
| 493 | w.set_sq(_i - 4, ch); | ||
| 494 | }); | ||
| 495 | } | ||
| 496 | 9..=13 => { | ||
| 497 | T::regs().sqr3().modify(|w| { | ||
| 498 | w.set_sq(_i - 9, ch); | ||
| 499 | }); | ||
| 500 | } | ||
| 501 | 14..=15 => { | ||
| 502 | T::regs().sqr4().modify(|w| { | ||
| 503 | w.set_sq(_i - 14, ch); | ||
| 504 | }); | ||
| 505 | } | ||
| 506 | _ => unreachable!(), | ||
| 507 | } | ||
| 508 | } | ||
| 509 | } | ||
| 510 | |||
| 496 | /// Set external trigger for regular conversion sequence | 511 | /// Set external trigger for regular conversion sequence |
| 497 | fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) { | 512 | fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) { |
| 498 | T::regs().cfgr().modify(|r| { | 513 | T::regs().cfgr().modify(|r| { |
| @@ -546,43 +561,15 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 546 | ); | 561 | ); |
| 547 | // reset conversions and enable the adc | 562 | // reset conversions and enable the adc |
| 548 | Self::stop_regular_conversions(); | 563 | Self::stop_regular_conversions(); |
| 549 | self.enable(); | 564 | Self::enable(); |
| 550 | 565 | ||
| 551 | //adc side setup | 566 | //adc side setup |
| 552 | 567 | ||
| 553 | // Set sequence length | 568 | Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { |
| 554 | T::regs().sqr1().modify(|w| { | 569 | channel.setup(); |
| 555 | w.set_l(sequence.len() as u8 - 1); | ||
| 556 | }); | ||
| 557 | |||
| 558 | // Configure channels and ranks | ||
| 559 | for (_i, (mut channel, sample_time)) in sequence.enumerate() { | ||
| 560 | Self::configure_channel(&mut channel, sample_time); | ||
| 561 | 570 | ||
| 562 | match _i { | 571 | (channel.channel, sample_time) |
| 563 | 0..=3 => { | 572 | })); |
| 564 | T::regs().sqr1().modify(|w| { | ||
| 565 | w.set_sq(_i, channel.channel()); | ||
| 566 | }); | ||
| 567 | } | ||
| 568 | 4..=8 => { | ||
| 569 | T::regs().sqr2().modify(|w| { | ||
| 570 | w.set_sq(_i - 4, channel.channel()); | ||
| 571 | }); | ||
| 572 | } | ||
| 573 | 9..=13 => { | ||
| 574 | T::regs().sqr3().modify(|w| { | ||
| 575 | w.set_sq(_i - 9, channel.channel()); | ||
| 576 | }); | ||
| 577 | } | ||
| 578 | 14..=15 => { | ||
| 579 | T::regs().sqr4().modify(|w| { | ||
| 580 | w.set_sq(_i - 14, channel.channel()); | ||
| 581 | }); | ||
| 582 | } | ||
| 583 | _ => unreachable!(), | ||
| 584 | } | ||
| 585 | } | ||
| 586 | 573 | ||
| 587 | // Clear overrun flag before starting transfer. | 574 | // Clear overrun flag before starting transfer. |
| 588 | T::regs().isr().modify(|reg| { | 575 | T::regs().isr().modify(|reg| { |
| @@ -655,7 +642,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 655 | ); | 642 | ); |
| 656 | 643 | ||
| 657 | Self::stop_regular_conversions(); | 644 | Self::stop_regular_conversions(); |
| 658 | self.enable(); | 645 | Self::enable(); |
| 659 | 646 | ||
| 660 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); | 647 | T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); |
| 661 | 648 | ||
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs index 0e4fe5847..f9f1bba2a 100644 --- a/embassy-stm32/src/adc/injected.rs +++ b/embassy-stm32/src/adc/injected.rs | |||
| @@ -38,7 +38,7 @@ impl<T: Instance, const N: usize> InjectedAdc<T, N> { | |||
| 38 | 38 | ||
| 39 | impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> { | 39 | impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> { |
| 40 | fn drop(&mut self) { | 40 | fn drop(&mut self) { |
| 41 | Adc::<T>::teardown_adc(); | 41 | Adc::<T>::teardown_dma(); |
| 42 | compiler_fence(Ordering::SeqCst); | 42 | compiler_fence(Ordering::SeqCst); |
| 43 | } | 43 | } |
| 44 | } | 44 | } |
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index 971c8195c..024c6acdc 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs | |||
| @@ -172,7 +172,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { | |||
| 172 | 172 | ||
| 173 | impl<T: Instance> Drop for RingBufferedAdc<'_, T> { | 173 | impl<T: Instance> Drop for RingBufferedAdc<'_, T> { |
| 174 | fn drop(&mut self) { | 174 | fn drop(&mut self) { |
| 175 | Adc::<T>::teardown_adc(); | 175 | Adc::<T>::teardown_dma(); |
| 176 | 176 | ||
| 177 | compiler_fence(Ordering::SeqCst); | 177 | compiler_fence(Ordering::SeqCst); |
| 178 | 178 | ||
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index af5d486d9..88a8b96ed 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -125,57 +125,14 @@ where | |||
| 125 | ) -> RingBufferedAdc<'d, T> { | 125 | ) -> RingBufferedAdc<'d, T> { |
| 126 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | 126 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); |
| 127 | 127 | ||
| 128 | T::regs().cr2().modify(|reg| { | 128 | Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { |
| 129 | reg.set_adon(true); | ||
| 130 | }); | ||
| 131 | |||
| 132 | // Check the sequence is long enough | ||
| 133 | T::regs().sqr1().modify(|r| { | ||
| 134 | r.set_l((sequence.len() - 1).try_into().unwrap()); | ||
| 135 | }); | ||
| 136 | |||
| 137 | for (i, (mut channel, sample_time)) in sequence.enumerate() { | ||
| 138 | // Set this GPIO as an analog input. | ||
| 139 | channel.setup(); | 129 | channel.setup(); |
| 140 | 130 | ||
| 141 | // Set the channel in the right sequence field. | 131 | (channel.channel, sample_time) |
| 142 | T::regs().sqr3().modify(|w| w.set_sq(i, channel.channel())); | 132 | })); |
| 143 | |||
| 144 | Self::set_channel_sample_time(channel.channel(), sample_time); | ||
| 145 | } | ||
| 146 | |||
| 147 | compiler_fence(Ordering::SeqCst); | 133 | compiler_fence(Ordering::SeqCst); |
| 148 | 134 | ||
| 149 | let r = T::regs(); | 135 | Self::setup_dma(); |
| 150 | |||
| 151 | // Clear all interrupts | ||
| 152 | r.sr().modify(|regs| { | ||
| 153 | regs.set_eoc(false); | ||
| 154 | regs.set_ovr(false); | ||
| 155 | regs.set_strt(false); | ||
| 156 | }); | ||
| 157 | |||
| 158 | r.cr1().modify(|w| { | ||
| 159 | // Enable interrupt for end of conversion | ||
| 160 | w.set_eocie(true); | ||
| 161 | // Enable interrupt for overrun | ||
| 162 | w.set_ovrie(true); | ||
| 163 | // Scanning converisons of multiple channels | ||
| 164 | w.set_scan(true); | ||
| 165 | // Continuous conversion mode | ||
| 166 | w.set_discen(false); | ||
| 167 | }); | ||
| 168 | |||
| 169 | r.cr2().modify(|w| { | ||
| 170 | // Enable DMA mode | ||
| 171 | w.set_dma(true); | ||
| 172 | // Enable continuous conversions | ||
| 173 | w.set_cont(true); | ||
| 174 | // DMA requests are issues as long as DMA=1 and data are converted. | ||
| 175 | w.set_dds(vals::Dds::CONTINUOUS); | ||
| 176 | // EOC flag is set at the end of each conversion. | ||
| 177 | w.set_eocs(vals::Eocs::EACH_CONVERSION); | ||
| 178 | }); | ||
| 179 | 136 | ||
| 180 | // Don't disable the clock | 137 | // Don't disable the clock |
| 181 | mem::forget(self); | 138 | mem::forget(self); |
| @@ -183,24 +140,14 @@ where | |||
| 183 | RingBufferedAdc::new(dma, dma_buf) | 140 | RingBufferedAdc::new(dma, dma_buf) |
| 184 | } | 141 | } |
| 185 | 142 | ||
| 186 | pub(super) fn start() { | 143 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { |
| 187 | // Begin ADC conversions | 144 | channel.setup(); |
| 188 | T::regs().cr2().modify(|reg| { | ||
| 189 | reg.set_adon(true); | ||
| 190 | reg.set_swstart(true); | ||
| 191 | }); | ||
| 192 | } | ||
| 193 | 145 | ||
| 194 | pub(super) fn stop() { | 146 | // Configure ADC |
| 195 | // Stop ADC | 147 | let channel = channel.channel(); |
| 196 | T::regs().cr2().modify(|reg| { | ||
| 197 | // Stop ADC | ||
| 198 | reg.set_swstart(false); | ||
| 199 | }); | ||
| 200 | } | ||
| 201 | 148 | ||
| 202 | pub fn set_resolution(&mut self, resolution: Resolution) { | 149 | Self::configure_sequence([(channel, sample_time)].into_iter()); |
| 203 | T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); | 150 | Self::blocking_convert() |
| 204 | } | 151 | } |
| 205 | 152 | ||
| 206 | /// Enables internal voltage reference and returns [VrefInt], which can be used in | 153 | /// Enables internal voltage reference and returns [VrefInt], which can be used in |
| @@ -236,8 +183,27 @@ where | |||
| 236 | Vbat {} | 183 | Vbat {} |
| 237 | } | 184 | } |
| 238 | 185 | ||
| 239 | /// Perform a single conversion. | 186 | pub(super) fn start() { |
| 240 | fn convert(&mut self) -> u16 { | 187 | // Begin ADC conversions |
| 188 | T::regs().cr2().modify(|reg| { | ||
| 189 | reg.set_adon(true); | ||
| 190 | reg.set_swstart(true); | ||
| 191 | }); | ||
| 192 | } | ||
| 193 | |||
| 194 | pub(super) fn stop() { | ||
| 195 | // Stop ADC | ||
| 196 | T::regs().cr2().modify(|reg| { | ||
| 197 | // Stop ADC | ||
| 198 | reg.set_swstart(false); | ||
| 199 | }); | ||
| 200 | } | ||
| 201 | |||
| 202 | pub fn set_resolution(&mut self, resolution: Resolution) { | ||
| 203 | T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); | ||
| 204 | } | ||
| 205 | |||
| 206 | pub(super) fn blocking_convert() -> u16 { | ||
| 241 | // clear end of conversion flag | 207 | // clear end of conversion flag |
| 242 | T::regs().sr().modify(|reg| { | 208 | T::regs().sr().modify(|reg| { |
| 243 | reg.set_eoc(false); | 209 | reg.set_eoc(false); |
| @@ -258,31 +224,63 @@ where | |||
| 258 | T::regs().dr().read().0 as u16 | 224 | T::regs().dr().read().0 as u16 |
| 259 | } | 225 | } |
| 260 | 226 | ||
| 261 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { | 227 | pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) { |
| 262 | channel.setup(); | 228 | T::regs().cr2().modify(|reg| { |
| 229 | reg.set_adon(true); | ||
| 230 | }); | ||
| 263 | 231 | ||
| 264 | // Configure ADC | 232 | // Check the sequence is long enough |
| 265 | let channel = channel.channel(); | 233 | T::regs().sqr1().modify(|r| { |
| 234 | r.set_l((sequence.len() - 1).try_into().unwrap()); | ||
| 235 | }); | ||
| 266 | 236 | ||
| 267 | // Select channel | 237 | for (i, (ch, sample_time)) in sequence.enumerate() { |
| 268 | T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); | 238 | // Set the channel in the right sequence field. |
| 239 | T::regs().sqr3().modify(|w| w.set_sq(i, ch)); | ||
| 240 | |||
| 241 | let sample_time = sample_time.into(); | ||
| 242 | if ch <= 9 { | ||
| 243 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | ||
| 244 | } else { | ||
| 245 | T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | } | ||
| 269 | 249 | ||
| 270 | // Configure channel | 250 | pub(super) fn setup_dma() { |
| 271 | Self::set_channel_sample_time(channel, sample_time); | 251 | let r = T::regs(); |
| 272 | 252 | ||
| 273 | self.convert() | 253 | // Clear all interrupts |
| 274 | } | 254 | r.sr().modify(|regs| { |
| 255 | regs.set_eoc(false); | ||
| 256 | regs.set_ovr(false); | ||
| 257 | regs.set_strt(false); | ||
| 258 | }); | ||
| 275 | 259 | ||
| 276 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 260 | r.cr1().modify(|w| { |
| 277 | let sample_time = sample_time.into(); | 261 | // Enable interrupt for end of conversion |
| 278 | if ch <= 9 { | 262 | w.set_eocie(true); |
| 279 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | 263 | // Enable interrupt for overrun |
| 280 | } else { | 264 | w.set_ovrie(true); |
| 281 | T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | 265 | // Scanning converisons of multiple channels |
| 282 | } | 266 | w.set_scan(true); |
| 267 | // Continuous conversion mode | ||
| 268 | w.set_discen(false); | ||
| 269 | }); | ||
| 270 | |||
| 271 | r.cr2().modify(|w| { | ||
| 272 | // Enable DMA mode | ||
| 273 | w.set_dma(true); | ||
| 274 | // Enable continuous conversions | ||
| 275 | w.set_cont(true); | ||
| 276 | // DMA requests are issues as long as DMA=1 and data are converted. | ||
| 277 | w.set_dds(vals::Dds::CONTINUOUS); | ||
| 278 | // EOC flag is set at the end of each conversion. | ||
| 279 | w.set_eocs(vals::Eocs::EACH_CONVERSION); | ||
| 280 | }); | ||
| 283 | } | 281 | } |
| 284 | 282 | ||
| 285 | pub(super) fn teardown_adc() { | 283 | pub(super) fn teardown_dma() { |
| 286 | let r = T::regs(); | 284 | let r = T::regs(); |
| 287 | 285 | ||
| 288 | // Stop ADC | 286 | // Stop ADC |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 0822fbb69..e816907d1 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -198,7 +198,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | #[cfg(any(adc_v3, adc_g0, adc_u0))] | 200 | #[cfg(any(adc_v3, adc_g0, adc_u0))] |
| 201 | pub(super) fn teardown_adc() { | 201 | pub(super) fn teardown_dma() { |
| 202 | //disable dma control | 202 | //disable dma control |
| 203 | #[cfg(not(any(adc_g0, adc_u0)))] | 203 | #[cfg(not(any(adc_g0, adc_u0)))] |
| 204 | T::regs().cfgr().modify(|reg| { | 204 | T::regs().cfgr().modify(|reg| { |
