const BDMA_BASE: u32 = 0x5802_5400;
const BDMA_ISR: u32 = BDMA_BASE + 0x00;
const BDMA_IFCR: u32 = BDMA_BASE + 0x04;
const CH1_BASE: u32 = BDMA_BASE + 0x08 + 0x14 * 1;
const CH1_CCR: u32 = CH1_BASE + 0x00;
const CH1_CNDTR: u32 = CH1_BASE + 0x04;
const CH1_CPAR: u32 = CH1_BASE + 0x08;
const CH1_CM0AR: u32 = CH1_BASE + 0x0C;
const CH1_CM1AR: u32 = CH1_BASE + 0x10;
const DMAMUX2_BASE: u32 = 0x5802_5800;
const DMAMUX2_C1CR: u32 = DMAMUX2_BASE + 0x04;
const RCC_AHB4ENR: u32 = 0x5802_44E0;
const CCR_EN: u32 = 1 << 0;
const CCR_TCIE: u32 = 1 << 1;
const CCR_HTIE: u32 = 1 << 2;
#[allow(dead_code)]
const CCR_TEIE: u32 = 1 << 3;
const CCR_MINC: u32 = 1 << 7;
const CCR_PSIZE_16: u32 = 0b01 << 8;
const CCR_MSIZE_16: u32 = 0b01 << 10;
const CCR_PL_HIGH: u32 = 0b10 << 12;
const CCR_CIRC: u32 = 1 << 5;
const CCR_DBM: u32 = 1 << 15;
const CCR_CT: u32 = 1 << 16;
const ISR_GIF1: u32 = 1 << 4;
const ISR_TCIF1: u32 = 1 << 5;
const ISR_HTIF1: u32 = 1 << 6;
const ISR_TEIF1: u32 = 1 << 7;
const IFCR_ALL_CH1: u32 = ISR_GIF1 | ISR_TCIF1 | ISR_HTIF1 | ISR_TEIF1;
const SAI4A_DMAREQ_ID: u32 = 15;
pub struct BdmaSai4Rx {
ndtr: u16,
}
impl BdmaSai4Rx {
pub fn new() -> Self {
Self { ndtr: 0 }
}
pub fn enable_clock(&self) {
unsafe {
let reg = RCC_AHB4ENR as *mut u32;
reg.write_volatile(reg.read_volatile() | (1 << 21)); let _ = (reg as *const u32).read_volatile(); }
}
pub fn configure(
&mut self,
periph_addr: u32,
buf0: *mut u16,
buf1: *mut u16,
buf_bytes: usize,
) {
let transfers = (buf_bytes / 2) as u16;
self.ndtr = transfers;
unsafe {
let ccr = CH1_CCR as *mut u32;
ccr.write_volatile(ccr.read_volatile() & !CCR_EN);
while (ccr as *const u32).read_volatile() & CCR_EN != 0 {}
(BDMA_IFCR as *mut u32).write_volatile(IFCR_ALL_CH1);
(CH1_CNDTR as *mut u32).write_volatile(transfers as u32);
(CH1_CPAR as *mut u32).write_volatile(periph_addr);
(CH1_CM0AR as *mut u32).write_volatile(buf0 as u32);
(CH1_CM1AR as *mut u32).write_volatile(buf1 as u32);
(DMAMUX2_C1CR as *mut u32).write_volatile(SAI4A_DMAREQ_ID);
let ccr_val = CCR_CIRC
| CCR_MINC
| CCR_PSIZE_16
| CCR_MSIZE_16
| CCR_PL_HIGH
| CCR_DBM
| CCR_TCIE
| CCR_HTIE;
ccr.write_volatile(ccr_val);
}
}
pub fn start(&self) {
unsafe {
let ccr = CH1_CCR as *mut u32;
ccr.write_volatile(ccr.read_volatile() | CCR_EN);
}
}
pub fn stop(&self) {
unsafe {
let ccr = CH1_CCR as *mut u32;
ccr.write_volatile(ccr.read_volatile() & !CCR_EN);
while (ccr as *const u32).read_volatile() & CCR_EN != 0 {}
(BDMA_IFCR as *mut u32).write_volatile(IFCR_ALL_CH1);
}
}
pub fn current_target(&self) -> u8 {
unsafe {
if (CH1_CCR as *const u32).read_volatile() & CCR_CT != 0 {
1
} else {
0
}
}
}
pub fn transfer_complete(&self) -> bool {
unsafe { (BDMA_ISR as *const u32).read_volatile() & ISR_TCIF1 != 0 }
}
pub fn half_transfer(&self) -> bool {
unsafe { (BDMA_ISR as *const u32).read_volatile() & ISR_HTIF1 != 0 }
}
pub fn clear_transfer_complete(&self) {
unsafe {
(BDMA_IFCR as *mut u32).write_volatile(ISR_TCIF1);
}
}
pub fn clear_half_transfer(&self) {
unsafe {
(BDMA_IFCR as *mut u32).write_volatile(ISR_HTIF1);
}
}
pub fn clear_all_flags(&self) {
unsafe {
(BDMA_IFCR as *mut u32).write_volatile(IFCR_ALL_CH1);
}
}
pub fn transfers_per_buffer(&self) -> u16 {
self.ndtr
}
}