aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-11 17:19:26 +0000
committerGitHub <[email protected]>2025-11-11 17:19:26 +0000
commit0d1fc76a10863b85961a63db4a9e1e2807f35957 (patch)
tree1ffe8a8dddec7085876adb8bfcd86c3fed22ae74
parentf078c85454f09f28a85aa834a9496b37058695e0 (diff)
parent769941980442ada1524ee4f60f1d003735caff4b (diff)
Merge pull request #4866 from xoviat/adc
adc: impl. differential channels
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs37
-rw-r--r--embassy-stm32/src/adc/c0.rs4
-rw-r--r--embassy-stm32/src/adc/f1.rs6
-rw-r--r--embassy-stm32/src/adc/f3.rs6
-rw-r--r--embassy-stm32/src/adc/g4.rs193
-rw-r--r--embassy-stm32/src/adc/mod.rs87
-rw-r--r--embassy-stm32/src/adc/v1.rs8
-rw-r--r--embassy-stm32/src/adc/v2.rs8
-rw-r--r--embassy-stm32/src/adc/v3.rs24
-rw-r--r--embassy-stm32/src/adc/v4.rs16
-rw-r--r--examples/stm32g4/src/bin/adc.rs5
-rw-r--r--examples/stm32g4/src/bin/adc_differential.rs6
13 files changed, 210 insertions, 194 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 0a1854dab..a722d2379 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -198,11 +198,11 @@ aligned = "0.4.1"
198heapless = "0.9.1" 198heapless = "0.9.1"
199 199
200#stm32-metapac = { version = "18" } 200#stm32-metapac = { version = "18" }
201stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e" } 201stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2" }
202 202
203[build-dependencies] 203[build-dependencies]
204#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} 204#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]}
205stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e", default-features = false, features = ["metadata"] } 205stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2", default-features = false, features = ["metadata"] }
206 206
207proc-macro2 = "1.0.36" 207proc-macro2 = "1.0.36"
208quote = "1.0.15" 208quote = "1.0.15"
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 09a05ce68..48da475df 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1353,6 +1353,8 @@ fn main() {
1353 1353
1354 for p in METADATA.peripherals { 1354 for p in METADATA.peripherals {
1355 if let Some(regs) = &p.registers { 1355 if let Some(regs) = &p.registers {
1356 let mut adc_pairs: BTreeMap<u8, (Option<Ident>, Option<Ident>)> = BTreeMap::new();
1357
1356 for pin in p.pins { 1358 for pin in p.pins {
1357 let key = (regs.kind, pin.signal); 1359 let key = (regs.kind, pin.signal);
1358 if let Some(tr) = signals.get(&key) { 1360 if let Some(tr) = signals.get(&key) {
@@ -1474,25 +1476,29 @@ fn main() {
1474 }; 1476 };
1475 1477
1476 // H7 has differential voltage measurements 1478 // H7 has differential voltage measurements
1477 let ch: Option<u8> = if pin.signal.starts_with("INP") { 1479 let ch: Option<(u8, bool)> = if pin.signal.starts_with("INP") {
1478 Some(pin.signal.strip_prefix("INP").unwrap().parse().unwrap()) 1480 Some((pin.signal.strip_prefix("INP").unwrap().parse().unwrap(), false))
1479 } else if pin.signal.starts_with("INN") { 1481 } else if pin.signal.starts_with("INN") {
1480 // TODO handle in the future when embassy supports differential measurements 1482 Some((pin.signal.strip_prefix("INN").unwrap().parse().unwrap(), true))
1481 None
1482 } else if pin.signal.starts_with("IN") && pin.signal.ends_with('b') { 1483 } else if pin.signal.starts_with("IN") && pin.signal.ends_with('b') {
1483 // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63 1484 // we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63
1484 let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix('b').unwrap(); 1485 let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix('b').unwrap();
1485 Some(32u8 + signal.parse::<u8>().unwrap()) 1486 Some((32u8 + signal.parse::<u8>().unwrap(), false))
1486 } else if pin.signal.starts_with("IN") { 1487 } else if pin.signal.starts_with("IN") {
1487 Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap()) 1488 Some((pin.signal.strip_prefix("IN").unwrap().parse().unwrap(), false))
1488 } else { 1489 } else {
1489 None 1490 None
1490 }; 1491 };
1491 if let Some(ch) = ch { 1492 if let Some((ch, false)) = ch {
1493 adc_pairs.entry(ch).or_insert((None, None)).0.replace(pin_name.clone());
1494
1492 g.extend(quote! { 1495 g.extend(quote! {
1493 impl_adc_pin!( #peri, #pin_name, #ch); 1496 impl_adc_pin!( #peri, #pin_name, #ch);
1494 }) 1497 })
1495 } 1498 }
1499 if let Some((ch, true)) = ch {
1500 adc_pairs.entry(ch).or_insert((None, None)).1.replace(pin_name.clone());
1501 }
1496 } 1502 }
1497 1503
1498 if regs.kind == "opamp" { 1504 if regs.kind == "opamp" {
@@ -1531,6 +1537,23 @@ fn main() {
1531 }) 1537 })
1532 } 1538 }
1533 } 1539 }
1540
1541 {
1542 let peri = format_ident!("{}", p.name);
1543
1544 for (ch, (pin, npin)) in adc_pairs {
1545 let (pin_name, npin_name) = match (pin, npin) {
1546 (Some(pin), Some(npin)) => (pin, npin),
1547 _ => {
1548 continue;
1549 }
1550 };
1551
1552 g.extend(quote! {
1553 impl_adc_pair!( #peri, #pin_name, #npin_name, #ch);
1554 })
1555 }
1556 }
1534 } 1557 }
1535 } 1558 }
1536 1559
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index 1869993a5..bc97a7c4b 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -24,11 +24,11 @@ const CHSELR_SQ_SIZE: usize = 8;
24const CHSELR_SQ_MAX_CHANNEL: u8 = 14; 24const CHSELR_SQ_MAX_CHANNEL: u8 = 14;
25const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; 25const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111;
26 26
27impl<T: Instance> super::VrefConverter for T { 27impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
28 const CHANNEL: u8 = 10; 28 const CHANNEL: u8 = 10;
29} 29}
30 30
31impl<T: Instance> super::TemperatureConverter for T { 31impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
32 const CHANNEL: u8 = 9; 32 const CHANNEL: u8 = 9;
33} 33}
34 34
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 835cc8c63..f6220de78 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -3,7 +3,7 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use super::blocking_delay_us; 5use super::blocking_delay_us;
6use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt};
7use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
8use crate::interrupt::{self}; 8use crate::interrupt::{self};
9use crate::time::Hertz; 9use crate::time::Hertz;
@@ -28,11 +28,11 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
28 } 28 }
29} 29}
30 30
31impl<T: Instance> super::VrefConverter for T { 31impl<T: Instance> super::SealedSpecialConverter<VrefInt> for T {
32 const CHANNEL: u8 = 17; 32 const CHANNEL: u8 = 17;
33} 33}
34 34
35impl<T: Instance> super::TemperatureConverter for T { 35impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
36 const CHANNEL: u8 = 16; 36 const CHANNEL: u8 = 16;
37} 37}
38 38
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index f6a4e1209..4a77f3c5b 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -3,7 +3,7 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use super::blocking_delay_us; 5use super::blocking_delay_us;
6use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt};
7use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
8use crate::time::Hertz; 8use crate::time::Hertz;
9use crate::{Peri, interrupt, rcc}; 9use crate::{Peri, interrupt, rcc};
@@ -29,11 +29,11 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
29 } 29 }
30} 30}
31 31
32impl<T: Instance> super::VrefConverter for T { 32impl<T: Instance> super::SealedSpecialConverter<VrefInt> for T {
33 const CHANNEL: u8 = 18; 33 const CHANNEL: u8 = 18;
34} 34}
35 35
36impl<T: Instance> super::TemperatureConverter for T { 36impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
37 const CHANNEL: u8 = 16; 37 const CHANNEL: u8 = 16;
38} 38}
39 39
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 5d9c6ff74..6430b0243 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -140,37 +140,19 @@ impl<'d, T: Instance> Adc<'d, T> {
140 ); 140 );
141 } 141 }
142 142
143 let mut s = Self { adc };
144 s.power_up();
145 s.configure_differential_inputs();
146
147 s.calibrate();
148 blocking_delay_us(1);
149
150 Self::enable();
151 s.configure();
152
153 s
154 }
155
156 fn power_up(&mut self) {
157 T::regs().cr().modify(|reg| { 143 T::regs().cr().modify(|reg| {
158 reg.set_deeppwd(false); 144 reg.set_deeppwd(false);
159 reg.set_advregen(true); 145 reg.set_advregen(true);
160 }); 146 });
161 147
162 blocking_delay_us(20); 148 blocking_delay_us(20);
163 }
164 149
165 fn configure_differential_inputs(&mut self) {
166 T::regs().difsel().modify(|w| { 150 T::regs().difsel().modify(|w| {
167 for n in 0..18 { 151 for n in 0..18 {
168 w.set_difsel(n, Difsel::SINGLE_ENDED); 152 w.set_difsel(n, Difsel::SINGLE_ENDED);
169 } 153 }
170 }); 154 });
171 }
172 155
173 fn calibrate(&mut self) {
174 T::regs().cr().modify(|w| { 156 T::regs().cr().modify(|w| {
175 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 157 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
176 }); 158 });
@@ -190,6 +172,16 @@ impl<'d, T: Instance> Adc<'d, T> {
190 while T::regs().cr().read().adcal() {} 172 while T::regs().cr().read().adcal() {}
191 173
192 blocking_delay_us(20); 174 blocking_delay_us(20);
175
176 Self::enable();
177
178 // single conversion mode, software trigger
179 T::regs().cfgr().modify(|w| {
180 w.set_cont(false);
181 w.set_exten(Exten::DISABLED);
182 });
183
184 Self { adc }
193 } 185 }
194 186
195 fn enable() { 187 fn enable() {
@@ -213,18 +205,10 @@ impl<'d, T: Instance> Adc<'d, T> {
213 } 205 }
214 } 206 }
215 207
216 fn configure(&mut self) {
217 // single conversion mode, software trigger
218 T::regs().cfgr().modify(|w| {
219 w.set_cont(false);
220 w.set_exten(Exten::DISABLED);
221 });
222 }
223
224 /// Enable reading the voltage reference internal channel. 208 /// Enable reading the voltage reference internal channel.
225 pub fn enable_vrefint(&self) -> super::VrefInt 209 pub fn enable_vrefint(&self) -> super::VrefInt
226 where 210 where
227 T: super::VrefConverter, 211 T: super::SpecialConverter<super::VrefInt>,
228 { 212 {
229 T::common_regs().ccr().modify(|reg| { 213 T::common_regs().ccr().modify(|reg| {
230 reg.set_vrefen(true); 214 reg.set_vrefen(true);
@@ -236,7 +220,7 @@ impl<'d, T: Instance> Adc<'d, T> {
236 /// Enable reading the temperature internal channel. 220 /// Enable reading the temperature internal channel.
237 pub fn enable_temperature(&self) -> super::Temperature 221 pub fn enable_temperature(&self) -> super::Temperature
238 where 222 where
239 T: super::TemperatureConverter, 223 T: super::SpecialConverter<super::Temperature>,
240 { 224 {
241 T::common_regs().ccr().modify(|reg| { 225 T::common_regs().ccr().modify(|reg| {
242 reg.set_vsenseen(true); 226 reg.set_vsenseen(true);
@@ -248,7 +232,7 @@ impl<'d, T: Instance> Adc<'d, T> {
248 /// Enable reading the vbat internal channel. 232 /// Enable reading the vbat internal channel.
249 pub fn enable_vbat(&self) -> super::Vbat 233 pub fn enable_vbat(&self) -> super::Vbat
250 where 234 where
251 T: super::VBatConverter, 235 T: super::SpecialConverter<super::Vbat>,
252 { 236 {
253 T::common_regs().ccr().modify(|reg| { 237 T::common_regs().ccr().modify(|reg| {
254 reg.set_vbaten(true); 238 reg.set_vbaten(true);
@@ -257,35 +241,6 @@ impl<'d, T: Instance> Adc<'d, T> {
257 super::Vbat {} 241 super::Vbat {}
258 } 242 }
259 243
260 /// Enable differential channel.
261 /// Caution:
262 /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i]
263 /// is connected to another channel. As a consequence, this channel is no longer usable in
264 /// single-ended mode or in differential mode and must never be configured to be converted.
265 /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the
266 /// channel on the other ADC unusable. The only exception is when ADC master and the slave
267 /// operate in interleaved mode.
268 #[cfg(stm32g4)]
269 fn set_differential_channel(&mut self, ch: usize, enable: bool) {
270 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
271 T::regs().difsel().modify(|w| {
272 w.set_difsel(
273 ch,
274 if enable {
275 Difsel::DIFFERENTIAL
276 } else {
277 Difsel::SINGLE_ENDED
278 },
279 );
280 });
281 T::regs().cr().modify(|w| w.set_aden(true));
282 }
283
284 #[cfg(stm32g4)]
285 pub fn set_differential(&mut self, channel: &mut impl AdcChannel<T>, enable: bool) {
286 self.set_differential_channel(channel.channel() as usize, enable);
287 }
288
289 /// Set oversampling shift. 244 /// Set oversampling shift.
290 #[cfg(stm32g4)] 245 #[cfg(stm32g4)]
291 pub fn set_oversampling_shift(&mut self, shift: u8) { 246 pub fn set_oversampling_shift(&mut self, shift: u8) {
@@ -347,7 +302,17 @@ impl<'d, T: Instance> Adc<'d, T> {
347 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 302 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
348 channel.setup(); 303 channel.setup();
349 304
350 self.read_channel(channel, sample_time) 305 Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
306
307 #[cfg(stm32h7)]
308 {
309 T::regs().cfgr2().modify(|w| w.set_lshift(0));
310 T::regs()
311 .pcsel()
312 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
313 }
314
315 self.convert()
351 } 316 }
352 317
353 /// Start regular adc conversion 318 /// Start regular adc conversion
@@ -420,11 +385,9 @@ impl<'d, T: Instance> Adc<'d, T> {
420 Self::stop_regular_conversions(); 385 Self::stop_regular_conversions();
421 Self::enable(); 386 Self::enable();
422 387
423 Self::configure_sequence(sequence.map(|(channel, sample_time)| { 388 Self::configure_sequence(
424 channel.setup(); 389 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
425 390 );
426 (channel.channel, sample_time)
427 }));
428 391
429 // Set continuous mode with oneshot dma. 392 // Set continuous mode with oneshot dma.
430 // Clear overrun flag before starting transfer. 393 // Clear overrun flag before starting transfer.
@@ -467,14 +430,14 @@ impl<'d, T: Instance> Adc<'d, T> {
467 }); 430 });
468 } 431 }
469 432
470 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) { 433 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
471 // Set sequence length 434 // Set sequence length
472 T::regs().sqr1().modify(|w| { 435 T::regs().sqr1().modify(|w| {
473 w.set_l(sequence.len() as u8 - 1); 436 w.set_l(sequence.len() as u8 - 1);
474 }); 437 });
475 438
476 // Configure channels and ranks 439 // Configure channels and ranks
477 for (_i, (ch, sample_time)) in sequence.enumerate() { 440 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() {
478 let sample_time = sample_time.into(); 441 let sample_time = sample_time.into();
479 if ch <= 9 { 442 if ch <= 9 {
480 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); 443 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time));
@@ -505,6 +468,24 @@ impl<'d, T: Instance> Adc<'d, T> {
505 } 468 }
506 _ => unreachable!(), 469 _ => unreachable!(),
507 } 470 }
471
472 #[cfg(stm32g4)]
473 {
474 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
475
476 T::regs().difsel().modify(|w| {
477 w.set_difsel(
478 ch.into(),
479 if is_differential {
480 Difsel::DIFFERENTIAL
481 } else {
482 Difsel::SINGLE_ENDED
483 },
484 );
485 });
486
487 T::regs().cr().modify(|w| w.set_aden(true)); // enable adc
488 }
508 } 489 }
509 } 490 }
510 491
@@ -564,12 +545,9 @@ impl<'d, T: Instance> Adc<'d, T> {
564 Self::enable(); 545 Self::enable();
565 546
566 //adc side setup 547 //adc side setup
567 548 Self::configure_sequence(
568 Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { 549 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
569 channel.setup(); 550 );
570
571 (channel.channel, sample_time)
572 }));
573 551
574 // Clear overrun flag before starting transfer. 552 // Clear overrun flag before starting transfer.
575 T::regs().isr().modify(|reg| { 553 T::regs().isr().modify(|reg| {
@@ -646,8 +624,17 @@ impl<'d, T: Instance> Adc<'d, T> {
646 624
647 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); 625 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
648 626
649 for (n, (mut channel, sample_time)) in sequence.into_iter().enumerate() { 627 for (n, (channel, sample_time)) in sequence.into_iter().enumerate() {
650 Self::configure_channel(&mut channel, sample_time); 628 let sample_time = sample_time.into();
629 if channel.channel() <= 9 {
630 T::regs()
631 .smpr()
632 .modify(|reg| reg.set_smp(channel.channel() as _, sample_time));
633 } else {
634 T::regs()
635 .smpr2()
636 .modify(|reg| reg.set_smp((channel.channel() - 10) as _, sample_time));
637 }
651 638
652 let idx = match n { 639 let idx = match n {
653 0..=3 => n, 640 0..=3 => n,
@@ -749,38 +736,6 @@ impl<'d, T: Instance> Adc<'d, T> {
749 T::regs().ier().modify(|r| r.set_jeosie(enable)); 736 T::regs().ier().modify(|r| r.set_jeosie(enable));
750 } 737 }
751 738
752 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
753 // Configure channel
754 Self::set_channel_sample_time(channel.channel(), sample_time);
755 }
756
757 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
758 Self::configure_channel(channel, sample_time);
759 #[cfg(stm32h7)]
760 {
761 T::regs().cfgr2().modify(|w| w.set_lshift(0));
762 T::regs()
763 .pcsel()
764 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
765 }
766
767 T::regs().sqr1().write(|reg| {
768 reg.set_sq(0, channel.channel());
769 reg.set_l(0);
770 });
771
772 self.convert()
773 }
774
775 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
776 let sample_time = sample_time.into();
777 if ch <= 9 {
778 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time));
779 } else {
780 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
781 }
782 }
783
784 // Stop regular conversions 739 // Stop regular conversions
785 fn stop_regular_conversions() { 740 fn stop_regular_conversions() {
786 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 741 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
@@ -811,47 +766,47 @@ impl<T: Instance, const N: usize> InjectedAdc<T, N> {
811 766
812#[cfg(stm32g4)] 767#[cfg(stm32g4)]
813mod g4 { 768mod g4 {
814 use crate::adc::{TemperatureConverter, VBatConverter, VrefConverter}; 769 use crate::adc::{SealedSpecialConverter, Temperature, Vbat, VrefInt};
815 770
816 impl TemperatureConverter for crate::peripherals::ADC1 { 771 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC1 {
817 const CHANNEL: u8 = 16; 772 const CHANNEL: u8 = 16;
818 } 773 }
819 774
820 impl VrefConverter for crate::peripherals::ADC1 { 775 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC1 {
821 const CHANNEL: u8 = 18; 776 const CHANNEL: u8 = 18;
822 } 777 }
823 778
824 impl VBatConverter for crate::peripherals::ADC1 { 779 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC1 {
825 const CHANNEL: u8 = 17; 780 const CHANNEL: u8 = 17;
826 } 781 }
827 782
828 #[cfg(peri_adc3_common)] 783 #[cfg(peri_adc3_common)]
829 impl VrefConverter for crate::peripherals::ADC3 { 784 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC3 {
830 const CHANNEL: u8 = 18; 785 const CHANNEL: u8 = 18;
831 } 786 }
832 787
833 #[cfg(peri_adc3_common)] 788 #[cfg(peri_adc3_common)]
834 impl VBatConverter for crate::peripherals::ADC3 { 789 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC3 {
835 const CHANNEL: u8 = 17; 790 const CHANNEL: u8 = 17;
836 } 791 }
837 792
838 #[cfg(not(stm32g4x1))] 793 #[cfg(not(stm32g4x1))]
839 impl VrefConverter for crate::peripherals::ADC4 { 794 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC4 {
840 const CHANNEL: u8 = 18; 795 const CHANNEL: u8 = 18;
841 } 796 }
842 797
843 #[cfg(not(stm32g4x1))] 798 #[cfg(not(stm32g4x1))]
844 impl TemperatureConverter for crate::peripherals::ADC5 { 799 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC5 {
845 const CHANNEL: u8 = 4; 800 const CHANNEL: u8 = 4;
846 } 801 }
847 802
848 #[cfg(not(stm32g4x1))] 803 #[cfg(not(stm32g4x1))]
849 impl VrefConverter for crate::peripherals::ADC5 { 804 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC5 {
850 const CHANNEL: u8 = 18; 805 const CHANNEL: u8 = 18;
851 } 806 }
852 807
853 #[cfg(not(stm32g4x1))] 808 #[cfg(not(stm32g4x1))]
854 impl VBatConverter for crate::peripherals::ADC5 { 809 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC5 {
855 const CHANNEL: u8 = 17; 810 const CHANNEL: u8 = 17;
856 } 811 }
857} 812}
@@ -859,13 +814,13 @@ mod g4 {
859// TODO this should look at each ADC individually and impl the correct channels 814// TODO this should look at each ADC individually and impl the correct channels
860#[cfg(stm32h7)] 815#[cfg(stm32h7)]
861mod h7 { 816mod h7 {
862 impl<T: Instance> TemperatureConverter for T { 817 impl<T: Instance> SealedSpecialConverter<Temperature> for T {
863 const CHANNEL: u8 = 18; 818 const CHANNEL: u8 = 18;
864 } 819 }
865 impl<T: Instance> VrefConverter for T { 820 impl<T: Instance> SealedSpecialConverter<VrefInt> for T {
866 const CHANNEL: u8 = 19; 821 const CHANNEL: u8 = 19;
867 } 822 }
868 impl<T: Instance> VBatConverter for T { 823 impl<T: Instance> SealedSpecialConverter<Vbat> for T {
869 // TODO this should be 14 for H7a/b/35 824 // TODO this should be 14 for H7a/b/35
870 const CHANNEL: u8 = 17; 825 const CHANNEL: u8 = 17;
871 } 826 }
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 3bf893a35..e321c4fa1 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -80,6 +80,11 @@ pub(crate) trait SealedAdcChannel<T> {
80 80
81 #[allow(unused)] 81 #[allow(unused)]
82 fn channel(&self) -> u8; 82 fn channel(&self) -> u8;
83
84 #[allow(unused)]
85 fn is_differential(&self) -> bool {
86 false
87 }
83} 88}
84 89
85/// Performs a busy-wait delay for a specified number of microseconds. 90/// Performs a busy-wait delay for a specified number of microseconds.
@@ -100,29 +105,28 @@ pub(crate) fn blocking_delay_us(us: u32) {
100 } 105 }
101} 106}
102 107
103/// Implemented for ADCs that have a Temperature channel 108pub(self) trait SpecialChannel {}
104pub trait TemperatureConverter { 109
105 const CHANNEL: u8; 110/// Implemented for ADCs that have a special channel
106} 111trait SealedSpecialConverter<T: SpecialChannel + Sized> {
107/// Implemented for ADCs that have a Vref channel
108pub trait VrefConverter {
109 const CHANNEL: u8;
110}
111/// Implemented for ADCs that have a VBat channel
112pub trait VBatConverter {
113 const CHANNEL: u8; 112 const CHANNEL: u8;
114} 113}
115 114
116// 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 115#[allow(private_bounds)]
117/// Internal voltage reference channel. 116pub trait SpecialConverter<T: SpecialChannel + Sized>: SealedSpecialConverter<T> {}
118pub struct VrefInt; 117
119impl<T: Instance + VrefConverter> AdcChannel<T> for VrefInt {} 118impl<C: SpecialChannel + Sized, T: SealedSpecialConverter<C>> SpecialConverter<C> for T {}
120impl<T: Instance + VrefConverter> SealedAdcChannel<T> for VrefInt { 119
120impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> AdcChannel<T> for C {}
121impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> SealedAdcChannel<T> for C {
121 fn channel(&self) -> u8 { 122 fn channel(&self) -> u8 {
122 T::CHANNEL 123 T::CHANNEL
123 } 124 }
124} 125}
125 126
127pub struct VrefInt;
128impl SpecialChannel for VrefInt {}
129
126impl VrefInt { 130impl VrefInt {
127 #[cfg(any(adc_f3v1, adc_f3v2))] 131 #[cfg(any(adc_f3v1, adc_f3v2))]
128 /// The value that vref would be if vdda was at 3300mv 132 /// The value that vref would be if vdda was at 3300mv
@@ -133,21 +137,11 @@ impl VrefInt {
133 137
134/// Internal temperature channel. 138/// Internal temperature channel.
135pub struct Temperature; 139pub struct Temperature;
136impl<T: Instance + TemperatureConverter> AdcChannel<T> for Temperature {} 140impl SpecialChannel for Temperature {}
137impl<T: Instance + TemperatureConverter> SealedAdcChannel<T> for Temperature {
138 fn channel(&self) -> u8 {
139 T::CHANNEL
140 }
141}
142 141
143/// Internal battery voltage channel. 142/// Internal battery voltage channel.
144pub struct Vbat; 143pub struct Vbat;
145impl<T: Instance + VBatConverter> AdcChannel<T> for Vbat {} 144impl SpecialChannel for Vbat {}
146impl<T: Instance + VBatConverter> SealedAdcChannel<T> for Vbat {
147 fn channel(&self) -> u8 {
148 T::CHANNEL
149 }
150}
151 145
152/// ADC instance. 146/// ADC instance.
153#[cfg(not(any( 147#[cfg(not(any(
@@ -178,6 +172,7 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
178 172
179 AnyAdcChannel { 173 AnyAdcChannel {
180 channel: self.channel(), 174 channel: self.channel(),
175 is_differential: self.is_differential(),
181 _phantom: PhantomData, 176 _phantom: PhantomData,
182 } 177 }
183 } 178 }
@@ -189,6 +184,7 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
189/// storing them in an array. 184/// storing them in an array.
190pub struct AnyAdcChannel<T> { 185pub struct AnyAdcChannel<T> {
191 channel: u8, 186 channel: u8,
187 is_differential: bool,
192 _phantom: PhantomData<T>, 188 _phantom: PhantomData<T>,
193} 189}
194impl_peripheral!(AnyAdcChannel<T: Instance>); 190impl_peripheral!(AnyAdcChannel<T: Instance>);
@@ -197,6 +193,10 @@ impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
197 fn channel(&self) -> u8 { 193 fn channel(&self) -> u8 {
198 self.channel 194 self.channel
199 } 195 }
196
197 fn is_differential(&self) -> bool {
198 self.is_differential
199 }
200} 200}
201 201
202impl<T> AnyAdcChannel<T> { 202impl<T> AnyAdcChannel<T> {
@@ -315,6 +315,39 @@ macro_rules! impl_adc_pin {
315 }; 315 };
316} 316}
317 317
318#[allow(unused_macros)]
319macro_rules! impl_adc_pair {
320 ($inst:ident, $pin:ident, $npin:ident, $ch:expr) => {
321 impl crate::adc::AdcChannel<peripherals::$inst>
322 for (
323 crate::Peri<'_, crate::peripherals::$pin>,
324 crate::Peri<'_, crate::peripherals::$npin>,
325 )
326 {
327 }
328 impl crate::adc::SealedAdcChannel<peripherals::$inst>
329 for (
330 crate::Peri<'_, crate::peripherals::$pin>,
331 crate::Peri<'_, crate::peripherals::$npin>,
332 )
333 {
334 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
335 fn setup(&mut self) {
336 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0);
337 <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1);
338 }
339
340 fn channel(&self) -> u8 {
341 $ch
342 }
343
344 fn is_differential(&self) -> bool {
345 true
346 }
347 }
348 };
349}
350
318/// Get the maximum reading value for this resolution. 351/// Get the maximum reading value for this resolution.
319/// 352///
320/// This is `2**n - 1`. 353/// This is `2**n - 1`.
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 97557ee8a..58c30935f 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -43,22 +43,22 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
43} 43}
44 44
45#[cfg(not(adc_l0))] 45#[cfg(not(adc_l0))]
46impl super::VBatConverter for crate::peripherals::ADC1 { 46impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC1 {
47 const CHANNEL: u8 = 18; 47 const CHANNEL: u8 = 18;
48} 48}
49 49
50#[cfg(not(adc_l0))] 50#[cfg(not(adc_l0))]
51impl super::VrefConverter for crate::peripherals::ADC1 { 51impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
52 const CHANNEL: u8 = 17; 52 const CHANNEL: u8 = 17;
53} 53}
54 54
55#[cfg(adc_l0)] 55#[cfg(adc_l0)]
56impl super::VrefConverter for crate::peripherals::ADC1 { 56impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
57 const CHANNEL: u8 = 18; 57 const CHANNEL: u8 = 18;
58} 58}
59 59
60#[cfg(not(adc_l0))] 60#[cfg(not(adc_l0))]
61impl super::TemperatureConverter for crate::peripherals::ADC1 { 61impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
62 const CHANNEL: u8 = 16; 62 const CHANNEL: u8 = 16;
63} 63}
64 64
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 88a8b96ed..efa1cc68c 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -22,21 +22,21 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
22/// VREF voltage used for factory calibration of VREFINTCAL register. 22/// VREF voltage used for factory calibration of VREFINTCAL register.
23pub const VREF_CALIB_MV: u32 = 3300; 23pub const VREF_CALIB_MV: u32 = 3300;
24 24
25impl super::VrefConverter for crate::peripherals::ADC1 { 25impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
26 const CHANNEL: u8 = 17; 26 const CHANNEL: u8 = 17;
27} 27}
28 28
29#[cfg(any(stm32f2, stm32f40x, stm32f41x))] 29#[cfg(any(stm32f2, stm32f40x, stm32f41x))]
30impl super::TemperatureConverter for crate::peripherals::ADC1 { 30impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
31 const CHANNEL: u8 = 16; 31 const CHANNEL: u8 = 16;
32} 32}
33 33
34#[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))] 34#[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))]
35impl super::TemperatureConverter for crate::peripherals::ADC1 { 35impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
36 const CHANNEL: u8 = 18; 36 const CHANNEL: u8 = 18;
37} 37}
38 38
39impl super::VBatConverter for crate::peripherals::ADC1 { 39impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC1 {
40 const CHANNEL: u8 = 18; 40 const CHANNEL: u8 = 18;
41} 41}
42 42
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index e816907d1..cbc217545 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -36,53 +36,53 @@ pub const VREF_CALIB_MV: u32 = 3000;
36const SAMPLE_TIMES_CAPACITY: usize = 2; 36const SAMPLE_TIMES_CAPACITY: usize = 2;
37 37
38#[cfg(adc_g0)] 38#[cfg(adc_g0)]
39impl<T: Instance> super::VrefConverter for T { 39impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
40 const CHANNEL: u8 = 13; 40 const CHANNEL: u8 = 13;
41} 41}
42#[cfg(any(adc_h5, adc_h7rs))] 42#[cfg(any(adc_h5, adc_h7rs))]
43impl<T: Instance> super::VrefConverter for T { 43impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
44 const CHANNEL: u8 = 17; 44 const CHANNEL: u8 = 17;
45} 45}
46#[cfg(adc_u0)] 46#[cfg(adc_u0)]
47impl<T: Instance> super::VrefConverter for T { 47impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
48 const CHANNEL: u8 = 12; 48 const CHANNEL: u8 = 12;
49} 49}
50#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] 50#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
51impl<T: Instance> super::VrefConverter for T { 51impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
52 const CHANNEL: u8 = 0; 52 const CHANNEL: u8 = 0;
53} 53}
54 54
55#[cfg(adc_g0)] 55#[cfg(adc_g0)]
56impl<T: Instance> super::TemperatureConverter for T { 56impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
57 const CHANNEL: u8 = 12; 57 const CHANNEL: u8 = 12;
58} 58}
59#[cfg(any(adc_h5, adc_h7rs))] 59#[cfg(any(adc_h5, adc_h7rs))]
60impl<T: Instance> super::TemperatureConverter for T { 60impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
61 const CHANNEL: u8 = 16; 61 const CHANNEL: u8 = 16;
62} 62}
63#[cfg(adc_u0)] 63#[cfg(adc_u0)]
64impl<T: Instance> super::TemperatureConverter for T { 64impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
65 const CHANNEL: u8 = 11; 65 const CHANNEL: u8 = 11;
66} 66}
67#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] 67#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
68impl<T: Instance> super::TemperatureConverter for T { 68impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
69 const CHANNEL: u8 = 17; 69 const CHANNEL: u8 = 17;
70} 70}
71 71
72#[cfg(adc_g0)] 72#[cfg(adc_g0)]
73impl<T: Instance> super::VBatConverter for T { 73impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
74 const CHANNEL: u8 = 14; 74 const CHANNEL: u8 = 14;
75} 75}
76#[cfg(any(adc_h5, adc_h7rs))] 76#[cfg(any(adc_h5, adc_h7rs))]
77impl<T: Instance> super::VBatConverter for T { 77impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
78 const CHANNEL: u8 = 2; 78 const CHANNEL: u8 = 2;
79} 79}
80#[cfg(adc_u0)] 80#[cfg(adc_u0)]
81impl<T: Instance> super::VBatConverter for T { 81impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
82 const CHANNEL: u8 = 13; 82 const CHANNEL: u8 = 13;
83} 83}
84#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] 84#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
85impl<T: Instance> super::VBatConverter for T { 85impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
86 const CHANNEL: u8 = 18; 86 const CHANNEL: u8 = 18;
87} 87}
88 88
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 2f7baf3bf..1d5d3fb92 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -26,39 +26,39 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
26const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 26const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
27 27
28#[cfg(stm32g4)] 28#[cfg(stm32g4)]
29impl<T: Instance> super::VrefConverter for T { 29impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
30 const CHANNEL: u8 = 18; 30 const CHANNEL: u8 = 18;
31} 31}
32#[cfg(stm32g4)] 32#[cfg(stm32g4)]
33impl<T: Instance> super::TemperatureConverter for T { 33impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
34 const CHANNEL: u8 = 16; 34 const CHANNEL: u8 = 16;
35} 35}
36 36
37#[cfg(stm32h7)] 37#[cfg(stm32h7)]
38impl<T: Instance> super::VrefConverter for T { 38impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
39 const CHANNEL: u8 = 19; 39 const CHANNEL: u8 = 19;
40} 40}
41#[cfg(stm32h7)] 41#[cfg(stm32h7)]
42impl<T: Instance> super::TemperatureConverter for T { 42impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
43 const CHANNEL: u8 = 18; 43 const CHANNEL: u8 = 18;
44} 44}
45 45
46// TODO this should be 14 for H7a/b/35 46// TODO this should be 14 for H7a/b/35
47#[cfg(not(stm32u5))] 47#[cfg(not(stm32u5))]
48impl<T: Instance> super::VBatConverter for T { 48impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
49 const CHANNEL: u8 = 17; 49 const CHANNEL: u8 = 17;
50} 50}
51 51
52#[cfg(stm32u5)] 52#[cfg(stm32u5)]
53impl<T: Instance> super::VrefConverter for T { 53impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
54 const CHANNEL: u8 = 0; 54 const CHANNEL: u8 = 0;
55} 55}
56#[cfg(stm32u5)] 56#[cfg(stm32u5)]
57impl<T: Instance> super::TemperatureConverter for T { 57impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
58 const CHANNEL: u8 = 19; 58 const CHANNEL: u8 = 19;
59} 59}
60#[cfg(stm32u5)] 60#[cfg(stm32u5)]
61impl<T: Instance> super::VBatConverter for T { 61impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
62 const CHANNEL: u8 = 18; 62 const CHANNEL: u8 = 18;
63} 63}
64 64
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 695f37115..94315141c 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -30,9 +30,14 @@ async fn main(_spawner: Spawner) {
30 30
31 let mut adc = Adc::new(p.ADC2); 31 let mut adc = Adc::new(p.ADC2);
32 32
33 let mut adc_temp = Adc::new(p.ADC1);
34 let mut temperature = adc_temp.enable_temperature();
35
33 loop { 36 loop {
34 let measured = adc.blocking_read(&mut p.PA7, SampleTime::CYCLES24_5); 37 let measured = adc.blocking_read(&mut p.PA7, SampleTime::CYCLES24_5);
38 let temperature = adc_temp.blocking_read(&mut temperature, SampleTime::CYCLES24_5);
35 info!("measured: {}", measured); 39 info!("measured: {}", measured);
40 info!("temperature: {}", temperature);
36 Timer::after_millis(500).await; 41 Timer::after_millis(500).await;
37 } 42 }
38} 43}
diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs
index a6e2f7d33..2773723e9 100644
--- a/examples/stm32g4/src/bin/adc_differential.rs
+++ b/examples/stm32g4/src/bin/adc_differential.rs
@@ -30,16 +30,16 @@ async fn main(_spawner: Spawner) {
30 config.rcc.mux.adc12sel = mux::Adcsel::SYS; 30 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
31 config.rcc.sys = Sysclk::PLL1_R; 31 config.rcc.sys = Sysclk::PLL1_R;
32 } 32 }
33 let mut p = embassy_stm32::init(config); 33 let p = embassy_stm32::init(config);
34 34
35 let mut adc = Adc::new(p.ADC1); 35 let mut adc = Adc::new(p.ADC1);
36 adc.set_differential(&mut p.PA0, true); //p:pa0,n:pa1 36 let mut differential_channel = (p.PA0, p.PA1);
37 37
38 // can also use 38 // can also use
39 // adc.set_differential_channel(1, true); 39 // adc.set_differential_channel(1, true);
40 info!("adc initialized"); 40 info!("adc initialized");
41 loop { 41 loop {
42 let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES247_5); 42 let measured = adc.blocking_read(&mut differential_channel, SampleTime::CYCLES247_5);
43 info!("data: {}", measured); 43 info!("data: {}", measured);
44 Timer::after_millis(500).await; 44 Timer::after_millis(500).await;
45 } 45 }