Skip to main content
Associate
January 18, 2026
Solved

How to synchronize two I2S

  • January 18, 2026
  • 2 replies
  • 407 views

Hi, 

I want to get synchronized samples from 4 microphones connected via I2S2 and I2S3. First I set one as master and other as slave and just connect Clock and Word Select, but I have only 0 values on slave interface. Is it possible to do it this way? Or there is another better one? 

I am using STM32H533

Best answer by AScha.3

>I had similar problem and after long time searching i found: it was on the wrong pin tx <--> rx swapped.

The rx was on the tx pin...thats what i tried to explain. (Dont ask me why...)

Look in rm of your chip, registers of the I2S : is there a swap bit ? (swap rx - tx ) .

from H743 :

AScha3_0-1768744549199.png

 

2 replies

wiewiórAuthor
Associate
January 18, 2026

I connected oscilloscope to both master and slave interfaces and both seems to be working fine (there is data that changes when I make noise). Unfortunately the problem is in GPDMA configuration and I cannot find it. 

AScha.3
Super User
January 18, 2026

Hi,

Is it possible to do it this way?

Yes, perfect. I do same to sync 3 I2S streams , just for output to dacs, but for input is same connection, clk+ws from master -> slave(s) .

+ for DMA:

You have to setup two dma channels, circular mode , check data size is correct for I2S and memory.

Enable callbacks in Cube -> project manager -> advanced : callbacks for SAI / I2S (whatever you use).

In half/full callbacks then ...use/copy the data.

"If you feel a post has answered your question, please click ""Accept as Solution""."
wiewiórAuthor
Associate
January 18, 2026

Thank you for your reply.

I have two dma channels configured as below:

/* I2S2 DMA Init */
 /* GPDMA1_REQUEST_SPI2_RX Init */
 NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
 NodeConfig.Init.Request = GPDMA1_REQUEST_SPI2_RX;
 NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
 NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
 NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
 NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
 NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
 NodeConfig.Init.SrcBurstLength = 1;
 NodeConfig.Init.DestBurstLength = 1;
 NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT1;
 NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 NodeConfig.Init.Mode = DMA_NORMAL;
 NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
 NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
 NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
 if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0, NULL, &Node_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
 handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
 handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
 handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
 handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
 if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(i2sHandle, hdmarx, handle_GPDMA1_Channel0);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }


/* I2S3 DMA Init */
 /* GPDMA1_REQUEST_SPI3_RX Init */
 NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
 NodeConfig.Init.Request = GPDMA1_REQUEST_SPI3_RX;
 NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
 NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
 NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
 NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
 NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
 NodeConfig.Init.SrcBurstLength = 1;
 NodeConfig.Init.DestBurstLength = 1;
 NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT1;
 NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 NodeConfig.Init.Mode = DMA_NORMAL;
 NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
 NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
 NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
 if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel1, NULL, &Node_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
 handle_GPDMA1_Channel1.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
 handle_GPDMA1_Channel1.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
 handle_GPDMA1_Channel1.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
 handle_GPDMA1_Channel1.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel1.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
 if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel1, &List_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(i2sHandle, hdmarx, handle_GPDMA1_Channel1);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel1, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }

I enabled I2S callback as you said, but it didn't help :(

Maybe there is something wrong with this DMA configuration? When I swap master/receive in cubemx always it is the slave which does not work (it produces callbacks, but reads only 0s).


EDIT: I use 4 x IC43434 microphones

EDIT2: Here are two screenshots from oscilloscope:
1. Shows clock signal on master vs on slave (probes were connected on two ends of cable that connets I2S2 and I2S3 clocks)

ch1 (yellow) - slave clock
ch4 (blue) - master clock

i2s-clock.png

2.  Shows data from microphones 
ch1 (yellow) clock
ch2 (turqoise) ws
ch3 (pink) i2s3 (slave) data
ch4 (blue) i2s2 (master) data

i2s-data.png

If I can provide you with more information, let me know.

AScha.3
Super User
January 18, 2026

>the slave which does not work (it produces callbacks, but reads only 0s).

Are you sure to read the pin with the data ?

I had similar problem and after long time searching i found: it was on the wrong pin tx <--> rx swapped.

+

Try the SAI , set to I2S mode; the SAI worked in all my tests perfect (the I2S not...but didnt test on H533).

"If you feel a post has answered your question, please click ""Accept as Solution""."