aboutsummaryrefslogtreecommitdiff
path: root/examples/nrf/src/bin
diff options
context:
space:
mode:
Diffstat (limited to 'examples/nrf/src/bin')
-rw-r--r--examples/nrf/src/bin/pdm_continuous.rs24
1 files changed, 23 insertions, 1 deletions
diff --git a/examples/nrf/src/bin/pdm_continuous.rs b/examples/nrf/src/bin/pdm_continuous.rs
index 33ba1e274..e78bc40dc 100644
--- a/examples/nrf/src/bin/pdm_continuous.rs
+++ b/examples/nrf/src/bin/pdm_continuous.rs
@@ -3,11 +3,13 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use defmt::info; 5use defmt::info;
6use core::cmp::Ordering;
6use embassy_executor::Spawner; 7use embassy_executor::Spawner;
7use embassy_nrf::interrupt; 8use embassy_nrf::interrupt;
8use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio}; 9use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio};
9use fixed::types::I7F1; 10use fixed::types::I7F1;
10use num_integer::Roots; 11use num_integer::Roots;
12use microfft::real::rfft_1024;
11use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
12 14
13// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer 15// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
@@ -36,8 +38,10 @@ async fn main(_p: Spawner) {
36 // and set the sample buffer size accordingly. Exceeding this 38 // and set the sample buffer size accordingly. Exceeding this
37 // time can lead to the peripheral re-writing the other buffer. 39 // time can lead to the peripheral re-writing the other buffer.
38 let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16; 40 let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
41 let (peak_freq_index, peak_mag) = fft_peak_freq(&buf);
42 let peak_freq = peak_freq_index * 16000 / buf.len();
39 info!( 43 info!(
40 "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}", 44 "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}, peak {} @ {} Hz",
41 buf.len(), 45 buf.len(),
42 buf.iter().min().unwrap(), 46 buf.iter().min().unwrap(),
43 buf.iter().max().unwrap(), 47 buf.iter().max().unwrap(),
@@ -45,9 +49,27 @@ async fn main(_p: Spawner) {
45 ( 49 (
46 buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b)) 50 buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b))
47 / buf.len() as i32).sqrt() as i16, 51 / buf.len() as i32).sqrt() as i16,
52 peak_mag, peak_freq,
48 ); 53 );
49 SamplerState::Sampled 54 SamplerState::Sampled
50 }, 55 },
51 ) 56 )
52 .await; 57 .await;
53} 58}
59
60fn fft_peak_freq(input: &[i16; 1024]) -> (usize, u32) {
61 let mut f = [0f32; 1024];
62 for i in 0..input.len() {
63 f[i] = (input[i] as f32) / 32768.0;
64 }
65 // N.B. rfft_1024 does the FFT in-place so result is actually also a reference to f.
66 let result = rfft_1024(&mut f);
67 result[0].im = 0.0;
68
69 result
70 .iter()
71 .map(|c| ((c.norm_sqr()*32768.0) as u32).sqrt())
72 .enumerate()
73 .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Equal))
74 .unwrap()
75} \ No newline at end of file