//! Daisy Seed rev.7(with PCM3060 codec) //! https://electro-smith.com/products/daisy-seed #![no_std] #![no_main] use embassy_executor::Spawner; use grounded::uninit::GroundedArrayCell; use hal::rcc::*; use hal::sai::*; use hal::time::Hertz; use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _}; const BLOCK_LENGTH: usize = 32; // 32 samples const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * 2; // 2 channels const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks const SAMPLE_RATE: u32 = 48000; //DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions #[unsafe(link_section = ".sram1_bss")] static mut TX_BUFFER: GroundedArrayCell = GroundedArrayCell::uninit(); #[unsafe(link_section = ".sram1_bss")] static mut RX_BUFFER: GroundedArrayCell = GroundedArrayCell::uninit(); #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = hal::Config::default(); config.rcc.pll1 = Some(Pll { source: PllSource::HSE, prediv: PllPreDiv::DIV4, mul: PllMul::MUL200, divp: Some(PllDiv::DIV2), divq: Some(PllDiv::DIV5), divr: Some(PllDiv::DIV2), }); config.rcc.pll3 = Some(Pll { source: PllSource::HSE, prediv: PllPreDiv::DIV6, mul: PllMul::MUL295, divp: Some(PllDiv::DIV16), divq: Some(PllDiv::DIV4), divr: Some(PllDiv::DIV32), }); config.rcc.sys = Sysclk::PLL1_P; config.rcc.mux.sai1sel = hal::pac::rcc::vals::Saisel::PLL3_P; config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz config.rcc.hse = Some(Hse { freq: Hertz::mhz(16), mode: HseMode::Oscillator, }); let p = hal::init(config); let (sub_block_tx, sub_block_rx) = hal::sai::split_subblocks(p.SAI1); let kernel_clock = hal::rcc::frequency::().0; let mclk_div = mclk_div_from_u8((kernel_clock / (SAMPLE_RATE * 256)) as u8); let mut tx_config = hal::sai::Config::default(); tx_config.mode = Mode::Master; tx_config.tx_rx = TxRx::Transmitter; tx_config.sync_output = true; tx_config.clock_strobe = ClockStrobe::Falling; tx_config.master_clock_divider = mclk_div; tx_config.stereo_mono = StereoMono::Stereo; tx_config.data_size = DataSize::Data24; tx_config.bit_order = BitOrder::MsbFirst; tx_config.frame_sync_polarity = FrameSyncPolarity::ActiveHigh; tx_config.frame_sync_offset = FrameSyncOffset::OnFirstBit; tx_config.frame_length = 64; tx_config.frame_sync_active_level_length = embassy_stm32::sai::word::U7(32); tx_config.fifo_threshold = FifoThreshold::Quarter; let mut rx_config = tx_config.clone(); rx_config.mode = Mode::Slave; rx_config.tx_rx = TxRx::Receiver; rx_config.sync_input = SyncInput::Internal; rx_config.clock_strobe = ClockStrobe::Rising; rx_config.sync_output = false; let tx_buffer: &mut [u32] = unsafe { let buf = &mut *core::ptr::addr_of_mut!(TX_BUFFER); buf.initialize_all_copied(0); let (ptr, len) = buf.get_ptr_len(); core::slice::from_raw_parts_mut(ptr, len) }; let mut sai_transmitter = Sai::new_asynchronous_with_mclk( sub_block_tx, p.PE5, p.PE6, p.PE4, p.PE2, p.DMA1_CH0, tx_buffer, tx_config, ); let rx_buffer: &mut [u32] = unsafe { let buf = &mut *core::ptr::addr_of_mut!(RX_BUFFER); buf.initialize_all_copied(0); let (ptr, len) = buf.get_ptr_len(); core::slice::from_raw_parts_mut(ptr, len) }; let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config); sai_receiver.start().unwrap(); let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; loop { // write() must be called before read() to start the master (transmitter) // clock used by the receiver sai_transmitter.write(&buf).await.unwrap(); sai_receiver.read(&mut buf).await.unwrap(); } } const fn mclk_div_from_u8(v: u8) -> MasterClockDivider { match v { 1 => MasterClockDivider::Div1, 2 => MasterClockDivider::Div2, 3 => MasterClockDivider::Div3, 4 => MasterClockDivider::Div4, 5 => MasterClockDivider::Div5, 6 => MasterClockDivider::Div6, 7 => MasterClockDivider::Div7, 8 => MasterClockDivider::Div8, 9 => MasterClockDivider::Div9, 10 => MasterClockDivider::Div10, 11 => MasterClockDivider::Div11, 12 => MasterClockDivider::Div12, 13 => MasterClockDivider::Div13, 14 => MasterClockDivider::Div14, 15 => MasterClockDivider::Div15, 16 => MasterClockDivider::Div16, 17 => MasterClockDivider::Div17, 18 => MasterClockDivider::Div18, 19 => MasterClockDivider::Div19, 20 => MasterClockDivider::Div20, 21 => MasterClockDivider::Div21, 22 => MasterClockDivider::Div22, 23 => MasterClockDivider::Div23, 24 => MasterClockDivider::Div24, 25 => MasterClockDivider::Div25, 26 => MasterClockDivider::Div26, 27 => MasterClockDivider::Div27, 28 => MasterClockDivider::Div28, 29 => MasterClockDivider::Div29, 30 => MasterClockDivider::Div30, 31 => MasterClockDivider::Div31, 32 => MasterClockDivider::Div32, 33 => MasterClockDivider::Div33, 34 => MasterClockDivider::Div34, 35 => MasterClockDivider::Div35, 36 => MasterClockDivider::Div36, 37 => MasterClockDivider::Div37, 38 => MasterClockDivider::Div38, 39 => MasterClockDivider::Div39, 40 => MasterClockDivider::Div40, 41 => MasterClockDivider::Div41, 42 => MasterClockDivider::Div42, 43 => MasterClockDivider::Div43, 44 => MasterClockDivider::Div44, 45 => MasterClockDivider::Div45, 46 => MasterClockDivider::Div46, 47 => MasterClockDivider::Div47, 48 => MasterClockDivider::Div48, 49 => MasterClockDivider::Div49, 50 => MasterClockDivider::Div50, 51 => MasterClockDivider::Div51, 52 => MasterClockDivider::Div52, 53 => MasterClockDivider::Div53, 54 => MasterClockDivider::Div54, 55 => MasterClockDivider::Div55, 56 => MasterClockDivider::Div56, 57 => MasterClockDivider::Div57, 58 => MasterClockDivider::Div58, 59 => MasterClockDivider::Div59, 60 => MasterClockDivider::Div60, 61 => MasterClockDivider::Div61, 62 => MasterClockDivider::Div62, 63 => MasterClockDivider::Div63, _ => panic!(), } }