I2S syncronized MCLK output

johboh
Posts: 8
Joined: Sat Apr 29, 2017 5:58 pm

I2S syncronized MCLK output

Postby johboh » Sun Apr 30, 2017 10:30 am

Hi!
I have an external DAC, namely a CS4344, that needs a MCLK that is 256x LRCK. Documentation states "there is no required phase relationship, but MCLK, LRCK and SCLK must be synchronous".

There are some threads here touching the subject:
https://esp32.com/viewtopic.php?t=1585
https://esp32.com/viewtopic.php?t=1521
https://esp32.com/viewtopic.php?t=1068
https://esp32.com/viewtopic.php?t=923

but none of them give any concrete answers on how to generate a MCLK for the DAC.

I'm using the example from https://github.com/espressif/esp-idf/tr ... herals/i2s and that one togheter with generating a clock using the LEDC driver, I get a tone but with a lot of extra noise and clicks, probably because the clock is not syncronized.

There are some documentation hinting that the I2S CLK can be muxed out on a GPIO to drive MCLK, but I'm unsure how to configure the PIN CTRL, and I can't find anywhere what this frequency will be.

I found that one can configure GPIO1/UOTXD to be CLK_OUT3:
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3);
but I don't know how to configure I2S CLK to use CLK_OUT3 as output, nor to control the frequency.

This is what I use to generate the clock:

Code: Select all

static void enable_out_clock() {
    periph_module_enable(PERIPH_LEDC_MODULE);
	 ledc_timer_bit_t bit_num = (ledc_timer_bit_t) 2;      // 3 normally
	int duty = pow(2, (int) bit_num) / 2;

    ledc_timer_config_t timer_conf;
    timer_conf.bit_num = bit_num;
    timer_conf.freq_hz = 12288000; //12288000; //8192000; // 22579200
    timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
    timer_conf.timer_num = LEDC_TIMER_0;
    esp_err_t err = ledc_timer_config(&timer_conf);
    if (err != ESP_OK) {
        //ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err);
    }

    ledc_channel_config_t ch_conf;
    ch_conf.channel = LEDC_CHANNEL_0;
    ch_conf.timer_sel = LEDC_TIMER_0;
    ch_conf.intr_type = LEDC_INTR_DISABLE;
    ch_conf.duty = duty;
    ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
    ch_conf.gpio_num = MCLK_GPIO; //s_config.pin_xclk; 
    err = ledc_channel_config(&ch_conf);
    if (err != ESP_OK) {
        //ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err);
    }

	  // Set the PWM to the duty specified
   ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, duty);
   ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0);
}
Any suggestion is appreciated!

ESP_Sprite
Posts: 9016
Joined: Thu Nov 26, 2015 4:08 am

Re: I2S syncronized MCLK output

Postby ESP_Sprite » Mon May 01, 2017 6:44 am

Both the I2S module as well as the timer module are fed from the main 80MHz APB clock, so they are actually synchronized in that respect. I think your pops and clicks may have a different source.

johboh
Posts: 8
Joined: Sat Apr 29, 2017 5:58 pm

Re: I2S syncronized MCLK output

Postby johboh » Mon May 01, 2017 4:37 pm

I found the issue, with help from this one:
https://github.com/espressif/esp-idf/issues/300

There where actually three problems:
1) the one that they suggest in the link, that is, push data to I2s only once, after the loop.
2) I had changed the sample rate from 36000 to 32000, but I hadn't changed the number of dma buffers and the size of each buffer. I had to adjust so the sum of number of buffers and buffer size aligned with the new number of samples, that is, 320 (32000 sample rate / 100 Hz). Now using 8 buffers with 40 bytes each.
3) the loop creating the samples ranged from 0-319 instead of 0-359, and thus not creating a full sine wave.

rangermw
Posts: 1
Joined: Tue Dec 18, 2018 2:58 am

Re: I2S syncronized MCLK output

Postby rangermw » Tue Dec 18, 2018 3:00 am

use gpio0
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
WRITE_PERI_REG(PIN_CTRL, READ_PERI_REG(PIN_CTRL) & 0xFFFFFFF0);

Who is online

Users browsing this forum: Bing [Bot] and 113 guests