100 lines
4.4 KiB
C
Raw Normal View History

#define SOUND_RX_BUF_SIZE 2000U
#define SOUND_TX_BUF_SIZE (SOUND_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];
static uint8_t sound_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);
}
}
}
// Playback processing
static void BDMA_Channel0_IRQ_Handler(void) {
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;
uint8_t tx_buf_idx = (((DMA1_Stream1->CR & DMA_SxCR_CT) >> DMA_SxCR_CT_Pos) == 1U) ? 0U : 1U;
// 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[tx_buf_idx][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 - tx_buf_idx][i] = (1UL << 11);
}
register_set(&DMA1_Stream1->CR, (1UL - tx_buf_idx) << DMA_SxCR_CT_Pos, DMA_SxCR_CT_Msk);
register_set_bits(&DMA1_Stream1->CR, DMA_SxCR_EN);
}
sound_idle_count = 4U;
}
sound_tick();
}
void sound_init(void) {
REGISTER_INTERRUPT(BDMA_Channel0_IRQn, BDMA_Channel0_IRQ_Handler, 64U, 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;
// 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);
// enable all initted blocks
register_set_bits(&SAI4_Block_B->CR1, SAI_xCR1_SAIEN);
NVIC_EnableIRQ(BDMA_Channel0_IRQn);
}