Categories
Manufacturers
Home  /  Community  /  ST STM32 MCU products  /  What is a good buffering method for real time DSP (I2S, DMA) ?

What is a good buffering method for real time DSP (I2S, DMA) ?



Mnemocron 2019-12-02

I have a custom board with an STM32F412RE and a TLV320aic Codec, where the Codec is in Master mode and the I2S2 Interface of the STM32 in Full Duplex Slave mode. So far I have the I2S2 interface configured to send and receive the data over DMA. On DMA transfer complete Interrupt I copy the input buffer (uint16_t) to the output buffer. This way I have a passthrough of the audio signal. Now I also implemented the float32_t FIR example from CMSIS/DSP. I have verified, that the FIR filter works (amplitude shows low-pass characteristic). However I am seeing (and hearing) that the audio signal has gaps. What is a good buffering method for real time DSP (I2S, DMA) ? (blue:Input, 1Vpp, 1kHz. green/pink:Line Out L/R) I suspect that this happens because I execute the FIR filter inside the DMA ISR - which is not the way to do it. The next step is to implement a buffering method to run the FIR-Filter not FFT (as in the comments) n the main loop. How can this be achieved? What is good practice? Is there an app-note or a white paper explaining how to implement a buffer for this application? My 1st approach:(main and interrupt) // main.c /* USER CODE BEGIN PV */ // four alternating buffers uint16_t pTxRxData_A[DSP_BUFFERSIZE]; uint16_t pTxRxData_B[DSP_BUFFERSIZE]; uint16_t pTxRxData_C[DSP_BUFFERSIZE]; uint16_t pTxRxData_D[DSP_BUFFERSIZE]; // a Merry go Around for the three buffers, containing the pointer to the first element volatile uint16_t* buffer_merry_go_around[4] = {pTxRxData_A, pTxRxData_B, pTxRxData_C, pTxRxData_D}; volatile uint8_t pDataIndex_Rx = 3; volatile uint8_t pDataIndex_DSP_in = 2; // increment to get Rx buffer volatile uint8_t pDataIndex_DSP_out = 1; // volatile uint8_t pDataIndex_Tx = 0; // increment to get DSP buffer volatile uint8_t newDataReadyFlag = 0; // ISR Flag to main /* USER CODE BEGIN 3 */ /* Use MAIN Loop to process buffered Data */ if(newDataReadyFlag){ newDataReadyFlag = 0; DSP_Process_Data((uint16_t*)buffer_merry_go_around[pDataIndex_DSP_in], (uint16_t*)buffer_merry_go_around[pDataIndex_DSP_out], DSP_BLOCK_SIZE); } // stm32f4xx_it.c /** * @brief This function handles DMA1 stream4 global interrupt. */ void DMA1_Stream4_IRQHandler(void) { /* USER CODE BEGIN DMA1_Stream4_IRQn 0 */ dmaTransferComplete ++; /* USER CODE END DMA1_Stream4_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_spi2_tx); /* USER CODE BEGIN DMA1_Stream4_IRQn 1 */ HAL_I2S_DMAStop(&hi2s2); pDataIndex_Rx = (pDataIndex_Rx+1) % 4; pDataIndex_Tx = (pDataIndex_Tx+1) % 4; pDataIndex_DSP_in = (pDataIndex_DSP_in+1) % 4; pDataIndex_DSP_out = (pDataIndex_DSP_out+1) % 4; HAL_I2S_DMAStop(&hi2s2); HAL_I2SEx_TransmitReceive_DMA(&hi2s2, (uint16_t*)buffer_merry_go_around[pDataIndex_Tx], (uint16_t*)buffer_merry_go_around[pDataIndex_Rx], DSP_BUFFERSIZE); newDataReadyFlag ++; } This turns out to be even worse. The passthrough functionality now too has gaps and the FIR amplitude stays the same. This is why I suspect, that the buffers are getting confused somewhere. (e.g. DMA output buffer is not FIR output) My second approach is similar, with two alternating buffer arrays[2]. Both approaches can be found here: https://github.com/mnemocron/P5-DSP-Board-mdk/tree/rotating-buffers/Src https://github.com/mnemocron/P5-DSP-Board-mdk/tree/switching-buffers/Src

------------------------------
The input and output speed are the same. The TLV320 is in Master mode and outputs a 12.288MHz clock to the STM32. Rx/Tx happens at the same time. The goal is to implement an FIR Filter (as opposed to an FFT in the replies to my question) so I need to modify the data. I was now able to implement the DMA Buffer with an interrupt on half-full. Another issues was in how I implemented the FIR filter with the wrong parameters. The DSP routine (including the FIR) is still called in the ISR as the processing time is much less than the buffer length times sampling period. DMA runns on the pRxData[2 * DSP_BUFFERSIZE] and pTxData[2 * DSP_BUFFERSIZE] void DMA1_Stream3_IRQHandler(void) { /* USER CODE BEGIN DMA1_Stream3_IRQn 0 */ /* DMA STREAM 3 is I2S2 RX complete */ dmaTransferComplete ++; /* USER CODE END DMA1_Stream3_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_i2s2_ext_rx); /* USER CODE BEGIN DMA1_Stream3_IRQn 1 */ // arm_fir_f32() is called in this function DSP_Process_Data( (pRxData + buffer_offset), (pTxData + buffer_offset), DSP_BUFFERSIZE); if(!buffer_offset) buffer_offset = DSP_BUFFERSIZE; else buffer_offset = 0; /* USER CODE END DMA1_Stream3_IRQn 1 */ } What is a good buffering method for real time DSP (I2S, DMA) ?

STM32F412RE



Request for Quotation
Part Number *
Manufacturer
Contact Person *
Email Address *
Inquiry Quantity *
Delivery Country *