esp-idf: Unable to set I2S APLL Clock for 48khz 32bit 2ch (IDFGH-432)

Environment

  • Core (if using chip or module): ESP-WROOM32
  • IDF version 7c29a39d6
  • Development Env: Eclipse
  • Operating System: MacOS
  • Power Supply: external 3.3V

Problem Description

In I2S Slave TX mode i2s_mode_t mode = I2S_MODE_SLAVE | I2S_MODE_TX; i2s_comm_format_t comm_fmt = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB;

If I set a frequency of 48Khz and APLL, it will not set the frequency correctly and I got audio problems, I imagine is because of DMA buffer under/overrun.

I (352) phy: phy_version: 4000, b6198fa, Sep 3 2018, 15:11:06, 0, 2 I (902) I2S: queue free spaces: 1 I (912) I2S: DMA Malloc info, datalen=blocksize=4088, dma_buf_count=16 I (912) I2S: APLL: Req RATE: 48000, real rate: 43945.238, BITS: 32, CLKM: 1, BCK_M: 8, MCLK: 22499962.000, SCLK: 2812495.250000, diva: 1, divb: 0 I (932) BT_APP_CORE: bt_app_task_handler, sig 0x1, 0x0 I (932) main: RAM left 75544

If I disable APLL, then the frequency is correctly set - but I get crappy sound due to fractional PLL.

In case I set mclk_fixed (at 24573600.000) I get 50Khz:

I (781) I2S: queue free spaces: 1 I (781) I2S: DMA Malloc info, datalen=blocksize=4088, dma_buf_count=16 I (791) I2S: APLL: Req RATE: 48000, real rate: 50223.129, BITS: 32, CLKM: 1, BCK_M: 7, MCLK: 22499962.000, SCLK: 2812495.250000, diva: 1, divb: 0 I (801) BT_APP_CORE: bt_app_task_handler, sig 0x1, 0x0 I (811) main: RAM left 75668

I imagine that the problem could be in function i2s_apll_calculate_fi2s that have a bad behaviour in case of 48Khz 32bit 2ch.

this issue could be related

Then further investigation get me through an error in the documentation: APLL_MAX_FREQ = 500Mhz and APLL_MIN_FREQ = 250 Mhz

but in the description of we read: * The dividend in this expression should be in the range of 240 - 600 MHz. and * 1. We will choose the parameters with the highest level of change, * With 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9,

What’s the trouth?

Steps to reproduce

Take A2DP_Sink Example and set I2S at 48Khz, Slave, 32Bit.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 19 (2 by maintainers)

Commits related to this issue

Most upvoted comments

I think 176k @ 16bits is the maximum that can be done, taking into account various constraints. The code is the follòwing. The sampling rate required is 2x the original sampling rate and sample size is 32 bits. Then the resulting buffer shall be send to a led connected to the SD line of the I2S, that’s all

 * SPDIF support
 */
#if BYTES_PER_FRAME == 4
typedef ISAMPLE_T s16_t
#else 
typedef ISAMPLE_T s32_t
#endif 
 
#define PREAMBLE_B  (0xE8) //11101000
#define PREAMBLE_M  (0xE2) //11100010
#define PREAMBLE_W  (0xE4) //11100100

#define VUCP   		((0xCC) << 24)
#define VUCP_MUTE 	((0xD4) << 24)	// To mute PCM, set VUCP = invalid.

extern const u16_t spdif_bmclookup[256];

/* 
 SPDIF is supposed to be (before BMC encoding, from LSB to MSB)				
	PPPP AAAA  SSSS SSSS  SSSS SSSS  SSSS VUCP				
 after BMC encoding, each bits becomes 2 hence this becomes a 64 bits word. The
 the trick is to start not with a PPPP sequence but with an VUCP sequence to that
 the 16 bits samples are aligned with a BMC word boundary. Note that the LSB of the
 audio is transmitted first (not the MSB) and that ESP32 libray sends R then L, 
 contrary to what seems to be usually done, so (dst) order had to be changed
*/
void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
	u16_t hi, lo, aux;
	
	// frames are 2 channels of 16 bits
	frames *= 2;

	while (frames--) {
#if BYTES_PER_FRAME == 4		
		hi  = spdif_bmclookup[(u8_t)(*src >> 8)];
		lo  = spdif_bmclookup[(u8_t) *src];
#else
		hi  = spdif_bmclookup[(u8_t)(*src >> 24)];
		lo  = spdif_bmclookup[(u8_t) *src >> 16];
#endif	
		lo ^= ~((s16_t)hi) >> 16;

		// 16 bits sample:
		*(dst+0) = ((u32_t)lo << 16) | hi;

		// 4 bits auxillary-audio-databits, the first used as parity
		aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);

		// VUCP-Bits: Valid, Subcode, Channelstatus, Parity = 0
		// As parity is always 0, we can use fixed preambles
		if (++(*count) > 383) {
			*(dst+1) =  VUCP | (PREAMBLE_B << 16 ) | aux; //special preamble for one of 192 frames
			*count = 0;
		} else {
			*(dst+1) = VUCP | ((((*count) & 0x01) ? PREAMBLE_W : PREAMBLE_M) << 16) | aux;
		}
		
		src++;
		dst += 2;
	}
}

const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least significant bit first)
	0xcccc, 0x4ccc, 0x2ccc, 0xaccc, 0x34cc, 0xb4cc, 0xd4cc, 0x54cc,
	0x32cc, 0xb2cc, 0xd2cc, 0x52cc, 0xcacc, 0x4acc, 0x2acc, 0xaacc,
	0x334c, 0xb34c, 0xd34c, 0x534c, 0xcb4c, 0x4b4c, 0x2b4c, 0xab4c,
	0xcd4c, 0x4d4c, 0x2d4c, 0xad4c, 0x354c, 0xb54c, 0xd54c, 0x554c,
	0x332c, 0xb32c, 0xd32c, 0x532c, 0xcb2c, 0x4b2c, 0x2b2c, 0xab2c,
	0xcd2c, 0x4d2c, 0x2d2c, 0xad2c, 0x352c, 0xb52c, 0xd52c, 0x552c,
	0xccac, 0x4cac, 0x2cac, 0xacac, 0x34ac, 0xb4ac, 0xd4ac, 0x54ac,
	0x32ac, 0xb2ac, 0xd2ac, 0x52ac, 0xcaac, 0x4aac, 0x2aac, 0xaaac,
	0x3334, 0xb334, 0xd334, 0x5334, 0xcb34, 0x4b34, 0x2b34, 0xab34,
	0xcd34, 0x4d34, 0x2d34, 0xad34, 0x3534, 0xb534, 0xd534, 0x5534,
	0xccb4, 0x4cb4, 0x2cb4, 0xacb4, 0x34b4, 0xb4b4, 0xd4b4, 0x54b4,
	0x32b4, 0xb2b4, 0xd2b4, 0x52b4, 0xcab4, 0x4ab4, 0x2ab4, 0xaab4,
	0xccd4, 0x4cd4, 0x2cd4, 0xacd4, 0x34d4, 0xb4d4, 0xd4d4, 0x54d4,
	0x32d4, 0xb2d4, 0xd2d4, 0x52d4, 0xcad4, 0x4ad4, 0x2ad4, 0xaad4,
	0x3354, 0xb354, 0xd354, 0x5354, 0xcb54, 0x4b54, 0x2b54, 0xab54,
	0xcd54, 0x4d54, 0x2d54, 0xad54, 0x3554, 0xb554, 0xd554, 0x5554,
	0x3332, 0xb332, 0xd332, 0x5332, 0xcb32, 0x4b32, 0x2b32, 0xab32,
	0xcd32, 0x4d32, 0x2d32, 0xad32, 0x3532, 0xb532, 0xd532, 0x5532,
	0xccb2, 0x4cb2, 0x2cb2, 0xacb2, 0x34b2, 0xb4b2, 0xd4b2, 0x54b2,
	0x32b2, 0xb2b2, 0xd2b2, 0x52b2, 0xcab2, 0x4ab2, 0x2ab2, 0xaab2,
	0xccd2, 0x4cd2, 0x2cd2, 0xacd2, 0x34d2, 0xb4d2, 0xd4d2, 0x54d2,
	0x32d2, 0xb2d2, 0xd2d2, 0x52d2, 0xcad2, 0x4ad2, 0x2ad2, 0xaad2,
	0x3352, 0xb352, 0xd352, 0x5352, 0xcb52, 0x4b52, 0x2b52, 0xab52,
	0xcd52, 0x4d52, 0x2d52, 0xad52, 0x3552, 0xb552, 0xd552, 0x5552,
	0xccca, 0x4cca, 0x2cca, 0xacca, 0x34ca, 0xb4ca, 0xd4ca, 0x54ca,
	0x32ca, 0xb2ca, 0xd2ca, 0x52ca, 0xcaca, 0x4aca, 0x2aca, 0xaaca,
	0x334a, 0xb34a, 0xd34a, 0x534a, 0xcb4a, 0x4b4a, 0x2b4a, 0xab4a,
	0xcd4a, 0x4d4a, 0x2d4a, 0xad4a, 0x354a, 0xb54a, 0xd54a, 0x554a,
	0x332a, 0xb32a, 0xd32a, 0x532a, 0xcb2a, 0x4b2a, 0x2b2a, 0xab2a,
	0xcd2a, 0x4d2a, 0x2d2a, 0xad2a, 0x352a, 0xb52a, 0xd52a, 0x552a,
	0xccaa, 0x4caa, 0x2caa, 0xacaa, 0x34aa, 0xb4aa, 0xd4aa, 0x54aa,
	0x32aa, 0xb2aa, 0xd2aa, 0x52aa, 0xcaaa, 0x4aaa, 0x2aaa, 0xaaaa
};`