From 8fae6f5a3f7055dc8250cd8926624010b14db6dc Mon Sep 17 00:00:00 2001 From: Michael Kefeder Date: Sun, 28 Sep 2025 18:32:40 +0200 Subject: Reset SAADC in Drop impl for nrf52, workaround for anomaly 241. --- examples/nrf52810/src/bin/saadc_lowpower.rs | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 examples/nrf52810/src/bin/saadc_lowpower.rs (limited to 'examples/nrf52810') diff --git a/examples/nrf52810/src/bin/saadc_lowpower.rs b/examples/nrf52810/src/bin/saadc_lowpower.rs new file mode 100644 index 000000000..d7e7f09a4 --- /dev/null +++ b/examples/nrf52810/src/bin/saadc_lowpower.rs @@ -0,0 +1,62 @@ +//! Run SAADC on multiple pins only every 3rd time, to show anomaly 241 workaround. +//! +//! To correctly measure the MCU current on the NRF52DK follow the instructions +//! +//! otherwise you will measure the whole board, including the segger j-link chip for example + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::saadc::{Oversample, Saadc}; +use embassy_nrf::{bind_interrupts, saadc}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SAADC => saadc::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_p: Spawner) { + let mut p = embassy_nrf::init(Default::default()); + + // For PPK2 digital channel plot to track when SAADC is on/off. + let mut ppk2_d0 = Output::new(p.P0_27, Level::Low, OutputDrive::Standard); + let mut num_loops: usize = 0; + loop { + num_loops += 1; + if num_loops.is_multiple_of(3) { + ppk2_d0.set_high(); + let battery_pin = p.P0_02.reborrow(); + let sensor1_pin = p.P0_03.reborrow(); + let mut adc_config = saadc::Config::default(); + adc_config.oversample = Oversample::OVER4X; + let battery = saadc::ChannelConfig::single_ended(battery_pin); + let sensor1 = saadc::ChannelConfig::single_ended(sensor1_pin); + let mut saadc = Saadc::new(p.SAADC.reborrow(), Irqs, adc_config, [battery, sensor1]); + // Indicated: wait for ADC calibration. + saadc.calibrate().await; + let mut buf = [0; 2]; + info!("sampling..."); + saadc.sample(&mut buf).await; + info!("data: {:x}", buf); + + // Sleep to show the high power usage on the plot, even though sampling is done. + Timer::after_millis(100).await; + ppk2_d0.set_low(); + // disable the following line to show the anomaly on the power profiler plot. + core::mem::drop(saadc); + // Sleep to show the power usage when drop did not happen. + Timer::after_millis(100).await; + // worst case drop happens here + } else { + info!("waiting"); + } + // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do. + // During this sleep, the nRF chip should only use ~3uA + Timer::after_secs(1).await; + } +} -- cgit