Skip to content

Commit c9ab128

Browse files
authored
adc: add methods to utilize oversampling
1 parent 0853587 commit c9ab128

File tree

4 files changed

+90
-33
lines changed

4 files changed

+90
-33
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
- Added `Rtc::calibrate_lp` to calibrate the RTC.
1111
- Added `Rtc::recalibration_pending`.
1212
- Added `Rtc::is_alarm_{a,b}_en`.
13+
- Added methods to utilize ADC oversampling.
1314

1415
## Changed
1516
- `Rtc.alarm_{a,b}` returns `Alarm` instead of `Option<Alarm>`.

Cargo.lock

Lines changed: 19 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hal/src/adc.rs

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
#![cfg_attr(feature = "stm32wl5x_cm0p", allow(dead_code))]
1010
#![cfg_attr(feature = "stm32wl5x_cm0p", allow(unused_imports))]
1111

12-
use crate::Ratio;
12+
#[cfg(not(feature = "stm32wl5x_cm0p"))]
13+
pub use pac::adc::cfgr2::{OVSR_A as OversampleRatio, OVSS_A as OversampleShift};
1314

1415
use crate::gpio;
16+
use crate::Ratio;
1517

1618
use super::pac;
1719
use core::{ptr::read_volatile, time::Duration};
@@ -1057,7 +1059,7 @@ impl Adc {
10571059

10581060
/// Returns `true` if the temperature sensor is enabled.
10591061
#[inline]
1060-
#[must_use = "no reason to call this function if you are not using the result"]
1062+
#[must_use]
10611063
pub fn is_tsen_enabled(&mut self) -> bool {
10621064
self.adc.ccr.read().tsen().is_enabled()
10631065
}
@@ -1145,11 +1147,48 @@ impl Adc {
11451147

11461148
/// Returns `true` if the internal voltage reference is enabled.
11471149
#[inline]
1148-
#[must_use = "no reason to call this function if you are not using the result"]
1150+
#[must_use]
11491151
pub fn is_vref_enabled(&mut self) -> bool {
11501152
self.adc.ccr.read().vrefen().is_enabled()
11511153
}
11521154

1155+
/// Enable oversampling.
1156+
///
1157+
/// # Panics
1158+
///
1159+
/// * (debug) ADC is enabled
1160+
#[inline]
1161+
#[cfg(not(feature = "stm32wl5x_cm0p"))]
1162+
pub fn enable_oversampling(&mut self, ratio: OversampleRatio, shift: OversampleShift) {
1163+
debug_assert!(!self.is_enabled());
1164+
self.adc.cfgr2.modify(|_, w| {
1165+
w.ovse()
1166+
.enabled()
1167+
.ovsr()
1168+
.variant(ratio)
1169+
.ovss()
1170+
.variant(shift)
1171+
})
1172+
}
1173+
1174+
/// Disables oversampling.
1175+
///
1176+
/// # Panics
1177+
///
1178+
/// * (debug) ADC is enabled
1179+
#[inline]
1180+
pub fn disable_oversampling(&mut self) {
1181+
debug_assert!(!self.is_enabled());
1182+
self.adc.cfgr2.modify(|_, w| w.ovse().disabled())
1183+
}
1184+
1185+
/// Returns `true` if oversampling is enabled.
1186+
#[inline]
1187+
#[must_use]
1188+
pub fn is_oversampling_enabled(&mut self) -> bool {
1189+
self.adc.cfgr2.read().ovse().is_enabled()
1190+
}
1191+
11531192
/// Read the internal voltage reference.
11541193
///
11551194
/// # Panics
@@ -1304,7 +1343,7 @@ impl Adc {
13041343

13051344
/// Returns `true` if V<sub>BAT</sub> is enabled.
13061345
#[inline]
1307-
#[must_use = "no reason to call this function if you are not using the result"]
1346+
#[must_use]
13081347
pub fn is_vbat_enabled(&self) -> bool {
13091348
self.adc.ccr.read().vbaten().is_enabled()
13101349
}
@@ -1381,14 +1420,14 @@ impl Adc {
13811420
/// assert_eq!(adc.is_enabled(), false);
13821421
/// ```
13831422
#[inline]
1384-
#[must_use = "no reason to call this function if you are not using the result"]
1423+
#[must_use]
13851424
pub fn is_enabled(&self) -> bool {
13861425
self.adc.cr.read().aden().bit_is_set()
13871426
}
13881427

13891428
/// Returns `true` if an ADC disable command is in-progress.
13901429
#[inline]
1391-
#[must_use = "no reason to call this function if you are not using the result"]
1430+
#[must_use]
13921431
pub fn disable_in_progress(&self) -> bool {
13931432
self.adc.cr.read().addis().bit_is_set()
13941433
}
@@ -1414,7 +1453,7 @@ impl Adc {
14141453
/// assert_eq!(adc.is_disabled(), true);
14151454
/// ```
14161455
#[inline]
1417-
#[must_use = "no reason to call this function if you are not using the result"]
1456+
#[must_use]
14181457
pub fn is_disabled(&self) -> bool {
14191458
let cr = self.adc.cr.read();
14201459
cr.aden().bit_is_clear() && cr.addis().bit_is_clear()

testsuite/src/adc.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
55
use defmt::unwrap;
66
use defmt_rtt as _; // global logger
77
use nucleo_wl55jc_bsp::hal::{
8-
adc::{self, Adc, Clk},
8+
adc::{self, Adc, Clk, OversampleRatio, OversampleShift},
99
cortex_m::{self, delay::Delay},
1010
pac::{self, DWT},
1111
rcc,
@@ -21,12 +21,14 @@ const CYC_PER_US: u32 = FREQ / 1000 / 1000;
2121
// WARNING will wrap-around eventually, use this for relative timing only
2222
defmt::timestamp!("{=u32:us}", DWT::cycle_count() / CYC_PER_US);
2323

24-
fn validate_vbat(sample: u16) {
24+
fn validate_vbat(sample: u16, oversample: i16) {
2525
const EXPECTED: i16 = 4096 / 3;
26-
let delta: i16 = unwrap!(i16::try_from(sample).ok()) - EXPECTED;
26+
let expected: i16 = EXPECTED * oversample;
27+
let delta: i16 = unwrap!(i16::try_from(sample).ok()) - expected;
2728

2829
defmt::info!("VBAT={} Δ {}", sample, delta);
29-
defmt::assert!(delta < 20);
30+
let tolerance: i16 = 20 * oversample;
31+
defmt::assert!(delta < tolerance);
3032
}
3133

3234
#[defmt_test::tests]
@@ -250,7 +252,22 @@ mod tests {
250252
ta.adc.set_max_sample_time();
251253
let sample: u16 = ta.adc.vbat();
252254

253-
validate_vbat(sample);
255+
validate_vbat(sample, 1);
256+
}
257+
258+
#[test]
259+
fn vbat_oversample(ta: &mut TestArgs) {
260+
ta.adc.disable();
261+
ta.adc
262+
.enable_oversampling(OversampleRatio::MUL2, OversampleShift::NOSHIFT);
263+
ta.adc.enable();
264+
let sample: u16 = ta.adc.vbat();
265+
validate_vbat(sample / 2, 2);
266+
267+
ta.adc.disable();
268+
defmt::assert!(ta.adc.is_oversampling_enabled());
269+
ta.adc.disable_oversampling();
270+
defmt::assert!(!ta.adc.is_oversampling_enabled());
254271
}
255272

256273
#[test]
@@ -312,8 +329,8 @@ mod tests {
312329
// instead of &mut self
313330
let vbat1: u16 = ta.adc.data();
314331
let vbat2: u16 = ta.adc.data();
315-
validate_vbat(vbat1);
316-
validate_vbat(vbat2);
332+
validate_vbat(vbat1, 1);
333+
validate_vbat(vbat2, 1);
317334
defmt::assert_eq!(vbat1, vbat2);
318335
}
319336

0 commit comments

Comments
 (0)