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