aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPer Rosengren <[email protected]>2025-09-13 19:21:44 +0200
committerPer Rosengren <[email protected]>2025-09-16 18:11:24 +0200
commit575b27f9f4412cf4d0aa18d77895117092e8c3b6 (patch)
treea6f99cd37964272027d3aa6a75a40349603bb468
parent25e0ebf5206fa2e2906f5826c0b1587739f628d8 (diff)
ADC v3: Migrate to stm32-data g0 with enums
Also allow separate sample times in read()
-rw-r--r--embassy-stm32/Cargo.toml5
-rw-r--r--embassy-stm32/src/adc/v3.rs179
2 files changed, 113 insertions, 71 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 9c2ba1f53..6cd8ed262 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -174,7 +174,7 @@ futures-util = { version = "0.3.30", default-features = false }
174sdio-host = "0.9.0" 174sdio-host = "0.9.0"
175critical-section = "1.1" 175critical-section = "1.1"
176#stm32-metapac = { version = "18" } 176#stm32-metapac = { version = "18" }
177stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d8432edd0406495adec19d31923584e80b8e03cb" } 177stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7" }
178 178
179vcell = "0.1.3" 179vcell = "0.1.3"
180nb = "1.0.0" 180nb = "1.0.0"
@@ -192,6 +192,7 @@ bitflags = "2.4.2"
192 192
193block-device-driver = { version = "0.2" } 193block-device-driver = { version = "0.2" }
194aligned = "0.4.1" 194aligned = "0.4.1"
195heapless = "0.9.1"
195 196
196[dev-dependencies] 197[dev-dependencies]
197critical-section = { version = "1.1", features = ["std"] } 198critical-section = { version = "1.1", features = ["std"] }
@@ -203,7 +204,7 @@ proc-macro2 = "1.0.36"
203quote = "1.0.15" 204quote = "1.0.15"
204 205
205#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} 206#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]}
206stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d8432edd0406495adec19d31923584e80b8e03cb", default-features = false, features = ["metadata"] } 207stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7", default-features = false, features = ["metadata"] }
207 208
208[features] 209[features]
209default = ["rt"] 210default = ["rt"]
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 77f24c87f..eb8b53495 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,8 +1,13 @@
1use cfg_if::cfg_if; 1use cfg_if::cfg_if;
2use pac::adc::vals::Dmacfg; 2use pac::adc::vals::Dmacfg;
3#[cfg(adc_g0)]
4use pac::adc::vals::{Ckmode, Ovsr, Ovss, Presc, Smpsel};
3#[cfg(adc_v3)] 5#[cfg(adc_v3)]
4use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; 6use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs};
5 7
8#[cfg(adc_g0)]
9use heapless::Vec;
10
6use super::{ 11use super::{
7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 12 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel,
8}; 13};
@@ -14,6 +19,11 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
14/// VREF voltage used for factory calibration of VREFINTCAL register. 19/// VREF voltage used for factory calibration of VREFINTCAL register.
15pub const VREF_CALIB_MV: u32 = 3000; 20pub const VREF_CALIB_MV: u32 = 3000;
16 21
22#[cfg(adc_g0)]
23/// The number of variants in Smpsel
24// TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable
25const SAMPLE_TIMES_CAPACITY: usize = 2;
26
17pub struct VrefInt; 27pub struct VrefInt;
18impl<T: Instance> AdcChannel<T> for VrefInt {} 28impl<T: Instance> AdcChannel<T> for VrefInt {}
19impl<T: Instance> SealedAdcChannel<T> for VrefInt { 29impl<T: Instance> SealedAdcChannel<T> for VrefInt {
@@ -111,30 +121,10 @@ pub enum Averaging {
111cfg_if! { if #[cfg(adc_g0)] { 121cfg_if! { if #[cfg(adc_g0)] {
112 122
113/// Synchronous PCLK prescaler 123/// Synchronous PCLK prescaler
114/// * ADC_CFGR2:CKMODE in STM32WL5x
115#[repr(u8)]
116pub enum CkModePclk { 124pub enum CkModePclk {
117 DIV1 = 3,
118 DIV2 = 1,
119 DIV4 = 2,
120}
121
122/// Asynchronous ADCCLK prescaler
123/// * ADC_CCR:PRESC in STM32WL5x
124#[repr(u8)]
125pub enum Presc {
126 DIV1, 125 DIV1,
127 DIV2, 126 DIV2,
128 DIV4, 127 DIV4,
129 DIV6,
130 DIV8,
131 DIV10,
132 DIV12,
133 DIV16,
134 DIV32,
135 DIV64,
136 DIV128,
137 DIV256,
138} 128}
139 129
140/// The analog clock is either the synchronous prescaled PCLK or 130/// The analog clock is either the synchronous prescaled PCLK or
@@ -213,8 +203,14 @@ impl<'d, T: Instance> Adc<'d, T> {
213 } 203 }
214 } 204 }
215 match clock { 205 match clock {
216 Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div as u8)), 206 Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)),
217 Clock::Sync { div } => T::regs().cfgr2().modify(|reg| reg.set_ckmode(div as u8)), 207 Clock::Sync { div } => T::regs().cfgr2().modify(|reg| {
208 reg.set_ckmode(match div {
209 CkModePclk::DIV1 => Ckmode::PCLK,
210 CkModePclk::DIV2 => Ckmode::PCLK_DIV2,
211 CkModePclk::DIV4 => Ckmode::PCLK_DIV4,
212 })
213 }),
218 } 214 }
219 215
220 Self::init_calibrate(); 216 Self::init_calibrate();
@@ -434,53 +430,78 @@ impl<'d, T: Instance> Adc<'d, T> {
434 w.set_l(sequence.len() as u8 - 1); 430 w.set_l(sequence.len() as u8 - 1);
435 }); 431 });
436 432
437 #[cfg(any(adc_g0, adc_u0))] 433 #[cfg(adc_g0)]
438 let mut channel_mask = 0; 434 {
439 435 let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new();
440 // Configure channels and ranks 436
441 for (_i, (channel, sample_time)) in sequence.enumerate() { 437 T::regs().chselr().write(|chselr| {
442 Self::configure_channel(channel, sample_time); 438 T::regs().smpr().write(|smpr| {
443 439 for (channel, sample_time) in sequence {
444 // Each channel is sampled according to sequence 440 chselr.set_chsel(channel.channel.into(), true);
445 #[cfg(not(any(adc_g0, adc_u0)))] 441 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
446 match _i { 442 smpr.set_smpsel(channel.channel.into(), (i as u8).into());
447 0..=3 => { 443 } else {
448 T::regs().sqr1().modify(|w| { 444 smpr.set_sample_time(sample_times.len(), sample_time);
449 w.set_sq(_i, channel.channel()); 445 if let Err(_) = sample_times.push(sample_time) {
450 }); 446 panic!(
451 } 447 "Implementation is limited to {} unique sample times among all channels.",
452 4..=8 => { 448 SAMPLE_TIMES_CAPACITY
453 T::regs().sqr2().modify(|w| { 449 );
454 w.set_sq(_i - 4, channel.channel()); 450 }
455 }); 451 }
456 } 452 }
457 9..=13 => { 453 })
458 T::regs().sqr3().modify(|w| { 454 });
459 w.set_sq(_i - 9, channel.channel()); 455 }
460 }); 456 #[cfg(not(adc_g0))]
457 {
458 #[cfg(adc_u0)]
459 let mut channel_mask = 0;
460
461 // Configure channels and ranks
462 for (_i, (channel, sample_time)) in sequence.enumerate() {
463 Self::configure_channel(channel, sample_time);
464
465 // Each channel is sampled according to sequence
466 #[cfg(not(any(adc_g0, adc_u0)))]
467 match _i {
468 0..=3 => {
469 T::regs().sqr1().modify(|w| {
470 w.set_sq(_i, channel.channel());
471 });
472 }
473 4..=8 => {
474 T::regs().sqr2().modify(|w| {
475 w.set_sq(_i - 4, channel.channel());
476 });
477 }
478 9..=13 => {
479 T::regs().sqr3().modify(|w| {
480 w.set_sq(_i - 9, channel.channel());
481 });
482 }
483 14..=15 => {
484 T::regs().sqr4().modify(|w| {
485 w.set_sq(_i - 14, channel.channel());
486 });
487 }
488 _ => unreachable!(),
461 } 489 }
462 14..=15 => { 490
463 T::regs().sqr4().modify(|w| { 491 #[cfg(adc_u0)]
464 w.set_sq(_i - 14, channel.channel()); 492 {
465 }); 493 channel_mask |= 1 << channel.channel();
466 } 494 }
467 _ => unreachable!(),
468 } 495 }
469 496
470 #[cfg(any(adc_g0, adc_u0))] 497 // On G0 and U0 enabled channels are sampled from 0 to last channel.
471 { 498 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
472 channel_mask |= 1 << channel.channel(); 499 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
473 } 500 #[cfg(adc_u0)]
501 T::regs().chselr().modify(|reg| {
502 reg.set_chsel(channel_mask);
503 });
474 } 504 }
475
476 // On G0 and U0 enabled channels are sampled from 0 to last channel.
477 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
478 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
479 #[cfg(any(adc_g0, adc_u0))]
480 T::regs().chselr().modify(|reg| {
481 reg.set_chsel(channel_mask);
482 });
483
484 // Set continuous mode with oneshot dma. 505 // Set continuous mode with oneshot dma.
485 // Clear overrun flag before starting transfer. 506 // Clear overrun flag before starting transfer.
486 T::regs().isr().modify(|reg| { 507 T::regs().isr().modify(|reg| {
@@ -535,6 +556,7 @@ impl<'d, T: Instance> Adc<'d, T> {
535 }); 556 });
536 } 557 }
537 558
559 #[cfg(not(adc_g0))]
538 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 560 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
539 // RM0492, RM0481, etc. 561 // RM0492, RM0481, etc.
540 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 562 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
@@ -549,13 +571,23 @@ impl<'d, T: Instance> Adc<'d, T> {
549 571
550 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 572 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
551 self.enable(); 573 self.enable();
574 #[cfg(not(adc_g0))]
552 Self::configure_channel(channel, self.sample_time); 575 Self::configure_channel(channel, self.sample_time);
553 576 #[cfg(adc_g0)]
577 T::regs().smpr().write(|reg| {
578 reg.set_sample_time(0, self.sample_time);
579 reg.set_smpsel(channel.channel().into(), Smpsel::SMP1);
580 });
554 // Select channel 581 // Select channel
555 #[cfg(not(any(adc_g0, adc_u0)))] 582 #[cfg(not(any(adc_g0, adc_u0)))]
556 T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel())); 583 T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel()));
557 #[cfg(any(adc_g0, adc_u0))] 584 #[cfg(any(adc_g0, adc_u0))]
558 T::regs().chselr().write(|reg| reg.set_chsel(1 << channel.channel())); 585 T::regs().chselr().write(|reg| {
586 #[cfg(adc_g0)]
587 reg.set_chsel(channel.channel().into(), true);
588 #[cfg(adc_u0)]
589 reg.set_chsel(1 << channel.channel());
590 });
559 591
560 // Some models are affected by an erratum: 592 // Some models are affected by an erratum:
561 // If we perform conversions slower than 1 kHz, the first read ADC value can be 593 // If we perform conversions slower than 1 kHz, the first read ADC value can be
@@ -579,12 +611,20 @@ impl<'d, T: Instance> Adc<'d, T> {
579 val 611 val
580 } 612 }
581 613
582 #[cfg(any(adc_g0, adc_u0))] 614 #[cfg(adc_g0)]
615 pub fn set_oversampling_shift(&mut self, shift: Ovss) {
616 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
617 }
618 #[cfg(adc_u0)]
583 pub fn set_oversampling_shift(&mut self, shift: u8) { 619 pub fn set_oversampling_shift(&mut self, shift: u8) {
584 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); 620 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
585 } 621 }
586 622
587 #[cfg(any(adc_g0, adc_u0))] 623 #[cfg(adc_g0)]
624 pub fn set_oversampling_ratio(&mut self, ratio: Ovsr) {
625 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
626 }
627 #[cfg(adc_u0)]
588 pub fn set_oversampling_ratio(&mut self, ratio: u8) { 628 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
589 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); 629 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
590 } 630 }
@@ -611,9 +651,10 @@ impl<'d, T: Instance> Adc<'d, T> {
611 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); 651 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
612 } 652 }
613 653
654 #[cfg(not(adc_g0))]
614 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { 655 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
615 cfg_if! { 656 cfg_if! {
616 if #[cfg(any(adc_g0, adc_u0))] { 657 if #[cfg(adc_u0)] {
617 // On G0 and U6 all channels use the same sampling time. 658 // On G0 and U6 all channels use the same sampling time.
618 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 659 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
619 } else if #[cfg(any(adc_h5, adc_h7rs))] { 660 } else if #[cfg(any(adc_h5, adc_h7rs))] {