From b5a635371434f4b71554d841ca8bb66ce824578f Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Mon, 3 Feb 2025 22:40:42 -0500 Subject: [PATCH 1/2] update examples/stm32f4/.../i2s_dma.rs --- examples/stm32f4/src/bin/i2s_dma.rs | 82 +++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs index 68392847b..618717cc9 100644 --- a/examples/stm32f4/src/bin/i2s_dma.rs +++ b/examples/stm32f4/src/bin/i2s_dma.rs @@ -1,33 +1,81 @@ +// This example is written for an STM32F411 chip communicating with an external +// PCM5102a DAC. Remap pins, change clock speeds, etc. as necessary for your own +// hardware. +// +// NOTE: This example outputs potentially loud audio. Please run responsibly. + #![no_std] #![no_main] -use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::i2s::{Config, I2S}; +use embassy_stm32::i2s::{Config, Format, I2S}; use embassy_stm32::time::Hertz; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); - info!("Hello World!"); + let config = { + use embassy_stm32::rcc::*; - let mut dma_buffer = [0x00_u16; 128]; + let mut config = embassy_stm32::Config::default(); + config.rcc.hse = Some(Hse { + freq: Hertz::mhz(25), + mode: HseMode::Oscillator, + }); + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV25, + mul: PllMul::MUL192, + divp: Some(PllPDiv::DIV2), + divq: Some(PllQDiv::DIV4), + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; - let mut i2s = I2S::new_txonly( - p.SPI2, - p.PC3, // sd - p.PB12, // ws - p.PB10, // ck - p.PC6, // mck - p.DMA1_CH4, + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + + config.rcc.plli2s = Some(Pll { + prediv: PllPreDiv::DIV25, + mul: PllMul::MUL384, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV5), + }); + config.enable_debug_during_sleep = true; + + config + }; + + let p = embassy_stm32::init(config); + + // stereo wavetable generation + let mut wavetable = [0u16; 1200]; + for (i, frame) in wavetable.chunks_mut(2).enumerate() { + frame[0] = ((((i / 150) % 2) * 2048) as i16 - 1024) as u16; // 160 Hz square wave in left channel + frame[1] = ((((i / 100) % 2) * 2048) as i16 - 1024) as u16; // 240 Hz square wave in right channel + } + + // i2s configuration + let mut dma_buffer = [0u16; 2400]; + + let mut i2s_config = Config::default(); + i2s_config.format = Format::Data16Channel32; + i2s_config.master_clock = false; + let mut i2s = I2S::new_txonly_nomck( + p.SPI3, + p.PB5, // sd + p.PA15, // ws + p.PB3, // ck + p.DMA1_CH7, &mut dma_buffer, - Hertz(1_000_000), - Config::default(), + Hertz(48_000), + i2s_config, ); + i2s.start(); - for i in 0_u16.. { - i2s.write(&mut [i * 2; 64]).await.ok(); - i2s.write(&mut [i * 2 + 1; 64]).await.ok(); + loop { + i2s.write(&wavetable).await.ok(); } } From b0e3a6481b5bacadc3d538f571d21f96b274934e Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Mon, 3 Feb 2025 22:52:38 -0500 Subject: [PATCH 2/2] document clock settings in examples/stm32f4/.../i2s_dma.rs --- examples/stm32f4/src/bin/i2s_dma.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs index 618717cc9..db5103d0f 100644 --- a/examples/stm32f4/src/bin/i2s_dma.rs +++ b/examples/stm32f4/src/bin/i2s_dma.rs @@ -36,6 +36,8 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; + // reference your chip's manual for proper clock settings; this config + // is recommended for a 32 bit frame at 48 kHz sample rate config.rcc.plli2s = Some(Pll { prediv: PllPreDiv::DIV25, mul: PllMul::MUL384,