diff options
| author | xoviat <[email protected]> | 2025-11-11 17:19:26 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-11 17:19:26 +0000 |
| commit | 0d1fc76a10863b85961a63db4a9e1e2807f35957 (patch) | |
| tree | 1ffe8a8dddec7085876adb8bfcd86c3fed22ae74 | |
| parent | f078c85454f09f28a85aa834a9496b37058695e0 (diff) | |
| parent | 769941980442ada1524ee4f60f1d003735caff4b (diff) | |
Merge pull request #4866 from xoviat/adc
adc: impl. differential channels
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/build.rs | 37 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/c0.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/f1.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/f3.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/g4.rs | 193 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 87 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v1.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v2.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 24 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v4.rs | 16 | ||||
| -rw-r--r-- | examples/stm32g4/src/bin/adc.rs | 5 | ||||
| -rw-r--r-- | examples/stm32g4/src/bin/adc_differential.rs | 6 |
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" | |||
| 198 | heapless = "0.9.1" | 198 | heapless = "0.9.1" |
| 199 | 199 | ||
| 200 | #stm32-metapac = { version = "18" } | 200 | #stm32-metapac = { version = "18" } |
| 201 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e" } | 201 | stm32-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"]} |
| 205 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e", default-features = false, features = ["metadata"] } | 205 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2", default-features = false, features = ["metadata"] } |
| 206 | 206 | ||
| 207 | proc-macro2 = "1.0.36" | 207 | proc-macro2 = "1.0.36" |
| 208 | quote = "1.0.15" | 208 | quote = "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; | |||
| 24 | const CHSELR_SQ_MAX_CHANNEL: u8 = 14; | 24 | const CHSELR_SQ_MAX_CHANNEL: u8 = 14; |
| 25 | const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; | 25 | const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; |
| 26 | 26 | ||
| 27 | impl<T: Instance> super::VrefConverter for T { | 27 | impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T { |
| 28 | const CHANNEL: u8 = 10; | 28 | const CHANNEL: u8 = 10; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | impl<T: Instance> super::TemperatureConverter for T { | 31 | impl<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; | |||
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use super::blocking_delay_us; | 5 | use super::blocking_delay_us; |
| 6 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; | 6 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt}; |
| 7 | use crate::interrupt::typelevel::Interrupt; | 7 | use crate::interrupt::typelevel::Interrupt; |
| 8 | use crate::interrupt::{self}; | 8 | use crate::interrupt::{self}; |
| 9 | use crate::time::Hertz; | 9 | use crate::time::Hertz; |
| @@ -28,11 +28,11 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 28 | } | 28 | } |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | impl<T: Instance> super::VrefConverter for T { | 31 | impl<T: Instance> super::SealedSpecialConverter<VrefInt> for T { |
| 32 | const CHANNEL: u8 = 17; | 32 | const CHANNEL: u8 = 17; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | impl<T: Instance> super::TemperatureConverter for T { | 35 | impl<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; | |||
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use super::blocking_delay_us; | 5 | use super::blocking_delay_us; |
| 6 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; | 6 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt}; |
| 7 | use crate::interrupt::typelevel::Interrupt; | 7 | use crate::interrupt::typelevel::Interrupt; |
| 8 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| 9 | use crate::{Peri, interrupt, rcc}; | 9 | use crate::{Peri, interrupt, rcc}; |
| @@ -29,11 +29,11 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 29 | } | 29 | } |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | impl<T: Instance> super::VrefConverter for T { | 32 | impl<T: Instance> super::SealedSpecialConverter<VrefInt> for T { |
| 33 | const CHANNEL: u8 = 18; | 33 | const CHANNEL: u8 = 18; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | impl<T: Instance> super::TemperatureConverter for T { | 36 | impl<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)] |
| 813 | mod g4 { | 768 | mod 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)] |
| 861 | mod h7 { | 816 | mod 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 | 108 | pub(self) trait SpecialChannel {} |
| 104 | pub trait TemperatureConverter { | 109 | |
| 105 | const CHANNEL: u8; | 110 | /// Implemented for ADCs that have a special channel |
| 106 | } | 111 | trait SealedSpecialConverter<T: SpecialChannel + Sized> { |
| 107 | /// Implemented for ADCs that have a Vref channel | ||
| 108 | pub trait VrefConverter { | ||
| 109 | const CHANNEL: u8; | ||
| 110 | } | ||
| 111 | /// Implemented for ADCs that have a VBat channel | ||
| 112 | pub 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. | 116 | pub trait SpecialConverter<T: SpecialChannel + Sized>: SealedSpecialConverter<T> {} |
| 118 | pub struct VrefInt; | 117 | |
| 119 | impl<T: Instance + VrefConverter> AdcChannel<T> for VrefInt {} | 118 | impl<C: SpecialChannel + Sized, T: SealedSpecialConverter<C>> SpecialConverter<C> for T {} |
| 120 | impl<T: Instance + VrefConverter> SealedAdcChannel<T> for VrefInt { | 119 | |
| 120 | impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> AdcChannel<T> for C {} | ||
| 121 | impl<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 | ||
| 127 | pub struct VrefInt; | ||
| 128 | impl SpecialChannel for VrefInt {} | ||
| 129 | |||
| 126 | impl VrefInt { | 130 | impl 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. |
| 135 | pub struct Temperature; | 139 | pub struct Temperature; |
| 136 | impl<T: Instance + TemperatureConverter> AdcChannel<T> for Temperature {} | 140 | impl SpecialChannel for Temperature {} |
| 137 | impl<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. |
| 144 | pub struct Vbat; | 143 | pub struct Vbat; |
| 145 | impl<T: Instance + VBatConverter> AdcChannel<T> for Vbat {} | 144 | impl SpecialChannel for Vbat {} |
| 146 | impl<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. |
| 190 | pub struct AnyAdcChannel<T> { | 185 | pub struct AnyAdcChannel<T> { |
| 191 | channel: u8, | 186 | channel: u8, |
| 187 | is_differential: bool, | ||
| 192 | _phantom: PhantomData<T>, | 188 | _phantom: PhantomData<T>, |
| 193 | } | 189 | } |
| 194 | impl_peripheral!(AnyAdcChannel<T: Instance>); | 190 | impl_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 | ||
| 202 | impl<T> AnyAdcChannel<T> { | 202 | impl<T> AnyAdcChannel<T> { |
| @@ -315,6 +315,39 @@ macro_rules! impl_adc_pin { | |||
| 315 | }; | 315 | }; |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | #[allow(unused_macros)] | ||
| 319 | macro_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))] |
| 46 | impl super::VBatConverter for crate::peripherals::ADC1 { | 46 | impl 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))] |
| 51 | impl super::VrefConverter for crate::peripherals::ADC1 { | 51 | impl 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)] |
| 56 | impl super::VrefConverter for crate::peripherals::ADC1 { | 56 | impl 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))] |
| 61 | impl super::TemperatureConverter for crate::peripherals::ADC1 { | 61 | impl 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. |
| 23 | pub const VREF_CALIB_MV: u32 = 3300; | 23 | pub const VREF_CALIB_MV: u32 = 3300; |
| 24 | 24 | ||
| 25 | impl super::VrefConverter for crate::peripherals::ADC1 { | 25 | impl 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))] |
| 30 | impl super::TemperatureConverter for crate::peripherals::ADC1 { | 30 | impl 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)))] |
| 35 | impl super::TemperatureConverter for crate::peripherals::ADC1 { | 35 | impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 { |
| 36 | const CHANNEL: u8 = 18; | 36 | const CHANNEL: u8 = 18; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | impl super::VBatConverter for crate::peripherals::ADC1 { | 39 | impl 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; | |||
| 36 | const SAMPLE_TIMES_CAPACITY: usize = 2; | 36 | const SAMPLE_TIMES_CAPACITY: usize = 2; |
| 37 | 37 | ||
| 38 | #[cfg(adc_g0)] | 38 | #[cfg(adc_g0)] |
| 39 | impl<T: Instance> super::VrefConverter for T { | 39 | impl<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))] |
| 43 | impl<T: Instance> super::VrefConverter for T { | 43 | impl<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)] |
| 47 | impl<T: Instance> super::VrefConverter for T { | 47 | impl<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)))] |
| 51 | impl<T: Instance> super::VrefConverter for T { | 51 | impl<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)] |
| 56 | impl<T: Instance> super::TemperatureConverter for T { | 56 | impl<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))] |
| 60 | impl<T: Instance> super::TemperatureConverter for T { | 60 | impl<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)] |
| 64 | impl<T: Instance> super::TemperatureConverter for T { | 64 | impl<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)))] |
| 68 | impl<T: Instance> super::TemperatureConverter for T { | 68 | impl<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)] |
| 73 | impl<T: Instance> super::VBatConverter for T { | 73 | impl<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))] |
| 77 | impl<T: Instance> super::VBatConverter for T { | 77 | impl<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)] |
| 81 | impl<T: Instance> super::VBatConverter for T { | 81 | impl<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)))] |
| 85 | impl<T: Instance> super::VBatConverter for T { | 85 | impl<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); | |||
| 26 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); | 26 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); |
| 27 | 27 | ||
| 28 | #[cfg(stm32g4)] | 28 | #[cfg(stm32g4)] |
| 29 | impl<T: Instance> super::VrefConverter for T { | 29 | impl<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)] |
| 33 | impl<T: Instance> super::TemperatureConverter for T { | 33 | impl<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)] |
| 38 | impl<T: Instance> super::VrefConverter for T { | 38 | impl<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)] |
| 42 | impl<T: Instance> super::TemperatureConverter for T { | 42 | impl<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))] |
| 48 | impl<T: Instance> super::VBatConverter for T { | 48 | impl<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)] |
| 53 | impl<T: Instance> super::VrefConverter for T { | 53 | impl<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)] |
| 57 | impl<T: Instance> super::TemperatureConverter for T { | 57 | impl<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)] |
| 61 | impl<T: Instance> super::VBatConverter for T { | 61 | impl<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 | } |
