openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
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.

185 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);
}