const DMA1_BASE: u32 = 0x4002_0000;
const DMA1_LISR: u32 = DMA1_BASE + 0x000;
const DMA1_LIFCR: u32 = DMA1_BASE + 0x008;
const S0_BASE: u32 = DMA1_BASE + 0x010;
const S0CR: u32 = S0_BASE + 0x00;
const S0NDTR: u32 = S0_BASE + 0x04;
const S0PAR: u32 = S0_BASE + 0x08;
const S0M0AR: u32 = S0_BASE + 0x0C;
const S0M1AR: u32 = S0_BASE + 0x10;
const S0FCR: u32 = S0_BASE + 0x14;
const DMAMUX1_BASE: u32 = 0x4002_0800;
const DMAMUX1_C0CR: u32 = DMAMUX1_BASE + 0x000;
const RCC_AHB1ENR: u32 = 0x5802_44D8;
const CR_EN: u32 = 1 << 0;
#[allow(dead_code)]
const CR_TCIE: u32 = 1 << 4; #[allow(dead_code)]
const CR_HTIE: u32 = 1 << 3; const CR_DIR_M2P: u32 = 0b01 << 6;
const CR_CIRC: u32 = 1 << 8;
const CR_MINC: u32 = 1 << 10;
const CR_PSIZE_16: u32 = 0b01 << 11;
const CR_MSIZE_16: u32 = 0b01 << 13;
const CR_PL_HIGH: u32 = 0b10 << 16;
const CR_DBM: u32 = 1 << 18;
const CR_CT: u32 = 1 << 19;
const CR_TRBUFF: u32 = 1 << 20;
const FCR_DMDIS: u32 = 1 << 2;
const FCR_FTH_FULL: u32 = 0b11;
const LISR_TCIF0: u32 = 1 << 5;
const LISR_HTIF0: u32 = 1 << 4;
const LISR_TEIF0: u32 = 1 << 3;
const LISR_DMEIF0: u32 = 1 << 2;
const LISR_FEIF0: u32 = 1 << 0;
const LIFCR_ALL_S0: u32 = LISR_TCIF0 | LISR_HTIF0 | LISR_TEIF0 | LISR_DMEIF0 | LISR_FEIF0;
const SAI1A_DMAREQ_ID: u32 = 87;
pub struct DmaSai1Tx {
ndtr: u16,
}
impl DmaSai1Tx {
pub fn new() -> Self {
Self { ndtr: 0 }
}
pub fn enable_clock(&self) {
unsafe {
let reg = RCC_AHB1ENR as *mut u32;
reg.write_volatile(reg.read_volatile() | 1); let _ = (reg as *const u32).read_volatile();
}
}
pub fn configure(
&mut self,
periph_addr: u32,
buf0: *const u8,
buf1: *const u8,
buf_bytes: usize,
) {
let transfers = (buf_bytes / 2) as u16; self.ndtr = transfers;
unsafe {
let cr = S0CR as *mut u32;
cr.write_volatile(cr.read_volatile() & !CR_EN);
while (cr as *const u32).read_volatile() & CR_EN != 0 {}
(DMA1_LIFCR as *mut u32).write_volatile(LIFCR_ALL_S0);
(S0NDTR as *mut u32).write_volatile(transfers as u32);
(S0PAR as *mut u32).write_volatile(periph_addr);
(S0M0AR as *mut u32).write_volatile(buf0 as u32);
(S0M1AR as *mut u32).write_volatile(buf1 as u32);
(S0FCR as *mut u32).write_volatile(FCR_DMDIS | FCR_FTH_FULL);
(DMAMUX1_C0CR as *mut u32).write_volatile(SAI1A_DMAREQ_ID);
let cr_val = CR_DIR_M2P
| CR_CIRC
| CR_MINC
| CR_PSIZE_16
| CR_MSIZE_16
| CR_PL_HIGH
| CR_DBM
| CR_TRBUFF;
cr.write_volatile(cr_val);
}
}
pub fn start(&self) {
unsafe {
let cr = S0CR as *mut u32;
cr.write_volatile(cr.read_volatile() | CR_EN);
}
}
pub fn stop(&self) {
unsafe {
let cr = S0CR as *mut u32;
cr.write_volatile(cr.read_volatile() & !CR_EN);
while (cr as *const u32).read_volatile() & CR_EN != 0 {}
(DMA1_LIFCR as *mut u32).write_volatile(LIFCR_ALL_S0);
}
}
pub fn current_target(&self) -> u8 {
unsafe {
let cr = (S0CR as *const u32).read_volatile();
if cr & CR_CT != 0 { 1 } else { 0 }
}
}
pub fn transfer_complete(&self) -> bool {
unsafe { (DMA1_LISR as *const u32).read_volatile() & LISR_TCIF0 != 0 }
}
pub fn half_transfer(&self) -> bool {
unsafe { (DMA1_LISR as *const u32).read_volatile() & LISR_HTIF0 != 0 }
}
pub fn clear_transfer_complete(&self) {
unsafe {
(DMA1_LIFCR as *mut u32).write_volatile(LISR_TCIF0);
}
}
pub fn clear_half_transfer(&self) {
unsafe {
(DMA1_LIFCR as *mut u32).write_volatile(LISR_HTIF0);
}
}
pub fn clear_all_flags(&self) {
unsafe {
(DMA1_LIFCR as *mut u32).write_volatile(LIFCR_ALL_S0);
}
}
pub fn transfers_per_buffer(&self) -> u16 {
self.ndtr
}
}