cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F7 I2S DMA data shift (flushing issue)

cbardou
Associate II
Posted on November 22, 2017 at 18:09

Hi,

I'm trying to use the STM32F723 I2S3 peripheral in reception (with a circular DMA).

But I'm having an issue : when I2S is started for the first time everything works fine. But if I stop/restart it, the received samples are shifted of 16bits.

It looks like when I disable the I2S, its 16bits RX buffer is not completely flushed and shift my samples next time I restart it.

Unfortunately I was not able to find a solution to flush that RX buffer, I tried to flush it manually by reading SPI3_RXCRCR buffer while SPI3_SR.FRLVL is not equal to zero. But it doesn't work.

I tried to deinit and reinit I2S but it doesn't fix the problem.

The only workaround I found is to hard reset the I2S3/SPI3 peripheral with a : __HAL_RCC_SPI3_FORCE_RESET();

The I2S3 is configured in slave to receive a 24bits stereo signals and store it in a 32bits array in memory.

The DMA is configured in circular mode and data alignement is HALF_WORD on peripheral side and WORD on memory side.

To start and stop I2S I use the HAL functions :

HAL_I2S_Transmit_DMA()

HAL_I2S_DMAStop()

Here are my I2S and DMA config :

    hi2s3.Instance = SPI3;

    hi2s3.Init.Mode = I2S_MODE_SLAVE_RX;

    hi2s3.Init.Standard = I2S_STANDARD_PHILIPS;

    hi2s3.Init.DataFormat = I2S_DATAFORMAT_24B;

    hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;

    hi2s3.Init.AudioFreq = 192000;

    hi2s3.Init.CPOL = I2S_CPOL_LOW;

    hi2s3.Init.ClockSource = I2S_CLOCK_PLL;

    hdma_spi3_rx.Instance = DMA1_Stream0;

    hdma_spi3_rx.Init.Channel = DMA_CHANNEL_0;

    hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;

    hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE;

    hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE;

    hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;

    hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

    hdma_spi3_rx.Init.Mode = DMA_CIRCULAR;

    hdma_spi3_rx.Init.Priority = DMA_PRIORITY_LOW;

    hdma_spi3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

Doyou have any idea where the problem could come from ?

Thank you.

#stm32f7 #i2s #dma #flush
5 REPLIES 5
Posted on November 22, 2017 at 18:52

That I2S is slave - do you stop the master (i.e. clock source) before that interruption? If not, you'll have one received halfword buffered in I2S before restart .

JW

cbardou
Associate II
Posted on November 23, 2017 at 14:50

I don't stop the master clock source before the I2S (because that clock is also used by other peripherals).

So I was wondering if there is the possibility to flush the buffer before restarting ?

I tried what you said, stopping master clock before I2S, indeed it seems to solve the issue (not completely though, the problem seems to come back from time to time).

Posted on November 23, 2017 at 14:57

You then need to stop I2S by clearing I2SE, if there are any outstanding data in Rx buffer read them out (I2SE may flush them but it's not documented so I wouldn't rely on that); then enable Rx DMA first, and then enable I2SE (pending ASTRTEN=0 it shall sync itself on the first incoming sample then).

[EDIT] re-reading the original post: why do you start Rx by calling a transmit function?

JW

cbardou
Associate II
Posted on November 23, 2017 at 17:41

Okay it finally works !!! I was not flushing the data register correctly.

After stopping the DMA I read the Data Register several time (to be sure I empty the FIFO) and everything work fine (no need to stop master clock).

I made a mistake in my 1st post, to start the RX I call 'HAL_I2S_Receive_DMA()'.

Thanks for your help

Posted on November 23, 2017 at 17:58

After stopping the DMA I read the Data Register several time (to be sure I empty the FIFO) and everything work fine (no need to stop master clock).

It's not enough to stop DMA, you'll need to stop I2S too. However, Cube apparently does both for you, if you use HAL_I2S_DMAStop().

After stopping the DMA I read the Data Register several time (to be sure I empty the FIFO)

FIFO should not apply to I2S (FIFO-related bits are marked as 'These bits are not used in I²S mode' in RM).

However, I can imagine that the timing between the I2S disable and last data 'appearing' in the data register, might be tricky...

JW