Merge branch 'bugfix/apll_coeff_calculate' into 'master'

i2s: impove the clock division calculation

Closes IDFGH-6283

See merge request espressif/esp-idf!16095
This commit is contained in:
Kevin (Lao Kaiyao) 2021-12-29 09:35:13 +00:00
commit 952b4d848f
22 changed files with 469 additions and 380 deletions

View File

@ -29,8 +29,7 @@
#include "esp_private/gdma.h"
#endif
#include "soc/rtc.h"
#include "soc/clk_ctrl_os.h"
#include "esp_intr_alloc.h"
#include "esp_err.h"
#include "esp_check.h"
@ -916,124 +915,6 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num)
/*-------------------------------------------------------------
I2S clock operation
-------------------------------------------------------------*/
#if SOC_I2S_SUPPORTS_APLL
/**
* @brief Get APLL frequency
*/
static float i2s_apll_get_freq(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir)
{
int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000;
#if CONFIG_IDF_TARGET_ESP32
/* ESP32 rev0 silicon issue for APLL range/accuracy, please see ESP32 ECO document for more information on this */
if (esp_efuse_get_chip_ver() == 0) {
sdm0 = 0;
sdm1 = 0;
}
#endif
float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4);
if (fout < SOC_I2S_APLL_MIN_FREQ || fout > SOC_I2S_APLL_MAX_FREQ) {
return SOC_I2S_APLL_MAX_FREQ;
}
float fpll = fout / (2 * (odir + 2)); //== fi2s (N=1, b=0, a=1)
return fpll / 2;
}
/**
* @brief APLL calculate function, was described by following:
* APLL Output frequency is given by the formula:
*
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
* apll_freq = fout / ((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 - 600 MHz.
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
* * sdm0 frequency adjustment parameter, 0..255
* * sdm1 frequency adjustment parameter, 0..255
* * sdm2 frequency adjustment parameter, 0..63
* * o_div frequency divider, 0..31
*
* The most accurate way to find the sdm0..2 and odir parameters is to loop through them all,
* then apply the above formula, finding the closest frequency to the desired one.
* But 256*256*64*32 = 134,217,728 loops are too slow with ESP32
* 1. We will choose the parameters with the highest level of change,
* With 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9,
* Take average frequency close to the desired frequency, and select sdm2
* 2. Next, we look for sequences of less influential and more detailed parameters,
* also by taking the average of the largest and smallest frequencies closer to the desired frequency.
* 3. And finally, loop through all the most detailed of the parameters, finding the best desired frequency
*
* @param[in] rate The I2S Frequency (MCLK)
* @param[in] bits_per_sample The bits per sample
* @param[out] sdm0 The sdm 0
* @param[out] sdm1 The sdm 1
* @param[out] sdm2 The sdm 2
* @param[out] odir The odir
*/
static void i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir)
{
int _odir, _sdm0, _sdm1, _sdm2;
float avg;
float min_rate, max_rate, min_diff;
*sdm0 = 0;
*sdm1 = 0;
*sdm2 = 0;
*odir = 0;
min_diff = SOC_I2S_APLL_MAX_FREQ;
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
max_rate = i2s_apll_get_freq(bits_per_sample, 255, 255, _sdm2, 0);
min_rate = i2s_apll_get_freq(bits_per_sample, 0, 0, _sdm2, 31);
avg = (max_rate + min_rate) / 2;
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm2 = _sdm2;
}
}
min_diff = SOC_I2S_APLL_MAX_FREQ;
for (_odir = 0; _odir < 32; _odir ++) {
max_rate = i2s_apll_get_freq(bits_per_sample, 255, 255, *sdm2, _odir);
min_rate = i2s_apll_get_freq(bits_per_sample, 0, 0, *sdm2, _odir);
avg = (max_rate + min_rate) / 2;
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*odir = _odir;
}
}
min_diff = SOC_I2S_APLL_MAX_FREQ;
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
max_rate = i2s_apll_get_freq(bits_per_sample, 255, 255, _sdm2, *odir);
min_rate = i2s_apll_get_freq(bits_per_sample, 0, 0, _sdm2, *odir);
avg = (max_rate + min_rate) / 2;
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm2 = _sdm2;
}
}
min_diff = SOC_I2S_APLL_MAX_FREQ;
for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) {
max_rate = i2s_apll_get_freq(bits_per_sample, 255, _sdm1, *sdm2, *odir);
min_rate = i2s_apll_get_freq(bits_per_sample, 0, _sdm1, *sdm2, *odir);
avg = (max_rate + min_rate) / 2;
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm1 = _sdm1;
}
}
min_diff = SOC_I2S_APLL_MAX_FREQ;
for (_sdm0 = 0; _sdm0 < 256; _sdm0 ++) {
avg = i2s_apll_get_freq(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir);
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm0 = _sdm0;
}
}
}
#endif
/**
* @brief Config I2S source clock and get its frequency
*
@ -1049,21 +930,29 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
{
#if SOC_I2S_SUPPORTS_APLL
if (use_apll) {
int sdm0 = 0;
int sdm1 = 0;
int sdm2 = 0;
int odir = 0;
if ((mclk / p_i2s[i2s_num]->hal_cfg.chan_bits / p_i2s[i2s_num]->hal_cfg.total_chan) < SOC_I2S_APLL_MIN_RATE) {
ESP_LOGE(TAG, "mclk is too small");
/* Calculate the expected APLL */
int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1);
/* apll_freq = mclk * div
* when div = 1, hardware will still divide 2
* when div = 0, the final mclk will be unpredictable
* So the div here should be at least 2 */
div = div < 2 ? 2 : div;
uint32_t expt_freq = mclk * div;
/* Set APLL coefficients to the given frequency */
uint32_t real_freq = 0;
esp_err_t ret = periph_rtc_apll_freq_set(expt_freq, &real_freq);
if (ret == ESP_ERR_INVALID_ARG) {
ESP_LOGE(TAG, "set APLL coefficients failed");
return 0;
}
i2s_apll_calculate_fi2s(mclk, p_i2s[i2s_num]->hal_cfg.sample_bits, &sdm0, &sdm1, &sdm2, &odir);
ESP_LOGI(TAG, "APLL Enabled, coefficient: sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir);
rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, odir);
if (ret == ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "APLL is occupied already, it is working at %d Hz", real_freq);
}
ESP_LOGI(TAG, "APLL expected frequency is %d Hz, real frequency is %d Hz", expt_freq, real_freq);
/* Set I2S_APLL as I2S module clock source */
i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_APLL);
/* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */
return 0;
return real_freq;
}
/* Set I2S_D2CLK (160M) as default I2S module clock source */
i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_D2CLK);
@ -1108,7 +997,7 @@ static esp_err_t i2s_calculate_adc_dac_clock(int i2s_num, i2s_hal_clock_cfg_t *c
clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk;
/* Check if the configuration is correct */
ESP_RETURN_ON_FALSE(!clk_cfg->sclk || clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
return ESP_OK;
}
@ -1146,7 +1035,7 @@ static esp_err_t i2s_calculate_pdm_tx_clock(int i2s_num, i2s_hal_clock_cfg_t *cl
clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk;
/* Check if the configuration is correct */
ESP_RETURN_ON_FALSE(!clk_cfg->sclk || clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
return ESP_OK;
}
@ -1184,7 +1073,7 @@ static esp_err_t i2s_calculate_pdm_rx_clock(int i2s_num, i2s_hal_clock_cfg_t *cl
clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk;
/* Check if the configuration is correct */
ESP_RETURN_ON_FALSE(!clk_cfg->sclk || clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
return ESP_OK;
}
@ -1240,7 +1129,7 @@ static esp_err_t i2s_calculate_common_clock(int i2s_num, i2s_hal_clock_cfg_t *cl
clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk;
/* Check if the configuration is correct */
ESP_RETURN_ON_FALSE(!clk_cfg->sclk || clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
ESP_RETURN_ON_FALSE(clk_cfg->mclk <= clk_cfg->sclk, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
return ESP_OK;
}
@ -2003,6 +1892,13 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
pre_alloc_i2s_obj->i2s_queue = NULL;
}
#if SOC_I2S_SUPPORTS_APLL
/* Power up APLL clock */
if (i2s_config->use_apll) {
periph_rtc_apll_acquire();
}
#endif
/* Step 7: Set I2S clocks and start. No need to give parameters since configurations has been set in 'i2s_driver_init' */
ESP_GOTO_ON_ERROR(i2s_set_clk(i2s_num, 0, 0, 0), err, TAG, "I2S set clock failed");
return ESP_OK;
@ -2057,7 +1953,7 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
if (p_i2s[i2s_num]->use_apll) {
// switch back to PLL clock source
i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_D2CLK);
rtc_clk_apll_enable(0, 0, 0, 0, 0);
periph_rtc_apll_release();
}
#endif

View File

@ -1,7 +1,7 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/**

View File

@ -24,7 +24,7 @@
#include "hal/emac_hal.h"
#include "hal/gpio_hal.h"
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/clk_ctrl_os.h"
#include "sdkconfig.h"
#include "esp_rom_gpio.h"
#include "esp_rom_sys.h"
@ -56,6 +56,7 @@ typedef struct {
bool isr_need_yield;
bool flow_ctrl_enabled; // indicates whether the user want to do flow control
bool do_flow_ctrl; // indicates whether we need to do software flow control
bool use_apll; // Only use APLL in EMAC_DATA_INTERFACE_RMII && EMAC_CLK_OUT
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
@ -299,30 +300,20 @@ static void emac_esp32_init_smi_gpio(emac_esp32_t *emac)
}
}
static void emac_config_apll_clock(void)
static esp_err_t emac_config_apll_clock(void)
{
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get();
switch (rtc_xtal_freq) {
case RTC_XTAL_FREQ_40M: // Recommended
/* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */
/* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */
rtc_clk_apll_enable(true, 0, 0, 6, 2);
break;
case RTC_XTAL_FREQ_26M:
/* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */
/* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */
rtc_clk_apll_enable(true, 39, 118, 15, 3);
break;
case RTC_XTAL_FREQ_24M:
/* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */
/* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */
rtc_clk_apll_enable(true, 255, 255, 12, 2);
break;
default: // Assume we have a 40M xtal
rtc_clk_apll_enable(true, 0, 0, 6, 2);
break;
uint32_t expt_freq = 50000000; // 50MHz
uint32_t real_freq = 0;
esp_err_t ret = periph_rtc_apll_freq_set(expt_freq, &real_freq);
ESP_RETURN_ON_FALSE(ret != ESP_ERR_INVALID_ARG, ESP_FAIL, TAG, "Set APLL clock coefficients failed");
if (ret == ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "APLL is occupied already, it is working at %d Hz", real_freq);
}
// If the difference of real APLL frequency is not within 50 ppm, i.e. 2500 Hz, the APLL is unavailable
ESP_RETURN_ON_FALSE(abs(real_freq - expt_freq) <= 2500,
ESP_ERR_INVALID_STATE, TAG, "The APLL is working at an unusable frequency");
return ESP_OK;
}
static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
@ -429,6 +420,9 @@ static void esp_emac_free_driver_obj(emac_esp32_t *emac, void *descriptors)
if (emac->intr_hdl) {
esp_intr_free(emac->intr_hdl);
}
if (emac->use_apll) {
periph_rtc_apll_release();
}
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac->tx_buf[i]);
}
@ -546,7 +540,10 @@ static esp_err_t esp_emac_config_data_interface(const eth_mac_config_t *config,
}
/* Enable RMII clock */
emac_ll_clock_enable_rmii_output(emac->hal.ext_regs);
emac_config_apll_clock();
// Power up APLL clock
periph_rtc_apll_acquire();
ESP_GOTO_ON_ERROR(emac_config_apll_clock(), err, TAG, "Configure APLL for RMII failed");
emac->use_apll = true;
} else {
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC clock mode");
}
@ -589,6 +586,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num;
emac->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK;
emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK;
emac->use_apll = false;
emac->parent.set_mediator = emac_esp32_set_mediator;
emac->parent.init = emac_esp32_init;
emac->parent.deinit = emac_esp32_deinit;

View File

@ -6,6 +6,7 @@
#include <freertos/FreeRTOS.h>
#include "soc/clk_ctrl_os.h"
#include "esp_check.h"
#include "sdkconfig.h"
#define DELAY_RTC_CLK_SWITCH 5
@ -14,6 +15,13 @@ static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED;
static uint8_t s_periph_ref_counts = 0;
static uint32_t s_rtc_clk_freq = 0; // Frequency of the 8M/256 clock in Hz
#if SOC_CLK_APLL_SUPPORTED
static const char *TAG = "clk_ctrl_os";
// Current APLL frequency, in HZ. Zero if APLL is not enabled.
static uint32_t s_cur_apll_freq = 0;
static int s_apll_ref_cnt = 0;
#endif
bool periph_rtc_dig_clk8m_enable(void)
{
@ -51,3 +59,65 @@ void periph_rtc_dig_clk8m_disable(void)
}
portEXIT_CRITICAL(&periph_spinlock);
}
#if SOC_CLK_APLL_SUPPORTED
void periph_rtc_apll_acquire(void)
{
portENTER_CRITICAL(&periph_spinlock);
s_apll_ref_cnt++;
if (s_apll_ref_cnt == 1) {
// For the first time enable APLL, need to set power up
rtc_clk_apll_enable(true);
}
portEXIT_CRITICAL(&periph_spinlock);
}
void periph_rtc_apll_release(void)
{
portENTER_CRITICAL(&periph_spinlock);
assert(s_apll_ref_cnt > 0);
s_apll_ref_cnt--;
if (s_apll_ref_cnt == 0) {
// If there is no peripheral using APLL, shut down the power
s_cur_apll_freq = 0;
rtc_clk_apll_enable(false);
}
portEXIT_CRITICAL(&periph_spinlock);
}
esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq)
{
uint32_t o_div = 0;
uint32_t sdm0 = 0;
uint32_t sdm1 = 0;
uint32_t sdm2 = 0;
// Guarantee 'periph_rtc_apll_acquire' has been called before set apll freq
assert(s_apll_ref_cnt > 0);
uint32_t apll_freq = rtc_clk_apll_coeff_calc(expt_freq, &o_div, &sdm0, &sdm1, &sdm2);
ESP_RETURN_ON_FALSE(apll_freq, ESP_ERR_INVALID_ARG, TAG, "APLL coefficients calculate failed");
bool need_config = true;
portENTER_CRITICAL(&periph_spinlock);
/* If APLL is not in use or only one peripheral in use, its frequency can be changed as will
* But when more than one peripheral refers APLL, its frequency is not allowed to change once it is set */
if (s_cur_apll_freq == 0 || s_apll_ref_cnt < 2) {
s_cur_apll_freq = apll_freq;
} else {
apll_freq = s_cur_apll_freq;
need_config = false;
}
portEXIT_CRITICAL(&periph_spinlock);
*real_freq = apll_freq;
if (need_config) {
ESP_LOGD(TAG, "APLL will working at %d Hz with coefficients [sdm0] %d [sdm1] %d [sdm2] %d [o_div] %d",
apll_freq, sdm0, sdm1, sdm2, o_div);
/* Set coefficients for APLL, notice that it doesn't mean APLL will start */
rtc_clk_apll_coeff_set(o_div, sdm0, sdm1, sdm2);
} else {
return ESP_ERR_INVALID_STATE;
}
return ESP_OK;
}
#endif // SOC_I2S_SUPPORTS_APLL

View File

@ -5,6 +5,7 @@
*/
#include "soc/rtc.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
@ -37,6 +38,39 @@ void periph_rtc_dig_clk8m_disable(void);
*/
uint32_t periph_rtc_dig_clk8m_get_freq(void);
#if SOC_CLK_APLL_SUPPORTED
/**
* @brief Enable APLL power if it has not enabled
*/
void periph_rtc_apll_acquire(void);
/**
* @brief Shut down APLL power if no peripherals using APLL
*/
void periph_rtc_apll_release(void);
/**
* @brief Calculate and set APLL coefficients by given frequency
* @note Have to call 'periph_rtc_apll_acquire' to enable APLL power before setting frequency
* @note This calculation is based on the inequality:
* xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= SOC_APLL_MULTIPLIER_OUT_MIN_HZ(350 MHz)
* It will always calculate the minimum coefficients that can satisfy the inequality above, instead of loop them one by one.
* which means more appropriate coefficients are likely to exist.
* But this algorithm can meet almost all the cases and the accuracy can be guaranteed as well.
* @note The APLL frequency is only allowed to set when there is only one peripheral refer to it.
* If APLL is already set by another peripheral, this function will return `ESP_ERR_INVALID_STATE`
* and output the current frequency by parameter `real_freq`.
*
* @param expt_freq Expected APLL frequency (unit: Hz)
* @param real_freq APLL real working frequency [output] (unit: Hz)
* @return
* - ESP_OK: APLL frequency set success
* - ESP_ERR_INVALID_ARG: The input expt_freq is out of APLL support range
* - ESP_ERR_INVALID_STATE: APLL is refered by more than one peripherals, not allowed to change its frequency now
*/
esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq);
#endif // SOC_CLK_APLL_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@ -12,7 +12,7 @@
*
* This file lists register fields of APLL, located on an internal configuration
* bus. These definitions are used via macros defined in regi2c_ctrl.h, by
* rtc_clk_apll_enable function in rtc_clk.c.
* rtc_clk_apll_freq_set and rtc_clk_apll_enable function in rtc_clk.c.
*/
#define I2C_APLL 0X6D

View File

@ -15,6 +15,7 @@
#include "soc/rtc.h"
#include "soc/rtc_periph.h"
#include "soc/sens_periph.h"
#include "soc/soc_caps.h"
#include "soc/dport_reg.h"
#include "soc/efuse_periph.h"
#include "soc/syscon_reg.h"
@ -268,7 +269,7 @@ bool rtc_clk_8md256_enabled(void)
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
}
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div)
void rtc_clk_apll_enable(bool enable)
{
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD, enable ? 0 : 1);
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU, enable ? 1 : 0);
@ -279,32 +280,92 @@ void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm
} else {
REG_CLR_BIT(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FORCE_PD);
}
}
if (enable) {
uint8_t sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV1;
uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0);
if (is_rev0) {
sdm0 = 0;
sdm1 = 0;
sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV0;
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
{
uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
if (rtc_xtal_freq == 0) {
// xtal_freq has not set yet
SOC_LOGE(TAG, "Get xtal clock frequency failed, it has not been set yet");
abort();
}
/* Reference formula: apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) / ((o_div + 2) * 2)
* ---------------------------------------------- -----------------
* 350 MHz <= Numerator <= 500 MHz Denominator
*/
int o_div = 0; // range: 0~31
int sdm0 = 0; // range: 0~255
int sdm1 = 0; // range: 0~255
int sdm2 = 0; // range: 0~63
/* Firstly try to satisfy the condition that the operation frequency of numerator should be greater than 350 MHz,
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value.
* With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is
* 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2;
if (o_div > 31) {
SOC_LOGE(TAG, "Expected frequency is too small");
return 0;
}
if (o_div < 0) {
/* Try to satisfy the condition that the operation frequency of numerator should be smaller than 500 MHz,
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code.
* With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is
* 500 MHz / ((0 + 2) * 2) = 125000000 Hz */
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2;
if (o_div < 0) {
SOC_LOGE(TAG, "Expected frequency is too big");
return 0;
}
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, sdm_stop_val_2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
}
// sdm2 = (int)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
sdm2 = (int)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * 1000000)) - 4;
// numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2
float numrator = (((o_div + 2) * 2 * freq) / ((float)rtc_xtal_freq * 1000000)) - 4 - sdm2;
// If numrator is bigger than 255/256 + 255/65536 + (1/65536)/2 = 1 - (1 / 65536)/2, carry bit to sdm2
if (numrator > 1.0 - (1.0 / 65536.0) / 2.0) {
sdm2++;
}
// If numrator is smaller than (1/65536)/2, keep sdm0 = sdm1 = 0, otherwise calculate sdm0 and sdm1
else if (numrator > (1.0 / 65536.0) / 2.0) {
// Get the closest sdm1
sdm1 = (int)(numrator * 65536.0 + 0.5) / 256;
// Get the closest sdm0
sdm0 = (int)(numrator * 65536.0 + 0.5) % 256;
}
uint32_t real_freq = (uint32_t)(rtc_xtal_freq * 1000000 * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2));
*_o_div = o_div;
*_sdm0 = sdm0;
*_sdm1 = sdm1;
*_sdm2 = sdm2;
return real_freq;
}
/* calibration */
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3);
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
{
uint8_t sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV1;
uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0);
if (is_rev0) {
sdm0 = 0;
sdm1 = 0;
sdm_stop_val_2 = APLL_SDM_STOP_VAL_2_REV0;
}
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, sdm_stop_val_2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
/* wait for calibration end */
while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) {
/* use esp_rom_delay_us so the RTC bus doesn't get flooded */
esp_rom_delay_us(1);
}
/* calibration */
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3);
/* wait for calibration end */
while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) {
/* use esp_rom_delay_us so the RTC bus doesn't get flooded */
esp_rom_delay_us(1);
}
}

View File

@ -12,7 +12,7 @@
*
* This file lists register fields of APLL, located on an internal configuration
* bus. These definitions are used via macros defined in regi2c_ctrl.h, by
* rtc_clk_apll_enable function in rtc_clk.c.
* rtc_clk_apll_freq_set and rtc_clk_apll_enable function in rtc_clk.c.
*/
#define I2C_APLL 0X6D

View File

@ -15,6 +15,7 @@
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_caps.h"
#include "soc/sens_reg.h"
#include "soc/dport_reg.h"
#include "soc/efuse_reg.h"
@ -119,30 +120,90 @@ bool rtc_clk_8md256_enabled(void)
return GET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M_DIV) == 0;
}
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div)
void rtc_clk_apll_enable(bool enable)
{
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PD, enable ? 0 : 1);
REG_SET_FIELD(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_PLLA_FORCE_PU, enable ? 1 : 0);
}
if (enable) {
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_2_REV1);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
/* calibration */
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3);
/* wait for calibration end */
while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) {
/* use esp_rom_delay_us so the RTC bus doesn't get flooded */
esp_rom_delay_us(1);
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
{
uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
if (rtc_xtal_freq == 0) {
// xtal_freq has not set yet
SOC_LOGE(TAG, "Get xtal clock frequency failed, it has not been set yet");
abort();
}
/* Reference formula: apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) / ((o_div + 2) * 2)
* ---------------------------------------------- -----------------
* 350 MHz <= Numerator <= 500 MHz Denominator
*/
int o_div = 0; // range: 0~31
int sdm0 = 0; // range: 0~255
int sdm1 = 0; // range: 0~255
int sdm2 = 0; // range: 0~63
/* Firstly try to satisfy the condition that the operation frequency of numerator should be greater than 350 MHz,
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value.
* With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is
* 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2;
if (o_div > 31) {
SOC_LOGE(TAG, "Expected frequency is too small");
return 0;
}
if (o_div < 0) {
/* Try to satisfy the condition that the operation frequency of numerator should be smaller than 500 MHz,
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code.
* With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is
* 500 MHz / ((0 + 2) * 2) = 125000000 Hz */
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2;
if (o_div < 0) {
SOC_LOGE(TAG, "Expected frequency is too big");
return 0;
}
}
// sdm2 = (int)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
sdm2 = (int)(((o_div + 2) * 2 * freq) / (rtc_xtal_freq * 1000000)) - 4;
// numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2
float numrator = (((o_div + 2) * 2 * freq) / ((float)rtc_xtal_freq * 1000000)) - 4 - sdm2;
// If numrator is bigger than 255/256 + 255/65536 + (1/65536)/2 = 1 - (1 / 65536)/2, carry bit to sdm2
if (numrator > 1.0 - (1.0 / 65536.0) / 2.0) {
sdm2++;
}
// If numrator is smaller than (1/65536)/2, keep sdm0 = sdm1 = 0, otherwise calculate sdm0 and sdm1
else if (numrator > (1.0 / 65536.0) / 2.0) {
// Get the closest sdm1
sdm1 = (int)(numrator * 65536.0 + 0.5) / 256;
// Get the closest sdm0
sdm0 = (int)(numrator * 65536.0 + 0.5) % 256;
}
uint32_t real_freq = (uint32_t)(rtc_xtal_freq * 1000000 * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2));
*_o_div = o_div;
*_sdm0 = sdm0;
*_sdm1 = sdm1;
*_sdm2 = sdm2;
return real_freq;
}
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
{
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM2, sdm2);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM0, sdm0);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_DSDM1, sdm1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_SDM_STOP, APLL_SDM_STOP_VAL_2_REV1);
REGI2C_WRITE_MASK(I2C_APLL, I2C_APLL_OR_OUTPUT_DIV, o_div);
/* calibration */
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_1);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_2);
REGI2C_WRITE(I2C_APLL, I2C_APLL_IR_CAL_DELAY, APLL_CAL_DELAY_3);
/* wait for calibration end */
while (!(REGI2C_READ_MASK(I2C_APLL, I2C_APLL_OR_CAL_END))) {
/* use esp_rom_delay_us so the RTC bus doesn't get flooded */
esp_rom_delay_us(1);
}
}
void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)

View File

@ -26,27 +26,32 @@ static void i2s_hal_mclk_div_decimal_cal(i2s_hal_clock_cfg_t *clk_cfg, i2s_ll_mc
cal->mclk_div = clk_cfg->mclk_div;
cal->a = 1;
cal->b = 0;
/* If sclk = 0 means APLL clock applied, mclk_div should set to 1 */
if (!clk_cfg->sclk) {
cal->mclk_div = 1;
uint32_t freq_diff = abs(clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div);
if (!freq_diff) {
return;
}
float decimal = freq_diff / (float)clk_cfg->mclk;
// Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0
if (decimal > 125.0 / 126.0) {
cal->mclk_div++;
return;
}
uint32_t freq_diff = clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div;
uint32_t min = ~0;
for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
for (int b = 1; b < a; b++) {
ma = freq_diff * a;
mb = clk_cfg->mclk * b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
// Calculate the closest 'b' in this loop, no need to loop 'b' to seek the closest value
int b = (int)(a * (freq_diff / (double)clk_cfg->mclk) + 0.5);
ma = freq_diff * a;
mb = clk_cfg->mclk * b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
}
}

View File

@ -1,16 +1,8 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

View File

@ -191,10 +191,34 @@ config SOC_I2C_SUPPORT_APB
bool
default y
config SOC_CLK_APLL_SUPPORTED
bool
default y
config SOC_APLL_MULTIPLIER_OUT_MIN_HZ
int
default 350000000
config SOC_APLL_MULTIPLIER_OUT_MAX_HZ
int
default 500000000
config SOC_APLL_MIN_HZ
int
default 5303031
config SOC_APLL_MAX_HZ
int
default 125000000
config SOC_I2S_NUM
int
default 2
config SOC_I2S_SUPPORTS_APLL
bool
default y
config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
@ -211,22 +235,6 @@ config SOC_I2S_SUPPORTS_DAC
bool
default y
config SOC_I2S_SUPPORTS_APLL
bool
default y
config SOC_I2S_APLL_MIN_FREQ
int
default 250000000
config SOC_I2S_APLL_MAX_FREQ
int
default 500000000
config SOC_I2S_APLL_MIN_RATE
int
default 10675
config SOC_I2S_TRANS_SIZE_ALIGN_WORD
bool
default y

View File

@ -1,16 +1,8 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
@ -54,7 +46,6 @@ extern "C" {
* - rtc_init: initialization
*/
/**
* @brief Possible main XTAL frequency values.
*
@ -260,13 +251,33 @@ bool rtc_clk_8md256_enabled(void);
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
*
* @param enable true to enable, false to disable
*/
void rtc_clk_apll_enable(bool enable);
/**
* @brief Calculate APLL clock coeffifcients
*
* @param freq expected APLL frequency
* @param o_div frequency divider, 0..31
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
* @param o_div frequency divider, 0..31
*
* @return
* - 0 Failed
* - else Sucess
*/
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1,
uint32_t sdm2, uint32_t o_div);
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2);
/**
* @brief Set APLL clock coeffifcients
*
* @param o_div frequency divider, 0..31
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
*/
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2);
/**
* @brief Select source for RTC_SLOW_CLK

View File

@ -157,18 +157,23 @@
#define SOC_I2C_SUPPORT_APB (1)
/*-------------------------- APLL CAPS ----------------------------------------*/
#define SOC_CLK_APLL_SUPPORTED (1)
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz
#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz
#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
/*-------------------------- I2S CAPS ----------------------------------------*/
// ESP32 have 2 I2S
#define SOC_I2S_NUM (2)
#define SOC_I2S_NUM (2U)
#define SOC_I2S_SUPPORTS_APLL (1) // ESP32 support APLL
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_SUPPORTS_ADC (1) // ESP32 support ADC and DAC
#define SOC_I2S_SUPPORTS_DAC (1)
#define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL
#define SOC_I2S_APLL_MIN_FREQ (250000000)
#define SOC_I2S_APLL_MAX_FREQ (500000000)
#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
#define SOC_I2S_TRANS_SIZE_ALIGN_WORD (1) // I2S DMA transfer size must be aligned to word
#define SOC_I2S_LCD_I80_VARIANT (1) // I2S has a special LCD mode that can generate Intel 8080 TX timing

View File

@ -157,7 +157,6 @@ typedef enum {
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M)
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
RTC_CPU_FREQ_SRC_APLL //!< APLL
} rtc_cpu_freq_src_t;
/**
@ -363,24 +362,6 @@ bool rtc_clk_8m_enabled(void);
*/
bool rtc_clk_8md256_enabled(void);
/**
* @brief Enable or disable APLL
*
* Output frequency is given by the formula:
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 - 600 MHz.
*
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
*
* @param enable true to enable, false to disable
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
* @param o_div frequency divider, 0..31
*/
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div);
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of rtc_slow_freq_t values)

View File

@ -369,24 +369,6 @@ bool rtc_clk_8m_enabled(void);
*/
bool rtc_clk_8md256_enabled(void);
/**
* @brief Enable or disable APLL
*
* Output frequency is given by the formula:
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 - 600 MHz.
*
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
*
* @param enable true to enable, false to disable
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
* @param o_div frequency divider, 0..31
*/
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div);
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of rtc_slow_freq_t values)

View File

@ -279,6 +279,26 @@ config SOC_I2C_SUPPORT_APB
bool
default y
config SOC_CLK_APLL_SUPPORTED
bool
default y
config SOC_APLL_MULTIPLIER_OUT_MIN_HZ
int
default 350000000
config SOC_APLL_MULTIPLIER_OUT_MAX_HZ
int
default 500000000
config SOC_APLL_MIN_HZ
int
default 5303031
config SOC_APLL_MAX_HZ
int
default 125000000
config SOC_I2S_NUM
int
default 1
@ -291,18 +311,6 @@ config SOC_I2S_SUPPORTS_DMA_EQUAL
bool
default y
config SOC_I2S_APLL_MIN_FREQ
int
default 250000000
config SOC_I2S_APLL_MAX_FREQ
int
default 500000000
config SOC_I2S_APLL_MIN_RATE
int
default 10675
config SOC_I2S_LCD_I80_VARIANT
bool
default y

View File

@ -1,16 +1,8 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
@ -406,12 +398,33 @@ bool rtc_clk_8md256_enabled(void);
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
*
* @param enable true to enable, false to disable
*/
void rtc_clk_apll_enable(bool enable);
/**
* @brief Calculate APLL clock coeffifcients
*
* @param freq expected APLL frequency
* @param o_div frequency divider, 0..31
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
* @param o_div frequency divider, 0..31
*
* @return
* - 0 Failed
* - else Sucess
*/
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div);
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2);
/**
* @brief Set APLL clock coeffifcients
*
* @param o_div frequency divider, 0..31
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
*/
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2);
/**
* @brief Select source for RTC_SLOW_CLK

View File

@ -153,14 +153,19 @@
#define SOC_I2C_SUPPORT_REF_TICK (1)
#define SOC_I2C_SUPPORT_APB (1)
/*-------------------------- APLL CAPS ----------------------------------------*/
#define SOC_CLK_APLL_SUPPORTED (1)
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz
#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz
#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
/*-------------------------- I2S CAPS ----------------------------------------*/
// ESP32-S2 have 1 I2S
#define SOC_I2S_NUM (1U)
#define SOC_I2S_SUPPORTS_APLL (1)// ESP32-S2 support APLL
#define SOC_I2S_SUPPORTS_APLL (1) // ESP32-S2 support APLL
#define SOC_I2S_SUPPORTS_DMA_EQUAL (1)
#define SOC_I2S_APLL_MIN_FREQ (250000000)
#define SOC_I2S_APLL_MAX_FREQ (500000000)
#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
#define SOC_I2S_LCD_I80_VARIANT (1)
/*-------------------------- LCD CAPS ----------------------------------------*/

View File

@ -157,7 +157,6 @@ typedef enum {
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M)
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
RTC_CPU_FREQ_SRC_APLL //!< APLL
} rtc_cpu_freq_src_t;
/**
@ -371,24 +370,6 @@ bool rtc_clk_8m_enabled(void);
*/
bool rtc_clk_8md256_enabled(void);
/**
* @brief Enable or disable APLL
*
* Output frequency is given by the formula:
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 - 600 MHz.
*
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
*
* @param enable true to enable, false to disable
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
* @param o_div frequency divider, 0..31
*/
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div);
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of rtc_slow_freq_t values)

View File

@ -150,7 +150,6 @@ typedef enum {
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M)
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
RTC_CPU_FREQ_SRC_APLL //!< APLL
} rtc_cpu_freq_src_t;
/**
@ -349,24 +348,6 @@ bool rtc_clk_8m_enabled(void);
*/
bool rtc_clk_8md256_enabled(void);
/**
* @brief Enable or disable APLL
*
* Output frequency is given by the formula:
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 - 600 MHz.
*
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
*
* @param enable true to enable, false to disable
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
* @param o_div frequency divider, 0..31
*/
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div);
/**
* @brief Select source for RTC_SLOW_CLK
* @param slow_freq clock source (one of rtc_slow_freq_t values)

View File

@ -1135,7 +1135,6 @@ components/hal/include/hal/esp_flash_err.h
components/hal/include/hal/gpio_hal.h
components/hal/include/hal/i2c_hal.h
components/hal/include/hal/i2c_types.h
components/hal/include/hal/i2s_types.h
components/hal/include/hal/interrupt_controller_hal.h
components/hal/include/hal/interrupt_controller_types.h
components/hal/include/hal/ledc_hal.h
@ -1632,7 +1631,6 @@ components/soc/esp32/include/soc/pid.h
components/soc/esp32/include/soc/reset_reasons.h
components/soc/esp32/include/soc/rmt_reg.h
components/soc/esp32/include/soc/rmt_struct.h
components/soc/esp32/include/soc/rtc.h
components/soc/esp32/include/soc/rtc_cntl_reg.h
components/soc/esp32/include/soc/rtc_cntl_struct.h
components/soc/esp32/include/soc/rtc_i2c_reg.h
@ -1855,7 +1853,6 @@ components/soc/esp32s2/include/soc/pcnt_struct.h
components/soc/esp32s2/include/soc/reset_reasons.h
components/soc/esp32s2/include/soc/rmt_reg.h
components/soc/esp32s2/include/soc/rmt_struct.h
components/soc/esp32s2/include/soc/rtc.h
components/soc/esp32s2/include/soc/rtc_cntl_reg.h
components/soc/esp32s2/include/soc/rtc_cntl_struct.h
components/soc/esp32s2/include/soc/rtc_i2c_reg.h