You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
8.7 KiB
184 lines
8.7 KiB
#define SOUND_RX_BUF_SIZE 1000U
|
|
#define SOUND_TX_BUF_SIZE (SOUND_RX_BUF_SIZE/2U)
|
|
#define MIC_RX_BUF_SIZE 512U
|
|
#define MIC_TX_BUF_SIZE (MIC_RX_BUF_SIZE * 2U)
|
|
__attribute__((section(".sram4"))) static uint16_t sound_rx_buf[2][SOUND_RX_BUF_SIZE];
|
|
__attribute__((section(".sram4"))) static uint16_t sound_tx_buf[2][SOUND_TX_BUF_SIZE];
|
|
__attribute__((section(".sram4"))) static uint32_t mic_rx_buf[2][MIC_RX_BUF_SIZE];
|
|
|
|
#define SOUND_IDLE_TIMEOUT 4U
|
|
static uint8_t sound_idle_count;
|
|
static uint8_t mic_idle_count;
|
|
|
|
void sound_tick(void) {
|
|
if (sound_idle_count > 0U) {
|
|
sound_idle_count--;
|
|
if (sound_idle_count == 0U) {
|
|
current_board->set_amp_enabled(false);
|
|
register_clear_bits(&DMA1_Stream1->CR, DMA_SxCR_EN);
|
|
}
|
|
}
|
|
|
|
if (mic_idle_count > 0U) {
|
|
mic_idle_count--;
|
|
if (mic_idle_count == 0U) {
|
|
register_clear_bits(&DFSDM1_Channel0->CHCFGR1, DFSDM_CHCFGR1_DFSDMEN);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Recording processing
|
|
static void DMA1_Stream0_IRQ_Handler(void) {
|
|
__attribute__((section(".sram4"))) static uint16_t tx_buf[MIC_TX_BUF_SIZE];
|
|
|
|
DMA1->LIFCR |= 0x7D; // clear flags
|
|
|
|
// process samples
|
|
uint8_t buf_idx = (((DMA1_Stream0->CR & DMA_SxCR_CT) >> DMA_SxCR_CT_Pos) == 1U) ? 0U : 1U;
|
|
for (uint16_t i=0U; i < MIC_RX_BUF_SIZE; i++) {
|
|
tx_buf[2U*i] = ((mic_rx_buf[buf_idx][i] >> 16U) & 0xFFFFU);
|
|
tx_buf[(2U*i)+1U] = tx_buf[2U*i];
|
|
}
|
|
|
|
BDMA->IFCR |= BDMA_IFCR_CGIF1;
|
|
BDMA_Channel1->CCR &= ~BDMA_CCR_EN;
|
|
register_set(&BDMA_Channel1->CM0AR, (uint32_t) tx_buf, 0xFFFFFFFFU);
|
|
BDMA_Channel1->CNDTR = MIC_TX_BUF_SIZE;
|
|
BDMA_Channel1->CCR |= BDMA_CCR_EN;
|
|
}
|
|
|
|
// Playback processing
|
|
static void BDMA_Channel0_IRQ_Handler(void) {
|
|
static uint8_t playback_buf = 0U;
|
|
|
|
BDMA->IFCR |= BDMA_IFCR_CGIF0; // clear flag
|
|
|
|
uint8_t rx_buf_idx = (((BDMA_Channel0->CCR & BDMA_CCR_CT) >> BDMA_CCR_CT_Pos) == 1U) ? 0U : 1U;
|
|
playback_buf = 1U - playback_buf;
|
|
|
|
// wait until we're done playing the current buf
|
|
for (uint32_t timeout_counter = 100000U; timeout_counter > 0U; timeout_counter--){
|
|
uint8_t playing_buf = (DMA1_Stream1->CR & DMA_SxCR_CT) >> DMA_SxCR_CT_Pos;
|
|
if ((playing_buf != playback_buf) || (!(DMA1_Stream1->CR & DMA_SxCR_EN))) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// process samples (shift to 12b and bias to be unsigned)
|
|
bool sound_playing = false;
|
|
for (uint16_t i=0U; i < SOUND_RX_BUF_SIZE; i += 2U) {
|
|
// since we are playing mono and receiving stereo, we take every other sample
|
|
sound_tx_buf[playback_buf][i/2U] = ((sound_rx_buf[rx_buf_idx][i] + (1UL << 14)) >> 3);
|
|
if (sound_rx_buf[rx_buf_idx][i] > 0U) {
|
|
sound_playing = true;
|
|
}
|
|
}
|
|
|
|
// manage amp state
|
|
if (sound_playing) {
|
|
if (sound_idle_count == 0U) {
|
|
current_board->set_amp_enabled(true);
|
|
|
|
// empty the other buf and start playing that
|
|
for (uint16_t i=0U; i < SOUND_TX_BUF_SIZE; i++) {
|
|
sound_tx_buf[1U - playback_buf][i] = (1UL << 11);
|
|
}
|
|
register_clear_bits(&DMA1_Stream1->CR, DMA_SxCR_EN);
|
|
register_set(&DMA1_Stream1->CR, (1UL - playback_buf) << DMA_SxCR_CT_Pos, DMA_SxCR_CT_Msk);
|
|
register_set_bits(&DMA1_Stream1->CR, DMA_SxCR_EN);
|
|
}
|
|
sound_idle_count = SOUND_IDLE_TIMEOUT;
|
|
}
|
|
|
|
// manage mic state
|
|
if (mic_idle_count == 0U) {
|
|
register_set_bits(&DFSDM1_Channel0->CHCFGR1, DFSDM_CHCFGR1_DFSDMEN);
|
|
DFSDM1_Filter0->FLTCR1 |= DFSDM_FLTCR1_RSWSTART;
|
|
}
|
|
mic_idle_count = SOUND_IDLE_TIMEOUT;
|
|
|
|
sound_tick();
|
|
}
|
|
|
|
void sound_init(void) {
|
|
REGISTER_INTERRUPT(BDMA_Channel0_IRQn, BDMA_Channel0_IRQ_Handler, 128U, FAULT_INTERRUPT_RATE_SOUND_DMA)
|
|
REGISTER_INTERRUPT(DMA1_Stream0_IRQn, DMA1_Stream0_IRQ_Handler, 128U, FAULT_INTERRUPT_RATE_SOUND_DMA)
|
|
|
|
// Init DAC
|
|
register_set(&DAC1->MCR, 0U, 0xFFFFFFFFU);
|
|
register_set(&DAC1->CR, DAC_CR_TEN1 | (4U << DAC_CR_TSEL1_Pos) | DAC_CR_DMAEN1, 0xFFFFFFFFU);
|
|
register_set_bits(&DAC1->CR, DAC_CR_EN1);
|
|
|
|
// Setup DMAMUX (DAC_CH1_DMA as input)
|
|
register_set(&DMAMUX1_Channel1->CCR, 67U, DMAMUX_CxCR_DMAREQ_ID_Msk);
|
|
|
|
// Setup DMA
|
|
register_set(&DMA1_Stream1->PAR, (uint32_t) &(DAC1->DHR12R1), 0xFFFFFFFFU);
|
|
register_set(&DMA1_Stream1->M0AR, (uint32_t) sound_tx_buf[0], 0xFFFFFFFFU);
|
|
register_set(&DMA1_Stream1->M1AR, (uint32_t) sound_tx_buf[1], 0xFFFFFFFFU);
|
|
register_set(&DMA1_Stream1->FCR, 0U, 0x00000083U);
|
|
DMA1_Stream1->NDTR = SOUND_TX_BUF_SIZE;
|
|
DMA1_Stream1->CR = DMA_SxCR_DBM | (0b11UL << DMA_SxCR_PL_Pos) | (0b01UL << DMA_SxCR_MSIZE_Pos) | (0b01UL << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC | (1U << DMA_SxCR_DIR_Pos);
|
|
|
|
// Init trigger timer (little slower than 48kHz, pulled in sync by SAI4_FS_B)
|
|
register_set(&TIM5->PSC, 2600U, 0xFFFFU);
|
|
register_set(&TIM5->ARR, 100U, 0xFFFFFFFFU); // not important
|
|
register_set(&TIM5->AF1, (0b0010UL << TIM5_AF1_ETRSEL_Pos), TIM5_AF1_ETRSEL_Msk);
|
|
register_set(&TIM5->CR2, (0b010U << TIM_CR2_MMS_Pos), TIM_CR2_MMS_Msk);
|
|
register_set(&TIM5->SMCR, TIM_SMCR_ECE | (0b00111UL << TIM_SMCR_TS_Pos)| (0b0100UL << TIM_SMCR_SMS_Pos), 0x31FFF7U);
|
|
TIM5->CNT = 0U; TIM5->SR = 0U;
|
|
TIM5->CR1 |= TIM_CR1_CEN;
|
|
|
|
// sync both SAIs
|
|
register_set(&SAI4->GCR, (0b10UL << SAI_GCR_SYNCOUT_Pos), SAI_GCR_SYNCIN_Msk | SAI_GCR_SYNCOUT_Msk);
|
|
register_set(&SAI1->GCR, (3U << SAI_GCR_SYNCIN_Pos), SAI_GCR_SYNCIN_Msk | SAI_GCR_SYNCOUT_Msk);
|
|
|
|
// stereo audio in
|
|
register_set(&SAI4_Block_B->CR1, SAI_xCR1_DMAEN | (0b00UL << SAI_xCR1_SYNCEN_Pos) | (0b100U << SAI_xCR1_DS_Pos) | (0b11U << SAI_xCR1_MODE_Pos), 0x0FFB3FEFU);
|
|
register_set(&SAI4_Block_B->CR2, (0b001U << SAI_xCR2_FTH_Pos), 0xFFFBU);
|
|
register_set(&SAI4_Block_B->FRCR, (31U << SAI_xFRCR_FRL_Pos), 0x7FFFFU);
|
|
register_set(&SAI4_Block_B->SLOTR, (0b11UL << SAI_xSLOTR_SLOTEN_Pos) | (1UL << SAI_xSLOTR_NBSLOT_Pos) | (0b01UL << SAI_xSLOTR_SLOTSZ_Pos), 0xFFFF0FDFU); // NBSLOT definition is vague
|
|
|
|
// init sound DMA (SAI4_B -> memory, double buffers)
|
|
register_set(&BDMA_Channel0->CPAR, (uint32_t) &(SAI4_Block_B->DR), 0xFFFFFFFFU);
|
|
register_set(&BDMA_Channel0->CM0AR, (uint32_t) sound_rx_buf[0], 0xFFFFFFFFU);
|
|
register_set(&BDMA_Channel0->CM1AR, (uint32_t) sound_rx_buf[1], 0xFFFFFFFFU);
|
|
BDMA_Channel0->CNDTR = SOUND_RX_BUF_SIZE;
|
|
register_set(&BDMA_Channel0->CCR, BDMA_CCR_DBM | (0b01UL << BDMA_CCR_MSIZE_Pos) | (0b01UL << BDMA_CCR_PSIZE_Pos) | BDMA_CCR_MINC | BDMA_CCR_CIRC | BDMA_CCR_TCIE, 0xFFFFU);
|
|
register_set(&DMAMUX2_Channel0->CCR, 16U, DMAMUX_CxCR_DMAREQ_ID_Msk); // SAI4_B_DMA
|
|
register_set_bits(&BDMA_Channel0->CCR, BDMA_CCR_EN);
|
|
|
|
// mic output
|
|
register_set(&SAI4_Block_A->CR1, SAI_xCR1_DMAEN | (0b01UL << SAI_xCR1_SYNCEN_Pos) | (0b100UL << SAI_xCR1_DS_Pos) | (0b10UL << SAI_xCR1_MODE_Pos), 0x0FFB3FEFU);
|
|
register_set(&SAI4_Block_A->CR2, 0U, 0xFFFBU);
|
|
register_set(&SAI4_Block_A->FRCR, (31U << SAI_xFRCR_FRL_Pos), 0x7FFFFU);
|
|
register_set(&SAI4_Block_A->SLOTR, (0b11UL << SAI_xSLOTR_SLOTEN_Pos) | (1UL << SAI_xSLOTR_NBSLOT_Pos) | (0b01U << SAI_xSLOTR_SLOTSZ_Pos), 0xFFFF0FDFU); // NBSLOT definition is vague
|
|
|
|
// init DFSDM for PDM mic
|
|
register_set(&DFSDM1_Channel0->CHCFGR1, (76UL << DFSDM_CHCFGR1_CKOUTDIV_Pos) | DFSDM_CHCFGR1_CHEN, 0xC0FFF1EFU); // CH0 controls the clock
|
|
register_set(&DFSDM1_Channel3->CHCFGR1, (0b01UL << DFSDM_CHCFGR1_SPICKSEL_Pos) | (0b00U << DFSDM_CHCFGR1_SITP_Pos) | DFSDM_CHCFGR1_CHEN, 0x0000F1EFU); // SITP determines sample edge
|
|
register_set(&DFSDM1_Channel3->CHCFGR2, (2U << DFSDM_CHCFGR2_DTRBS_Pos), 0xFFFFFFF7U);
|
|
register_set(&DFSDM1_Filter0->FLTFCR, (0U << DFSDM_FLTFCR_IOSR_Pos) | (64UL << DFSDM_FLTFCR_FOSR_Pos) | (4UL << DFSDM_FLTFCR_FORD_Pos), 0xE3FF00FFU);
|
|
register_set(&DFSDM1_Filter0->FLTCR1, DFSDM_FLTCR1_FAST | (3UL << DFSDM_FLTCR1_RCH_Pos) | DFSDM_FLTCR1_RDMAEN | DFSDM_FLTCR1_RCONT | DFSDM_FLTCR1_DFEN, 0x672E7F3BU);
|
|
|
|
// DMA (DFSDM1 -> memory)
|
|
register_set(&DMA1_Stream0->PAR, (uint32_t) &DFSDM1_Filter0->FLTRDATAR, 0xFFFFFFFFU);
|
|
register_set(&DMA1_Stream0->M0AR, (uint32_t)mic_rx_buf[0], 0xFFFFFFFFU);
|
|
register_set(&DMA1_Stream0->M1AR, (uint32_t)mic_rx_buf[1], 0xFFFFFFFFU);
|
|
DMA1_Stream0->NDTR = MIC_RX_BUF_SIZE;
|
|
register_set(&DMA1_Stream0->CR, DMA_SxCR_DBM | (0b10UL << DMA_SxCR_MSIZE_Pos) | (0b10UL << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_TCIE, 0x01FFFFFFU);
|
|
register_set(&DMAMUX1_Channel0->CCR, 101U, DMAMUX_CxCR_DMAREQ_ID_Msk); // DFSDM1_DMA0
|
|
register_set_bits(&DMA1_Stream0->CR, DMA_SxCR_EN);
|
|
DMA1->LIFCR |= 0x7D; // clear flags
|
|
|
|
// DMA (memory -> SAI4)
|
|
register_set(&BDMA_Channel1->CPAR, (uint32_t) &(SAI4_Block_A->DR), 0xFFFFFFFFU);
|
|
register_set(&BDMA_Channel1->CCR, (0b01UL << BDMA_CCR_MSIZE_Pos) | (0b01UL << BDMA_CCR_PSIZE_Pos) | BDMA_CCR_MINC | (0b1U << BDMA_CCR_DIR_Pos), 0xFFFEU);
|
|
register_set(&DMAMUX2_Channel1->CCR, 15U, DMAMUX_CxCR_DMAREQ_ID_Msk); // SAI4_A_DMA
|
|
|
|
// enable all initted blocks
|
|
register_set_bits(&SAI4_Block_A->CR1, SAI_xCR1_SAIEN);
|
|
register_set_bits(&SAI4_Block_B->CR1, SAI_xCR1_SAIEN);
|
|
NVIC_EnableIRQ(BDMA_Channel0_IRQn);
|
|
NVIC_EnableIRQ(DMA1_Stream0_IRQn);
|
|
}
|
|
|