aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/adc
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-13 17:41:44 -0600
committerxoviat <[email protected]>2025-11-13 17:41:44 -0600
commitcc1aad2cc4d2f87a177495e8352dd312c1ac331c (patch)
tree8bca5d0816882f151a87b88121e15c9e4f11f36a /embassy-stm32/src/adc
parent4fb60b5991c4c98427ef23e6c011210341ba09e1 (diff)
parent578679771eafe93ccc0e8de8fc3f97a5b991b02c (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into adc
Diffstat (limited to 'embassy-stm32/src/adc')
-rw-r--r--embassy-stm32/src/adc/adc4.rs83
-rw-r--r--embassy-stm32/src/adc/c0.rs507
-rw-r--r--embassy-stm32/src/adc/f1.rs4
-rw-r--r--embassy-stm32/src/adc/f3.rs2
-rw-r--r--embassy-stm32/src/adc/g4.rs82
-rw-r--r--embassy-stm32/src/adc/mod.rs101
-rw-r--r--embassy-stm32/src/adc/v2.rs51
-rw-r--r--embassy-stm32/src/adc/v3.rs18
-rw-r--r--embassy-stm32/src/adc/v4.rs102
9 files changed, 301 insertions, 649 deletions
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 52678d1b6..babdebfdb 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -76,71 +76,17 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 {
76 } 76 }
77} 77}
78 78
79// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 79fn from_ker_ck(frequency: Hertz) -> Presc {
80// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 80 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
81#[allow(unused)] 81 match raw_prescaler {
82enum Prescaler { 82 0 => Presc::DIV1,
83 NotDivided, 83 1 => Presc::DIV2,
84 DividedBy2, 84 2..=3 => Presc::DIV4,
85 DividedBy4, 85 4..=5 => Presc::DIV6,
86 DividedBy6, 86 6..=7 => Presc::DIV8,
87 DividedBy8, 87 8..=9 => Presc::DIV10,
88 DividedBy10, 88 10..=11 => Presc::DIV12,
89 DividedBy12, 89 _ => unimplemented!(),
90 DividedBy16,
91 DividedBy32,
92 DividedBy64,
93 DividedBy128,
94 DividedBy256,
95}
96
97impl Prescaler {
98 fn from_ker_ck(frequency: Hertz) -> Self {
99 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
100 match raw_prescaler {
101 0 => Self::NotDivided,
102 1 => Self::DividedBy2,
103 2..=3 => Self::DividedBy4,
104 4..=5 => Self::DividedBy6,
105 6..=7 => Self::DividedBy8,
106 8..=9 => Self::DividedBy10,
107 10..=11 => Self::DividedBy12,
108 _ => unimplemented!(),
109 }
110 }
111
112 fn divisor(&self) -> u32 {
113 match self {
114 Prescaler::NotDivided => 1,
115 Prescaler::DividedBy2 => 2,
116 Prescaler::DividedBy4 => 4,
117 Prescaler::DividedBy6 => 6,
118 Prescaler::DividedBy8 => 8,
119 Prescaler::DividedBy10 => 10,
120 Prescaler::DividedBy12 => 12,
121 Prescaler::DividedBy16 => 16,
122 Prescaler::DividedBy32 => 32,
123 Prescaler::DividedBy64 => 64,
124 Prescaler::DividedBy128 => 128,
125 Prescaler::DividedBy256 => 256,
126 }
127 }
128
129 fn presc(&self) -> Presc {
130 match self {
131 Prescaler::NotDivided => Presc::DIV1,
132 Prescaler::DividedBy2 => Presc::DIV2,
133 Prescaler::DividedBy4 => Presc::DIV4,
134 Prescaler::DividedBy6 => Presc::DIV6,
135 Prescaler::DividedBy8 => Presc::DIV8,
136 Prescaler::DividedBy10 => Presc::DIV10,
137 Prescaler::DividedBy12 => Presc::DIV12,
138 Prescaler::DividedBy16 => Presc::DIV16,
139 Prescaler::DividedBy32 => Presc::DIV32,
140 Prescaler::DividedBy64 => Presc::DIV64,
141 Prescaler::DividedBy128 => Presc::DIV128,
142 Prescaler::DividedBy256 => Presc::DIV256,
143 }
144 } 90 }
145} 91}
146 92
@@ -212,6 +158,7 @@ foreach_adc!(
212 reg.set_chselrmod(Chselrmod::ENABLE_INPUT) 158 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
213 }); 159 });
214 } 160 }
161 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
215 _ => unreachable!(), 162 _ => unreachable!(),
216 } 163 }
217 } 164 }
@@ -283,11 +230,11 @@ impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> {
283 /// Create a new ADC driver. 230 /// Create a new ADC driver.
284 pub fn new_adc4(adc: Peri<'d, T>) -> Self { 231 pub fn new_adc4(adc: Peri<'d, T>) -> Self {
285 rcc::enable_and_reset::<T>(); 232 rcc::enable_and_reset::<T>();
286 let prescaler = Prescaler::from_ker_ck(T::frequency()); 233 let prescaler = from_ker_ck(T::frequency());
287 234
288 T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 235 T::regs().ccr().modify(|w| w.set_presc(prescaler));
289 236
290 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 237 let frequency = T::frequency() / prescaler;
291 info!("ADC4 frequency set to {}", frequency); 238 info!("ADC4 frequency set to {}", frequency);
292 239
293 if frequency > MAX_ADC_CLK_FREQ { 240 if frequency > MAX_ADC_CLK_FREQ {
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index bc97a7c4b..3bdca7edb 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -1,12 +1,10 @@
1use pac::adc::vals::Scandir;
2#[allow(unused)] 1#[allow(unused)]
3use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; 2use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr};
4use pac::adccommon::vals::Presc; 3use pac::adccommon::vals::Presc;
4use stm32_metapac::adc::vals::Scandir;
5 5
6use super::{ 6use super::{Adc, Instance, Resolution, blocking_delay_us};
7 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, 7use crate::adc::{AnyInstance, ConversionMode};
8};
9use crate::dma::Transfer;
10use crate::time::Hertz; 8use crate::time::Hertz;
11use crate::{Peri, pac, rcc}; 9use crate::{Peri, pac, rcc};
12 10
@@ -32,123 +30,184 @@ impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
32 const CHANNEL: u8 = 9; 30 const CHANNEL: u8 = 9;
33} 31}
34 32
35#[derive(Copy, Clone, Debug)] 33fn from_ker_ck(frequency: Hertz) -> Presc {
36pub enum Prescaler { 34 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
37 NotDivided, 35 match raw_prescaler {
38 DividedBy2, 36 0 => Presc::DIV1,
39 DividedBy4, 37 1 => Presc::DIV2,
40 DividedBy6, 38 2..=3 => Presc::DIV4,
41 DividedBy8, 39 4..=5 => Presc::DIV6,
42 DividedBy10, 40 6..=7 => Presc::DIV8,
43 DividedBy12, 41 8..=9 => Presc::DIV10,
44 DividedBy16, 42 10..=11 => Presc::DIV12,
45 DividedBy32, 43 _ => unimplemented!(),
46 DividedBy64, 44 }
47 DividedBy128,
48 DividedBy256,
49} 45}
50 46
51impl Prescaler { 47impl<T: Instance> super::SealedAnyInstance for T {
52 fn from_ker_ck(frequency: Hertz) -> Self { 48 fn dr() -> *mut u16 {
53 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 49 T::regs().dr().as_ptr() as *mut u16
54 match raw_prescaler {
55 0 => Self::NotDivided,
56 1 => Self::DividedBy2,
57 2..=3 => Self::DividedBy4,
58 4..=5 => Self::DividedBy6,
59 6..=7 => Self::DividedBy8,
60 8..=9 => Self::DividedBy10,
61 10..=11 => Self::DividedBy12,
62 _ => unimplemented!(),
63 }
64 } 50 }
65 51
66 #[allow(unused)] 52 fn enable() {
67 fn divisor(&self) -> u32 { 53 T::regs().isr().modify(|w| w.set_adrdy(true));
68 match self { 54 T::regs().cr().modify(|w| w.set_aden(true));
69 Prescaler::NotDivided => 1, 55 // ADRDY is "ADC ready". Wait until it will be True.
70 Prescaler::DividedBy2 => 2, 56 while !T::regs().isr().read().adrdy() {}
71 Prescaler::DividedBy4 => 4, 57 }
72 Prescaler::DividedBy6 => 6, 58
73 Prescaler::DividedBy8 => 8, 59 fn start() {
74 Prescaler::DividedBy10 => 10, 60 // Start conversion
75 Prescaler::DividedBy12 => 12, 61 T::regs().cr().modify(|reg| {
76 Prescaler::DividedBy16 => 16, 62 reg.set_adstart(true);
77 Prescaler::DividedBy32 => 32, 63 });
78 Prescaler::DividedBy64 => 64, 64 }
79 Prescaler::DividedBy128 => 128, 65
80 Prescaler::DividedBy256 => 256, 66 fn stop() {
67 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
68 T::regs().cr().modify(|reg| {
69 reg.set_adstp(Adstp::STOP);
70 });
71 while T::regs().cr().read().adstart() {}
81 } 72 }
73
74 // Reset configuration.
75 T::regs().cfgr1().modify(|reg| {
76 reg.set_cont(false);
77 reg.set_dmacfg(Dmacfg::from_bits(0));
78 reg.set_dmaen(false);
79 });
82 } 80 }
83 81
84 fn presc(&self) -> Presc { 82 fn configure_dma(conversion_mode: super::ConversionMode) {
85 match self { 83 match conversion_mode {
86 Prescaler::NotDivided => Presc::DIV1, 84 ConversionMode::Singular => {
87 Prescaler::DividedBy2 => Presc::DIV2, 85 // Enable overrun control, so no new DMA requests will be generated until
88 Prescaler::DividedBy4 => Presc::DIV4, 86 // previous DR values is read.
89 Prescaler::DividedBy6 => Presc::DIV6, 87 T::regs().isr().modify(|reg| {
90 Prescaler::DividedBy8 => Presc::DIV8, 88 reg.set_ovr(true);
91 Prescaler::DividedBy10 => Presc::DIV10, 89 });
92 Prescaler::DividedBy12 => Presc::DIV12, 90
93 Prescaler::DividedBy16 => Presc::DIV16, 91 // Set continuous mode with oneshot dma.
94 Prescaler::DividedBy32 => Presc::DIV32, 92 T::regs().cfgr1().modify(|reg| {
95 Prescaler::DividedBy64 => Presc::DIV64, 93 reg.set_discen(false);
96 Prescaler::DividedBy128 => Presc::DIV128, 94 reg.set_cont(true);
97 Prescaler::DividedBy256 => Presc::DIV256, 95 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
96 reg.set_dmaen(true);
97 reg.set_ovrmod(Ovrmod::PRESERVE);
98 });
99 }
98 } 100 }
99 } 101 }
100}
101 102
102#[cfg(feature = "defmt")] 103 fn configure_sequence(mut sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool) {
103impl<'a> defmt::Format for Prescaler { 104 T::regs().cfgr1().modify(|reg| {
104 fn format(&self, fmt: defmt::Formatter) { 105 reg.set_chselrmod(!blocking);
105 match self { 106 reg.set_align(Align::RIGHT);
106 Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), 107 });
107 Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), 108
108 Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), 109 assert!(!blocking || sequence.len() == 1, "Sequence len must be 1 for blocking.");
109 Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), 110 if blocking {
110 Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), 111 let ((ch, _), sample_time) = sequence.next().unwrap();
111 Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), 112 // Set all channels to use SMP1 field as source.
112 Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), 113 T::regs().smpr().modify(|w| {
113 Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), 114 w.smpsel(0);
114 Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), 115 w.set_smp1(sample_time);
115 Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), 116 });
116 Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), 117
117 Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), 118 // write() because we want all other bits to be set to 0.
119 T::regs().chselr().write(|w| w.set_chsel(ch.into(), true));
120 } else {
121 let mut hw_channel_selection: u32 = 0;
122 let mut is_ordered_up = true;
123 let mut is_ordered_down = true;
124 let mut needs_hw = false;
125
126 assert!(
127 sequence.len() <= CHSELR_SQ_SIZE,
128 "Sequence read set cannot be more than {} in size.",
129 CHSELR_SQ_SIZE
130 );
131 let mut last_sq_set: usize = 0;
132 let mut last_channel: u8 = 0;
133 T::regs().chselr_sq().write(|w| {
134 for (i, ((channel, _), _sample_time)) in sequence.enumerate() {
135 needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL;
136 last_sq_set = i;
137 is_ordered_up = is_ordered_up && channel > last_channel;
138 is_ordered_down = is_ordered_down && channel < last_channel;
139 hw_channel_selection += 1 << channel;
140 last_channel = channel;
141
142 if !needs_hw {
143 w.set_sq(i, channel);
144 }
145 }
146
147 assert!(
148 !needs_hw || is_ordered_up || is_ordered_down,
149 "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.",
150 CHSELR_SQ_MAX_CHANNEL
151 );
152
153 if needs_hw {
154 assert!(
155 hw_channel_selection != 0,
156 "Some bits in `hw_channel_selection` shall be set."
157 );
158 assert!(
159 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
160 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
161 NUM_HW_CHANNELS
162 );
163
164 T::regs().cfgr1().modify(|reg| {
165 reg.set_chselrmod(false);
166 reg.set_scandir(if is_ordered_up { Scandir::UP} else { Scandir::BACK });
167 });
168
169 // Set required channels for multi-convert.
170 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
171 } else {
172 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
173 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
174 }
175 }
176 });
118 } 177 }
178
179 // Trigger and wait for the channel selection procedure to complete.
180 T::regs().isr().modify(|w| w.set_ccrdy(false));
181 while !T::regs().isr().read().ccrdy() {}
119 } 182 }
120}
121 183
122/// Number of samples used for averaging. 184 fn convert() -> u16 {
123/// TODO: Implement hardware averaging setting. 185 // Set single conversion mode.
124#[allow(unused)] 186 T::regs().cfgr1().modify(|w| w.set_cont(false));
125#[derive(Copy, Clone, Debug)] 187
126#[cfg_attr(feature = "defmt", derive(defmt::Format))] 188 // Start conversion
127pub enum Averaging { 189 T::regs().cr().modify(|reg| {
128 Disabled, 190 reg.set_adstart(true);
129 Samples2, 191 });
130 Samples4, 192
131 Samples8, 193 // Waiting for End Of Conversion (EOC).
132 Samples16, 194 while !T::regs().isr().read().eoc() {}
133 Samples32, 195
134 Samples64, 196 T::regs().dr().read().data() as u16
135 Samples128, 197 }
136 Samples256,
137 Samples512,
138 Samples1024,
139} 198}
140 199
141impl<'d, T: Instance> Adc<'d, T> { 200impl<'d, T: AnyInstance> Adc<'d, T> {
142 /// Create a new ADC driver. 201 /// Create a new ADC driver.
143 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { 202 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self {
144 rcc::enable_and_reset::<T>(); 203 rcc::enable_and_reset::<T>();
145 204
146 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); 205 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
147 206
148 let prescaler = Prescaler::from_ker_ck(T::frequency()); 207 let prescaler = from_ker_ck(T::frequency());
149 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 208 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
150 209
151 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 210 let frequency = T::frequency() / prescaler;
152 debug!("ADC frequency set to {}", frequency); 211 debug!("ADC frequency set to {}", frequency);
153 212
154 if frequency > MAX_ADC_CLK_FREQ { 213 if frequency > MAX_ADC_CLK_FREQ {
@@ -158,32 +217,16 @@ impl<'d, T: Instance> Adc<'d, T> {
158 ); 217 );
159 } 218 }
160 219
161 let mut s = Self { adc };
162
163 s.power_up();
164
165 s.set_resolution(resolution);
166
167 s.calibrate();
168
169 s.enable();
170
171 s.configure_default();
172
173 s
174 }
175
176 fn power_up(&mut self) {
177 T::regs().cr().modify(|reg| { 220 T::regs().cr().modify(|reg| {
178 reg.set_advregen(true); 221 reg.set_advregen(true);
179 }); 222 });
180 223
181 // "The software must wait for the ADC voltage regulator startup time." 224 // "The software must wait for the ADC voltage regulator startup time."
182 // See datasheet for the value. 225 // See datasheet for the value.
183 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); 226 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US as u64 + 1);
184 } 227
228 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
185 229
186 fn calibrate(&mut self) {
187 // We have to make sure AUTOFF is OFF, but keep its value after calibration. 230 // We have to make sure AUTOFF is OFF, but keep its value after calibration.
188 let autoff_value = T::regs().cfgr1().read().autoff(); 231 let autoff_value = T::regs().cfgr1().read().autoff();
189 T::regs().cfgr1().modify(|w| w.set_autoff(false)); 232 T::regs().cfgr1().modify(|w| w.set_autoff(false));
@@ -197,22 +240,17 @@ impl<'d, T: Instance> Adc<'d, T> {
197 debug!("ADC calibration value: {}.", T::regs().dr().read().data()); 240 debug!("ADC calibration value: {}.", T::regs().dr().read().data());
198 241
199 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); 242 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value));
200 }
201 243
202 fn enable(&mut self) { 244 T::enable();
203 T::regs().isr().modify(|w| w.set_adrdy(true));
204 T::regs().cr().modify(|w| w.set_aden(true));
205 // ADRDY is "ADC ready". Wait until it will be True.
206 while !T::regs().isr().read().adrdy() {}
207 }
208 245
209 fn configure_default(&mut self) {
210 // single conversion mode, software trigger 246 // single conversion mode, software trigger
211 T::regs().cfgr1().modify(|w| { 247 T::regs().cfgr1().modify(|w| {
212 w.set_cont(false); 248 w.set_cont(false);
213 w.set_exten(Exten::DISABLED); 249 w.set_exten(Exten::DISABLED);
214 w.set_align(Align::RIGHT); 250 w.set_align(Align::RIGHT);
215 }); 251 });
252
253 Self { adc }
216 } 254 }
217 255
218 /// Enable reading the voltage reference internal channel. 256 /// Enable reading the voltage reference internal channel.
@@ -233,219 +271,4 @@ impl<'d, T: Instance> Adc<'d, T> {
233 271
234 super::Temperature {} 272 super::Temperature {}
235 } 273 }
236
237 /// Set the ADC sample time.
238 /// Shall only be called when ADC is not converting.
239 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
240 // Set all channels to use SMP1 field as source.
241 T::regs().smpr().modify(|w| {
242 w.smpsel(0);
243 w.set_smp1(sample_time);
244 });
245 }
246
247 /// Set the ADC resolution.
248 pub fn set_resolution(&mut self, resolution: Resolution) {
249 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
250 }
251
252 /// Perform a single conversion.
253 fn convert(&mut self) -> u16 {
254 // Set single conversion mode.
255 T::regs().cfgr1().modify(|w| w.set_cont(false));
256
257 // Start conversion
258 T::regs().cr().modify(|reg| {
259 reg.set_adstart(true);
260 });
261
262 // Waiting for End Of Conversion (EOC).
263 while !T::regs().isr().read().eoc() {}
264
265 T::regs().dr().read().data() as u16
266 }
267
268 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
269 self.set_sample_time_all_channels(sample_time);
270
271 Self::configure_channel(channel);
272 T::regs().cfgr1().write(|reg| {
273 reg.set_chselrmod(false);
274 reg.set_align(Align::RIGHT);
275 });
276 self.convert()
277 }
278
279 fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) {
280 assert!(
281 channel_sequence.len() <= CHSELR_SQ_SIZE,
282 "Seqenced read set cannot be more than {} in size.",
283 CHSELR_SQ_SIZE
284 );
285 let mut last_sq_set: usize = 0;
286 T::regs().chselr_sq().write(|w| {
287 for (i, channel) in channel_sequence.enumerate() {
288 assert!(
289 channel.channel() <= CHSELR_SQ_MAX_CHANNEL,
290 "Sequencer only support HW channels smaller than {}.",
291 CHSELR_SQ_MAX_CHANNEL
292 );
293 w.set_sq(i, channel.channel());
294 last_sq_set = i;
295 }
296
297 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
298 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
299 }
300 });
301
302 Self::apply_channel_conf()
303 }
304
305 async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) {
306 // Enable overrun control, so no new DMA requests will be generated until
307 // previous DR values is read.
308 T::regs().isr().modify(|reg| {
309 reg.set_ovr(true);
310 });
311
312 // Set continuous mode with oneshot dma.
313 T::regs().cfgr1().modify(|reg| {
314 reg.set_discen(false);
315 reg.set_cont(true);
316 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
317 reg.set_dmaen(true);
318 reg.set_ovrmod(Ovrmod::PRESERVE);
319 });
320
321 let request = rx_dma.request();
322 let transfer = unsafe {
323 Transfer::new_read(
324 rx_dma,
325 request,
326 T::regs().dr().as_ptr() as *mut u16,
327 readings,
328 Default::default(),
329 )
330 };
331
332 // Start conversion.
333 T::regs().cr().modify(|reg| {
334 reg.set_adstart(true);
335 });
336
337 // Wait for conversion sequence to finish.
338 transfer.await;
339
340 // Ensure conversions are finished.
341 Self::cancel_conversions();
342
343 // Reset configuration.
344 T::regs().cfgr1().modify(|reg| {
345 reg.set_cont(false);
346 reg.set_dmacfg(Dmacfg::from_bits(0));
347 reg.set_dmaen(false);
348 });
349 }
350
351 /// Read one or multiple ADC channels using DMA in hardware order.
352 /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting.
353 /// Readings won't be in the same order as in the `set`!
354 ///
355 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
356 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
357 /// TODO(chudsaviet): externalize generic code and merge with read().
358 pub async fn read_in_hw_order(
359 &mut self,
360 rx_dma: Peri<'_, impl RxDma<T>>,
361 hw_channel_selection: u32,
362 scandir: Scandir,
363 readings: &mut [u16],
364 ) {
365 assert!(
366 hw_channel_selection != 0,
367 "Some bits in `hw_channel_selection` shall be set."
368 );
369 assert!(
370 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
371 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
372 NUM_HW_CHANNELS
373 );
374 // To check for correct readings slice size, we shall solve Hamming weight problem,
375 // which is either slow or memory consuming.
376 // Since we have limited resources, we don't do it here.
377 // Not doing this have a great potential for a bug through.
378
379 // Ensure no conversions are ongoing.
380 Self::cancel_conversions();
381
382 T::regs().cfgr1().modify(|reg| {
383 reg.set_chselrmod(false);
384 reg.set_scandir(scandir);
385 reg.set_align(Align::RIGHT);
386 });
387
388 // Set required channels for multi-convert.
389 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
390
391 Self::apply_channel_conf();
392
393 self.dma_convert(rx_dma, readings).await
394 }
395
396 // Read ADC channels in specified order using DMA (CHSELRMOD = 1).
397 // In STM32C0, only lower 14 ADC channels can be read this way.
398 // For other channels, use `read_in_hw_order()` or blocking read.
399 pub async fn read(
400 &mut self,
401 rx_dma: Peri<'_, impl RxDma<T>>,
402 channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
403 readings: &mut [u16],
404 ) {
405 assert!(
406 channel_sequence.len() != 0,
407 "Asynchronous read channel sequence cannot be empty."
408 );
409 assert!(
410 channel_sequence.len() == readings.len(),
411 "Channel sequence length must be equal to readings length."
412 );
413
414 // Ensure no conversions are ongoing.
415 Self::cancel_conversions();
416
417 T::regs().cfgr1().modify(|reg| {
418 reg.set_chselrmod(true);
419 reg.set_align(Align::RIGHT);
420 });
421
422 Self::setup_channel_sequencer(channel_sequence);
423
424 self.dma_convert(rx_dma, readings).await
425 }
426
427 fn configure_channel(channel: &mut impl AdcChannel<T>) {
428 channel.setup();
429 // write() because we want all other bits to be set to 0.
430 T::regs()
431 .chselr()
432 .write(|w| w.set_chsel(channel.channel().into(), true));
433
434 Self::apply_channel_conf();
435 }
436
437 fn apply_channel_conf() {
438 // Trigger and wait for the channel selection procedure to complete.
439 T::regs().isr().modify(|w| w.set_ccrdy(false));
440 while !T::regs().isr().read().ccrdy() {}
441 }
442
443 fn cancel_conversions() {
444 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
445 T::regs().cr().modify(|reg| {
446 reg.set_adstp(Adstp::STOP);
447 });
448 while T::regs().cr().read().adstart() {}
449 }
450 }
451} 274}
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index f6220de78..d6c6f480b 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -43,7 +43,7 @@ impl<'d, T: Instance> Adc<'d, T> {
43 43
44 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) 44 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
45 // for at least two ADC clock cycles. 45 // for at least two ADC clock cycles.
46 blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1); 46 blocking_delay_us((1_000_000 * 2) / Self::freq().0 as u64 + 1);
47 47
48 // Reset calibration 48 // Reset calibration
49 T::regs().cr2().modify(|reg| reg.set_rstcal(true)); 49 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
@@ -58,7 +58,7 @@ impl<'d, T: Instance> Adc<'d, T> {
58 } 58 }
59 59
60 // One cycle after calibration 60 // One cycle after calibration
61 blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1); 61 blocking_delay_us((1_000_000 * 1) / Self::freq().0 as u64 + 1);
62 62
63 T::Interrupt::unpend(); 63 T::Interrupt::unpend();
64 unsafe { T::Interrupt::enable() }; 64 unsafe { T::Interrupt::enable() };
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 4a77f3c5b..29bfdac97 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -62,7 +62,7 @@ impl<'d, T: Instance> Adc<'d, T> {
62 while T::regs().cr().read().adcal() {} 62 while T::regs().cr().read().adcal() {}
63 63
64 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223). 64 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223).
65 blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1); 65 blocking_delay_us((1_000_000 * 4) / Self::freq().0 as u64 + 1);
66 66
67 // Enable the adc 67 // Enable the adc
68 T::regs().cr().modify(|w| w.set_aden(true)); 68 T::regs().cr().modify(|w| w.set_aden(true));
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 71dc8acc0..514734017 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -32,71 +32,17 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
32#[cfg(stm32h7)] 32#[cfg(stm32h7)]
33const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 33const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
34 34
35// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 35fn from_ker_ck(frequency: Hertz) -> Presc {
36// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 36 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
37#[allow(unused)] 37 match raw_prescaler {
38enum Prescaler { 38 0 => Presc::DIV1,
39 NotDivided, 39 1 => Presc::DIV2,
40 DividedBy2, 40 2..=3 => Presc::DIV4,
41 DividedBy4, 41 4..=5 => Presc::DIV6,
42 DividedBy6, 42 6..=7 => Presc::DIV8,
43 DividedBy8, 43 8..=9 => Presc::DIV10,
44 DividedBy10, 44 10..=11 => Presc::DIV12,
45 DividedBy12, 45 _ => unimplemented!(),
46 DividedBy16,
47 DividedBy32,
48 DividedBy64,
49 DividedBy128,
50 DividedBy256,
51}
52
53impl Prescaler {
54 fn from_ker_ck(frequency: Hertz) -> Self {
55 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
56 match raw_prescaler {
57 0 => Self::NotDivided,
58 1 => Self::DividedBy2,
59 2..=3 => Self::DividedBy4,
60 4..=5 => Self::DividedBy6,
61 6..=7 => Self::DividedBy8,
62 8..=9 => Self::DividedBy10,
63 10..=11 => Self::DividedBy12,
64 _ => unimplemented!(),
65 }
66 }
67
68 fn divisor(&self) -> u32 {
69 match self {
70 Prescaler::NotDivided => 1,
71 Prescaler::DividedBy2 => 2,
72 Prescaler::DividedBy4 => 4,
73 Prescaler::DividedBy6 => 6,
74 Prescaler::DividedBy8 => 8,
75 Prescaler::DividedBy10 => 10,
76 Prescaler::DividedBy12 => 12,
77 Prescaler::DividedBy16 => 16,
78 Prescaler::DividedBy32 => 32,
79 Prescaler::DividedBy64 => 64,
80 Prescaler::DividedBy128 => 128,
81 Prescaler::DividedBy256 => 256,
82 }
83 }
84
85 fn presc(&self) -> Presc {
86 match self {
87 Prescaler::NotDivided => Presc::DIV1,
88 Prescaler::DividedBy2 => Presc::DIV2,
89 Prescaler::DividedBy4 => Presc::DIV4,
90 Prescaler::DividedBy6 => Presc::DIV6,
91 Prescaler::DividedBy8 => Presc::DIV8,
92 Prescaler::DividedBy10 => Presc::DIV10,
93 Prescaler::DividedBy12 => Presc::DIV12,
94 Prescaler::DividedBy16 => Presc::DIV16,
95 Prescaler::DividedBy32 => Presc::DIV32,
96 Prescaler::DividedBy64 => Presc::DIV64,
97 Prescaler::DividedBy128 => Presc::DIV128,
98 Prescaler::DividedBy256 => Presc::DIV256,
99 }
100 } 46 }
101} 47}
102 48
@@ -292,11 +238,11 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> {
292 pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { 238 pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self {
293 rcc::enable_and_reset::<T>(); 239 rcc::enable_and_reset::<T>();
294 240
295 let prescaler = Prescaler::from_ker_ck(T::frequency()); 241 let prescaler = from_ker_ck(T::frequency());
296 242
297 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 243 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
298 244
299 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 245 let frequency = T::frequency() / prescaler;
300 trace!("ADC frequency set to {}", frequency); 246 trace!("ADC frequency set to {}", frequency);
301 247
302 if frequency > MAX_ADC_CLK_FREQ { 248 if frequency > MAX_ADC_CLK_FREQ {
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 856c2e61e..5ec08a22d 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -35,6 +35,8 @@ pub use ringbuffered::RingBufferedAdc;
35#[path = "adc4.rs"] 35#[path = "adc4.rs"]
36pub mod adc4; 36pub mod adc4;
37 37
38#[allow(unused)]
39pub(self) use crate::block_for_us as blocking_delay_us;
38pub use crate::pac::adc::vals; 40pub use crate::pac::adc::vals;
39#[cfg(not(any(adc_f1, adc_f3v3)))] 41#[cfg(not(any(adc_f1, adc_f3v3)))]
40pub use crate::pac::adc::vals::Res as Resolution; 42pub use crate::pac::adc::vals::Res as Resolution;
@@ -88,31 +90,37 @@ pub(crate) trait SealedAdcChannel<T> {
88} 90}
89 91
90// Temporary patch for ADCs that have not implemented the standard iface yet 92// Temporary patch for ADCs that have not implemented the standard iface yet
91#[cfg(not(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4)))] 93#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))]
92trait_set::trait_set! { 94trait_set::trait_set! {
93 pub trait AnyInstance = Instance; 95 pub trait AnyInstance = Instance;
94} 96}
95 97
96#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 98#[cfg(any(
97#[allow(dead_code)] 99 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
100))]
98pub trait BasicAnyInstance { 101pub trait BasicAnyInstance {
99 type SampleTime; 102 type SampleTime;
100} 103}
101 104
102#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 105#[cfg(any(
103#[allow(dead_code)] 106 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
107))]
104pub(self) trait SealedAnyInstance: BasicAnyInstance { 108pub(self) trait SealedAnyInstance: BasicAnyInstance {
105 fn enable(); 109 fn enable();
106 fn start(); 110 fn start();
107 fn stop(); 111 fn stop();
108 fn convert() -> u16; 112 fn convert() -> u16;
109 fn configure_dma(conversion_mode: ConversionMode); 113 fn configure_dma(conversion_mode: ConversionMode);
114 #[cfg(not(adc_c0))]
110 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); 115 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>);
116 #[cfg(adc_c0)]
117 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool);
118 #[allow(dead_code)]
111 fn dr() -> *mut u16; 119 fn dr() -> *mut u16;
112} 120}
113 121
114// On chips without ADC4, AnyInstance is an Instance 122// On chips without ADC4, AnyInstance is an Instance
115#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4))] 123#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))]
116#[allow(private_bounds)] 124#[allow(private_bounds)]
117pub trait AnyInstance: SealedAnyInstance + Instance {} 125pub trait AnyInstance: SealedAnyInstance + Instance {}
118 126
@@ -122,44 +130,53 @@ pub trait AnyInstance: SealedAnyInstance + Instance {}
122pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} 130pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {}
123 131
124// Implement AnyInstance automatically for SealedAnyInstance 132// Implement AnyInstance automatically for SealedAnyInstance
125#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 133#[cfg(any(
134 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
135))]
126impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { 136impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T {
127 type SampleTime = SampleTime; 137 type SampleTime = SampleTime;
128} 138}
129 139
130#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 140#[cfg(any(
141 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
142))]
131impl<T: SealedAnyInstance + Instance> AnyInstance for T {} 143impl<T: SealedAnyInstance + Instance> AnyInstance for T {}
132 144
133/// Performs a busy-wait delay for a specified number of microseconds. 145#[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
134#[allow(unused)] 146/// Number of samples used for averaging.
135pub(crate) fn blocking_delay_us(us: u32) { 147#[derive(Copy, Clone, Debug)]
136 cfg_if::cfg_if! { 148#[cfg_attr(feature = "defmt", derive(defmt::Format))]
137 // this does strange things on stm32wlx in low power mode depending on exactly when it's called 149pub enum Averaging {
138 // as in sometimes 15 us (1 tick) would take > 20 seconds. 150 Disabled,
139 if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] { 151 Samples2,
140 let duration = embassy_time::Duration::from_micros(us as u64); 152 Samples4,
141 embassy_time::block_for(duration); 153 Samples8,
142 } else { 154 Samples16,
143 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; 155 Samples32,
144 let us = us as u64; 156 Samples64,
145 let cycles = freq * us / 1_000_000; 157 Samples128,
146 cortex_m::asm::delay(cycles as u32); 158 Samples256,
147 } 159 #[cfg(any(adc_c0, adc_v4, adc_u5))]
148 } 160 Samples512,
161 #[cfg(any(adc_c0, adc_v4, adc_u5))]
162 Samples1024,
149} 163}
150 164
151#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 165#[cfg(any(
152#[allow(dead_code)] 166 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0
167))]
153pub(crate) enum ConversionMode { 168pub(crate) enum ConversionMode {
154 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 169 // Should match the cfg on "read" below
170 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
155 Singular, 171 Singular,
156 #[allow(dead_code)] 172 // Should match the cfg on "into_ring_buffered" below
173 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
157 Repeated(RegularConversionMode), 174 Repeated(RegularConversionMode),
158} 175}
159 176
160#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 177// Should match the cfg on "into_ring_buffered" below
178#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
161// Conversion mode for regular ADC channels 179// Conversion mode for regular ADC channels
162#[allow(dead_code)]
163#[derive(Copy, Clone)] 180#[derive(Copy, Clone)]
164pub enum RegularConversionMode { 181pub enum RegularConversionMode {
165 // Samples as fast as possible 182 // Samples as fast as possible
@@ -170,7 +187,9 @@ pub enum RegularConversionMode {
170} 187}
171 188
172impl<'d, T: AnyInstance> Adc<'d, T> { 189impl<'d, T: AnyInstance> Adc<'d, T> {
173 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba))] 190 #[cfg(any(
191 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0
192 ))]
174 /// Read an ADC pin. 193 /// Read an ADC pin.
175 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { 194 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 {
176 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 195 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
@@ -178,12 +197,18 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
178 197
179 #[cfg(not(adc_v4))] 198 #[cfg(not(adc_v4))]
180 T::enable(); 199 T::enable();
200 #[cfg(not(adc_c0))]
181 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); 201 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
202 #[cfg(adc_c0)]
203 T::configure_sequence(
204 [((channel.channel(), channel.is_differential()), sample_time)].into_iter(),
205 true,
206 );
182 207
183 T::convert() 208 T::convert()
184 } 209 }
185 210
186 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 211 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
187 /// Read one or multiple ADC regular channels using DMA. 212 /// Read one or multiple ADC regular channels using DMA.
188 /// 213 ///
189 /// `sequence` iterator and `readings` must have the same length. 214 /// `sequence` iterator and `readings` must have the same length.
@@ -212,6 +237,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
212 /// 237 ///
213 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use 238 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
214 /// `into_ring_buffered`, `into_ring_buffered_and_injected` 239 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
240 ///
241 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
242 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
243 ///
244 /// In addtion, on STM320, this method will panic if the channels are not passed in order
215 pub async fn read( 245 pub async fn read(
216 &mut self, 246 &mut self,
217 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, 247 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
@@ -232,8 +262,15 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
232 T::stop(); 262 T::stop();
233 T::enable(); 263 T::enable();
234 264
265 #[cfg(not(adc_c0))]
266 T::configure_sequence(
267 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
268 );
269
270 #[cfg(adc_c0)]
235 T::configure_sequence( 271 T::configure_sequence(
236 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), 272 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
273 false,
237 ); 274 );
238 275
239 T::configure_dma(ConversionMode::Singular); 276 T::configure_dma(ConversionMode::Singular);
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 4065f89a7..07eaebf7c 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -3,6 +3,7 @@ use core::sync::atomic::{Ordering, compiler_fence};
3use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; 3use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us};
4use crate::adc::{Adc, Instance, Resolution, SampleTime}; 4use crate::adc::{Adc, Instance, Resolution, SampleTime};
5use crate::pac::adc::vals; 5use crate::pac::adc::vals;
6pub use crate::pac::adccommon::vals::Adcpre;
6use crate::time::Hertz; 7use crate::time::Hertz;
7use crate::{Peri, rcc}; 8use crate::{Peri, rcc};
8 9
@@ -50,38 +51,20 @@ impl Temperature {
50 } 51 }
51} 52}
52 53
53enum Prescaler { 54fn from_pclk2(freq: Hertz) -> Adcpre {
54 Div2, 55 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V).
55 Div4, 56 #[cfg(stm32f2)]
56 Div6, 57 const MAX_FREQUENCY: Hertz = Hertz(30_000_000);
57 Div8, 58 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
58} 59 #[cfg(not(stm32f2))]
59 60 const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
60impl Prescaler { 61 let raw_div = freq.0 / MAX_FREQUENCY.0;
61 fn from_pclk2(freq: Hertz) -> Self { 62 match raw_div {
62 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). 63 0..=1 => Adcpre::DIV2,
63 #[cfg(stm32f2)] 64 2..=3 => Adcpre::DIV4,
64 const MAX_FREQUENCY: Hertz = Hertz(30_000_000); 65 4..=5 => Adcpre::DIV6,
65 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. 66 6..=7 => Adcpre::DIV8,
66 #[cfg(not(stm32f2))] 67 _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."),
67 const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
68 let raw_div = freq.0 / MAX_FREQUENCY.0;
69 match raw_div {
70 0..=1 => Self::Div2,
71 2..=3 => Self::Div4,
72 4..=5 => Self::Div6,
73 6..=7 => Self::Div8,
74 _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."),
75 }
76 }
77
78 fn adcpre(&self) -> crate::pac::adccommon::vals::Adcpre {
79 match self {
80 Prescaler::Div2 => crate::pac::adccommon::vals::Adcpre::DIV2,
81 Prescaler::Div4 => crate::pac::adccommon::vals::Adcpre::DIV4,
82 Prescaler::Div6 => crate::pac::adccommon::vals::Adcpre::DIV6,
83 Prescaler::Div8 => crate::pac::adccommon::vals::Adcpre::DIV8,
84 }
85 } 68 }
86} 69}
87 70
@@ -224,8 +207,8 @@ where
224 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { 207 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
225 rcc::enable_and_reset::<T>(); 208 rcc::enable_and_reset::<T>();
226 209
227 let presc = Prescaler::from_pclk2(T::frequency()); 210 let presc = from_pclk2(T::frequency());
228 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); 211 T::common_regs().ccr().modify(|w| w.set_adcpre(presc));
229 T::regs().cr2().modify(|reg| { 212 T::regs().cr2().modify(|reg| {
230 reg.set_adon(true); 213 reg.set_adon(true);
231 }); 214 });
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index ba1afbe05..288bd77ce 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -11,7 +11,7 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc};
11 11
12#[allow(unused_imports)] 12#[allow(unused_imports)]
13use super::SealedAdcChannel; 13use super::SealedAdcChannel;
14use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; 14use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
15use crate::adc::ConversionMode; 15use crate::adc::ConversionMode;
16use crate::{Peri, pac, rcc}; 16use crate::{Peri, pac, rcc};
17 17
@@ -100,21 +100,6 @@ cfg_if! {
100 } 100 }
101} 101}
102 102
103/// Number of samples used for averaging.
104#[derive(Copy, Clone, Debug)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub enum Averaging {
107 Disabled,
108 Samples2,
109 Samples4,
110 Samples8,
111 Samples16,
112 Samples32,
113 Samples64,
114 Samples128,
115 Samples256,
116}
117
118cfg_if! { if #[cfg(adc_g0)] { 103cfg_if! { if #[cfg(adc_g0)] {
119 104
120/// Synchronous PCLK prescaler 105/// Synchronous PCLK prescaler
@@ -267,6 +252,7 @@ impl<T: Instance> super::SealedAnyInstance for T {
267 reg.set_cont(true); 252 reg.set_cont(true);
268 reg.set_dmacfg(match conversion_mode { 253 reg.set_dmacfg(match conversion_mode {
269 ConversionMode::Singular => Dmacfg::ONE_SHOT, 254 ConversionMode::Singular => Dmacfg::ONE_SHOT,
255 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
270 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, 256 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
271 }); 257 });
272 reg.set_dmaen(true); 258 reg.set_dmaen(true);
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 43eb16fd5..804e63db6 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -4,7 +4,7 @@ use pac::adc::vals::{Adcaldif, Boost};
4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; 4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 5use pac::adccommon::vals::Presc;
6 6
7use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; 7use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
8use crate::adc::ConversionMode; 8use crate::adc::ConversionMode;
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{Peri, pac, rcc}; 10use crate::{Peri, pac, rcc};
@@ -59,91 +59,20 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
59 const CHANNEL: u8 = 18; 59 const CHANNEL: u8 = 18;
60} 60}
61 61
62// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 62fn from_ker_ck(frequency: Hertz) -> Presc {
63// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 63 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
64#[allow(unused)] 64 match raw_prescaler {
65enum Prescaler { 65 0 => Presc::DIV1,
66 NotDivided, 66 1 => Presc::DIV2,
67 DividedBy2, 67 2..=3 => Presc::DIV4,
68 DividedBy4, 68 4..=5 => Presc::DIV6,
69 DividedBy6, 69 6..=7 => Presc::DIV8,
70 DividedBy8, 70 8..=9 => Presc::DIV10,
71 DividedBy10, 71 10..=11 => Presc::DIV12,
72 DividedBy12, 72 _ => unimplemented!(),
73 DividedBy16,
74 DividedBy32,
75 DividedBy64,
76 DividedBy128,
77 DividedBy256,
78}
79
80impl Prescaler {
81 fn from_ker_ck(frequency: Hertz) -> Self {
82 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
83 match raw_prescaler {
84 0 => Self::NotDivided,
85 1 => Self::DividedBy2,
86 2..=3 => Self::DividedBy4,
87 4..=5 => Self::DividedBy6,
88 6..=7 => Self::DividedBy8,
89 8..=9 => Self::DividedBy10,
90 10..=11 => Self::DividedBy12,
91 _ => unimplemented!(),
92 }
93 }
94
95 fn divisor(&self) -> u32 {
96 match self {
97 Prescaler::NotDivided => 1,
98 Prescaler::DividedBy2 => 2,
99 Prescaler::DividedBy4 => 4,
100 Prescaler::DividedBy6 => 6,
101 Prescaler::DividedBy8 => 8,
102 Prescaler::DividedBy10 => 10,
103 Prescaler::DividedBy12 => 12,
104 Prescaler::DividedBy16 => 16,
105 Prescaler::DividedBy32 => 32,
106 Prescaler::DividedBy64 => 64,
107 Prescaler::DividedBy128 => 128,
108 Prescaler::DividedBy256 => 256,
109 }
110 }
111
112 fn presc(&self) -> Presc {
113 match self {
114 Prescaler::NotDivided => Presc::DIV1,
115 Prescaler::DividedBy2 => Presc::DIV2,
116 Prescaler::DividedBy4 => Presc::DIV4,
117 Prescaler::DividedBy6 => Presc::DIV6,
118 Prescaler::DividedBy8 => Presc::DIV8,
119 Prescaler::DividedBy10 => Presc::DIV10,
120 Prescaler::DividedBy12 => Presc::DIV12,
121 Prescaler::DividedBy16 => Presc::DIV16,
122 Prescaler::DividedBy32 => Presc::DIV32,
123 Prescaler::DividedBy64 => Presc::DIV64,
124 Prescaler::DividedBy128 => Presc::DIV128,
125 Prescaler::DividedBy256 => Presc::DIV256,
126 }
127 } 73 }
128} 74}
129 75
130/// Number of samples used for averaging.
131#[derive(Copy, Clone, Debug)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133pub enum Averaging {
134 Disabled,
135 Samples2,
136 Samples4,
137 Samples8,
138 Samples16,
139 Samples32,
140 Samples64,
141 Samples128,
142 Samples256,
143 Samples512,
144 Samples1024,
145}
146
147/// Adc configuration 76/// Adc configuration
148#[derive(Default)] 77#[derive(Default)]
149pub struct AdcConfig { 78pub struct AdcConfig {
@@ -214,6 +143,7 @@ impl<T: Instance> super::SealedAnyInstance for T {
214 reg.set_dmngt(Dmngt::DMA_ONE_SHOT); 143 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
215 }); 144 });
216 } 145 }
146 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
217 _ => unreachable!(), 147 _ => unreachable!(),
218 } 148 }
219 } 149 }
@@ -309,11 +239,11 @@ impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> {
309 pub fn new(adc: Peri<'d, T>) -> Self { 239 pub fn new(adc: Peri<'d, T>) -> Self {
310 rcc::enable_and_reset::<T>(); 240 rcc::enable_and_reset::<T>();
311 241
312 let prescaler = Prescaler::from_ker_ck(T::frequency()); 242 let prescaler = from_ker_ck(T::frequency());
313 243
314 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 244 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
315 245
316 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 246 let frequency = T::frequency() / prescaler;
317 info!("ADC frequency set to {}", frequency); 247 info!("ADC frequency set to {}", frequency);
318 248
319 if frequency > MAX_ADC_CLK_FREQ { 249 if frequency > MAX_ADC_CLK_FREQ {