Skip to content

Commit 1cf5f2f

Browse files
tacertainclaude
andcommitted
Add SAI clock gates, Audio PLL config, and SAI resources in BSP
Enable SAI1-3 clock gates, configure Audio PLL (PLL4) for 44.1 kHz sample rates, and expose sai1/sai2/sai3 register blocks in board Resources. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0d6b3de commit 1cf5f2f

6 files changed

Lines changed: 83 additions & 8 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Cargo.lock
55
/out
66
/svd/imxrt1062/*
77
.vscode/
8+
.claude/
89

910
# Let developers specify their own configs in non Teensy crates
1011
imxrt1062-fcb-gen/.cargo

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
Add LPUART5 and LPUART7 aliases, resources, to teensy4-bsp.
66

7+
Add SAI clock gates, Audio PLL config, and SAI resources in BSP
8+
79
## [0.5.1] 2024-11-11
810

911
Add additional LPSPI instances and type aliases.

examples/rtic_defmt_usb_log.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,19 +179,19 @@ mod app {
179179
defmt::println!("Hello from defmt! The count is {=u32}", counter);
180180
defmt::trace!("TRACE: {=u32}", counter);
181181

182-
if counter % 3 == 0 {
182+
if counter.is_multiple_of(3) {
183183
defmt::debug!("DEBUG: {=u32}", counter);
184184
}
185185

186-
if counter % 5 == 0 {
186+
if counter.is_multiple_of(5) {
187187
defmt::info!("INFO: {=u32}", counter);
188188
}
189189

190-
if counter % 7 == 0 {
190+
if counter.is_multiple_of(7) {
191191
defmt::warn!("WARN: {=u32}", counter);
192192
}
193193

194-
if counter % 31 == 0 {
194+
if counter.is_multiple_of(31) {
195195
defmt::error!("ERROR: {=u32}", counter);
196196
}
197197

examples/rtic_usb_log.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,19 @@ mod app {
9090

9191
log::trace!("TRACE: {counter}");
9292

93-
if counter % 3 == 0 {
93+
if counter.is_multiple_of(3) {
9494
log::debug!("DEBUG: {counter}");
9595
}
9696

97-
if counter % 5 == 0 {
97+
if counter.is_multiple_of(5) {
9898
log::info!("INFO: {counter}");
9999
}
100100

101-
if counter % 7 == 0 {
101+
if counter.is_multiple_of(7) {
102102
log::warn!("WARN: {counter}");
103103
}
104104

105-
if counter % 31 == 0 {
105+
if counter.is_multiple_of(31) {
106106
log::error!("ERROR: {counter}");
107107
}
108108

src/board.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,16 @@ pub struct Resources<Pins> {
289289
pub trng: hal::trng::Trng,
290290
/// Temperature monitor of the core.
291291
pub tempmon: hal::tempmon::TempMon,
292+
/// The register block for SAI1 (I2S audio).
293+
///
294+
/// SAI1 is the primary audio interface used by the Teensy Audio Shield.
295+
pub sai1: ral::sai::SAI1,
296+
/// The register block for SAI2.
297+
pub sai2: ral::sai::SAI2,
298+
/// The register block for SAI3.
299+
pub sai3: ral::sai::SAI3,
300+
/// The IOMUXC general purpose register block.
301+
pub iomuxc_gpr: ral::iomuxc_gpr::IOMUXC_GPR,
292302
}
293303

294304
/// The board's dedicated LED.
@@ -675,6 +685,10 @@ fn prepare_resources<Pins>(
675685
adc2,
676686
trng,
677687
tempmon,
688+
sai1: instances.SAI1,
689+
sai2: instances.SAI2,
690+
sai3: instances.SAI3,
691+
iomuxc_gpr: instances.IOMUXC_GPR,
678692
}
679693
}
680694

src/clock_power.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
176229
const 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

Comments
 (0)