refactor(hal): use hal utils to calculate clock division

pull/12330/head
laokaiyao 2023-09-11 12:58:38 +08:00
rodzic 9bec9ccade
commit dd4072a80c
23 zmienionych plików z 432 dodań i 292 usunięć

Wyświetl plik

@ -97,7 +97,7 @@ static esp_err_t s_dac_dma_periph_set_clock(uint32_t freq_hz, bool is_apll)
ESP_LOGD(TAG, "[sclk] %"PRIu32" [mclk] %"PRIu32" [mclk_div] %"PRIu32" [bclk] %"PRIu32" [bclk_div] %"PRIu32, sclk, mclk, mclk_div, bclk, bclk_div); ESP_LOGD(TAG, "[sclk] %"PRIu32" [mclk] %"PRIu32" [mclk_div] %"PRIu32" [bclk] %"PRIu32" [bclk_div] %"PRIu32, sclk, mclk, mclk_div, bclk, bclk_div);
i2s_ll_tx_clk_set_src(s_ddp->periph_dev, is_apll ? I2S_CLK_SRC_APLL : I2S_CLK_SRC_DEFAULT); i2s_ll_tx_clk_set_src(s_ddp->periph_dev, is_apll ? I2S_CLK_SRC_APLL : I2S_CLK_SRC_DEFAULT);
i2s_ll_mclk_div_t mclk_div_coeff = {}; hal_utils_clk_div_t mclk_div_coeff = {};
i2s_hal_calc_mclk_precise_division(sclk, mclk, &mclk_div_coeff); i2s_hal_calc_mclk_precise_division(sclk, mclk, &mclk_div_coeff);
i2s_ll_tx_set_mclk(s_ddp->periph_dev, &mclk_div_coeff); i2s_ll_tx_set_mclk(s_ddp->periph_dev, &mclk_div_coeff);
i2s_ll_tx_set_bck_div_num(s_ddp->periph_dev, bclk_div); i2s_ll_tx_set_bck_div_num(s_ddp->periph_dev, bclk_div);

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -18,6 +18,7 @@
#include "hal/spi_ll.h" #include "hal/spi_ll.h"
#include "hal/dac_ll.h" #include "hal/dac_ll.h"
#include "hal/adc_ll.h" #include "hal/adc_ll.h"
#include "hal/hal_utils.h"
#include "soc/lldesc.h" #include "soc/lldesc.h"
#include "soc/soc.h" #include "soc/soc.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
@ -99,36 +100,21 @@ static esp_err_t s_dac_dma_periph_set_clock(uint32_t freq_hz, bool is_apll){
} }
ESP_RETURN_ON_FALSE(interval * 256 > total_div, ESP_ERR_INVALID_ARG, TAG, "the DAC frequency is too small"); ESP_RETURN_ON_FALSE(interval * 256 > total_div, ESP_ERR_INVALID_ARG, TAG, "the DAC frequency is too small");
/* Step 3: Calculate the coefficients of ADC digital controller divider*/ /* Step 3: Calculate the coefficients of ADC digital controller divider */
uint32_t fsclk = interval * freq_hz; /* The clock frequency that produced by ADC controller divider */ hal_utils_clk_info_t adc_clk_info = {
uint32_t clk_div = digi_ctrl_freq / fsclk; .src_freq_hz = digi_ctrl_freq / interval,
uint32_t mod = digi_ctrl_freq % fsclk; .exp_freq_hz = freq_hz,
uint32_t a = 0; .max_integ = 257,
uint32_t b = 1; .min_integ = 1,
if (mod == 0) { .max_fract = 64,
goto finish; };
} hal_utils_clk_div_t adc_clk_div = {};
uint32_t min_diff = mod + 1; hal_utils_calc_clk_div_frac_accurate(&adc_clk_info, &adc_clk_div);
for (uint32_t tmp_b = 1; tmp_b < 64; tmp_b++) {
uint32_t tmp_a = (uint32_t)(((mod * b) / (float)fsclk) + 0.5);
uint32_t diff = (uint32_t)abs((int)(mod * tmp_b) - (int)(fsclk * tmp_a));
if (diff == 0) {
a = tmp_a;
b = tmp_b;
goto finish;
}
if (diff < min_diff) {
min_diff = diff;
a = tmp_a;
b = tmp_b;
}
}
finish:
/* Step 4: Set the clock coefficients */ /* Step 4: Set the clock coefficients */
dac_ll_digi_clk_inv(true); dac_ll_digi_clk_inv(true);
dac_ll_digi_set_trigger_interval(interval); // secondary clock division dac_ll_digi_set_trigger_interval(interval); // secondary clock division
adc_ll_digi_controller_clk_div(clk_div - 1, b, a); adc_ll_digi_controller_clk_div(adc_clk_div.integer - 1, adc_clk_div.denominator, adc_clk_div.numerator);
adc_ll_digi_clk_sel(is_apll ? ADC_DIGI_CLK_SRC_APLL : ADC_DIGI_CLK_SRC_DEFAULT); adc_ll_digi_clk_sel(is_apll ? ADC_DIGI_CLK_SRC_APLL : ADC_DIGI_CLK_SRC_DEFAULT);
return ESP_OK; return ESP_OK;
} }

Wyświetl plik

@ -9,3 +9,4 @@ archive: libhal.a
entries: entries:
if LCD_RGB_ISR_IRAM_SAFE = y: if LCD_RGB_ISR_IRAM_SAFE = y:
lcd_hal: lcd_hal_cal_pclk_freq (noflash) lcd_hal: lcd_hal_cal_pclk_freq (noflash)
hal_utils: hal_utils_calc_clk_div_frac_fast (noflash)

Wyświetl plik

@ -0,0 +1,7 @@
components/hal/test_apps/hal_utils:
enable:
- if: IDF_TARGET == "linux"
disable:
- if: IDF_TARGET == "linux"
temporary: true
reason: env not ready

Wyświetl plik

@ -180,7 +180,7 @@ static void adc_hal_digi_sample_freq_config(adc_hal_dma_ctx_t *hal, adc_continuo
uint32_t bclk_div = 16; uint32_t bclk_div = 16;
uint32_t bclk = sample_freq_hz * 2; uint32_t bclk = sample_freq_hz * 2;
uint32_t mclk = bclk * bclk_div; uint32_t mclk = bclk * bclk_div;
i2s_ll_mclk_div_t mclk_div = {}; hal_utils_clk_div_t mclk_div = {};
i2s_hal_calc_mclk_precise_division(I2S_BASE_CLK, mclk, &mclk_div); i2s_hal_calc_mclk_precise_division(I2S_BASE_CLK, mclk, &mclk_div);
i2s_ll_rx_set_mclk(hal->dev, &mclk_div); i2s_ll_rx_set_mclk(hal->dev, &mclk_div);
i2s_ll_rx_set_bck_div_num(hal->dev, bclk_div); i2s_ll_rx_set_bck_div_num(hal->dev, bclk_div);

Wyświetl plik

@ -19,6 +19,8 @@
#include "soc/i2s_periph.h" #include "soc/i2s_periph.h"
#include "soc/i2s_struct.h" #include "soc/i2s_struct.h"
#include "hal/i2s_types.h" #include "hal/i2s_types.h"
#include "hal/hal_utils.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -30,8 +32,8 @@ extern "C" {
#define I2S_LL_AD_BCK_FACTOR (2) #define I2S_LL_AD_BCK_FACTOR (2)
#define I2S_LL_PDM_BCK_FACTOR (64) #define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6) #define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) #define I2S_LL_CLK_FRAC_DIV_AB_MAX 64 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 6 bit-width
#define I2S_LL_BCK_MAX_PRESCALE (64) #define I2S_LL_BCK_MAX_PRESCALE (64)
@ -48,16 +50,6 @@ extern "C" {
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT #define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief I2S clock configuration structure
* @note Fmclk = Fsclk /(integ+numer/denom)
*/
typedef struct {
uint16_t integ; // Integer part of I2S module clock divider
uint16_t denom; // Denominator part of I2S module clock divider
uint16_t numer; // Numerator part of I2S module clock divider
} i2s_ll_mclk_div_t;
/** /**
* @brief Enable DMA descriptor owner check * @brief Enable DMA descriptor owner check
* *
@ -312,14 +304,14 @@ static inline void i2s_ll_set_raw_mclk_div(i2s_dev_t *hw, uint32_t mclk_div, uin
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
* otherwise the clock division might be inaccurate. * otherwise the clock division might be inaccurate.
* the general idea is to set a value that unlike to calculate from the regular decimal */ * the general idea is to set a value that unlike to calculate from the regular decimal */
i2s_ll_set_raw_mclk_div(hw, 7, 47, 3); i2s_ll_set_raw_mclk_div(hw, 7, 47, 3);
i2s_ll_set_raw_mclk_div(hw, mclk_div->integ, mclk_div->denom, mclk_div->numer); i2s_ll_set_raw_mclk_div(hw, mclk_div->integer, mclk_div->denominator, mclk_div->numerator);
} }
/** /**
@ -340,7 +332,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
// TX and RX channel on ESP32 shares a same mclk // TX and RX channel on ESP32 shares a same mclk
i2s_ll_tx_set_mclk(hw, mclk_div); i2s_ll_tx_set_mclk(hw, mclk_div);

Wyświetl plik

@ -18,6 +18,7 @@
#include "soc/i2s_periph.h" #include "soc/i2s_periph.h"
#include "soc/i2s_struct.h" #include "soc/i2s_struct.h"
#include "hal/i2s_types.h" #include "hal/i2s_types.h"
#include "hal/hal_utils.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -29,22 +30,12 @@ extern "C" {
#define I2S_LL_TDM_CH_MASK (0xffff) #define I2S_LL_TDM_CH_MASK (0xffff)
#define I2S_LL_PDM_BCK_FACTOR (64) #define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) #define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) #define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT #define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief I2S clock configuration structure
* @note Fmclk = Fsclk /(integ+numer/denom)
*/
typedef struct {
uint16_t integ; // Integer part of I2S module clock divider
uint16_t denom; // Denominator part of I2S module clock divider
uint16_t numer; // Numerator part of I2S module clock divider
} i2s_ll_mclk_div_t;
/** /**
* @brief I2S module general init, enable I2S clock. * @brief I2S module general init, enable I2S clock.
* *
@ -304,7 +295,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
@ -317,13 +308,13 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0; uint32_t div_z = 0;
uint32_t div_yn1 = 0; uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */ /* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) { if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom; div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denom / div_z - 1; div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denom % div_z; div_y = mclk_div->denominator % div_z;
} }
i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1); i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
} }
/** /**
@ -344,7 +335,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
@ -357,13 +348,13 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0; uint32_t div_z = 0;
uint32_t div_yn1 = 0; uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */ /* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) { if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom; div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denom / div_z - 1; div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denom % div_z; div_y = mclk_div->denominator % div_z;
} }
i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1); i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
} }
/** /**

Wyświetl plik

@ -19,6 +19,7 @@
#include "soc/i2s_struct.h" #include "soc/i2s_struct.h"
#include "soc/pcr_struct.h" #include "soc/pcr_struct.h"
#include "hal/i2s_types.h" #include "hal/i2s_types.h"
#include "hal/hal_utils.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -30,22 +31,12 @@ extern "C" {
#define I2S_LL_TDM_CH_MASK (0xffff) #define I2S_LL_TDM_CH_MASK (0xffff)
#define I2S_LL_PDM_BCK_FACTOR (64) #define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) #define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) #define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT #define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief I2S clock configuration structure
* @note Fmclk = Fsclk /(integ+numer/denom)
*/
typedef struct {
uint16_t integ; // Integer part of I2S module clock divider
uint16_t denom; // Denominator part of I2S module clock divider
uint16_t numer; // Numerator part of I2S module clock divider
} i2s_ll_mclk_div_t;
/** /**
* @brief I2S module general init, enable I2S clock. * @brief I2S module general init, enable I2S clock.
* *
@ -313,7 +304,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
@ -326,13 +317,13 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0; uint32_t div_z = 0;
uint32_t div_yn1 = 0; uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */ /* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) { if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom; div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denom / div_z - 1; div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denom % div_z; div_y = mclk_div->denominator % div_z;
} }
i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1); i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
} }
/** /**
@ -353,7 +344,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
@ -366,13 +357,13 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0; uint32_t div_z = 0;
uint32_t div_yn1 = 0; uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */ /* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) { if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom; div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denom / div_z - 1; div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denom % div_z; div_y = mclk_div->denominator % div_z;
} }
i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1); i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
} }
/** /**

Wyświetl plik

@ -19,6 +19,7 @@
#include "soc/i2s_struct.h" #include "soc/i2s_struct.h"
#include "soc/pcr_struct.h" #include "soc/pcr_struct.h"
#include "hal/i2s_types.h" #include "hal/i2s_types.h"
#include "hal/hal_utils.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -30,23 +31,13 @@ extern "C" {
#define I2S_LL_TDM_CH_MASK (0xffff) #define I2S_LL_TDM_CH_MASK (0xffff)
#define I2S_LL_PDM_BCK_FACTOR (64) #define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) #define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) #define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
#define I2S_LL_PLL_F96M_CLK_FREQ (96 * 1000000) // PLL_F96M_CLK: 96MHz #define I2S_LL_PLL_F96M_CLK_FREQ (96 * 1000000) // PLL_F96M_CLK: 96MHz
#define I2S_LL_PLL_F64M_CLK_FREQ (64 * 1000000) // PLL_F64M_CLK: 64MHz #define I2S_LL_PLL_F64M_CLK_FREQ (64 * 1000000) // PLL_F64M_CLK: 64MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT #define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief I2S clock configuration structure
* @note Fmclk = Fsclk /(integ+numer/denom)
*/
typedef struct {
uint16_t integ; // Integer part of I2S module clock divider
uint16_t denom; // Denominator part of I2S module clock divider
uint16_t numer; // Numerator part of I2S module clock divider
} i2s_ll_mclk_div_t;
/** /**
* @brief I2S module general init, enable I2S clock. * @brief I2S module general init, enable I2S clock.
* *
@ -320,7 +311,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
@ -333,13 +324,13 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0; uint32_t div_z = 0;
uint32_t div_yn1 = 0; uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */ /* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) { if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom; div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denom / div_z - 1; div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denom % div_z; div_y = mclk_div->denominator % div_z;
} }
i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1); i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
} }
/** /**
@ -360,7 +351,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
@ -373,13 +364,13 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0; uint32_t div_z = 0;
uint32_t div_yn1 = 0; uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */ /* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) { if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom; div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denom / div_z - 1; div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denom % div_z; div_y = mclk_div->denominator % div_z;
} }
i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1); i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
} }
/** /**

Wyświetl plik

@ -19,6 +19,7 @@
#include "soc/i2s_periph.h" #include "soc/i2s_periph.h"
#include "soc/i2s_struct.h" #include "soc/i2s_struct.h"
#include "hal/i2s_types.h" #include "hal/i2s_types.h"
#include "hal/hal_utils.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -30,8 +31,9 @@ extern "C" {
#define I2S_LL_BCK_MAX_PRESCALE (64) #define I2S_LL_BCK_MAX_PRESCALE (64)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6) #define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) #define I2S_LL_CLK_FRAC_DIV_AB_MAX 64 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 6 bit-width
#define I2S_LL_EVENT_RX_EOF BIT(9) #define I2S_LL_EVENT_RX_EOF BIT(9)
#define I2S_LL_EVENT_TX_EOF BIT(12) #define I2S_LL_EVENT_TX_EOF BIT(12)
@ -45,16 +47,6 @@ extern "C" {
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT #define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief I2S clock configuration structure
* @note Fmclk = Fsclk /(integ+numer/denom)
*/
typedef struct {
uint16_t integ; // Integer part of I2S module clock divider
uint16_t denom; // Denominator part of I2S module clock divider
uint16_t numer; // Numerator part of I2S module clock divider
} i2s_ll_mclk_div_t;
/** /**
* @brief Enable DMA descriptor owner check * @brief Enable DMA descriptor owner check
* *
@ -303,14 +295,14 @@ static inline void i2s_ll_set_raw_mclk_div(i2s_dev_t *hw, uint32_t mclk_div, uin
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
* otherwise the clock division might be inaccurate. * otherwise the clock division might be inaccurate.
* the general idea is to set a value that unlike to calculate from the regular decimal */ * the general idea is to set a value that unlike to calculate from the regular decimal */
i2s_ll_set_raw_mclk_div(hw, 7, 47, 3); i2s_ll_set_raw_mclk_div(hw, 7, 47, 3);
i2s_ll_set_raw_mclk_div(hw, mclk_div->integ, mclk_div->denom, mclk_div->numer); i2s_ll_set_raw_mclk_div(hw, mclk_div->integer, mclk_div->denominator, mclk_div->numerator);
} }
/** /**
@ -331,7 +323,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
// TX and RX channel on ESP32 shares a same mclk // TX and RX channel on ESP32 shares a same mclk
i2s_ll_tx_set_mclk(hw, mclk_div); i2s_ll_tx_set_mclk(hw, mclk_div);

Wyświetl plik

@ -18,6 +18,7 @@
#include "soc/i2s_periph.h" #include "soc/i2s_periph.h"
#include "soc/i2s_struct.h" #include "soc/i2s_struct.h"
#include "hal/i2s_types.h" #include "hal/i2s_types.h"
#include "hal/hal_utils.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -30,22 +31,12 @@ extern "C" {
#define I2S_LL_TDM_CH_MASK (0xffff) #define I2S_LL_TDM_CH_MASK (0xffff)
#define I2S_LL_PDM_BCK_FACTOR (64) #define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) #define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) #define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT #define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief I2S clock configuration structure
* @note Fmclk = Fsclk /(integ+numer/denom)
*/
typedef struct {
uint16_t integ; // Integer part of I2S module clock divider
uint16_t denom; // Denominator part of I2S module clock divider
uint16_t numer; // Numerator part of I2S module clock divider
} i2s_ll_mclk_div_t;
/** /**
* @brief I2S module general init, enable I2S clock. * @brief I2S module general init, enable I2S clock.
* *
@ -304,7 +295,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
@ -317,13 +308,13 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0; uint32_t div_z = 0;
uint32_t div_yn1 = 0; uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */ /* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) { if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom; div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denom / div_z - 1; div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denom % div_z; div_y = mclk_div->denominator % div_z;
} }
i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1); i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
} }
/** /**
@ -344,7 +335,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
* @param hw Peripheral I2S hardware instance address. * @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients * @param mclk_div The mclk division coefficients
*/ */
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div) static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{ {
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients, * Set to particular coefficients first then update to the target coefficients,
@ -357,13 +348,13 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0; uint32_t div_z = 0;
uint32_t div_yn1 = 0; uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */ /* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) { if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom; div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer; div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denom / div_z - 1; div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denom % div_z; div_y = mclk_div->denominator % div_z;
} }
i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1); i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
} }

Wyświetl plik

@ -5,6 +5,7 @@
*/ */
#include "hal/hal_utils.h" #include "hal/hal_utils.h"
#include "hal/assert.h"
/** /**
* @brief helper function, calculate the Greatest Common Divisor * @brief helper function, calculate the Greatest Common Divisor
@ -31,36 +32,42 @@ static inline uint32_t _sub_abs(uint32_t a, uint32_t b)
return a > b ? a - b : b - a; return a > b ? a - b : b - a;
} }
uint32_t hal_utils_calc_clk_div_fast(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div) uint32_t hal_utils_calc_clk_div_frac_fast(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div)
{ {
uint32_t div_denom = 1; HAL_ASSERT(clk_info->max_fract > 2);
uint32_t div_denom = 2;
uint32_t div_numer = 0; uint32_t div_numer = 0;
uint32_t div_integ = clk_info->src_freq_hz / clk_info->exp_freq_hz; uint32_t div_integ = clk_info->src_freq_hz / clk_info->exp_freq_hz;
uint32_t freq_error = clk_info->src_freq_hz % clk_info->exp_freq_hz; uint32_t freq_error = clk_info->src_freq_hz % clk_info->exp_freq_hz;
// fractional divider
if (freq_error) {
// Carry bit if the decimal is greater than 1.0 - 1.0 / ((max_fract - 1) * 2)
if (freq_error < clk_info->exp_freq_hz - clk_info->exp_freq_hz / (clk_info->max_fract - 1) * 2) {
// Calculate the Greatest Common Divisor, time complexity O(log n)
uint32_t gcd = _gcd(clk_info->exp_freq_hz, freq_error);
// divide by the Greatest Common Divisor to get the accurate fraction before normalization
div_denom = clk_info->exp_freq_hz / gcd;
div_numer = freq_error / gcd;
// normalize div_denom and div_numer
uint32_t d = div_denom / clk_info->max_fract + 1;
// divide by the normalization coefficient to get the denominator and numerator within range of clk_info->max_fract
div_denom /= d;
div_numer /= d;
} else {
div_integ++;
}
}
// If the expect frequency is too high or too low to satisfy the integral division range, failed and return 0 // If the expect frequency is too high or too low to satisfy the integral division range, failed and return 0
if (div_integ < clk_info->min_integ || div_integ > clk_info->max_integ) { if (div_integ < clk_info->min_integ || div_integ >= clk_info->max_integ || div_integ == 0) {
return 0; return 0;
} }
// fractional divider
if (freq_error) {
// Calculate the Greatest Common Divisor, time complexity O(log n)
uint32_t gcd = _gcd(clk_info->exp_freq_hz, freq_error);
// divide by the Greatest Common Divisor to get the accurate fraction before normalization
div_denom = clk_info->exp_freq_hz / gcd;
div_numer = freq_error / gcd;
// normalize div_denom and div_numer
uint32_t d = div_denom / clk_info->max_fract + 1;
// divide by the normalization coefficient to get the denominator and numerator within range of clk_info->max_fract
div_denom /= d;
div_numer /= d;
}
// Assign result // Assign result
clk_div->integ = div_integ; clk_div->integer = div_integ;
clk_div->denom = div_denom; clk_div->denominator = div_denom;
clk_div->numer = div_numer; clk_div->numerator = div_numer;
// Return the actual frequency // Return the actual frequency
if (div_numer) { if (div_numer) {
@ -70,23 +77,19 @@ uint32_t hal_utils_calc_clk_div_fast(const hal_utils_clk_info_t *clk_info, hal_u
return clk_info->src_freq_hz / div_integ; return clk_info->src_freq_hz / div_integ;
} }
uint32_t hal_utils_calc_clk_div_accurate(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div) uint32_t hal_utils_calc_clk_div_frac_accurate(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div)
{ {
uint32_t div_denom = 1; HAL_ASSERT(clk_info->max_fract > 2);
uint32_t div_denom = 2;
uint32_t div_numer = 0; uint32_t div_numer = 0;
uint32_t div_integ = clk_info->src_freq_hz / clk_info->exp_freq_hz; uint32_t div_integ = clk_info->src_freq_hz / clk_info->exp_freq_hz;
uint32_t freq_error = clk_info->src_freq_hz % clk_info->exp_freq_hz; uint32_t freq_error = clk_info->src_freq_hz % clk_info->exp_freq_hz;
// If the expect frequency is too high to satisfy the minimum integral division, failed and return 0
if (div_integ < clk_info->min_integ) {
return 0;
}
if (freq_error) { if (freq_error) {
// Carry bit if the decimal is greater than 1.0 - 1.0 / (PARLIO_LL_CLK_DIVIDER_MAX * 2) // Carry bit if the decimal is greater than 1.0 - 1.0 / ((max_fract - 1) * 2)
if (freq_error < clk_info->exp_freq_hz - clk_info->exp_freq_hz / (clk_info->max_fract * 2)) { if (freq_error < clk_info->exp_freq_hz - clk_info->exp_freq_hz / (clk_info->max_fract - 1) * 2) {
// Search the closest fraction, time complexity O(n) // Search the closest fraction, time complexity O(n)
for (uint32_t sub = 0, a = 2, b = 0, min = UINT32_MAX; min && a <= clk_info->max_fract; a++) { for (uint32_t sub = 0, a = 2, b = 0, min = UINT32_MAX; min && a < clk_info->max_fract; a++) {
b = (a * freq_error + clk_info->exp_freq_hz / 2) / clk_info->exp_freq_hz; b = (a * freq_error + clk_info->exp_freq_hz / 2) / clk_info->exp_freq_hz;
sub = _sub_abs(clk_info->exp_freq_hz * b, freq_error * a); sub = _sub_abs(clk_info->exp_freq_hz * b, freq_error * a);
if (sub < min) { if (sub < min) {
@ -99,15 +102,16 @@ uint32_t hal_utils_calc_clk_div_accurate(const hal_utils_clk_info_t *clk_info, h
div_integ++; div_integ++;
} }
} }
// If the expect frequency is too low to satisfy the maximum integral division, failed and return 0
if (div_integ > clk_info->max_integ) { // If the expect frequency is too high or too low to satisfy the integral division range, failed and return 0
if (div_integ < clk_info->min_integ || div_integ >= clk_info->max_integ || div_integ == 0) {
return 0; return 0;
} }
// Assign result // Assign result
clk_div->integ = div_integ; clk_div->integer = div_integ;
clk_div->denom = div_denom; clk_div->denominator = div_denom;
clk_div->numer = div_numer; clk_div->numerator = div_numer;
// Return the actual frequency // Return the actual frequency
if (div_numer) { if (div_numer) {
@ -116,3 +120,22 @@ uint32_t hal_utils_calc_clk_div_accurate(const hal_utils_clk_info_t *clk_info, h
} }
return clk_info->src_freq_hz / div_integ; return clk_info->src_freq_hz / div_integ;
} }
uint32_t hal_utils_calc_clk_div_integer(const hal_utils_clk_info_t *clk_info, uint32_t *int_div)
{
uint32_t div_integ = clk_info->src_freq_hz / clk_info->exp_freq_hz;
uint32_t freq_error = clk_info->src_freq_hz % clk_info->exp_freq_hz;
/* If there is error and always round up,
Or, do the normal rounding and error >= (src/n + src/(n+1)) / 2,
then carry the bit */
if ((freq_error && clk_info->round_opt == HAL_DIV_ROUND_UP) || (clk_info->round_opt == HAL_DIV_ROUND &&
(freq_error >= clk_info->src_freq_hz / (2 * div_integ * (div_integ + 1))))) {
div_integ++;
}
// Assign result
*int_div = div_integ;
// Return the actual frequency
return clk_info->src_freq_hz / div_integ;
}

Wyświetl plik

@ -29,46 +29,18 @@ static const float cut_off_coef[21][3] = {
* *
* @param sclk system clock * @param sclk system clock
* @param mclk module clock * @param mclk module clock
* @param integer output the integer part of the division * @param mclk_div output the mclk division coefficients
* @param denominator output the denominator part of the division
* @param numerator output the numerator part of the division
*/ */
void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, i2s_ll_mclk_div_t *mclk_div) void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_clk_div_t *mclk_div)
{ {
int ma = 0; hal_utils_clk_info_t i2s_clk_info = {
int mb = 0; .src_freq_hz = sclk,
int min = INT32_MAX; .exp_freq_hz = mclk,
uint32_t div_denom = 1; .max_integ = I2S_LL_CLK_FRAC_DIV_N_MAX,
uint32_t div_numer = 0; .min_integ = 1,
uint32_t div_inter = sclk / mclk; .max_fract = I2S_LL_CLK_FRAC_DIV_AB_MAX,
uint32_t freq_diff = sclk % mclk; };
hal_utils_calc_clk_div_frac_accurate(&i2s_clk_info, mclk_div);
if (freq_diff) {
float decimal = freq_diff / (float)mclk;
// Carry bit if the decimal is greater than 1.0 - 1.0 / (I2S_LL_MCLK_DIVIDER_MAX * 2)
if (decimal <= 1.0 - 1.0 / (float)(I2S_LL_MCLK_DIVIDER_MAX * 2)) {
for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
int b = (int)(a * (freq_diff / (double)mclk) + 0.5);
ma = freq_diff * a;
mb = mclk * b;
if (ma == mb) {
div_denom = (uint32_t)a;
div_numer = (uint32_t)b;
break;
}
if (abs(mb - ma) < min) {
div_denom = (uint32_t)a;
div_numer = (uint32_t)b;
min = abs(mb - ma);
}
}
} else {
div_inter++;
}
}
mclk_div->integ = div_inter;
mclk_div->denom = div_denom;
mclk_div->numer = div_numer;
} }
void i2s_hal_init(i2s_hal_context_t *hal, int port_id) void i2s_hal_init(i2s_hal_context_t *hal, int port_id)
@ -79,7 +51,7 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id)
void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src)
{ {
i2s_ll_mclk_div_t mclk_div = {}; hal_utils_clk_div_t mclk_div = {};
#if SOC_I2S_HW_VERSION_2 #if SOC_I2S_HW_VERSION_2
i2s_ll_tx_enable_clock(hal->dev); i2s_ll_tx_enable_clock(hal->dev);
i2s_ll_mclk_bind_to_tx_clk(hal->dev); i2s_ll_mclk_bind_to_tx_clk(hal->dev);
@ -92,7 +64,7 @@ void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *cl
void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src)
{ {
i2s_ll_mclk_div_t mclk_div = {}; hal_utils_clk_div_t mclk_div = {};
#if SOC_I2S_HW_VERSION_2 #if SOC_I2S_HW_VERSION_2
i2s_ll_rx_enable_clock(hal->dev); i2s_ll_rx_enable_clock(hal->dev);
i2s_ll_mclk_bind_to_rx_clk(hal->dev); i2s_ll_mclk_bind_to_rx_clk(hal->dev);

Wyświetl plik

@ -12,6 +12,16 @@
extern "C" { extern "C" {
#endif #endif
/**
* @brief Integer division operation
*
*/
typedef enum {
HAL_DIV_ROUND_DOWN, /*!< Round the division down to the floor integer */
HAL_DIV_ROUND_UP, /*!< Round the division up to the ceiling integer */
HAL_DIV_ROUND, /*!< Round the division to the nearest integer (round up if fraction >= 1/2, round down if fraction < 1/2) */
} hal_utils_div_round_opt_t;
/** /**
* @brief Clock infomation * @brief Clock infomation
* *
@ -21,7 +31,11 @@ typedef struct {
uint32_t exp_freq_hz; /*!< Expected output clock frequency, unit: Hz */ uint32_t exp_freq_hz; /*!< Expected output clock frequency, unit: Hz */
uint32_t max_integ; /*!< The max value of the integral part */ uint32_t max_integ; /*!< The max value of the integral part */
uint32_t min_integ; /*!< The min value of the integral part, integer range: [min_integ, max_integ) */ uint32_t min_integ; /*!< The min value of the integral part, integer range: [min_integ, max_integ) */
uint32_t max_fract; /*!< The max value of the denominator and numerator, numerator range: [0, max_fract), denominator range: [1, max_fract) */ union {
uint32_t max_fract; /*!< The max value of the denominator and numerator, numerator range: [0, max_fract), denominator range: [1, max_fract)
* Please make sure max_fract > 2 when calculate the division with fractal part */
hal_utils_div_round_opt_t round_opt; /*!< Integer division operation. For the case that doesn't have fractal part, set this field to the to specify the rounding method */
};
} hal_utils_clk_info_t; } hal_utils_clk_info_t;
/** /**
@ -29,36 +43,47 @@ typedef struct {
* *
*/ */
typedef struct { typedef struct {
uint32_t integ; /*!< Integer part of division */ uint32_t integer; /*!< Integer part of division */
uint32_t denom; /*!< Denominator part of division */ uint32_t denominator; /*!< Denominator part of division */
uint32_t numer; /*!< Numerator part of division */ uint32_t numerator; /*!< Numerator part of division */
} hal_utils_clk_div_t; } hal_utils_clk_div_t;
/** /**
* @brief Calculate the clock division * @brief Calculate the clock division with fractal part fast
* @note Speed first algorithm, Time complexity O(log n). * @note Speed first algorithm, Time complexity O(log n).
* About 8~10 times faster than the accurate algorithm * About 8~10 times faster than the accurate algorithm
* *
* @param[in] clk_info The clock infomation * @param[in] clk_info The clock infomation
* @param[out] clk_div The clock division * @param[out] clk_div The clock division with integral and fractal part
* @return * @return
* - 0: Failed to get the result because the division is out of range * - 0: Failed to get the result because the division is out of range
* - others: The real output clock frequency * - others: The real output clock frequency
*/ */
uint32_t hal_utils_calc_clk_div_fast(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div); uint32_t hal_utils_calc_clk_div_frac_fast(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div);
/** /**
* @brief Calculate the clock division * @brief Calculate the clock division with fractal part accurately
* @note Accuracy first algorithm, Time complexity O(n). * @note Accuracy first algorithm, Time complexity O(n).
* About 1~hundreds times more accurate than the fast algorithm * About 1~hundreds times more accurate than the fast algorithm
* *
* @param[in] clk_info The clock infomation * @param[in] clk_info The clock infomation
* @param[out] clk_div The clock division * @param[out] clk_div The clock division with integral and fractal part
* @return * @return
* - 0: Failed to get the result because the division is out of range * - 0: Failed to get the result because the division is out of range
* - others: The real output clock frequency * - others: The real output clock frequency
*/ */
uint32_t hal_utils_calc_clk_div_accurate(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div); uint32_t hal_utils_calc_clk_div_frac_accurate(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div);
/**
* @brief Calculate the clock division without fractal part
*
* @param[in] clk_info The clock infomation
* @param[out] int_div The clock integral division
* @return
* - 0: Failed to get the result because the division is out of range
* - others: The real output clock frequency
*/
uint32_t hal_utils_calc_clk_div_integer(const hal_utils_clk_info_t *clk_info, uint32_t *int_div);
#ifdef __cplusplus #ifdef __cplusplus
} }

Wyświetl plik

@ -130,7 +130,7 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id);
* @param mclk module clock * @param mclk module clock
* @param mclk_div mclk division coefficients, including integer part and decimal part * @param mclk_div mclk division coefficients, including integer part and decimal part
*/ */
void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, i2s_ll_mclk_div_t *mclk_div); void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_clk_div_t *mclk_div);
/** /**
* @brief Set tx channel clock * @brief Set tx channel clock

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -7,31 +7,13 @@
#include "hal/lcd_hal.h" #include "hal/lcd_hal.h"
#include "hal/lcd_ll.h" #include "hal/lcd_ll.h"
#include "hal/log.h" #include "hal/log.h"
#include "hal/hal_utils.h"
void lcd_hal_init(lcd_hal_context_t *hal, int id) void lcd_hal_init(lcd_hal_context_t *hal, int id)
{ {
hal->dev = LCD_LL_GET_HW(id); hal->dev = LCD_LL_GET_HW(id);
} }
/**
* @brief helper function, calculate the Greatest Common Divisor
* @note gcd(a, b) = gcd(b, a % b)
* @param a bigger value
* @param b smaller value
* @return result of gcd(a, b)
*/
__attribute__((always_inline))
static inline uint32_t _gcd(uint32_t a, uint32_t b)
{
uint32_t c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return b;
}
uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uint32_t expect_pclk_freq_hz, int lcd_clk_flags) uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uint32_t expect_pclk_freq_hz, int lcd_clk_flags)
{ {
// lcd_clk = module_clock_src / (n + b / a) // lcd_clk = module_clock_src / (n + b / a)
@ -40,30 +22,19 @@ uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uin
if (mo == 1 && !(lcd_clk_flags & LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK)) { if (mo == 1 && !(lcd_clk_flags & LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK)) {
mo = 2; mo = 2;
} }
uint32_t n = src_freq_hz / expect_pclk_freq_hz / mo; hal_utils_clk_info_t lcd_clk_info = {
uint32_t a = 0; .src_freq_hz = src_freq_hz,
uint32_t b = 0; .exp_freq_hz = expect_pclk_freq_hz * mo,
// delta_hz / expect_pclk_freq_hz <==> b / a .max_integ = LCD_LL_CLK_FRAC_DIV_N_MAX,
uint32_t delta_hz = src_freq_hz / mo - expect_pclk_freq_hz * n; .min_integ = 2,
// fractional divider .max_fract = LCD_LL_CLK_FRAC_DIV_AB_MAX,
if (delta_hz) { };
uint32_t gcd = _gcd(expect_pclk_freq_hz, delta_hz); hal_utils_clk_div_t lcd_clk_div = {};
a = expect_pclk_freq_hz / gcd; uint32_t real_freq = hal_utils_calc_clk_div_frac_fast(&lcd_clk_info, &lcd_clk_div);
b = delta_hz / gcd; HAL_EARLY_LOGD("lcd_hal", "n=%"PRIu32",a=%"PRIu32",b=%"PRIu32",mo=%"PRIu32, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator, mo);
// normalize div_a and div_b
uint32_t d = a / LCD_LL_CLK_FRAC_DIV_AB_MAX + 1;
a /= d;
b /= d;
}
HAL_EARLY_LOGD("lcd_hal", "n=%"PRIu32",a=%"PRIu32",b=%"PRIu32",mo=%"PRIu32"", n, a, b, mo); lcd_ll_set_group_clock_coeff(hal->dev, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
lcd_ll_set_group_clock_coeff(hal->dev, n, a, b);
lcd_ll_set_pixel_clock_prescale(hal->dev, mo); lcd_ll_set_pixel_clock_prescale(hal->dev, mo);
if (delta_hz) { return real_freq / mo;
return ((uint64_t)src_freq_hz * a) / (n * a + b) / mo;
} else {
return src_freq_hz / n / mo;
}
} }

Wyświetl plik

@ -0,0 +1,10 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(COMPONENTS main)
project(test_hal_utils)

Wyświetl plik

@ -0,0 +1,2 @@
| Supported Targets | Linux |
| ----------------- | ----- |

Wyświetl plik

@ -0,0 +1,5 @@
idf_component_register(SRCS "test_app_main.c"
"test_calc_clk_div.c"
INCLUDE_DIRS "."
REQUIRES unity hal
WHOLE_ARCHIVE)

Wyświetl plik

@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "unity.h"
#include "unity_test_runner.h"
void app_main(void)
{
/**
* _ _ _ _ _ _ _____ ___ _ ____
* | | | | / \ | | | | | |_ _|_ _| | / ___|
* | |_| | / _ \ | | | | | | | | | || | \___ \
* | _ |/ ___ \| |___ | |_| | | | | || |___ ___) |
* |_| |_/_/ \_\_____| \___/ |_| |___|_____|____/
*/
printf(" _ _ _ _ _ _ _____ ___ _ ____ \r\n");
printf(" | | | | / \\ | | | | | |_ _|_ _| | / ___| \r\n");
printf(" | |_| | / _ \\ | | | | | | | | | || | \\___ \\ \r\n");
printf(" | _ |/ ___ \\| |___ | |_| | | | | || |___ ___) |\r\n");
printf(" |_| |_/_/ \\_\\_____| \\___/ |_| |___|_____|____/ \r\n");
unity_run_menu();
}

Wyświetl plik

@ -0,0 +1,150 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "unity.h"
#include "hal/hal_utils.h"
TEST_CASE("test_integral_division", "[clk_div]")
{
uint32_t int_div = 0;
hal_utils_clk_info_t clk_info = {
.src_freq_hz = 80 * 1000 * 1000,
.exp_freq_hz = 57 * 1000 * 1000,
.max_integ = 256,
.min_integ = 1,
.round_opt = 0, // round down
};
// Round down test
uint32_t real_freq = 0;
real_freq = hal_utils_calc_clk_div_integer(&clk_info, &int_div);
TEST_ASSERT_EQUAL_UINT32(1, int_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.src_freq_hz, real_freq);
// Normal round test
clk_info.round_opt = 2;
real_freq = hal_utils_calc_clk_div_integer(&clk_info, &int_div);
TEST_ASSERT_EQUAL_UINT32(2, int_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.src_freq_hz / 2, real_freq);
clk_info.exp_freq_hz = 60 * 1000 * 1000;
real_freq = hal_utils_calc_clk_div_integer(&clk_info, &int_div);
TEST_ASSERT_EQUAL_UINT32(2, int_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.src_freq_hz / 2, real_freq);
clk_info.exp_freq_hz = 63 * 1000 * 1000;
real_freq = hal_utils_calc_clk_div_integer(&clk_info, &int_div);
TEST_ASSERT_EQUAL_UINT32(1, int_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.src_freq_hz, real_freq);
// Round up test
clk_info.round_opt = 1;
real_freq = hal_utils_calc_clk_div_integer(&clk_info, &int_div);
TEST_ASSERT_EQUAL_UINT32(2, int_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.src_freq_hz / 2, real_freq);
// Integral division
clk_info.exp_freq_hz = 40 * 1000 * 1000;
real_freq = hal_utils_calc_clk_div_integer(&clk_info, &int_div);
TEST_ASSERT_EQUAL_UINT32(2, int_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.src_freq_hz / 2, real_freq);
clk_info.round_opt = 0;
real_freq = hal_utils_calc_clk_div_integer(&clk_info, &int_div);
TEST_ASSERT_EQUAL_UINT32(2, int_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.src_freq_hz / 2, real_freq);
clk_info.round_opt = 2;
real_freq = hal_utils_calc_clk_div_integer(&clk_info, &int_div);
TEST_ASSERT_EQUAL_UINT32(2, int_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.src_freq_hz / 2, real_freq);
}
TEST_CASE("test_fractal_division", "[clk_div]")
{
hal_utils_clk_div_t clk_div = {};
hal_utils_clk_info_t clk_info = {
.src_freq_hz = 160 * 1000 * 1000,
.exp_freq_hz = 16 * 1024 * 1024,
.max_integ = 256,
.min_integ = 1,
.max_fract = 512,
};
uint32_t real_freq = 0;
// Fractal division with error
real_freq = hal_utils_calc_clk_div_frac_fast(&clk_info, &clk_div);
TEST_ASSERT_EQUAL_UINT32(9, clk_div.integer);
TEST_ASSERT_UINT32_WITHIN(clk_info.exp_freq_hz * 0.001, clk_info.exp_freq_hz, real_freq);
real_freq = hal_utils_calc_clk_div_frac_accurate(&clk_info, &clk_div);
TEST_ASSERT_EQUAL_UINT32(9, clk_div.integer);
TEST_ASSERT_UINT32_WITHIN(clk_info.exp_freq_hz * 0.0001, clk_info.exp_freq_hz, real_freq);
// Fractal division with no error
clk_info.exp_freq_hz = 50 * 1000 * 1000;
real_freq = hal_utils_calc_clk_div_frac_fast(&clk_info, &clk_div);
TEST_ASSERT_EQUAL_UINT32(3, clk_div.integer);
TEST_ASSERT_EQUAL_UINT32(clk_info.exp_freq_hz, real_freq);
real_freq = hal_utils_calc_clk_div_frac_accurate(&clk_info, &clk_div);
TEST_ASSERT_EQUAL_UINT32(3, clk_div.integer);
TEST_ASSERT_EQUAL_UINT32(clk_info.exp_freq_hz, real_freq);
// Integral division
clk_info.exp_freq_hz = 40 * 1000 * 1000;
real_freq = hal_utils_calc_clk_div_frac_fast(&clk_info, &clk_div);
TEST_ASSERT_EQUAL_UINT32(4, clk_div.integer);
TEST_ASSERT_EQUAL_UINT32(0, clk_div.numerator);
TEST_ASSERT_EQUAL_UINT32(clk_info.exp_freq_hz, real_freq);
real_freq = hal_utils_calc_clk_div_frac_accurate(&clk_info, &clk_div);
TEST_ASSERT_EQUAL_UINT32(4, clk_div.integer);
TEST_ASSERT_EQUAL_UINT32(0, clk_div.numerator);
TEST_ASSERT_EQUAL_UINT32(clk_info.exp_freq_hz, real_freq);
}
TEST_CASE("test_fault_division", "[clk_div]")
{
hal_utils_clk_div_t clk_div = {};
hal_utils_clk_info_t clk_info = {
.src_freq_hz = 160 * 1000 * 1000,
.exp_freq_hz = 1250 * 1000,
.max_integ = 128,
.min_integ = 2,
.max_fract = 512,
};
uint32_t real_freq = 0;
// Equal to the max integer
real_freq = hal_utils_calc_clk_div_frac_fast(&clk_info, &clk_div);
TEST_ASSERT_FALSE(real_freq);
real_freq = hal_utils_calc_clk_div_frac_accurate(&clk_info, &clk_div);
TEST_ASSERT_FALSE(real_freq);
// Exceed the max integer
clk_info.exp_freq_hz = 1000 * 1000;
real_freq = hal_utils_calc_clk_div_frac_fast(&clk_info, &clk_div);
TEST_ASSERT_FALSE(real_freq);
real_freq = hal_utils_calc_clk_div_frac_accurate(&clk_info, &clk_div);
TEST_ASSERT_FALSE(real_freq);
// Blow the min integer
clk_info.exp_freq_hz = 125 * 1000 * 1000;
real_freq = hal_utils_calc_clk_div_frac_fast(&clk_info, &clk_div);
TEST_ASSERT_FALSE(real_freq);
real_freq = hal_utils_calc_clk_div_frac_accurate(&clk_info, &clk_div);
TEST_ASSERT_FALSE(real_freq);
// Equal to the min integer
clk_info.exp_freq_hz = 80 * 1000 * 1000;
real_freq = hal_utils_calc_clk_div_frac_fast(&clk_info, &clk_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.exp_freq_hz, real_freq);
real_freq = hal_utils_calc_clk_div_frac_accurate(&clk_info, &clk_div);
TEST_ASSERT_EQUAL_UINT32(clk_info.exp_freq_hz, real_freq);
// divide 0 case
clk_info.exp_freq_hz = 200 * 1000 * 1000;
clk_info.min_integ = 0;
real_freq = hal_utils_calc_clk_div_frac_fast(&clk_info, &clk_div);
TEST_ASSERT_FALSE(real_freq);
real_freq = hal_utils_calc_clk_div_frac_accurate(&clk_info, &clk_div);
TEST_ASSERT_FALSE(real_freq);
}

Wyświetl plik

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import pytest
from pytest_embedded import Dut
@pytest.mark.linux
@pytest.mark.host_test
def test_hal_utils(dut: Dut) -> None:
dut.run_all_single_board_cases()

Wyświetl plik

@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="linux"
CONFIG_ESP_TASK_WDT_EN=n