use core::num::Wrapping;
use core::ptr;
use super::codec::{Codec, Pins as CodecPins};
use super::transfer::{Channel, Config as TransferConfig, Sai1Pins, State, Sync, Transfer};
use super::{BLOCK_LENGTH, DMA_BUFFER_LENGTH, FS, HALF_DMA_BUFFER_LENGTH};
use crate::hal;
use hal::pac::{CPUID, CorePeripherals};
use hal::time;
#[unsafe(link_section = ".sram1_bss")]
static mut TX_BUFFER: [u32; DMA_BUFFER_LENGTH] = [0; DMA_BUFFER_LENGTH];
#[unsafe(link_section = ".sram1_bss")]
static mut RX_BUFFER: [u32; DMA_BUFFER_LENGTH] = [0; DMA_BUFFER_LENGTH];
pub type Frame = (f32, f32);
pub type Block = [Frame; BLOCK_LENGTH];
#[derive(Debug)]
pub enum Error {
I2c,
Dma,
}
pub struct Interface {
pub fs: time::Hertz,
codec: Codec,
transfer: Transfer,
}
impl Interface {
pub fn init(
clocks: &hal::rcc::CoreClocks,
sai1_rec: hal::rcc::rec::Sai1,
sai1_pins: Sai1Pins,
codec_pins: CodecPins,
#[allow(unused_variables)] i2c2_rec: hal::rcc::rec::I2c2,
dma1_rec: hal::rcc::rec::Dma1,
) -> Result<Interface, Error> {
#[cfg(any(feature = "seed", feature = "seed_1_2"))]
let codec = Codec::init(codec_pins);
#[cfg(any(feature = "seed_1_1", feature = "patch_sm"))]
let codec = Codec::init(clocks, i2c2_rec, codec_pins);
#[cfg(any(feature = "seed_1_2", feature = "seed"))]
let transfer_config = TransferConfig {
tx_channel: Channel::A,
rx_channel: Channel::B,
tx_sync: Sync::Master,
rx_sync: Sync::Slave,
};
#[cfg(any(feature = "seed_1_1", feature = "patch_sm"))]
let transfer_config = TransferConfig {
tx_channel: Channel::B,
rx_channel: Channel::A,
tx_sync: Sync::Slave,
rx_sync: Sync::Master,
};
let transfer = Transfer::init(
clocks,
sai1_rec,
sai1_pins,
dma1_rec,
unsafe { &mut *ptr::addr_of_mut!(TX_BUFFER) },
unsafe { &mut *ptr::addr_of_mut!(RX_BUFFER) },
transfer_config,
);
validate_slice_against_cache_line(unsafe { &*ptr::addr_of!(TX_BUFFER) });
validate_slice_against_cache_line(unsafe { &*ptr::addr_of!(RX_BUFFER) });
Ok(Self {
fs: FS,
codec,
transfer,
})
}
pub fn spawn(mut self) -> Result<Self, Error> {
self.codec.start();
self.transfer.start();
Ok(self)
}
pub fn handle_interrupt_dma1_str1(
&mut self,
mut callback: impl FnMut(&mut [(f32, f32); BLOCK_LENGTH]),
) -> Result<(), Error> {
let skip = match self.transfer.examine_interrupt() {
Ok(State::HalfSent) => (0, HALF_DMA_BUFFER_LENGTH),
Ok(State::FullSent) => (HALF_DMA_BUFFER_LENGTH, 0),
_ => return Err(Error::Dma),
};
let mut block: Block = [(0.0, 0.0); BLOCK_LENGTH];
unsafe {
CorePeripherals::steal()
.SCB
.invalidate_dcache_by_slice(&mut *ptr::addr_of_mut!(RX_BUFFER));
}
let mut dma_index: usize = 0;
let mut block_index: usize = 0;
while dma_index < HALF_DMA_BUFFER_LENGTH {
let rx0: usize = dma_index + skip.1;
let rx1: usize = rx0 + 1;
let rx_y0 = unsafe { RX_BUFFER[rx0] };
let rx_y1 = unsafe { RX_BUFFER[rx1] };
let y0 = u24_to_f32(rx_y0);
let y1 = u24_to_f32(rx_y1);
block[block_index] = (y0, y1);
dma_index += 2;
block_index += 1;
}
callback(&mut block);
let mut dma_index: usize = 0;
let mut block_index: usize = 0;
while dma_index < HALF_DMA_BUFFER_LENGTH {
let tx0: usize = dma_index + skip.0;
let tx1: usize = tx0 + 1;
let (y1, y0) = block[block_index];
unsafe { TX_BUFFER[tx0] = f32_to_u24(y0) };
unsafe { TX_BUFFER[tx1] = f32_to_u24(y1) };
dma_index += 2;
block_index += 1;
}
unsafe {
CorePeripherals::steal()
.SCB
.clean_dcache_by_slice(&*ptr::addr_of!(TX_BUFFER));
}
Ok(())
}
}
fn validate_slice_against_cache_line<T>(slice: &[T]) {
let addr = slice.as_ptr() as usize;
let size = slice.len() * core::mem::size_of_val(slice);
let dminline = CPUID::cache_dminline();
let line_size = (1 << dminline) * 4;
assert!((addr & (line_size - 1)) == 0);
assert!((size & (line_size - 1)) == 0);
}
#[inline(always)]
fn u24_to_f32(y: u32) -> f32 {
let y = (Wrapping(y) + Wrapping(0x0080_0000)).0 & 0x00FF_FFFF; (y as f32 / 8_388_608.0) - 1.0 }
#[inline(always)]
fn f32_to_u24(x: f32) -> u32 {
let x = x * 8_388_607.0;
let x = x.clamp(-8_388_608.0, 8_388_607.0);
(x as i32) as u32
}