With 48k sample rate I'm getting the correct MCLK (12.288) however LRCLK is around 51 kHz, BCLK is correctly aligned to LRCLK.
At 44.1KHz same issue with LRCLK close to 47kHz.
The issue occurs on both an S3 and a traditional ESP32 DevkitC.
Is there something I'm not setting correctly?
Code: Select all
/****************************************************
* SIMPLE I2S test
TX mode - I2S0
Signed 24 bit data
48kHz
ESP32-S3 or ESP32
ESP32 2.0.6 - IDF 4.4
Arduino 1.8.19
* *************************************************/
#define STATS // print stats
#include <Arduino.h>
int samplerate = 48000;
//int samplerate = 44100;
#define BUFSIZE 128 // 32 bit samples
#define SAMPSIZE 4 // length of sample variable for ibuf/obuf
#define DMASAMPSIZE 3 // length of sample variable for ibuf/obuf
#define DMA_BUFS 4
#define DMABUFSIZ (BUFSIZE * DMASAMPSIZE) // bytes ( < 4096)
int32_t obuf[BUFSIZE];
int32_t ibuf[BUFSIZE];
#define LEFT 0
#define RIGHT 1
//#define S3
#ifdef S3
#define DATA_IN 37 //S3 GPIO MUX allows any pin mappings
#define MCLK 38
#define BCLK 39
#define LRCLK 40
#define DATA_OUT 41
#else // std ES32
#define MCLK 0 // Earlier ESP32s support setting MCLK on GPIO0/GPIO1/GPIO3 only
#define BCLK 5
#define LRCLK 25
#define DATA_IN 35
#define DATA_OUT 27
#endif
#define I2S_CORE 1
#include <driver/i2s.h>
#define STD_I2S
#ifdef STD_I2S // Phillips: +1 bit/frame
//#define I2S_AFMT I2S_COMM_FORMAT_STAND_I2S
#define I2S_AFMT I2S_COMM_FORMAT_I2S
#else // MSB format, no pre-bit
#define I2S_AFMT I2S_COMM_FORMAT_STAND_MSB
//#define I2S_AFMT I2S_COMM_FORMAT_I2S_MSB
#endif
i2s_port_t i2s_num_x = I2S_NUM_0;
i2s_config_t i2s_config_x;
TaskHandle_t AudioStreamTaskHandle;
static void AudioStreamTask(void * pvParameters);
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n\***** I2S - 24 bit test *****");
//fillBuf_32();
fillBuf_24();
//fillBuf_16();
printbuf();
Serial.println("** Start I2S.");
configure_i2s(samplerate);
Serial.printf("Real I2S rate %4.3f\n", i2s_get_clk(i2s_num_x));
xTaskCreatePinnedToCore(AudioStreamTask, "AudioStreamTask", 20000, NULL, 4, &AudioStreamTaskHandle, I2S_CORE);
Serial.println("Setup done");
}
void loop()
{
// processing occurs in pinned task AudioStreamTask()
delay(5000);
yield();
}
static void AudioStreamTask(void * pvParameters){
size_t bytesOut, bytesIn;
esp_err_t errchk;
while(1)
{
// blocks until a DMA buffer is available
errchk = i2s_write(i2s_num_x, &obuf[0], DMABUFSIZ, &bytesOut, portMAX_DELAY );
if(bytesOut < 100 || errchk != ESP_OK)
Serial.printf("Bad I2S write %i bytes, err %i\n", bytesOut, errchk);
vTaskDelay(1);
}
}
volatile bool i2s_running = false;
void configure_i2s(int SampleRate)
{
#ifdef STATS
Serial.printf("I2S out: sample rate %u\n", SampleRate);
#endif
i2s_config_x = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX ), //| I2S_MODE_RX
.sample_rate = samplerate,
.bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t)(I2S_AFMT),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = DMA_BUFS,
.dma_buf_len = DMABUFSIZ,
.use_apll = 1,
.mclk_multiple = I2S_MCLK_MULTIPLE_256
};
static const i2s_pin_config_t pin_config_x =
{
.mck_io_num = MCLK,
.bck_io_num = BCLK,
.ws_io_num = LRCLK,
.data_out_num = DATA_OUT,
.data_in_num = I2S_PIN_NO_CHANGE//DATA_IN
};
if(i2s_running)
{
i2s_stop(i2s_num_x);
i2s_driver_uninstall(i2s_num_x);
}
i2s_driver_install(i2s_num_x, &i2s_config_x, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num_x, &pin_config_x);
i2s_set_sample_rates(i2s_num_x, SampleRate); //set sample rates
i2s_zero_dma_buffer(i2s_num_x);
i2s_running = true;
}
void fillBuf_32() // fill with a simple sequence, 32 bit offsets
{
for (int i = 0; i < BUFSIZE; i++)
obuf[i] = i;
}
void fillBuf_24() // fill with a simple sequence, 24 bit offsets
{
char * sp = (char *)&obuf;
//sp +=3; // start at the low byte
int count = BUFSIZE * 32/24;
int i;
for (i = 0; i < BUFSIZE; i++)
obuf[i] = 0;
for (i = 0; i < count; i++)
{
*sp = i+1;
sp += 3;
}
}
void fillBuf_16() // fill first BUFSIZE with a simple sequence, 16 bit offsets
{
char * sp = (char *)&obuf;
int count = BUFSIZE;
int i;
for (i = 0; i < BUFSIZE; i++)
obuf[i] = 0;
for (i = 0; i < count; i++)
{
*sp = i+1;
sp += 2;
}
}
void printbuf()
{
for (int i = 0; i < 10; i++)
Serial.printf(" 0x%08x,", obuf[i]);
}