From 9a873d1dbf301bf6416fec675a40ebd3aa3f1174 Mon Sep 17 00:00:00 2001 From: huntc Date: Fri, 26 Aug 2022 14:40:20 +1000 Subject: [PATCH 1/4] Ensure that the sampling is stopped Ensures that nRF saadc sampling is stopped and is awaited prior to exiting the two sampling methods. Not doing so causes a potential power drain and the potential for dropped buffer writes when having finished continuous sampling. --- embassy-nrf/src/saadc.rs | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 7dc66349e..43c98a888 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -183,6 +183,11 @@ impl<'d, const N: usize> Saadc<'d, N> { r.intenclr.write(|w| w.started().clear()); WAKER.wake(); } + + if r.events_stopped.read().bits() != 0 { + r.intenclr.write(|w| w.stopped().clear()); + WAKER.wake(); + } } fn regs() -> &'static saadc::RegisterBlock { @@ -251,6 +256,8 @@ impl<'d, const N: usize> Saadc<'d, N> { Poll::Pending }) .await; + + Self::stop_sampling().await; } /// Continuous sampling with double buffers. @@ -403,6 +410,42 @@ impl<'d, const N: usize> Saadc<'d, N> { Poll::Pending }) .await; + + Self::stop_sampling().await; + } + + // Stop sampling and wait for it to stop + async fn stop_sampling() { + let r = Self::regs(); + + // Reset and enable the events + + compiler_fence(Ordering::SeqCst); + + r.events_stopped.reset(); + r.intenset.write(|w| { + w.stopped().set(); + w + }); + + // Stop + + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + + // Wait for 'stopped' event. + poll_fn(|cx| { + let r = Self::regs(); + + WAKER.register(cx.waker()); + + if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return Poll::Ready(()); + } + + Poll::Pending + }) + .await; } } From c0b7fd910e5663242d9320dd9893dbc1844b2729 Mon Sep 17 00:00:00 2001 From: huntc Date: Tue, 30 Aug 2022 09:49:04 +1000 Subject: [PATCH 2/4] Additional doco --- embassy-nrf/src/saadc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 43c98a888..69926ec03 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -224,6 +224,8 @@ impl<'d, const N: usize> Saadc<'d, N> { } /// One shot sampling. The buffer must be the same size as the number of channels configured. + /// The sampling is stopped prior to returning in order to reduce power consumption (power + /// consumption remains higher if sampling is not stopped explicitly). pub async fn sample(&mut self, buf: &mut [i16; N]) { let r = Self::regs(); From dcd8c62169fc92224e2672c621b7d0b846b59cdf Mon Sep 17 00:00:00 2001 From: huntc Date: Tue, 30 Aug 2022 20:56:56 +1000 Subject: [PATCH 3/4] Permits the future to be cancelled Includes documentation --- embassy-nrf/src/saadc.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 69926ec03..5f2ac64ef 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -3,6 +3,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; +use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use futures::future::poll_fn; @@ -225,8 +226,12 @@ impl<'d, const N: usize> Saadc<'d, N> { /// One shot sampling. The buffer must be the same size as the number of channels configured. /// The sampling is stopped prior to returning in order to reduce power consumption (power - /// consumption remains higher if sampling is not stopped explicitly). + /// consumption remains higher if sampling is not stopped explicitly). Cancellation will + /// also cause the sampling to be stopped. pub async fn sample(&mut self, buf: &mut [i16; N]) { + // In case the future is dropped, stop the task and wait for it to end. + let on_drop = OnDrop::new(Self::stop_sampling_immediately); + let r = Self::regs(); // Set up the DMA @@ -259,6 +264,7 @@ impl<'d, const N: usize> Saadc<'d, N> { }) .await; + on_drop.defuse(); Self::stop_sampling().await; } @@ -279,6 +285,12 @@ impl<'d, const N: usize> Saadc<'d, N> { /// taken to acquire the samples into a single buffer. You should measure the /// time taken by the callback and set the sample buffer size accordingly. /// Exceeding this time can lead to samples becoming dropped. + /// + /// The sampling is stopped prior to returning in order to reduce power consumption (power + /// consumption remains higher if sampling is not stopped explicitly), and to + /// free the buffers from being used by the peripheral. Cancellation will + /// also cause the sampling to be stopped. + pub async fn run_task_sampler( &mut self, timer: &mut T, @@ -330,6 +342,9 @@ impl<'d, const N: usize> Saadc<'d, N> { I: FnMut(), S: FnMut(&[[i16; N]]) -> SamplerState, { + // In case the future is dropped, stop the task and wait for it to end. + let on_drop = OnDrop::new(Self::stop_sampling_immediately); + let r = Self::regs(); // Establish mode and sample rate @@ -413,10 +428,24 @@ impl<'d, const N: usize> Saadc<'d, N> { }) .await; + on_drop.defuse(); Self::stop_sampling().await; } - // Stop sampling and wait for it to stop + // Stop sampling and wait for it to stop in a blocking fashion + fn stop_sampling_immediately() { + let r = Self::regs(); + + compiler_fence(Ordering::SeqCst); + + r.events_stopped.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + + while r.events_stopped.read().bits() == 0 {} + r.events_stopped.reset(); + } + + // Stop sampling and wait for it to stop in a non-blocking fashino async fn stop_sampling() { let r = Self::regs(); From 30641d05640a7a3cd4d71c70c09694a3eef825e0 Mon Sep 17 00:00:00 2001 From: huntc Date: Wed, 31 Aug 2022 08:44:28 +1000 Subject: [PATCH 4/4] Avoid context switch and wait for stop Should be more efficient given the sub 100 cycles to wait. --- embassy-nrf/src/saadc.rs | 49 ++-------------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 5f2ac64ef..9bc89eb38 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -184,11 +184,6 @@ impl<'d, const N: usize> Saadc<'d, N> { r.intenclr.write(|w| w.started().clear()); WAKER.wake(); } - - if r.events_stopped.read().bits() != 0 { - r.intenclr.write(|w| w.stopped().clear()); - WAKER.wake(); - } } fn regs() -> &'static saadc::RegisterBlock { @@ -230,7 +225,7 @@ impl<'d, const N: usize> Saadc<'d, N> { /// also cause the sampling to be stopped. pub async fn sample(&mut self, buf: &mut [i16; N]) { // In case the future is dropped, stop the task and wait for it to end. - let on_drop = OnDrop::new(Self::stop_sampling_immediately); + OnDrop::new(Self::stop_sampling_immediately); let r = Self::regs(); @@ -263,9 +258,6 @@ impl<'d, const N: usize> Saadc<'d, N> { Poll::Pending }) .await; - - on_drop.defuse(); - Self::stop_sampling().await; } /// Continuous sampling with double buffers. @@ -343,7 +335,7 @@ impl<'d, const N: usize> Saadc<'d, N> { S: FnMut(&[[i16; N]]) -> SamplerState, { // In case the future is dropped, stop the task and wait for it to end. - let on_drop = OnDrop::new(Self::stop_sampling_immediately); + OnDrop::new(Self::stop_sampling_immediately); let r = Self::regs(); @@ -427,9 +419,6 @@ impl<'d, const N: usize> Saadc<'d, N> { Poll::Pending }) .await; - - on_drop.defuse(); - Self::stop_sampling().await; } // Stop sampling and wait for it to stop in a blocking fashion @@ -444,40 +433,6 @@ impl<'d, const N: usize> Saadc<'d, N> { while r.events_stopped.read().bits() == 0 {} r.events_stopped.reset(); } - - // Stop sampling and wait for it to stop in a non-blocking fashino - async fn stop_sampling() { - let r = Self::regs(); - - // Reset and enable the events - - compiler_fence(Ordering::SeqCst); - - r.events_stopped.reset(); - r.intenset.write(|w| { - w.stopped().set(); - w - }); - - // Stop - - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - - // Wait for 'stopped' event. - poll_fn(|cx| { - let r = Self::regs(); - - WAKER.register(cx.waker()); - - if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); - return Poll::Ready(()); - } - - Poll::Pending - }) - .await; - } } impl<'d> Saadc<'d, 1> {