diff options
| author | huntc <[email protected]> | 2022-03-07 12:45:37 +1100 |
|---|---|---|
| committer | huntc <[email protected]> | 2022-03-07 14:51:17 +1100 |
| commit | 3990f09b2927ca8062482680f4caba04e0cb78a7 (patch) | |
| tree | 37b8743495f27444477f790d2f2838b8ca31b169 | |
| parent | 98bdac51fe24c48ba097fcba3ec705f9da7df783 (diff) | |
Simplifies the API by taking in the TIMER and PPI channels
| -rw-r--r-- | embassy-nrf/src/saadc.rs | 92 | ||||
| -rw-r--r-- | examples/nrf/src/bin/saadc_continuous.rs | 26 |
2 files changed, 59 insertions, 59 deletions
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index dcc7e86a2..c4de7315f 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs | |||
| @@ -10,7 +10,8 @@ use embassy_hal_common::unborrow; | |||
| 10 | use futures::future::poll_fn; | 10 | use futures::future::poll_fn; |
| 11 | 11 | ||
| 12 | use crate::interrupt; | 12 | use crate::interrupt; |
| 13 | use crate::ppi::{Event, Task}; | 13 | use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; |
| 14 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | ||
| 14 | use crate::{pac, peripherals}; | 15 | use crate::{pac, peripherals}; |
| 15 | 16 | ||
| 16 | use pac::{saadc, SAADC}; | 17 | use pac::{saadc, SAADC}; |
| @@ -297,36 +298,67 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 297 | 298 | ||
| 298 | /// Continuous sampling with double buffers. | 299 | /// Continuous sampling with double buffers. |
| 299 | /// | 300 | /// |
| 300 | /// NOTE: It is important that the time spent within the callback supplied | 301 | /// A TIMER and two PPI peripherals are passed in so that precise sampling |
| 301 | /// does not exceed the time taken to acquire the samples into a single buffer. | 302 | /// can be attained. The sampling interval is expressed by selecting a |
| 302 | /// You should measure the time taken by the callback and set the sample buffer | 303 | /// timer clock frequency to use along with a counter threshold to be reached. |
| 303 | /// size accordingly. Exceeding this time can lead to the peripheral re-writing | 304 | /// For example, 1KHz can be achieved using a frequency of 1MHz and a counter |
| 304 | /// the other buffer. | 305 | /// threshold of 1000. |
| 305 | /// | ||
| 306 | /// A task-driven approach to driving TASK_SAMPLE is expected. With a task | ||
| 307 | /// driven approach, multiple channels can be used. | ||
| 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 | /// | 306 | /// |
| 316 | /// A sampler closure is provided that receives the buffer of samples, noting | 307 | /// A sampler closure is provided that receives the buffer of samples, noting |
| 317 | /// that the size of this buffer can be less than the original buffer's size. | 308 | /// that the size of this buffer can be less than the original buffer's size. |
| 318 | /// A command is return from the closure that indicates whether the sampling | 309 | /// A command is return from the closure that indicates whether the sampling |
| 319 | /// should continue or stop. | 310 | /// should continue or stop. |
| 320 | pub async fn run_task_sampler<I, S, const N0: usize>( | 311 | /// |
| 312 | /// NOTE: The time spent within the callback supplied should not exceed the time | ||
| 313 | /// taken to acquire the samples into a single buffer. You should measure the | ||
| 314 | /// time taken by the callback and set the sample buffer size accordingly. | ||
| 315 | /// Exceeding this time can lead to samples becoming dropped. | ||
| 316 | pub async fn run_task_sampler<S, T: TimerInstance, const N0: usize>( | ||
| 321 | &mut self, | 317 | &mut self, |
| 318 | timer: &mut T, | ||
| 319 | ppi_ch1: &mut impl ConfigurableChannel, | ||
| 320 | ppi_ch2: &mut impl ConfigurableChannel, | ||
| 321 | frequency: Frequency, | ||
| 322 | sample_counter: u32, | ||
| 322 | bufs: &mut [[[i16; N]; N0]; 2], | 323 | bufs: &mut [[[i16; N]; N0]; 2], |
| 323 | init: I, | ||
| 324 | sampler: S, | 324 | sampler: S, |
| 325 | ) where | 325 | ) where |
| 326 | I: FnMut(), | ||
| 327 | S: FnMut(&[[i16; N]]) -> SamplerState, | 326 | S: FnMut(&[[i16; N]]) -> SamplerState, |
| 328 | { | 327 | { |
| 329 | self.run_sampler(bufs, None, init, sampler).await; | 328 | let r = Self::regs(); |
| 329 | |||
| 330 | // We want the task start to effectively short with the last one ending so | ||
| 331 | // we don't miss any samples. It'd be great for the SAADC to offer a SHORTS | ||
| 332 | // register instead, but it doesn't, so we must use PPI. | ||
| 333 | let mut start_ppi = Ppi::new_one_to_one( | ||
| 334 | ppi_ch1, | ||
| 335 | Event::from_reg(&r.events_end), | ||
| 336 | Task::from_reg(&r.tasks_start), | ||
| 337 | ); | ||
| 338 | start_ppi.enable(); | ||
| 339 | |||
| 340 | let mut timer = Timer::new(timer); | ||
| 341 | timer.set_frequency(frequency); | ||
| 342 | timer.cc(0).write(sample_counter); | ||
| 343 | timer.cc(0).short_compare_clear(); | ||
| 344 | |||
| 345 | let mut sample_ppi = Ppi::new_one_to_one( | ||
| 346 | ppi_ch2, | ||
| 347 | timer.cc(0).event_compare(), | ||
| 348 | Task::from_reg(&r.tasks_sample), | ||
| 349 | ); | ||
| 350 | |||
| 351 | timer.start(); | ||
| 352 | |||
| 353 | self.run_sampler( | ||
| 354 | bufs, | ||
| 355 | None, | ||
| 356 | || { | ||
| 357 | sample_ppi.enable(); | ||
| 358 | }, | ||
| 359 | sampler, | ||
| 360 | ) | ||
| 361 | .await; | ||
| 330 | } | 362 | } |
| 331 | 363 | ||
| 332 | async fn run_sampler<I, S, const N0: usize>( | 364 | async fn run_sampler<I, S, const N0: usize>( |
| @@ -424,31 +456,13 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 424 | }) | 456 | }) |
| 425 | .await; | 457 | .await; |
| 426 | } | 458 | } |
| 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 | |||
| 434 | /// Return the sample task for use with PPI | ||
| 435 | pub fn task_sample(&self) -> Task { | ||
| 436 | let r = Self::regs(); | ||
| 437 | Task::from_reg(&r.tasks_sample) | ||
| 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 | } | ||
| 445 | } | 459 | } |
| 446 | 460 | ||
| 447 | impl<'d> Saadc<'d, 1> { | 461 | impl<'d> Saadc<'d, 1> { |
| 448 | /// Continuous sampling on a single channel with double buffers. | 462 | /// Continuous sampling on a single channel with double buffers. |
| 449 | /// | 463 | /// |
| 450 | /// The internal clock is to be used with a sample rate expressed as a divisor of | 464 | /// The internal clock is to be used with a sample rate expressed as a divisor of |
| 451 | /// 16MHz, ranging from 80..2047. For example, 1600 represnts a sample rate of 10KHz | 465 | /// 16MHz, ranging from 80..2047. For example, 1600 represents a sample rate of 10KHz |
| 452 | /// given 16_000_000 / 10_000_000 = 1600. | 466 | /// given 16_000_000 / 10_000_000 = 1600. |
| 453 | /// | 467 | /// |
| 454 | /// A sampler closure is provided that receives the buffer of samples, noting | 468 | /// A sampler closure is provided that receives the buffer of samples, noting |
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 @@ | |||
| 6 | mod example_common; | 6 | mod example_common; |
| 7 | use embassy::executor::Spawner; | 7 | use embassy::executor::Spawner; |
| 8 | use embassy::time::Duration; | 8 | use embassy::time::Duration; |
| 9 | use embassy_nrf::ppi::Ppi; | ||
| 10 | use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; | 9 | use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; |
| 11 | use embassy_nrf::timer::{Frequency, Timer}; | 10 | use embassy_nrf::timer::Frequency; |
| 12 | use embassy_nrf::{interrupt, Peripherals}; | 11 | use embassy_nrf::{interrupt, Peripherals}; |
| 13 | use example_common::*; | 12 | use example_common::*; |
| 14 | 13 | ||
| @@ -27,21 +26,6 @@ async fn main(_spawner: Spawner, mut p: Peripherals) { | |||
| 27 | [channel_1_config, channel_2_config, channel_3_config], | 26 | [channel_1_config, channel_2_config, channel_3_config], |
| 28 | ); | 27 | ); |
| 29 | 28 | ||
| 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 | |||
| 35 | let mut timer = Timer::new(p.TIMER0); | ||
| 36 | timer.set_frequency(Frequency::F1MHz); | ||
| 37 | timer.cc(0).write(1000); // We want to sample at 1KHz | ||
| 38 | timer.cc(0).short_compare_clear(); | ||
| 39 | |||
| 40 | let mut sample_ppi = | ||
| 41 | Ppi::new_one_to_one(p.PPI_CH1, timer.cc(0).event_compare(), saadc.task_sample()); | ||
| 42 | |||
| 43 | timer.start(); | ||
| 44 | |||
| 45 | // This delay demonstrates that starting the timer prior to running | 29 | // This delay demonstrates that starting the timer prior to running |
| 46 | // the task sampler is benign given the calibration that follows. | 30 | // the task sampler is benign given the calibration that follows. |
| 47 | embassy::time::Timer::after(Duration::from_millis(500)).await; | 31 | embassy::time::Timer::after(Duration::from_millis(500)).await; |
| @@ -54,10 +38,12 @@ async fn main(_spawner: Spawner, mut p: Peripherals) { | |||
| 54 | 38 | ||
| 55 | saadc | 39 | saadc |
| 56 | .run_task_sampler( | 40 | .run_task_sampler( |
| 41 | &mut p.TIMER0, | ||
| 42 | &mut p.PPI_CH0, | ||
| 43 | &mut p.PPI_CH1, | ||
| 44 | Frequency::F1MHz, | ||
| 45 | 1000, // We want to sample at 1KHz | ||
| 57 | &mut bufs, | 46 | &mut bufs, |
| 58 | || { | ||
| 59 | sample_ppi.enable(); | ||
| 60 | }, | ||
| 61 | move |buf| { | 47 | move |buf| { |
| 62 | // NOTE: It is important that the time spent within this callback | 48 | // NOTE: It is important that the time spent within this callback |
| 63 | // does not exceed the time taken to acquire the 1500 samples we | 49 | // does not exceed the time taken to acquire the 1500 samples we |
