cancel
Showing results for 
Search instead for 
Did you mean: 

Filling a Queue with Data from 4 Microphones from 2 different I2S Interfaces

chikenJoe1
Associate

 


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.


1. Hardware & DMA Setup

  • 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[]).

2. Current Callback Code

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

3. Observed Behavior

  • 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.

4. What I’ve Already Checked

  1. DMA handles are correctly linked to hi2s1 and hi2s2.

  2. Interrupt priorities: I’ve ensured DMA and I2S IRQs don’t mask each other.

  3. Buffer sizes: The receive arrays are distinct and large enough.

  4. Flag reset: Flags are cleared immediately after calling enqueueData().

5. My Questions

  1. How can I guarantee that both I²S interfaces complete their DMA transfer before enqueueData() fires?

  2. Why might the hi2s2 branch be skipped or only partially served?

  3. 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!

3 REPLIES 3
Saket_Om
ST Employee

Hello @chikenJoe1 

Check the DMA transfer complete callback function for the two I2S before calling enqueueData().

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om

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 

 

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
    }
}

 

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om