aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-07-21 16:24:48 -0500
committerxoviat <[email protected]>2023-07-21 16:24:48 -0500
commit2cdd593290ea318d0ca9d71a270ac3b63e30470e (patch)
tree9dd8df6d49c26195c281e609a728d20a2ed716ec /examples
parentc675208b8a90bee39e99c8cd3bb620b99c439482 (diff)
parent4d1d125f4157084668a949f9bc24e4417628f9fe (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into mac
Diffstat (limited to 'examples')
-rw-r--r--examples/nrf52840/Cargo.toml3
-rw-r--r--examples/nrf52840/src/bin/pdm.rs46
-rw-r--r--examples/nrf52840/src/bin/pdm_continuous.rs81
3 files changed, 117 insertions, 13 deletions
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 7b9c371bb..9b41ec5ab 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -43,6 +43,7 @@ embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-host
43defmt = "0.3" 43defmt = "0.3"
44defmt-rtt = "0.4" 44defmt-rtt = "0.4"
45 45
46fixed = "1.10.0"
46static_cell = "1.1" 47static_cell = "1.1"
47cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 48cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
48cortex-m-rt = "0.7.0" 49cortex-m-rt = "0.7.0"
@@ -53,6 +54,8 @@ embedded-storage = "0.3.0"
53usbd-hid = "0.6.0" 54usbd-hid = "0.6.0"
54serde = { version = "1.0.136", default-features = false } 55serde = { version = "1.0.136", default-features = false }
55embedded-hal-async = { version = "0.2.0-alpha.2", optional = true } 56embedded-hal-async = { version = "0.2.0-alpha.2", optional = true }
57num-integer = { version = "0.1.45", default-features = false }
58microfft = "0.5.0"
56 59
57[patch.crates-io] 60[patch.crates-io]
58lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" } 61lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/examples/nrf52840/src/bin/pdm.rs b/examples/nrf52840/src/bin/pdm.rs
index 6b41320ca..444b9137f 100644
--- a/examples/nrf52840/src/bin/pdm.rs
+++ b/examples/nrf52840/src/bin/pdm.rs
@@ -7,6 +7,8 @@ use embassy_executor::Spawner;
7use embassy_nrf::pdm::{self, Config, Pdm}; 7use embassy_nrf::pdm::{self, Config, Pdm};
8use embassy_nrf::{bind_interrupts, peripherals}; 8use embassy_nrf::{bind_interrupts, peripherals};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use fixed::types::I7F1;
11use num_integer::Roots;
10use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
11 13
12bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
@@ -20,18 +22,36 @@ async fn main(_p: Spawner) {
20 let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config); 22 let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config);
21 23
22 loop { 24 loop {
23 pdm.start().await; 25 for gain in [I7F1::from_num(-20), I7F1::from_num(0), I7F1::from_num(20)] {
24 26 pdm.set_gain(gain, gain);
25 // wait some time till the microphon settled 27 info!("Gain = {} dB", defmt::Debug2Format(&gain));
26 Timer::after(Duration::from_millis(1000)).await; 28 pdm.start().await;
27 29
28 const SAMPLES: usize = 2048; 30 // wait some time till the microphon settled
29 let mut buf = [0i16; SAMPLES]; 31 Timer::after(Duration::from_millis(1000)).await;
30 pdm.sample(&mut buf).await.unwrap(); 32
31 33 const SAMPLES: usize = 2048;
32 info!("samples: {:?}", &buf); 34 let mut buf = [0i16; SAMPLES];
33 35 pdm.sample(&mut buf).await.unwrap();
34 pdm.stop().await; 36
35 Timer::after(Duration::from_millis(100)).await; 37 let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
38 info!(
39 "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}",
40 buf.len(),
41 buf.iter().min().unwrap(),
42 buf.iter().max().unwrap(),
43 mean,
44 (buf.iter()
45 .map(|v| i32::from(*v - mean).pow(2))
46 .fold(0i32, |a, b| a.saturating_add(b))
47 / buf.len() as i32)
48 .sqrt() as i16,
49 );
50
51 info!("samples: {:?}", &buf);
52
53 pdm.stop().await;
54 Timer::after(Duration::from_millis(100)).await;
55 }
36 } 56 }
37} 57}
diff --git a/examples/nrf52840/src/bin/pdm_continuous.rs b/examples/nrf52840/src/bin/pdm_continuous.rs
new file mode 100644
index 000000000..7d8531475
--- /dev/null
+++ b/examples/nrf52840/src/bin/pdm_continuous.rs
@@ -0,0 +1,81 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::cmp::Ordering;
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_nrf::pdm::{self, Config, Frequency, OperationMode, Pdm, Ratio, SamplerState};
10use embassy_nrf::{bind_interrupts, peripherals};
11use fixed::types::I7F1;
12use microfft::real::rfft_1024;
13use num_integer::Roots;
14use {defmt_rtt as _, panic_probe as _};
15
16// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
17
18bind_interrupts!(struct Irqs {
19 PDM => pdm::InterruptHandler<peripherals::PDM>;
20});
21
22#[embassy_executor::main]
23async fn main(_p: Spawner) {
24 let mut p = embassy_nrf::init(Default::default());
25 let mut config = Config::default();
26 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense.
27 config.frequency = Frequency::_1280K; // 16 kHz sample rate
28 config.ratio = Ratio::RATIO80;
29 config.operation_mode = OperationMode::Mono;
30 config.gain_left = I7F1::from_bits(5); // 2.5 dB
31 let mut pdm = Pdm::new(p.PDM, Irqs, &mut p.P0_00, &mut p.P0_01, config);
32
33 let mut bufs = [[0; 1024]; 2];
34
35 pdm.run_task_sampler(&mut bufs, move |buf| {
36 // NOTE: It is important that the time spent within this callback
37 // does not exceed the time taken to acquire the 1500 samples we
38 // have in this example, which would be 10us + 2us per
39 // sample * 1500 = 18ms. You need to measure the time taken here
40 // and set the sample buffer size accordingly. Exceeding this
41 // time can lead to the peripheral re-writing the other buffer.
42 let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
43 let (peak_freq_index, peak_mag) = fft_peak_freq(&buf);
44 let peak_freq = peak_freq_index * 16000 / buf.len();
45 info!(
46 "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}, peak {} @ {} Hz",
47 buf.len(),
48 buf.iter().min().unwrap(),
49 buf.iter().max().unwrap(),
50 mean,
51 (buf.iter()
52 .map(|v| i32::from(*v - mean).pow(2))
53 .fold(0i32, |a, b| a.saturating_add(b))
54 / buf.len() as i32)
55 .sqrt() as i16,
56 peak_mag,
57 peak_freq,
58 );
59 SamplerState::Sampled
60 })
61 .await
62 .unwrap();
63}
64
65fn fft_peak_freq(input: &[i16; 1024]) -> (usize, u32) {
66 let mut f = [0f32; 1024];
67 for i in 0..input.len() {
68 f[i] = (input[i] as f32) / 32768.0;
69 }
70 // N.B. rfft_1024 does the FFT in-place so result is actually also a reference to f.
71 let result = rfft_1024(&mut f);
72 result[0].im = 0.0;
73
74 result
75 .iter()
76 .map(|c| c.norm_sqr())
77 .enumerate()
78 .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Equal))
79 .map(|(i, v)| (i, ((v * 32768.0) as u32).sqrt()))
80 .unwrap()
81}