aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-09-05 16:50:33 -0500
committerxoviat <[email protected]>2023-09-05 16:50:33 -0500
commit7e18e5e0c123027f15dd7a75706b9950da9aed0c (patch)
treea4c42d0b7197056d9e9e1797f120784fbdf3be75
parente2f8bf19ea55341f274c6cb9c3650a96f4a09fe4 (diff)
parent49ba9c3da2b6929c5ec1fb17d8c43c271a70eb34 (diff)
Merge branch 'stm32g4_adc' of https://github.com/daehyeok/embassy into adc-g4
-rw-r--r--embassy-stm32/Cargo.toml5
-rw-r--r--embassy-stm32/src/adc/v4.rs193
-rw-r--r--embassy-stm32/src/rcc/g4.rs54
-rw-r--r--embassy-stm32/src/rcc/mod.rs6
-rw-r--r--examples/stm32g4/Cargo.toml2
-rw-r--r--examples/stm32g4/src/bin/adc.rs41
6 files changed, 192 insertions, 109 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index d169107df..712996f23 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -58,7 +58,7 @@ sdio-host = "0.5.0"
58embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 58embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
59critical-section = "1.1" 59critical-section = "1.1"
60atomic-polyfill = "1.0.1" 60atomic-polyfill = "1.0.1"
61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9a61a1f090462df8bd1751f89951f04934fdceb3" } 61stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0" }
62vcell = "0.1.3" 62vcell = "0.1.3"
63bxcan = "0.7.0" 63bxcan = "0.7.0"
64nb = "1.0.0" 64nb = "1.0.0"
@@ -70,6 +70,7 @@ embedded-io-async = { version = "0.5.0", optional = true }
70chrono = { version = "^0.4", default-features = false, optional = true} 70chrono = { version = "^0.4", default-features = false, optional = true}
71bit_field = "0.10.2" 71bit_field = "0.10.2"
72document-features = "0.2.7" 72document-features = "0.2.7"
73paste = "1.0"
73 74
74[dev-dependencies] 75[dev-dependencies]
75critical-section = { version = "1.1", features = ["std"] } 76critical-section = { version = "1.1", features = ["std"] }
@@ -77,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
77[build-dependencies] 78[build-dependencies]
78proc-macro2 = "1.0.36" 79proc-macro2 = "1.0.36"
79quote = "1.0.15" 80quote = "1.0.15"
80stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9a61a1f090462df8bd1751f89951f04934fdceb3", default-features = false, features = ["metadata"]} 81stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7e2310f49fa123fbc3225b91be73522b212703f0", default-features = false, features = ["metadata"]}
81 82
82[features] 83[features]
83default = ["rt"] 84default = ["rt"]
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 64d0f0c75..d03f2550d 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -1,8 +1,10 @@
1use core::sync::atomic::{AtomicU8, Ordering}; 1use core::sync::atomic::{AtomicU8, Ordering};
2 2
3use embedded_hal_02::blocking::delay::DelayUs; 3use embedded_hal_02::blocking::delay::DelayUs;
4#[allow(unused)]
4use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; 5use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 6use pac::adccommon::vals::Presc;
7use paste::paste;
6 8
7use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; 9use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
8use crate::time::Hertz; 10use crate::time::Hertz;
@@ -13,12 +15,31 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
13/// VREF voltage used for factory calibration of VREFINTCAL register. 15/// VREF voltage used for factory calibration of VREFINTCAL register.
14pub const VREF_CALIB_MV: u32 = 3300; 16pub const VREF_CALIB_MV: u32 = 3300;
15 17
16// NOTE: Vrefint/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 18/// Max single ADC operation clock frequency
19#[cfg(stm32g4)]
20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
21#[cfg(stm32h7)]
22const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
23
24#[cfg(stm32g4)]
25const VREF_CHANNEL: u8 = 18;
26#[cfg(stm32g4)]
27const TEMP_CHANNEL: u8 = 16;
28
29#[cfg(stm32h7)]
30const VREF_CHANNEL: u8 = 19;
31#[cfg(stm32h7)]
32const TEMP_CHANNEL: u8 = 18;
33
34// TODO this should be 14 for H7a/b/35
35const VBAT_CHANNEL: u8 = 17;
36
37// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
17pub struct VrefInt; 38pub struct VrefInt;
18impl<T: Instance> InternalChannel<T> for VrefInt {} 39impl<T: Instance> InternalChannel<T> for VrefInt {}
19impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { 40impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
20 fn channel(&self) -> u8 { 41 fn channel(&self) -> u8 {
21 19 42 VREF_CHANNEL
22 } 43 }
23} 44}
24 45
@@ -26,7 +47,7 @@ pub struct Temperature;
26impl<T: Instance> InternalChannel<T> for Temperature {} 47impl<T: Instance> InternalChannel<T> for Temperature {}
27impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { 48impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
28 fn channel(&self) -> u8 { 49 fn channel(&self) -> u8 {
29 18 50 TEMP_CHANNEL
30 } 51 }
31} 52}
32 53
@@ -34,59 +55,20 @@ pub struct Vbat;
34impl<T: Instance> InternalChannel<T> for Vbat {} 55impl<T: Instance> InternalChannel<T> for Vbat {}
35impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { 56impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
36 fn channel(&self) -> u8 { 57 fn channel(&self) -> u8 {
37 // TODO this should be 14 for H7a/b/35 58 VBAT_CHANNEL
38 17
39 } 59 }
40} 60}
41 61
42static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); 62static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
63#[cfg(any(stm32g4x3, stm32g4x4))]
64static ADC345_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0);
43 65
44#[cfg(stm32h7)] 66macro_rules! rcc_peripheral {
45foreach_peripheral!( 67 ($adc_name:ident, $freqs:ident, $ahb:ident, $reg:ident $(, $counter:ident )? ) => {
46 (adc, ADC1) => { 68 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::$adc_name {
47 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
48 fn frequency() -> crate::time::Hertz {
49 critical_section::with(|_| {
50 match unsafe { crate::rcc::get_freqs() }.adc {
51 Some(ck) => ck,
52 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
53 }
54 })
55 }
56
57 fn enable() {
58 critical_section::with(|_| {
59 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
60 });
61 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
62 }
63
64 fn disable() {
65 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
66 critical_section::with(|_| {
67 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
68 })
69 }
70 ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst);
71 }
72
73 fn reset() {
74 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
75 critical_section::with(|_| {
76 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
77 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
78 });
79 }
80 }
81 }
82
83 impl crate::rcc::RccPeripheral for crate::peripherals::ADC1 {}
84 };
85 (adc, ADC2) => {
86 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
87 fn frequency() -> crate::time::Hertz { 69 fn frequency() -> crate::time::Hertz {
88 critical_section::with(|_| { 70 critical_section::with(|_| {
89 match unsafe { crate::rcc::get_freqs() }.adc { 71 match unsafe { crate::rcc::get_freqs() }.$freqs {
90 Some(ck) => ck, 72 Some(ck) => ck,
91 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") 73 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
92 } 74 }
@@ -95,65 +77,57 @@ foreach_peripheral!(
95 77
96 fn enable() { 78 fn enable() {
97 critical_section::with(|_| { 79 critical_section::with(|_| {
98 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) 80 paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](true))}
99 }); 81 });
100 ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); 82 $ ( $counter.fetch_add(1, Ordering::SeqCst); )?
101 } 83 }
102 84
103 fn disable() { 85 fn disable() {
104 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 86 $ ( if $counter.load(Ordering::SeqCst) == 1 )? {
105 critical_section::with(|_| { 87 critical_section::with(|_| {
106 crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); 88 paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](false))}
107 }) 89 })
108 } 90 }
109 ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst); 91 $ ( $counter.fetch_sub(1, Ordering::SeqCst); )?
110 } 92 }
111 93
112 fn reset() { 94 fn reset() {
113 if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { 95 $ ( if $counter.load(Ordering::SeqCst) == 1 )? {
114 critical_section::with(|_| { 96 critical_section::with(|_| {
115 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); 97 paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](true))}
116 crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); 98 paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](false))}
117 }); 99 });
118 } 100 }
119 } 101 }
120 } 102 }
121 103
122 impl crate::rcc::RccPeripheral for crate::peripherals::ADC2 {} 104 impl crate::rcc::RccPeripheral for crate::peripherals::$adc_name {}
123 }; 105 };
124 (adc, ADC3) => { 106}
125 impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
126 fn frequency() -> crate::time::Hertz {
127 critical_section::with(|_| {
128 match unsafe { crate::rcc::get_freqs() }.adc {
129 Some(ck) => ck,
130 None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
131 }
132 })
133 }
134 107
135 fn enable() { 108#[cfg(stm32g4)]
136 critical_section::with(|_| { 109foreach_peripheral!(
137 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) 110 (adc, ADC1) => { rcc_peripheral!(ADC1, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); };
138 }); 111 (adc, ADC2) => { rcc_peripheral!(ADC2, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); };
139 } 112);
140 113
141 fn disable() { 114#[cfg(stm32g4x1)]
142 critical_section::with(|_| { 115foreach_peripheral!(
143 crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); 116 (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345); };
144 }) 117);
145 }
146 118
147 fn reset() { 119#[cfg(any(stm32g4x3, stm32g4x4))]
148 critical_section::with(|_| { 120foreach_peripheral!(
149 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); 121 (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); };
150 crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); 122 (adc, ADC4) => { rcc_peripheral!(ADC4, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); };
151 }); 123 (adc, ADC5) => { rcc_peripheral!(ADC5, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); };
152 } 124);
153 }
154 125
155 impl crate::rcc::RccPeripheral for crate::peripherals::ADC3 {} 126#[cfg(stm32h7)]
156 }; 127foreach_peripheral!(
128 (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); };
129 (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); };
130 (adc, ADC3) => { rcc_peripheral!(ADC3, adc, ahb4, adc3); };
157); 131);
158 132
159// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 133// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
@@ -176,7 +150,7 @@ enum Prescaler {
176 150
177impl Prescaler { 151impl Prescaler {
178 fn from_ker_ck(frequency: Hertz) -> Self { 152 fn from_ker_ck(frequency: Hertz) -> Self {
179 let raw_prescaler = frequency.0 / 50_000_000; 153 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
180 match raw_prescaler { 154 match raw_prescaler {
181 0 => Self::NotDivided, 155 0 => Self::NotDivided,
182 1 => Self::DividedBy2, 156 1 => Self::DividedBy2,
@@ -237,20 +211,23 @@ impl<'d, T: Instance> Adc<'d, T> {
237 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 211 let frequency = Hertz(T::frequency().0 / prescaler.divisor());
238 info!("ADC frequency set to {} Hz", frequency.0); 212 info!("ADC frequency set to {} Hz", frequency.0);
239 213
240 if frequency > Hertz::mhz(50) { 214 if frequency > MAX_ADC_CLK_FREQ {
241 panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information."); 215 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
242 } 216 }
243 let boost = if frequency < Hertz::khz(6_250) {
244 Boost::LT6_25
245 } else if frequency < Hertz::khz(12_500) {
246 Boost::LT12_5
247 } else if frequency < Hertz::mhz(25) {
248 Boost::LT25
249 } else {
250 Boost::LT50
251 };
252 T::regs().cr().modify(|w| w.set_boost(boost));
253 217
218 #[cfg(stm32h7)]
219 {
220 let boost = if frequency < Hertz::khz(6_250) {
221 Boost::LT6_25
222 } else if frequency < Hertz::khz(12_500) {
223 Boost::LT12_5
224 } else if frequency < Hertz::mhz(25) {
225 Boost::LT25
226 } else {
227 Boost::LT50
228 };
229 T::regs().cr().modify(|w| w.set_boost(boost));
230 }
254 let mut s = Self { 231 let mut s = Self {
255 adc, 232 adc,
256 sample_time: Default::default(), 233 sample_time: Default::default(),
@@ -379,10 +356,14 @@ impl<'d, T: Instance> Adc<'d, T> {
379 // Configure channel 356 // Configure channel
380 Self::set_channel_sample_time(channel, self.sample_time); 357 Self::set_channel_sample_time(channel, self.sample_time);
381 358
382 T::regs().cfgr2().modify(|w| w.set_lshift(0)); 359 #[cfg(stm32h7)]
383 T::regs() 360 {
384 .pcsel() 361 T::regs().cfgr2().modify(|w| w.set_lshift(0));
385 .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); 362 T::regs()
363 .pcsel()
364 .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
365 }
366
386 T::regs().sqr1().write(|reg| { 367 T::regs().sqr1().write(|reg| {
387 reg.set_sq(0, channel); 368 reg.set_sq(0, channel);
388 reg.set_l(0); 369 reg.set_l(0);
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 3b044cd11..4c95bb154 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,5 +1,5 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; 2use stm32_metapac::rcc::vals::{Adcsel, Hpre, Pllsrc, Ppre, Sw};
3use stm32_metapac::FLASH; 3use stm32_metapac::FLASH;
4 4
5pub use super::bus::{AHBPrescaler, APBPrescaler}; 5pub use super::bus::{AHBPrescaler, APBPrescaler};
@@ -14,6 +14,29 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
14/// LSI speed 14/// LSI speed
15pub const LSI_FREQ: Hertz = Hertz(32_000); 15pub const LSI_FREQ: Hertz = Hertz(32_000);
16 16
17#[derive(Clone, Copy)]
18pub enum AdcClockSource {
19 NoClk,
20 SysClk,
21 PllP,
22}
23
24impl AdcClockSource {
25 pub fn adcsel(&self) -> Adcsel {
26 match self {
27 AdcClockSource::NoClk => Adcsel::NOCLK,
28 AdcClockSource::SysClk => Adcsel::SYSCLK,
29 AdcClockSource::PllP => Adcsel::PLLP,
30 }
31 }
32}
33
34impl Default for AdcClockSource {
35 fn default() -> Self {
36 Self::NoClk
37 }
38}
39
17/// System clock mux source 40/// System clock mux source
18#[derive(Clone, Copy)] 41#[derive(Clone, Copy)]
19pub enum ClockSrc { 42pub enum ClockSrc {
@@ -327,6 +350,8 @@ pub struct Config {
327 pub pll: Option<Pll>, 350 pub pll: Option<Pll>,
328 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. 351 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
329 pub clock_48mhz_src: Option<Clock48MhzSrc>, 352 pub clock_48mhz_src: Option<Clock48MhzSrc>,
353 pub adc12_clock_source: AdcClockSource,
354 pub adc345_clock_source: AdcClockSource,
330} 355}
331 356
332/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. 357/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
@@ -346,6 +371,8 @@ impl Default for Config {
346 low_power_run: false, 371 low_power_run: false,
347 pll: None, 372 pll: None,
348 clock_48mhz_src: None, 373 clock_48mhz_src: None,
374 adc12_clock_source: Default::default(),
375 adc345_clock_source: Default::default(),
349 } 376 }
350 } 377 }
351} 378}
@@ -549,6 +576,29 @@ pub(crate) unsafe fn init(config: Config) {
549 RCC.ccipr().modify(|w| w.set_clk48sel(source)); 576 RCC.ccipr().modify(|w| w.set_clk48sel(source));
550 } 577 }
551 578
579 RCC.ccipr()
580 .modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel()));
581 RCC.ccipr()
582 .modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel()));
583
584 let adc12_ck = match config.adc12_clock_source {
585 AdcClockSource::NoClk => None,
586 AdcClockSource::PllP => match &pll_freq {
587 Some(pll) => pll.pll_p,
588 None => None,
589 },
590 AdcClockSource::SysClk => Some(Hertz(sys_clk)),
591 };
592
593 let adc345_ck = match config.adc345_clock_source {
594 AdcClockSource::NoClk => None,
595 AdcClockSource::PllP => match &pll_freq {
596 Some(pll) => pll.pll_p,
597 None => None,
598 },
599 AdcClockSource::SysClk => Some(Hertz(sys_clk)),
600 };
601
552 if config.low_power_run { 602 if config.low_power_run {
553 assert!(sys_clk <= 2_000_000); 603 assert!(sys_clk <= 2_000_000);
554 PWR.cr1().modify(|w| w.set_lpr(true)); 604 PWR.cr1().modify(|w| w.set_lpr(true));
@@ -562,5 +612,7 @@ pub(crate) unsafe fn init(config: Config) {
562 apb1_tim: Hertz(apb1_tim_freq), 612 apb1_tim: Hertz(apb1_tim_freq),
563 apb2: Hertz(apb2_freq), 613 apb2: Hertz(apb2_freq),
564 apb2_tim: Hertz(apb2_tim_freq), 614 apb2_tim: Hertz(apb2_tim_freq),
615 adc12: adc12_ck,
616 adc345: adc345_ck,
565 }); 617 });
566} 618}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 0430e4a74..ecabe23ae 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -77,6 +77,12 @@ pub struct Clocks {
77 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] 77 #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
78 pub adc: Option<Hertz>, 78 pub adc: Option<Hertz>,
79 79
80 #[cfg(any(rcc_g4))]
81 pub adc12: Option<Hertz>,
82
83 #[cfg(any(rcc_g4))]
84 pub adc345: Option<Hertz>,
85
80 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 86 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
81 /// Set only if the lsi or lse is configured, indicates stop is supported 87 /// Set only if the lsi or lse is configured, indicates stop is supported
82 pub rtc: Option<Hertz>, 88 pub rtc: Option<Hertz>,
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 0c1cdd67c..2e81d2060 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -11,6 +11,8 @@ embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["de
11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15usbd-hid = "0.6.0"
14 16
15defmt = "0.3" 17defmt = "0.3"
16defmt-rtt = "0.4" 18defmt-rtt = "0.4"
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
new file mode 100644
index 000000000..a792748bc
--- /dev/null
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_stm32::rcc::{AdcClockSource, ClockSrc, Pll, PllM, PllN, PllR, PllSrc};
9use embassy_stm32::Config;
10use embassy_time::{Delay, Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let mut config = Config::default();
16
17 config.rcc.pll = Some(Pll {
18 source: PllSrc::HSI16,
19 prediv_m: PllM::Div4,
20 mul_n: PllN::Mul85,
21 div_p: None,
22 div_q: None,
23 // Main system clock at 170 MHz
24 div_r: Some(PllR::Div2),
25 });
26
27 config.rcc.adc12_clock_source = AdcClockSource::SysClk;
28 config.rcc.mux = ClockSrc::PLL;
29
30 let mut p = embassy_stm32::init(config);
31 info!("Hello World!");
32
33 let mut adc = Adc::new(p.ADC2, &mut Delay);
34 adc.set_sample_time(SampleTime::Cycles32_5);
35
36 loop {
37 let measured = adc.read(&mut p.PA7);
38 info!("measured: {}", measured);
39 Timer::after(Duration::from_millis(500)).await;
40 }
41}