I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

JB2050
Posts: 9
Joined: Sun Feb 11, 2018 4:23 pm

I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby JB2050 » Sat Oct 06, 2018 11:02 pm

Hello

I want an ESP32 to output I2S data with its I2S0 interface in slave mode.

I'm finding that with the I2S interface in master mode, the Tx data is correct. However, with it in slave mode, and the BCK and WS (FS) clocks supplied from an SAI interface (configured for I2S) in an STM32F767 MCU, some of the samples appear as zeros.

This can easily be seen with the i2s_adc_dac example in esp-idf/examples/peripherals. Here are the signals. The top trace is the data from the I2S interface:

Master mode:
20181006 2154 ESP32 I2S Master.jpg
20181006 2154 ESP32 I2S Master.jpg (222.65 KiB) Viewed 76538 times
Slave mode:
20181006 2154 ESP32 I2S Slave.jpg
20181006 2154 ESP32 I2S Slave.jpg (228.41 KiB) Viewed 76538 times
Note the zeros in the decoded I2S at the bottom of the second (slave mode) image.

Note also that the zeros replace samples; the zeros are not inserted. (I've tested this by outputting an incrementing integer. I found that 450, 451, 452, 453 typically becomes something like 450, 0, 0, 453).

I can see nothing in the esp-idf i2s.c driver file that could cause this problem. When slave mode is requested, it simply configures the IO pins appropriately and sets the I2S peripheral to slave mode.

Section 12.3 of the ESP32 technical reference says "When ESP32 I2S works in slave mode, the master must use I2Sn_CLK as the master clock and fi2s>= 8 *fBCK." I don't know whether that is relevant or not. In any case, which master is it referring to, given that if the ESP32 I2S interface is configured as a slave then the master is likely elsewhere - somewhere that it cannot use I2Sn_CLK?

These two posts may be about the same problem: The first was apparently solved by using APLL / using a later esp-idf, though doing these things did not help me. The second is not solved.

The ESP32 module is mounted on a 4 layer PCB (with power planes) along with the STM32F767, and the ESP32 has its own 3.3V 1A LDO regulator, so I don't think signal / power integrity is a problem. The I2S clocks supplied by the STM32F767 come via 330R resistors (which limit the current in the event that both the ESP32 and STM32 are configured in master mode) and are clean.

Any ideas?

Cheers,
JB.

Other info:
  • ESP32: ESP-WROOM-32. Silicon revision 1. Main clock = 40Mhz. MCU clock = 240Mhz.
  • esp-idf: v3.2-dev-1231-g3977d4b56
  • I2S pins: BCK = IO16, WS (FS) = IO17, D = IO21
  • OS: Windows 7
Last edited by JB2050 on Sun Oct 07, 2018 9:25 pm, edited 4 times in total.

JB2050
Posts: 9
Joined: Sun Feb 11, 2018 4:23 pm

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby JB2050 » Sun Oct 07, 2018 12:05 pm

Given that excerpt from the technical reference manual "When ESP32 I2S works in slave mode, the master must use I2Sn_CLK (MCLK) as the master clock and fi2s>= 8*fBCK.", I tried outputting the ESP32 I2S0_CLK to IO0 and using that to clock the STM32 I2S (SAI) interface.

Zeros are still present.

However, now every other sample is zero, as opposed to seemingly random ones.

In both the following diagrams, the ESP32 I2S interface is in slave mode, and the STM32 I2S interface is in master mode.

Here, the STM32 I2S interface is clocked from a PLL on the STM32:
ESP32 I2S in slave mode with STM32 I2S clocked at 11.3 MHz from own PLL.png
ESP32 I2S in slave mode with STM32 I2S clocked at 11.3 MHz from own PLL.png (36.85 KiB) Viewed 76511 times
And here, the STM32 I2S interface is clocked from the ESP32 I2S0_CLK (MCLK):
ESP32 I2S in slave mode with STM32 I2S clocked at 11.289 MHz from ESP32.png
ESP32 I2S in slave mode with STM32 I2S clocked at 11.289 MHz from ESP32.png (32.16 KiB) Viewed 76511 times
Note that in the second diagram, every other sample is zero.

So it seems that the ESP32 I2S interface in slave mode is indeed affected by whether the external BCK and WS (FS) clocks are synchronized with its own I2Sn_CLK (MCLK) clock (which is produced by its APLL). However, even when they are, even when the STM32 I2S master is clocked from the ESP32's I2Sn_CLK, and when freq(BCK) is an eighth of freq(I2Sn_CLK) as in my case, things are still not right because zeros are output on every other sample.

Any ideas?

JB.
Last edited by JB2050 on Sun Oct 07, 2018 3:39 pm, edited 2 times in total.

JB2050
Posts: 9
Joined: Sun Feb 11, 2018 4:23 pm

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby JB2050 » Sun Oct 07, 2018 3:18 pm

Is there any way to input a MCLK into the ESP32 for use by (one of) its I2S interfaces (as with many DACs, PAs, etc)?

If so, that would solve my problem nicely.

JB2050
Posts: 9
Joined: Sun Feb 11, 2018 4:23 pm

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby JB2050 » Sun Oct 07, 2018 3:59 pm

Even though the WS (FS) edges produced by my STM32 I2S interface change on the falling edge of BCK (SCK), which is correct, I'm getting crackling that is resolved when WS is delayed slightly by adding a small capacitor (22pF to 100pF) after the 330R resistor between the STM32 and the ESP32 (or by touching WS with my finger at the ESP32 end of the resistor). I'm fairly certain that the cracking is a different issue to the zeroed samples on the basis that with WS delayed, the crackling stops yet the zeros remain.

(Incidentally, there are numerous other I2S devices using the STM32 I2S clocks, albeit without the 330R resistors, and they work fine).

As I understand it, WS should be sampled by I2S slaves on the rising edge of BCK, in which case such a small timing change, one that is not noticeable on the logic analyzer, should make no difference.

Is there maybe something wrong with the ESP32 slave design / implementation?
Last edited by JB2050 on Sun Oct 07, 2018 10:50 pm, edited 1 time in total.

JB2050
Posts: 9
Joined: Sun Feb 11, 2018 4:23 pm

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby JB2050 » Sun Oct 07, 2018 9:23 pm

The sample zeroing problem appears to be sample rate dependent.

To recap: I have the ESP32 configured as an I2S slave and an STM32 an I2S master. I have configured the ESP32 APLL to generate the I2S MCLK for the STM32 I2S master. The STM32 supplies the I2S BCK and FS clocks to the ESP32.

When the sample rate is set to 44100Hz, I found previously that every other LR sample from the ESP32 I2S slave is zeroed. I also found that minor changes to the phase of the BCK and FS clocks causes errors, which is incorrect.

I've since found that if the sample rate rate is set to 16000Hz or 22050Hz or 24000Hz or 36000Hz, the I2S data from the ESP32 slave is completely correct. I also found that minor changes to the phase of the BCK and FS clocks is then not critical, as expected of I2S.

If I it set to 40000Hz or 44100Hz or 48000Hz or 60000Hz, the zero / phase problem returns.

I get the same results if the ESP32 APLL is not used (though there's noticeable timing jitter when the APLL is not used).

All the results so far were with a 240MHz MCU clock frequency. They are unchanged with a 160MHz MCU clock frequency. I've not tried changing the main crystal frequency.

I don't know what to make of these findings.

Ideas and suggestions welcome.

JB2050
Posts: 9
Joined: Sun Feb 11, 2018 4:23 pm

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby JB2050 » Sun Oct 07, 2018 9:59 pm

Possible solution

Setting bit I2S_TX_DSYNC_SW in I2S_TIMING_REG using this:

Code: Select all

SET_PERI_REG_BITS(I2S_TIMING_REG(0), 0x1, 1, I2S_TX_DSYNC_SW_S);
appears to have cured both the unwanted zeros appearing in the ESP32 I2S slave output data, and the phase sensitivity of the BCK and FS signals into the ESP32. I've not tested this solution thoroughly yet.

The technical reference says of this bit: "Set this bit to synchronize signals into the transmitter in double sync method.". I've not found any other information about double synchronizing.

It is still necessary to clock the remote (STM32) master I2S interface from the I2S0_CLK signal of the ESP32.

JB2050
Posts: 9
Joined: Sun Feb 11, 2018 4:23 pm

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby JB2050 » Tue Oct 09, 2018 4:58 pm

Can someone from ESP please confirm that my findings above are correct?

In particular, please confirm:
  • Whether the ESP32 cannot operate as an asynchonous I2S slave like other I2S slave devices, including, I think, various Bluetooth A2DP receivers, and instead must be the supplier of the master clock for the other I2S components in the system. (If this is the case, then the ESP32 is, I'd argue, fundamentally inferior to other Bluetooth receivers and other I2S devices in terms of applicability (clearly not all the I2S slaves in any given system can be the supplier of the master clock for the system) to the extent that a silicon revision to overcome this limitation would, I think, be very sensible).
  • Whether it's normal to need to enable double buffering for the esternal BCK and (WS) FS clocks. (If this is the case, then I suggest it should be added to the documentation and be easier to enable from esp-idf).
Thanks,
JB.

PS: I don't know your relationship with Espressif, including the influence you have on them. I'm assuming in this post that you have some means of giving them feedback that has the potential to effect change.

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby WiFive » Wed Oct 10, 2018 1:14 am

JB2050 wrote: PS: I don't know your relationship with Espressif, including the influence you have on them. I'm assuming in this post that you have some means of giving them feedback that has the potential to effect change.
This forum is run by Espressif and employees post here with ESP_* usernames. One should answer you soon.

crespum
Posts: 3
Joined: Thu Nov 29, 2018 6:21 pm

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby crespum » Fri Mar 22, 2019 8:17 am

Hi @JB2050, I've encountered a similar issue. Have you ever got an answer from the ESP staff?

Stephan
Posts: 12
Joined: Tue Aug 27, 2019 2:42 am

Re: I2S: Samples incorrectly zeroed when I2S interface is in slave mode but not master mode

Postby Stephan » Tue Aug 25, 2020 7:36 am

I ran into the same problem, when taking webradio sound from ESP32 with I2S slave. What works well for me is to manually detect and correct the zero samples. Since the zero samples always occur as 4 zero bytes in a row, I look for that pattern and interpolate accordingly. It's a workaround and the sound result is quite acceptable. The used code takes 300us to detect/correct the zero patterns, for a sound amount of 0x3000 = 12'288 bytes. We sample at 44.1kHz 16bit stereo, making these 12'288 bytes equal to 12'288/(2*2*44100 for stereo*16bit*sample_rate) = 70ms. As the sound data is fetched by double buffered DMA, it's not time critical to interpolate the zero samples (300us are about a half percent of the sound data of 700ms). The CPU in charge is an iMX233 at 217MHz (it's an ARM9).

Code: Select all

// Data to process has length of 0x3000 bytes and is placed in 'data':
memcpy(data,&slot_fetch[slides*0x3000],0x3000);
// Check for zero samples and interpolate:
UINT32* probe;
int zero_check;
for(zero_check=0,probe=(UINT32*)data;zero_check<0xC00;zero_check++) {
  if((*probe)==0) { // Found 4 zero bytes in a row => interpolate
	short*  s;
	s=(short*)probe;
	int left, right;
	if(zero_check>0 && zero_check<0xBFC) {  // Interpolate from "before" and "after"
	  left=s[-2]+s[+2];
	  left/=2;
	  right=s[-1]+s[+3];
	  right/=2;
	  s[0]=left;
	  s[1]=right;
	} else {  // Is first or last sample
	  if(zero_check<0xBFC) {  // Is first sample. Just copy 2nd sample to 1st:
		s[0]=s[2];
		s[1]=s[3];
	  } else {  // Is last sample. Just repeat the one before last:
		s[0]=s[-2];
		s[1]=s[-1];
	  }
	}
  }
  probe++;
}
// Above loop to pick & correct zero samples takes 300us (iMX233 (ARM9), 217MHz)
//////////////////////////////////////////////////////////////////////////////////
Attachments
I2S.c
(1009 Bytes) Downloaded 627 times

Who is online

Users browsing this forum: No registered users and 53 guests