APLL / GPIO16_EMAC_CLK_OUT - wrong frequency - unable to generate 50MHz clk with rev0 chip

sauttefk
Posts: 2
Joined: Thu Oct 12, 2017 10:00 am

APLL / GPIO16_EMAC_CLK_OUT - wrong frequency - unable to generate 50MHz clk with rev0 chip

Postby sauttefk » Thu Oct 12, 2017 10:52 am

I want to use the APLL to generate the required 50MHz for an external Ethernet PHY using the APLL and the EMAC_CLK_OUT on GPIO16.

Somehow the output frequency is unexpectedly divided by 5

According to the ECO and Workarounds for Bugs in ESP32 (issue 3.7) document the formula for the APLL frequency for rev0 chips is:
f_out = f_xtal × (sdm2 + 4) / (2 × (o_div + 2)) where f_xtal is 40MHz, sdm2 is 6 (4th parameter), o_div is 2 (5th parameter).
This evaluates to f_out = 40MHz × (6 + 4) / (2 × (2 + 2)) =>f_out = 400MHz / 8 => f_out = 50MHz
According to the ESP32 Technical Reference Manual (paragraph 3.2.7) the dividend of the formula (f_xtal × (sdm2 + 4)) has a frequency range from 350MHz to 500MHz (Where 400MHz lies well within).

I'm setting up set the correct parameters with rtc_clk_apll_enable(1, 0, 0, 6, 2) but the frequency I get on GPIO16 is 10MHz instead of 50MHz.

When I change o_div from 2 to 0, I get 20MHz (which prooves that the divisor works as described).
When I change sdm2 from 6 to 8, I get 12MHz (which prooves that the dividend works as described in the formula).
When I change sdm2 to 1 and o_div to 0 rtc_clk_apll_enable(1, 0, 0, 1, 0) - this also evaluates to 50MHz - the function call never returns, as the dividend now gets 200MHz which is out of the frequency range of the APLL but rtc_clk_apll_enable waits for a PLL-lock which never happens (which prooves that the dividend is lower than the specified minimum).
When I change sdm2 to 11 and o_div to 4 rtc_clk_apll_enable(1, 0, 0, 11, 4) - this also evaluates to 50MHz - but the dividend is now 600MHz and the PLL gets no lock (which prooves that the dividend is higher than the specified maximum).

My questions:
  • Is there any by 5 divider which has to be disabled?
  • Is the APLL somehow using the internal 8MHz clock instead of the external 40MHz crystal?
  • Can anybody provide me some code that generates a 50MHz clk on GPIO16?
The code that I'm currently using is as follows:

Code: Select all

#include "soc/rtc.h"
#include "soc/emac_ex_reg.h"

ESP_LOGD(TAG, "################ set up EMAC_CLK_OUT #############");
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_H_DIV_NUM, 0);
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_DIV_NUM, 0);
REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);
ESP_LOGD(TAG, "################ before enabling APLL ############");
rtc_clk_apll_enable(1, 0, 0, 6, 2); // 50 MHz
ESP_LOGD(TAG, "################ APLL has a stable lock ##########");

hwmaier
Posts: 31
Joined: Sun May 28, 2017 7:30 am

Re: APLL / GPIO16_EMAC_CLK_OUT - wrong frequency - unable to generate 50MHz clk with rev0 chip

Postby hwmaier » Thu Nov 30, 2017 6:49 am

I managed to generate clean 50MHz using the Audio PLL and I2S using the following code. Signal is routed to GPIO0.

Code: Select all

    // Enable the I2S peripheral 
    periph_module_enable(PERIPH_I2S0_MODULE);

    //
    // Configure Audio PLL to 100 MHz.
    // Note: sdm2 seems limited to 12 for some reason.
    //
    //             f_xtal (sdm2 + sdm1/2^8 + sdm0/2^16 + 4)
    //    f_out = ------------------------------------------
    //                          2 (odiv + 2)
    //
    // with f_xtal = 40MHz, sdm2 = 6, sdm0 = 0, sdm1 = 0, odir = 0
    //
    //rtc_clk_apll_enable(1, 0 /*sdm0*/, 0 /*sdm1*/, 6 /*sdm2*/, 2 /*odiv*/); // 50 MHz
    rtc_clk_apll_enable(1, 0 /*sdm0*/, 0 /*sdm1*/, 6 /*sdm2*/, 0 /*odiv*/); // 100 MHz

    //
    // Configute I2C_CLK frequency using APLL_CLK.
    // This is the more accurate clock source with low jitter.
    // If I2S_CLKA_ENA is set, then clock source is APLL_CLK else
    // if I2S_CLK_EN is set then PLL_D2_CLK (160 MHz).
    // Refer to Figure 36 "I2S Clock" in "ESP32 Technical Reference Manual".
    // Note: N must be >= 2 for some reason.
    //
    //                f_pll
    //    f_i2s  = ----------
    //               N + b/a
    //
    //  with f_pll = 50MHz, a = 0, b = 0, N = 2 for 25MHz (clean signal)
    //  with f_pll = 100MHz, a = 0, b = 0, N = 2 for 50MHz (clean signal)
    //  with f_pll = 160MHz, a = 5, b = 2, N = 6 for 25MHz (harmonics)
    //  with f_pll = 160MHz, a = 10, b = 2, N = 3 for 50MHz (harmonics, jitter)
    //
    WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
                  I2S_CLKA_ENA | // Use APLL_CLK
                  //I2S_CLK_EN | // Use PLL_D2_CLK
                  (0 << I2S_CLKM_DIV_A_S) |
                  (0 << I2S_CLKM_DIV_B_S) |
                  (2 << I2S_CLKM_DIV_NUM_S)); // Divide by 2

    // Output I2C clock to CLK_OUT1
    // Refer to "Register 4.33: IO_MUX_PIN_CTRL"" description in "ESP32 Technical Reference Manual"
    WRITE_PERI_REG(PIN_CTRL, (0x0 << CLK_OUT1_S) | (0xF << CLK_OUT2_S) | (0xF << CLK_OUT3_S));
   
    // Output CLK_OUT1 on GPIO0
    PIN_FUNC_SELECT(GPIO_PIN_REG_0, FUNC_GPIO0_CLK_OUT1); 
scope_0.png
scope_0.png (36.11 KiB) Viewed 7524 times

hwmaier
Posts: 31
Joined: Sun May 28, 2017 7:30 am

Re: APLL / GPIO16_EMAC_CLK_OUT - wrong frequency - unable to generate 50MHz clk with rev0 chip

Postby hwmaier » Thu Nov 30, 2017 7:11 am

And your code works as well once the order of initialization is modified. See below code which outputs nice 50MHz on GPIO16.

Code: Select all

    // Enable the I2S peripheral 
    periph_module_enable(PERIPH_I2S0_MODULE);

    //
    // Configure Audio PLL to 100 MHz.
    // Note: sdm2 seems limited to 12 for some reason.
    //
    //             f_xtal (sdm2 + sdm1/2^8 + sdm0/2^16 + 4)
    //    f_out = ------------------------------------------
    //                          2 (odiv + 2)
    //
    // with f_xtal = 40MHz, sdm2 = 6, sdm0 = 0, sdm1 = 0, odir = 0
    //
    rtc_clk_apll_enable(1, 0 /*sdm0*/, 0 /*sdm1*/, 6 /*sdm2*/, 2 /*odiv*/); // 50 MHz

    REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_H_DIV_NUM, 0);
    REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_DIV_NUM, 0);
    REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN);
    REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN);

    // Output EMAC_CLK_OUT on GPIO16
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);

Who is online

Users browsing this forum: Google [Bot] and 88 guests