microbit_bsp/
mic.rs

1//! micrphone peripheral
2use embassy_nrf::gpio::{Level, Output, OutputDrive};
3use embassy_nrf::interrupt;
4use embassy_nrf::interrupt::typelevel::Binding;
5use embassy_nrf::peripherals::{P0_05, P0_20, SAADC};
6use embassy_nrf::saadc::*;
7use embassy_time::{Duration, Timer};
8
9/// Microphone interface
10pub struct Microphone<'a> {
11    adc: Saadc<'a, 1>,
12    enable: Output<'a, P0_20>,
13}
14
15impl<'a> Microphone<'a> {
16    /// Create a new microphone instance
17    pub fn new(
18        saadc: SAADC,
19        irq: impl Binding<interrupt::typelevel::SAADC, InterruptHandler> + 'a,
20        mic: P0_05,
21        micen: P0_20,
22    ) -> Self {
23        let config = Config::default();
24        let mut channel_config = ChannelConfig::single_ended(mic);
25        channel_config.gain = Gain::GAIN4;
26        let saadc = Saadc::new(saadc, irq, config, [channel_config]);
27        let enable = Output::new(micen, Level::Low, OutputDrive::HighDrive);
28        Self { adc: saadc, enable }
29    }
30
31    /// Enable the microphone and return the sound level as detected by the microphone.
32    ///
33    /// The returned value is a number between 0 and 255 and does not correspond to any official sound level meter number.
34    pub async fn sound_level(&mut self) -> u8 {
35        self.enable.set_high();
36        Timer::after(Duration::from_millis(10)).await;
37
38        let mut bufs = [[[0; 1]; 1024]; 2];
39
40        self.adc
41            .run_timer_sampler::<u32, _, 1024>(&mut bufs, 727, move |_| CallbackResult::Stop)
42            .await;
43        self.enable.set_low();
44
45        let mut max: i16 = i16::MIN;
46        let mut min: i16 = i16::MAX;
47        for b in bufs[0] {
48            if b[0] > max {
49                max = b[0];
50            }
51            if b[0] < min {
52                min = b[0];
53            }
54        }
55        let amplitude = max - min;
56        // Transpose to u8
57        (amplitude / 16) as u8
58    }
59}