I2S0 Clock (master clock) up to 80MHz derived from APLL clock

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby jgustavoam » Sat Feb 08, 2020 9:39 pm

After long research, study, I finally made it! I2S0 clock (main clock) up to 80MHz derived from the APLL clock
It's very complicated, but now I understand.
Many resources in only small chip - awesome!
BCK clock (serial clock) not working yet.

Correction
  • using PLL_D2 clock - master clock up to 80 MHz
  • using APLL clock - master clock up to 70 MHz
I2S0.clkm_conf.clka_en >>> Set this bit to enable clk_apll or reset to enable PLL Clock!

Code: Select all

/*  Project ESP32 Logic Analyzer     Tests with I2S Clock
    ESP32 Dev Kit 38 pins - Arduino IDE 1.8.10 - ESP32 Arduino V1.0.2
    https://github.com/Gustavomurta/ESP32-Logic-analyzer
    Gustavo Murta and Rui Vianna - 08/feb/2020
    I2S0 MCLK pin = GPIO0 (derived from APLL Clock) 
 */


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

#include "soc/syscon_reg.h"
#include "soc/rtc_cntl_struct.h"

//#include "esp32-hal-cpu.h"
#include "driver/i2s.h"

void setup()
{
  Serial.begin(115200);                         // IDE Console 115200 bps
  socDetails ();                                // system on a chip details
  apllClock ();                                 // Read RTC Control Clock configuration
  enableAudioPLLClock ();                       // power up audio PLL clock
  configAPLclock ();                            // enable APLL clock 80 Mhz
  mclkI2S0config ();                            // configure I2S0 MCLK clock
  bckI2S0config ();                             // configure I2S0 BCK  clock
  mclkClock ();                                 // configure GPIO0 to CLock OUT 1 - I2S MCLK
}

void socDetails ()
{
  Serial.println();
  Serial.print("ESP32 - Chip Revision: ");
  Serial.println(ESP.getChipRevision());                       // print ESP32 chip revision
  Serial.print("ESP32 - CPU frequency: ");
  Serial.println(ESP.getCpuFreqMHz());                         // print ESP32 cpu frequency
  Serial.print("ESP32 - RTC Crystal Clock frequency = ");
  Serial.println(rtc_clk_xtal_freq_get());                     // print ESP32 RTC Crystal Clock frequency      soc/rtc.h    40 MHz
  Serial.print("ESP32 - RTC APB frequency: ");
  Serial.println(rtc_clk_apb_freq_get());                      // print ESP32 RTC APB frequency                soc/rtc.h    80 MHz
  Serial.println();
}

void apllClock ()
{
  Serial.print("RTC Control Clock configuration (0x");
  Serial.print(RTC_CNTL_CLK_CONF_REG, HEX);                        // Read RTC Control Clock configuration (0x3FF48070) = 0x29580010
  Serial.print(") = 0x"); Serial.println (REG_READ(RTC_CNTL_CLK_CONF_REG), HEX);

  Serial.print("APLL Tick configuration (0x");
  Serial.print(SYSCON_APLL_TICK_CONF_REG, HEX);                    // Read APLL Tick configuration (0x3FF6603C) = 0x63
  Serial.print(") = 0x"); Serial.println (REG_READ(SYSCON_APLL_TICK_CONF_REG), HEX);

  Serial.print("RTC Optons0 control configuration (0x");
  Serial.print(RTC_CNTL_OPTIONS0_REG, HEX);                        // Read RTC Optons 0 control configuration (0x3FF48000) = 0x1C124000
  Serial.print(") = 0x"); Serial.println (REG_READ(RTC_CNTL_OPTIONS0_REG), HEX);
  Serial.println();
}

void rtcCntlAnaConfReg ()
{
  Serial.print("RTC power up/down configuration (0x");
  Serial.print(RTC_CNTL_ANA_CONF_REG, HEX);                        // Read RTC power up/down configuration (0x3FF48030)= 0x800000
  Serial.print(") = 0x"); Serial.println (REG_READ(RTC_CNTL_ANA_CONF_REG), HEX);
}

void enableAudioPLLClock ()
{
  Serial.println();
  rtcCntlAnaConfReg ();                                             // Read RTC power up/down configuration
  Serial.println("RTC PLLA power down");                            // Disable audio PLL clock
  RTCCNTL.ana_conf.plla_force_pd = 0;                               // RTC APLL power down
  rtcCntlAnaConfReg ();                                             // Read RTC power up/down configuration
  Serial.println("RTC PLLA power up");                              // Enable audio PLL clock
  RTCCNTL.ana_conf.plla_force_pu = 1;                               // RTC APLL power up
  rtcCntlAnaConfReg ();                                             // Read RTC power up/down configuration
}

void configAPLclock ()
{
  // apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
  // apll_freq = 40MHz * (4+4+0+0)/(0+2)*2 = 80 MHz
  // rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div)
    
  rtc_clk_apll_enable(1, 0, 0, 4, 0);                               // enable APLL clock 80 Mhz
}

void mclkClock ()
{
  // Enable I2S0 MCLK clock output at GPIO0 pin - ESP32 Tech Reference pag 70 and 71
  Serial.println();
  Serial.print("IO_MUX_PIN_CTRL ("); Serial.print(PIN_CTRL, HEX);                           // Clock output configuration register (0x3FF49000)
  Serial.print(") = 0x"); Serial.println (REG_READ(PIN_CTRL), HEX);                         // print register value = 0x3FF

  // PIN_FUNC_SELECT(PIN_CTRL, CLK_OUT1);                                                   // wrong function?
  REG_WRITE(PIN_CTRL, 0xFF0);                                                               // it works - Clock output 1 to I2S0 

  Serial.print("IO_MUX_PIN_CTRL ("); Serial.print(PIN_CTRL, HEX);                           // Clock output configuration register (0x3FF49000)
  Serial.print(") = 0x"); Serial.println (REG_READ(PIN_CTRL), HEX);                         // print register value = 0xFF0

  Serial.println();
  Serial.print("PERIPHS_IO_MUX_GPIO0_U ("); Serial.print(PERIPHS_IO_MUX_GPIO0_U, HEX);      // Configuration register for pad GPIO 0 (0x3FF49044)
  Serial.print(") = 0x"); Serial.println (REG_READ(PERIPHS_IO_MUX_GPIO0_U), HEX);           // print register value = 0xB00

  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);                             // Configuration register for pad GPIO0 => set function 2
  //PIN_INPUT_DISABLE(PERIPHS_IO_MUX_GPIO0_U);                                                // disable input at GPIO 0

  Serial.print("PERIPHS_IO_MUX_GPIO0_U ("); Serial.print(PERIPHS_IO_MUX_GPIO0_U, HEX);      // Configuration register for pad GPIO 0 (0x3FF49044)
  Serial.print(") = 0x"); Serial.println (REG_READ(PERIPHS_IO_MUX_GPIO0_U), HEX);           // print register value = 0x1B00
}

void mclkI2S0config ()
{
  periph_module_enable(PERIPH_I2S0_MODULE);                                                 // enable peripheral I2S0 module (essential)

  Serial.println();
  Serial.print("I2S0 Bit clock configuration (0x");                                         // print register name and address (0x3FF4F0AC)
  Serial.print(I2S_CLKM_CONF_REG(0), HEX);                                                  // Register I2S0 Bit clock configuration
  Serial.print(") = 0x"); Serial.println (REG_READ(I2S_CLKM_CONF_REG(0)), HEX);             // print register value = 0x4 (default)

  // Configure Bit Clock configuration - ESP32 Tech Reference page 308 and 337
  // fclk = fapll / (N + b/a) = 80 MHz / (8 +(0/1) = 10 MHz  (using APLL clock)

  I2S0.clkm_conf.clkm_div_num = 8;                                                          // I2S clock divider’s integral value
  I2S0.clkm_conf.clkm_div_b = 0;                                                            // Fractional clock divider’s numerator value
  I2S0.clkm_conf.clkm_div_a = 1;                                                            // Fractional clock divider’s denominator value
  I2S0.clkm_conf.clk_en = 1;                                                                // I2S clock enable
  I2S0.clkm_conf.clka_en = 1;                                                               // Set this bit to enable clk_apll

  Serial.print("I2S0 Bit clock configuration (0x");                                         // print register name and address (0x3FF4F0AC)
  Serial.print(I2S_CLKM_CONF_REG(0), HEX);                                                  // Register I2S0 Bit clock configuration
  Serial.print(") = 0x"); Serial.println (REG_READ(I2S_CLKM_CONF_REG(0)), HEX);             // print register value = 0x104008
}

void bckI2S0config ()
{
  Serial.println();                                                                         // ESP32 Tech Reference page 308
  Serial.print("I2S0 sample rate configuration (0x");                                       // print register name and address (0x3FF4F0B0)
  Serial.print(I2S_SAMPLE_RATE_CONF_REG(0), HEX);                                           // Register I2S0 sample rate configuration
  Serial.print(") = 0x"); Serial.println (REG_READ(I2S_SAMPLE_RATE_CONF_REG(0)), HEX);      // print register value = 0x410186 (default)

  I2S0.sample_rate_conf.tx_bck_div_num = 4;                                                 // TX BCK clock = MCLK / num
  I2S0.sample_rate_conf.rx_bck_div_num = 4;                                                 // RX BCK clock = MCLK / num

  Serial.print("I2S0 sample rate configuration (0x");                                       // print register name and address (0x3FF4F0B0)
  Serial.print(I2S_SAMPLE_RATE_CONF_REG(0), HEX);                                           // Register I2S0 sample rate configuration
  Serial.print(") = 0x"); Serial.println (REG_READ(I2S_SAMPLE_RATE_CONF_REG(0)), HEX);      // print register value = 0x410104
}

void loop()
{
  // put your main code here, to run repeatedly:
}
Last edited by jgustavoam on Tue Jun 16, 2020 2:12 am, edited 4 times in total.
Retired IBM Brasil
Electronic hobbyist since 1976.

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby jgustavoam » Sat Feb 08, 2020 10:11 pm

ESP32 serial console output (detailed information for better understanding):

Code: Select all

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:9720
ho 0 tail 12 room 4
load:0x40080400,len:6352
entry 0x400806b8

ESP32 - Chip Revision: 1
ESP32 - CPU frequency: 160
ESP32 - RTC Crystal Clock frequency = 40
ESP32 - RTC APB frequency: 80000000

RTC Control Clock configuration (0x3FF48070) = 0x29580010
APLL Tick configuration (0x3FF6603C) = 0x63
RTC Optons0 control configuration (0x3FF48000) = 0x1C124000


RTC power up/down configuration (0x3FF48030) = 0x800000
RTC PLLA power down
RTC power up/down configuration (0x3FF48030) = 0x0
RTC PLLA power up
RTC power up/down configuration (0x3FF48030) = 0x1000000

I2S0 Bit clock configuration (0x3FF4F0AC) = 0x4
I2S0 Bit clock configuration (0x3FF4F0AC) = 0x304008

I2S0 sample rate configuration (0x3FF4F0B0) = 0x410186
I2S0 sample rate configuration (0x3FF4F0B0) = 0x410104

IO_MUX_PIN_CTRL (3FF49000) = 0x3FF
IO_MUX_PIN_CTRL (3FF49000) = 0xFF0

PERIPHS_IO_MUX_GPIO0_U (3FF49044) = 0xB00
PERIPHS_IO_MUX_GPIO0_U (3FF49044) = 0x1900

Retired IBM Brasil
Electronic hobbyist since 1976.

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby jgustavoam » Sun Feb 09, 2020 1:26 pm

I included information about some ESP32 Registers used in this sample code.

ESP32 Estudos sobre I2S.xlsx
Excel Information about some ESP32 Registers
(21.02 KiB) Downloaded 1537 times
ESP32 I2S Sample rate config.JPG
ESP32 I2S Sample rate config.JPG (123.23 KiB) Viewed 66149 times
Retired IBM Brasil
Electronic hobbyist since 1976.

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby jgustavoam » Sun Jun 14, 2020 11:28 pm

Added some frequency calculations.

Code: Select all

/*  Project ESP32 Logic Analyzer     Testes com I2S Bit Clock
    ESP32 Dev Kit 38 pins - Arduino IDE 1.8.12 - ESP32 Arduino V1.0.4
    https://github.com/Gustavomurta/ESP32-Logic-analyzer
    Gustavo Murta and Rui Vianna - 14/jun/2020

    I2S0 MCLK pin = GPIO0 (derived from APLL Clock)
    
    using PLL_D2 clock - master clock up to 80 MHz
    using APLL clock - master clock up to 70 MHz
    I2S0.clkm_conf.clka_en >>> Set this bit to enable clk_apll or reset to enable PLL Clock!

    References:
    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/driver/driver/i2s.h
    https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-cpu.h

    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/rtc.h
    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/rtc_cntl_reg.h
    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/dport_reg.h
    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/rtc_cntl_struct.h

    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/syscon_reg.h
    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/syscon_struct.h

    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/periph_defs.h
    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/i2s_struct.h
    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/i2s_reg.h

    https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/soc/soc/io_mux_reg.h
*/

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

#include "soc/syscon_reg.h"
#include "soc/rtc_cntl_struct.h"

//#include "esp32-hal-cpu.h"
#include "driver/i2s.h"

float APL_CLK;
int sdm0, sdm1, sdm2, o_div;
float fclk;
float  div_num, div_b, div_a;

void setup()
{
  Serial.begin(115200);                         // IDE Console 115200 bps
  socDetails ();                                // system on a chip details
  apllClock ();                                 // Read RTC Control Clock configuration
  enableAudioPLLClock ();                       // power up audio PLL clock
  configAPLclock ();                            // enable APLL clock 80 Mhz
  mclkI2S0config ();                            // configure I2S0 MCLK clock
  bckI2S0config ();                             // configure I2S0 BCK  clock
  mclkClock ();                                 // configure GPIO0 to CLock OUT 1 - I2S MCLK
}

void socDetails ()
{
  Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
  Serial.println();
  Serial.print("ESP32 - Chip Revision: ");
  Serial.println(ESP.getChipRevision());                       // print ESP32 chip revision
  Serial.print("ESP32 - CPU frequency: ");
  Serial.println(ESP.getCpuFreqMHz());                         // print ESP32 cpu frequency
  Serial.print("ESP32 - RTC Crystal Clock frequency = ");
  Serial.println(rtc_clk_xtal_freq_get());                     // print ESP32 RTC Crystal Clock frequency      soc/rtc.h    40 MHz
  Serial.print("ESP32 - RTC APB frequency: ");
  Serial.println(rtc_clk_apb_freq_get());                      // print ESP32 RTC APB frequency                soc/rtc.h    80 MHz
  Serial.println();
}

void apllClock ()
{
  Serial.print("RTC Control Clock configuration (0x");
  Serial.print(RTC_CNTL_CLK_CONF_REG, HEX);                        // Read RTC Control Clock configuration (0x3FF48070) = 0x29580010
  Serial.print(") = 0x"); Serial.println (REG_READ(RTC_CNTL_CLK_CONF_REG), HEX);

  Serial.print("APLL Tick configuration (0x");
  Serial.print(SYSCON_APLL_TICK_CONF_REG, HEX);                    // Read APLL Tick configuration (0x3FF6603C) = 0x63
  Serial.print(") = 0x"); Serial.println (REG_READ(SYSCON_APLL_TICK_CONF_REG), HEX);

  Serial.print("RTC Optons0 control configuration (0x");
  Serial.print(RTC_CNTL_OPTIONS0_REG, HEX);                        // Read RTC Optons 0 control configuration (0x3FF48000) = 0x1C124000
  Serial.print(") = 0x"); Serial.println (REG_READ(RTC_CNTL_OPTIONS0_REG), HEX);
  Serial.println();
}

void rtcCntlAnaConfReg ()
{
  Serial.print("RTC power up/down configuration (0x");
  Serial.print(RTC_CNTL_ANA_CONF_REG, HEX);                        // Read RTC power up/down configuration (0x3FF48030)= 0x800000
  Serial.print(") = 0x"); Serial.println (REG_READ(RTC_CNTL_ANA_CONF_REG), HEX);
}

void enableAudioPLLClock ()
{
  rtcCntlAnaConfReg ();                                             // Read RTC power up/down configuration
  Serial.println("RTC PLLA power down");                            // Disable audio PLL clock
  RTCCNTL.ana_conf.plla_force_pd = 0;                               // RTC APLL power down
  rtcCntlAnaConfReg ();                                             // Read RTC power up/down configuration
  Serial.println("RTC PLLA power up");                              // Enable audio PLL clock
  RTCCNTL.ana_conf.plla_force_pu = 1;                               // RTC APLL power up
  rtcCntlAnaConfReg ();                                             // Read RTC power up/down configuration
}

void configAPLclock ()
{

  // @param sdm0  frequency adjustment parameter, 0..255
  // @param sdm1  frequency adjustment parameter, 0..255
  // @param sdm2  frequency adjustment parameter, 0..63 max = 10
  // @param o_div  frequency divider, 0..31
  // The dividend in this expression should be in the range of 240 and 560 MHz - tested 

  // apll_freq = xtal_freq * (4 + sdm0/65536 + sdm1/256 + sdm2)/((o_div + 2) * 2)
  // rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1,uint32_t sdm2, uint32_t o_div);

  // apll_freq = 40MHz * (4+0+0+6)/(0+2)*2
  // apll_freq = 40 * 10 / 4 = 100 MHz          // enable APLL clock 100 Mhz

  sdm0 = 0; sdm1 = 0; sdm2 = 10; o_div = 0;
  rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, o_div);                               // enable APLL clock 

  APL_CLK = 40 * (4 + (sdm0 / 65536) + (sdm1 / 256) + sdm2) / (2 * (o_div + 2));
  Serial.println();
  Serial.print ("APL_CLK =  "); Serial.print (APL_CLK, 3); Serial.println (" MHz");
}

void mclkClock ()
{
  // Enable I2S0 MCLK clock output at GPIO0 pin - ESP32 Tech Reference pag 70 and 71
  Serial.println();
  Serial.print("IO_MUX_PIN_CTRL ("); Serial.print(PIN_CTRL, HEX);                           // Clock output configuration register (0x3FF49000)
  Serial.print(") = 0x"); Serial.println (REG_READ(PIN_CTRL), HEX);                         // print register value = 0x3FF

  // PIN_FUNC_SELECT(PIN_CTRL, CLK_OUT1);                                                   // wrong function?
  REG_WRITE(PIN_CTRL, 0xFF0);                                                               // it works - Clock output 1 to I2S0

  Serial.print("IO_MUX_PIN_CTRL ("); Serial.print(PIN_CTRL, HEX);                           // Clock output configuration register (0x3FF49000)
  Serial.print(") = 0x"); Serial.print (REG_READ(PIN_CTRL), HEX);                           // print register value = 0xFF0
  Serial.println(" after configuration");

  Serial.println();
  Serial.print("PERIPHS_IO_MUX_GPIO0_U ("); Serial.print(PERIPHS_IO_MUX_GPIO0_U, HEX);      // Configuration register for pad GPIO 0 (0x3FF49044)
  Serial.print(") = 0x"); Serial.println (REG_READ(PERIPHS_IO_MUX_GPIO0_U), HEX);           // print register value = 0xB00

  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);                             // Configuration register for pad GPIO0 => set function 2
  PIN_INPUT_DISABLE(PERIPHS_IO_MUX_GPIO0_U);                                                // disable input at GPIO 0

  Serial.print("PERIPHS_IO_MUX_GPIO0_U ("); Serial.print(PERIPHS_IO_MUX_GPIO0_U, HEX);      // Configuration register for pad GPIO 0 (0x3FF49044)
  Serial.print(") = 0x"); Serial.print (REG_READ(PERIPHS_IO_MUX_GPIO0_U), HEX);             // print register value = 0x1B00
  Serial.println(" after configuration");
}

void mclkI2S0config ()
{
  periph_module_enable(PERIPH_I2S0_MODULE);                                                 // enable peripheral I2S0 module (essential)

  Serial.println();
  Serial.print("I2S0 Bit clock configuration (0x");                                         // print register name and address (0x3FF4F0AC)
  Serial.print(I2S_CLKM_CONF_REG(0), HEX);                                                  // Register I2S0 Bit clock configuration
  Serial.print(") = 0x"); Serial.println (REG_READ(I2S_CLKM_CONF_REG(0)), HEX);             // print register value = 0x4 (default)

  div_num = 2; div_b = 0; div_a = 1;

  I2S0.clkm_conf.clkm_div_num = div_num;                                                    // I2S clock divider’s integral value >= 2
  I2S0.clkm_conf.clkm_div_b = div_b;                                                        // Fractional clock divider’s numerator value
  I2S0.clkm_conf.clkm_div_a = div_a;                                                        // Fractional clock divider’s denominator value
  I2S0.clkm_conf.clk_en = 1;                                                                // I2S clock enable
  I2S0.clkm_conf.clka_en = 1;                                                               // Set this bit to enable clk_apll

  // Configure Bit Clock configuration - ESP32 Tech Reference page 308 and 337
  // fclk = fapll / (N + b/a)
  // fclk = 100 MHz / (2 +(0/1) = 50 MHz  (using APLL clock)

  fclk = APL_CLK / ( div_num + ( div_b / div_a));
  Serial.print("I2S0 master clock = "); Serial.print(fclk, 3); Serial.println (" MHz");
  Serial.println();

  Serial.print("I2S0 Bit clock configuration (0x");                                         // print register name and address (0x3FF4F0AC)
  Serial.print(I2S_CLKM_CONF_REG(0), HEX);                                                  // Register I2S0 Bit clock configuration
  Serial.print(") = 0x"); Serial.print (REG_READ(I2S_CLKM_CONF_REG(0)), HEX);               // print register value = 0x104008
  Serial.println(" after configuration");
}

void bckI2S0config ()
{
  Serial.println();                                                                         // ESP32 Tech Reference page 308
  Serial.print("I2S0 sample rate configuration (0x");                                       // print register name and address (0x3FF4F0B0)
  Serial.print(I2S_SAMPLE_RATE_CONF_REG(0), HEX);                                           // Register I2S0 sample rate configuration
  Serial.print(") = 0x"); Serial.println (REG_READ(I2S_SAMPLE_RATE_CONF_REG(0)), HEX);      // print register value = 0x410186 (default)

  I2S0.sample_rate_conf.tx_bck_div_num = 4;                                                 // TX BCK clock = MCLK / num
  I2S0.sample_rate_conf.rx_bck_div_num = 4;                                                 // RX BCK clock = MCLK / num

  Serial.print("I2S0 sample rate configuration (0x");                                       // print register name and address (0x3FF4F0B0)
  Serial.print(I2S_SAMPLE_RATE_CONF_REG(0), HEX);                                           // Register I2S0 sample rate configuration
  Serial.print(") = 0x"); Serial.print (REG_READ(I2S_SAMPLE_RATE_CONF_REG(0)), HEX);        // print register value = 0x410104
  Serial.println(" after configuration");
}

void loop()
{
  // put your main code here, to run repeatedly:
}
Last edited by jgustavoam on Tue Jun 16, 2020 2:17 am, edited 2 times in total.
Retired IBM Brasil
Electronic hobbyist since 1976.

User avatar
Jakobsen
Posts: 89
Joined: Mon Jan 16, 2017 8:12 am

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby Jakobsen » Mon Jun 15, 2020 7:44 am

Will take closer look in to you finding tonight - I need a to find a way to fine tune the APLL with out stopping the clock.
Until now i just found that the APLL control looks like some IP hooked up on internal I2C - with SW interface through ESP-IDF stack. Happy to find if you work can get me further. /J
Analog Digital IC designer / DevOps @ Merus Audio, Copenhagen, Denmark.
We do novel and best in class Audio amplifiers for consumer products.
Programmed assembler for C-64 back in 1980's, learned some electronics - hacking since then

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby jgustavoam » Mon Jun 15, 2020 12:34 pm

Hi Jacobsen,
" APLL control looks like some IP hooked up on internal I2C "
You are wrong. APLL clock is configured by dividers that controlled by registers. Only that.
I think it is possible to fine adjust frequency on the fly. But I don't know if it is real.
You will certainly have some jitters when you are changing frequency.
You can test using functions of my program.
Retired IBM Brasil
Electronic hobbyist since 1976.

User avatar
Jakobsen
Posts: 89
Joined: Mon Jan 16, 2017 8:12 am

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby Jakobsen » Mon Jun 15, 2020 10:18 pm

Hi Gustavo
Thanks - I took the time and hacked around with the APLL - the most low level I got was the the call to enable_apll(sdm0, sdm1 ... )
And yes you are right it can be done realtime will out audible effects - I am very happy. This will be next phase of synchronized multi channel audio streaming.

Code: Select all

(480281) I2S: Chunk :960 191040 191520, 48301.133 , 211
I (481281) I2S: Chunk :960 191232 191712, 48301.219 , 212
I (482281) I2S: Chunk :960 191424 191904, 48301.305 , 213
I (483281) I2S: Chunk :960 191616 192096, 48301.387 , 214
I (484281) I2S: Chunk :960 191808 192288, 48301.473 , 215
I (485281) I2S: Chunk :960 192000 191460, 48301.562 , 216
I (486271) I2S: Chunk :960 192192 191472, 48301.648 , 217
I (487271) I2S: Chunk :960 192384 191904, 48301.730 , 218
I (488271) I2S: Chunk :960 192576 192096, 48301.816 , 219
I (489271) I2S: Chunk :960 192768 192279, 48301.902 , 220
I (490271) I2S: Chunk :960 192960 191616, 48301.988 , 221
I (491271) I2S: Chunk :960 193152 191673, 48302.070 , 222
I (492271) I2S: Chunk :960 193344 191850, 48302.156 , 223
I (493271) I2S: Chunk :960 193536 192027, 48324.039 , 224
I (493521) SNAPCAST: SNTP diff us: 800658 , 801266 
I (493521) SNAPCAST: SNTP diff us: -0.61
I (494271) I2S: Chunk :960 193728 192204, 48324.125 , 225
I (495271) I2S: Chunk :960 190080 191901, 48324.211 , 226
I (496271) I2S: Chunk :960 190272 191598, 48324.293 , 227
I (497271) I2S: Chunk :960 190464 191775, 48324.379 , 228
I (498271) I2S: Chunk :960 190656 191952, 48324.465 , 229
I (499271) I2S: Chunk :960 190848 192129, 48324.551 , 230
Regards Jakobsen
Analog Digital IC designer / DevOps @ Merus Audio, Copenhagen, Denmark.
We do novel and best in class Audio amplifiers for consumer products.
Programmed assembler for C-64 back in 1980's, learned some electronics - hacking since then

User avatar
jgustavoam
Posts: 165
Joined: Thu Feb 01, 2018 2:43 pm
Location: Belo Horizonte , Brazil
Contact:

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby jgustavoam » Mon Jun 15, 2020 10:42 pm

Hi Jakobsen,
I'm glad if my experiments helped you.

Commodore 64 was my first computer! I have C64 and C128 until today! :D
Regards,
Gustavo
Retired IBM Brasil
Electronic hobbyist since 1976.

ayrtonestrella
Posts: 1
Joined: Fri Aug 27, 2021 9:07 pm

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby ayrtonestrella » Fri Aug 27, 2021 9:27 pm

Hi jgustavoam!
I found your post based on https://github.com/YetAnotherElectronic ... _I2S_SETUP
I'm still trying to understand the technical documentation, but I have the following situation:

I'm using both I2S0 and I2S1. And I seem to understand how the CLK_OUT1 is redirected to GPIO0.
CLK_OUT1, then set PIN_CTRL[3:0] = 0x0;
That's where this comes from: REG_WRITE(PIN_CTRL, 0xFF0);

That would solve the MCLK for the I2S0, but to configure the MCLK of the I2S1 to the CLK_OUT3 (GPIO1), it says this:
CLK_OUT3, then set PIN_CTRL[3:0] = 0xF and PIN_CTRL[11:8] = 0x0. (R/W)

But, this seems to change the value of the PIN_CTRL like this: REG_WRITE(PIN_CTRL, 0x0FF);

My question is: how would the configuration would look like in order to set this:
I2S0 -> CLK_OUT1 -> GPIO0
I2S1 -> CLK_OUT3 -> GPIO3


I imagine that it would look something like this:

Code: Select all

/*
    If you want to output clock for I2S0 to:
    CLK_OUT1, then set PIN_CTRL[3:0] = 0x0;
    CLK_OUT2, then set PIN_CTRL[3:0] = 0x0 and PIN_CTRL[7:4] = 0x0; 
    CLK_OUT3, then set PIN_CTRL[3:0] = 0x0 and PIN_CTRL[11:8] = 0x0.
  */
  // I2S0 -> CLK_OUT1 -> GPIO0
REG_WRITE(PIN_CTRL, 0xFF0);                                       
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);

  /*
    If you want to output clock for I2S1 to:
    CLK_OUT1, then set PIN_CTRL[3:0] = 0xF;
    CLK_OUT2, then set PIN_CTRL[3:0] = 0xF and PIN_CTRL[7:4] = 0x0; 
    CLK_OUT3, then set PIN_CTRL[3:0] = 0xF and PIN_CTRL[11:8] = 0x0. (R/W)
  */
// I2S1 -> CLK_OUT3 -> GPIO1
REG_WRITE(PIN_CTRL, 0x0FF);                                       
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3);

User avatar
fasani
Posts: 197
Joined: Wed Jan 30, 2019 12:00 pm
Location: Barcelona
Contact:

Re: I2S0 Clock (master clock) up to 80MHz derived from APLL clock

Postby fasani » Sat Sep 11, 2021 6:00 pm

Very interesting Gustavo,
Bookmarking this. I have to try it soon!
Thanks for your sharing it.
epdiy collaborator | http://fasani.de Fan of Espressif MCUs and electronic design

Who is online

Users browsing this forum: No registered users and 31 guests