diff options
| author | xoviat <[email protected]> | 2023-07-21 16:24:48 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-07-21 16:24:48 -0500 |
| commit | 2cdd593290ea318d0ca9d71a270ac3b63e30470e (patch) | |
| tree | 9dd8df6d49c26195c281e609a728d20a2ed716ec /examples | |
| parent | c675208b8a90bee39e99c8cd3bb620b99c439482 (diff) | |
| parent | 4d1d125f4157084668a949f9bc24e4417628f9fe (diff) | |
Merge branch 'main' of https://github.com/embassy-rs/embassy into mac
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/nrf52840/Cargo.toml | 3 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/pdm.rs | 46 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/pdm_continuous.rs | 81 |
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 | |||
| 43 | defmt = "0.3" | 43 | defmt = "0.3" |
| 44 | defmt-rtt = "0.4" | 44 | defmt-rtt = "0.4" |
| 45 | 45 | ||
| 46 | fixed = "1.10.0" | ||
| 46 | static_cell = "1.1" | 47 | static_cell = "1.1" |
| 47 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 48 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 48 | cortex-m-rt = "0.7.0" | 49 | cortex-m-rt = "0.7.0" |
| @@ -53,6 +54,8 @@ embedded-storage = "0.3.0" | |||
| 53 | usbd-hid = "0.6.0" | 54 | usbd-hid = "0.6.0" |
| 54 | serde = { version = "1.0.136", default-features = false } | 55 | serde = { version = "1.0.136", default-features = false } |
| 55 | embedded-hal-async = { version = "0.2.0-alpha.2", optional = true } | 56 | embedded-hal-async = { version = "0.2.0-alpha.2", optional = true } |
| 57 | num-integer = { version = "0.1.45", default-features = false } | ||
| 58 | microfft = "0.5.0" | ||
| 56 | 59 | ||
| 57 | [patch.crates-io] | 60 | [patch.crates-io] |
| 58 | lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" } | 61 | lora-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; | |||
| 7 | use embassy_nrf::pdm::{self, Config, Pdm}; | 7 | use embassy_nrf::pdm::{self, Config, Pdm}; |
| 8 | use embassy_nrf::{bind_interrupts, peripherals}; | 8 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 9 | use embassy_time::{Duration, Timer}; | 9 | use embassy_time::{Duration, Timer}; |
| 10 | use fixed::types::I7F1; | ||
| 11 | use num_integer::Roots; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 13 | ||
| 12 | bind_interrupts!(struct Irqs { | 14 | bind_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 | |||
| 5 | use core::cmp::Ordering; | ||
| 6 | |||
| 7 | use defmt::info; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_nrf::pdm::{self, Config, Frequency, OperationMode, Pdm, Ratio, SamplerState}; | ||
| 10 | use embassy_nrf::{bind_interrupts, peripherals}; | ||
| 11 | use fixed::types::I7F1; | ||
| 12 | use microfft::real::rfft_1024; | ||
| 13 | use num_integer::Roots; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | // Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer | ||
| 17 | |||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | PDM => pdm::InterruptHandler<peripherals::PDM>; | ||
| 20 | }); | ||
| 21 | |||
| 22 | #[embassy_executor::main] | ||
| 23 | async 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 | |||
| 65 | fn 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 | } | ||
