#![allow(unused_macros)]
#![deny(warnings)]
#![no_main]
#![no_std]
use cortex_m::asm;
use cortex_m_rt::entry;
use hal::device;
use hal::dma;
use hal::rcc::rec::Sai1ClkSel;
use hal::sai::{self, I2sUsers, SaiChannel, SaiI2sExt};
use hal::stm32;
use hal::{pac, prelude::*};
use stm32h7xx_hal as hal;
use stm32h7xx_hal::rcc;
use stm32h7xx_hal::time::Hertz;
use stm32h7xx_hal::traits::i2s::FullDuplex;
use pac::interrupt;
use log::info;
#[macro_use]
mod utilities;
const DMA_BUFFER_LENGTH: usize = 48 * 2 * 2;
const AUDIO_SAMPLE_HZ: Hertz = Hertz::from_raw(48_000);
const PLL3_P_HZ: Hertz = Hertz::from_raw(AUDIO_SAMPLE_HZ.raw() * 257);
#[link_section = ".sram3"]
static mut TX_BUFFER: [u32; DMA_BUFFER_LENGTH] = [0; DMA_BUFFER_LENGTH];
#[link_section = ".sram3"]
static mut RX_BUFFER: [u32; DMA_BUFFER_LENGTH] = [0; DMA_BUFFER_LENGTH];
pub const CLOCK_RATE_HZ: Hertz = Hertz::MHz(400);
const HSE_CLOCK_MHZ: Hertz = Hertz::MHz(16);
const PCLK_HZ: Hertz = Hertz::from_raw(CLOCK_RATE_HZ.raw() / 4);
const PLL1_P_HZ: Hertz = CLOCK_RATE_HZ;
#[entry]
fn main() -> ! {
utilities::logger::init();
let dp = hal::pac::Peripherals::take().unwrap();
let pwr = dp.PWR.constrain();
let vos = pwr.freeze();
let ccdr = dp
.RCC
.constrain()
.use_hse(HSE_CLOCK_MHZ)
.sys_ck(CLOCK_RATE_HZ)
.pclk1(PCLK_HZ) .pll1_strategy(rcc::PllConfigStrategy::Iterative)
.pll1_p_ck(PLL1_P_HZ)
.pll3_strategy(rcc::PllConfigStrategy::Iterative)
.pll3_p_ck(PLL3_P_HZ)
.freeze(vos, &dp.SYSCFG);
let mut core = device::CorePeripherals::take().unwrap();
core.SCB.enable_icache();
let sai1_rec = ccdr.peripheral.SAI1.kernel_clk_mux(Sai1ClkSel::Pll3P);
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
let mut ak4556_reset = gpiob.pb11.into_push_pull_output();
let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
let sai1_pins = (
gpioe.pe2.into_alternate(), gpioe.pe5.into_alternate(), gpioe.pe4.into_alternate(), gpioe.pe6.into_alternate(), Some(gpioe.pe3.into_alternate()), );
let dma1_streams =
dma::dma::StreamsTuple::new(dp.DMA1, ccdr.peripheral.DMA1);
let tx_buffer: &'static mut [u32; DMA_BUFFER_LENGTH] =
unsafe { &mut TX_BUFFER };
let dma_config = dma::dma::DmaConfig::default()
.priority(dma::config::Priority::High)
.memory_increment(true)
.peripheral_increment(false)
.circular_buffer(true)
.fifo_enable(false);
let mut dma1_str0: dma::Transfer<_, _, dma::MemoryToPeripheral, _, _> =
dma::Transfer::init(
dma1_streams.0,
unsafe { pac::Peripherals::steal().SAI1.dma_ch_b() }, tx_buffer,
None,
dma_config,
);
let rx_buffer: &'static mut [u32; DMA_BUFFER_LENGTH] =
unsafe { &mut RX_BUFFER };
let dma_config = dma_config
.transfer_complete_interrupt(true)
.half_transfer_interrupt(true);
let mut dma1_str1: dma::Transfer<_, _, dma::PeripheralToMemory, _, _> =
dma::Transfer::init(
dma1_streams.1,
unsafe { pac::Peripherals::steal().SAI1.dma_ch_a() }, rx_buffer,
None,
dma_config,
);
let sai1_tx_config = sai::I2SChanConfig::new(sai::I2SDir::Tx)
.set_frame_sync_active_high(true)
.set_clock_strobe(sai::I2SClockStrobe::Falling);
let sai1_rx_config = sai::I2SChanConfig::new(sai::I2SDir::Rx)
.set_sync_type(sai::I2SSync::Internal)
.set_frame_sync_active_high(true)
.set_clock_strobe(sai::I2SClockStrobe::Rising);
let mut sai1 = dp.SAI1.i2s_ch_a(
sai1_pins,
AUDIO_SAMPLE_HZ,
sai::I2SDataSize::BITS_24,
sai1_rec,
&ccdr.clocks,
I2sUsers::new(sai1_tx_config).add_slave(sai1_rx_config),
);
ak4556_reset.set_low();
asm::delay(480_000); ak4556_reset.set_high();
unsafe {
pac::NVIC::unmask(pac::Interrupt::DMA1_STR1);
}
dma1_str1.start(|_sai1_rb| {
sai1.enable_dma(SaiChannel::ChannelB);
});
dma1_str0.start(|sai1_rb| {
sai1.enable_dma(SaiChannel::ChannelA);
info!("sai1 fifo waiting to receive data");
while sai1_rb.cha().sr.read().flvl().is_empty() {}
info!("audio started");
sai1.enable();
sai1.try_send(0, 0).unwrap();
});
type TransferDma1Str1 = dma::Transfer<
dma::dma::Stream1<stm32::DMA1>,
sai::dma::ChannelA<stm32::SAI1>,
dma::PeripheralToMemory,
&'static mut [u32; DMA_BUFFER_LENGTH],
dma::DBTransfer,
>;
static mut TRANSFER_DMA1_STR1: Option<TransferDma1Str1> = None;
unsafe {
TRANSFER_DMA1_STR1 = Some(dma1_str1);
info!(
"{:?}, {:?}",
&TX_BUFFER[0] as *const u32, &RX_BUFFER[0] as *const u32
);
}
#[interrupt]
fn DMA1_STR1() {
let tx_buffer: &'static mut [u32; DMA_BUFFER_LENGTH] =
unsafe { &mut TX_BUFFER };
let rx_buffer: &'static mut [u32; DMA_BUFFER_LENGTH] =
unsafe { &mut RX_BUFFER };
let stereo_block_length = tx_buffer.len() / 2;
if let Some(transfer) = unsafe { &mut TRANSFER_DMA1_STR1 } {
let skip = if transfer.get_half_transfer_flag() {
transfer.clear_half_transfer_interrupt();
(0, stereo_block_length)
} else if transfer.get_transfer_complete_flag() {
transfer.clear_transfer_complete_interrupt();
(stereo_block_length, 0)
} else {
return;
};
let mut index = 0;
while index < stereo_block_length {
let tx0 = index + skip.0;
let tx1 = tx0 + 1;
let rx0 = index + skip.1;
let rx1 = rx0 + 1;
tx_buffer[tx0] = rx_buffer[rx0];
tx_buffer[tx1] = rx_buffer[rx1];
index += 2;
}
}
}
loop {
asm::wfi();
}
}