From ed97e61dbecc636c3cc9f67778d4b7eb48cff893 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Sun, 21 Aug 2022 02:16:26 -0400 Subject: [PATCH] PDM clock frequency control --- embassy-nrf/src/pdm.rs | 13 ++++++++++--- examples/nrf/src/bin/pdm_continuous.rs | 13 ++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 6a070e7b..b58a0e97 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -9,6 +9,8 @@ use embassy_util::waitqueue::AtomicWaker; use futures::future::poll_fn; use pac::{pdm, PDM}; use pdm::mode::{EDGE_A, OPERATION_A}; +pub use pdm::pdmclkctrl::FREQ_A as Frequency; +pub use pdm::ratio::RATIO_A as Ratio; use fixed::types::I7F1; use crate::interrupt::InterruptExt; @@ -32,8 +34,10 @@ static WAKER: AtomicWaker = AtomicWaker::new(); /// See the `Default` impl for suitable default values. #[non_exhaustive] pub struct Config { - /// Clock + /// Clock frequency + pub frequency: Frequency, /// Clock ratio + pub ratio: Ratio, /// Channels pub channels: Channels, /// Edge to sample on @@ -48,6 +52,8 @@ impl Default for Config { /// Default configuration for single channel sampling. fn default() -> Self { Self { + frequency: Frequency::DEFAULT, + ratio: Ratio::RATIO80, channels: Channels::Stereo, left_edge: Edge::FallingEdge, gain_left: I7F1::ZERO, @@ -78,11 +84,12 @@ impl<'d> Pdm<'d> { let r = unsafe { &*PDM::ptr() }; - let Config { channels, left_edge, gain_left, gain_right } = config; + let Config { frequency, ratio, channels, left_edge, gain_left, gain_right } = config; // Configure channels r.enable.write(|w| w.enable().enabled()); - // TODO: Clock control + r.pdmclkctrl.write(|w| w.freq().variant(frequency)); + r.ratio.write(|w| w.ratio().variant(ratio)); r.mode.write(|w| { w.operation().variant(channels.into()); w.edge().variant(left_edge.into()); diff --git a/examples/nrf/src/bin/pdm_continuous.rs b/examples/nrf/src/bin/pdm_continuous.rs index e7d1806b..33ba1e27 100644 --- a/examples/nrf/src/bin/pdm_continuous.rs +++ b/examples/nrf/src/bin/pdm_continuous.rs @@ -5,8 +5,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_nrf::interrupt; -use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState}; -use embassy_nrf::timer::Frequency; +use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio}; use fixed::types::I7F1; use num_integer::Roots; use {defmt_rtt as _, panic_probe as _}; @@ -18,11 +17,13 @@ async fn main(_p: Spawner) { let mut p = embassy_nrf::init(Default::default()); let mut config = Config::default(); // Pins are correct for the onboard microphone on the Feather nRF52840 Sense. + config.frequency = Frequency::_1280K; // 16 kHz sample rate + config.ratio = Ratio::RATIO80; config.channels = Channels::Mono; config.gain_left = I7F1::from_bits(5); // 2.5 dB let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), &mut p.P0_00, &mut p.P0_01, config); - let mut bufs = [[0; 500]; 2]; + let mut bufs = [[0; 1024]; 2]; pdm .run_task_sampler( @@ -34,13 +35,15 @@ async fn main(_p: Spawner) { // 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. + let mean = (buf.iter().map(|v| i32::from(*v)).sum::() / buf.len() as i32) as i16; info!( - "{} samples, min {=i16}, max {=i16}, RMS {=i16}", + "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}", buf.len(), buf.iter().min().unwrap(), buf.iter().max().unwrap(), + mean, ( - buf.iter().map(|v| i32::from(*v).pow(2)).fold(0i32, |a,b| a.saturating_add(b)) + buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b)) / buf.len() as i32).sqrt() as i16, ); SamplerState::Sampled