cancel
Showing results for 
Search instead for 
Did you mean: 

I2S Master has Full Duplex DMA L/R Swapped after Restart

john gassel
Associate III
Posted on January 02, 2018 at 22:53

I have an application using an STM32F429ZI processor and I'm seeing a strange problem where the L/R audio output gets swapped after changing I2S frequencies.

My procedure to change frequencies is as follows:

HAL_I2S_DMAStop(&hi2s3);

HAL_I2S_DeInit(&hi2s3);

hi2s3.Init.AudioFreq = sampling_rate;

HAL_StatusTypeDef result = HAL_I2S_Init( &hi2s3);

I2SEx_TransmitReceive_DMA_DB();

//my own function above is called, which is similar to the following but instead has call to 

//HAL_DMAEx_MultiBufferStart_IT(&hi2s3, &DummyAudioOutBuf, &DummyAudioOutBuf, AUDIO_OUT_BUF_SIZE);

It doesn't always happen.  I'd say that it gets swapped about 10% of the time.  I've seen people who have similar problems when running a slave, but with the ST configured as the master, I'm surprised to see this.

Here is my I2S3 configuration:

hi2s3.Instance = SPI3;

hi2s3.Init.Mode = I2S_MODE_MASTER_TX;

hi2s3.Init.Standard = I2S_STANDARD_PHILIPS;

hi2s3.Init.DataFormat = I2S_DATAFORMAT_16B;

hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;

hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_16K;

hi2s3.Init.CPOL = I2S_CPOL_LOW;

hi2s3.Init.ClockSource = I2S_CLOCK_PLL;

hi2s3.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;

#swap #stm32f4 #i2s #dma
20 REPLIES 20
Posted on January 09, 2018 at 19:40

It's still humm here. Truth is, I never tried to stop and start I2S - I just initialize it then keep it running all the time.

Can you please try to reset the I2S, by toggling its respective RCC_APBxRSTR.SPIyRST bit, before you reenable it?

JW

Posted on January 09, 2018 at 20:23

Initial results look good after adding this reset in.  Thanks!  I'll keep testing further.

This seems consistent with another test I was running.  I can see the problem if I simply do this:

__HAL_I2S_DISABLE(hi2s);

vTaskDelay(pdMS_TO_TICKS(1));

__HAL_I2S_ENABLE(hi2s);
Posted on January 10, 2018 at 16:11

Further testing confirms that this actually does resolve the issue.  Does anyone have a clue why that might be?  I'd love to know the root cause and not just the workaround.

alemv
Associate II

I don’t know the reasons, but I can confirm that trying to synchronize with channel "0" before calling dma like

while (SPI2->SR & SPI_SR_CHSIDE);

while (!SPI2->SR & SPI_SR_CHSIDE);

does not work, and I have to reset and re-init the I2S interface.

Can you please give us more context of your particular setup/software?

JW

JVini
Associate

Hi Guys!

Sorry for this late answer, but I had this problem last week. I guess that the point here is the follow: in any STM32F4 manual with I2S we can see a description about the transmission that says “The transmission sequence begins when a half-word is written into the Tx buffer.�? So, when you suddenly stop a transmission, the last data that was put in the buffer is pending when the I2S is reinitialized. In this case, this pending data assumes the first position in a new transmission that corresponds to first channel (WS low in my case) and as a consequence our data is swapped.

I could confirm this writing a dummy in the DR register in every transmission. I saw that this byte assumed the first position and the swapped stopped (but this is not a solution). I was unable to find a way to empty this pending data with some register and I am using the same approach for while (HAL_I2S_DMAStop(&hi2n), __HAL_RCC_SPIn_FORCE_RESET(), __HAL_RCC_SPIn_RELEASE_RESET().

Was this problem ever resolved.

I've got the same problem and would like to know how to fix it

Implement the stopping of transmission in such a way that it always waits and stops only when both channels of the current frame are transmitted.

Thanks.

We ended up leaving the transfer running, but filling the final buffer with 0x00 so that its sending silence when there is no real audio.

Also changed the ISR's to return immediatly if no real data needs to be transferred.

FYI

Starting the I2S slave in sync with the master was also problematic.

But we finally read an Errata which indicated that you must wait for WS to be high before the Slave is started.

We wait for WS to toggle from low to high before calling the HAL API function, and this seems to reliably start the slave in sync with the master

i.e we use GPIO ReadPin ( WS ) even though in theory the WS pin is assigned to its alternate function as part of the I2S interface.

But its common knowledge that both GPIO Write and Read seem to be possible even when pins are assigned to alternate uses, even USB.

Just a note for everyone - if SAI is available, it is highly recommended to use that instead of I2S. It has more features, less (almost none) problems, is more flexible and simultaneously is also easier to use.