2025-06-12 2:25 AM
Platform: STM32 Nucleo-H7A3ZI-Q
Goal: Read audio from four microphones in stereo mode (two mics per I²S interface) via DMA, then enqueue complete stereo frames for processing.
I2S1 handles Mic 1 (left) and Mic 2 (right).
I2S2 handles Mic 3 (left) and Mic 4 (right).
Each I2S interface uses DMA to fill its receive buffer (data_i2s[] and data_i2s_2[]).
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s){
if(hi2s==&hi2s1){
if(x1Flag == 0){
valX1 = 0;
valX1 = sample_left = ((int32_t)data_i2s[0]) >> 8;
x1Flag = 1;
}else if(x2Flag == 0){
valX2 = 0;
valX2 = sample_right = ((int32_t)data_i2s[1]) >> 8;
x2Flag = 1;
/*if(x1Flag != 0 && x2Flag != 0){
enqueueData();
}*/
}
}else if (hi2s == &hi2s2){
if(y1Flag == 0){
valY1 = 0;
valY1 = sample_left_2 = ((int32_t)data_i2s_2[0]) >> 8;
y1Flag = 1;
}else if (y2Flag == 0){
valY2 = 0;
valY2 = sample_right_2 = ((int32_t)data_i2s_2[1]) >> 8;
y2Flag = 1;
/*if(y1Flag != 0 && y2Flag != 0){
enqueueData();
}*/
}
}
if(x1Flag != 0 && x2Flag != 0 && y1Flag != 0 && y2Flag != 0){
enqueueData();
}
}
Often the callback only ever enters the hi2s1 branch and never the hi2s2 branch.
Other times, I see data from three mics but never from the fourth, so enqueueData() either never runs or runs with incomplete data.
DMA handles are correctly linked to hi2s1 and hi2s2.
Interrupt priorities: I’ve ensured DMA and I2S IRQs don’t mask each other.
Buffer sizes: The receive arrays are distinct and large enough.
Flag reset: Flags are cleared immediately after calling enqueueData().
How can I guarantee that both I²S interfaces complete their DMA transfer before enqueueData() fires?
Why might the hi2s2 branch be skipped or only partially served?
Is there a cleaner or more reliable pattern in FreeRTOS for gathering four DMA callbacks and pushing full stereo frames into a queue?
Thanks in advance for any suggestions!
2025-06-16 3:50 AM
Hello @chikenJoe1
Check the DMA transfer complete callback function for the two I2S before calling enqueueData().
2025-06-16 7:09 AM
Hello,
thanks for your Reply!
What do mean by Checking, I call the DMA in main, for both I2S.
I now try to solve this via SAI in I2S Mode so all the Mics Share the same clock, with SAI A and B.
What is the better Option, i need the Data from the 4 Microphones at the same time to do Processing, i've red that with 2 master I2S to sync the timings is harder then to solve it via SAI with A and B in master Slave mode
Thanks in Advance
2025-06-16 7:31 AM
Hello @chikenJoe1
You make flag in the HAL_I2S_RxCpltCallback() and then check the flag in the main.
#include "stm32f4xx_hal.h"
// DMA buffer for I2S data
uint16_t i2s_rx_buffer[128]; // Example buffer size
// Flag to indicate data reception is complete
volatile uint8_t i2s_rx_complete_flag = 0;
int main(void)
{
// HAL initialization
HAL_Init();
// System clock configuration
SystemClock_Config();
// I2S handle and initialization
I2S_HandleTypeDef hi2s;
// (Assume hi2s is properly initialized here)
// Start I2S receive in DMA mode
HAL_I2S_Receive_DMA(&hi2s, i2s_rx_buffer, sizeof(i2s_rx_buffer) / sizeof(uint16_t));
while (1)
{
// Check if the flag is set
if (i2s_rx_complete_flag)
{
// Clear the flag
i2s_rx_complete_flag = 0;
// Process the received data
ProcessI2SData(i2s_rx_buffer, sizeof(i2s_rx_buffer) / sizeof(uint16_t));
// Restart I2S receive
HAL_I2S_Receive_DMA(&hi2s, i2s_rx_buffer, sizeof(i2s_rx_buffer) / sizeof(uint16_t));
}
// Other main loop tasks
}
}