Compare commits
1 commit
master
...
microphone
| Author | SHA1 | Date | |
|---|---|---|---|
| a36eab3aa1 |
5 changed files with 234 additions and 0 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -115,6 +115,7 @@ dependencies = [
|
|||
"bitmask-enum",
|
||||
"embedded-hal-bus",
|
||||
"esp-hal",
|
||||
"esp32s3",
|
||||
"mipidsi",
|
||||
"thiserror",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ bitflags = "2.9.1"
|
|||
bitmask-enum = "2.2.5"
|
||||
embedded-hal-bus = "0.3.0"
|
||||
esp-hal = {version = "=1.0.0-beta.1", features = ["esp32s3", "unstable"]}
|
||||
esp32s3 = "0.32.0"
|
||||
mipidsi = "0.9.0"
|
||||
thiserror = {version = "2.0.11", default-features = false}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
pub mod display;
|
||||
pub mod keyboard;
|
||||
pub mod microphone;
|
||||
|
||||
#[cfg(test)]
|
||||
fn main() {}
|
||||
|
|
|
|||
38
src/microphone.rs
Normal file
38
src/microphone.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use crate::microphone::clock_calculation::{calculate_clock, set_clock};
|
||||
|
||||
mod clock_calculation;
|
||||
|
||||
fn mic(i2s0: esp_hal::peripherals::I2S0) {
|
||||
drop(i2s0);
|
||||
|
||||
let i2s0 = unsafe { esp32s3::I2S0::steal() };
|
||||
|
||||
// clear clock config register
|
||||
// i2s0.rx_clkm_conf().reset();
|
||||
// i2s0.rx_conf().reset();
|
||||
|
||||
set_clock(
|
||||
&i2s0,
|
||||
calculate_clock(esp_hal::time::Rate::from_mhz(2), 1, 16),
|
||||
);
|
||||
|
||||
let gpio = unsafe { esp32s3::GPIO::steal() };
|
||||
gpio.func46_in_sel_cfg().modify(|_, w| w.)
|
||||
|
||||
// let io_mux = unsafe { esp32s3::IO_MUX::steal() };
|
||||
// io_mux.gpio(46).modify(|_, w| w.)
|
||||
|
||||
i2s0.rx_conf()
|
||||
.modify(|_, w| w.rx_reset().set_bit().rx_fifo_reset().set_bit());
|
||||
|
||||
i2s0.rx_conf()
|
||||
.modify(|_, w| w.rx_reset().clear_bit().rx_fifo_reset().clear_bit());
|
||||
|
||||
i2s0.rx_conf().modify(|_, w| w.rx_ws_idle_pol().clear_bit());
|
||||
|
||||
i2s0.rx_conf1()
|
||||
.modify(|_, w| unsafe { w.rx_half_sample_bits().bits(15).rx_bits_mod().bits(15) });
|
||||
|
||||
// Enable PDM mode
|
||||
i2s0.rx_conf().modify(|_, w| w.rx_pdm_en().set_bit());
|
||||
}
|
||||
193
src/microphone/clock_calculation.rs
Normal file
193
src/microphone/clock_calculation.rs
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
//! This module contains code lifted from esp-rs/esp-hal,
|
||||
//! which has been slightly modified for use in this library.
|
||||
//!
|
||||
//! ## License
|
||||
//!
|
||||
//! Copyright 2021 esp-rs
|
||||
//!
|
||||
//! Permission is hereby granted, free of charge, to any
|
||||
//! person obtaining a copy of this software and associated
|
||||
//! documentation files (the "Software"), to deal in the
|
||||
//! Software without restriction, including without
|
||||
//! limitation the rights to use, copy, modify, merge,
|
||||
//! publish, distribute, sublicense, and/or sell copies of
|
||||
//! the Software, and to permit persons to whom the Software
|
||||
//! is furnished to do so, subject to the following
|
||||
//! conditions:
|
||||
//!
|
||||
//! The above copyright notice and this permission notice
|
||||
//! shall be included in all copies or substantial portions
|
||||
//! of the Software.
|
||||
//!
|
||||
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
//! ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
//! TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
//! PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
//! SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
//! CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
//! OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
//! IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
//! DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use esp_hal::time::Rate;
|
||||
|
||||
pub(super) struct I2sClockDividers {
|
||||
mclk_divider: u32,
|
||||
bclk_divider: u32,
|
||||
denominator: u32,
|
||||
numerator: u32,
|
||||
}
|
||||
/// The default clock source for I2S operations.
|
||||
const I2S_DEFAULT_CLK_SRC: u8 = 2;
|
||||
|
||||
const I2S_SCLK: u32 = 160_000_000;
|
||||
|
||||
const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6;
|
||||
|
||||
const I2S_LL_MCLK_DIVIDER_MAX: usize = (1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1;
|
||||
|
||||
pub(super) fn calculate_clock(sample_rate: Rate, channels: u8, data_bits: u8) -> I2sClockDividers {
|
||||
// this loosely corresponds to `i2s_std_calculate_clock` and
|
||||
// `i2s_ll_tx_set_mclk` in esp-idf
|
||||
//
|
||||
// main difference is we are using fixed-point arithmetic here
|
||||
|
||||
// If data_bits is a power of two, use 256 as the mclk_multiple
|
||||
// If data_bits is 24, use 192 (24 * 8) as the mclk_multiple
|
||||
let mclk_multiple = if data_bits == 24 { 192 } else { 256 };
|
||||
let sclk = I2S_SCLK; // for now it's fixed 160MHz
|
||||
|
||||
let rate = sample_rate.as_hz();
|
||||
|
||||
let bclk = rate * channels as u32 * data_bits as u32;
|
||||
let mclk = rate * mclk_multiple;
|
||||
let bclk_divider = mclk / bclk;
|
||||
let mut mclk_divider = sclk / mclk;
|
||||
|
||||
let mut ma: u32;
|
||||
let mut mb: u32;
|
||||
let mut denominator: u32 = 0;
|
||||
let mut numerator: u32 = 0;
|
||||
|
||||
let freq_diff = sclk.abs_diff(mclk * mclk_divider);
|
||||
|
||||
if freq_diff != 0 {
|
||||
let decimal = freq_diff as u64 * 10000 / mclk as u64;
|
||||
|
||||
// Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 /
|
||||
// 126.0
|
||||
if decimal > 1250000 / 126 {
|
||||
mclk_divider += 1;
|
||||
} else {
|
||||
let mut min: u32 = !0;
|
||||
|
||||
for a in 2..=I2S_LL_MCLK_DIVIDER_MAX {
|
||||
let b = (a as u64) * (freq_diff as u64 * 10000u64 / mclk as u64) + 5000;
|
||||
ma = ((freq_diff as u64 * 10000u64 * a as u64) / 10000) as u32;
|
||||
mb = (mclk as u64 * (b / 10000)) as u32;
|
||||
|
||||
if ma == mb {
|
||||
denominator = a as u32;
|
||||
numerator = (b / 10000) as u32;
|
||||
break;
|
||||
}
|
||||
|
||||
if mb.abs_diff(ma) < min {
|
||||
denominator = a as u32;
|
||||
numerator = b as u32;
|
||||
min = mb.abs_diff(ma);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
I2sClockDividers {
|
||||
mclk_divider,
|
||||
bclk_divider,
|
||||
denominator,
|
||||
numerator,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_clock(i2s0: &esp32s3::I2S0, clock_settings: I2sClockDividers) {
|
||||
let clkm_div_x: u32;
|
||||
let clkm_div_y: u32;
|
||||
let clkm_div_z: u32;
|
||||
let clkm_div_yn1: u32;
|
||||
|
||||
if clock_settings.denominator == 0 || clock_settings.numerator == 0 {
|
||||
clkm_div_x = 0;
|
||||
clkm_div_y = 0;
|
||||
clkm_div_z = 0;
|
||||
clkm_div_yn1 = 1;
|
||||
} else if clock_settings.numerator > clock_settings.denominator / 2 {
|
||||
clkm_div_x = clock_settings
|
||||
.denominator
|
||||
.overflowing_div(
|
||||
clock_settings
|
||||
.denominator
|
||||
.overflowing_sub(clock_settings.numerator)
|
||||
.0,
|
||||
)
|
||||
.0
|
||||
.overflowing_sub(1)
|
||||
.0;
|
||||
clkm_div_y = clock_settings.denominator
|
||||
% (clock_settings
|
||||
.denominator
|
||||
.overflowing_sub(clock_settings.numerator)
|
||||
.0);
|
||||
clkm_div_z = clock_settings
|
||||
.denominator
|
||||
.overflowing_sub(clock_settings.numerator)
|
||||
.0;
|
||||
clkm_div_yn1 = 1;
|
||||
} else {
|
||||
clkm_div_x = clock_settings.denominator / clock_settings.numerator - 1;
|
||||
clkm_div_y = clock_settings.denominator % clock_settings.numerator;
|
||||
clkm_div_z = clock_settings.numerator;
|
||||
clkm_div_yn1 = 0;
|
||||
}
|
||||
|
||||
i2s0.tx_clkm_div_conf().modify(|_, w| unsafe {
|
||||
w.tx_clkm_div_x().bits(clkm_div_x as u16);
|
||||
w.tx_clkm_div_y().bits(clkm_div_y as u16);
|
||||
w.tx_clkm_div_yn1().bit(clkm_div_yn1 != 0);
|
||||
w.tx_clkm_div_z().bits(clkm_div_z as u16)
|
||||
});
|
||||
|
||||
i2s0.tx_clkm_conf().modify(|_, w| unsafe {
|
||||
w.clk_en().set_bit();
|
||||
w.tx_clk_active().set_bit();
|
||||
w.tx_clk_sel()
|
||||
.bits(I2S_DEFAULT_CLK_SRC) // for now fixed at 160MHz
|
||||
;
|
||||
w.tx_clkm_div_num().bits(clock_settings.mclk_divider as u8)
|
||||
});
|
||||
|
||||
i2s0.tx_conf1().modify(|_, w| unsafe {
|
||||
w.tx_bck_div_num()
|
||||
.bits((clock_settings.bclk_divider - 1) as u8)
|
||||
});
|
||||
|
||||
i2s0.rx_clkm_div_conf().modify(|_, w| unsafe {
|
||||
w.rx_clkm_div_x().bits(clkm_div_x as u16);
|
||||
w.rx_clkm_div_y().bits(clkm_div_y as u16);
|
||||
w.rx_clkm_div_yn1().bit(clkm_div_yn1 != 0);
|
||||
w.rx_clkm_div_z().bits(clkm_div_z as u16)
|
||||
});
|
||||
|
||||
i2s0.rx_clkm_conf().modify(|_, w| unsafe {
|
||||
w.rx_clk_active().set_bit();
|
||||
// for now fixed at 160MHz
|
||||
w.rx_clk_sel()
|
||||
.bits(I2S_DEFAULT_CLK_SRC);
|
||||
w.rx_clkm_div_num().bits(clock_settings.mclk_divider as u8);
|
||||
w.mclk_sel().bit(true)
|
||||
});
|
||||
|
||||
i2s0.rx_conf1().modify(|_, w| unsafe {
|
||||
w.rx_bck_div_num()
|
||||
.bits((clock_settings.bclk_divider - 1) as u8)
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue