@@ -173,6 +173,59 @@ fn setup_lpspi_clk(ccm: &mut ral::ccm::CCM) {
173173 ccm:: lpspi_clk:: set_divider ( ccm, LPSPI_DIVIDER ) ;
174174}
175175
176+ // --- Audio PLL (PLL4) and SAI clock configuration ---
177+ //
178+ // The Audio PLL is configured to produce a MCLK that yields a ~44117.647 Hz sample rate.
179+ // This mirrors the Teensy Audio Library's C++ `set_audioClock(28, 2348, 10000)`:
180+ //
181+ // PLL4 = 24 MHz × (28 + 2348/10000) / 1 = 677,635,200 Hz
182+ // SAI1_CLK = PLL4 / prediv(4) / podf(15) = 11,293,920 Hz (MCLK)
183+ // Sample rate = MCLK / 256 ≈ 44,117.656 Hz
184+ //
185+
186+ /// Audio PLL (PLL4) divider selection.
187+ const AUDIO_PLL_DIV_SELECT : u32 = 28 ;
188+ /// Audio PLL numerator.
189+ const AUDIO_PLL_NUM : u32 = 2348 ;
190+ /// Audio PLL denominator.
191+ const AUDIO_PLL_DENOM : u32 = 10000 ;
192+
193+ /// SAI clock predivider (1..=8).
194+ const SAI_CLK_PREDIVIDER : u32 = 4 ;
195+ /// SAI clock post-divider (1..=64).
196+ const SAI_CLK_DIVIDER : u32 = 15 ;
197+
198+ /// Frequency (Hz) of the SAI MCLK after all dividers.
199+ ///
200+ /// Approximately 11,293,920 Hz, yielding ~44,117.656 Hz sample rate
201+ /// when MCLK/BCLK ratio is 256.
202+ pub const SAI_MCLK_FREQUENCY : u32 = {
203+ // PLL4 output frequency (with post_div = 1):
204+ // 24_000_000 * (28 + 2348/10000) = 24_000_000 * 28 + 24_000_000 * 2348 / 10000
205+ let pll4_freq: u32 = XTAL_OSCILLATOR_HZ * AUDIO_PLL_DIV_SELECT
206+ + XTAL_OSCILLATOR_HZ / AUDIO_PLL_DENOM * AUDIO_PLL_NUM ;
207+ pll4_freq / SAI_CLK_PREDIVIDER / SAI_CLK_DIVIDER
208+ } ;
209+
210+ /// Configure the Audio PLL (PLL4) for 44.1 kHz–family sample rates.
211+ fn setup_audio_pll ( ccm_analog : & mut ral:: ccm_analog:: CCM_ANALOG ) {
212+ ccm:: analog:: pll4:: reconfigure (
213+ ccm_analog,
214+ AUDIO_PLL_DIV_SELECT ,
215+ AUDIO_PLL_NUM ,
216+ AUDIO_PLL_DENOM ,
217+ ccm:: analog:: pll4:: PostDivider :: U1 ,
218+ ) ;
219+ }
220+
221+ /// Configure SAI1 clock root to derive from Audio PLL.
222+ fn setup_sai1_clk ( ccm : & mut ral:: ccm:: CCM ) {
223+ clock_gate:: sai :: < 1 > ( ) . set ( ccm, clock_gate:: OFF ) ;
224+ ccm:: sai_clk:: set_selection :: < 1 > ( ccm, ccm:: sai_clk:: Selection :: Pll4 ) ;
225+ ccm:: sai_clk:: set_predivider :: < 1 > ( ccm, SAI_CLK_PREDIVIDER ) ;
226+ ccm:: sai_clk:: set_divider :: < 1 > ( ccm, SAI_CLK_DIVIDER ) ;
227+ }
228+
176229const CLOCK_GATES : & [ clock_gate:: Locator ] = & [
177230 clock_gate:: pit ( ) ,
178231 clock_gate:: gpt_bus :: < 1 > ( ) ,
@@ -211,6 +264,9 @@ const CLOCK_GATES: &[clock_gate::Locator] = &[
211264 clock_gate:: adc :: < 1 > ( ) ,
212265 clock_gate:: adc :: < 2 > ( ) ,
213266 clock_gate:: trng ( ) ,
267+ clock_gate:: sai :: < 1 > ( ) ,
268+ clock_gate:: sai :: < 2 > ( ) ,
269+ clock_gate:: sai :: < 3 > ( ) ,
214270] ;
215271
216272/// Prepare clocks and power for the MCU.
@@ -231,6 +287,8 @@ pub fn prepare_clocks_and_power(
231287 setup_lpspi_clk ( ccm) ;
232288 setup_perclk_clk ( ccm) ;
233289 setup_uart_clk ( ccm) ;
290+ setup_audio_pll ( ccm_analog) ;
291+ setup_sai1_clk ( ccm) ;
234292
235293 CLOCK_GATES
236294 . iter ( )
0 commit comments