diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 828dae6083..84d47d44fd 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -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" @@ -888,123 +887,54 @@ 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) +static esp_err_t i2s_set_apll_freq(uint32_t expt_freq, uint32_t *real_freq) { - int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; + uint32_t rtc_xtal_freq = (uint32_t)rtc_clk_xtal_freq_get(); + ESP_RETURN_ON_FALSE(rtc_xtal_freq, ESP_ERR_INVALID_STATE, TAG, "Get xtal clock frequency failed, it has not been set yet"); -#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; + /* 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)(expt_freq * 2) + 1) - 2; + ESP_RETURN_ON_FALSE(o_div < 32, ESP_ERR_INVALID_ARG, TAG, "Expected frequency is too small"); + 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)(expt_freq * 2)) - 2; + ESP_RETURN_ON_FALSE(o_div >= 0, ESP_ERR_INVALID_ARG, TAG, "Expected frequency is too small"); } -#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; + // sdm2 = (int)(((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 + sdm2 = (int)(((o_div + 2) * 2 * expt_freq) / (rtc_xtal_freq * 1000000)) - 4; + // numrator = (((o_div + 2) * 2) * apll_freq / xtal_freq) - 4 - sdm2 + float numrator = (((o_div + 2) * 2 * expt_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++; } - float fpll = fout / (2 * (odir + 2)); //== fi2s (N=1, b=0, a=1) - return fpll / 2; -} + // 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; + } + rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, o_div); + *real_freq = (uint32_t)(rtc_xtal_freq * 1000000 * (4 + sdm2 + (float)sdm1/256.0 + (float)sdm0/65536.0) / (((float)o_div + 2) * 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 350MHzhal_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 = i2s_set_apll_freq(expt_freq, &real_freq); + if (ret != ESP_OK) { + 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); + 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); @@ -1079,7 +1014,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; } @@ -1117,7 +1052,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; } @@ -1155,7 +1090,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; } @@ -1211,7 +1146,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; } diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index bc34eba55a..895aa1d9c1 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -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); } } } diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index 48d745eb2f..c59220c89c 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -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-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 42219fc56d..3449129ad0 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -140,18 +140,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 +#define SOC_APLL_MAX_HZ (125000000) // 125MHz + /*-------------------------- 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 diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 99911fac6c..10d2af25da 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -135,14 +135,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 +#define SOC_APLL_MAX_HZ (125000000) // 125MHz + /*-------------------------- I2S CAPS ----------------------------------------*/ // ESP32-S2 have 1 I2S #define SOC_I2S_NUM (1) #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 ----------------------------------------*/ diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 690bb6877c..b32d02d6a6 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1141,7 +1141,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