Skip to main content

esp_hal/i2s/pdm/
clock.rs

1//! PDM clock calculations.
2
3use super::{PdmDownsampleRate, PdmError, PdmRxClockConfig, PdmTxClockConfig};
4use crate::{i2s::master::private::I2sClockDividers, soc, time::Rate};
5
6pub(crate) const PDM_BCK_FACTOR: u32 = 64;
7pub(crate) const PDM_TX_BCLK_DIV_MIN: u32 = 8;
8pub(crate) const PDM_RX_BCLK_DIV_MIN: u32 = 8;
9
10pub(crate) struct PdmTxClockResult {
11    pub dividers: I2sClockDividers,
12    pub over_sample_ratio: u32,
13}
14
15pub(crate) struct PdmRxClockResult {
16    pub dividers: I2sClockDividers,
17}
18
19fn calculate_mclk_dividers(sclk: u32, mclk: u32) -> Result<I2sClockDividers, PdmError> {
20    // Require `sclk > mclk * 1.99` — use integer math to avoid soft-float.
21    if (sclk as u64) * 100 <= (mclk as u64) * 199 {
22        return Err(PdmError::InvalidClock);
23    }
24
25    let dividers = I2sClockDividers::from_frequencies(sclk, mclk, 0);
26
27    if dividers.mclk_divider >= 256 {
28        return Err(PdmError::InvalidClock);
29    }
30
31    Ok(dividers)
32}
33
34pub(crate) fn calculate_tx_clock(
35    clk: &PdmTxClockConfig,
36    pcm: bool,
37) -> Result<PdmTxClockResult, PdmError> {
38    if clk.up_sample_fs > 480 {
39        return Err(PdmError::InvalidClock);
40    }
41
42    let rate = clk.sample_rate.as_hz();
43    let bclk_div = clk.bclk_div.max(PDM_TX_BCLK_DIV_MIN);
44
45    let (bclk, over_sample_ratio) = if pcm {
46        let over_sample_ratio = clk.up_sample_fp / clk.up_sample_fs.max(1);
47        (rate * PDM_BCK_FACTOR * over_sample_ratio, over_sample_ratio)
48    } else {
49        (rate * 2, 0)
50    };
51
52    let mclk = bclk * bclk_div;
53    let sclk = soc::i2s_sclk_frequency();
54    let mut dividers = calculate_mclk_dividers(sclk, mclk)?;
55    dividers.bclk_divider = bclk_div;
56
57    Ok(PdmTxClockResult {
58        dividers,
59        over_sample_ratio,
60    })
61}
62
63const PDM_RX_CLK_LIMIT_COEFF: u32 = 128;
64
65pub(crate) fn calculate_rx_clock(
66    clk: &PdmRxClockConfig,
67    pcm: bool,
68    slot_mask: u16,
69) -> Result<PdmRxClockResult, PdmError> {
70    let rate = clk.sample_rate.as_hz();
71    let dn_sample_factor = PDM_BCK_FACTOR * clk.downsample_rate.factor();
72    let slot_num = slot_mask.count_ones().max(1);
73
74    let bclk = if pcm {
75        rate * dn_sample_factor
76    } else {
77        rate * 2
78    };
79
80    let bclk_limit = (PDM_RX_CLK_LIMIT_COEFF * slot_num).div_ceil(dn_sample_factor);
81    let bclk_div = clk.bclk_div.max(PDM_RX_BCLK_DIV_MIN).max(bclk_limit);
82
83    let mclk = bclk * bclk_div;
84    let sclk = soc::i2s_sclk_frequency();
85    let mut dividers = calculate_mclk_dividers(sclk, mclk)?;
86    dividers.bclk_divider = bclk_div;
87
88    Ok(PdmRxClockResult { dividers })
89}
90
91impl PdmDownsampleRate {
92    fn factor(self) -> u32 {
93        match self {
94            PdmDownsampleRate::Dsr8s => 1,
95            PdmDownsampleRate::Dsr16s => 2,
96        }
97    }
98}
99
100impl PdmTxClockConfig {
101    /// Default codec-line PDM TX clock (`I2S_PDM_TX_CLK_DEFAULT_CONFIG`).
102    pub fn codec_default(sample_rate: Rate) -> Self {
103        Self {
104            sample_rate,
105            up_sample_fp: 960,
106            up_sample_fs: 480,
107            bclk_div: PDM_TX_BCLK_DIV_MIN,
108        }
109    }
110
111    /// Default DAC-line PDM TX clock (`I2S_PDM_TX_CLK_DAC_DEFAULT_CONFIG`).
112    pub fn dac_default(sample_rate: Rate) -> Self {
113        Self {
114            sample_rate,
115            up_sample_fp: 960,
116            up_sample_fs: sample_rate.as_hz() / 100,
117            bclk_div: 13,
118        }
119    }
120}
121
122impl PdmRxClockConfig {
123    /// Default PDM RX clock (`I2S_PDM_RX_CLK_DEFAULT_CONFIG`).
124    pub fn default(sample_rate: Rate) -> Self {
125        Self {
126            sample_rate,
127            downsample_rate: PdmDownsampleRate::Dsr8s,
128            bclk_div: PDM_RX_BCLK_DIV_MIN,
129        }
130    }
131}