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

User avatar
jgustavoam
Posts: 43
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 64 MHz

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 Sat Feb 08, 2020 10:45 pm, edited 2 times in total.
Retired IBM Brasil
Electronic hobbyist since 1976.

User avatar
jgustavoam
Posts: 43
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: 43
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 27 times
ESP32 I2S Sample rate config.JPG
ESP32 I2S Sample rate config.JPG (123.23 KiB) Viewed 1637 times
Retired IBM Brasil
Electronic hobbyist since 1976.

Who is online

Users browsing this forum: No registered users and 20 guests