648: Fix nRF Saadc continuous sampling r=Dirbaio a=huntc 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. Given these additional tasks, we now simplify the API by passing in the TIMER and two PPI channels. As a bonus, we provide an async `calibrate` method as it is recommended to use before starting up the sampling. The example has been updated to illustrate these new features along with the simplified API. The changes here have been tested on my nRF52840-DK. 656: stm32: Refactor DMA interrupts r=Dirbaio a=GrantM11235 Previously, every dma interrupt handler called the same `on_irq` function which had to check the state of every dma channel. Now, each dma interrupt handler only calls an `on_irq` method for its corresponding channel or channels. Co-authored-by: huntc <huntchr@gmail.com> Co-authored-by: Grant Miller <GrantM11235@gmail.com>
This commit is contained in:
@ -5,9 +5,9 @@
|
||||
#[path = "../example_common.rs"]
|
||||
mod example_common;
|
||||
use embassy::executor::Spawner;
|
||||
use embassy_nrf::ppi::Ppi;
|
||||
use embassy::time::Duration;
|
||||
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::*;
|
||||
|
||||
@ -26,34 +26,43 @@ async fn main(_spawner: Spawner, mut p: Peripherals) {
|
||||
[channel_1_config, channel_2_config, channel_3_config],
|
||||
);
|
||||
|
||||
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).short_compare_clear();
|
||||
// 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 ppi = Ppi::new_one_to_one(p.PPI_CH0, timer.cc(0).event_compare(), saadc.task_sample());
|
||||
ppi.enable();
|
||||
|
||||
timer.start();
|
||||
|
||||
let mut bufs = [[[0; 3]; 50]; 2];
|
||||
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 p.TIMER0,
|
||||
&mut p.PPI_CH0,
|
||||
&mut p.PPI_CH1,
|
||||
Frequency::F1MHz,
|
||||
1000, // We want to sample at 1KHz
|
||||
&mut bufs,
|
||||
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;
|
||||
}
|
||||
|
@ -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(),
|
||||
);
|
||||
|
Reference in New Issue
Block a user