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