aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/saadc.rs83
-rw-r--r--examples/nrf/src/bin/saadc_continuous.rs57
2 files changed, 116 insertions, 24 deletions
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 617c9e041..dcc7e86a2 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -10,7 +10,7 @@ use embassy_hal_common::unborrow;
10use futures::future::poll_fn; 10use futures::future::poll_fn;
11 11
12use crate::interrupt; 12use crate::interrupt;
13use crate::ppi::Task; 13use crate::ppi::{Event, Task};
14use crate::{pac, peripherals}; 14use crate::{pac, peripherals};
15 15
16use pac::{saadc, SAADC}; 16use pac::{saadc, SAADC};
@@ -207,6 +207,11 @@ impl<'d, const N: usize> Saadc<'d, N> {
207 fn on_interrupt(_ctx: *mut ()) { 207 fn on_interrupt(_ctx: *mut ()) {
208 let r = Self::regs(); 208 let r = Self::regs();
209 209
210 if r.events_calibratedone.read().bits() != 0 {
211 r.intenclr.write(|w| w.calibratedone().clear());
212 WAKER.wake();
213 }
214
210 if r.events_end.read().bits() != 0 { 215 if r.events_end.read().bits() != 0 {
211 r.intenclr.write(|w| w.end().clear()); 216 r.intenclr.write(|w| w.end().clear());
212 WAKER.wake(); 217 WAKER.wake();
@@ -222,6 +227,35 @@ impl<'d, const N: usize> Saadc<'d, N> {
222 unsafe { &*SAADC::ptr() } 227 unsafe { &*SAADC::ptr() }
223 } 228 }
224 229
230 /// Perform SAADC calibration. Completes when done.
231 pub async fn calibrate(&self) {
232 let r = Self::regs();
233
234 // Reset and enable the end event
235 r.events_calibratedone.reset();
236 r.intenset.write(|w| w.calibratedone().set());
237
238 // Order is important
239 compiler_fence(Ordering::SeqCst);
240
241 r.tasks_calibrateoffset.write(|w| unsafe { w.bits(1) });
242
243 // Wait for 'calibratedone' event.
244 poll_fn(|cx| {
245 let r = Self::regs();
246
247 WAKER.register(cx.waker());
248
249 if r.events_calibratedone.read().bits() != 0 {
250 r.events_calibratedone.reset();
251 return Poll::Ready(());
252 }
253
254 Poll::Pending
255 })
256 .await;
257 }
258
225 /// One shot sampling. The buffer must be the same size as the number of channels configured. 259 /// One shot sampling. The buffer must be the same size as the number of channels configured.
226 pub async fn sample(&mut self, buf: &mut [i16; N]) { 260 pub async fn sample(&mut self, buf: &mut [i16; N]) {
227 let r = Self::regs(); 261 let r = Self::regs();
@@ -263,29 +297,46 @@ impl<'d, const N: usize> Saadc<'d, N> {
263 297
264 /// Continuous sampling with double buffers. 298 /// Continuous sampling with double buffers.
265 /// 299 ///
300 /// NOTE: It is important that the time spent within the callback supplied
301 /// does not exceed the time taken to acquire the samples into a single buffer.
302 /// You should measure the time taken by the callback and set the sample buffer
303 /// size accordingly. Exceeding this time can lead to the peripheral re-writing
304 /// the other buffer.
305 ///
266 /// A task-driven approach to driving TASK_SAMPLE is expected. With a task 306 /// A task-driven approach to driving TASK_SAMPLE is expected. With a task
267 /// driven approach, multiple channels can be used. 307 /// driven approach, multiple channels can be used.
268 /// 308 ///
309 /// In addition, the caller is responsible for triggering TASK_START in
310 /// relation to the previous one having ended (EVENTS_END). The the initial
311 /// TASKS_START is triggered by this method.
312 ///
313 /// A closure is provided so that any required initialization such as starting
314 /// the sampling task can occur once the peripheral has been started.
315 ///
269 /// A sampler closure is provided that receives the buffer of samples, noting 316 /// A sampler closure is provided that receives the buffer of samples, noting
270 /// that the size of this buffer can be less than the original buffer's size. 317 /// that the size of this buffer can be less than the original buffer's size.
271 /// A command is return from the closure that indicates whether the sampling 318 /// A command is return from the closure that indicates whether the sampling
272 /// should continue or stop. 319 /// should continue or stop.
273 pub async fn run_task_sampler<S, const N0: usize>( 320 pub async fn run_task_sampler<I, S, const N0: usize>(
274 &mut self, 321 &mut self,
275 bufs: &mut [[[i16; N]; N0]; 2], 322 bufs: &mut [[[i16; N]; N0]; 2],
323 init: I,
276 sampler: S, 324 sampler: S,
277 ) where 325 ) where
326 I: FnMut(),
278 S: FnMut(&[[i16; N]]) -> SamplerState, 327 S: FnMut(&[[i16; N]]) -> SamplerState,
279 { 328 {
280 self.run_sampler(bufs, None, sampler).await; 329 self.run_sampler(bufs, None, init, sampler).await;
281 } 330 }
282 331
283 async fn run_sampler<S, const N0: usize>( 332 async fn run_sampler<I, S, const N0: usize>(
284 &mut self, 333 &mut self,
285 bufs: &mut [[[i16; N]; N0]; 2], 334 bufs: &mut [[[i16; N]; N0]; 2],
286 sample_rate_divisor: Option<u16>, 335 sample_rate_divisor: Option<u16>,
336 mut init: I,
287 mut sampler: S, 337 mut sampler: S,
288 ) where 338 ) where
339 I: FnMut(),
289 S: FnMut(&[[i16; N]]) -> SamplerState, 340 S: FnMut(&[[i16; N]]) -> SamplerState,
290 { 341 {
291 let r = Self::regs(); 342 let r = Self::regs();
@@ -330,6 +381,8 @@ impl<'d, const N: usize> Saadc<'d, N> {
330 381
331 r.tasks_start.write(|w| unsafe { w.bits(1) }); 382 r.tasks_start.write(|w| unsafe { w.bits(1) });
332 383
384 let mut inited = false;
385
333 let mut current_buffer = 0; 386 let mut current_buffer = 0;
334 387
335 // Wait for events and complete when the sampler indicates it has had enough. 388 // Wait for events and complete when the sampler indicates it has had enough.
@@ -347,7 +400,6 @@ impl<'d, const N: usize> Saadc<'d, N> {
347 if sampler(&bufs[current_buffer]) == SamplerState::Sampled { 400 if sampler(&bufs[current_buffer]) == SamplerState::Sampled {
348 let next_buffer = 1 - current_buffer; 401 let next_buffer = 1 - current_buffer;
349 current_buffer = next_buffer; 402 current_buffer = next_buffer;
350 r.tasks_start.write(|w| unsafe { w.bits(1) });
351 } else { 403 } else {
352 return Poll::Ready(()); 404 return Poll::Ready(());
353 }; 405 };
@@ -357,6 +409,11 @@ impl<'d, const N: usize> Saadc<'d, N> {
357 r.events_started.reset(); 409 r.events_started.reset();
358 r.intenset.write(|w| w.started().set()); 410 r.intenset.write(|w| w.started().set());
359 411
412 if !inited {
413 init();
414 inited = true;
415 }
416
360 let next_buffer = 1 - current_buffer; 417 let next_buffer = 1 - current_buffer;
361 r.result 418 r.result
362 .ptr 419 .ptr
@@ -368,11 +425,23 @@ impl<'d, const N: usize> Saadc<'d, N> {
368 .await; 425 .await;
369 } 426 }
370 427
428 /// Return the end event for use with PPI
429 pub fn event_end(&self) -> Event {
430 let r = Self::regs();
431 Event::from_reg(&r.events_end)
432 }
433
371 /// Return the sample task for use with PPI 434 /// Return the sample task for use with PPI
372 pub fn task_sample(&self) -> Task { 435 pub fn task_sample(&self) -> Task {
373 let r = Self::regs(); 436 let r = Self::regs();
374 Task::from_reg(&r.tasks_sample) 437 Task::from_reg(&r.tasks_sample)
375 } 438 }
439
440 /// Return the start task for use with PPI
441 pub fn task_start(&self) -> Task {
442 let r = Self::regs();
443 Task::from_reg(&r.tasks_start)
444 }
376} 445}
377 446
378impl<'d> Saadc<'d, 1> { 447impl<'d> Saadc<'d, 1> {
@@ -386,7 +455,7 @@ impl<'d> Saadc<'d, 1> {
386 /// that the size of this buffer can be less than the original buffer's size. 455 /// that the size of this buffer can be less than the original buffer's size.
387 /// A command is return from the closure that indicates whether the sampling 456 /// A command is return from the closure that indicates whether the sampling
388 /// should continue or stop. 457 /// should continue or stop.
389 pub async fn run_timer_sampler<S, const N0: usize>( 458 pub async fn run_timer_sampler<I, S, const N0: usize>(
390 &mut self, 459 &mut self,
391 bufs: &mut [[[i16; 1]; N0]; 2], 460 bufs: &mut [[[i16; 1]; N0]; 2],
392 sample_rate_divisor: u16, 461 sample_rate_divisor: u16,
@@ -394,7 +463,7 @@ impl<'d> Saadc<'d, 1> {
394 ) where 463 ) where
395 S: FnMut(&[[i16; 1]]) -> SamplerState, 464 S: FnMut(&[[i16; 1]]) -> SamplerState,
396 { 465 {
397 self.run_sampler(bufs, Some(sample_rate_divisor), sampler) 466 self.run_sampler(bufs, Some(sample_rate_divisor), || {}, sampler)
398 .await; 467 .await;
399 } 468 }
400} 469}
diff --git a/examples/nrf/src/bin/saadc_continuous.rs b/examples/nrf/src/bin/saadc_continuous.rs
index 81559237b..991adabad 100644
--- a/examples/nrf/src/bin/saadc_continuous.rs
+++ b/examples/nrf/src/bin/saadc_continuous.rs
@@ -5,6 +5,7 @@
5#[path = "../example_common.rs"] 5#[path = "../example_common.rs"]
6mod example_common; 6mod example_common;
7use embassy::executor::Spawner; 7use embassy::executor::Spawner;
8use embassy::time::Duration;
8use embassy_nrf::ppi::Ppi; 9use embassy_nrf::ppi::Ppi;
9use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; 10use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState};
10use embassy_nrf::timer::{Frequency, Timer}; 11use embassy_nrf::timer::{Frequency, Timer};
@@ -26,34 +27,56 @@ async fn main(_spawner: Spawner, mut p: Peripherals) {
26 [channel_1_config, channel_2_config, channel_3_config], 27 [channel_1_config, channel_2_config, channel_3_config],
27 ); 28 );
28 29
30 // We want the task start to effectively short with the last one ending so
31 // we don't miss any samples. The Saadc will trigger the initial TASKS_START.
32 let mut start_ppi = Ppi::new_one_to_one(p.PPI_CH0, saadc.event_end(), saadc.task_start());
33 start_ppi.enable();
34
29 let mut timer = Timer::new(p.TIMER0); 35 let mut timer = Timer::new(p.TIMER0);
30 timer.set_frequency(Frequency::F1MHz); 36 timer.set_frequency(Frequency::F1MHz);
31 timer.cc(0).write(100); // We want to sample at 10KHz 37 timer.cc(0).write(1000); // We want to sample at 1KHz
32 timer.cc(0).short_compare_clear(); 38 timer.cc(0).short_compare_clear();
33 39
34 let mut ppi = Ppi::new_one_to_one(p.PPI_CH0, timer.cc(0).event_compare(), saadc.task_sample()); 40 let mut sample_ppi =
35 ppi.enable(); 41 Ppi::new_one_to_one(p.PPI_CH1, timer.cc(0).event_compare(), saadc.task_sample());
36 42
37 timer.start(); 43 timer.start();
38 44
39 let mut bufs = [[[0; 3]; 50]; 2]; 45 // This delay demonstrates that starting the timer prior to running
46 // the task sampler is benign given the calibration that follows.
47 embassy::time::Timer::after(Duration::from_millis(500)).await;
48 saadc.calibrate().await;
49
50 let mut bufs = [[[0; 3]; 500]; 2];
40 51
41 let mut c = 0; 52 let mut c = 0;
42 let mut a: i32 = 0; 53 let mut a: i32 = 0;
43 54
44 saadc 55 saadc
45 .run_task_sampler(&mut bufs, move |buf| { 56 .run_task_sampler(
46 for b in buf { 57 &mut bufs,
47 a += b[0] as i32; 58 || {
48 } 59 sample_ppi.enable();
49 c += buf.len(); 60 },
50 if c > 10000 { 61 move |buf| {
51 a = a / c as i32; 62 // NOTE: It is important that the time spent within this callback
52 info!("channel 1: {=i32}", a); 63 // does not exceed the time taken to acquire the 1500 samples we
53 c = 0; 64 // have in this example, which would be 10us + 2us per
54 a = 0; 65 // sample * 1500 = 18ms. You need to measure the time taken here
55 } 66 // and set the sample buffer size accordingly. Exceeding this
56 SamplerState::Sampled 67 // time can lead to the peripheral re-writing the other buffer.
57 }) 68 for b in buf {
69 a += b[0] as i32;
70 }
71 c += buf.len();
72 if c > 1000 {
73 a = a / c as i32;
74 info!("channel 1: {=i32}", a);
75 c = 0;
76 a = 0;
77 }
78 SamplerState::Sampled
79 },
80 )
58 .await; 81 .await;
59} 82}