From 98bdac51fe24c48ba097fcba3ec705f9da7df783 Mon Sep 17 00:00:00 2001 From: huntc Date: Sat, 26 Feb 2022 18:15:37 +1100 Subject: 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. --- examples/nrf/src/bin/saadc_continuous.rs | 57 ++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 17 deletions(-) (limited to 'examples') 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 @@ #[path = "../example_common.rs"] mod example_common; use embassy::executor::Spawner; +use embassy::time::Duration; use embassy_nrf::ppi::Ppi; use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; use embassy_nrf::timer::{Frequency, Timer}; @@ -26,34 +27,56 @@ async fn main(_spawner: Spawner, mut p: Peripherals) { [channel_1_config, channel_2_config, channel_3_config], ); + // We want the task start to effectively short with the last one ending so + // we don't miss any samples. The Saadc will trigger the initial TASKS_START. + let mut start_ppi = Ppi::new_one_to_one(p.PPI_CH0, saadc.event_end(), saadc.task_start()); + start_ppi.enable(); + let mut timer = Timer::new(p.TIMER0); timer.set_frequency(Frequency::F1MHz); - timer.cc(0).write(100); // We want to sample at 10KHz + timer.cc(0).write(1000); // We want to sample at 1KHz timer.cc(0).short_compare_clear(); - let mut ppi = Ppi::new_one_to_one(p.PPI_CH0, timer.cc(0).event_compare(), saadc.task_sample()); - ppi.enable(); + let mut sample_ppi = + Ppi::new_one_to_one(p.PPI_CH1, timer.cc(0).event_compare(), saadc.task_sample()); timer.start(); - let mut bufs = [[[0; 3]; 50]; 2]; + // This delay demonstrates that starting the timer prior to running + // the task sampler is benign given the calibration that follows. + embassy::time::Timer::after(Duration::from_millis(500)).await; + saadc.calibrate().await; + + let mut bufs = [[[0; 3]; 500]; 2]; let mut c = 0; let mut a: i32 = 0; saadc - .run_task_sampler(&mut bufs, move |buf| { - for b in buf { - a += b[0] as i32; - } - c += buf.len(); - if c > 10000 { - a = a / c as i32; - info!("channel 1: {=i32}", a); - c = 0; - a = 0; - } - SamplerState::Sampled - }) + .run_task_sampler( + &mut bufs, + || { + sample_ppi.enable(); + }, + move |buf| { + // NOTE: It is important that the time spent within this callback + // does not exceed the time taken to acquire the 1500 samples we + // have in this example, which would be 10us + 2us per + // sample * 1500 = 18ms. You need to measure the time taken here + // and set the sample buffer size accordingly. Exceeding this + // time can lead to the peripheral re-writing the other buffer. + for b in buf { + a += b[0] as i32; + } + c += buf.len(); + if c > 1000 { + a = a / c as i32; + info!("channel 1: {=i32}", a); + c = 0; + a = 0; + } + SamplerState::Sampled + }, + ) .await; } -- cgit From 3990f09b2927ca8062482680f4caba04e0cb78a7 Mon Sep 17 00:00:00 2001 From: huntc Date: Mon, 7 Mar 2022 12:45:37 +1100 Subject: Simplifies the API by taking in the TIMER and PPI channels --- examples/nrf/src/bin/saadc_continuous.rs | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'examples') diff --git a/examples/nrf/src/bin/saadc_continuous.rs b/examples/nrf/src/bin/saadc_continuous.rs index 991adabad..bdf552fba 100644 --- a/examples/nrf/src/bin/saadc_continuous.rs +++ b/examples/nrf/src/bin/saadc_continuous.rs @@ -6,9 +6,8 @@ mod example_common; use embassy::executor::Spawner; use embassy::time::Duration; -use embassy_nrf::ppi::Ppi; use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; -use embassy_nrf::timer::{Frequency, Timer}; +use embassy_nrf::timer::Frequency; use embassy_nrf::{interrupt, Peripherals}; use example_common::*; @@ -27,21 +26,6 @@ async fn main(_spawner: Spawner, mut p: Peripherals) { [channel_1_config, channel_2_config, channel_3_config], ); - // We want the task start to effectively short with the last one ending so - // we don't miss any samples. The Saadc will trigger the initial TASKS_START. - let mut start_ppi = Ppi::new_one_to_one(p.PPI_CH0, saadc.event_end(), saadc.task_start()); - start_ppi.enable(); - - let mut timer = Timer::new(p.TIMER0); - timer.set_frequency(Frequency::F1MHz); - timer.cc(0).write(1000); // We want to sample at 1KHz - timer.cc(0).short_compare_clear(); - - let mut sample_ppi = - Ppi::new_one_to_one(p.PPI_CH1, timer.cc(0).event_compare(), saadc.task_sample()); - - timer.start(); - // This delay demonstrates that starting the timer prior to running // the task sampler is benign given the calibration that follows. embassy::time::Timer::after(Duration::from_millis(500)).await; @@ -54,10 +38,12 @@ async fn main(_spawner: Spawner, mut p: Peripherals) { saadc .run_task_sampler( + &mut p.TIMER0, + &mut p.PPI_CH0, + &mut p.PPI_CH1, + Frequency::F1MHz, + 1000, // We want to sample at 1KHz &mut bufs, - || { - sample_ppi.enable(); - }, move |buf| { // NOTE: It is important that the time spent within this callback // does not exceed the time taken to acquire the 1500 samples we -- cgit From ed84d753c7591ccc98005ed8ab6f4d5c7b8121d0 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Tue, 8 Mar 2022 17:12:50 -0600 Subject: Update examples --- examples/stm32l4/src/bin/spi_dma.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs index b4d5091b2..a9327f8fe 100644 --- a/examples/stm32l4/src/bin/spi_dma.rs +++ b/examples/stm32l4/src/bin/spi_dma.rs @@ -21,8 +21,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { p.PC10, p.PC12, p.PC11, - p.DMA1_CH0, p.DMA1_CH1, + p.DMA1_CH2, Hertz(1_000_000), Config::default(), ); -- cgit