cancel
Showing results for 
Search instead for 
Did you mean: 

How to synchronize two I2S

wiewiór
Associate II

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

1 ACCEPTED SOLUTION

Accepted Solutions

>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 I2C : is there a swap bit ? (swap rx - tx ) .

from H743 :

AScha3_0-1768744549199.png

 

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

View solution in original post

8 REPLIES 8
wiewiór
Associate II

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

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

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.

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

>Are you sure to read the pin with the data ?
Yes, I double checked: 

/**I2S2 GPIO Configuration
    PC2     ------> I2S2_SDI
    PB1     ------> I2S2_WS
    PB2     ------> I2S2_CK
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/**I2S3 GPIO Configuration
    PA4     ------> I2S3_WS
    PB0     ------> I2S3_SDI
    PC10     ------> I2S3_CK
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

 

wiewir_0-1768743921971.png

Also, after swapping master / slave roles in CubeMX, there is data on new master (previous slave), but there is no data on new slave (previous master). So I checked that I2S2 and I2S3 works while in master mode but none of them works as slave.  

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

I am new to SAI, but unfortunately, I cannot find any proof that there is any on H533RE.

>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 I2C : is there a swap bit ? (swap rx - tx ) .

from H743 :

AScha3_0-1768744549199.png

 

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

It worked, thank you very much! 

I wonder why did Cube configure it differently? 

For future generations, here you have functions that helped mi resolve the issue:

HAL_I2S_DisableIOSwap(master->i2s_handler);
HAL_I2S_EnableIOSwap(slave->i2s_handler);

wiewir_0-1768755802373.png

 

>I wonder why did Cube configure it differently?

that was my > (Dont ask me why...)

Maybe someone of the ingenious HAL designers was thinking: if its a slave now, so tx/rx has to be swapped.

Might be useful, to avoid swapping the wires if changing from master to slave ---

BUT: it should be a setting in Cube, that can be set or not set - not a hidden setting !

Dont ask me, how many hours i needed to find this sh.. quirk.

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