aboutsummaryrefslogtreecommitdiff
path: root/examples/nrf
diff options
context:
space:
mode:
authorhuntc <[email protected]>2022-02-26 18:15:37 +1100
committerhuntc <[email protected]>2022-03-07 14:51:17 +1100
commit98bdac51fe24c48ba097fcba3ec705f9da7df783 (patch)
treec259432d7cf8ba49ef5c53bf62c25fd4e6f7a2c2 /examples/nrf
parent9735c38592ab6749d832f027fdc3070f97dc57cf (diff)
Improve nRF Saadc sampling
Starting the sampling task prior to starting the SAADC peripheral can lead to unexpected buffer behaviour with multiple channels. We now provide an init callback at the point where the SAADC has started for the first time. This callback can be used to kick off sampling via PPI. We also need to trigger the SAADC to start sampling the next buffer when the previous one is ended so that we do not drop samples - the major benefit of double buffering. As a bonus we provide a calibrate method as it is recommended to use before starting up the sampling. The example has been updated to illustrate these new features.
Diffstat (limited to 'examples/nrf')
-rw-r--r--examples/nrf/src/bin/saadc_continuous.rs57
1 files changed, 40 insertions, 17 deletions
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}