Created
February 26, 2021 06:23
-
-
Save kargeor/b4200fc859a8e6c2234701368c82acd2 to your computer and use it in GitHub Desktop.
Using the APLL clock source to output DMA parallel output from I2S1 at greater than 20Mhz bitrate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Source: https://www.esp32.com/viewtopic.php?t=14185 | |
/* 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 | |
I2S1 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 | |
I2S1.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 | |
mclkI2S1config (); // configure I2S1 MCLK clock | |
bckI2S1config (); // configure I2S1 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 OptonS1 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 = 4; 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 I2S1 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 I2S1 | |
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 mclkI2S1config () | |
{ | |
periph_module_enable(PERIPH_I2S1_MODULE); // enable peripheral I2S1 module (essential) | |
Serial.println(); | |
Serial.print("I2S1 Bit clock configuration (0x"); // print register name and address (0x3FF4F0AC) | |
Serial.print(I2S_CLKM_CONF_REG(0), HEX); // Register I2S1 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; | |
I2S1.clkm_conf.clkm_div_num = div_num; // I2S clock divider’s integral value >= 2 | |
I2S1.clkm_conf.clkm_div_b = div_b; // Fractional clock divider’s numerator value | |
I2S1.clkm_conf.clkm_div_a = div_a; // Fractional clock divider’s denominator value | |
I2S1.clkm_conf.clk_en = 1; // I2S clock enable | |
I2S1.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("I2S1 master clock = "); Serial.print(fclk, 3); Serial.println (" MHz"); | |
Serial.println(); | |
Serial.print("I2S1 Bit clock configuration (0x"); // print register name and address (0x3FF4F0AC) | |
Serial.print(I2S_CLKM_CONF_REG(0), HEX); // Register I2S1 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 bckI2S1config () | |
{ | |
Serial.println(); // ESP32 Tech Reference page 308 | |
Serial.print("I2S1 sample rate configuration (0x"); // print register name and address (0x3FF4F0B0) | |
Serial.print(I2S_SAMPLE_RATE_CONF_REG(0), HEX); // Register I2S1 sample rate configuration | |
Serial.print(") = 0x"); Serial.println (REG_READ(I2S_SAMPLE_RATE_CONF_REG(0)), HEX); // print register value = 0x410186 (default) | |
I2S1.sample_rate_conf.tx_bck_div_num = 4; // TX BCK clock = MCLK / num | |
I2S1.sample_rate_conf.rx_bck_div_num = 4; // RX BCK clock = MCLK / num | |
Serial.print("I2S1 sample rate configuration (0x"); // print register name and address (0x3FF4F0B0) | |
Serial.print(I2S_SAMPLE_RATE_CONF_REG(0), HEX); // Register I2S1 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: | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment