Restarting an I2S transfer changes alignement in DMA RX buffer

Report here problems in any of ChibiOS components. This forum is NOT for support.
User avatar
Giovanni
Site Admin
Posts: 12774
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 697 times
Been thanked: 576 times
Contact:

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby Giovanni » Fri Jul 27, 2018 3:01 pm

Interesting, that is on the F7 which has a FIFO but flushing the data register after stopping the master clock and DMAs could be a solution. Another option would be to reset the SPI peripheral on i2sStart().

Giovanni

tsichevski
Posts: 35
Joined: Fri Feb 09, 2018 12:44 am
Has thanked: 2 times
Been thanked: 5 times

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby tsichevski » Fri Oct 26, 2018 3:08 pm

I've managed to recover from this problem. Before starting DMA, I explicitly fetch a few half-words from the I2S data register, and find where the sample start sequence begins. Unfortunately, this solution is not universal: is works for my particular codec chip :(

Regards,
Vladimir

User avatar
Giovanni
Site Admin
Posts: 12774
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 697 times
Been thanked: 576 times
Contact:

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby Giovanni » Sun Nov 10, 2019 10:25 am

bump

jpp
Posts: 2
Joined: Fri Nov 29, 2019 10:36 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby jpp » Fri Nov 29, 2019 10:57 pm

Hello,

This is my first post in this forum :)

I think I just ran into this same problem though I did not fully characterized the issue on an STM32F429 (discovery board) and in RX mode.

I found those two links that seem related:
https://community.st.com/s/question/0D5 ... hing-issue
https://community.st.com/s/question/0D5 ... er-restart

So it seems that the issue comes from the fact that when I2S is turned off some data may still arrive into the DR register and those data will get as first data for next reception and shift all the data by 1 channel.

Also I found that ST dedicated a paragraph on "Disabling the SPI" because it is probably a bit tricky and I suppose it applies to the I2S even more.

The interresting sequence they describe is as follow:
- wait for RXNE=1 (this will be the second to last data receive)
- disable the SPI : SPE=0
- wait for RXNE=1 (this is the last)

And this is how I changed the stop_exchange routine:

Code: Select all

void i2s_lld_stop_exchange(I2SDriver *i2sp) {

  /* Stop TX DMA, if enabled.*/
  if (NULL != i2sp->dmatx) {
    dmaStreamDisable(i2sp->dmatx);

    /* From the RM: To switch off the I2S, by clearing I2SE, it is mandatory
       to wait for TXE = 1 and BSY = 0.*/
    while ((i2sp->spi->SR & (SPI_SR_TXE | SPI_SR_BSY)) != SPI_SR_TXE)
      ;
  }

  /* Stop RX DMA, if enabled.*/
  if (NULL != i2sp->dmarx) {
    dmaStreamDisable(i2sp->dmarx);
    while ((i2sp->spi->SR & SPI_SR_RXNE) != SPI_SR_RXNE);
  }

  /* Stop SPI/I2S peripheral.*/
  i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE;

  /* Drain the last DATA to clean for next exchange */
  if (NULL != i2sp->dmarx) {
    while (i2sp->spi->SR & SPI_SR_RXNE)
      i2sp->spi->DR;
  }
}


What I believe it could happen before is that:
- Disable SPI : SPE=0
- Disable DMA before that last data arrive
- The last data may arrive but nobody to discard it and let the pipeline clean for next exchange

What I believe it fixes the issue:
- Disable DMA
- Wait for last data (so that we are sure it is here and perhaps preventing other to arrive as there is no buffer)
- Disable SPI : SPE=0
- Drain the last data

This seems to work for me.
Again I don't fully understand what's happening only suppositions.

User avatar
Giovanni
Site Admin
Posts: 12774
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 697 times
Been thanked: 576 times
Contact:

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby Giovanni » Sat Nov 30, 2019 5:59 am

Hi,

Thanks for experimenting with this, I need to look at that paragraph.

The fix makes sense, I wonder if it should go in the SPI driver too when stopping a continuous transfer.

Giovanni

User avatar
Giovanni
Site Admin
Posts: 12774
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 697 times
Been thanked: 576 times
Contact:

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby Giovanni » Sat Dec 07, 2019 9:54 am

Hi,

I committed the change in trunk, just removed an extra condition, could you check everything is OK?

Code: Select all

void i2s_lld_stop_exchange(I2SDriver *i2sp) {

  /* Stop TX DMA, if enabled.*/
  if (NULL != i2sp->dmatx) {
    dmaStreamDisable(i2sp->dmatx);

    /* From the RM: To switch off the I2S, by clearing I2SE, it is mandatory
       to wait for TXE = 1 and BSY = 0.*/
    while ((i2sp->spi->SR & (SPI_SR_TXE | SPI_SR_BSY)) != SPI_SR_TXE)
      ;

    /* Stop SPI/I2S peripheral.*/
    i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE;
  }

  /* Stop RX DMA, if enabled then draining the RX DR.*/
  if (NULL != i2sp->dmarx) {
    dmaStreamDisable(i2sp->dmarx);

    /* Waiting for some data to be present in RX DR.*/
    while ((i2sp->spi->SR & SPI_SR_RXNE) != SPI_SR_RXNE)
      ;

    /* Stop SPI/I2S peripheral.*/
    i2sp->spi->I2SCFGR &= ~SPI_I2SCFGR_I2SE;

    /* Purging data in DR.*/
    while ((i2sp->spi->SR & SPI_SR_RXNE) != 0)
      (void) i2sp->spi->DR;
  }
}


Giovanni

User avatar
Giovanni
Site Admin
Posts: 12774
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 697 times
Been thanked: 576 times
Contact:

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby Giovanni » Sat Jan 11, 2020 10:30 am

Any comment on this?

Giovanni

jpp
Posts: 2
Joined: Fri Nov 29, 2019 10:36 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby jpp » Mon Feb 24, 2020 11:04 pm

Hello Giovanni I am sorry I completely forgot about this and did not see the notifications...

I cannot try to run your code immediately but I have been running my version of the change since my first post and it is working when I can very easily reproduce the old issue.

BUT I am only using 1 I2S driver in RX and 1 I2S driver in TX

Carefully reading you code comparing to my patch makes me think that it is absolutely the same IF the I2S driver is exclusively either in RX or TX mode.

I believe that if the driver could operate in both TX and RX mode this would not work, but double checking the Ref Manual there is no RX+TX (full duplex) mode in I2S. Well ... there is but it is done via a I2S_ext peripherals which I think are kind of "virtual". I don't know what is your intention but I think the current version of the driver is only supporting Half-Duplex (only RX or TX) as you don't seem to play with the I2S_ext peripheral.
So if the driver is meant only to operate either the RX or the TX mode then your patch looks fine to me.

Again really sorry for the delay here...
JP:

User avatar
Giovanni
Site Admin
Posts: 12774
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 697 times
Been thanked: 576 times
Contact:

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby Giovanni » Thu Feb 27, 2020 6:17 pm

Hi,

Don't worry. Let me know if you have a chance to test it.

The driver does not support full duplex mode so it should be fine.

Giovanni

User avatar
Giovanni
Site Admin
Posts: 12774
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 697 times
Been thanked: 576 times
Contact:

Re: Restarting an I2S transfer changes alignement in DMA RX buffer

Postby Giovanni » Sat May 23, 2020 9:09 am

Any news on this?

Giovanni


Return to “Bug Reports”

Who is online

Users browsing this forum: No registered users and 10 guests