2024-12-29 01:36 PM
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
Solved! Go to Solution.
2024-12-31 03:07 PM
Oh BTW: "since I am using MSB justified transmission, I should make sure the WS line should be low".
NO!!!
LRCK (WS) signal is there to indicate if left or right channel data. It does not have any relation to the protocol.
As I understand: I2S, Left or Right Justified... are always as "shift MSB first". Just: where the MSB (and LSB) is - in RELATION to SCLK (WS) signal depends on which protocol is used.
LRCK (WS) should always toggle (after word size (16bit) BCK) - if you use two channels (stereo). In Mono mode - than it should stay constant at one level.
Based on the waveforms you have attached: the very first cycle is "invalid", BCLK (WS) toggling for less than 16bit BCK. So, the startup (enable) has a "hick up", just reliable signals afterwards (after some cycles stable, keep running both in endless mode).
SCLK (WS) should toggle automatically in stereo mode (left and right channel indication, also indicating the word size, e.g. 16 BCK clocks for one channel). You cannot control and influence the SCLK (WS) behavior (just via Stereo or Mono config).
2024-12-31 03:09 PM
Sorry" "LRCK", a signal to indicate left of right channel (and channel word size) - anyway: generated automatically (nothing to control, except to configure the protocol and channel word size properly).
2024-12-31 03:40 PM
BTW: if you would use the LRCK (WS) signal as DATA input on the Receiver (connect LRCK out - here on your Master Receiver generating it, to the DATA in on your Master Receiver) - now you should see 0xFFFF and 0x0000 for the right channel (when LRCK is high) and left channel (when LRCK is low).
If this works (both channels have different values: 0xFFFF vs. 0x0000) - all should be ok.
If the channel values are a bit different (e.g. LSB is 0 vs. 1) - the I2S protocol is configured: I2S has the LSB on DATA when LRCK has changed already (for one BCK cycle). Otherwise (if all 0xFFFF and 0x0000) - the Left or Right Aligned protocol is used. These protocols just differs where the MSB and LSB is (in relation to LRCK).
I suggest:
now you can focus on I2S Slave Receiver:
it should receive exactly what you have sent.
If so: BCK and LRCK generated by the Master Transmitter goes to Slave Receiver as inputs, DATA from Transmitter (out) goes to Slave Receiver (in).
Just watch for:
If you do not check for "transmission completed" and you would overwrite the Transmitter Data Register (when transmission is still inn process) - you can get also "strange" results.
2025-01-01 12:04 PM
First of all - sorry, I didn't have much time for changes in code as you suggested, probably will try to do this tomorrow.
Regarding other topics.
1. I get that WS/LRCK indicates which channel is currently streaming, I just understood the workaround from errata orders me to make sure WS is low when I start I2S peripherals. Finally did this by using pull down, which I forgot about. Nevertheless, it didn't change much.
2. Until now I tried two flow controls:
- I had a "feeder" task, when I checked TXE flag in I2S status register. If it indicated emptiness, I wrote data to DR.
- I used interrupts, triggered on TXE as well
I thought that maybe I am writing something until not all of data is shifted, (this constant shift of 16 bits could indicate so) but I don't get how this would be possible if I'm checking TXE.
3. Why I'm using this weird config - I wanted to make a "hello world" I2S project by interfacing PDM microphone. This required me to configure I2S as master receiver. Unfortunately, I encountered a problem with PDM2PCM library (which I wrote at this forum about). In the meantime, I thought that I can make sure, that I configured everything properly, so decided on implementing slave transmitter to simulate microphone and check if I'm not scrambling the packet order.
2025-01-01 12:11 PM
Either way to sum up my initialization procedure:
2025-01-01 12:15 PM
Btw, here is the start of transmission, where I made sure WS is pulled down low when I start both Tx and Rx.
2025-01-01 12:17 PM
A pull-down does not help: if the LRCK signal is generated it is Totem Pole (or Push-Poll). It is actively driven (not Open Drain output), so a pull-up or -down does not have any effect.
PDM microphones? But is PDM not a completely different interface (protocol)? Or are you trying to connect I2S microphones?
PDM does not have a LRCK signal. Instead: the left and right is done via the falling and raising edge of the PDMCLK signal. And the PDMCLK is way faster (something between 1..3 MHz, depending on the PDM audio format, oversampling factor).
What was your problem with the PDM2PCM library? (I did a lot of tests with PDM mics and this library, on a different board: Portenta H7)
2025-01-01 01:02 PM
WS with pull-down does not fix, does not do anything (actively driven signals).
Your "problem" is: when all starts, the very first cycle is not correct (some BCK clocks but WS/LRCK changes - sure: now it goes to the 1st correct cycle).
This is due to the fact (for my understanding):
This creates a "kick-up" (incorrect first cycle). Your Slave Transmitter is confused and therefore the Master Receiver gets unpredictable Rx data.
What happens on the following cycles? Do not do all the time Start and Stop (let both run forever after enabled).
Have you tried to let both run forever and you pull-up or pull-down the DATA Rx input? What if you connect DATA Rx with LRCK/WS signal? (do you see 0xFFFF vs. 0x0000 in the two channels?)
2025-01-01 01:52 PM
I think, your issue is due to the very first cycle is an "unreliable" (unpredictable) cycle.
Even, you would change to a slightly different start sequence, e.g.:
it is still a potential "hick-up": the Slave Transmitter might start anywhere, to see the generated signals at any time (the start of both instances are not in sync). So, the started Slave Transmitter might not see a complete valid I2S cycle, a bit too short, on the very first iteration.
So, you have to wait a bit after Master Receiver was enabled (at least one complete I2S cycle), enable Slave Transmitter and wait also at least one complete I2C cycle). Now send something, but not immediately (Slave Transmitter might not be in sync yet with the I2S cycles).
All it just stable after one fully completed I2S cycle (a second I2S cycle needed to be completed). Send something a while after both I2S instances are launched and running in a stable state (on I2S cycles). You have to discard the results of the very first I2S cycle (which is potentially not a correct valid complete cycle).
Send something later and have the receiver hot (waiting for something received). This should match now. Potentially, you have to discard the result of the very first iteration.
2025-01-02 02:26 AM
Looking at your pin initialization code, you don't set OSPEEDR for the bit clock. Your problem thus may be the Corrupted last bit of data and/or CRC received in Master mode with delayed SCK feedback erratum. Try setting OSPEEDR to higher than the default lowest state.
JW