mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-06 22:24:33 +02:00
i2s: impove the clock division calculation
Reported from: https://esp32.com/viewtopic.php?f=25&t=24542&p=87595#p87595
This commit is contained in:
@@ -916,124 +916,6 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num)
|
|||||||
/*-------------------------------------------------------------
|
/*-------------------------------------------------------------
|
||||||
I2S clock operation
|
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
|
* @brief Config I2S source clock and get its frequency
|
||||||
*
|
*
|
||||||
@@ -1049,21 +931,19 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
|
|||||||
{
|
{
|
||||||
#if SOC_I2S_SUPPORTS_APLL
|
#if SOC_I2S_SUPPORTS_APLL
|
||||||
if (use_apll) {
|
if (use_apll) {
|
||||||
int sdm0 = 0;
|
int div_min = (int)(RTC_APLL_FREQ_MIN / (float)mclk + 1);
|
||||||
int sdm1 = 0;
|
int div_max = (int)(RTC_APLL_FREQ_MAX / (float)mclk);
|
||||||
int sdm2 = 0;
|
div_min = div_min < 2 ? 2 : div_min; // APLL / mclk >= 2
|
||||||
int odir = 0;
|
if (div_min > div_max) {
|
||||||
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 frequency is too big for APLL colck source");
|
||||||
ESP_LOGE(TAG, "mclk is too small");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
i2s_apll_calculate_fi2s(mclk, p_i2s[i2s_num]->hal_cfg.sample_bits, &sdm0, &sdm1, &sdm2, &odir);
|
uint32_t expt_freq = div_min * mclk;
|
||||||
ESP_LOGI(TAG, "APLL Enabled, coefficient: sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir);
|
rtc_clk_apll_freq_set(expt_freq);
|
||||||
rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, odir);
|
|
||||||
/* Set I2S_APLL as I2S module clock source */
|
/* Set I2S_APLL as I2S module clock source */
|
||||||
i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_APLL);
|
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 */
|
/* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */
|
||||||
return 0;
|
return expt_freq;
|
||||||
}
|
}
|
||||||
/* Set I2S_D2CLK (160M) as default I2S module clock source */
|
/* Set I2S_D2CLK (160M) as default I2S module clock source */
|
||||||
i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_D2CLK);
|
i2s_hal_set_clock_src(&(p_i2s[i2s_num]->hal), I2S_CLK_D2CLK);
|
||||||
@@ -1108,7 +988,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;
|
clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk;
|
||||||
|
|
||||||
/* Check if the configuration is correct */
|
/* 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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -1146,7 +1026,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;
|
clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk;
|
||||||
|
|
||||||
/* Check if the configuration is correct */
|
/* 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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -1184,7 +1064,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;
|
clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk;
|
||||||
|
|
||||||
/* Check if the configuration is correct */
|
/* 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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -1240,7 +1120,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;
|
clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk;
|
||||||
|
|
||||||
/* Check if the configuration is correct */
|
/* 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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,10 @@
|
|||||||
#define RTC_SLOW_CLK_FREQ_8MD256 (RTC_FAST_CLK_FREQ_8M / 256)
|
#define RTC_SLOW_CLK_FREQ_8MD256 (RTC_FAST_CLK_FREQ_8M / 256)
|
||||||
#define RTC_SLOW_CLK_FREQ_32K 32768
|
#define RTC_SLOW_CLK_FREQ_32K 32768
|
||||||
|
|
||||||
|
/* APLL numerator frequency range */
|
||||||
|
#define RTC_APLL_NUMERATOR_FREQ_MAX 500000000 // 500MHz
|
||||||
|
#define RTC_APLL_NUMERATOR_FREQ_MIN 350000000 // 350MHz
|
||||||
|
|
||||||
/* BBPLL configuration values */
|
/* BBPLL configuration values */
|
||||||
#define BBPLL_ENDIV5_VAL_320M 0x43
|
#define BBPLL_ENDIV5_VAL_320M 0x43
|
||||||
#define BBPLL_BBADC_DSMP_VAL_320M 0x84
|
#define BBPLL_BBADC_DSMP_VAL_320M 0x84
|
||||||
@@ -308,6 +312,49 @@ void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t rtc_clk_apll_freq_set(uint32_t freq)
|
||||||
|
{
|
||||||
|
if (freq < RTC_APLL_FREQ_MIN || freq > RTC_APLL_FREQ_MAX) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
|
||||||
|
uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
|
||||||
|
if (rtc_xtal_freq == 0) {
|
||||||
|
// xtal_freq has not set yet
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
uint32_t o_div = 0;
|
||||||
|
uint32_t sdm0 = 0;
|
||||||
|
uint32_t sdm1 = 0;
|
||||||
|
uint32_t sdm2 = 0;
|
||||||
|
/**
|
||||||
|
* This formula is to satisfy the condition xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz
|
||||||
|
* '+ 1' in this formular is to get the ceil value
|
||||||
|
* We can also choose the condition xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz
|
||||||
|
* Then the formula should be o_div = (uint32_t)(RTC_APLL_NUMERATOR_FREQ_MAX / (float)(freq * 2)) - 2; */
|
||||||
|
o_div = (uint32_t)(RTC_APLL_NUMERATOR_FREQ_MIN / (float)(freq * 2) + 1) - 2;
|
||||||
|
// sdm2 = (uint32_t)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
|
||||||
|
sdm2 = (uint32_t)(((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 = (uint32_t)(numrator * 65536.0 + 0.5) / 256;
|
||||||
|
// Get the closest sdm0
|
||||||
|
sdm0 = (uint32_t)(numrator * 65536.0 + 0.5) % 256;
|
||||||
|
}
|
||||||
|
rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, o_div);
|
||||||
|
float real_freq = (float)rtc_xtal_freq * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2);
|
||||||
|
SOC_LOGD(TAG, "APLL is working at %d Hz with coefficient [sdm0] %d [sdm1] %d [sdm2] %d [o_div] %d",
|
||||||
|
(uint32_t)(real_freq * 1000000), sdm0, sdm1, sdm2, o_div);
|
||||||
|
return (uint32_t)(real_freq * 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)
|
void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)
|
||||||
{
|
{
|
||||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
|
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
|
||||||
|
@@ -31,6 +31,10 @@ static const char *TAG = "rtc_clk";
|
|||||||
#define RTC_PLL_FREQ_480M 480
|
#define RTC_PLL_FREQ_480M 480
|
||||||
#define DELAY_RTC_CLK_SWITCH 5
|
#define DELAY_RTC_CLK_SWITCH 5
|
||||||
|
|
||||||
|
/* APLL numerator frequency range */
|
||||||
|
#define RTC_APLL_NUMERATOR_FREQ_MAX 500000000 // 500MHz
|
||||||
|
#define RTC_APLL_NUMERATOR_FREQ_MIN 350000000 // 350MHz
|
||||||
|
|
||||||
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
|
// Current PLL frequency, in MHZ (320 or 480). Zero if PLL is not enabled.
|
||||||
// On the ESP32-S2, 480MHz PLL is enabled at reset.
|
// On the ESP32-S2, 480MHz PLL is enabled at reset.
|
||||||
static uint32_t s_cur_pll_freq = RTC_PLL_FREQ_480M;
|
static uint32_t s_cur_pll_freq = RTC_PLL_FREQ_480M;
|
||||||
@@ -145,6 +149,49 @@ void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1, uint32_t sdm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t rtc_clk_apll_freq_set(uint32_t freq)
|
||||||
|
{
|
||||||
|
if (freq < RTC_APLL_FREQ_MIN || freq > RTC_APLL_FREQ_MAX) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
|
||||||
|
uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get();
|
||||||
|
if (rtc_xtal_freq == 0) {
|
||||||
|
// xtal_freq has not set yet
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
uint32_t o_div = 0;
|
||||||
|
uint32_t sdm0 = 0;
|
||||||
|
uint32_t sdm1 = 0;
|
||||||
|
uint32_t sdm2 = 0;
|
||||||
|
/**
|
||||||
|
* This formula is to satisfy the condition xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz
|
||||||
|
* '+ 1' in this formular is to get the ceil value
|
||||||
|
* We can also choose the condition xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz
|
||||||
|
* Then the formula should be o_div = (uint32_t)(RTC_APLL_NUMERATOR_FREQ_MAX / (float)(freq * 2)) - 2; */
|
||||||
|
o_div = (uint32_t)(RTC_APLL_NUMERATOR_FREQ_MIN / (float)(freq * 2) + 1) - 2;
|
||||||
|
// sdm2 = (uint32_t)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4
|
||||||
|
sdm2 = (uint32_t)(((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 = (uint32_t)(numrator * 65536.0 + 0.5) / 256;
|
||||||
|
// Get the closest sdm0
|
||||||
|
sdm0 = (uint32_t)(numrator * 65536.0 + 0.5) % 256;
|
||||||
|
}
|
||||||
|
rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, o_div);
|
||||||
|
float real_freq = (float)rtc_xtal_freq * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 2);
|
||||||
|
SOC_LOGD(TAG, "APLL is working at %d Hz with coefficient [sdm0] %d [sdm1] %d [sdm2] %d [o_div] %d",
|
||||||
|
(uint32_t)(real_freq * 1000000), sdm0, sdm1, sdm2, o_div);
|
||||||
|
return (uint32_t)(real_freq * 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)
|
void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq)
|
||||||
{
|
{
|
||||||
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
|
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL, slow_freq);
|
||||||
|
@@ -26,27 +26,26 @@ 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->mclk_div = clk_cfg->mclk_div;
|
||||||
cal->a = 1;
|
cal->a = 1;
|
||||||
cal->b = 0;
|
cal->b = 0;
|
||||||
/* If sclk = 0 means APLL clock applied, mclk_div should set to 1 */
|
|
||||||
if (!clk_cfg->sclk) {
|
uint32_t freq_diff = clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div;
|
||||||
cal->mclk_div = 1;
|
if (!freq_diff) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t freq_diff = clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div;
|
|
||||||
uint32_t min = ~0;
|
uint32_t min = ~0;
|
||||||
for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
|
for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
|
||||||
for (int b = 1; b < a; b++) {
|
// Calculate the closest 'b' in this loop, no need to loop 'b' to seek the closest value
|
||||||
ma = freq_diff * a;
|
int b = (int)(a * (freq_diff / (double)clk_cfg->mclk) + 0.5);
|
||||||
mb = clk_cfg->mclk * b;
|
ma = freq_diff * a;
|
||||||
if (ma == mb) {
|
mb = clk_cfg->mclk * b;
|
||||||
cal->a = a;
|
if (ma == mb) {
|
||||||
cal->b = b;
|
cal->a = a;
|
||||||
return;
|
cal->b = b;
|
||||||
}
|
return;
|
||||||
if (abs((mb - ma)) < min) {
|
}
|
||||||
cal->a = a;
|
if (abs((mb - ma)) < min) {
|
||||||
cal->b = b;
|
cal->a = a;
|
||||||
min = abs(mb - ma);
|
cal->b = b;
|
||||||
}
|
min = abs(mb - ma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,8 @@
|
|||||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
||||||
// you may not use this file except in compliance with the License.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
// 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.
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -54,6 +46,9 @@ extern "C" {
|
|||||||
* - rtc_init: initialization
|
* - rtc_init: initialization
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* APLL frequency range */
|
||||||
|
#define RTC_APLL_FREQ_MAX 128000000 // 128MHz
|
||||||
|
#define RTC_APLL_FREQ_MIN 16000000 // 16MHz
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Possible main XTAL frequency values.
|
* @brief Possible main XTAL frequency values.
|
||||||
@@ -268,6 +263,15 @@ bool rtc_clk_8md256_enabled(void);
|
|||||||
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1,
|
void rtc_clk_apll_enable(bool enable, uint32_t sdm0, uint32_t sdm1,
|
||||||
uint32_t sdm2, uint32_t o_div);
|
uint32_t sdm2, uint32_t o_div);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set APLL clock freqency
|
||||||
|
* @param freq Expected APLL freqency (unit: Hz)
|
||||||
|
* @return
|
||||||
|
* - 0: Failed, the expected APLL frequency is out of range
|
||||||
|
* - else: The true APLL clock (unit: Hz)
|
||||||
|
*/
|
||||||
|
uint32_t rtc_clk_apll_freq_set(uint32_t freq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Select source for RTC_SLOW_CLK
|
* @brief Select source for RTC_SLOW_CLK
|
||||||
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
||||||
|
@@ -157,7 +157,6 @@ typedef enum {
|
|||||||
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
|
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
|
||||||
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M)
|
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M)
|
||||||
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
|
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
|
||||||
RTC_CPU_FREQ_SRC_APLL //!< APLL
|
|
||||||
} rtc_cpu_freq_src_t;
|
} rtc_cpu_freq_src_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -363,24 +362,6 @@ bool rtc_clk_8m_enabled(void);
|
|||||||
*/
|
*/
|
||||||
bool rtc_clk_8md256_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
|
* @brief Select source for RTC_SLOW_CLK
|
||||||
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
||||||
|
@@ -369,24 +369,6 @@ bool rtc_clk_8m_enabled(void);
|
|||||||
*/
|
*/
|
||||||
bool rtc_clk_8md256_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
|
* @brief Select source for RTC_SLOW_CLK
|
||||||
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
||||||
|
@@ -1,16 +1,8 @@
|
|||||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
||||||
// you may not use this file except in compliance with the License.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
// 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.
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -81,6 +73,10 @@ extern "C" {
|
|||||||
#define DELAY_SLOW_CLK_SWITCH 300
|
#define DELAY_SLOW_CLK_SWITCH 300
|
||||||
#define DELAY_8M_ENABLE 50
|
#define DELAY_8M_ENABLE 50
|
||||||
|
|
||||||
|
/* APLL frequency range */
|
||||||
|
#define RTC_APLL_FREQ_MAX 128000000 // 128MHz
|
||||||
|
#define RTC_APLL_FREQ_MIN 16000000 // 16MHz
|
||||||
|
|
||||||
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
|
/* Number of 8M/256 clock cycles to use for XTAL frequency estimation.
|
||||||
* 10 cycles will take approximately 300 microseconds.
|
* 10 cycles will take approximately 300 microseconds.
|
||||||
*/
|
*/
|
||||||
@@ -413,6 +409,15 @@ bool rtc_clk_8md256_enabled(void);
|
|||||||
*/
|
*/
|
||||||
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, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2, uint32_t o_div);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set APLL clock freqency
|
||||||
|
* @param freq Expected APLL freqency (unit: Hz)
|
||||||
|
* @return
|
||||||
|
* - 0: Failed, the expected APLL frequency is out of range
|
||||||
|
* - else: The true APLL clock (unit: Hz)
|
||||||
|
*/
|
||||||
|
uint32_t rtc_clk_apll_freq_set(uint32_t freq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Select source for RTC_SLOW_CLK
|
* @brief Select source for RTC_SLOW_CLK
|
||||||
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
||||||
|
@@ -157,7 +157,6 @@ typedef enum {
|
|||||||
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
|
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
|
||||||
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M)
|
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M or 320M)
|
||||||
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
|
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
|
||||||
RTC_CPU_FREQ_SRC_APLL //!< APLL
|
|
||||||
} rtc_cpu_freq_src_t;
|
} rtc_cpu_freq_src_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -371,24 +370,6 @@ bool rtc_clk_8m_enabled(void);
|
|||||||
*/
|
*/
|
||||||
bool rtc_clk_8md256_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
|
* @brief Select source for RTC_SLOW_CLK
|
||||||
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
||||||
|
@@ -150,7 +150,6 @@ typedef enum {
|
|||||||
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
|
RTC_CPU_FREQ_SRC_XTAL, //!< XTAL
|
||||||
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M)
|
RTC_CPU_FREQ_SRC_PLL, //!< PLL (480M)
|
||||||
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
|
RTC_CPU_FREQ_SRC_8M, //!< Internal 8M RTC oscillator
|
||||||
RTC_CPU_FREQ_SRC_APLL //!< APLL
|
|
||||||
} rtc_cpu_freq_src_t;
|
} rtc_cpu_freq_src_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -349,24 +348,6 @@ bool rtc_clk_8m_enabled(void);
|
|||||||
*/
|
*/
|
||||||
bool rtc_clk_8md256_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
|
* @brief Select source for RTC_SLOW_CLK
|
||||||
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
* @param slow_freq clock source (one of rtc_slow_freq_t values)
|
||||||
|
@@ -1632,7 +1632,6 @@ components/soc/esp32/include/soc/pid.h
|
|||||||
components/soc/esp32/include/soc/reset_reasons.h
|
components/soc/esp32/include/soc/reset_reasons.h
|
||||||
components/soc/esp32/include/soc/rmt_reg.h
|
components/soc/esp32/include/soc/rmt_reg.h
|
||||||
components/soc/esp32/include/soc/rmt_struct.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_reg.h
|
||||||
components/soc/esp32/include/soc/rtc_cntl_struct.h
|
components/soc/esp32/include/soc/rtc_cntl_struct.h
|
||||||
components/soc/esp32/include/soc/rtc_i2c_reg.h
|
components/soc/esp32/include/soc/rtc_i2c_reg.h
|
||||||
@@ -1855,7 +1854,6 @@ components/soc/esp32s2/include/soc/pcnt_struct.h
|
|||||||
components/soc/esp32s2/include/soc/reset_reasons.h
|
components/soc/esp32s2/include/soc/reset_reasons.h
|
||||||
components/soc/esp32s2/include/soc/rmt_reg.h
|
components/soc/esp32s2/include/soc/rmt_reg.h
|
||||||
components/soc/esp32s2/include/soc/rmt_struct.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_reg.h
|
||||||
components/soc/esp32s2/include/soc/rtc_cntl_struct.h
|
components/soc/esp32s2/include/soc/rtc_cntl_struct.h
|
||||||
components/soc/esp32s2/include/soc/rtc_i2c_reg.h
|
components/soc/esp32s2/include/soc/rtc_i2c_reg.h
|
||||||
|
Reference in New Issue
Block a user