aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-11-12 21:03:36 +0100
committerHybridChild <[email protected]>2025-11-12 21:03:36 +0100
commit18a43908725366a230c990b8dee4a1d89fef11d0 (patch)
treef2c515ecc23131e1ef7a4bebc15f025e23a62f03
parent973fdb6b222a24e881c722b33767aab76ab92896 (diff)
parent07c918023c1b233a2f9f16eb0b654169c0379f79 (diff)
Merge branch 'main' into stm32_i2c_v2_transaction
-rw-r--r--embassy-stm32/Cargo.toml28
-rw-r--r--embassy-stm32/build.rs37
-rw-r--r--embassy-stm32/src/adc/adc4.rs110
-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.rs612
-rw-r--r--embassy-stm32/src/adc/injected.rs2
-rw-r--r--embassy-stm32/src/adc/mod.rs256
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs2
-rw-r--r--embassy-stm32/src/adc/v1.rs8
-rw-r--r--embassy-stm32/src/adc/v2.rs241
-rw-r--r--embassy-stm32/src/adc/v3.rs762
-rw-r--r--embassy-stm32/src/adc/v4.rs343
-rw-r--r--embassy-usb/CHANGELOG.md2
-rw-r--r--embassy-usb/src/class/hid.rs101
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs58
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs56
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs86
-rwxr-xr-xexamples/rp/src/bin/usb_hid_mouse.rs60
-rw-r--r--examples/rp235x/src/bin/usb_hid_keyboard.rs85
-rw-r--r--examples/stm32f4/src/bin/adc.rs2
-rw-r--r--examples/stm32f4/src/bin/adc_dma.rs8
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs84
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs56
-rw-r--r--examples/stm32g0/src/bin/adc_oversampling.rs14
-rw-r--r--examples/stm32g4/src/bin/adc.rs7
-rw-r--r--examples/stm32g4/src/bin/adc_differential.rs8
-rw-r--r--examples/stm32g4/src/bin/adc_dma.rs2
-rw-r--r--examples/stm32g4/src/bin/adc_injected_and_regular.rs2
-rw-r--r--examples/stm32g4/src/bin/adc_oversampling.rs13
-rw-r--r--examples/stm32l4/src/bin/adc.rs9
-rw-r--r--examples/stm32l4/src/bin/adc_dma.rs5
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs56
-rw-r--r--examples/stm32u0/src/bin/adc.rs7
-rw-r--r--examples/stm32u5/src/bin/adc.rs16
36 files changed, 1583 insertions, 1571 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 0a1854dab..ec49924a2 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -139,6 +139,7 @@ flavors = [
139 { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, 139 { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
140 { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" }, 140 { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" },
141 { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" }, 141 { regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" },
142 { regex_feature = "stm32n6.*", target = "thumbv8m.main-none-eabihf" },
142] 143]
143 144
144[package.metadata.docs.rs] 145[package.metadata.docs.rs]
@@ -198,11 +199,11 @@ aligned = "0.4.1"
198heapless = "0.9.1" 199heapless = "0.9.1"
199 200
200#stm32-metapac = { version = "18" } 201#stm32-metapac = { version = "18" }
201stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-22374e3344a2c9150b9b3d4da45c03f398fdc54e" } 202stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2" }
202 203
203[build-dependencies] 204[build-dependencies]
204#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} 205#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"] } 206stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2", default-features = false, features = ["metadata"] }
206 207
207proc-macro2 = "1.0.36" 208proc-macro2 = "1.0.36"
208quote = "1.0.15" 209quote = "1.0.15"
@@ -1642,7 +1643,30 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ]
1642stm32l562re = [ "stm32-metapac/stm32l562re" ] 1643stm32l562re = [ "stm32-metapac/stm32l562re" ]
1643stm32l562ve = [ "stm32-metapac/stm32l562ve" ] 1644stm32l562ve = [ "stm32-metapac/stm32l562ve" ]
1644stm32l562ze = [ "stm32-metapac/stm32l562ze" ] 1645stm32l562ze = [ "stm32-metapac/stm32l562ze" ]
1646stm32n645a0 = [ "stm32-metapac/stm32n645a0" ]
1647stm32n645b0 = [ "stm32-metapac/stm32n645b0" ]
1648stm32n645i0 = [ "stm32-metapac/stm32n645i0" ]
1649stm32n645l0 = [ "stm32-metapac/stm32n645l0" ]
1650stm32n645x0 = [ "stm32-metapac/stm32n645x0" ]
1651stm32n645z0 = [ "stm32-metapac/stm32n645z0" ]
1652stm32n647a0 = [ "stm32-metapac/stm32n647a0" ]
1653stm32n647b0 = [ "stm32-metapac/stm32n647b0" ]
1654stm32n647i0 = [ "stm32-metapac/stm32n647i0" ]
1655stm32n647l0 = [ "stm32-metapac/stm32n647l0" ]
1656stm32n647x0 = [ "stm32-metapac/stm32n647x0" ]
1657stm32n647z0 = [ "stm32-metapac/stm32n647z0" ]
1658stm32n655a0 = [ "stm32-metapac/stm32n655a0" ]
1659stm32n655b0 = [ "stm32-metapac/stm32n655b0" ]
1660stm32n655i0 = [ "stm32-metapac/stm32n655i0" ]
1661stm32n655l0 = [ "stm32-metapac/stm32n655l0" ]
1662stm32n655x0 = [ "stm32-metapac/stm32n655x0" ]
1663stm32n655z0 = [ "stm32-metapac/stm32n655z0" ]
1664stm32n657a0 = [ "stm32-metapac/stm32n657a0" ]
1665stm32n657b0 = [ "stm32-metapac/stm32n657b0" ]
1666stm32n657i0 = [ "stm32-metapac/stm32n657i0" ]
1667stm32n657l0 = [ "stm32-metapac/stm32n657l0" ]
1645stm32n657x0 = [ "stm32-metapac/stm32n657x0" ] 1668stm32n657x0 = [ "stm32-metapac/stm32n657x0" ]
1669stm32n657z0 = [ "stm32-metapac/stm32n657z0" ]
1646stm32u031c6 = [ "stm32-metapac/stm32u031c6" ] 1670stm32u031c6 = [ "stm32-metapac/stm32u031c6" ]
1647stm32u031c8 = [ "stm32-metapac/stm32u031c8" ] 1671stm32u031c8 = [ "stm32-metapac/stm32u031c8" ]
1648stm32u031f4 = [ "stm32-metapac/stm32u031f4" ] 1672stm32u031f4 = [ "stm32-metapac/stm32u031f4" ]
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/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index befa8ed4a..04d976513 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -4,7 +4,7 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR
4#[cfg(stm32wba)] 4#[cfg(stm32wba)]
5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; 5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel};
6 6
7use super::{AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel, blocking_delay_us}; 7use super::{AdcChannel, AnyAdcChannel, RxDma4, blocking_delay_us};
8use crate::dma::Transfer; 8use crate::dma::Transfer;
9#[cfg(stm32u5)] 9#[cfg(stm32u5)]
10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; 10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr;
@@ -24,56 +24,24 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
24/// VREF voltage used for factory calibration of VREFINTCAL register. 24/// VREF voltage used for factory calibration of VREFINTCAL register.
25pub const VREF_CALIB_MV: u32 = 3300; 25pub const VREF_CALIB_MV: u32 = 3300;
26 26
27const VREF_CHANNEL: u8 = 0; 27impl<'d, T: Instance> super::SealedSpecialConverter<super::VrefInt> for Adc4<'d, T> {
28const VCORE_CHANNEL: u8 = 12; 28 const CHANNEL: u8 = 0;
29const TEMP_CHANNEL: u8 = 13;
30const VBAT_CHANNEL: u8 = 14;
31const DAC_CHANNEL: u8 = 21;
32
33// 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
34/// Internal voltage reference channel.
35pub struct VrefInt;
36impl<T: Instance> AdcChannel<T> for VrefInt {}
37impl<T: Instance> SealedAdcChannel<T> for VrefInt {
38 fn channel(&self) -> u8 {
39 VREF_CHANNEL
40 }
41} 29}
42 30
43/// Internal temperature channel. 31impl<'d, T: Instance> super::SealedSpecialConverter<super::Temperature> for Adc4<'d, T> {
44pub struct Temperature; 32 const CHANNEL: u8 = 13;
45impl<T: Instance> AdcChannel<T> for Temperature {}
46impl<T: Instance> SealedAdcChannel<T> for Temperature {
47 fn channel(&self) -> u8 {
48 TEMP_CHANNEL
49 }
50} 33}
51 34
52/// Internal battery voltage channel. 35impl<'d, T: Instance> super::SealedSpecialConverter<super::Vcore> for Adc4<'d, T> {
53pub struct Vbat; 36 const CHANNEL: u8 = 12;
54impl<T: Instance> AdcChannel<T> for Vbat {}
55impl<T: Instance> SealedAdcChannel<T> for Vbat {
56 fn channel(&self) -> u8 {
57 VBAT_CHANNEL
58 }
59} 37}
60 38
61/// Internal DAC channel. 39impl<'d, T: Instance> super::SealedSpecialConverter<super::Vbat> for Adc4<'d, T> {
62pub struct Dac; 40 const CHANNEL: u8 = 14;
63impl<T: Instance> AdcChannel<T> for Dac {}
64impl<T: Instance> SealedAdcChannel<T> for Dac {
65 fn channel(&self) -> u8 {
66 DAC_CHANNEL
67 }
68} 41}
69 42
70/// Internal Vcore channel. 43impl<'d, T: Instance> super::SealedSpecialConverter<super::Dac> for Adc4<'d, T> {
71pub struct Vcore; 44 const CHANNEL: u8 = 21;
72impl<T: Instance> AdcChannel<T> for Vcore {}
73impl<T: Instance> SealedAdcChannel<T> for Vcore {
74 fn channel(&self) -> u8 {
75 VCORE_CHANNEL
76 }
77} 45}
78 46
79#[derive(Copy, Clone)] 47#[derive(Copy, Clone)]
@@ -214,20 +182,6 @@ impl<'d, T: Instance> Adc4<'d, T> {
214 ); 182 );
215 } 183 }
216 184
217 let mut s = Self { adc };
218
219 s.power_up();
220
221 s.calibrate();
222 blocking_delay_us(1);
223
224 s.enable();
225 s.configure();
226
227 s
228 }
229
230 fn power_up(&mut self) {
231 T::regs().isr().modify(|w| { 185 T::regs().isr().modify(|w| {
232 w.set_ldordy(true); 186 w.set_ldordy(true);
233 }); 187 });
@@ -239,22 +193,15 @@ impl<'d, T: Instance> Adc4<'d, T> {
239 T::regs().isr().modify(|w| { 193 T::regs().isr().modify(|w| {
240 w.set_ldordy(true); 194 w.set_ldordy(true);
241 }); 195 });
242 }
243 196
244 fn calibrate(&mut self) {
245 T::regs().cr().modify(|w| w.set_adcal(true)); 197 T::regs().cr().modify(|w| w.set_adcal(true));
246 while T::regs().cr().read().adcal() {} 198 while T::regs().cr().read().adcal() {}
247 T::regs().isr().modify(|w| w.set_eocal(true)); 199 T::regs().isr().modify(|w| w.set_eocal(true));
248 }
249 200
250 fn enable(&mut self) { 201 blocking_delay_us(1);
251 T::regs().isr().write(|w| w.set_adrdy(true)); 202
252 T::regs().cr().modify(|w| w.set_aden(true)); 203 Self::enable();
253 while !T::regs().isr().read().adrdy() {}
254 T::regs().isr().write(|w| w.set_adrdy(true));
255 }
256 204
257 fn configure(&mut self) {
258 // single conversion mode, software trigger 205 // single conversion mode, software trigger
259 T::regs().cfgr1().modify(|w| { 206 T::regs().cfgr1().modify(|w| {
260 #[cfg(stm32u5)] 207 #[cfg(stm32u5)]
@@ -280,51 +227,60 @@ impl<'d, T: Instance> Adc4<'d, T> {
280 w.set_smpsel(i, Smpsel::SMP1); 227 w.set_smpsel(i, Smpsel::SMP1);
281 } 228 }
282 }); 229 });
230
231 Self { adc }
232 }
233
234 fn enable() {
235 T::regs().isr().write(|w| w.set_adrdy(true));
236 T::regs().cr().modify(|w| w.set_aden(true));
237 while !T::regs().isr().read().adrdy() {}
238 T::regs().isr().write(|w| w.set_adrdy(true));
283 } 239 }
284 240
285 /// Enable reading the voltage reference internal channel. 241 /// Enable reading the voltage reference internal channel.
286 pub fn enable_vrefint(&self) -> VrefInt { 242 pub fn enable_vrefint(&self) -> super::VrefInt {
287 T::regs().ccr().modify(|w| { 243 T::regs().ccr().modify(|w| {
288 w.set_vrefen(true); 244 w.set_vrefen(true);
289 }); 245 });
290 246
291 VrefInt {} 247 super::VrefInt {}
292 } 248 }
293 249
294 /// Enable reading the temperature internal channel. 250 /// Enable reading the temperature internal channel.
295 pub fn enable_temperature(&self) -> Temperature { 251 pub fn enable_temperature(&self) -> super::Temperature {
296 T::regs().ccr().modify(|w| { 252 T::regs().ccr().modify(|w| {
297 w.set_vsensesel(true); 253 w.set_vsensesel(true);
298 }); 254 });
299 255
300 Temperature {} 256 super::Temperature {}
301 } 257 }
302 258
303 /// Enable reading the vbat internal channel. 259 /// Enable reading the vbat internal channel.
304 #[cfg(stm32u5)] 260 #[cfg(stm32u5)]
305 pub fn enable_vbat(&self) -> Vbat { 261 pub fn enable_vbat(&self) -> super::Vbat {
306 T::regs().ccr().modify(|w| { 262 T::regs().ccr().modify(|w| {
307 w.set_vbaten(true); 263 w.set_vbaten(true);
308 }); 264 });
309 265
310 Vbat {} 266 super::Vbat {}
311 } 267 }
312 268
313 /// Enable reading the vbat internal channel. 269 /// Enable reading the vbat internal channel.
314 pub fn enable_vcore(&self) -> Vcore { 270 pub fn enable_vcore(&self) -> super::Vcore {
315 Vcore {} 271 super::Vcore {}
316 } 272 }
317 273
318 /// Enable reading the vbat internal channel. 274 /// Enable reading the vbat internal channel.
319 #[cfg(stm32u5)] 275 #[cfg(stm32u5)]
320 pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { 276 pub fn enable_dac_channel(&self, dac: DacChannel) -> super::Dac {
321 let mux; 277 let mux;
322 match dac { 278 match dac {
323 DacChannel::OUT1 => mux = false, 279 DacChannel::OUT1 => mux = false,
324 DacChannel::OUT2 => mux = true, 280 DacChannel::OUT2 => mux = true,
325 } 281 }
326 T::regs().or().modify(|w| w.set_chn21sel(mux)); 282 T::regs().or().modify(|w| w.set_chn21sel(mux));
327 Dac {} 283 super::Dac {}
328 } 284 }
329 285
330 /// Set the ADC resolution. 286 /// Set the ADC resolution.
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..0a9f35a5b 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,5 +1,3 @@
1use core::mem;
2
3#[allow(unused)] 1#[allow(unused)]
4#[cfg(stm32h7)] 2#[cfg(stm32h7)]
5use pac::adc::vals::{Adcaldif, Difsel, Exten}; 3use pac::adc::vals::{Adcaldif, Difsel, Exten};
@@ -10,15 +8,14 @@ pub use pac::adccommon::vals::Presc;
10pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; 8pub use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
11pub use stm32_metapac::adccommon::vals::Dual; 9pub use stm32_metapac::adccommon::vals::Dual;
12 10
13use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us}; 11use super::{
12 Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime,
13 blocking_delay_us,
14};
14use crate::adc::SealedAdcChannel; 15use crate::adc::SealedAdcChannel;
15use crate::dma::Transfer;
16use crate::time::Hertz; 16use crate::time::Hertz;
17use crate::{Peri, pac, rcc}; 17use crate::{Peri, pac, rcc};
18 18
19mod ringbuffered;
20pub use ringbuffered::RingBufferedAdc;
21
22mod injected; 19mod injected;
23pub use injected::InjectedAdc; 20pub use injected::InjectedAdc;
24 21
@@ -103,6 +100,19 @@ impl Prescaler {
103 } 100 }
104} 101}
105 102
103/// ADC configuration
104#[derive(Default)]
105pub struct AdcConfig {
106 pub dual_mode: Option<Dual>,
107 pub resolution: Option<Resolution>,
108 #[cfg(stm32g4)]
109 pub oversampling_shift: Option<u8>,
110 #[cfg(stm32g4)]
111 pub oversampling_ratio: Option<u8>,
112 #[cfg(stm32g4)]
113 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
114}
115
106// Trigger source for ADC conversions¨ 116// Trigger source for ADC conversions¨
107#[derive(Copy, Clone)] 117#[derive(Copy, Clone)]
108pub struct ConversionTrigger { 118pub struct ConversionTrigger {
@@ -112,18 +122,9 @@ pub struct ConversionTrigger {
112 pub edge: Exten, 122 pub edge: Exten,
113} 123}
114 124
115// Conversion mode for regular ADC channels
116#[derive(Copy, Clone)]
117pub enum RegularConversionMode {
118 // Samples as fast as possible
119 Continuous,
120 // Sample at rate determined by external trigger
121 Triggered(ConversionTrigger),
122}
123
124impl<'d, T: Instance> Adc<'d, T> { 125impl<'d, T: Instance> Adc<'d, T> {
125 /// Create a new ADC driver. 126 /// Create a new ADC driver.
126 pub fn new(adc: Peri<'d, T>) -> Self { 127 pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self {
127 rcc::enable_and_reset::<T>(); 128 rcc::enable_and_reset::<T>();
128 129
129 let prescaler = Prescaler::from_ker_ck(T::frequency()); 130 let prescaler = Prescaler::from_ker_ck(T::frequency());
@@ -140,37 +141,19 @@ impl<'d, T: Instance> Adc<'d, T> {
140 ); 141 );
141 } 142 }
142 143
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| { 144 T::regs().cr().modify(|reg| {
158 reg.set_deeppwd(false); 145 reg.set_deeppwd(false);
159 reg.set_advregen(true); 146 reg.set_advregen(true);
160 }); 147 });
161 148
162 blocking_delay_us(20); 149 blocking_delay_us(20);
163 }
164 150
165 fn configure_differential_inputs(&mut self) {
166 T::regs().difsel().modify(|w| { 151 T::regs().difsel().modify(|w| {
167 for n in 0..18 { 152 for n in 0..18 {
168 w.set_difsel(n, Difsel::SINGLE_ENDED); 153 w.set_difsel(n, Difsel::SINGLE_ENDED);
169 } 154 }
170 }); 155 });
171 }
172 156
173 fn calibrate(&mut self) {
174 T::regs().cr().modify(|w| { 157 T::regs().cr().modify(|w| {
175 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 158 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
176 }); 159 });
@@ -190,9 +173,47 @@ impl<'d, T: Instance> Adc<'d, T> {
190 while T::regs().cr().read().adcal() {} 173 while T::regs().cr().read().adcal() {}
191 174
192 blocking_delay_us(20); 175 blocking_delay_us(20);
176
177 Self::enable();
178
179 // single conversion mode, software trigger
180 T::regs().cfgr().modify(|w| {
181 w.set_cont(false);
182 w.set_exten(Exten::DISABLED);
183 });
184
185 if let Some(dual) = config.dual_mode {
186 T::common_regs().ccr().modify(|reg| {
187 reg.set_dual(dual);
188 })
189 }
190
191 if let Some(resolution) = config.resolution {
192 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
193 }
194
195 #[cfg(stm32g4)]
196 if let Some(shift) = config.oversampling_shift {
197 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
198 }
199
200 #[cfg(stm32g4)]
201 if let Some(ratio) = config.oversampling_ratio {
202 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
203 }
204
205 #[cfg(stm32g4)]
206 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
207 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
208 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
209 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
210 }
211
212 Self { adc }
193 } 213 }
194 214
195 fn enable() { 215 /// Enable the ADC
216 pub(super) fn enable() {
196 // Make sure bits are off 217 // Make sure bits are off
197 while T::regs().cr().read().addis() { 218 while T::regs().cr().read().addis() {
198 // spin 219 // spin
@@ -213,119 +234,33 @@ impl<'d, T: Instance> Adc<'d, T> {
213 } 234 }
214 } 235 }
215 236
216 fn configure(&mut self) { 237 /// Start regular adc conversion
217 // single conversion mode, software trigger 238 pub(super) fn start() {
218 T::regs().cfgr().modify(|w| { 239 T::regs().cr().modify(|reg| {
219 w.set_cont(false); 240 reg.set_adstart(true);
220 w.set_exten(Exten::DISABLED);
221 });
222 }
223
224 /// Enable reading the voltage reference internal channel.
225 pub fn enable_vrefint(&self) -> super::VrefInt
226 where
227 T: super::VrefConverter,
228 {
229 T::common_regs().ccr().modify(|reg| {
230 reg.set_vrefen(true);
231 });
232
233 super::VrefInt {}
234 }
235
236 /// Enable reading the temperature internal channel.
237 pub fn enable_temperature(&self) -> super::Temperature
238 where
239 T: super::TemperatureConverter,
240 {
241 T::common_regs().ccr().modify(|reg| {
242 reg.set_vsenseen(true);
243 }); 241 });
244
245 super::Temperature {}
246 } 242 }
247 243
248 /// Enable reading the vbat internal channel. 244 /// Stop regular conversions and disable DMA
249 pub fn enable_vbat(&self) -> super::Vbat 245 pub(super) fn stop() {
250 where 246 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
251 T: super::VBatConverter, 247 T::regs().cr().modify(|reg| {
252 { 248 reg.set_adstp(Adstp::STOP);
253 T::common_regs().ccr().modify(|reg| { 249 });
254 reg.set_vbaten(true); 250 // The software must poll ADSTART until the bit is reset before assuming the
255 }); 251 // ADC is completely stopped
256 252 while T::regs().cr().read().adstart() {}
257 super::Vbat {} 253 }
258 }
259 254
260 /// Enable differential channel. 255 // Disable dma control and continuous conversion, if enabled
261 /// Caution: 256 T::regs().cfgr().modify(|reg| {
262 /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i] 257 reg.set_cont(false);
263 /// is connected to another channel. As a consequence, this channel is no longer usable in 258 reg.set_dmaen(Dmaen::DISABLE);
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 }); 259 });
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.
290 #[cfg(stm32g4)]
291 pub fn set_oversampling_shift(&mut self, shift: u8) {
292 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
293 }
294
295 /// Set oversampling ratio.
296 #[cfg(stm32g4)]
297 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
298 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
299 }
300
301 /// Enable oversampling in regular mode.
302 #[cfg(stm32g4)]
303 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
304 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
305 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
306 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
307 }
308
309 // Reads that are not implemented as INJECTED in "blocking_read"
310 // #[cfg(stm32g4)]
311 // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) {
312 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
313 // }
314
315 // #[cfg(stm32g4)]
316 // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) {
317 // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored),
318 // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
319 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
320 // }
321
322 /// Set the ADC resolution.
323 pub fn set_resolution(&mut self, resolution: Resolution) {
324 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
325 } 260 }
326 261
327 /// Perform a single conversion. 262 /// Perform a single conversion.
328 fn convert(&mut self) -> u16 { 263 pub(super) fn convert() -> u16 {
329 T::regs().isr().modify(|reg| { 264 T::regs().isr().modify(|reg| {
330 reg.set_eos(true); 265 reg.set_eos(true);
331 reg.set_eoc(true); 266 reg.set_eoc(true);
@@ -343,138 +278,52 @@ impl<'d, T: Instance> Adc<'d, T> {
343 T::regs().dr().read().0 as u16 278 T::regs().dr().read().0 as u16
344 } 279 }
345 280
346 /// Read an ADC pin. 281 pub(super) fn configure_dma(conversion_mode: ConversionMode) {
347 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
348 channel.setup();
349
350 self.read_channel(channel, sample_time)
351 }
352
353 /// Start regular adc conversion
354 pub(super) fn start() {
355 T::regs().cr().modify(|reg| {
356 reg.set_adstart(true);
357 });
358 }
359
360 /// Stop regular conversions
361 pub(super) fn stop() {
362 Self::stop_regular_conversions();
363 }
364
365 /// Teardown method for stopping regular ADC conversions
366 pub(super) fn teardown_dma() {
367 Self::stop_regular_conversions();
368
369 // Disable dma control
370 T::regs().cfgr().modify(|reg| {
371 reg.set_dmaen(Dmaen::DISABLE);
372 });
373 }
374
375 /// Read one or multiple ADC regular channels using DMA.
376 ///
377 /// `sequence` iterator and `readings` must have the same length.
378 ///
379 /// Example
380 /// ```rust,ignore
381 /// use embassy_stm32::adc::{Adc, AdcChannel}
382 ///
383 /// let mut adc = Adc::new(p.ADC1);
384 /// let mut adc_pin0 = p.PA0.into();
385 /// let mut adc_pin1 = p.PA1.into();
386 /// let mut measurements = [0u16; 2];
387 ///
388 /// adc.read(
389 /// p.DMA1_CH2.reborrow(),
390 /// [
391 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
392 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
393 /// ]
394 /// .into_iter(),
395 /// &mut measurements,
396 /// )
397 /// .await;
398 /// defmt::info!("measurements: {}", measurements);
399 /// ```
400 ///
401 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
402 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
403 pub async fn read(
404 &mut self,
405 rx_dma: Peri<'_, impl RxDma<T>>,
406 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
407 readings: &mut [u16],
408 ) {
409 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
410 assert!(
411 sequence.len() == readings.len(),
412 "Sequence length must be equal to readings length"
413 );
414 assert!(
415 sequence.len() <= 16,
416 "Asynchronous read sequence cannot be more than 16 in length"
417 );
418
419 // Ensure no conversions are ongoing and ADC is enabled.
420 Self::stop_regular_conversions();
421 Self::enable();
422
423 Self::configure_sequence(sequence.map(|(channel, sample_time)| {
424 channel.setup();
425
426 (channel.channel, sample_time)
427 }));
428
429 // Set continuous mode with oneshot dma.
430 // Clear overrun flag before starting transfer.
431 T::regs().isr().modify(|reg| { 282 T::regs().isr().modify(|reg| {
432 reg.set_ovr(true); 283 reg.set_ovr(true);
433 }); 284 });
434 285
435 T::regs().cfgr().modify(|reg| { 286 T::regs().cfgr().modify(|reg| {
436 reg.set_discen(false); 287 reg.set_discen(false); // Convert all channels for each trigger
437 reg.set_cont(true); 288 reg.set_dmacfg(match conversion_mode {
438 reg.set_dmacfg(Dmacfg::ONE_SHOT); 289 ConversionMode::Singular => Dmacfg::ONE_SHOT,
290 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
291 });
439 reg.set_dmaen(Dmaen::ENABLE); 292 reg.set_dmaen(Dmaen::ENABLE);
440 }); 293 });
441 294
442 let request = rx_dma.request(); 295 if let ConversionMode::Repeated(mode) = conversion_mode {
443 let transfer = unsafe { 296 match mode {
444 Transfer::new_read( 297 RegularConversionMode::Continuous => {
445 rx_dma, 298 T::regs().cfgr().modify(|reg| {
446 request, 299 reg.set_cont(true);
447 T::regs().dr().as_ptr() as *mut u16, 300 });
448 readings, 301 }
449 Default::default(), 302 RegularConversionMode::Triggered(trigger) => {
450 ) 303 T::regs().cfgr().modify(|r| {
451 }; 304 r.set_cont(false); // New trigger is neede for each sample to be read
452 305 });
453 // Start conversion
454 T::regs().cr().modify(|reg| {
455 reg.set_adstart(true);
456 });
457
458 // Wait for conversion sequence to finish.
459 transfer.await;
460 306
461 // Ensure conversions are finished. 307 T::regs().cfgr().modify(|r| {
462 Self::stop_regular_conversions(); 308 r.set_extsel(trigger.channel);
309 r.set_exten(trigger.edge);
310 });
463 311
464 // Reset configuration. 312 // Regular conversions uses DMA so no need to generate interrupt
465 T::regs().cfgr().modify(|reg| { 313 T::regs().ier().modify(|r| r.set_eosie(false));
466 reg.set_cont(false); 314 }
467 }); 315 }
316 }
468 } 317 }
469 318
470 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) { 319 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
471 // Set sequence length 320 // Set sequence length
472 T::regs().sqr1().modify(|w| { 321 T::regs().sqr1().modify(|w| {
473 w.set_l(sequence.len() as u8 - 1); 322 w.set_l(sequence.len() as u8 - 1);
474 }); 323 });
475 324
476 // Configure channels and ranks 325 // Configure channels and ranks
477 for (_i, (ch, sample_time)) in sequence.enumerate() { 326 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() {
478 let sample_time = sample_time.into(); 327 let sample_time = sample_time.into();
479 if ch <= 9 { 328 if ch <= 9 {
480 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); 329 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time));
@@ -505,101 +354,75 @@ impl<'d, T: Instance> Adc<'d, T> {
505 } 354 }
506 _ => unreachable!(), 355 _ => unreachable!(),
507 } 356 }
357
358 #[cfg(stm32g4)]
359 {
360 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
361
362 T::regs().difsel().modify(|w| {
363 w.set_difsel(
364 ch.into(),
365 if is_differential {
366 Difsel::DIFFERENTIAL
367 } else {
368 Difsel::SINGLE_ENDED
369 },
370 );
371 });
372
373 T::regs().cr().modify(|w| w.set_aden(true)); // enable adc
374 }
508 } 375 }
509 } 376 }
510 377
511 /// Set external trigger for regular conversion sequence 378 /// Enable reading the voltage reference internal channel.
512 fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) { 379 pub fn enable_vrefint(&self) -> super::VrefInt
513 T::regs().cfgr().modify(|r| { 380 where
514 r.set_extsel(trigger.channel); 381 T: super::SpecialConverter<super::VrefInt>,
515 r.set_exten(trigger.edge); 382 {
383 T::common_regs().ccr().modify(|reg| {
384 reg.set_vrefen(true);
516 }); 385 });
517 // Regular conversions uses DMA so no need to generate interrupt
518 T::regs().ier().modify(|r| r.set_eosie(false));
519 }
520 386
521 // Dual ADC mode selection 387 super::VrefInt {}
522 pub fn configure_dual_mode(&mut self, val: Dual) {
523 T::common_regs().ccr().modify(|reg| {
524 reg.set_dual(val);
525 })
526 } 388 }
527 389
528 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. 390 /// Enable reading the temperature internal channel.
529 /// 391 pub fn enable_temperature(&self) -> super::Temperature
530 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer 392 where
531 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended 393 T: super::SpecialConverter<super::Temperature>,
532 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half 394 {
533 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively 395 T::common_regs().ccr().modify(|reg| {
534 /// defines the period at which the buffer should be read. 396 reg.set_vsenseen(true);
535 ///
536 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
537 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
538 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
539 /// the buffer length should be `3 * 40 = 120`.
540 ///
541 /// # Parameters
542 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
543 /// - `dma_buf`: The buffer where DMA stores ADC samples.
544 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
545 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
546 ///
547 /// # Returns
548 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
549 pub fn into_ring_buffered<'a>(
550 mut self,
551 dma: Peri<'a, impl RxDma<T>>,
552 dma_buf: &'a mut [u16],
553 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
554 mode: RegularConversionMode,
555 ) -> RingBufferedAdc<'a, T> {
556 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
557 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
558 assert!(
559 sequence.len() <= 16,
560 "Asynchronous read sequence cannot be more than 16 in length"
561 );
562 // reset conversions and enable the adc
563 Self::stop_regular_conversions();
564 Self::enable();
565
566 //adc side setup
567
568 Self::configure_sequence(sequence.map(|(mut channel, sample_time)| {
569 channel.setup();
570
571 (channel.channel, sample_time)
572 }));
573
574 // Clear overrun flag before starting transfer.
575 T::regs().isr().modify(|reg| {
576 reg.set_ovr(true);
577 }); 397 });
578 398
579 T::regs().cfgr().modify(|reg| { 399 super::Temperature {}
580 reg.set_discen(false); // Convert all channels for each trigger 400 }
581 reg.set_dmacfg(Dmacfg::CIRCULAR); 401
582 reg.set_dmaen(Dmaen::ENABLE); 402 /// Enable reading the vbat internal channel.
403 pub fn enable_vbat(&self) -> super::Vbat
404 where
405 T: super::SpecialConverter<super::Vbat>,
406 {
407 T::common_regs().ccr().modify(|reg| {
408 reg.set_vbaten(true);
583 }); 409 });
584 410
585 match mode { 411 super::Vbat {}
586 RegularConversionMode::Continuous => { 412 }
587 T::regs().cfgr().modify(|reg| {
588 reg.set_cont(true);
589 });
590 }
591 RegularConversionMode::Triggered(trigger) => {
592 T::regs().cfgr().modify(|r| {
593 r.set_cont(false); // New trigger is neede for each sample to be read
594 });
595 self.set_regular_conversion_trigger(trigger);
596 }
597 }
598 413
599 mem::forget(self); 414 // Reads that are not implemented as INJECTED in "blocking_read"
415 // #[cfg(stm32g4)]
416 // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) {
417 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
418 // }
600 419
601 RingBufferedAdc::new(dma, dma_buf) 420 // #[cfg(stm32g4)]
602 } 421 // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) {
422 // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored),
423 // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
424 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
425 // }
603 426
604 /// Configures the ADC for injected conversions. 427 /// Configures the ADC for injected conversions.
605 /// 428 ///
@@ -629,7 +452,7 @@ impl<'d, T: Instance> Adc<'d, T> {
629 /// - Accessing samples beyond `N` will result in a panic; use the returned type 452 /// - Accessing samples beyond `N` will result in a panic; use the returned type
630 /// `InjectedAdc<T, N>` to enforce bounds at compile time. 453 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
631 pub fn setup_injected_conversions<'a, const N: usize>( 454 pub fn setup_injected_conversions<'a, const N: usize>(
632 mut self, 455 self,
633 sequence: [(AnyAdcChannel<T>, SampleTime); N], 456 sequence: [(AnyAdcChannel<T>, SampleTime); N],
634 trigger: ConversionTrigger, 457 trigger: ConversionTrigger,
635 interrupt: bool, 458 interrupt: bool,
@@ -641,13 +464,22 @@ impl<'d, T: Instance> Adc<'d, T> {
641 NR_INJECTED_RANKS 464 NR_INJECTED_RANKS
642 ); 465 );
643 466
644 Self::stop_regular_conversions(); 467 Self::stop();
645 Self::enable(); 468 Self::enable();
646 469
647 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); 470 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
648 471
649 for (n, (mut channel, sample_time)) in sequence.into_iter().enumerate() { 472 for (n, (channel, sample_time)) in sequence.into_iter().enumerate() {
650 Self::configure_channel(&mut channel, sample_time); 473 let sample_time = sample_time.into();
474 if channel.channel() <= 9 {
475 T::regs()
476 .smpr()
477 .modify(|reg| reg.set_smp(channel.channel() as _, sample_time));
478 } else {
479 T::regs()
480 .smpr2()
481 .modify(|reg| reg.set_smp((channel.channel() - 10) as _, sample_time));
482 }
651 483
652 let idx = match n { 484 let idx = match n {
653 0..=3 => n, 485 0..=3 => n,
@@ -662,8 +494,16 @@ impl<'d, T: Instance> Adc<'d, T> {
662 494
663 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false)); 495 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
664 496
665 self.set_injected_conversion_trigger(trigger); 497 // Set external trigger for injected conversion sequence
666 self.enable_injected_eos_interrupt(interrupt); 498 // Possible trigger values are seen in Table 167 in RM0440 Rev 9
499 T::regs().jsqr().modify(|r| {
500 r.set_jextsel(trigger.channel);
501 r.set_jexten(trigger.edge);
502 });
503
504 // Enable end of injected sequence interrupt
505 T::regs().ier().modify(|r| r.set_jeosie(interrupt));
506
667 Self::start_injected_conversions(); 507 Self::start_injected_conversions();
668 508
669 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels 509 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
@@ -701,7 +541,7 @@ impl<'d, T: Instance> Adc<'d, T> {
701 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N], 541 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N],
702 injected_trigger: ConversionTrigger, 542 injected_trigger: ConversionTrigger,
703 injected_interrupt: bool, 543 injected_interrupt: bool,
704 ) -> (RingBufferedAdc<'a, T>, InjectedAdc<T, N>) { 544 ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<T, N>) {
705 unsafe { 545 unsafe {
706 ( 546 (
707 Self { 547 Self {
@@ -734,64 +574,6 @@ impl<'d, T: Instance> Adc<'d, T> {
734 reg.set_jadstart(true); 574 reg.set_jadstart(true);
735 }); 575 });
736 } 576 }
737
738 /// Set external trigger for injected conversion sequence
739 /// Possible trigger values are seen in Table 167 in RM0440 Rev 9
740 fn set_injected_conversion_trigger(&mut self, trigger: ConversionTrigger) {
741 T::regs().jsqr().modify(|r| {
742 r.set_jextsel(trigger.channel);
743 r.set_jexten(trigger.edge);
744 });
745 }
746
747 /// Enable end of injected sequence interrupt
748 fn enable_injected_eos_interrupt(&mut self, enable: bool) {
749 T::regs().ier().modify(|r| r.set_jeosie(enable));
750 }
751
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
785 fn stop_regular_conversions() {
786 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
787 T::regs().cr().modify(|reg| {
788 reg.set_adstp(Adstp::STOP);
789 });
790 // The software must poll ADSTART until the bit is reset before assuming the
791 // ADC is completely stopped
792 while T::regs().cr().read().adstart() {}
793 }
794 }
795} 577}
796 578
797impl<T: Instance, const N: usize> InjectedAdc<T, N> { 579impl<T: Instance, const N: usize> InjectedAdc<T, N> {
@@ -811,47 +593,47 @@ impl<T: Instance, const N: usize> InjectedAdc<T, N> {
811 593
812#[cfg(stm32g4)] 594#[cfg(stm32g4)]
813mod g4 { 595mod g4 {
814 use crate::adc::{TemperatureConverter, VBatConverter, VrefConverter}; 596 use crate::adc::{SealedSpecialConverter, Temperature, Vbat, VrefInt};
815 597
816 impl TemperatureConverter for crate::peripherals::ADC1 { 598 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC1 {
817 const CHANNEL: u8 = 16; 599 const CHANNEL: u8 = 16;
818 } 600 }
819 601
820 impl VrefConverter for crate::peripherals::ADC1 { 602 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC1 {
821 const CHANNEL: u8 = 18; 603 const CHANNEL: u8 = 18;
822 } 604 }
823 605
824 impl VBatConverter for crate::peripherals::ADC1 { 606 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC1 {
825 const CHANNEL: u8 = 17; 607 const CHANNEL: u8 = 17;
826 } 608 }
827 609
828 #[cfg(peri_adc3_common)] 610 #[cfg(peri_adc3_common)]
829 impl VrefConverter for crate::peripherals::ADC3 { 611 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC3 {
830 const CHANNEL: u8 = 18; 612 const CHANNEL: u8 = 18;
831 } 613 }
832 614
833 #[cfg(peri_adc3_common)] 615 #[cfg(peri_adc3_common)]
834 impl VBatConverter for crate::peripherals::ADC3 { 616 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC3 {
835 const CHANNEL: u8 = 17; 617 const CHANNEL: u8 = 17;
836 } 618 }
837 619
838 #[cfg(not(stm32g4x1))] 620 #[cfg(not(stm32g4x1))]
839 impl VrefConverter for crate::peripherals::ADC4 { 621 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC4 {
840 const CHANNEL: u8 = 18; 622 const CHANNEL: u8 = 18;
841 } 623 }
842 624
843 #[cfg(not(stm32g4x1))] 625 #[cfg(not(stm32g4x1))]
844 impl TemperatureConverter for crate::peripherals::ADC5 { 626 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC5 {
845 const CHANNEL: u8 = 4; 627 const CHANNEL: u8 = 4;
846 } 628 }
847 629
848 #[cfg(not(stm32g4x1))] 630 #[cfg(not(stm32g4x1))]
849 impl VrefConverter for crate::peripherals::ADC5 { 631 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC5 {
850 const CHANNEL: u8 = 18; 632 const CHANNEL: u8 = 18;
851 } 633 }
852 634
853 #[cfg(not(stm32g4x1))] 635 #[cfg(not(stm32g4x1))]
854 impl VBatConverter for crate::peripherals::ADC5 { 636 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC5 {
855 const CHANNEL: u8 = 17; 637 const CHANNEL: u8 = 17;
856 } 638 }
857} 639}
@@ -859,13 +641,13 @@ mod g4 {
859// TODO this should look at each ADC individually and impl the correct channels 641// TODO this should look at each ADC individually and impl the correct channels
860#[cfg(stm32h7)] 642#[cfg(stm32h7)]
861mod h7 { 643mod h7 {
862 impl<T: Instance> TemperatureConverter for T { 644 impl<T: Instance> SealedSpecialConverter<Temperature> for T {
863 const CHANNEL: u8 = 18; 645 const CHANNEL: u8 = 18;
864 } 646 }
865 impl<T: Instance> VrefConverter for T { 647 impl<T: Instance> SealedSpecialConverter<VrefInt> for T {
866 const CHANNEL: u8 = 19; 648 const CHANNEL: u8 = 19;
867 } 649 }
868 impl<T: Instance> VBatConverter for T { 650 impl<T: Instance> SealedSpecialConverter<Vbat> for T {
869 // TODO this should be 14 for H7a/b/35 651 // TODO this should be 14 for H7a/b/35
870 const CHANNEL: u8 = 17; 652 const CHANNEL: u8 = 17;
871 } 653 }
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs
index f9f1bba2a..7bb3a541c 100644
--- a/embassy-stm32/src/adc/injected.rs
+++ b/embassy-stm32/src/adc/injected.rs
@@ -38,7 +38,7 @@ impl<T: Instance, const N: usize> InjectedAdc<T, N> {
38 38
39impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> { 39impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> {
40 fn drop(&mut self) { 40 fn drop(&mut self) {
41 Adc::<T>::teardown_dma(); 41 Adc::<T>::stop();
42 compiler_fence(Ordering::SeqCst); 42 compiler_fence(Ordering::SeqCst);
43 } 43 }
44} 44}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 3bf893a35..bf404d6ef 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -17,6 +17,9 @@
17#[cfg_attr(adc_c0, path = "c0.rs")] 17#[cfg_attr(adc_c0, path = "c0.rs")]
18mod _version; 18mod _version;
19 19
20#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
21mod ringbuffered;
22
20use core::marker::PhantomData; 23use core::marker::PhantomData;
21 24
22#[allow(unused)] 25#[allow(unused)]
@@ -25,6 +28,8 @@ pub use _version::*;
25use embassy_hal_internal::{PeripheralType, impl_peripheral}; 28use embassy_hal_internal::{PeripheralType, impl_peripheral};
26#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] 29#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))]
27use embassy_sync::waitqueue::AtomicWaker; 30use embassy_sync::waitqueue::AtomicWaker;
31#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
32pub use ringbuffered::RingBufferedAdc;
28 33
29#[cfg(any(adc_u5, adc_wba))] 34#[cfg(any(adc_u5, adc_wba))]
30#[path = "adc4.rs"] 35#[path = "adc4.rs"]
@@ -80,6 +85,11 @@ pub(crate) trait SealedAdcChannel<T> {
80 85
81 #[allow(unused)] 86 #[allow(unused)]
82 fn channel(&self) -> u8; 87 fn channel(&self) -> u8;
88
89 #[allow(unused)]
90 fn is_differential(&self) -> bool {
91 false
92 }
83} 93}
84 94
85/// Performs a busy-wait delay for a specified number of microseconds. 95/// Performs a busy-wait delay for a specified number of microseconds.
@@ -100,29 +110,188 @@ pub(crate) fn blocking_delay_us(us: u32) {
100 } 110 }
101} 111}
102 112
103/// Implemented for ADCs that have a Temperature channel 113#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
104pub trait TemperatureConverter { 114pub(self) enum ConversionMode {
105 const CHANNEL: u8; 115 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
116 Singular,
117 #[allow(dead_code)]
118 Repeated(RegularConversionMode),
106} 119}
107/// Implemented for ADCs that have a Vref channel 120
108pub trait VrefConverter { 121#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
109 const CHANNEL: u8; 122// Conversion mode for regular ADC channels
123#[derive(Copy, Clone)]
124pub enum RegularConversionMode {
125 // Samples as fast as possible
126 Continuous,
127 #[cfg(adc_g4)]
128 // Sample at rate determined by external trigger
129 Triggered(ConversionTrigger),
110} 130}
111/// Implemented for ADCs that have a VBat channel 131
112pub trait VBatConverter { 132impl<'d, T: Instance> Adc<'d, T> {
133 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4))]
134 /// Read an ADC pin.
135 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
136 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
137 channel.setup();
138
139 #[cfg(not(adc_v4))]
140 Self::enable();
141 Self::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
142
143 Self::convert()
144 }
145
146 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
147 /// Read one or multiple ADC regular channels using DMA.
148 ///
149 /// `sequence` iterator and `readings` must have the same length.
150 ///
151 /// Example
152 /// ```rust,ignore
153 /// use embassy_stm32::adc::{Adc, AdcChannel}
154 ///
155 /// let mut adc = Adc::new(p.ADC1);
156 /// let mut adc_pin0 = p.PA0.into();
157 /// let mut adc_pin1 = p.PA1.into();
158 /// let mut measurements = [0u16; 2];
159 ///
160 /// adc.read(
161 /// p.DMA1_CH2.reborrow(),
162 /// [
163 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
164 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
165 /// ]
166 /// .into_iter(),
167 /// &mut measurements,
168 /// )
169 /// .await;
170 /// defmt::info!("measurements: {}", measurements);
171 /// ```
172 ///
173 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
174 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
175 pub async fn read(
176 &mut self,
177 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
178 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
179 readings: &mut [u16],
180 ) {
181 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
182 assert!(
183 sequence.len() == readings.len(),
184 "Sequence length must be equal to readings length"
185 );
186 assert!(
187 sequence.len() <= 16,
188 "Asynchronous read sequence cannot be more than 16 in length"
189 );
190
191 // Ensure no conversions are ongoing and ADC is enabled.
192 Self::stop();
193 Self::enable();
194
195 Self::configure_sequence(
196 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
197 );
198
199 Self::configure_dma(ConversionMode::Singular);
200
201 let request = rx_dma.request();
202 let transfer = unsafe {
203 crate::dma::Transfer::new_read(
204 rx_dma,
205 request,
206 T::regs().dr().as_ptr() as *mut u16,
207 readings,
208 Default::default(),
209 )
210 };
211
212 Self::start();
213
214 // Wait for conversion sequence to finish.
215 transfer.await;
216
217 // Ensure conversions are finished.
218 Self::stop();
219 }
220
221 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
222 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
223 ///
224 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
225 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
226 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
227 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
228 /// defines the period at which the buffer should be read.
229 ///
230 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
231 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
232 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
233 /// the buffer length should be `3 * 40 = 120`.
234 ///
235 /// # Parameters
236 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
237 /// - `dma_buf`: The buffer where DMA stores ADC samples.
238 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
239 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
240 ///
241 /// # Returns
242 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
243 pub fn into_ring_buffered<'a>(
244 self,
245 dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>,
246 dma_buf: &'a mut [u16],
247 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
248 mode: RegularConversionMode,
249 ) -> RingBufferedAdc<'a, T> {
250 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
251 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
252 assert!(
253 sequence.len() <= 16,
254 "Asynchronous read sequence cannot be more than 16 in length"
255 );
256 // reset conversions and enable the adc
257 Self::stop();
258 Self::enable();
259
260 //adc side setup
261 Self::configure_sequence(
262 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
263 );
264
265 Self::configure_dma(ConversionMode::Repeated(mode));
266
267 core::mem::forget(self);
268
269 RingBufferedAdc::new(dma, dma_buf)
270 }
271}
272
273pub(self) trait SpecialChannel {}
274
275/// Implemented for ADCs that have a special channel
276trait SealedSpecialConverter<T: SpecialChannel + Sized> {
113 const CHANNEL: u8; 277 const CHANNEL: u8;
114} 278}
115 279
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 280#[allow(private_bounds)]
117/// Internal voltage reference channel. 281pub trait SpecialConverter<T: SpecialChannel + Sized>: SealedSpecialConverter<T> {}
118pub struct VrefInt; 282
119impl<T: Instance + VrefConverter> AdcChannel<T> for VrefInt {} 283impl<C: SpecialChannel + Sized, T: SealedSpecialConverter<C>> SpecialConverter<C> for T {}
120impl<T: Instance + VrefConverter> SealedAdcChannel<T> for VrefInt { 284
285impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> AdcChannel<T> for C {}
286impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> SealedAdcChannel<T> for C {
121 fn channel(&self) -> u8 { 287 fn channel(&self) -> u8 {
122 T::CHANNEL 288 T::CHANNEL
123 } 289 }
124} 290}
125 291
292pub struct VrefInt;
293impl SpecialChannel for VrefInt {}
294
126impl VrefInt { 295impl VrefInt {
127 #[cfg(any(adc_f3v1, adc_f3v2))] 296 #[cfg(any(adc_f3v1, adc_f3v2))]
128 /// The value that vref would be if vdda was at 3300mv 297 /// The value that vref would be if vdda was at 3300mv
@@ -133,21 +302,19 @@ impl VrefInt {
133 302
134/// Internal temperature channel. 303/// Internal temperature channel.
135pub struct Temperature; 304pub struct Temperature;
136impl<T: Instance + TemperatureConverter> AdcChannel<T> for Temperature {} 305impl SpecialChannel for Temperature {}
137impl<T: Instance + TemperatureConverter> SealedAdcChannel<T> for Temperature {
138 fn channel(&self) -> u8 {
139 T::CHANNEL
140 }
141}
142 306
143/// Internal battery voltage channel. 307/// Internal battery voltage channel.
144pub struct Vbat; 308pub struct Vbat;
145impl<T: Instance + VBatConverter> AdcChannel<T> for Vbat {} 309impl SpecialChannel for Vbat {}
146impl<T: Instance + VBatConverter> SealedAdcChannel<T> for Vbat { 310
147 fn channel(&self) -> u8 { 311/// Vcore channel.
148 T::CHANNEL 312pub struct Vcore;
149 } 313impl SpecialChannel for Vcore {}
150} 314
315/// Internal dac channel.
316pub struct Dac;
317impl SpecialChannel for Dac {}
151 318
152/// ADC instance. 319/// ADC instance.
153#[cfg(not(any( 320#[cfg(not(any(
@@ -178,6 +345,7 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
178 345
179 AnyAdcChannel { 346 AnyAdcChannel {
180 channel: self.channel(), 347 channel: self.channel(),
348 is_differential: self.is_differential(),
181 _phantom: PhantomData, 349 _phantom: PhantomData,
182 } 350 }
183 } 351 }
@@ -189,6 +357,7 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
189/// storing them in an array. 357/// storing them in an array.
190pub struct AnyAdcChannel<T> { 358pub struct AnyAdcChannel<T> {
191 channel: u8, 359 channel: u8,
360 is_differential: bool,
192 _phantom: PhantomData<T>, 361 _phantom: PhantomData<T>,
193} 362}
194impl_peripheral!(AnyAdcChannel<T: Instance>); 363impl_peripheral!(AnyAdcChannel<T: Instance>);
@@ -197,6 +366,10 @@ impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> {
197 fn channel(&self) -> u8 { 366 fn channel(&self) -> u8 {
198 self.channel 367 self.channel
199 } 368 }
369
370 fn is_differential(&self) -> bool {
371 self.is_differential
372 }
200} 373}
201 374
202impl<T> AnyAdcChannel<T> { 375impl<T> AnyAdcChannel<T> {
@@ -315,6 +488,39 @@ macro_rules! impl_adc_pin {
315 }; 488 };
316} 489}
317 490
491#[allow(unused_macros)]
492macro_rules! impl_adc_pair {
493 ($inst:ident, $pin:ident, $npin:ident, $ch:expr) => {
494 impl crate::adc::AdcChannel<peripherals::$inst>
495 for (
496 crate::Peri<'_, crate::peripherals::$pin>,
497 crate::Peri<'_, crate::peripherals::$npin>,
498 )
499 {
500 }
501 impl crate::adc::SealedAdcChannel<peripherals::$inst>
502 for (
503 crate::Peri<'_, crate::peripherals::$pin>,
504 crate::Peri<'_, crate::peripherals::$npin>,
505 )
506 {
507 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
508 fn setup(&mut self) {
509 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0);
510 <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1);
511 }
512
513 fn channel(&self) -> u8 {
514 $ch
515 }
516
517 fn is_differential(&self) -> bool {
518 true
519 }
520 }
521 };
522}
523
318/// Get the maximum reading value for this resolution. 524/// Get the maximum reading value for this resolution.
319/// 525///
320/// This is `2**n - 1`. 526/// This is `2**n - 1`.
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs
index 024c6acdc..62ea0d3a2 100644
--- a/embassy-stm32/src/adc/ringbuffered.rs
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -172,7 +172,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
172 172
173impl<T: Instance> Drop for RingBufferedAdc<'_, T> { 173impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
174 fn drop(&mut self) { 174 fn drop(&mut self) {
175 Adc::<T>::teardown_dma(); 175 Adc::<T>::stop();
176 176
177 compiler_fence(Ordering::SeqCst); 177 compiler_fence(Ordering::SeqCst);
178 178
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..2f9fabafb 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,15 +1,11 @@
1use core::mem;
2use core::sync::atomic::{Ordering, compiler_fence}; 1use core::sync::atomic::{Ordering, compiler_fence};
3 2
4use super::{Temperature, Vbat, VrefInt, blocking_delay_us}; 3use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us};
5use crate::adc::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel}; 4use crate::adc::{Adc, Instance, Resolution, SampleTime};
6use crate::pac::adc::vals; 5use crate::pac::adc::vals;
7use crate::time::Hertz; 6use crate::time::Hertz;
8use crate::{Peri, rcc}; 7use crate::{Peri, rcc};
9 8
10mod ringbuffered;
11pub use ringbuffered::RingBufferedAdc;
12
13fn clear_interrupt_flags(r: crate::pac::adc::Adc) { 9fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
14 r.sr().modify(|regs| { 10 r.sr().modify(|regs| {
15 regs.set_eoc(false); 11 regs.set_eoc(false);
@@ -22,21 +18,21 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
22/// VREF voltage used for factory calibration of VREFINTCAL register. 18/// VREF voltage used for factory calibration of VREFINTCAL register.
23pub const VREF_CALIB_MV: u32 = 3300; 19pub const VREF_CALIB_MV: u32 = 3300;
24 20
25impl super::VrefConverter for crate::peripherals::ADC1 { 21impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
26 const CHANNEL: u8 = 17; 22 const CHANNEL: u8 = 17;
27} 23}
28 24
29#[cfg(any(stm32f2, stm32f40x, stm32f41x))] 25#[cfg(any(stm32f2, stm32f40x, stm32f41x))]
30impl super::TemperatureConverter for crate::peripherals::ADC1 { 26impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
31 const CHANNEL: u8 = 16; 27 const CHANNEL: u8 = 16;
32} 28}
33 29
34#[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))] 30#[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))]
35impl super::TemperatureConverter for crate::peripherals::ADC1 { 31impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
36 const CHANNEL: u8 = 18; 32 const CHANNEL: u8 = 18;
37} 33}
38 34
39impl super::VBatConverter for crate::peripherals::ADC1 { 35impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC1 {
40 const CHANNEL: u8 = 18; 36 const CHANNEL: u8 = 18;
41} 37}
42 38
@@ -89,11 +85,21 @@ impl Prescaler {
89 } 85 }
90} 86}
91 87
88/// ADC configuration
89#[derive(Default)]
90pub struct AdcConfig {
91 resolution: Option<Resolution>,
92}
93
92impl<'d, T> Adc<'d, T> 94impl<'d, T> Adc<'d, T>
93where 95where
94 T: Instance, 96 T: Instance,
95{ 97{
96 pub fn new(adc: Peri<'d, T>) -> Self { 98 pub fn new(adc: Peri<'d, T>) -> Self {
99 Self::new_with_config(adc, Default::default())
100 }
101
102 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
97 rcc::enable_and_reset::<T>(); 103 rcc::enable_and_reset::<T>();
98 104
99 let presc = Prescaler::from_pclk2(T::frequency()); 105 let presc = Prescaler::from_pclk2(T::frequency());
@@ -104,84 +110,14 @@ where
104 110
105 blocking_delay_us(3); 111 blocking_delay_us(3);
106 112
107 Self { adc } 113 if let Some(resolution) = config.resolution {
108 } 114 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
109 115 }
110 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
111 ///
112 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
113 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
114 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
115 ///
116 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
117 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
118 ///
119 /// [`read`]: #method.read
120 pub fn into_ring_buffered<'a>(
121 self,
122 dma: Peri<'d, impl RxDma<T>>,
123 dma_buf: &'d mut [u16],
124 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
125 ) -> RingBufferedAdc<'d, T> {
126 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
127
128 Self::configure_sequence(sequence.map(|(mut channel, sample_time)| {
129 channel.setup();
130
131 (channel.channel, sample_time)
132 }));
133 compiler_fence(Ordering::SeqCst);
134
135 Self::setup_dma();
136
137 // Don't disable the clock
138 mem::forget(self);
139
140 RingBufferedAdc::new(dma, dma_buf)
141 }
142
143 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
144 channel.setup();
145
146 // Configure ADC
147 let channel = channel.channel();
148
149 Self::configure_sequence([(channel, sample_time)].into_iter());
150 Self::blocking_convert()
151 }
152
153 /// Enables internal voltage reference and returns [VrefInt], which can be used in
154 /// [Adc::read_internal()] to perform conversion.
155 pub fn enable_vrefint(&self) -> VrefInt {
156 T::common_regs().ccr().modify(|reg| {
157 reg.set_tsvrefe(true);
158 });
159
160 VrefInt {}
161 }
162
163 /// Enables internal temperature sensor and returns [Temperature], which can be used in
164 /// [Adc::read_internal()] to perform conversion.
165 ///
166 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
167 /// temperature sensor will return vbat value.
168 pub fn enable_temperature(&self) -> Temperature {
169 T::common_regs().ccr().modify(|reg| {
170 reg.set_tsvrefe(true);
171 });
172 116
173 Temperature {} 117 Self { adc }
174 } 118 }
175 119
176 /// Enables vbat input and returns [Vbat], which can be used in 120 pub(super) fn enable() {}
177 /// [Adc::read_internal()] to perform conversion.
178 pub fn enable_vbat(&self) -> Vbat {
179 T::common_regs().ccr().modify(|reg| {
180 reg.set_vbate(true);
181 });
182
183 Vbat {}
184 }
185 121
186 pub(super) fn start() { 122 pub(super) fn start() {
187 // Begin ADC conversions 123 // Begin ADC conversions
@@ -192,18 +128,31 @@ where
192 } 128 }
193 129
194 pub(super) fn stop() { 130 pub(super) fn stop() {
131 let r = T::regs();
132
195 // Stop ADC 133 // Stop ADC
196 T::regs().cr2().modify(|reg| { 134 r.cr2().modify(|reg| {
197 // Stop ADC 135 // Stop ADC
198 reg.set_swstart(false); 136 reg.set_swstart(false);
137 // Stop ADC
138 reg.set_adon(false);
139 // Stop DMA
140 reg.set_dma(false);
199 }); 141 });
200 }
201 142
202 pub fn set_resolution(&mut self, resolution: Resolution) { 143 r.cr1().modify(|w| {
203 T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); 144 // Disable interrupt for end of conversion
145 w.set_eocie(false);
146 // Disable interrupt for overrun
147 w.set_ovrie(false);
148 });
149
150 clear_interrupt_flags(r);
151
152 compiler_fence(Ordering::SeqCst);
204 } 153 }
205 154
206 pub(super) fn blocking_convert() -> u16 { 155 pub(super) fn convert() -> u16 {
207 // clear end of conversion flag 156 // clear end of conversion flag
208 T::regs().sr().modify(|reg| { 157 T::regs().sr().modify(|reg| {
209 reg.set_eoc(false); 158 reg.set_eoc(false);
@@ -224,7 +173,44 @@ where
224 T::regs().dr().read().0 as u16 173 T::regs().dr().read().0 as u16
225 } 174 }
226 175
227 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = (u8, SampleTime)>) { 176 pub(super) fn configure_dma(conversion_mode: ConversionMode) {
177 match conversion_mode {
178 ConversionMode::Repeated(_) => {
179 let r = T::regs();
180
181 // Clear all interrupts
182 r.sr().modify(|regs| {
183 regs.set_eoc(false);
184 regs.set_ovr(false);
185 regs.set_strt(false);
186 });
187
188 r.cr1().modify(|w| {
189 // Enable interrupt for end of conversion
190 w.set_eocie(true);
191 // Enable interrupt for overrun
192 w.set_ovrie(true);
193 // Scanning converisons of multiple channels
194 w.set_scan(true);
195 // Continuous conversion mode
196 w.set_discen(false);
197 });
198
199 r.cr2().modify(|w| {
200 // Enable DMA mode
201 w.set_dma(true);
202 // Enable continuous conversions
203 w.set_cont(true);
204 // DMA requests are issues as long as DMA=1 and data are converted.
205 w.set_dds(vals::Dds::CONTINUOUS);
206 // EOC flag is set at the end of each conversion.
207 w.set_eocs(vals::Eocs::EACH_CONVERSION);
208 });
209 }
210 }
211 }
212
213 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
228 T::regs().cr2().modify(|reg| { 214 T::regs().cr2().modify(|reg| {
229 reg.set_adon(true); 215 reg.set_adon(true);
230 }); 216 });
@@ -234,7 +220,7 @@ where
234 r.set_l((sequence.len() - 1).try_into().unwrap()); 220 r.set_l((sequence.len() - 1).try_into().unwrap());
235 }); 221 });
236 222
237 for (i, (ch, sample_time)) in sequence.enumerate() { 223 for (i, ((ch, _), sample_time)) in sequence.enumerate() {
238 // Set the channel in the right sequence field. 224 // Set the channel in the right sequence field.
239 T::regs().sqr3().modify(|w| w.set_sq(i, ch)); 225 T::regs().sqr3().modify(|w| w.set_sq(i, ch));
240 226
@@ -247,62 +233,37 @@ where
247 } 233 }
248 } 234 }
249 235
250 pub(super) fn setup_dma() { 236 /// Enables internal voltage reference and returns [VrefInt], which can be used in
251 let r = T::regs(); 237 /// [Adc::read_internal()] to perform conversion.
252 238 pub fn enable_vrefint(&self) -> VrefInt {
253 // Clear all interrupts 239 T::common_regs().ccr().modify(|reg| {
254 r.sr().modify(|regs| { 240 reg.set_tsvrefe(true);
255 regs.set_eoc(false);
256 regs.set_ovr(false);
257 regs.set_strt(false);
258 });
259
260 r.cr1().modify(|w| {
261 // Enable interrupt for end of conversion
262 w.set_eocie(true);
263 // Enable interrupt for overrun
264 w.set_ovrie(true);
265 // Scanning converisons of multiple channels
266 w.set_scan(true);
267 // Continuous conversion mode
268 w.set_discen(false);
269 }); 241 });
270 242
271 r.cr2().modify(|w| { 243 VrefInt {}
272 // Enable DMA mode
273 w.set_dma(true);
274 // Enable continuous conversions
275 w.set_cont(true);
276 // DMA requests are issues as long as DMA=1 and data are converted.
277 w.set_dds(vals::Dds::CONTINUOUS);
278 // EOC flag is set at the end of each conversion.
279 w.set_eocs(vals::Eocs::EACH_CONVERSION);
280 });
281 } 244 }
282 245
283 pub(super) fn teardown_dma() { 246 /// Enables internal temperature sensor and returns [Temperature], which can be used in
284 let r = T::regs(); 247 /// [Adc::read_internal()] to perform conversion.
285 248 ///
286 // Stop ADC 249 /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
287 r.cr2().modify(|reg| { 250 /// temperature sensor will return vbat value.
288 // Stop ADC 251 pub fn enable_temperature(&self) -> Temperature {
289 reg.set_swstart(false); 252 T::common_regs().ccr().modify(|reg| {
290 // Stop ADC 253 reg.set_tsvrefe(true);
291 reg.set_adon(false);
292 // Stop DMA
293 reg.set_dma(false);
294 }); 254 });
295 255
296 r.cr1().modify(|w| { 256 Temperature {}
297 // Disable interrupt for end of conversion 257 }
298 w.set_eocie(false);
299 // Disable interrupt for overrun
300 w.set_ovrie(false);
301 });
302 258
303 clear_interrupt_flags(r); 259 /// Enables vbat input and returns [Vbat], which can be used in
260 /// [Adc::read_internal()] to perform conversion.
261 pub fn enable_vbat(&self) -> Vbat {
262 T::common_regs().ccr().modify(|reg| {
263 reg.set_vbate(true);
264 });
304 265
305 compiler_fence(Ordering::SeqCst); 266 Vbat {}
306 } 267 }
307} 268}
308 269
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index e816907d1..62b5043ee 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,9 +1,9 @@
1use cfg_if::cfg_if; 1use cfg_if::cfg_if;
2#[cfg(adc_g0)] 2#[cfg(adc_g0)]
3use heapless::Vec; 3use heapless::Vec;
4use pac::adc::vals::Dmacfg;
5#[cfg(adc_g0)] 4#[cfg(adc_g0)]
6use pac::adc::vals::{Ckmode, Smpsel}; 5use pac::adc::vals::Ckmode;
6use pac::adc::vals::Dmacfg;
7#[cfg(adc_v3)] 7#[cfg(adc_v3)]
8use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; 8use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs};
9#[cfg(adc_g0)] 9#[cfg(adc_g0)]
@@ -11,18 +11,8 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc};
11 11
12#[allow(unused_imports)] 12#[allow(unused_imports)]
13use super::SealedAdcChannel; 13use super::SealedAdcChannel;
14use super::{ 14use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
15 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, Temperature, Vbat, VrefInt, 15use crate::adc::ConversionMode;
16 blocking_delay_us,
17};
18
19#[cfg(any(adc_v3, adc_g0, adc_u0))]
20mod ringbuffered;
21
22#[cfg(any(adc_v3, adc_g0, adc_u0))]
23use ringbuffered::RingBufferedAdc;
24
25use crate::dma::Transfer;
26use crate::{Peri, pac, rcc}; 16use crate::{Peri, pac, rcc};
27 17
28/// Default VREF voltage used for sample conversion to millivolts. 18/// Default VREF voltage used for sample conversion to millivolts.
@@ -36,60 +26,60 @@ pub const VREF_CALIB_MV: u32 = 3000;
36const SAMPLE_TIMES_CAPACITY: usize = 2; 26const SAMPLE_TIMES_CAPACITY: usize = 2;
37 27
38#[cfg(adc_g0)] 28#[cfg(adc_g0)]
39impl<T: Instance> super::VrefConverter for T { 29impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
40 const CHANNEL: u8 = 13; 30 const CHANNEL: u8 = 13;
41} 31}
42#[cfg(any(adc_h5, adc_h7rs))] 32#[cfg(any(adc_h5, adc_h7rs))]
43impl<T: Instance> super::VrefConverter for T { 33impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
44 const CHANNEL: u8 = 17; 34 const CHANNEL: u8 = 17;
45} 35}
46#[cfg(adc_u0)] 36#[cfg(adc_u0)]
47impl<T: Instance> super::VrefConverter for T { 37impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
48 const CHANNEL: u8 = 12; 38 const CHANNEL: u8 = 12;
49} 39}
50#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] 40#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
51impl<T: Instance> super::VrefConverter for T { 41impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
52 const CHANNEL: u8 = 0; 42 const CHANNEL: u8 = 0;
53} 43}
54 44
55#[cfg(adc_g0)] 45#[cfg(adc_g0)]
56impl<T: Instance> super::TemperatureConverter for T { 46impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
57 const CHANNEL: u8 = 12; 47 const CHANNEL: u8 = 12;
58} 48}
59#[cfg(any(adc_h5, adc_h7rs))] 49#[cfg(any(adc_h5, adc_h7rs))]
60impl<T: Instance> super::TemperatureConverter for T { 50impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
61 const CHANNEL: u8 = 16; 51 const CHANNEL: u8 = 16;
62} 52}
63#[cfg(adc_u0)] 53#[cfg(adc_u0)]
64impl<T: Instance> super::TemperatureConverter for T { 54impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
65 const CHANNEL: u8 = 11; 55 const CHANNEL: u8 = 11;
66} 56}
67#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] 57#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
68impl<T: Instance> super::TemperatureConverter for T { 58impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
69 const CHANNEL: u8 = 17; 59 const CHANNEL: u8 = 17;
70} 60}
71 61
72#[cfg(adc_g0)] 62#[cfg(adc_g0)]
73impl<T: Instance> super::VBatConverter for T { 63impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
74 const CHANNEL: u8 = 14; 64 const CHANNEL: u8 = 14;
75} 65}
76#[cfg(any(adc_h5, adc_h7rs))] 66#[cfg(any(adc_h5, adc_h7rs))]
77impl<T: Instance> super::VBatConverter for T { 67impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
78 const CHANNEL: u8 = 2; 68 const CHANNEL: u8 = 2;
79} 69}
80#[cfg(adc_u0)] 70#[cfg(adc_u0)]
81impl<T: Instance> super::VBatConverter for T { 71impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
82 const CHANNEL: u8 = 13; 72 const CHANNEL: u8 = 13;
83} 73}
84#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))] 74#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
85impl<T: Instance> super::VBatConverter for T { 75impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
86 const CHANNEL: u8 = 18; 76 const CHANNEL: u8 = 18;
87} 77}
88 78
89cfg_if! { 79cfg_if! {
90 if #[cfg(any(adc_h5, adc_h7rs))] { 80 if #[cfg(any(adc_h5, adc_h7rs))] {
91 pub struct VddCore; 81 pub struct VddCore;
92 impl<T: Instance> AdcChannel<T> for VddCore {} 82 impl<T: Instance> super::AdcChannel<T> for VddCore {}
93 impl<T: Instance> super::SealedAdcChannel<T> for VddCore { 83 impl<T: Instance> super::SealedAdcChannel<T> for VddCore {
94 fn channel(&self) -> u8 { 84 fn channel(&self) -> u8 {
95 6 85 6
@@ -101,7 +91,7 @@ cfg_if! {
101cfg_if! { 91cfg_if! {
102 if #[cfg(adc_u0)] { 92 if #[cfg(adc_u0)] {
103 pub struct DacOut; 93 pub struct DacOut;
104 impl<T: Instance> AdcChannel<T> for DacOut {} 94 impl<T: Instance> super::AdcChannel<T> for DacOut {}
105 impl<T: Instance> super::SealedAdcChannel<T> for DacOut { 95 impl<T: Instance> super::SealedAdcChannel<T> for DacOut {
106 fn channel(&self) -> u8 { 96 fn channel(&self) -> u8 {
107 19 97 19
@@ -145,6 +135,32 @@ pub enum Clock {
145 135
146}} 136}}
147 137
138#[cfg(adc_u0)]
139type Ovss = u8;
140#[cfg(adc_u0)]
141type Ovsr = u8;
142#[cfg(adc_v3)]
143type Ovss = OversamplingShift;
144#[cfg(adc_v3)]
145type Ovsr = OversamplingRatio;
146
147/// Adc configuration
148#[derive(Default)]
149pub struct AdcConfig {
150 #[cfg(any(adc_u0, adc_g0, adc_v3))]
151 pub oversampling_shift: Option<Ovss>,
152 #[cfg(any(adc_u0, adc_g0, adc_v3))]
153 pub oversampling_ratio: Option<Ovsr>,
154 #[cfg(any(adc_u0, adc_g0))]
155 pub oversampling_enable: Option<bool>,
156 #[cfg(adc_v3)]
157 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
158 #[cfg(adc_g0)]
159 pub clock: Option<Clock>,
160 pub resolution: Option<Resolution>,
161 pub averaging: Option<Averaging>,
162}
163
148impl<'d, T: Instance> Adc<'d, T> { 164impl<'d, T: Instance> Adc<'d, T> {
149 /// Enable the voltage regulator 165 /// Enable the voltage regulator
150 fn init_regulator() { 166 fn init_regulator() {
@@ -178,38 +194,6 @@ impl<'d, T: Instance> Adc<'d, T> {
178 blocking_delay_us(1); 194 blocking_delay_us(1);
179 } 195 }
180 196
181 #[cfg(any(adc_v3, adc_g0, adc_u0))]
182 pub(super) fn start() {
183 // Start adc conversion
184 T::regs().cr().modify(|reg| {
185 reg.set_adstart(true);
186 });
187 }
188
189 #[cfg(any(adc_v3, adc_g0, adc_u0))]
190 pub(super) fn stop() {
191 // Stop adc conversion
192 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
193 T::regs().cr().modify(|reg| {
194 reg.set_adstp(true);
195 });
196 while T::regs().cr().read().adstart() {}
197 }
198 }
199
200 #[cfg(any(adc_v3, adc_g0, adc_u0))]
201 pub(super) fn teardown_dma() {
202 //disable dma control
203 #[cfg(not(any(adc_g0, adc_u0)))]
204 T::regs().cfgr().modify(|reg| {
205 reg.set_dmaen(false);
206 });
207 #[cfg(any(adc_g0, adc_u0))]
208 T::regs().cfgr1().modify(|reg| {
209 reg.set_dmaen(false);
210 });
211 }
212
213 /// Initialize the ADC leaving any analog clock at reset value. 197 /// Initialize the ADC leaving any analog clock at reset value.
214 /// For G0 and WL, this is the async clock without prescaler. 198 /// For G0 and WL, this is the async clock without prescaler.
215 pub fn new(adc: Peri<'d, T>) -> Self { 199 pub fn new(adc: Peri<'d, T>) -> Self {
@@ -218,6 +202,73 @@ impl<'d, T: Instance> Adc<'d, T> {
218 Self { adc } 202 Self { adc }
219 } 203 }
220 204
205 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
206 #[cfg(not(adc_g0))]
207 let s = Self::new(adc);
208
209 #[cfg(adc_g0)]
210 let s = match config.clock {
211 Some(clock) => Self::new_with_clock(adc, clock),
212 None => Self::new(adc),
213 };
214
215 #[cfg(any(adc_g0, adc_u0, adc_v3))]
216 if let Some(shift) = config.oversampling_shift {
217 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
218 }
219
220 #[cfg(any(adc_g0, adc_u0, adc_v3))]
221 if let Some(ratio) = config.oversampling_ratio {
222 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
223 }
224
225 #[cfg(any(adc_g0, adc_u0))]
226 if let Some(enable) = config.oversampling_enable {
227 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
228 }
229
230 #[cfg(adc_v3)]
231 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
232 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
233 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
234 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
235 }
236
237 if let Some(resolution) = config.resolution {
238 #[cfg(not(any(adc_g0, adc_u0)))]
239 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
240 #[cfg(any(adc_g0, adc_u0))]
241 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
242 }
243
244 if let Some(averaging) = config.averaging {
245 let (enable, samples, right_shift) = match averaging {
246 Averaging::Disabled => (false, 0, 0),
247 Averaging::Samples2 => (true, 0, 1),
248 Averaging::Samples4 => (true, 1, 2),
249 Averaging::Samples8 => (true, 2, 3),
250 Averaging::Samples16 => (true, 3, 4),
251 Averaging::Samples32 => (true, 4, 5),
252 Averaging::Samples64 => (true, 5, 6),
253 Averaging::Samples128 => (true, 6, 7),
254 Averaging::Samples256 => (true, 7, 8),
255 };
256 T::regs().cfgr2().modify(|reg| {
257 #[cfg(not(any(adc_g0, adc_u0)))]
258 reg.set_rovse(enable);
259 #[cfg(any(adc_g0, adc_u0))]
260 reg.set_ovse(enable);
261 #[cfg(any(adc_h5, adc_h7rs))]
262 reg.set_ovsr(samples.into());
263 #[cfg(not(any(adc_h5, adc_h7rs)))]
264 reg.set_ovsr(samples.into());
265 reg.set_ovss(right_shift.into());
266 })
267 }
268
269 s
270 }
271
221 #[cfg(adc_g0)] 272 #[cfg(adc_g0)]
222 /// Initialize ADC with explicit clock for the analog ADC 273 /// Initialize ADC with explicit clock for the analog ADC
223 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { 274 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self {
@@ -255,7 +306,7 @@ impl<'d, T: Instance> Adc<'d, T> {
255 } 306 }
256 307
257 // Enable ADC only when it is not already running. 308 // Enable ADC only when it is not already running.
258 fn enable(&mut self) { 309 pub(super) fn enable() {
259 // Make sure bits are off 310 // Make sure bits are off
260 while T::regs().cr().read().addis() { 311 while T::regs().cr().read().addis() {
261 // spin 312 // spin
@@ -276,258 +327,75 @@ impl<'d, T: Instance> Adc<'d, T> {
276 } 327 }
277 } 328 }
278 329
279 pub fn enable_vrefint(&self) -> VrefInt { 330 pub(super) fn start() {
280 #[cfg(not(any(adc_g0, adc_u0)))] 331 #[cfg(any(adc_v3, adc_g0, adc_u0))]
281 T::common_regs().ccr().modify(|reg| { 332 {
282 reg.set_vrefen(true); 333 // Start adc conversion
283 }); 334 T::regs().cr().modify(|reg| {
284 #[cfg(any(adc_g0, adc_u0))] 335 reg.set_adstart(true);
285 T::regs().ccr().modify(|reg| { 336 });
286 reg.set_vrefen(true);
287 });
288
289 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
290 // to stabilize the internal voltage reference.
291 blocking_delay_us(15);
292
293 VrefInt {}
294 }
295
296 pub fn enable_temperature(&self) -> Temperature {
297 cfg_if! {
298 if #[cfg(any(adc_g0, adc_u0))] {
299 T::regs().ccr().modify(|reg| {
300 reg.set_tsen(true);
301 });
302 } else if #[cfg(any(adc_h5, adc_h7rs))] {
303 T::common_regs().ccr().modify(|reg| {
304 reg.set_tsen(true);
305 });
306 } else {
307 T::common_regs().ccr().modify(|reg| {
308 reg.set_ch17sel(true);
309 });
310 }
311 } 337 }
312
313 Temperature {}
314 } 338 }
315 339
316 pub fn enable_vbat(&self) -> Vbat { 340 pub(super) fn stop() {
317 cfg_if! { 341 #[cfg(any(adc_v3, adc_g0, adc_u0))]
318 if #[cfg(any(adc_g0, adc_u0))] { 342 {
319 T::regs().ccr().modify(|reg| { 343 // Ensure conversions are finished.
320 reg.set_vbaten(true); 344 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
321 }); 345 T::regs().cr().modify(|reg| {
322 } else if #[cfg(any(adc_h5, adc_h7rs))] { 346 reg.set_adstp(true);
323 T::common_regs().ccr().modify(|reg| {
324 reg.set_vbaten(true);
325 });
326 } else {
327 T::common_regs().ccr().modify(|reg| {
328 reg.set_ch18sel(true);
329 }); 347 });
348 while T::regs().cr().read().adstart() {}
330 } 349 }
331 }
332
333 Vbat {}
334 }
335
336 /// Set the ADC resolution.
337 pub fn set_resolution(&mut self, resolution: Resolution) {
338 #[cfg(not(any(adc_g0, adc_u0)))]
339 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
340 #[cfg(any(adc_g0, adc_u0))]
341 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
342 }
343 350
344 pub fn set_averaging(&mut self, averaging: Averaging) { 351 // Reset configuration.
345 let (enable, samples, right_shift) = match averaging {
346 Averaging::Disabled => (false, 0, 0),
347 Averaging::Samples2 => (true, 0, 1),
348 Averaging::Samples4 => (true, 1, 2),
349 Averaging::Samples8 => (true, 2, 3),
350 Averaging::Samples16 => (true, 3, 4),
351 Averaging::Samples32 => (true, 4, 5),
352 Averaging::Samples64 => (true, 5, 6),
353 Averaging::Samples128 => (true, 6, 7),
354 Averaging::Samples256 => (true, 7, 8),
355 };
356 T::regs().cfgr2().modify(|reg| {
357 #[cfg(not(any(adc_g0, adc_u0)))] 352 #[cfg(not(any(adc_g0, adc_u0)))]
358 reg.set_rovse(enable); 353 T::regs().cfgr().modify(|reg| {
354 reg.set_cont(false);
355 reg.set_dmaen(false);
356 });
359 #[cfg(any(adc_g0, adc_u0))] 357 #[cfg(any(adc_g0, adc_u0))]
360 reg.set_ovse(enable); 358 T::regs().cfgr1().modify(|reg| {
361 #[cfg(any(adc_h5, adc_h7rs))] 359 reg.set_cont(false);
362 reg.set_ovsr(samples.into()); 360 reg.set_dmaen(false);
363 #[cfg(not(any(adc_h5, adc_h7rs)))] 361 });
364 reg.set_ovsr(samples.into());
365 reg.set_ovss(right_shift.into());
366 })
367 }
368 /*
369 /// Convert a raw sample from the `Temperature` to deg C
370 pub fn to_degrees_centigrade(sample: u16) -> f32 {
371 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
372 * (sample as f32 - VtempCal30::get().read() as f32)
373 + 30.0
374 }
375 */
376
377 /// Perform a single conversion.
378 fn convert(&mut self) -> u16 {
379 T::regs().isr().modify(|reg| {
380 reg.set_eos(true);
381 reg.set_eoc(true);
382 });
383
384 // Start conversion
385 T::regs().cr().modify(|reg| {
386 reg.set_adstart(true);
387 });
388
389 while !T::regs().isr().read().eos() {
390 // spin
391 } 362 }
392
393 T::regs().dr().read().0 as u16
394 } 363 }
395 364
396 /// Read an ADC channel. 365 /// Perform a single conversion.
397 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 366 pub(super) fn convert() -> u16 {
398 self.read_channel(channel, sample_time) 367 // Some models are affected by an erratum:
399 } 368 // If we perform conversions slower than 1 kHz, the first read ADC value can be
400 369 // corrupted, so we discard it and measure again.
401 /// Read one or multiple ADC channels using DMA. 370 //
402 /// 371 // STM32L471xx: Section 2.7.3
403 /// `readings` must have a length that is a multiple of the length of the 372 // STM32G4: Section 2.7.3
404 /// `sequence` iterator. 373 #[cfg(any(rcc_l4, rcc_g4))]
405 /// 374 let len = 2;
406 /// Note: The order of values in `readings` is defined by the pin ADC
407 /// channel number and not the pin order in `sequence`.
408 ///
409 /// Example
410 /// ```rust,ignore
411 /// use embassy_stm32::adc::{Adc, AdcChannel}
412 ///
413 /// let mut adc = Adc::new(p.ADC1);
414 /// let mut adc_pin0 = p.PA0.degrade_adc();
415 /// let mut adc_pin1 = p.PA1.degrade_adc();
416 /// let mut measurements = [0u16; 2];
417 ///
418 /// adc.read(
419 /// p.DMA1_CH2.reborrow(),
420 /// [
421 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
422 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
423 /// ]
424 /// .into_iter(),
425 /// &mut measurements,
426 /// )
427 /// .await;
428 /// defmt::info!("measurements: {}", measurements);
429 /// ```
430 pub async fn read(
431 &mut self,
432 rx_dma: Peri<'_, impl RxDma<T>>,
433 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
434 readings: &mut [u16],
435 ) {
436 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
437 assert!(
438 readings.len() % sequence.len() == 0,
439 "Readings length must be a multiple of sequence length"
440 );
441 assert!(
442 sequence.len() <= 16,
443 "Asynchronous read sequence cannot be more than 16 in length"
444 );
445
446 #[cfg(all(feature = "low-power", stm32wlex))]
447 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
448
449 // Ensure no conversions are ongoing and ADC is enabled.
450 Self::cancel_conversions();
451 self.enable();
452 375
453 // Set sequence length 376 #[cfg(not(any(rcc_l4, rcc_g4)))]
454 #[cfg(not(any(adc_g0, adc_u0)))] 377 let len = 1;
455 T::regs().sqr1().modify(|w| {
456 w.set_l(sequence.len() as u8 - 1);
457 });
458 378
459 #[cfg(adc_g0)] 379 for _ in 0..len {
460 { 380 T::regs().isr().modify(|reg| {
461 let mut sample_times = Vec::<SampleTime, SAMPLE_TIMES_CAPACITY>::new(); 381 reg.set_eos(true);
462 382 reg.set_eoc(true);
463 T::regs().chselr().write(|chselr| {
464 T::regs().smpr().write(|smpr| {
465 for (channel, sample_time) in sequence {
466 chselr.set_chsel(channel.channel.into(), true);
467 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
468 smpr.set_smpsel(channel.channel.into(), (i as u8).into());
469 } else {
470 smpr.set_sample_time(sample_times.len(), sample_time);
471 if let Err(_) = sample_times.push(sample_time) {
472 panic!(
473 "Implementation is limited to {} unique sample times among all channels.",
474 SAMPLE_TIMES_CAPACITY
475 );
476 }
477 }
478 }
479 })
480 }); 383 });
481 }
482 #[cfg(not(adc_g0))]
483 {
484 #[cfg(adc_u0)]
485 let mut channel_mask = 0;
486
487 // Configure channels and ranks
488 for (_i, (channel, sample_time)) in sequence.enumerate() {
489 Self::configure_channel(channel, sample_time);
490 384
491 // Each channel is sampled according to sequence 385 // Start conversion
492 #[cfg(not(any(adc_g0, adc_u0)))] 386 T::regs().cr().modify(|reg| {
493 match _i { 387 reg.set_adstart(true);
494 0..=3 => { 388 });
495 T::regs().sqr1().modify(|w| {
496 w.set_sq(_i, channel.channel());
497 });
498 }
499 4..=8 => {
500 T::regs().sqr2().modify(|w| {
501 w.set_sq(_i - 4, channel.channel());
502 });
503 }
504 9..=13 => {
505 T::regs().sqr3().modify(|w| {
506 w.set_sq(_i - 9, channel.channel());
507 });
508 }
509 14..=15 => {
510 T::regs().sqr4().modify(|w| {
511 w.set_sq(_i - 14, channel.channel());
512 });
513 }
514 _ => unreachable!(),
515 }
516 389
517 #[cfg(adc_u0)] 390 while !T::regs().isr().read().eos() {
518 { 391 // spin
519 channel_mask |= 1 << channel.channel();
520 }
521 } 392 }
522
523 // On G0 and U0 enabled channels are sampled from 0 to last channel.
524 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
525 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
526 #[cfg(adc_u0)]
527 T::regs().chselr().modify(|reg| {
528 reg.set_chsel(channel_mask);
529 });
530 } 393 }
394
395 T::regs().dr().read().0 as u16
396 }
397
398 pub(super) fn configure_dma(conversion_mode: ConversionMode) {
531 // Set continuous mode with oneshot dma. 399 // Set continuous mode with oneshot dma.
532 // Clear overrun flag before starting transfer. 400 // Clear overrun flag before starting transfer.
533 T::regs().isr().modify(|reg| { 401 T::regs().isr().modify(|reg| {
@@ -535,82 +403,23 @@ impl<'d, T: Instance> Adc<'d, T> {
535 }); 403 });
536 404
537 #[cfg(not(any(adc_g0, adc_u0)))] 405 #[cfg(not(any(adc_g0, adc_u0)))]
538 T::regs().cfgr().modify(|reg| { 406 let regs = T::regs().cfgr();
539 reg.set_discen(false); 407
540 reg.set_cont(true);
541 reg.set_dmacfg(Dmacfg::ONE_SHOT);
542 reg.set_dmaen(true);
543 });
544 #[cfg(any(adc_g0, adc_u0))] 408 #[cfg(any(adc_g0, adc_u0))]
545 T::regs().cfgr1().modify(|reg| { 409 let regs = T::regs().cfgr1();
410
411 regs.modify(|reg| {
546 reg.set_discen(false); 412 reg.set_discen(false);
547 reg.set_cont(true); 413 reg.set_cont(true);
548 reg.set_dmacfg(Dmacfg::ONE_SHOT); 414 reg.set_dmacfg(match conversion_mode {
415 ConversionMode::Singular => Dmacfg::ONE_SHOT,
416 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
417 });
549 reg.set_dmaen(true); 418 reg.set_dmaen(true);
550 }); 419 });
551
552 let request = rx_dma.request();
553 let transfer = unsafe {
554 Transfer::new_read(
555 rx_dma,
556 request,
557 T::regs().dr().as_ptr() as *mut u16,
558 readings,
559 Default::default(),
560 )
561 };
562
563 // Start conversion
564 T::regs().cr().modify(|reg| {
565 reg.set_adstart(true);
566 });
567
568 // Wait for conversion sequence to finish.
569 transfer.await;
570
571 // Ensure conversions are finished.
572 Self::cancel_conversions();
573
574 // Reset configuration.
575 #[cfg(not(any(adc_g0, adc_u0)))]
576 T::regs().cfgr().modify(|reg| {
577 reg.set_cont(false);
578 });
579 #[cfg(any(adc_g0, adc_u0))]
580 T::regs().cfgr1().modify(|reg| {
581 reg.set_cont(false);
582 });
583 } 420 }
584 421
585 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. 422 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
586 ///
587 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
588 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
589 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
590 ///
591 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
592 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
593 ///
594 /// [`read`]: #method.read
595 #[cfg(any(adc_v3, adc_g0, adc_u0))]
596 pub fn into_ring_buffered<'a>(
597 &mut self,
598 dma: Peri<'a, impl RxDma<T>>,
599 dma_buf: &'a mut [u16],
600 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
601 ) -> RingBufferedAdc<'a, T> {
602 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
603 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
604 assert!(
605 sequence.len() <= 16,
606 "Asynchronous read sequence cannot be more than 16 in length"
607 );
608 // reset conversions and enable the adc
609 Self::cancel_conversions();
610 self.enable();
611
612 //adc side setup
613
614 // Set sequence length 423 // Set sequence length
615 #[cfg(not(any(adc_g0, adc_u0)))] 424 #[cfg(not(any(adc_g0, adc_u0)))]
616 T::regs().sqr1().modify(|w| { 425 T::regs().sqr1().modify(|w| {
@@ -623,10 +432,10 @@ impl<'d, T: Instance> Adc<'d, T> {
623 432
624 T::regs().chselr().write(|chselr| { 433 T::regs().chselr().write(|chselr| {
625 T::regs().smpr().write(|smpr| { 434 T::regs().smpr().write(|smpr| {
626 for (channel, sample_time) in sequence { 435 for ((channel, _), sample_time) in sequence {
627 chselr.set_chsel(channel.channel.into(), true); 436 chselr.set_chsel(channel.into(), true);
628 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { 437 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
629 smpr.set_smpsel(channel.channel.into(), (i as u8).into()); 438 smpr.set_smpsel(channel.into(), (i as u8).into());
630 } else { 439 } else {
631 smpr.set_sample_time(sample_times.len(), sample_time); 440 smpr.set_sample_time(sample_times.len(), sample_time);
632 if let Err(_) = sample_times.push(sample_time) { 441 if let Err(_) = sample_times.push(sample_time) {
@@ -646,30 +455,63 @@ impl<'d, T: Instance> Adc<'d, T> {
646 let mut channel_mask = 0; 455 let mut channel_mask = 0;
647 456
648 // Configure channels and ranks 457 // Configure channels and ranks
649 for (_i, (mut channel, sample_time)) in sequence.enumerate() { 458 for (_i, ((channel, _), sample_time)) in sequence.enumerate() {
650 Self::configure_channel(&mut channel, sample_time); 459 // RM0492, RM0481, etc.
460 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
461 #[cfg(any(adc_h5, adc_h7rs))]
462 if channel == 0 {
463 T::regs().or().modify(|reg| reg.set_op0(true));
464 }
465
466 // Configure channel
467 cfg_if! {
468 if #[cfg(adc_u0)] {
469 // On G0 and U6 all channels use the same sampling time.
470 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
471 } else if #[cfg(any(adc_h5, adc_h7rs))] {
472 match channel {
473 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
474 _ => T::regs().smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
475 }
476 } else {
477 let sample_time = sample_time.into();
478 T::regs()
479 .smpr(channel as usize / 10)
480 .modify(|reg| reg.set_smp(channel as usize % 10, sample_time));
481 }
482 }
483
484 #[cfg(stm32h7)]
485 {
486 use crate::pac::adc::vals::Pcsel;
487
488 T::regs().cfgr2().modify(|w| w.set_lshift(0));
489 T::regs()
490 .pcsel()
491 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
492 }
651 493
652 // Each channel is sampled according to sequence 494 // Each channel is sampled according to sequence
653 #[cfg(not(any(adc_g0, adc_u0)))] 495 #[cfg(not(any(adc_g0, adc_u0)))]
654 match _i { 496 match _i {
655 0..=3 => { 497 0..=3 => {
656 T::regs().sqr1().modify(|w| { 498 T::regs().sqr1().modify(|w| {
657 w.set_sq(_i, channel.channel()); 499 w.set_sq(_i, channel);
658 }); 500 });
659 } 501 }
660 4..=8 => { 502 4..=8 => {
661 T::regs().sqr2().modify(|w| { 503 T::regs().sqr2().modify(|w| {
662 w.set_sq(_i - 4, channel.channel()); 504 w.set_sq(_i - 4, channel);
663 }); 505 });
664 } 506 }
665 9..=13 => { 507 9..=13 => {
666 T::regs().sqr3().modify(|w| { 508 T::regs().sqr3().modify(|w| {
667 w.set_sq(_i - 9, channel.channel()); 509 w.set_sq(_i - 9, channel);
668 }); 510 });
669 } 511 }
670 14..=15 => { 512 14..=15 => {
671 T::regs().sqr4().modify(|w| { 513 T::regs().sqr4().modify(|w| {
672 w.set_sq(_i - 14, channel.channel()); 514 w.set_sq(_i - 14, channel);
673 }); 515 });
674 } 516 }
675 _ => unreachable!(), 517 _ => unreachable!(),
@@ -677,7 +519,7 @@ impl<'d, T: Instance> Adc<'d, T> {
677 519
678 #[cfg(adc_u0)] 520 #[cfg(adc_u0)]
679 { 521 {
680 channel_mask |= 1 << channel.channel(); 522 channel_mask |= 1 << channel;
681 } 523 }
682 } 524 }
683 525
@@ -689,151 +531,71 @@ impl<'d, T: Instance> Adc<'d, T> {
689 reg.set_chsel(channel_mask); 531 reg.set_chsel(channel_mask);
690 }); 532 });
691 } 533 }
692 // Set continuous mode with Circular dma. 534 }
693 // Clear overrun flag before starting transfer.
694 T::regs().isr().modify(|reg| {
695 reg.set_ovr(true);
696 });
697 535
536 pub fn enable_vrefint(&self) -> VrefInt {
698 #[cfg(not(any(adc_g0, adc_u0)))] 537 #[cfg(not(any(adc_g0, adc_u0)))]
699 T::regs().cfgr().modify(|reg| { 538 T::common_regs().ccr().modify(|reg| {
700 reg.set_discen(false); 539 reg.set_vrefen(true);
701 reg.set_cont(true);
702 reg.set_dmacfg(Dmacfg::CIRCULAR);
703 reg.set_dmaen(true);
704 }); 540 });
705 #[cfg(any(adc_g0, adc_u0))] 541 #[cfg(any(adc_g0, adc_u0))]
706 T::regs().cfgr1().modify(|reg| { 542 T::regs().ccr().modify(|reg| {
707 reg.set_discen(false); 543 reg.set_vrefen(true);
708 reg.set_cont(true);
709 reg.set_dmacfg(Dmacfg::CIRCULAR);
710 reg.set_dmaen(true);
711 }); 544 });
712 545
713 RingBufferedAdc::new(dma, dma_buf) 546 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
714 } 547 // to stabilize the internal voltage reference.
715 548 blocking_delay_us(15);
716 #[cfg(not(adc_g0))]
717 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
718 // RM0492, RM0481, etc.
719 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
720 #[cfg(any(adc_h5, adc_h7rs))]
721 if channel.channel() == 0 {
722 T::regs().or().modify(|reg| reg.set_op0(true));
723 }
724 549
725 // Configure channel 550 VrefInt {}
726 Self::set_channel_sample_time(channel.channel(), sample_time);
727 } 551 }
728 552
729 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 553 pub fn enable_temperature(&self) -> Temperature {
730 self.enable(); 554 cfg_if! {
731 #[cfg(not(adc_g0))] 555 if #[cfg(any(adc_g0, adc_u0))] {
732 Self::configure_channel(channel, sample_time); 556 T::regs().ccr().modify(|reg| {
733 #[cfg(adc_g0)] 557 reg.set_tsen(true);
734 T::regs().smpr().write(|reg| { 558 });
735 reg.set_sample_time(0, sample_time); 559 } else if #[cfg(any(adc_h5, adc_h7rs))] {
736 reg.set_smpsel(channel.channel().into(), Smpsel::SMP1); 560 T::common_regs().ccr().modify(|reg| {
737 }); 561 reg.set_tsen(true);
738 // Select channel 562 });
739 #[cfg(not(any(adc_g0, adc_u0)))] 563 } else {
740 T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel())); 564 T::common_regs().ccr().modify(|reg| {
741 #[cfg(any(adc_g0, adc_u0))] 565 reg.set_ch17sel(true);
742 T::regs().chselr().write(|reg| { 566 });
743 #[cfg(adc_g0)] 567 }
744 reg.set_chsel(channel.channel().into(), true);
745 #[cfg(adc_u0)]
746 reg.set_chsel(1 << channel.channel());
747 });
748
749 // Some models are affected by an erratum:
750 // If we perform conversions slower than 1 kHz, the first read ADC value can be
751 // corrupted, so we discard it and measure again.
752 //
753 // STM32L471xx: Section 2.7.3
754 // STM32G4: Section 2.7.3
755 #[cfg(any(rcc_l4, rcc_g4))]
756 let _ = self.convert();
757 let val = self.convert();
758
759 T::regs().cr().modify(|reg| reg.set_addis(true));
760
761 // RM0492, RM0481, etc.
762 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
763 #[cfg(any(adc_h5, adc_h7rs))]
764 if channel.channel() == 0 {
765 T::regs().or().modify(|reg| reg.set_op0(false));
766 } 568 }
767 569
768 val 570 Temperature {}
769 }
770
771 #[cfg(adc_g0)]
772 pub fn set_oversampling_shift(&mut self, shift: Ovss) {
773 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
774 }
775 #[cfg(adc_u0)]
776 pub fn set_oversampling_shift(&mut self, shift: u8) {
777 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
778 }
779
780 #[cfg(adc_g0)]
781 pub fn set_oversampling_ratio(&mut self, ratio: Ovsr) {
782 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
783 }
784 #[cfg(adc_u0)]
785 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
786 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
787 }
788
789 #[cfg(any(adc_g0, adc_u0))]
790 pub fn oversampling_enable(&mut self, enable: bool) {
791 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
792 }
793
794 #[cfg(adc_v3)]
795 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
796 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
797 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
798 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
799 }
800
801 #[cfg(adc_v3)]
802 pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) {
803 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
804 }
805
806 #[cfg(adc_v3)]
807 pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) {
808 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
809 } 571 }
810 572
811 #[cfg(not(adc_g0))] 573 pub fn enable_vbat(&self) -> Vbat {
812 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
813 cfg_if! { 574 cfg_if! {
814 if #[cfg(adc_u0)] { 575 if #[cfg(any(adc_g0, adc_u0))] {
815 // On G0 and U6 all channels use the same sampling time. 576 T::regs().ccr().modify(|reg| {
816 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 577 reg.set_vbaten(true);
578 });
817 } else if #[cfg(any(adc_h5, adc_h7rs))] { 579 } else if #[cfg(any(adc_h5, adc_h7rs))] {
818 match _ch { 580 T::common_regs().ccr().modify(|reg| {
819 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 581 reg.set_vbaten(true);
820 _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 582 });
821 }
822 } else { 583 } else {
823 let sample_time = sample_time.into(); 584 T::common_regs().ccr().modify(|reg| {
824 T::regs() 585 reg.set_ch18sel(true);
825 .smpr(_ch as usize / 10) 586 });
826 .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time));
827 } 587 }
828 } 588 }
589
590 Vbat {}
829 } 591 }
830 592
831 fn cancel_conversions() { 593 /*
832 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 594 /// Convert a raw sample from the `Temperature` to deg C
833 T::regs().cr().modify(|reg| { 595 pub fn to_degrees_centigrade(sample: u16) -> f32 {
834 reg.set_adstp(true); 596 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
835 }); 597 * (sample as f32 - VtempCal30::get().read() as f32)
836 while T::regs().cr().read().adstart() {} 598 + 30.0
837 }
838 } 599 }
600 */
839} 601}
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 2f7baf3bf..9be6bcd0b 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -4,11 +4,8 @@ use pac::adc::vals::{Adcaldif, Boost};
4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; 4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 5use pac::adccommon::vals::Presc;
6 6
7use super::{ 7use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
8 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, Temperature, Vbat, 8use crate::adc::ConversionMode;
9 VrefInt, blocking_delay_us,
10};
11use crate::dma::Transfer;
12use crate::time::Hertz; 9use crate::time::Hertz;
13use crate::{Peri, pac, rcc}; 10use crate::{Peri, pac, rcc};
14 11
@@ -26,39 +23,39 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
26const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
27 24
28#[cfg(stm32g4)] 25#[cfg(stm32g4)]
29impl<T: Instance> super::VrefConverter for T { 26impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
30 const CHANNEL: u8 = 18; 27 const CHANNEL: u8 = 18;
31} 28}
32#[cfg(stm32g4)] 29#[cfg(stm32g4)]
33impl<T: Instance> super::TemperatureConverter for T { 30impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
34 const CHANNEL: u8 = 16; 31 const CHANNEL: u8 = 16;
35} 32}
36 33
37#[cfg(stm32h7)] 34#[cfg(stm32h7)]
38impl<T: Instance> super::VrefConverter for T { 35impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
39 const CHANNEL: u8 = 19; 36 const CHANNEL: u8 = 19;
40} 37}
41#[cfg(stm32h7)] 38#[cfg(stm32h7)]
42impl<T: Instance> super::TemperatureConverter for T { 39impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
43 const CHANNEL: u8 = 18; 40 const CHANNEL: u8 = 18;
44} 41}
45 42
46// TODO this should be 14 for H7a/b/35 43// TODO this should be 14 for H7a/b/35
47#[cfg(not(stm32u5))] 44#[cfg(not(stm32u5))]
48impl<T: Instance> super::VBatConverter for T { 45impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
49 const CHANNEL: u8 = 17; 46 const CHANNEL: u8 = 17;
50} 47}
51 48
52#[cfg(stm32u5)] 49#[cfg(stm32u5)]
53impl<T: Instance> super::VrefConverter for T { 50impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
54 const CHANNEL: u8 = 0; 51 const CHANNEL: u8 = 0;
55} 52}
56#[cfg(stm32u5)] 53#[cfg(stm32u5)]
57impl<T: Instance> super::TemperatureConverter for T { 54impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
58 const CHANNEL: u8 = 19; 55 const CHANNEL: u8 = 19;
59} 56}
60#[cfg(stm32u5)] 57#[cfg(stm32u5)]
61impl<T: Instance> super::VBatConverter for T { 58impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
62 const CHANNEL: u8 = 18; 59 const CHANNEL: u8 = 18;
63} 60}
64 61
@@ -147,7 +144,48 @@ pub enum Averaging {
147 Samples1024, 144 Samples1024,
148} 145}
149 146
147/// Adc configuration
148#[derive(Default)]
149pub struct AdcConfig {
150 pub resolution: Option<Resolution>,
151 pub averaging: Option<Averaging>,
152}
153
150impl<'d, T: Instance> Adc<'d, T> { 154impl<'d, T: Instance> Adc<'d, T> {
155 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
156 let s = Self::new(adc);
157
158 // Set the ADC resolution.
159 if let Some(resolution) = config.resolution {
160 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
161 }
162
163 // Set hardware averaging.
164 if let Some(averaging) = config.averaging {
165 let (enable, samples, right_shift) = match averaging {
166 Averaging::Disabled => (false, 0, 0),
167 Averaging::Samples2 => (true, 1, 1),
168 Averaging::Samples4 => (true, 3, 2),
169 Averaging::Samples8 => (true, 7, 3),
170 Averaging::Samples16 => (true, 15, 4),
171 Averaging::Samples32 => (true, 31, 5),
172 Averaging::Samples64 => (true, 63, 6),
173 Averaging::Samples128 => (true, 127, 7),
174 Averaging::Samples256 => (true, 255, 8),
175 Averaging::Samples512 => (true, 511, 9),
176 Averaging::Samples1024 => (true, 1023, 10),
177 };
178
179 T::regs().cfgr2().modify(|reg| {
180 reg.set_rovse(enable);
181 reg.set_ovsr(samples);
182 reg.set_ovss(right_shift);
183 })
184 }
185
186 s
187 }
188
151 /// Create a new ADC driver. 189 /// Create a new ADC driver.
152 pub fn new(adc: Peri<'d, T>) -> Self { 190 pub fn new(adc: Peri<'d, T>) -> Self {
153 rcc::enable_and_reset::<T>(); 191 rcc::enable_and_reset::<T>();
@@ -179,37 +217,20 @@ impl<'d, T: Instance> Adc<'d, T> {
179 }; 217 };
180 T::regs().cr().modify(|w| w.set_boost(boost)); 218 T::regs().cr().modify(|w| w.set_boost(boost));
181 } 219 }
182 let mut s = Self { adc };
183 s.power_up();
184 s.configure_differential_inputs();
185
186 s.calibrate();
187 blocking_delay_us(1);
188
189 s.enable();
190 s.configure();
191
192 s
193 }
194 220
195 fn power_up(&mut self) {
196 T::regs().cr().modify(|reg| { 221 T::regs().cr().modify(|reg| {
197 reg.set_deeppwd(false); 222 reg.set_deeppwd(false);
198 reg.set_advregen(true); 223 reg.set_advregen(true);
199 }); 224 });
200 225
201 blocking_delay_us(10); 226 blocking_delay_us(10);
202 }
203 227
204 fn configure_differential_inputs(&mut self) {
205 T::regs().difsel().modify(|w| { 228 T::regs().difsel().modify(|w| {
206 for n in 0..20 { 229 for n in 0..20 {
207 w.set_difsel(n, Difsel::SINGLE_ENDED); 230 w.set_difsel(n, Difsel::SINGLE_ENDED);
208 } 231 }
209 }); 232 });
210 }
211 233
212 fn calibrate(&mut self) {
213 T::regs().cr().modify(|w| { 234 T::regs().cr().modify(|w| {
214 #[cfg(not(adc_u5))] 235 #[cfg(not(adc_u5))]
215 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 236 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
@@ -219,80 +240,50 @@ impl<'d, T: Instance> Adc<'d, T> {
219 T::regs().cr().modify(|w| w.set_adcal(true)); 240 T::regs().cr().modify(|w| w.set_adcal(true));
220 241
221 while T::regs().cr().read().adcal() {} 242 while T::regs().cr().read().adcal() {}
222 }
223 243
224 fn enable(&mut self) { 244 blocking_delay_us(1);
225 T::regs().isr().write(|w| w.set_adrdy(true)); 245
226 T::regs().cr().modify(|w| w.set_aden(true)); 246 Self::enable();
227 while !T::regs().isr().read().adrdy() {}
228 T::regs().isr().write(|w| w.set_adrdy(true));
229 }
230 247
231 fn configure(&mut self) {
232 // single conversion mode, software trigger 248 // single conversion mode, software trigger
233 T::regs().cfgr().modify(|w| { 249 T::regs().cfgr().modify(|w| {
234 w.set_cont(false); 250 w.set_cont(false);
235 w.set_exten(Exten::DISABLED); 251 w.set_exten(Exten::DISABLED);
236 }); 252 });
237 }
238 253
239 /// Enable reading the voltage reference internal channel. 254 Self { adc }
240 pub fn enable_vrefint(&self) -> VrefInt {
241 T::common_regs().ccr().modify(|reg| {
242 reg.set_vrefen(true);
243 });
244
245 VrefInt {}
246 } 255 }
247 256
248 /// Enable reading the temperature internal channel. 257 pub(super) fn enable() {
249 pub fn enable_temperature(&self) -> Temperature { 258 T::regs().isr().write(|w| w.set_adrdy(true));
250 T::common_regs().ccr().modify(|reg| { 259 T::regs().cr().modify(|w| w.set_aden(true));
251 reg.set_vsenseen(true); 260 while !T::regs().isr().read().adrdy() {}
252 }); 261 T::regs().isr().write(|w| w.set_adrdy(true));
253
254 Temperature {}
255 } 262 }
256 263
257 /// Enable reading the vbat internal channel. 264 pub(super) fn start() {
258 pub fn enable_vbat(&self) -> Vbat { 265 // Start conversion
259 T::common_regs().ccr().modify(|reg| { 266 T::regs().cr().modify(|reg| {
260 reg.set_vbaten(true); 267 reg.set_adstart(true);
261 }); 268 });
262
263 Vbat {}
264 } 269 }
265 270
266 /// Set the ADC resolution. 271 pub(super) fn stop() {
267 pub fn set_resolution(&mut self, resolution: Resolution) { 272 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
268 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 273 T::regs().cr().modify(|reg| {
269 } 274 reg.set_adstp(Adstp::STOP);
275 });
276 while T::regs().cr().read().adstart() {}
277 }
270 278
271 /// Set hardware averaging. 279 // Reset configuration.
272 pub fn set_averaging(&mut self, averaging: Averaging) { 280 T::regs().cfgr().modify(|reg| {
273 let (enable, samples, right_shift) = match averaging { 281 reg.set_cont(false);
274 Averaging::Disabled => (false, 0, 0), 282 reg.set_dmngt(Dmngt::from_bits(0));
275 Averaging::Samples2 => (true, 1, 1), 283 });
276 Averaging::Samples4 => (true, 3, 2),
277 Averaging::Samples8 => (true, 7, 3),
278 Averaging::Samples16 => (true, 15, 4),
279 Averaging::Samples32 => (true, 31, 5),
280 Averaging::Samples64 => (true, 63, 6),
281 Averaging::Samples128 => (true, 127, 7),
282 Averaging::Samples256 => (true, 255, 8),
283 Averaging::Samples512 => (true, 511, 9),
284 Averaging::Samples1024 => (true, 1023, 10),
285 };
286
287 T::regs().cfgr2().modify(|reg| {
288 reg.set_rovse(enable);
289 reg.set_ovsr(samples);
290 reg.set_ovss(right_shift);
291 })
292 } 284 }
293 285
294 /// Perform a single conversion. 286 pub(super) fn convert() -> u16 {
295 fn convert(&mut self) -> u16 {
296 T::regs().isr().modify(|reg| { 287 T::regs().isr().modify(|reg| {
297 reg.set_eos(true); 288 reg.set_eos(true);
298 reg.set_eoc(true); 289 reg.set_eoc(true);
@@ -310,170 +301,96 @@ impl<'d, T: Instance> Adc<'d, T> {
310 T::regs().dr().read().0 as u16 301 T::regs().dr().read().0 as u16
311 } 302 }
312 303
313 /// Read an ADC channel. 304 pub(super) fn configure_dma(conversion_mode: ConversionMode) {
314 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 305 match conversion_mode {
315 self.read_channel(channel, sample_time) 306 ConversionMode::Singular => {
307 T::regs().isr().modify(|reg| {
308 reg.set_ovr(true);
309 });
310 T::regs().cfgr().modify(|reg| {
311 reg.set_cont(true);
312 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
313 });
314 }
315 _ => unreachable!(),
316 }
316 } 317 }
317 318
318 /// Read one or multiple ADC channels using DMA. 319 pub(super) fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
319 ///
320 /// `sequence` iterator and `readings` must have the same length.
321 ///
322 /// Example
323 /// ```rust,ignore
324 /// use embassy_stm32::adc::{Adc, AdcChannel}
325 ///
326 /// let mut adc = Adc::new(p.ADC1);
327 /// let mut adc_pin0 = p.PA0.into();
328 /// let mut adc_pin2 = p.PA2.into();
329 /// let mut measurements = [0u16; 2];
330 ///
331 /// adc.read(
332 /// p.DMA2_CH0.reborrow(),
333 /// [
334 /// (&mut *adc_pin0, SampleTime::CYCLES112),
335 /// (&mut *adc_pin2, SampleTime::CYCLES112),
336 /// ]
337 /// .into_iter(),
338 /// &mut measurements,
339 /// )
340 /// .await;
341 /// defmt::info!("measurements: {}", measurements);
342 /// ```
343 pub async fn read(
344 &mut self,
345 rx_dma: Peri<'_, impl RxDma<T>>,
346 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
347 readings: &mut [u16],
348 ) {
349 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
350 assert!(
351 sequence.len() == readings.len(),
352 "Sequence length must be equal to readings length"
353 );
354 assert!(
355 sequence.len() <= 16,
356 "Asynchronous read sequence cannot be more than 16 in length"
357 );
358
359 // Ensure no conversions are ongoing
360 Self::cancel_conversions();
361
362 // Set sequence length 320 // Set sequence length
363 T::regs().sqr1().modify(|w| { 321 T::regs().sqr1().modify(|w| {
364 w.set_l(sequence.len() as u8 - 1); 322 w.set_l(sequence.len() as u8 - 1);
365 }); 323 });
366 324
367 // Configure channels and ranks 325 // Configure channels and ranks
368 for (i, (channel, sample_time)) in sequence.enumerate() { 326 for (i, ((channel, _), sample_time)) in sequence.enumerate() {
369 Self::configure_channel(channel, sample_time); 327 let sample_time = sample_time.into();
328 if channel <= 9 {
329 T::regs().smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time));
330 } else {
331 T::regs()
332 .smpr(1)
333 .modify(|reg| reg.set_smp((channel - 10) as _, sample_time));
334 }
335
336 #[cfg(any(stm32h7, stm32u5))]
337 {
338 T::regs().cfgr2().modify(|w| w.set_lshift(0));
339 T::regs()
340 .pcsel()
341 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
342 }
343
370 match i { 344 match i {
371 0..=3 => { 345 0..=3 => {
372 T::regs().sqr1().modify(|w| { 346 T::regs().sqr1().modify(|w| {
373 w.set_sq(i, channel.channel()); 347 w.set_sq(i, channel);
374 }); 348 });
375 } 349 }
376 4..=8 => { 350 4..=8 => {
377 T::regs().sqr2().modify(|w| { 351 T::regs().sqr2().modify(|w| {
378 w.set_sq(i - 4, channel.channel()); 352 w.set_sq(i - 4, channel);
379 }); 353 });
380 } 354 }
381 9..=13 => { 355 9..=13 => {
382 T::regs().sqr3().modify(|w| { 356 T::regs().sqr3().modify(|w| {
383 w.set_sq(i - 9, channel.channel()); 357 w.set_sq(i - 9, channel);
384 }); 358 });
385 } 359 }
386 14..=15 => { 360 14..=15 => {
387 T::regs().sqr4().modify(|w| { 361 T::regs().sqr4().modify(|w| {
388 w.set_sq(i - 14, channel.channel()); 362 w.set_sq(i - 14, channel);
389 }); 363 });
390 } 364 }
391 _ => unreachable!(), 365 _ => unreachable!(),
392 } 366 }
393 } 367 }
394
395 // Set continuous mode with oneshot dma.
396 // Clear overrun flag before starting transfer.
397
398 T::regs().isr().modify(|reg| {
399 reg.set_ovr(true);
400 });
401 T::regs().cfgr().modify(|reg| {
402 reg.set_cont(true);
403 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
404 });
405
406 let request = rx_dma.request();
407 let transfer = unsafe {
408 Transfer::new_read(
409 rx_dma,
410 request,
411 T::regs().dr().as_ptr() as *mut u16,
412 readings,
413 Default::default(),
414 )
415 };
416
417 // Start conversion
418 T::regs().cr().modify(|reg| {
419 reg.set_adstart(true);
420 });
421
422 // Wait for conversion sequence to finish.
423 transfer.await;
424
425 // Ensure conversions are finished.
426 Self::cancel_conversions();
427
428 // Reset configuration.
429 T::regs().cfgr().modify(|reg| {
430 reg.set_cont(false);
431 reg.set_dmngt(Dmngt::from_bits(0));
432 });
433 } 368 }
434 369
435 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 370 /// Enable reading the voltage reference internal channel.
436 channel.setup(); 371 pub fn enable_vrefint(&self) -> VrefInt {
437 372 T::common_regs().ccr().modify(|reg| {
438 let channel = channel.channel(); 373 reg.set_vrefen(true);
439 374 });
440 Self::set_channel_sample_time(channel, sample_time);
441 375
442 #[cfg(any(stm32h7, stm32u5))] 376 VrefInt {}
443 {
444 T::regs().cfgr2().modify(|w| w.set_lshift(0));
445 T::regs()
446 .pcsel()
447 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
448 }
449 } 377 }
450 378
451 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { 379 /// Enable reading the temperature internal channel.
452 Self::configure_channel(channel, sample_time); 380 pub fn enable_temperature(&self) -> Temperature {
453 381 T::common_regs().ccr().modify(|reg| {
454 T::regs().sqr1().modify(|reg| { 382 reg.set_vsenseen(true);
455 reg.set_sq(0, channel.channel());
456 reg.set_l(0);
457 }); 383 });
458 384
459 self.convert() 385 Temperature {}
460 } 386 }
461 387
462 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 388 /// Enable reading the vbat internal channel.
463 let sample_time = sample_time.into(); 389 pub fn enable_vbat(&self) -> Vbat {
464 if ch <= 9 { 390 T::common_regs().ccr().modify(|reg| {
465 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); 391 reg.set_vbaten(true);
466 } else { 392 });
467 T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
468 }
469 }
470 393
471 fn cancel_conversions() { 394 Vbat {}
472 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
473 T::regs().cr().modify(|reg| {
474 reg.set_adstp(Adstp::STOP);
475 });
476 while T::regs().cr().read().adstart() {}
477 }
478 } 395 }
479} 396}
diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md
index 0a30bc24b..cfb1bf021 100644
--- a/embassy-usb/CHANGELOG.md
+++ b/embassy-usb/CHANGELOG.md
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- Add support for USB HID Boot Protocol Mode
12
11## 0.5.1 - 2025-08-26 13## 0.5.1 - 2025-08-26
12 14
13## 0.5.0 - 2025-07-16 15## 0.5.0 - 2025-07-16
diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs
index 182e1f83f..64e8fd59f 100644
--- a/embassy-usb/src/class/hid.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -15,8 +15,6 @@ use crate::types::InterfaceNumber;
15use crate::{Builder, Handler}; 15use crate::{Builder, Handler};
16 16
17const USB_CLASS_HID: u8 = 0x03; 17const USB_CLASS_HID: u8 = 0x03;
18const USB_SUBCLASS_NONE: u8 = 0x00;
19const USB_PROTOCOL_NONE: u8 = 0x00;
20 18
21// HID 19// HID
22const HID_DESC_DESCTYPE_HID: u8 = 0x21; 20const HID_DESC_DESCTYPE_HID: u8 = 0x21;
@@ -31,6 +29,52 @@ const HID_REQ_SET_REPORT: u8 = 0x09;
31const HID_REQ_GET_PROTOCOL: u8 = 0x03; 29const HID_REQ_GET_PROTOCOL: u8 = 0x03;
32const HID_REQ_SET_PROTOCOL: u8 = 0x0b; 30const HID_REQ_SET_PROTOCOL: u8 = 0x0b;
33 31
32/// Get/Set Protocol mapping
33/// See (7.2.5 and 7.2.6): <https://www.usb.org/sites/default/files/hid1_11.pdf>
34#[derive(Copy, Clone, Debug, PartialEq, Eq)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36#[repr(u8)]
37pub enum HidProtocolMode {
38 /// Hid Boot Protocol Mode
39 Boot = 0,
40 /// Hid Report Protocol Mode
41 Report = 1,
42}
43
44impl From<u8> for HidProtocolMode {
45 fn from(mode: u8) -> HidProtocolMode {
46 if mode == HidProtocolMode::Boot as u8 {
47 HidProtocolMode::Boot
48 } else {
49 HidProtocolMode::Report
50 }
51 }
52}
53
54/// USB HID interface subclass values.
55#[derive(Copy, Clone, Debug, PartialEq, Eq)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
57#[repr(u8)]
58pub enum HidSubclass {
59 /// No subclass, standard HID device.
60 No = 0,
61 /// Boot interface subclass, supports BIOS boot protocol.
62 Boot = 1,
63}
64
65/// USB HID protocol values.
66#[derive(Copy, Clone, Debug, PartialEq, Eq)]
67#[cfg_attr(feature = "defmt", derive(defmt::Format))]
68#[repr(u8)]
69pub enum HidBootProtocol {
70 /// No boot protocol.
71 None = 0,
72 /// Keyboard boot protocol.
73 Keyboard = 1,
74 /// Mouse boot protocol.
75 Mouse = 2,
76}
77
34/// Configuration for the HID class. 78/// Configuration for the HID class.
35pub struct Config<'d> { 79pub struct Config<'d> {
36 /// HID report descriptor. 80 /// HID report descriptor.
@@ -48,6 +92,12 @@ pub struct Config<'d> {
48 92
49 /// Max packet size for both the IN and OUT endpoints. 93 /// Max packet size for both the IN and OUT endpoints.
50 pub max_packet_size: u16, 94 pub max_packet_size: u16,
95
96 /// The HID subclass of this interface
97 pub hid_subclass: HidSubclass,
98
99 /// The HID boot protocol of this interface
100 pub hid_boot_protocol: HidBootProtocol,
51} 101}
52 102
53/// Report ID 103/// Report ID
@@ -109,10 +159,15 @@ fn build<'d, D: Driver<'d>>(
109) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) { 159) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) {
110 let len = config.report_descriptor.len(); 160 let len = config.report_descriptor.len();
111 161
112 let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE); 162 let mut func = builder.function(USB_CLASS_HID, config.hid_subclass as u8, config.hid_boot_protocol as u8);
113 let mut iface = func.interface(); 163 let mut iface = func.interface();
114 let if_num = iface.interface_number(); 164 let if_num = iface.interface_number();
115 let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE, None); 165 let mut alt = iface.alt_setting(
166 USB_CLASS_HID,
167 config.hid_subclass as u8,
168 config.hid_boot_protocol as u8,
169 None,
170 );
116 171
117 // HID descriptor 172 // HID descriptor
118 alt.descriptor( 173 alt.descriptor(
@@ -389,6 +444,23 @@ pub trait RequestHandler {
389 OutResponse::Rejected 444 OutResponse::Rejected
390 } 445 }
391 446
447 /// Gets the current hid protocol.
448 ///
449 /// Returns `Report` protocol by default.
450 fn get_protocol(&self) -> HidProtocolMode {
451 HidProtocolMode::Report
452 }
453
454 /// Sets the current hid protocol to `protocol`.
455 ///
456 /// Accepts only `Report` protocol by default.
457 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
458 match protocol {
459 HidProtocolMode::Report => OutResponse::Accepted,
460 HidProtocolMode::Boot => OutResponse::Rejected,
461 }
462 }
463
392 /// Get the idle rate for `id`. 464 /// Get the idle rate for `id`.
393 /// 465 ///
394 /// If `id` is `None`, get the idle rate for all reports. Returning `None` 466 /// If `id` is `None`, get the idle rate for all reports. Returning `None`
@@ -482,11 +554,14 @@ impl<'d> Handler for Control<'d> {
482 _ => Some(OutResponse::Rejected), 554 _ => Some(OutResponse::Rejected),
483 }, 555 },
484 HID_REQ_SET_PROTOCOL => { 556 HID_REQ_SET_PROTOCOL => {
485 if req.value == 1 { 557 let hid_protocol = HidProtocolMode::from(req.value as u8);
486 Some(OutResponse::Accepted) 558 match (self.request_handler.as_mut(), hid_protocol) {
487 } else { 559 (Some(request_handler), hid_protocol) => Some(request_handler.set_protocol(hid_protocol)),
488 warn!("HID Boot Protocol is unsupported."); 560 (None, HidProtocolMode::Report) => Some(OutResponse::Accepted),
489 Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol 561 (None, HidProtocolMode::Boot) => {
562 info!("Received request to switch to Boot protocol mode, but it is disabled by default.");
563 Some(OutResponse::Rejected)
564 }
490 } 565 }
491 } 566 }
492 _ => Some(OutResponse::Rejected), 567 _ => Some(OutResponse::Rejected),
@@ -539,8 +614,12 @@ impl<'d> Handler for Control<'d> {
539 } 614 }
540 } 615 }
541 HID_REQ_GET_PROTOCOL => { 616 HID_REQ_GET_PROTOCOL => {
542 // UNSUPPORTED: Boot Protocol 617 if let Some(request_handler) = self.request_handler.as_mut() {
543 buf[0] = 1; 618 buf[0] = request_handler.get_protocol() as u8;
619 } else {
620 // Return `Report` protocol mode by default
621 buf[0] = HidProtocolMode::Report as u8;
622 }
544 Some(InResponse::Accepted(&buf[0..1])) 623 Some(InResponse::Accepted(&buf[0..1]))
545 } 624 }
546 _ => Some(InResponse::Rejected), 625 _ => Some(InResponse::Rejected),
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 1cd730503..7b7303526 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -13,7 +13,9 @@ use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
13use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 13use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
14use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 14use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::signal::Signal; 15use embassy_sync::signal::Signal;
16use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 16use embassy_usb::class::hid::{
17 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
18};
17use embassy_usb::control::OutResponse; 19use embassy_usb::control::OutResponse;
18use embassy_usb::{Builder, Config, Handler}; 20use embassy_usb::{Builder, Config, Handler};
19use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 21use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -26,6 +28,8 @@ bind_interrupts!(struct Irqs {
26 28
27static SUSPENDED: AtomicBool = AtomicBool::new(false); 29static SUSPENDED: AtomicBool = AtomicBool::new(false);
28 30
31static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
32
29#[embassy_executor::main] 33#[embassy_executor::main]
30async fn main(_spawner: Spawner) { 34async fn main(_spawner: Spawner) {
31 let p = embassy_nrf::init(Default::default()); 35 let p = embassy_nrf::init(Default::default());
@@ -45,6 +49,10 @@ async fn main(_spawner: Spawner) {
45 config.max_power = 100; 49 config.max_power = 100;
46 config.max_packet_size_0 = 64; 50 config.max_packet_size_0 = 64;
47 config.supports_remote_wakeup = true; 51 config.supports_remote_wakeup = true;
52 config.composite_with_iads = false;
53 config.device_class = 0;
54 config.device_sub_class = 0;
55 config.device_protocol = 0;
48 56
49 // Create embassy-usb DeviceBuilder using the driver and config. 57 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors. 58 // It needs some buffers for building the descriptors.
@@ -74,6 +82,8 @@ async fn main(_spawner: Spawner) {
74 request_handler: None, 82 request_handler: None,
75 poll_ms: 60, 83 poll_ms: 60,
76 max_packet_size: 64, 84 max_packet_size: 64,
85 hid_subclass: HidSubclass::Boot,
86 hid_boot_protocol: HidBootProtocol::Keyboard,
77 }; 87 };
78 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 88 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
79 89
@@ -106,6 +116,11 @@ async fn main(_spawner: Spawner) {
106 if SUSPENDED.load(Ordering::Acquire) { 116 if SUSPENDED.load(Ordering::Acquire) {
107 info!("Triggering remote wakeup"); 117 info!("Triggering remote wakeup");
108 remote_wakeup.signal(()); 118 remote_wakeup.signal(());
119 } else if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
120 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
121 Ok(()) => {}
122 Err(e) => warn!("Failed to send boot report: {:?}", e),
123 };
109 } else { 124 } else {
110 let report = KeyboardReport { 125 let report = KeyboardReport {
111 keycodes: [4, 0, 0, 0, 0, 0], 126 keycodes: [4, 0, 0, 0, 0, 0],
@@ -121,16 +136,23 @@ async fn main(_spawner: Spawner) {
121 136
122 button.wait_for_high().await; 137 button.wait_for_high().await;
123 info!("RELEASED"); 138 info!("RELEASED");
124 let report = KeyboardReport { 139 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
125 keycodes: [0, 0, 0, 0, 0, 0], 140 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
126 leds: 0, 141 Ok(()) => {}
127 modifier: 0, 142 Err(e) => warn!("Failed to send boot report: {:?}", e),
128 reserved: 0, 143 };
129 }; 144 } else {
130 match writer.write_serialize(&report).await { 145 let report = KeyboardReport {
131 Ok(()) => {} 146 keycodes: [0, 0, 0, 0, 0, 0],
132 Err(e) => warn!("Failed to send report: {:?}", e), 147 leds: 0,
133 }; 148 modifier: 0,
149 reserved: 0,
150 };
151 match writer.write_serialize(&report).await {
152 Ok(()) => {}
153 Err(e) => warn!("Failed to send report: {:?}", e),
154 };
155 }
134 } 156 }
135 }; 157 };
136 158
@@ -156,6 +178,18 @@ impl RequestHandler for MyRequestHandler {
156 OutResponse::Accepted 178 OutResponse::Accepted
157 } 179 }
158 180
181 fn get_protocol(&self) -> HidProtocolMode {
182 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
183 info!("The current HID protocol mode is: {}", protocol);
184 protocol
185 }
186
187 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
188 info!("Switching to HID protocol mode: {}", protocol);
189 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
190 OutResponse::Accepted
191 }
192
159 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 193 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
160 info!("Set idle rate for {:?} to {:?}", id, dur); 194 info!("Set idle rate for {:?} to {:?}", id, dur);
161 } 195 }
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index 3c0fc04e8..6bee4546b 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicU8, Ordering};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_futures::join::join; 8use embassy_futures::join::join;
@@ -8,7 +10,9 @@ use embassy_nrf::usb::Driver;
8use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; 10use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
9use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 11use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
10use embassy_time::Timer; 12use embassy_time::Timer;
11use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
15};
12use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
13use embassy_usb::{Builder, Config}; 17use embassy_usb::{Builder, Config};
14use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
@@ -19,6 +23,8 @@ bind_interrupts!(struct Irqs {
19 CLOCK_POWER => usb::vbus_detect::InterruptHandler; 23 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
20}); 24});
21 25
26static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
27
22#[embassy_executor::main] 28#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 29async fn main(_spawner: Spawner) {
24 let p = embassy_nrf::init(Default::default()); 30 let p = embassy_nrf::init(Default::default());
@@ -37,6 +43,10 @@ async fn main(_spawner: Spawner) {
37 config.serial_number = Some("12345678"); 43 config.serial_number = Some("12345678");
38 config.max_power = 100; 44 config.max_power = 100;
39 config.max_packet_size_0 = 64; 45 config.max_packet_size_0 = 64;
46 config.composite_with_iads = false;
47 config.device_class = 0;
48 config.device_sub_class = 0;
49 config.device_protocol = 0;
40 50
41 // Create embassy-usb DeviceBuilder using the driver and config. 51 // Create embassy-usb DeviceBuilder using the driver and config.
42 // It needs some buffers for building the descriptors. 52 // It needs some buffers for building the descriptors.
@@ -63,6 +73,8 @@ async fn main(_spawner: Spawner) {
63 request_handler: Some(&mut request_handler), 73 request_handler: Some(&mut request_handler),
64 poll_ms: 60, 74 poll_ms: 60,
65 max_packet_size: 8, 75 max_packet_size: 8,
76 hid_subclass: HidSubclass::Boot,
77 hid_boot_protocol: HidBootProtocol::Mouse,
66 }; 78 };
67 79
68 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); 80 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
@@ -80,16 +92,26 @@ async fn main(_spawner: Spawner) {
80 Timer::after_millis(500).await; 92 Timer::after_millis(500).await;
81 93
82 y = -y; 94 y = -y;
83 let report = MouseReport { 95
84 buttons: 0, 96 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
85 x: 0, 97 let buttons = 0u8;
86 y, 98 let x = 0i8;
87 wheel: 0, 99 match writer.write(&[buttons, x as u8, y as u8]).await {
88 pan: 0, 100 Ok(()) => {}
89 }; 101 Err(e) => warn!("Failed to send boot report: {:?}", e),
90 match writer.write_serialize(&report).await { 102 }
91 Ok(()) => {} 103 } else {
92 Err(e) => warn!("Failed to send report: {:?}", e), 104 let report = MouseReport {
105 buttons: 0,
106 x: 0,
107 y,
108 wheel: 0,
109 pan: 0,
110 };
111 match writer.write_serialize(&report).await {
112 Ok(()) => {}
113 Err(e) => warn!("Failed to send report: {:?}", e),
114 }
93 } 115 }
94 } 116 }
95 }; 117 };
@@ -112,6 +134,18 @@ impl RequestHandler for MyRequestHandler {
112 OutResponse::Accepted 134 OutResponse::Accepted
113 } 135 }
114 136
137 fn get_protocol(&self) -> HidProtocolMode {
138 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
139 info!("The current HID protocol mode is: {}", protocol);
140 protocol
141 }
142
143 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
144 info!("Switching to HID protocol mode: {}", protocol);
145 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
146 OutResponse::Accepted
147 }
148
115 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 149 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
116 info!("Set idle rate for {:?} to {:?}", id, dur); 150 info!("Set idle rate for {:?} to {:?}", id, dur);
117 } 151 }
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs
index a7cb322d8..2f6d169bf 100644
--- a/examples/rp/src/bin/usb_hid_keyboard.rs
+++ b/examples/rp/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -10,7 +10,9 @@ use embassy_rp::bind_interrupts;
10use embassy_rp::gpio::{Input, Pull}; 10use embassy_rp::gpio::{Input, Pull};
11use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver, InterruptHandler}; 12use embassy_rp::usb::{Driver, InterruptHandler};
13use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
15};
14use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
15use embassy_usb::{Builder, Config, Handler}; 17use embassy_usb::{Builder, Config, Handler};
16use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -20,6 +22,8 @@ bind_interrupts!(struct Irqs {
20 USBCTRL_IRQ => InterruptHandler<USB>; 22 USBCTRL_IRQ => InterruptHandler<USB>;
21}); 23});
22 24
25static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
26
23#[embassy_executor::main] 27#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 28async fn main(_spawner: Spawner) {
25 let p = embassy_rp::init(Default::default()); 29 let p = embassy_rp::init(Default::default());
@@ -33,6 +37,10 @@ async fn main(_spawner: Spawner) {
33 config.serial_number = Some("12345678"); 37 config.serial_number = Some("12345678");
34 config.max_power = 100; 38 config.max_power = 100;
35 config.max_packet_size_0 = 64; 39 config.max_packet_size_0 = 64;
40 config.composite_with_iads = false;
41 config.device_class = 0;
42 config.device_sub_class = 0;
43 config.device_protocol = 0;
36 44
37 // Create embassy-usb DeviceBuilder using the driver and config. 45 // Create embassy-usb DeviceBuilder using the driver and config.
38 // It needs some buffers for building the descriptors. 46 // It needs some buffers for building the descriptors.
@@ -63,6 +71,8 @@ async fn main(_spawner: Spawner) {
63 request_handler: None, 71 request_handler: None,
64 poll_ms: 60, 72 poll_ms: 60,
65 max_packet_size: 64, 73 max_packet_size: 64,
74 hid_subclass: HidSubclass::Boot,
75 hid_boot_protocol: HidBootProtocol::Keyboard,
66 }; 76 };
67 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 77 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
68 78
@@ -86,30 +96,46 @@ async fn main(_spawner: Spawner) {
86 info!("Waiting for HIGH on pin 16"); 96 info!("Waiting for HIGH on pin 16");
87 signal_pin.wait_for_high().await; 97 signal_pin.wait_for_high().await;
88 info!("HIGH DETECTED"); 98 info!("HIGH DETECTED");
89 // Create a report with the A key pressed. (no shift modifier) 99
90 let report = KeyboardReport { 100 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
91 keycodes: [4, 0, 0, 0, 0, 0], 101 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
92 leds: 0, 102 Ok(()) => {}
93 modifier: 0, 103 Err(e) => warn!("Failed to send boot report: {:?}", e),
94 reserved: 0, 104 };
95 }; 105 } else {
96 // Send the report. 106 // Create a report with the A key pressed. (no shift modifier)
97 match writer.write_serialize(&report).await { 107 let report = KeyboardReport {
98 Ok(()) => {} 108 keycodes: [4, 0, 0, 0, 0, 0],
99 Err(e) => warn!("Failed to send report: {:?}", e), 109 leds: 0,
100 }; 110 modifier: 0,
111 reserved: 0,
112 };
113 // Send the report.
114 match writer.write_serialize(&report).await {
115 Ok(()) => {}
116 Err(e) => warn!("Failed to send report: {:?}", e),
117 };
118 }
119
101 signal_pin.wait_for_low().await; 120 signal_pin.wait_for_low().await;
102 info!("LOW DETECTED"); 121 info!("LOW DETECTED");
103 let report = KeyboardReport { 122 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
104 keycodes: [0, 0, 0, 0, 0, 0], 123 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
105 leds: 0, 124 Ok(()) => {}
106 modifier: 0, 125 Err(e) => warn!("Failed to send boot report: {:?}", e),
107 reserved: 0, 126 };
108 }; 127 } else {
109 match writer.write_serialize(&report).await { 128 let report = KeyboardReport {
110 Ok(()) => {} 129 keycodes: [0, 0, 0, 0, 0, 0],
111 Err(e) => warn!("Failed to send report: {:?}", e), 130 leds: 0,
112 }; 131 modifier: 0,
132 reserved: 0,
133 };
134 match writer.write_serialize(&report).await {
135 Ok(()) => {}
136 Err(e) => warn!("Failed to send report: {:?}", e),
137 };
138 }
113 } 139 }
114 }; 140 };
115 141
@@ -135,6 +161,18 @@ impl RequestHandler for MyRequestHandler {
135 OutResponse::Accepted 161 OutResponse::Accepted
136 } 162 }
137 163
164 fn get_protocol(&self) -> HidProtocolMode {
165 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
166 info!("The current HID protocol mode is: {}", protocol);
167 protocol
168 }
169
170 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
171 info!("Switching to HID protocol mode: {}", protocol);
172 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
173 OutResponse::Accepted
174 }
175
138 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 176 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
139 info!("Set idle rate for {:?} to {:?}", id, dur); 177 info!("Set idle rate for {:?} to {:?}", id, dur);
140 } 178 }
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs
index 4454c593c..dc331cbdd 100755
--- a/examples/rp/src/bin/usb_hid_mouse.rs
+++ b/examples/rp/src/bin/usb_hid_mouse.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -11,7 +11,9 @@ use embassy_rp::clocks::RoscRng;
11use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver, InterruptHandler}; 12use embassy_rp::usb::{Driver, InterruptHandler};
13use embassy_time::Timer; 13use embassy_time::Timer;
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
16};
15use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Config, Handler}; 18use embassy_usb::{Builder, Config, Handler};
17use rand::Rng; 19use rand::Rng;
@@ -22,6 +24,8 @@ bind_interrupts!(struct Irqs {
22 USBCTRL_IRQ => InterruptHandler<USB>; 24 USBCTRL_IRQ => InterruptHandler<USB>;
23}); 25});
24 26
27static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
28
25#[embassy_executor::main] 29#[embassy_executor::main]
26async fn main(_spawner: Spawner) { 30async fn main(_spawner: Spawner) {
27 let p = embassy_rp::init(Default::default()); 31 let p = embassy_rp::init(Default::default());
@@ -35,6 +39,10 @@ async fn main(_spawner: Spawner) {
35 config.serial_number = Some("12345678"); 39 config.serial_number = Some("12345678");
36 config.max_power = 100; 40 config.max_power = 100;
37 config.max_packet_size_0 = 64; 41 config.max_packet_size_0 = 64;
42 config.composite_with_iads = false;
43 config.device_class = 0;
44 config.device_sub_class = 0;
45 config.device_protocol = 0;
38 46
39 // Create embassy-usb DeviceBuilder using the driver and config. 47 // Create embassy-usb DeviceBuilder using the driver and config.
40 // It needs some buffers for building the descriptors. 48 // It needs some buffers for building the descriptors.
@@ -65,6 +73,8 @@ async fn main(_spawner: Spawner) {
65 request_handler: None, 73 request_handler: None,
66 poll_ms: 60, 74 poll_ms: 60,
67 max_packet_size: 64, 75 max_packet_size: 64,
76 hid_subclass: HidSubclass::Boot,
77 hid_boot_protocol: HidBootProtocol::Mouse,
68 }; 78 };
69 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 79 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
70 80
@@ -83,17 +93,29 @@ async fn main(_spawner: Spawner) {
83 loop { 93 loop {
84 // every 1 second 94 // every 1 second
85 _ = Timer::after_secs(1).await; 95 _ = Timer::after_secs(1).await;
86 let report = MouseReport { 96
87 buttons: 0, 97 let x = rng.random_range(-100..100); // random small x movement
88 x: rng.random_range(-100..100), // random small x movement 98 let y = rng.random_range(-100..100); // random small y movement
89 y: rng.random_range(-100..100), // random small y movement 99
90 wheel: 0, 100 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
91 pan: 0, 101 let buttons = 0u8;
92 }; 102 match writer.write(&[buttons, x as u8, y as u8]).await {
93 // Send the report. 103 Ok(()) => {}
94 match writer.write_serialize(&report).await { 104 Err(e) => warn!("Failed to send boot report: {:?}", e),
95 Ok(()) => {} 105 }
96 Err(e) => warn!("Failed to send report: {:?}", e), 106 } else {
107 let report = MouseReport {
108 buttons: 0,
109 x,
110 y,
111 wheel: 0,
112 pan: 0,
113 };
114 // Send the report.
115 match writer.write_serialize(&report).await {
116 Ok(()) => {}
117 Err(e) => warn!("Failed to send report: {:?}", e),
118 }
97 } 119 }
98 } 120 }
99 }; 121 };
@@ -120,6 +142,18 @@ impl RequestHandler for MyRequestHandler {
120 OutResponse::Accepted 142 OutResponse::Accepted
121 } 143 }
122 144
145 fn get_protocol(&self) -> HidProtocolMode {
146 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
147 info!("The current HID protocol mode is: {}", protocol);
148 protocol
149 }
150
151 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
152 info!("Switching to HID protocol mode: {}", protocol);
153 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
154 OutResponse::Accepted
155 }
156
123 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 157 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
124 info!("Set idle rate for {:?} to {:?}", id, dur); 158 info!("Set idle rate for {:?} to {:?}", id, dur);
125 } 159 }
diff --git a/examples/rp235x/src/bin/usb_hid_keyboard.rs b/examples/rp235x/src/bin/usb_hid_keyboard.rs
index 6f496e23a..d8f64c470 100644
--- a/examples/rp235x/src/bin/usb_hid_keyboard.rs
+++ b/examples/rp235x/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -10,7 +10,9 @@ use embassy_rp::bind_interrupts;
10use embassy_rp::gpio::{Input, Pull}; 10use embassy_rp::gpio::{Input, Pull};
11use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; 12use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler};
13use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State as HidState}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State as HidState,
15};
14use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
15use embassy_usb::{Builder, Config, Handler}; 17use embassy_usb::{Builder, Config, Handler};
16use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -20,6 +22,8 @@ bind_interrupts!(struct Irqs {
20 USBCTRL_IRQ => InterruptHandler<USB>; 22 USBCTRL_IRQ => InterruptHandler<USB>;
21}); 23});
22 24
25static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
26
23#[embassy_executor::main] 27#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 28async fn main(_spawner: Spawner) {
25 let p = embassy_rp::init(Default::default()); 29 let p = embassy_rp::init(Default::default());
@@ -33,6 +37,10 @@ async fn main(_spawner: Spawner) {
33 config.serial_number = Some("12345678"); 37 config.serial_number = Some("12345678");
34 config.max_power = 100; 38 config.max_power = 100;
35 config.max_packet_size_0 = 64; 39 config.max_packet_size_0 = 64;
40 config.composite_with_iads = false;
41 config.device_class = 0;
42 config.device_sub_class = 0;
43 config.device_protocol = 0;
36 44
37 // Create embassy-usb DeviceBuilder using the driver and config. 45 // Create embassy-usb DeviceBuilder using the driver and config.
38 // It needs some buffers for building the descriptors. 46 // It needs some buffers for building the descriptors.
@@ -63,6 +71,8 @@ async fn main(_spawner: Spawner) {
63 request_handler: None, 71 request_handler: None,
64 poll_ms: 60, 72 poll_ms: 60,
65 max_packet_size: 64, 73 max_packet_size: 64,
74 hid_subclass: HidSubclass::Boot,
75 hid_boot_protocol: HidBootProtocol::Keyboard,
66 }; 76 };
67 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 77 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
68 78
@@ -86,30 +96,45 @@ async fn main(_spawner: Spawner) {
86 info!("Waiting for HIGH on pin 16"); 96 info!("Waiting for HIGH on pin 16");
87 signal_pin.wait_for_high().await; 97 signal_pin.wait_for_high().await;
88 info!("HIGH DETECTED"); 98 info!("HIGH DETECTED");
89 // Create a report with the A key pressed. (no shift modifier) 99
90 let report = KeyboardReport { 100 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
91 keycodes: [4, 0, 0, 0, 0, 0], 101 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
92 leds: 0, 102 Ok(()) => {}
93 modifier: 0, 103 Err(e) => warn!("Failed to send boot report: {:?}", e),
94 reserved: 0, 104 };
95 }; 105 } else {
96 // Send the report. 106 // Create a report with the A key pressed. (no shift modifier)
97 match writer.write_serialize(&report).await { 107 let report = KeyboardReport {
98 Ok(()) => {} 108 keycodes: [4, 0, 0, 0, 0, 0],
99 Err(e) => warn!("Failed to send report: {:?}", e), 109 leds: 0,
100 }; 110 modifier: 0,
111 reserved: 0,
112 };
113 // Send the report.
114 match writer.write_serialize(&report).await {
115 Ok(()) => {}
116 Err(e) => warn!("Failed to send report: {:?}", e),
117 };
118 }
101 signal_pin.wait_for_low().await; 119 signal_pin.wait_for_low().await;
102 info!("LOW DETECTED"); 120 info!("LOW DETECTED");
103 let report = KeyboardReport { 121 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
104 keycodes: [0, 0, 0, 0, 0, 0], 122 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
105 leds: 0, 123 Ok(()) => {}
106 modifier: 0, 124 Err(e) => warn!("Failed to send boot report: {:?}", e),
107 reserved: 0, 125 };
108 }; 126 } else {
109 match writer.write_serialize(&report).await { 127 let report = KeyboardReport {
110 Ok(()) => {} 128 keycodes: [0, 0, 0, 0, 0, 0],
111 Err(e) => warn!("Failed to send report: {:?}", e), 129 leds: 0,
112 }; 130 modifier: 0,
131 reserved: 0,
132 };
133 match writer.write_serialize(&report).await {
134 Ok(()) => {}
135 Err(e) => warn!("Failed to send report: {:?}", e),
136 };
137 }
113 } 138 }
114 }; 139 };
115 140
@@ -135,6 +160,18 @@ impl RequestHandler for MyRequestHandler {
135 OutResponse::Accepted 160 OutResponse::Accepted
136 } 161 }
137 162
163 fn get_protocol(&self) -> HidProtocolMode {
164 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
165 info!("The current HID protocol mode is: {}", protocol);
166 protocol
167 }
168
169 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
170 info!("Switching to HID protocol mode: {}", protocol);
171 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
172 OutResponse::Accepted
173 }
174
138 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 175 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
139 info!("Set idle rate for {:?} to {:?}", id, dur); 176 info!("Set idle rate for {:?} to {:?}", id, dur);
140 } 177 }
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 5628cb827..694e85657 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let mut delay = Delay; 16 let mut delay = Delay;
17 let mut adc = Adc::new(p.ADC1); 17 let mut adc = Adc::new_with_config(p.ADC1, Default::default());
18 let mut pin = p.PC1; 18 let mut pin = p.PC1;
19 19
20 let mut vrefint = adc.enable_vrefint(); 20 let mut vrefint = adc.enable_vrefint();
diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs
index 01b881c79..d61b1b2eb 100644
--- a/examples/stm32f4/src/bin/adc_dma.rs
+++ b/examples/stm32f4/src/bin/adc_dma.rs
@@ -4,7 +4,7 @@ use cortex_m::singleton;
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::Peripherals; 6use embassy_stm32::Peripherals;
7use embassy_stm32::adc::{Adc, AdcChannel, RingBufferedAdc, SampleTime}; 7use embassy_stm32::adc::{Adc, AdcChannel, RegularConversionMode, RingBufferedAdc, SampleTime};
8use embassy_time::Instant; 8use embassy_time::Instant;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -20,8 +20,8 @@ async fn adc_task(p: Peripherals) {
20 let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); 20 let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
21 let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap(); 21 let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
22 22
23 let adc = Adc::new(p.ADC1); 23 let adc = Adc::new_with_config(p.ADC1, Default::default());
24 let adc2 = Adc::new(p.ADC2); 24 let adc2 = Adc::new_with_config(p.ADC2, Default::default());
25 25
26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered( 26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
27 p.DMA2_CH0, 27 p.DMA2_CH0,
@@ -31,6 +31,7 @@ async fn adc_task(p: Peripherals) {
31 (p.PA2.degrade_adc(), SampleTime::CYCLES112), 31 (p.PA2.degrade_adc(), SampleTime::CYCLES112),
32 ] 32 ]
33 .into_iter(), 33 .into_iter(),
34 RegularConversionMode::Continuous,
34 ); 35 );
35 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered( 36 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(
36 p.DMA2_CH2, 37 p.DMA2_CH2,
@@ -40,6 +41,7 @@ async fn adc_task(p: Peripherals) {
40 (p.PA3.degrade_adc(), SampleTime::CYCLES112), 41 (p.PA3.degrade_adc(), SampleTime::CYCLES112),
41 ] 42 ]
42 .into_iter(), 43 .into_iter(),
44 RegularConversionMode::Continuous,
43 ); 45 );
44 46
45 // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around 47 // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index a3afb887c..9971e43f5 100644
--- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicBool, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -11,7 +11,9 @@ use embassy_stm32::gpio::Pull;
11use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
12use embassy_stm32::usb::Driver; 12use embassy_stm32::usb::Driver;
13use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; 13use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
16};
15use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Handler}; 18use embassy_usb::{Builder, Handler};
17use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 19use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -21,6 +23,8 @@ bind_interrupts!(struct Irqs {
21 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; 23 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
22}); 24});
23 25
26static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
27
24// If you are trying this and your USB device doesn't connect, the most 28// If you are trying this and your USB device doesn't connect, the most
25// common issues are the RCC config and vbus_detection 29// common issues are the RCC config and vbus_detection
26// 30//
@@ -70,6 +74,10 @@ async fn main(_spawner: Spawner) {
70 config.serial_number = Some("12345678"); 74 config.serial_number = Some("12345678");
71 config.max_power = 100; 75 config.max_power = 100;
72 config.max_packet_size_0 = 64; 76 config.max_packet_size_0 = 64;
77 config.composite_with_iads = false;
78 config.device_class = 0;
79 config.device_sub_class = 0;
80 config.device_protocol = 0;
73 81
74 // Create embassy-usb DeviceBuilder using the driver and config. 82 // Create embassy-usb DeviceBuilder using the driver and config.
75 // It needs some buffers for building the descriptors. 83 // It needs some buffers for building the descriptors.
@@ -101,6 +109,8 @@ async fn main(_spawner: Spawner) {
101 request_handler: None, 109 request_handler: None,
102 poll_ms: 60, 110 poll_ms: 60,
103 max_packet_size: 8, 111 max_packet_size: 8,
112 hid_subclass: HidSubclass::Boot,
113 hid_boot_protocol: HidBootProtocol::Keyboard,
104 }; 114 };
105 115
106 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 116 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
@@ -121,32 +131,46 @@ async fn main(_spawner: Spawner) {
121 button.wait_for_rising_edge().await; 131 button.wait_for_rising_edge().await;
122 // signal_pin.wait_for_high().await; 132 // signal_pin.wait_for_high().await;
123 info!("Button pressed!"); 133 info!("Button pressed!");
124 // Create a report with the A key pressed. (no shift modifier) 134 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
125 let report = KeyboardReport { 135 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
126 keycodes: [4, 0, 0, 0, 0, 0], 136 Ok(()) => {}
127 leds: 0, 137 Err(e) => warn!("Failed to send boot report: {:?}", e),
128 modifier: 0, 138 };
129 reserved: 0, 139 } else {
130 }; 140 // Create a report with the A key pressed. (no shift modifier)
131 // Send the report. 141 let report = KeyboardReport {
132 match writer.write_serialize(&report).await { 142 keycodes: [4, 0, 0, 0, 0, 0],
133 Ok(()) => {} 143 leds: 0,
134 Err(e) => warn!("Failed to send report: {:?}", e), 144 modifier: 0,
135 }; 145 reserved: 0,
146 };
147 // Send the report.
148 match writer.write_serialize(&report).await {
149 Ok(()) => {}
150 Err(e) => warn!("Failed to send report: {:?}", e),
151 };
152 }
136 153
137 button.wait_for_falling_edge().await; 154 button.wait_for_falling_edge().await;
138 // signal_pin.wait_for_low().await; 155 // signal_pin.wait_for_low().await;
139 info!("Button released!"); 156 info!("Button released!");
140 let report = KeyboardReport { 157 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
141 keycodes: [0, 0, 0, 0, 0, 0], 158 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
142 leds: 0, 159 Ok(()) => {}
143 modifier: 0, 160 Err(e) => warn!("Failed to send boot report: {:?}", e),
144 reserved: 0, 161 };
145 }; 162 } else {
146 match writer.write_serialize(&report).await { 163 let report = KeyboardReport {
147 Ok(()) => {} 164 keycodes: [0, 0, 0, 0, 0, 0],
148 Err(e) => warn!("Failed to send report: {:?}", e), 165 leds: 0,
149 }; 166 modifier: 0,
167 reserved: 0,
168 };
169 match writer.write_serialize(&report).await {
170 Ok(()) => {}
171 Err(e) => warn!("Failed to send report: {:?}", e),
172 };
173 }
150 } 174 }
151 }; 175 };
152 176
@@ -172,6 +196,18 @@ impl RequestHandler for MyRequestHandler {
172 OutResponse::Accepted 196 OutResponse::Accepted
173 } 197 }
174 198
199 fn get_protocol(&self) -> HidProtocolMode {
200 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
201 info!("The current HID protocol mode is: {}", protocol);
202 protocol
203 }
204
205 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
206 info!("Switching to HID protocol mode: {}", protocol);
207 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
208 OutResponse::Accepted
209 }
210
175 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 211 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
176 info!("Set idle rate for {:?} to {:?}", id, dur); 212 info!("Set idle rate for {:?} to {:?}", id, dur);
177 } 213 }
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
index 162a035f2..e83d01f88 100644
--- a/examples/stm32f4/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicU8, Ordering};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_futures::join::join; 8use embassy_futures::join::join;
@@ -9,7 +11,9 @@ use embassy_stm32::usb::Driver;
9use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; 11use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
10use embassy_time::Timer; 12use embassy_time::Timer;
11use embassy_usb::Builder; 13use embassy_usb::Builder;
12use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 14use embassy_usb::class::hid::{
15 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
16};
13use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
14use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
15use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
@@ -18,6 +22,8 @@ bind_interrupts!(struct Irqs {
18 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; 22 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>;
19}); 23});
20 24
25static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
26
21// If you are trying this and your USB device doesn't connect, the most 27// If you are trying this and your USB device doesn't connect, the most
22// common issues are the RCC config and vbus_detection 28// common issues are the RCC config and vbus_detection
23// 29//
@@ -65,6 +71,10 @@ async fn main(_spawner: Spawner) {
65 config.manufacturer = Some("Embassy"); 71 config.manufacturer = Some("Embassy");
66 config.product = Some("HID mouse example"); 72 config.product = Some("HID mouse example");
67 config.serial_number = Some("12345678"); 73 config.serial_number = Some("12345678");
74 config.composite_with_iads = false;
75 config.device_class = 0;
76 config.device_sub_class = 0;
77 config.device_protocol = 0;
68 78
69 // Create embassy-usb DeviceBuilder using the driver and config. 79 // Create embassy-usb DeviceBuilder using the driver and config.
70 // It needs some buffers for building the descriptors. 80 // It needs some buffers for building the descriptors.
@@ -91,6 +101,8 @@ async fn main(_spawner: Spawner) {
91 request_handler: Some(&mut request_handler), 101 request_handler: Some(&mut request_handler),
92 poll_ms: 60, 102 poll_ms: 60,
93 max_packet_size: 8, 103 max_packet_size: 8,
104 hid_subclass: HidSubclass::Boot,
105 hid_boot_protocol: HidBootProtocol::Mouse,
94 }; 106 };
95 107
96 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); 108 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
@@ -108,16 +120,26 @@ async fn main(_spawner: Spawner) {
108 Timer::after_millis(500).await; 120 Timer::after_millis(500).await;
109 121
110 y = -y; 122 y = -y;
111 let report = MouseReport { 123
112 buttons: 0, 124 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
113 x: 0, 125 let buttons = 0u8;
114 y, 126 let x = 0i8;
115 wheel: 0, 127 match writer.write(&[buttons, x as u8, y as u8]).await {
116 pan: 0, 128 Ok(()) => {}
117 }; 129 Err(e) => warn!("Failed to send boot report: {:?}", e),
118 match writer.write_serialize(&report).await { 130 }
119 Ok(()) => {} 131 } else {
120 Err(e) => warn!("Failed to send report: {:?}", e), 132 let report = MouseReport {
133 buttons: 0,
134 x: 0,
135 y,
136 wheel: 0,
137 pan: 0,
138 };
139 match writer.write_serialize(&report).await {
140 Ok(()) => {}
141 Err(e) => warn!("Failed to send report: {:?}", e),
142 }
121 } 143 }
122 } 144 }
123 }; 145 };
@@ -140,6 +162,18 @@ impl RequestHandler for MyRequestHandler {
140 OutResponse::Accepted 162 OutResponse::Accepted
141 } 163 }
142 164
165 fn get_protocol(&self) -> HidProtocolMode {
166 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
167 info!("The current HID protocol mode is: {}", protocol);
168 protocol
169 }
170
171 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
172 info!("Switching to HID protocol mode: {}", protocol);
173 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
174 OutResponse::Accepted
175 }
176
143 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 177 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
144 info!("Set idle rate for {:?} to {:?}", id, dur); 178 info!("Set idle rate for {:?} to {:?}", id, dur);
145 } 179 }
diff --git a/examples/stm32g0/src/bin/adc_oversampling.rs b/examples/stm32g0/src/bin/adc_oversampling.rs
index f6979889d..aa8b1771b 100644
--- a/examples/stm32g0/src/bin/adc_oversampling.rs
+++ b/examples/stm32g0/src/bin/adc_oversampling.rs
@@ -7,7 +7,7 @@
7 7
8use defmt::*; 8use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::adc::{Adc, Clock, Ovsr, Ovss, Presc, SampleTime}; 10use embassy_stm32::adc::{Adc, AdcConfig, Clock, Ovsr, Ovss, Presc, SampleTime};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
@@ -16,12 +16,14 @@ async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default()); 16 let p = embassy_stm32::init(Default::default());
17 info!("Adc oversample test"); 17 info!("Adc oversample test");
18 18
19 let mut adc = Adc::new_with_clock(p.ADC1, Clock::Async { div: Presc::DIV1 }); 19 let mut config = AdcConfig::default();
20 let mut pin = p.PA1; 20 config.clock = Some(Clock::Async { div: Presc::DIV1 });
21 config.oversampling_ratio = Some(Ovsr::MUL16);
22 config.oversampling_shift = Some(Ovss::NO_SHIFT);
23 config.oversampling_enable = Some(true);
21 24
22 adc.set_oversampling_ratio(Ovsr::MUL16); 25 let mut adc = Adc::new_with_config(p.ADC1, config);
23 adc.set_oversampling_shift(Ovss::NO_SHIFT); 26 let mut pin = p.PA1;
24 adc.oversampling_enable(true);
25 27
26 loop { 28 loop {
27 let v = adc.blocking_read(&mut pin, SampleTime::CYCLES1_5); 29 let v = adc.blocking_read(&mut pin, SampleTime::CYCLES1_5);
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 695f37115..2149e0748 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -28,11 +28,16 @@ async fn main(_spawner: Spawner) {
28 let mut p = embassy_stm32::init(config); 28 let mut p = embassy_stm32::init(config);
29 info!("Hello World!"); 29 info!("Hello World!");
30 30
31 let mut adc = Adc::new(p.ADC2); 31 let mut adc = Adc::new(p.ADC2, Default::default());
32
33 let mut adc_temp = Adc::new(p.ADC1, Default::default());
34 let mut temperature = adc_temp.enable_temperature();
32 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..6dedf88d6 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, Default::default());
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 }
diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs
index ef8b0c3c2..478b6b2ca 100644
--- a/examples/stm32g4/src/bin/adc_dma.rs
+++ b/examples/stm32g4/src/bin/adc_dma.rs
@@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) {
33 33
34 info!("Hello World!"); 34 info!("Hello World!");
35 35
36 let mut adc = Adc::new(p.ADC1); 36 let mut adc = Adc::new(p.ADC1, Default::default());
37 37
38 let mut dma = p.DMA1_CH1; 38 let mut dma = p.DMA1_CH1;
39 let mut vrefint_channel = adc.enable_vrefint().degrade_adc(); 39 let mut vrefint_channel = adc.enable_vrefint().degrade_adc();
diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs
index 3ae2ff064..1e97fa925 100644
--- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs
+++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs
@@ -77,7 +77,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
77 pwm.set_mms2(Mms2::UPDATE); 77 pwm.set_mms2(Mms2::UPDATE);
78 78
79 // Configure regular conversions with DMA 79 // Configure regular conversions with DMA
80 let adc1 = Adc::new(p.ADC1); 80 let adc1 = Adc::new(p.ADC1, Default::default());
81 81
82 let vrefint_channel = adc1.enable_vrefint().degrade_adc(); 82 let vrefint_channel = adc1.enable_vrefint().degrade_adc();
83 let pa0 = p.PC1.degrade_adc(); 83 let pa0 = p.PC1.degrade_adc();
diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs
index cb99ab2a7..87ffea4be 100644
--- a/examples/stm32g4/src/bin/adc_oversampling.rs
+++ b/examples/stm32g4/src/bin/adc_oversampling.rs
@@ -9,7 +9,7 @@ use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::Config; 10use embassy_stm32::Config;
11use embassy_stm32::adc::vals::{Rovsm, Trovs}; 11use embassy_stm32::adc::vals::{Rovsm, Trovs};
12use embassy_stm32::adc::{Adc, SampleTime}; 12use embassy_stm32::adc::{Adc, AdcConfig, SampleTime};
13use embassy_time::Timer; 13use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
15 15
@@ -32,7 +32,8 @@ async fn main(_spawner: Spawner) {
32 } 32 }
33 let mut p = embassy_stm32::init(config); 33 let mut p = embassy_stm32::init(config);
34 34
35 let mut adc = Adc::new(p.ADC1); 35 let mut config = AdcConfig::default();
36
36 // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf 37 // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
37 // page652 Oversampler 38 // page652 Oversampler
38 // Table 172. Maximum output results vs N and M. Grayed values indicates truncation 39 // Table 172. Maximum output results vs N and M. Grayed values indicates truncation
@@ -44,9 +45,11 @@ async fn main(_spawner: Spawner) {
44 // 0x05 oversampling ratio X64 45 // 0x05 oversampling ratio X64
45 // 0x06 oversampling ratio X128 46 // 0x06 oversampling ratio X128
46 // 0x07 oversampling ratio X256 47 // 0x07 oversampling ratio X256
47 adc.set_oversampling_ratio(0x03); // ratio X3 48 config.oversampling_ratio = Some(0x03); // ratio X3
48 adc.set_oversampling_shift(0b0000); // no shift 49 config.oversampling_shift = Some(0b0000); // no shift
49 adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true); 50 config.oversampling_mode = Some((Rovsm::RESUMED, Trovs::AUTOMATIC, true));
51
52 let mut adc = Adc::new(p.ADC1, config);
50 53
51 loop { 54 loop {
52 let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES6_5); 55 let measured = adc.blocking_read(&mut p.PA0, SampleTime::CYCLES6_5);
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 835bf5411..42766a5e3 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::Config; 5use embassy_stm32::Config;
6use embassy_stm32::adc::{Adc, Resolution, SampleTime}; 6use embassy_stm32::adc::{Adc, AdcConfig, Resolution, SampleTime};
7use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
8 8
9#[cortex_m_rt::entry] 9#[cortex_m_rt::entry]
@@ -17,9 +17,12 @@ fn main() -> ! {
17 } 17 }
18 let p = embassy_stm32::init(config); 18 let p = embassy_stm32::init(config);
19 19
20 let mut adc = Adc::new(p.ADC1); 20 let mut config = AdcConfig::default();
21 config.resolution = Some(Resolution::BITS8);
22
23 let mut adc = Adc::new_with_config(p.ADC1, config);
21 //adc.enable_vref(); 24 //adc.enable_vref();
22 adc.set_resolution(Resolution::BITS8); 25
23 let mut channel = p.PC0; 26 let mut channel = p.PC0;
24 27
25 loop { 28 loop {
diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs
index ab1e9d2e9..550da95a4 100644
--- a/examples/stm32l4/src/bin/adc_dma.rs
+++ b/examples/stm32l4/src/bin/adc_dma.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::Config; 6use embassy_stm32::Config;
7use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; 7use embassy_stm32::adc::{Adc, AdcChannel, RegularConversionMode, SampleTime};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10const DMA_BUF_LEN: usize = 512; 10const DMA_BUF_LEN: usize = 512;
@@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
20 } 20 }
21 let p = embassy_stm32::init(config); 21 let p = embassy_stm32::init(config);
22 22
23 let mut adc = Adc::new(p.ADC1); 23 let adc = Adc::new(p.ADC1);
24 let adc_pin0 = p.PA0.degrade_adc(); 24 let adc_pin0 = p.PA0.degrade_adc();
25 let adc_pin1 = p.PA1.degrade_adc(); 25 let adc_pin1 = p.PA1.degrade_adc();
26 let mut adc_dma_buf = [0u16; DMA_BUF_LEN]; 26 let mut adc_dma_buf = [0u16; DMA_BUF_LEN];
@@ -29,6 +29,7 @@ async fn main(_spawner: Spawner) {
29 p.DMA1_CH1, 29 p.DMA1_CH1,
30 &mut adc_dma_buf, 30 &mut adc_dma_buf,
31 [(adc_pin0, SampleTime::CYCLES640_5), (adc_pin1, SampleTime::CYCLES640_5)].into_iter(), 31 [(adc_pin0, SampleTime::CYCLES640_5), (adc_pin1, SampleTime::CYCLES640_5)].into_iter(),
32 RegularConversionMode::Continuous,
32 ); 33 );
33 34
34 info!("starting measurement loop"); 35 info!("starting measurement loop");
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index b721f5b2e..d8f2de941 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::sync::atomic::{AtomicU8, Ordering};
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_futures::join::join; 8use embassy_futures::join::join;
@@ -8,7 +10,9 @@ use embassy_stm32::usb::Driver;
8use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; 10use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
9use embassy_time::Timer; 11use embassy_time::Timer;
10use embassy_usb::Builder; 12use embassy_usb::Builder;
11use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
15};
12use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
13use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 17use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
14use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
@@ -17,6 +21,8 @@ bind_interrupts!(struct Irqs {
17 USB_FS => usb::InterruptHandler<peripherals::USB>; 21 USB_FS => usb::InterruptHandler<peripherals::USB>;
18}); 22});
19 23
24static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
25
20#[embassy_executor::main] 26#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
22 let mut config = Config::default(); 28 let mut config = Config::default();
@@ -48,6 +54,10 @@ async fn main(_spawner: Spawner) {
48 config.serial_number = Some("12345678"); 54 config.serial_number = Some("12345678");
49 config.max_power = 100; 55 config.max_power = 100;
50 config.max_packet_size_0 = 64; 56 config.max_packet_size_0 = 64;
57 config.composite_with_iads = false;
58 config.device_class = 0;
59 config.device_sub_class = 0;
60 config.device_protocol = 0;
51 61
52 // Create embassy-usb DeviceBuilder using the driver and config. 62 // Create embassy-usb DeviceBuilder using the driver and config.
53 // It needs some buffers for building the descriptors. 63 // It needs some buffers for building the descriptors.
@@ -73,6 +83,8 @@ async fn main(_spawner: Spawner) {
73 request_handler: Some(&mut request_handler), 83 request_handler: Some(&mut request_handler),
74 poll_ms: 60, 84 poll_ms: 60,
75 max_packet_size: 8, 85 max_packet_size: 8,
86 hid_subclass: HidSubclass::Boot,
87 hid_boot_protocol: HidBootProtocol::Mouse,
76 }; 88 };
77 89
78 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); 90 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
@@ -90,16 +102,26 @@ async fn main(_spawner: Spawner) {
90 Timer::after_millis(500).await; 102 Timer::after_millis(500).await;
91 103
92 y = -y; 104 y = -y;
93 let report = MouseReport { 105
94 buttons: 0, 106 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
95 x: 0, 107 let buttons = 0u8;
96 y, 108 let x = 0i8;
97 wheel: 0, 109 match writer.write(&[buttons, x as u8, y as u8]).await {
98 pan: 0, 110 Ok(()) => {}
99 }; 111 Err(e) => warn!("Failed to send boot report: {:?}", e),
100 match writer.write_serialize(&report).await { 112 }
101 Ok(()) => {} 113 } else {
102 Err(e) => warn!("Failed to send report: {:?}", e), 114 let report = MouseReport {
115 buttons: 0,
116 x: 0,
117 y,
118 wheel: 0,
119 pan: 0,
120 };
121 match writer.write_serialize(&report).await {
122 Ok(()) => {}
123 Err(e) => warn!("Failed to send report: {:?}", e),
124 }
103 } 125 }
104 } 126 }
105 }; 127 };
@@ -122,6 +144,18 @@ impl RequestHandler for MyRequestHandler {
122 OutResponse::Accepted 144 OutResponse::Accepted
123 } 145 }
124 146
147 fn get_protocol(&self) -> HidProtocolMode {
148 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
149 info!("The current HID protocol mode is: {}", protocol);
150 protocol
151 }
152
153 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
154 info!("Switching to HID protocol mode: {}", protocol);
155 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
156 OutResponse::Accepted
157 }
158
125 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 159 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
126 info!("Set idle rate for {:?} to {:?}", id, dur); 160 info!("Set idle rate for {:?} to {:?}", id, dur);
127 } 161 }
diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs
index 4fbc6f17f..53bd37303 100644
--- a/examples/stm32u0/src/bin/adc.rs
+++ b/examples/stm32u0/src/bin/adc.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::Config; 5use embassy_stm32::Config;
6use embassy_stm32::adc::{Adc, Resolution, SampleTime}; 6use embassy_stm32::adc::{Adc, AdcConfig, Resolution, SampleTime};
7use embassy_time::Duration; 7use embassy_time::Duration;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
@@ -18,8 +18,9 @@ fn main() -> ! {
18 } 18 }
19 let p = embassy_stm32::init(config); 19 let p = embassy_stm32::init(config);
20 20
21 let mut adc = Adc::new(p.ADC1); 21 let mut config = AdcConfig::default();
22 adc.set_resolution(Resolution::BITS8); 22 config.resolution = Some(Resolution::BITS8);
23 let mut adc = Adc::new_with_config(p.ADC1, config);
23 let mut channel = p.PC0; 24 let mut channel = p.PC0;
24 25
25 loop { 26 loop {
diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs
index 99944f7c7..6b9a91d6e 100644
--- a/examples/stm32u5/src/bin/adc.rs
+++ b/examples/stm32u5/src/bin/adc.rs
@@ -2,7 +2,7 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::adc::{self, AdcChannel, SampleTime, adc4}; 5use embassy_stm32::adc::{self, AdcChannel, AdcConfig, SampleTime, adc4};
6use {defmt_rtt as _, panic_probe as _}; 6use {defmt_rtt as _, panic_probe as _};
7 7
8#[embassy_executor::main] 8#[embassy_executor::main]
@@ -12,19 +12,21 @@ async fn main(_spawner: embassy_executor::Spawner) {
12 let mut p = embassy_stm32::init(config); 12 let mut p = embassy_stm32::init(config);
13 13
14 // **** ADC1 init **** 14 // **** ADC1 init ****
15 let mut adc1 = adc::Adc::new(p.ADC1); 15 let mut config = AdcConfig::default();
16 config.averaging = Some(adc::Averaging::Samples1024);
17 config.resolution = Some(adc::Resolution::BITS14);
18 let mut adc1 = adc::Adc::new_with_config(p.ADC1, config);
16 let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 19 let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5
17 let mut adc1_pin2 = p.PA2; // A1 20 let mut adc1_pin2 = p.PA2; // A1
18 adc1.set_resolution(adc::Resolution::BITS14);
19 adc1.set_averaging(adc::Averaging::Samples1024);
20 let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); 21 let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14);
21 22
22 // **** ADC2 init **** 23 // **** ADC2 init ****
23 let mut adc2 = adc::Adc::new(p.ADC2); 24 let mut config = AdcConfig::default();
25 config.averaging = Some(adc::Averaging::Samples1024);
26 config.resolution = Some(adc::Resolution::BITS14);
27 let mut adc2 = adc::Adc::new_with_config(p.ADC2, config);
24 let mut adc2_pin1 = p.PC3; // A2 28 let mut adc2_pin1 = p.PC3; // A2
25 let mut adc2_pin2 = p.PB0; // A3 29 let mut adc2_pin2 = p.PB0; // A3
26 adc2.set_resolution(adc::Resolution::BITS14);
27 adc2.set_averaging(adc::Averaging::Samples1024);
28 let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); 30 let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14);
29 31
30 // **** ADC4 init **** 32 // **** ADC4 init ****