cancel
Showing results for 
Search instead for 
Did you mean: 

I2S weird bit shift problem

baator025
Associate II

Hi,

I'm getting a problem in my project, where I tried to create a loopback between I2S3 and I2S4 on STM32F411 Disco.
It seems that only the least significant bit of 16-bit packets is somehow shifted to the next packet. The rest of the transmission is intact.
For example - I send {0x0001 0x0000 0x0000 0x0000} and I get {0x0000 0x0000 0x0001 0x0000}, but if I send {0xFFFE 0x0000 0x0000 0x0000}, I will receive {0x0000 0x0000 0x0000 0xFFFE}.
Packets order reversal is expected, but during analysis pay attention what happens with the least significant bit. Another example: transmitting {0x8001 0x0000 0x0000 0x0000} will end up with receiving {0x0000 0x0000 0x0001 0x8000} (I'd expect {0x0000 0x0000 0x000 0x8001}).
What is also interesting, readouts from logic analyzer seem to be correct.

I am not using HAL, I am configuring registers manually. I2S4 is configured as master receiver and uses DMA. I2S3 is configured as slave transmitter and I tried "feeding" it both with polling and interrupts. I always fill transmitter's buffer before initializing receiver with the first packet.

Since I've written my own abstraction layer, attaching code here may be difficult. Therefore I am uploading the link to repo: https://github.com/baator025/I2S_loopback . The most recent branch is rtos_integration.

I'd really appreciate help, because I've run out of ideas long ago.

Thanks,
Bartosz

16 REPLIES 16

Observe the I2S signals using oscilloscope and/or LA. You may have inadvertently generated edges which act as clock during initialization. Mind the In I2S slave mode, WS level must be set by the external master
when enabling the I2S erratum.

JW

Thanks for the reply.

I already struggled with some edges during initialization - whole transmission was shifted by 3 bits. If I remember correctly I applied your suggestion about clock value from someone else's topic.

There are still indeed some extra edges in the beginning, but I suppose they are somehow discarded by STM - WS line does not go high during their period and after that, there are exactly 16 clock cycles during first '1'. I think that it would also cause shift of all of data - not only the least significant bits by a packet size. 

Either way, I attached some LA captures below. To make it readable, I cropped two last packets - there were zeroes only, so nothing unexpected happened.

Data sent: 0x8001 0x0000 0x0000 0x000 0x8001 0x0000 0x0000 0x00000x8001 0x0000 0x0000 0x0000

Data sent: 0x0001 0x0000 0x0000 0x000 0x0001 0x0000 0x0000 0x00000x0001 0x0000 0x0000 0x0000

Data sent: 0xFFFE 0x0000 0x0000 0x000 

0xFFFE 0x0000 0x0000 0x00000xFFFE 0x0000 0x0000 0x0000

 

Regarding WS - What did you mean about setting WS by master? Could I forget something about I2S master if WS seems to behave properly on captures above?

 

Thanks,
Bartosz

I am referring to the errata.

Make sure you are enabling the slave according to the rule outlined there.

JW

 

The short BCLK and also the unusually short WS pulses at the beginning are concerning, too.

JW

What I see:
OK, it is not an I2S signal, potentially a Left or Right Adjusted signal (OK, as long as both sides use the same protocol), with 16bit per channel.

Yes, the first short WS (LRCK) pulse can confuse the transmitter:
based on your description: master receiver and slave transmitter. It means: the receiver generates the BCK and LRCK signal, the transmitter will receive it (in order to send data out).
But if you load transmitter first but you start receiver afterwards - there can be a phase where the receiver master starts to generate the output signals (BCK and LRCK). These can be unreliable on the very first start - what we see in the waveform.

BCK and SCLK are continuous clocks afterwards.

I would ignore the very first cycle, instead check it at the 2nd or any following cycles (to make sure the signals are "stable").

"Packet reversal": if words are sent as 16bit (and they are little endian), the bytes are "flipped" in the memory, but on the I2S bus it should be MSB...LSB (MSB first out and in).
If Tx and Rx use the same protocol - you should receive what you send, didn't you?

I would send: 0x0000 0x0000 0xFFFE 0x5551 and check for the 2nd word pairs (ignore the first two words, they can be wrong on the Rx side, e.g. due to this too short LRCK signal on first cycle).

Never stop the Master Receiver: otherwise you will get all the time this "hick-up", when the signals start again.
I2S is an always going on synchronous signal, the BCK and LRCK are always toggling. If you do not have anything to send, the data words sent should be 0.

You "cannot" use I2S in "Start&Stop" mode (first cycle is potentially always "wrong").

Thanks for involving in this topic. If I understood you correctly, you suggested discarding first packets. Unfortunately, it seems that the following packets are shifted in the same manner.
I also enlarged the length of transmission to 16 words to see if the transmission stabilizes later on. It did not help as well - data also got shifted in following packets.

I got to errata, it makes sense to work with this rule. If I understand correctly, since I am using MSB justified transmission, I should make sure the WS line should be low. 
One thing that I'm not sure how to do - WS pins both in master and slave are switched to alternate mode in MODER register, so I'm not able to use it as output. How can I make it go to low state? 

"hmmm" - I want to make you happy at the last day of the year - LOL

Yes, discard the first word pairs. Let the I2S (both sides) run "forever".

Please, can "we" do this:

  • you configure master and slave (with same protocol, in a regular way)
  • also all signals via ALT, on both
  • on the master receiver side: it should provide BCK and SCLK (WS) as output,
    on the transmitter slave side - it should have BCK and SCLK (WS) as inputs
  • can you let run the master receiver side - generating the I2S signals (actually a bit strange config: see below)
    and check with scope or logic analyzer that you see a correct endless transmission of I2S bus cycles?
    (BCLK is continuous, SCLK toggles every 16 clocks and is continuous)
  • now connect BCK out and SCLK out from master receiver with transmitter slave (where these signals should be inputs)
  • If you leave the DATA signal open on master receiver - it might read all as 0 or 1:
    if you ground now on master receiver the DATA pin to GND or pull-up to VDD - you should see a steady 0 or 1
  • At the end you connect DATA out (on slave transmitter) to DATA in (on master receiver)

Personally, I would change the "logic" a bit:

  • configure a Master Transmitter - all signals out (also BCK, SCLK)
  • and configure a Slave Receiver - all signals in (also BCK, SCLK)

Let the Master Transmitter run endlessly (after first enable and start - let it run forever), also the Slave Receiver.

Now check the I2S signals, if they make sense (BCK, LRCK, every 16 BCK clocks the LRCK changes polarity).

Try to send another set of words (2x 16bit, for each channel): do they come out as expected?

Connect Tx master DATA with Rx slave DATA: now you should get what you have sent (plus BCK and SCLK from Master to Slave).

But: make sure to load the I2S FIFO (data register) just when the previous transmission has completed (check the status of the transmitter, do not overwrite the words to send when it is still in progress).
Maybe a "flow control" on transmitter is missing (to make sure just to load a new pair of words when the previous
shift out has completed).

It might be easier to have a Master Transmitter (with all out) and a Slave Receiver (with all in) - even it should work as well as a Master Receiver (which provides not BCK and SCLK for the Slave Transmitter, just a bit "strange").

sorry: "Master Receiver would provide BCK and SCLK" and Slave Transmitter uses these as inputs. A bit strange: Change to Master Transmitter and Slave Receiver (it makes it a bit easier to debug and understand).