Discard the first N samples due to transients

This commit is contained in:
Quentin Smith 2022-08-21 01:44:04 -04:00
parent 0963b5f92c
commit 3d26573c6b
2 changed files with 24 additions and 6 deletions

View file

@ -139,7 +139,8 @@ impl<'d> Pdm<'d> {
}
/// One shot sampling. If the PDM is configured for multiple channels, the samples will be interleaved.
pub async fn sample<const N: usize>(&mut self, buf: &mut [i16; N]) {
/// The first samples from the PDM peripheral and microphone usually contain garbage data, so the discard parameter sets the number of complete buffers to discard before returning.
pub async fn sample<const N: usize>(&mut self, mut discard: usize, buf: &mut [i16; N]) {
let r = Self::regs();
// Set up the DMA
@ -148,9 +149,11 @@ impl<'d> Pdm<'d> {
// Reset and enable the events
r.events_end.reset();
r.events_started.reset();
r.events_stopped.reset();
r.intenset.write(|w| {
w.end().set();
w.started().set();
w.stopped().set();
w
});
@ -168,13 +171,26 @@ impl<'d> Pdm<'d> {
WAKER.register(cx.waker());
if r.events_end.read().bits() != 0 {
compiler_fence(Ordering::SeqCst);
// END means the whole buffer has been received.
r.events_end.reset();
r.intenset.write(|w| w.end().set());
if discard > 0 {
discard -= 1;
} else {
// Note that the beginning of the buffer might be overwritten before the task fully stops :(
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
}
}
if r.events_started.read().bits() != 0 {
compiler_fence(Ordering::SeqCst);
r.events_started.reset();
}
if r.events_stopped.read().bits() != 0 {
compiler_fence(Ordering::SeqCst);
r.events_stopped.reset();
return Poll::Ready(());
}

View file

@ -26,14 +26,16 @@ async fn main(_p: Spawner) {
info!("Gain = {} dB", defmt::Debug2Format(&gain));
for _ in 0..10 {
let mut buf = [0; 1500];
pdm.sample(&mut buf).await;
pdm.sample(5, &mut buf).await;
let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / 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,
);
info!("samples = {}", &buf);