aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs25
-rw-r--r--embassy-stm32/src/adc/mod.rs51
-rw-r--r--embassy-stm32/src/adc/v1.rs1
-rw-r--r--embassy-stm32/src/adc/v4.rs542
-rw-r--r--embassy-stm32/src/rcc/h7.rs39
-rw-r--r--embassy-stm32/src/rcc/mod.rs3
-rw-r--r--examples/stm32h7/Cargo.toml2
-rw-r--r--examples/stm32h7/src/bin/adc.rs42
m---------stm32-data0
9 files changed, 693 insertions, 12 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 2c8409a35..9125155c5 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -145,7 +145,10 @@ fn main() {
145 // Generate RccPeripheral impls 145 // Generate RccPeripheral impls
146 146
147 for p in METADATA.peripherals { 147 for p in METADATA.peripherals {
148 if !singletons.contains(&p.name.to_string()) { 148 // generating RccPeripheral impl for H7 ADC3 would result in bad frequency
149 if !singletons.contains(&p.name.to_string())
150 || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7"))
151 {
149 continue; 152 continue;
150 } 153 }
151 154
@@ -459,11 +462,23 @@ fn main() {
459 if regs.kind == "adc" { 462 if regs.kind == "adc" {
460 let peri = format_ident!("{}", p.name); 463 let peri = format_ident!("{}", p.name);
461 let pin_name = format_ident!("{}", pin.pin); 464 let pin_name = format_ident!("{}", pin.pin);
462 let ch: u8 = pin.signal.strip_prefix("IN").unwrap().parse().unwrap();
463 465
464 g.extend(quote! { 466 // H7 has differential voltage measurements
465 impl_adc_pin!( #peri, #pin_name, #ch); 467 let ch: Option<u8> = if pin.signal.starts_with("INP") {
466 }) 468 Some(pin.signal.strip_prefix("INP").unwrap().parse().unwrap())
469 } else if pin.signal.starts_with("INN") {
470 // TODO handle in the future when embassy supports differential measurements
471 None
472 } else if pin.signal.starts_with("IN") {
473 Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap())
474 } else {
475 None
476 };
477 if let Some(ch) = ch {
478 g.extend(quote! {
479 impl_adc_pin!( #peri, #pin_name, #ch);
480 })
481 }
467 } 482 }
468 483
469 // DAC is special 484 // DAC is special
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 7b3233a1d..8da13073e 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -1,9 +1,11 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg_attr(adc_v4, path = "v4.rs")]
3#[cfg_attr(adc_v3, path = "v3.rs")] 4#[cfg_attr(adc_v3, path = "v3.rs")]
4#[cfg_attr(adc_v2, path = "v2.rs")] 5#[cfg_attr(adc_v2, path = "v2.rs")]
5#[cfg_attr(adc_g0, path = "v3.rs")] 6#[cfg_attr(adc_g0, path = "v3.rs")]
6#[cfg_attr(adc_f1, path = "f1.rs")] 7#[cfg_attr(adc_f1, path = "f1.rs")]
8#[cfg_attr(adc_v1, path = "v1.rs")]
7mod _version; 9mod _version;
8 10
9#[allow(unused)] 11#[allow(unused)]
@@ -14,11 +16,11 @@ use crate::peripherals;
14pub(crate) mod sealed { 16pub(crate) mod sealed {
15 pub trait Instance { 17 pub trait Instance {
16 fn regs() -> &'static crate::pac::adc::Adc; 18 fn regs() -> &'static crate::pac::adc::Adc;
17 #[cfg(not(adc_f1))] 19 #[cfg(all(not(adc_f1), not(adc_v1)))]
18 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon; 20 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon;
19 } 21 }
20 22
21 #[cfg(not(adc_f1))] 23 #[cfg(all(not(adc_f1), not(adc_v1)))]
22 pub trait Common { 24 pub trait Common {
23 fn regs() -> &'static crate::pac::adccommon::AdcCommon; 25 fn regs() -> &'static crate::pac::adccommon::AdcCommon;
24 } 26 }
@@ -32,17 +34,18 @@ pub(crate) mod sealed {
32pub trait Instance: sealed::Instance + 'static {} 34pub trait Instance: sealed::Instance + 'static {}
33#[cfg(adc_f1)] 35#[cfg(adc_f1)]
34pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral + 'static {} 36pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral + 'static {}
35#[cfg(not(adc_f1))] 37#[cfg(all(not(adc_f1), not(adc_v1)))]
36pub trait Common: sealed::Common + 'static {} 38pub trait Common: sealed::Common + 'static {}
37pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 39pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
38 40
41#[cfg(not(stm32h7))]
39foreach_peripheral!( 42foreach_peripheral!(
40 (adc, $inst:ident) => { 43 (adc, $inst:ident) => {
41 impl crate::adc::sealed::Instance for peripherals::$inst { 44 impl crate::adc::sealed::Instance for peripherals::$inst {
42 fn regs() -> &'static crate::pac::adc::Adc { 45 fn regs() -> &'static crate::pac::adc::Adc {
43 &crate::pac::$inst 46 &crate::pac::$inst
44 } 47 }
45 #[cfg(not(adc_f1))] 48 #[cfg(all(not(adc_f1), not(adc_v1)))]
46 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon { 49 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
47 foreach_peripheral!{ 50 foreach_peripheral!{
48 (adccommon, $common_inst:ident) => { 51 (adccommon, $common_inst:ident) => {
@@ -56,7 +59,45 @@ foreach_peripheral!(
56 }; 59 };
57); 60);
58 61
59#[cfg(not(adc_f1))] 62#[cfg(stm32h7)]
63foreach_peripheral!(
64 (adc, ADC3) => {
65 impl crate::adc::sealed::Instance for peripherals::ADC3 {
66 fn regs() -> &'static crate::pac::adc::Adc {
67 &crate::pac::ADC3
68 }
69 #[cfg(all(not(adc_f1), not(adc_v1)))]
70 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
71 foreach_peripheral!{
72 (adccommon, ADC3_COMMON) => {
73 return &crate::pac::ADC3_COMMON
74 };
75 }
76 }
77 }
78
79 impl crate::adc::Instance for peripherals::ADC3 {}
80 };
81 (adc, $inst:ident) => {
82 impl crate::adc::sealed::Instance for peripherals::$inst {
83 fn regs() -> &'static crate::pac::adc::Adc {
84 &crate::pac::$inst
85 }
86 #[cfg(all(not(adc_f1), not(adc_v1)))]
87 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
88 foreach_peripheral!{
89 (adccommon, ADC_COMMON) => {
90 return &crate::pac::ADC_COMMON
91 };
92 }
93 }
94 }
95
96 impl crate::adc::Instance for peripherals::$inst {}
97 };
98);
99
100#[cfg(all(not(adc_f1), not(adc_v1)))]
60foreach_peripheral!( 101foreach_peripheral!(
61 (adccommon, $inst:ident) => { 102 (adccommon, $inst:ident) => {
62 impl sealed::Common for peripherals::$inst { 103 impl sealed::Common for peripherals::$inst {
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/embassy-stm32/src/adc/v1.rs
@@ -0,0 +1 @@
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
new file mode 100644
index 000000000..11df9677e
--- /dev/null
+++ b/embassy-stm32/src/adc/v4.rs
@@ -0,0 +1,542 @@
1use core::marker::PhantomData;
2
3use crate::time::{Hertz, U32Ext};
4use atomic_polyfill::AtomicU8;
5use atomic_polyfill::Ordering;
6use embassy::util::Unborrow;
7use embedded_hal_02::blocking::delay::DelayUs;
8use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
9use pac::adccommon::vals::Presc;
10
11use crate::pac;
12
13use super::{AdcPin, Instance};
14
15pub enum Resolution {
16 SixteenBit,
17 FourteenBit,
18 TwelveBit,
19 TenBit,
20 EightBit,
21}
22
23impl Default for Resolution {
24 fn default() -> Self {
25 Self::SixteenBit
26 }
27}
28
29impl Resolution {
30 fn res(&self) -> pac::adc::vals::Res {
31 match self {
32 Resolution::SixteenBit => pac::adc::vals::Res::SIXTEENBIT,
33 Resolution::FourteenBit => pac::adc::vals::Res::FOURTEENBITV,
34 Resolution::TwelveBit => pac::adc::vals::Res::TWELVEBITV,
35 Resolution::TenBit => pac::adc::vals::Res::TENBIT,
36 Resolution::EightBit => pac::adc::vals::Res::EIGHTBIT,
37 }
38 }
39
40 pub fn to_max_count(&self) -> u32 {
41 match self {
42 Resolution::SixteenBit => (1 << 16) - 1,
43 Resolution::FourteenBit => (1 << 14) - 1,
44 Resolution::TwelveBit => (1 << 12) - 1,
45 Resolution::TenBit => (1 << 10) - 1,
46 Resolution::EightBit => (1 << 8) - 1,
47 }
48 }
49}
50
51pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
52
53mod sealed {
54 pub trait InternalChannel<T> {
55 fn channel(&self) -> u8;
56 }
57}
58
59// NOTE: Vref/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
60pub struct Vref;
61impl<T: Instance> InternalChannel<T> for Vref {}
62impl<T: Instance> sealed::InternalChannel<T> for Vref {
63 fn channel(&self) -> u8 {
64 19
65 }
66}
67
68pub struct Temperature;
69impl<T: Instance> InternalChannel<T> for Temperature {}
70impl<T: Instance> sealed::InternalChannel<T> for Temperature {
71 fn channel(&self) -> u8 {
72 18
73 }
74}
75
76pub struct Vbat;
77impl<T: Instance> InternalChannel<T> for Vbat {}
78impl<T: Instance> sealed::InternalChannel<T> for Vbat {
79 fn channel(&self) -> u8 {
80 // TODO this should be 14 for H7a/b/35
81 17
82 }
83}
84
85static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
86
87#[cfg(stm32h7)]
88foreach_peripheral!(
89 (adc, ADC1) => {
90 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
91 fn frequency() -> crate::time::Hertz {
92 critical_section::with(|_| unsafe {
93 match crate::rcc::get_freqs().adc {
94 Some(ck) => ck,
95 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
96 }
97 })
98 }
99
100 fn enable() {
101 critical_section::with(|_| unsafe {
102 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
103 });
104 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
105 }
106
107 fn disable() {
108 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
109 critical_section::with(|_| unsafe {
110 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
111 })
112 }
113 ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
114 }
115
116 fn reset() {
117 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
118 critical_section::with(|_| unsafe {
119 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
120 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
121 });
122 }
123 }
124 }
125
126 impl crate::rcc::RccPeripheral for crate::peripherals::ADC1 {}
127 };
128 (adc, ADC2) => {
129 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
130 fn frequency() -> crate::time::Hertz {
131 critical_section::with(|_| unsafe {
132 match crate::rcc::get_freqs().adc {
133 Some(ck) => ck,
134 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
135 }
136 })
137 }
138
139 fn enable() {
140 critical_section::with(|_| unsafe {
141 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
142 });
143 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
144 }
145
146 fn disable() {
147 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
148 critical_section::with(|_| unsafe {
149 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
150 })
151 }
152 ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
153 }
154
155 fn reset() {
156 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
157 critical_section::with(|_| unsafe {
158 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
159 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
160 });
161 }
162 }
163 }
164
165 impl crate::rcc::RccPeripheral for crate::peripherals::ADC2 {}
166 };
167 (adc, ADC3) => {
168 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
169 fn frequency() -> crate::time::Hertz {
170 critical_section::with(|_| unsafe {
171 match crate::rcc::get_freqs().adc {
172 Some(ck) => ck,
173 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
174 }
175 })
176 }
177
178 fn enable() {
179 critical_section::with(|_| unsafe {
180 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
181 });
182 }
183
184 fn disable() {
185 critical_section::with(|_| unsafe {
186 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
187 })
188 }
189
190 fn reset() {
191 critical_section::with(|_| unsafe {
192 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
193 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
194 });
195 }
196 }
197
198 impl crate::rcc::RccPeripheral for crate::peripherals::ADC3 {}
199 };
200);
201
202/// ADC sample time
203///
204/// The default setting is 2.5 ADC clock cycles.
205#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
206pub enum SampleTime {
207 /// 1.5 ADC clock cycles
208 Cycles1_5,
209
210 /// 2.5 ADC clock cycles
211 Cycles2_5,
212
213 /// 8.5 ADC clock cycles
214 Cycles8_5,
215
216 /// 16.5 ADC clock cycles
217 Cycles16_5,
218
219 /// 32.5 ADC clock cycles
220 Cycles32_5,
221
222 /// 64.5 ADC clock cycles
223 Cycles64_5,
224
225 /// 387.5 ADC clock cycles
226 Cycles387_5,
227
228 /// 810.5 ADC clock cycles
229 Cycles810_5,
230}
231
232impl SampleTime {
233 pub(crate) fn sample_time(&self) -> pac::adc::vals::Smp {
234 match self {
235 SampleTime::Cycles1_5 => pac::adc::vals::Smp::CYCLES1_5,
236 SampleTime::Cycles2_5 => pac::adc::vals::Smp::CYCLES2_5,
237 SampleTime::Cycles8_5 => pac::adc::vals::Smp::CYCLES8_5,
238 SampleTime::Cycles16_5 => pac::adc::vals::Smp::CYCLES16_5,
239 SampleTime::Cycles32_5 => pac::adc::vals::Smp::CYCLES32_5,
240 SampleTime::Cycles64_5 => pac::adc::vals::Smp::CYCLES64_5,
241 SampleTime::Cycles387_5 => pac::adc::vals::Smp::CYCLES387_5,
242 SampleTime::Cycles810_5 => pac::adc::vals::Smp::CYCLES810_5,
243 }
244 }
245}
246
247impl Default for SampleTime {
248 fn default() -> Self {
249 Self::Cycles1_5
250 }
251}
252
253// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
254// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
255#[allow(unused)]
256enum Prescaler {
257 NotDivided,
258 DividedBy2,
259 DividedBy4,
260 DividedBy6,
261 DividedBy8,
262 DividedBy10,
263 DividedBy12,
264 DividedBy16,
265 DividedBy32,
266 DividedBy64,
267 DividedBy128,
268 DividedBy256,
269}
270
271impl Prescaler {
272 fn from_ker_ck(frequency: Hertz) -> Self {
273 let raw_prescaler = frequency.0 / 50_000_000;
274 match raw_prescaler {
275 0 => Self::NotDivided,
276 1 => Self::DividedBy2,
277 2..=3 => Self::DividedBy4,
278 4..=5 => Self::DividedBy6,
279 6..=7 => Self::DividedBy8,
280 8..=9 => Self::DividedBy10,
281 10..=11 => Self::DividedBy12,
282 _ => unimplemented!(),
283 }
284 }
285
286 fn divisor(&self) -> u32 {
287 match self {
288 Prescaler::NotDivided => 1,
289 Prescaler::DividedBy2 => 2,
290 Prescaler::DividedBy4 => 4,
291 Prescaler::DividedBy6 => 6,
292 Prescaler::DividedBy8 => 8,
293 Prescaler::DividedBy10 => 10,
294 Prescaler::DividedBy12 => 12,
295 Prescaler::DividedBy16 => 16,
296 Prescaler::DividedBy32 => 32,
297 Prescaler::DividedBy64 => 64,
298 Prescaler::DividedBy128 => 128,
299 Prescaler::DividedBy256 => 256,
300 }
301 }
302
303 fn presc(&self) -> Presc {
304 match self {
305 Prescaler::NotDivided => Presc::DIV1,
306 Prescaler::DividedBy2 => Presc::DIV2,
307 Prescaler::DividedBy4 => Presc::DIV4,
308 Prescaler::DividedBy6 => Presc::DIV6,
309 Prescaler::DividedBy8 => Presc::DIV8,
310 Prescaler::DividedBy10 => Presc::DIV10,
311 Prescaler::DividedBy12 => Presc::DIV12,
312 Prescaler::DividedBy16 => Presc::DIV16,
313 Prescaler::DividedBy32 => Presc::DIV32,
314 Prescaler::DividedBy64 => Presc::DIV64,
315 Prescaler::DividedBy128 => Presc::DIV128,
316 Prescaler::DividedBy256 => Presc::DIV256,
317 }
318 }
319}
320
321pub struct Adc<'d, T: Instance> {
322 sample_time: SampleTime,
323 resolution: Resolution,
324 phantom: PhantomData<&'d mut T>,
325}
326
327impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
328 pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
329 embassy_hal_common::unborrow!(_peri);
330 T::enable();
331 T::reset();
332
333 let prescaler = Prescaler::from_ker_ck(T::frequency());
334
335 unsafe {
336 T::common_regs()
337 .ccr()
338 .modify(|w| w.set_presc(prescaler.presc()));
339 }
340
341 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
342 defmt::info!("ADC frequency set to {} Hz", frequency.0);
343
344 if frequency > 50.mhz().into() {
345 panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information.");
346 }
347 let boost = if frequency < 6_250.khz().into() {
348 Boost::LT6_25
349 } else if frequency < 12_500.khz().into() {
350 Boost::LT12_5
351 } else if frequency < 25.mhz().into() {
352 Boost::LT25
353 } else {
354 Boost::LT50
355 };
356 unsafe {
357 T::regs().cr().modify(|w| w.set_boost(boost));
358 }
359
360 let mut s = Self {
361 sample_time: Default::default(),
362 resolution: Resolution::default(),
363 phantom: PhantomData,
364 };
365 s.power_up(delay);
366 s.configure_differential_inputs();
367
368 s.calibrate();
369 delay.delay_us(1);
370
371 s.enable();
372 s.configure();
373
374 s
375 }
376
377 fn power_up(&mut self, delay: &mut impl DelayUs<u16>) {
378 unsafe {
379 T::regs().cr().modify(|reg| {
380 reg.set_deeppwd(false);
381 reg.set_advregen(true);
382 });
383 }
384
385 delay.delay_us(10);
386 }
387
388 fn configure_differential_inputs(&mut self) {
389 unsafe {
390 T::regs().difsel().modify(|w| {
391 for n in 0..20 {
392 w.set_difsel(n, Difsel::SINGLEENDED);
393 }
394 })
395 };
396 }
397
398 fn calibrate(&mut self) {
399 unsafe {
400 T::regs().cr().modify(|w| {
401 w.set_adcaldif(Adcaldif::SINGLEENDED);
402 w.set_adcallin(true);
403 });
404
405 T::regs().cr().modify(|w| w.set_adcal(true));
406
407 while T::regs().cr().read().adcal() {}
408 }
409 }
410
411 fn enable(&mut self) {
412 unsafe {
413 T::regs().isr().write(|w| w.set_adrdy(true));
414 T::regs().cr().modify(|w| w.set_aden(true));
415 while !T::regs().isr().read().adrdy() {}
416 T::regs().isr().write(|w| w.set_adrdy(true));
417 }
418 }
419
420 fn configure(&mut self) {
421 // single conversion mode, software trigger
422 unsafe {
423 T::regs().cfgr().modify(|w| {
424 w.set_cont(false);
425 w.set_exten(Exten::DISABLED);
426 })
427 }
428 }
429
430 pub fn enable_vref(&self) -> Vref {
431 unsafe {
432 T::common_regs().ccr().modify(|reg| {
433 reg.set_vrefen(true);
434 });
435 }
436
437 Vref {}
438 }
439
440 pub fn enable_temperature(&self) -> Temperature {
441 unsafe {
442 T::common_regs().ccr().modify(|reg| {
443 reg.set_vsenseen(true);
444 });
445 }
446
447 Temperature {}
448 }
449
450 pub fn enable_vbat(&self) -> Vbat {
451 unsafe {
452 T::common_regs().ccr().modify(|reg| {
453 reg.set_vbaten(true);
454 });
455 }
456
457 Vbat {}
458 }
459
460 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
461 self.sample_time = sample_time;
462 }
463
464 pub fn set_resolution(&mut self, resolution: Resolution) {
465 self.resolution = resolution;
466 }
467
468 /// Convert a measurement to millivolts
469 pub fn to_millivolts(&self, sample: u16) -> u16 {
470 ((u32::from(sample) * 3300) / self.resolution.to_max_count()) as u16
471 }
472
473 /// Perform a single conversion.
474 fn convert(&mut self) -> u16 {
475 unsafe {
476 T::regs().isr().modify(|reg| {
477 reg.set_eos(true);
478 reg.set_eoc(true);
479 });
480
481 // Start conversion
482 T::regs().cr().modify(|reg| {
483 reg.set_adstart(true);
484 });
485
486 while !T::regs().isr().read().eos() {
487 // spin
488 }
489
490 T::regs().dr().read().0 as u16
491 }
492 }
493
494 pub fn read<P>(&mut self, pin: &mut P) -> u16
495 where
496 P: AdcPin<T>,
497 P: crate::gpio::sealed::Pin,
498 {
499 unsafe {
500 pin.set_as_analog();
501
502 self.read_channel(pin.channel())
503 }
504 }
505
506 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
507 unsafe { self.read_channel(channel.channel()) }
508 }
509
510 unsafe fn read_channel(&mut self, channel: u8) -> u16 {
511 // Configure ADC
512 T::regs()
513 .cfgr()
514 .modify(|reg| reg.set_res(self.resolution.res()));
515
516 // Configure channel
517 Self::set_channel_sample_time(channel, self.sample_time);
518
519 T::regs().cfgr2().modify(|w| w.set_lshift(0));
520 T::regs()
521 .pcsel()
522 .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
523 T::regs().sqr1().write(|reg| {
524 reg.set_sq(0, channel);
525 reg.set_l(0);
526 });
527
528 self.convert()
529 }
530
531 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
532 if ch <= 9 {
533 T::regs()
534 .smpr(0)
535 .modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
536 } else {
537 T::regs()
538 .smpr(1)
539 .modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
540 }
541 }
542}
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
index d2668525d..6c81d3dbd 100644
--- a/embassy-stm32/src/rcc/h7.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -7,7 +7,7 @@ use stm32_metapac::rcc::vals::{Mco1, Mco2};
7use crate::gpio::sealed::AFType; 7use crate::gpio::sealed::AFType;
8use crate::gpio::Speed; 8use crate::gpio::Speed;
9use crate::pac::rcc::vals::Timpre; 9use crate::pac::rcc::vals::Timpre;
10use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsidiv, Pllsrc, Sw}; 10use crate::pac::rcc::vals::{Adcsel, Ckpersel, Dppre, Hpre, Hsidiv, Pllsrc, Sw};
11use crate::pac::{PWR, RCC, SYSCFG}; 11use crate::pac::{PWR, RCC, SYSCFG};
12use crate::peripherals; 12use crate::peripherals;
13use crate::rcc::{set_freqs, Clocks}; 13use crate::rcc::{set_freqs, Clocks};
@@ -36,6 +36,29 @@ pub enum VoltageScale {
36 Scale3, 36 Scale3,
37} 37}
38 38
39#[derive(Clone, Copy)]
40pub enum AdcClockSource {
41 Pll2PCk,
42 Pll3RCk,
43 PerCk,
44}
45
46impl AdcClockSource {
47 pub fn adcsel(&self) -> Adcsel {
48 match self {
49 AdcClockSource::Pll2PCk => Adcsel::PLL2_P,
50 AdcClockSource::Pll3RCk => Adcsel::PLL3_R,
51 AdcClockSource::PerCk => Adcsel::PER,
52 }
53 }
54}
55
56impl Default for AdcClockSource {
57 fn default() -> Self {
58 Self::Pll2PCk
59 }
60}
61
39/// Core clock frequencies 62/// Core clock frequencies
40#[derive(Clone, Copy)] 63#[derive(Clone, Copy)]
41pub struct CoreClocks { 64pub struct CoreClocks {
@@ -65,6 +88,7 @@ pub struct CoreClocks {
65 pub pll3_r_ck: Option<Hertz>, 88 pub pll3_r_ck: Option<Hertz>,
66 pub timx_ker_ck: Option<Hertz>, 89 pub timx_ker_ck: Option<Hertz>,
67 pub timy_ker_ck: Option<Hertz>, 90 pub timy_ker_ck: Option<Hertz>,
91 pub adc_ker_ck: Option<Hertz>,
68 pub sys_ck: Hertz, 92 pub sys_ck: Hertz,
69 pub c_ck: Hertz, 93 pub c_ck: Hertz,
70} 94}
@@ -85,6 +109,7 @@ pub struct Config {
85 pub pll1: PllConfig, 109 pub pll1: PllConfig,
86 pub pll2: PllConfig, 110 pub pll2: PllConfig,
87 pub pll3: PllConfig, 111 pub pll3: PllConfig,
112 pub adc_clock_source: AdcClockSource,
88} 113}
89 114
90/// Setup traceclk 115/// Setup traceclk
@@ -614,6 +639,16 @@ pub(crate) unsafe fn init(mut config: Config) {
614 // Peripheral Clock (per_ck) 639 // Peripheral Clock (per_ck)
615 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); 640 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
616 641
642 // ADC clock MUX
643 RCC.d3ccipr()
644 .modify(|w| w.set_adcsel(config.adc_clock_source.adcsel()));
645
646 let adc_ker_ck = match config.adc_clock_source {
647 AdcClockSource::Pll2PCk => pll2_p_ck.map(Hertz),
648 AdcClockSource::Pll3RCk => pll3_r_ck.map(Hertz),
649 AdcClockSource::PerCk => Some(per_ck),
650 };
651
617 // Set timer clocks prescaler setting 652 // Set timer clocks prescaler setting
618 RCC.cfgr().modify(|w| w.set_timpre(timpre)); 653 RCC.cfgr().modify(|w| w.set_timpre(timpre));
619 654
@@ -668,6 +703,7 @@ pub(crate) unsafe fn init(mut config: Config) {
668 pll3_r_ck: pll3_r_ck.map(Hertz), 703 pll3_r_ck: pll3_r_ck.map(Hertz),
669 timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), 704 timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
670 timy_ker_ck: rcc_timery_ker_ck.map(Hertz), 705 timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
706 adc_ker_ck,
671 sys_ck, 707 sys_ck,
672 c_ck: Hertz(sys_d1cpre_ck), 708 c_ck: Hertz(sys_d1cpre_ck),
673 }; 709 };
@@ -683,6 +719,7 @@ pub(crate) unsafe fn init(mut config: Config) {
683 apb4: core_clocks.pclk4, 719 apb4: core_clocks.pclk4,
684 apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1), 720 apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1),
685 apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2), 721 apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
722 adc: core_clocks.adc_ker_ck,
686 }); 723 });
687} 724}
688 725
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index d0ae2fc79..9a95836a6 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -58,6 +58,9 @@ pub struct Clocks {
58 58
59 #[cfg(rcc_f1)] 59 #[cfg(rcc_f1)]
60 pub adc: Hertz, 60 pub adc: Hertz,
61
62 #[cfg(any(rcc_h7, rcc_h7ab))]
63 pub adc: Option<Hertz>,
61} 64}
62 65
63/// Frozen clock frequencies 66/// Frozen clock frequencies
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 6146b6dc6..64baad994 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -8,7 +8,7 @@ resolver = "2"
8[features] 8[features]
9 9
10[dependencies] 10[dependencies]
11embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits"] }
12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
13embassy-net = { path = "../../embassy-net", default-features = false, features = ["defmt", "tcp", "medium-ethernet", "pool-16"] } 13embassy-net = { path = "../../embassy-net", default-features = false, features = ["defmt", "tcp", "medium-ethernet", "pool-16"] }
14 14
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
new file mode 100644
index 000000000..b12bca307
--- /dev/null
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -0,0 +1,42 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy::executor::Spawner;
6use embassy::time::{Delay, Duration, Timer};
7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_stm32::rcc::AdcClockSource;
9use embassy_stm32::time::U32Ext;
10use embassy_stm32::{Config, Peripherals};
11
12use defmt::*;
13use defmt_rtt as _; // global logger
14use panic_probe as _;
15
16pub fn config() -> Config {
17 let mut config = Config::default();
18 config.rcc.sys_ck = Some(400.mhz().into());
19 config.rcc.hclk = Some(200.mhz().into());
20 config.rcc.per_ck = Some(64.mhz().into());
21 config.rcc.adc_clock_source = AdcClockSource::PerCk;
22 config
23}
24
25#[embassy::main(config = "config()")]
26async fn main(_spawner: Spawner, mut p: Peripherals) {
27 info!("Hello World!");
28
29 let mut adc = Adc::new(p.ADC3, &mut Delay);
30
31 adc.set_sample_time(SampleTime::Cycles32_5);
32
33 let mut vref_channel = adc.enable_vref();
34
35 loop {
36 let vref = adc.read_internal(&mut vref_channel);
37 info!("vref: {}", vref);
38 let measured = adc.read(&mut p.PC0);
39 info!("measured: {}", measured);
40 Timer::after(Duration::from_millis(500)).await;
41 }
42}
diff --git a/stm32-data b/stm32-data
Subproject 5295cf1aa474aa4b70ba2bc19ab0ced0173cd79 Subproject 8fb98d74620ab71fb9d0be2d800c427e0b77c46