I2S0 Clock (master clock) up to 80MHz derived from APLL clock
Posted: 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
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
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:
}