mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
refactor(hal): use hal utils to calculate clock division
This commit is contained in:
parent
9bec9ccade
commit
dd4072a80c
@ -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);
|
||||
|
||||
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_ll_tx_set_mclk(s_ddp->periph_dev, &mclk_div_coeff);
|
||||
i2s_ll_tx_set_bck_div_num(s_ddp->periph_dev, bclk_div);
|
||||
|
@ -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
|
||||
*/
|
||||
@ -18,6 +18,7 @@
|
||||
#include "hal/spi_ll.h"
|
||||
#include "hal/dac_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/hal_utils.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "soc/soc.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");
|
||||
|
||||
/* 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 */
|
||||
uint32_t clk_div = digi_ctrl_freq / fsclk;
|
||||
uint32_t mod = digi_ctrl_freq % fsclk;
|
||||
uint32_t a = 0;
|
||||
uint32_t b = 1;
|
||||
if (mod == 0) {
|
||||
goto finish;
|
||||
}
|
||||
uint32_t min_diff = mod + 1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* Step 3: Calculate the coefficients of ADC digital controller divider */
|
||||
hal_utils_clk_info_t adc_clk_info = {
|
||||
.src_freq_hz = digi_ctrl_freq / interval,
|
||||
.exp_freq_hz = freq_hz,
|
||||
.max_integ = 257,
|
||||
.min_integ = 1,
|
||||
.max_fract = 64,
|
||||
};
|
||||
hal_utils_clk_div_t adc_clk_div = {};
|
||||
hal_utils_calc_clk_div_frac_accurate(&adc_clk_info, &adc_clk_div);
|
||||
|
||||
finish:
|
||||
/* Step 4: Set the clock coefficients */
|
||||
dac_ll_digi_clk_inv(true);
|
||||
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);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -9,3 +9,4 @@ archive: libhal.a
|
||||
entries:
|
||||
if LCD_RGB_ISR_IRAM_SAFE = y:
|
||||
lcd_hal: lcd_hal_cal_pclk_freq (noflash)
|
||||
hal_utils: hal_utils_calc_clk_div_frac_fast (noflash)
|
||||
|
7
components/hal/.build-test-rules.yml
Normal file
7
components/hal/.build-test-rules.yml
Normal file
@ -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
|
@ -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 = sample_freq_hz * 2;
|
||||
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_ll_rx_set_mclk(hal->dev, &mclk_div);
|
||||
i2s_ll_rx_set_bck_div_num(hal->dev, bclk_div);
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -30,8 +32,8 @@ extern "C" {
|
||||
#define I2S_LL_AD_BCK_FACTOR (2)
|
||||
#define I2S_LL_PDM_BCK_FACTOR (64)
|
||||
|
||||
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6)
|
||||
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
|
||||
#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_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)
|
||||
|
||||
@ -48,16 +50,6 @@ extern "C" {
|
||||
#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
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
@ -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 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
|
||||
* Set to particular coefficients first then update to the target coefficients,
|
||||
* otherwise the clock division might be inaccurate.
|
||||
* 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, 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 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
|
||||
i2s_ll_tx_set_mclk(hw, mclk_div);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -29,22 +30,12 @@ extern "C" {
|
||||
#define I2S_LL_TDM_CH_MASK (0xffff)
|
||||
#define I2S_LL_PDM_BCK_FACTOR (64)
|
||||
|
||||
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9)
|
||||
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
|
||||
#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_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_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.
|
||||
*
|
||||
@ -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 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
|
||||
* 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_yn1 = 0;
|
||||
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
|
||||
if (mclk_div->denom && mclk_div->numer) {
|
||||
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
|
||||
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
|
||||
div_x = mclk_div->denom / div_z - 1;
|
||||
div_y = mclk_div->denom % div_z;
|
||||
if (mclk_div->denominator && mclk_div->numerator) {
|
||||
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
|
||||
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
|
||||
div_x = mclk_div->denominator / div_z - 1;
|
||||
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 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
|
||||
* 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_yn1 = 0;
|
||||
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
|
||||
if (mclk_div->denom && mclk_div->numer) {
|
||||
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
|
||||
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
|
||||
div_x = mclk_div->denom / div_z - 1;
|
||||
div_y = mclk_div->denom % div_z;
|
||||
if (mclk_div->denominator && mclk_div->numerator) {
|
||||
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
|
||||
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
|
||||
div_x = mclk_div->denominator / div_z - 1;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "soc/pcr_struct.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -30,22 +31,12 @@ extern "C" {
|
||||
#define I2S_LL_TDM_CH_MASK (0xffff)
|
||||
#define I2S_LL_PDM_BCK_FACTOR (64)
|
||||
|
||||
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9)
|
||||
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
|
||||
#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_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_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.
|
||||
*
|
||||
@ -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 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
|
||||
* 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_yn1 = 0;
|
||||
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
|
||||
if (mclk_div->denom && mclk_div->numer) {
|
||||
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
|
||||
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
|
||||
div_x = mclk_div->denom / div_z - 1;
|
||||
div_y = mclk_div->denom % div_z;
|
||||
if (mclk_div->denominator && mclk_div->numerator) {
|
||||
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
|
||||
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
|
||||
div_x = mclk_div->denominator / div_z - 1;
|
||||
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 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
|
||||
* 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_yn1 = 0;
|
||||
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
|
||||
if (mclk_div->denom && mclk_div->numer) {
|
||||
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
|
||||
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
|
||||
div_x = mclk_div->denom / div_z - 1;
|
||||
div_y = mclk_div->denom % div_z;
|
||||
if (mclk_div->denominator && mclk_div->numerator) {
|
||||
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
|
||||
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
|
||||
div_x = mclk_div->denominator / div_z - 1;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "soc/pcr_struct.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -30,23 +31,13 @@ extern "C" {
|
||||
#define I2S_LL_TDM_CH_MASK (0xffff)
|
||||
#define I2S_LL_PDM_BCK_FACTOR (64)
|
||||
|
||||
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9)
|
||||
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
|
||||
#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_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_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
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
@ -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 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
|
||||
* 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_yn1 = 0;
|
||||
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
|
||||
if (mclk_div->denom && mclk_div->numer) {
|
||||
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
|
||||
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
|
||||
div_x = mclk_div->denom / div_z - 1;
|
||||
div_y = mclk_div->denom % div_z;
|
||||
if (mclk_div->denominator && mclk_div->numerator) {
|
||||
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
|
||||
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
|
||||
div_x = mclk_div->denominator / div_z - 1;
|
||||
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 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
|
||||
* 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_yn1 = 0;
|
||||
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
|
||||
if (mclk_div->denom && mclk_div->numer) {
|
||||
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
|
||||
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
|
||||
div_x = mclk_div->denom / div_z - 1;
|
||||
div_y = mclk_div->denom % div_z;
|
||||
if (mclk_div->denominator && mclk_div->numerator) {
|
||||
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
|
||||
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
|
||||
div_x = mclk_div->denominator / div_z - 1;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -30,8 +31,9 @@ extern "C" {
|
||||
|
||||
#define I2S_LL_BCK_MAX_PRESCALE (64)
|
||||
|
||||
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6)
|
||||
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
|
||||
#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_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_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_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
|
||||
*
|
||||
@ -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 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
|
||||
* Set to particular coefficients first then update to the target coefficients,
|
||||
* otherwise the clock division might be inaccurate.
|
||||
* 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, 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 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
|
||||
i2s_ll_tx_set_mclk(hw, mclk_div);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -30,22 +31,12 @@ extern "C" {
|
||||
#define I2S_LL_TDM_CH_MASK (0xffff)
|
||||
#define I2S_LL_PDM_BCK_FACTOR (64)
|
||||
|
||||
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9)
|
||||
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
|
||||
#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_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_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.
|
||||
*
|
||||
@ -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 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
|
||||
* 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_yn1 = 0;
|
||||
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
|
||||
if (mclk_div->denom && mclk_div->numer) {
|
||||
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
|
||||
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
|
||||
div_x = mclk_div->denom / div_z - 1;
|
||||
div_y = mclk_div->denom % div_z;
|
||||
if (mclk_div->denominator && mclk_div->numerator) {
|
||||
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
|
||||
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
|
||||
div_x = mclk_div->denominator / div_z - 1;
|
||||
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 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
|
||||
* 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_yn1 = 0;
|
||||
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
|
||||
if (mclk_div->denom && mclk_div->numer) {
|
||||
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
|
||||
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
|
||||
div_x = mclk_div->denom / div_z - 1;
|
||||
div_y = mclk_div->denom % div_z;
|
||||
if (mclk_div->denominator && mclk_div->numerator) {
|
||||
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
|
||||
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
|
||||
div_x = mclk_div->denominator / div_z - 1;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "hal/hal_utils.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
/**
|
||||
* @brief helper function, calculate the Greatest Common Divisor
|
||||
@ -31,20 +32,18 @@ static inline uint32_t _sub_abs(uint32_t a, uint32_t b)
|
||||
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_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 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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -55,12 +54,20 @@ uint32_t hal_utils_calc_clk_div_fast(const hal_utils_clk_info_t *clk_info, hal_u
|
||||
// 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 (div_integ < clk_info->min_integ || div_integ >= clk_info->max_integ || div_integ == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Assign result
|
||||
clk_div->integ = div_integ;
|
||||
clk_div->denom = div_denom;
|
||||
clk_div->numer = div_numer;
|
||||
clk_div->integer = div_integ;
|
||||
clk_div->denominator = div_denom;
|
||||
clk_div->numerator = div_numer;
|
||||
|
||||
// Return the actual frequency
|
||||
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;
|
||||
}
|
||||
|
||||
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_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 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) {
|
||||
// Carry bit if the decimal is greater than 1.0 - 1.0 / (PARLIO_LL_CLK_DIVIDER_MAX * 2)
|
||||
if (freq_error < clk_info->exp_freq_hz - clk_info->exp_freq_hz / (clk_info->max_fract * 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 - 1) * 2) {
|
||||
// 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;
|
||||
sub = _sub_abs(clk_info->exp_freq_hz * b, freq_error * a);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Assign result
|
||||
clk_div->integ = div_integ;
|
||||
clk_div->denom = div_denom;
|
||||
clk_div->numer = div_numer;
|
||||
clk_div->integer = div_integ;
|
||||
clk_div->denominator = div_denom;
|
||||
clk_div->numerator = div_numer;
|
||||
|
||||
// Return the actual frequency
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -29,46 +29,18 @@ static const float cut_off_coef[21][3] = {
|
||||
*
|
||||
* @param sclk system clock
|
||||
* @param mclk module clock
|
||||
* @param integer output the integer part of the division
|
||||
* @param denominator output the denominator part of the division
|
||||
* @param numerator output the numerator part of the division
|
||||
* @param mclk_div output the mclk division coefficients
|
||||
*/
|
||||
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;
|
||||
int mb = 0;
|
||||
int min = INT32_MAX;
|
||||
uint32_t div_denom = 1;
|
||||
uint32_t div_numer = 0;
|
||||
uint32_t div_inter = sclk / mclk;
|
||||
uint32_t freq_diff = sclk % mclk;
|
||||
|
||||
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;
|
||||
hal_utils_clk_info_t i2s_clk_info = {
|
||||
.src_freq_hz = sclk,
|
||||
.exp_freq_hz = mclk,
|
||||
.max_integ = I2S_LL_CLK_FRAC_DIV_N_MAX,
|
||||
.min_integ = 1,
|
||||
.max_fract = I2S_LL_CLK_FRAC_DIV_AB_MAX,
|
||||
};
|
||||
hal_utils_calc_clk_div_frac_accurate(&i2s_clk_info, mclk_div);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
i2s_ll_mclk_div_t mclk_div = {};
|
||||
hal_utils_clk_div_t mclk_div = {};
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
i2s_ll_tx_enable_clock(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)
|
||||
{
|
||||
i2s_ll_mclk_div_t mclk_div = {};
|
||||
hal_utils_clk_div_t mclk_div = {};
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
i2s_ll_rx_enable_clock(hal->dev);
|
||||
i2s_ll_mclk_bind_to_rx_clk(hal->dev);
|
||||
|
@ -12,6 +12,16 @@
|
||||
extern "C" {
|
||||
#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
|
||||
*
|
||||
@ -21,7 +31,11 @@ typedef struct {
|
||||
uint32_t exp_freq_hz; /*!< Expected output clock frequency, unit: Hz */
|
||||
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 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;
|
||||
|
||||
/**
|
||||
@ -29,36 +43,47 @@ typedef struct {
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t integ; /*!< Integer part of division */
|
||||
uint32_t denom; /*!< Denominator part of division */
|
||||
uint32_t numer; /*!< Numerator part of division */
|
||||
uint32_t integer; /*!< Integer part of division */
|
||||
uint32_t denominator; /*!< Denominator part of division */
|
||||
uint32_t numerator; /*!< Numerator part of division */
|
||||
} 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).
|
||||
* About 8~10 times faster than the accurate algorithm
|
||||
*
|
||||
* @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
|
||||
* - 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_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).
|
||||
* About 1~hundreds times more accurate than the fast algorithm
|
||||
*
|
||||
* @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
|
||||
* - 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_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
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id);
|
||||
* @param mclk module clock
|
||||
* @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
|
||||
|
@ -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
|
||||
*/
|
||||
@ -7,31 +7,13 @@
|
||||
#include "hal/lcd_hal.h"
|
||||
#include "hal/lcd_ll.h"
|
||||
#include "hal/log.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
void lcd_hal_init(lcd_hal_context_t *hal, int 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)
|
||||
{
|
||||
// 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)) {
|
||||
mo = 2;
|
||||
}
|
||||
uint32_t n = src_freq_hz / expect_pclk_freq_hz / mo;
|
||||
uint32_t a = 0;
|
||||
uint32_t b = 0;
|
||||
// delta_hz / expect_pclk_freq_hz <==> b / a
|
||||
uint32_t delta_hz = src_freq_hz / mo - expect_pclk_freq_hz * n;
|
||||
// fractional divider
|
||||
if (delta_hz) {
|
||||
uint32_t gcd = _gcd(expect_pclk_freq_hz, delta_hz);
|
||||
a = expect_pclk_freq_hz / gcd;
|
||||
b = delta_hz / gcd;
|
||||
// normalize div_a and div_b
|
||||
uint32_t d = a / LCD_LL_CLK_FRAC_DIV_AB_MAX + 1;
|
||||
a /= d;
|
||||
b /= d;
|
||||
}
|
||||
hal_utils_clk_info_t lcd_clk_info = {
|
||||
.src_freq_hz = src_freq_hz,
|
||||
.exp_freq_hz = expect_pclk_freq_hz * mo,
|
||||
.max_integ = LCD_LL_CLK_FRAC_DIV_N_MAX,
|
||||
.min_integ = 2,
|
||||
.max_fract = LCD_LL_CLK_FRAC_DIV_AB_MAX,
|
||||
};
|
||||
hal_utils_clk_div_t lcd_clk_div = {};
|
||||
uint32_t real_freq = hal_utils_calc_clk_div_frac_fast(&lcd_clk_info, &lcd_clk_div);
|
||||
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);
|
||||
|
||||
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, n, a, b);
|
||||
lcd_ll_set_group_clock_coeff(hal->dev, lcd_clk_div.integer, lcd_clk_div.denominator, lcd_clk_div.numerator);
|
||||
lcd_ll_set_pixel_clock_prescale(hal->dev, mo);
|
||||
|
||||
if (delta_hz) {
|
||||
return ((uint64_t)src_freq_hz * a) / (n * a + b) / mo;
|
||||
} else {
|
||||
return src_freq_hz / n / mo;
|
||||
}
|
||||
return real_freq / mo;
|
||||
}
|
||||
|
10
components/hal/test_apps/hal_utils/CMakeLists.txt
Normal file
10
components/hal/test_apps/hal_utils/CMakeLists.txt
Normal file
@ -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)
|
2
components/hal/test_apps/hal_utils/README.md
Normal file
2
components/hal/test_apps/hal_utils/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | Linux |
|
||||
| ----------------- | ----- |
|
5
components/hal/test_apps/hal_utils/main/CMakeLists.txt
Normal file
5
components/hal/test_apps/hal_utils/main/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
idf_component_register(SRCS "test_app_main.c"
|
||||
"test_calc_clk_div.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES unity hal
|
||||
WHOLE_ARCHIVE)
|
27
components/hal/test_apps/hal_utils/main/test_app_main.c
Normal file
27
components/hal/test_apps/hal_utils/main/test_app_main.c
Normal file
@ -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();
|
||||
}
|
150
components/hal/test_apps/hal_utils/main/test_calc_clk_div.c
Normal file
150
components/hal/test_apps/hal_utils/main/test_calc_clk_div.c
Normal file
@ -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);
|
||||
}
|
11
components/hal/test_apps/hal_utils/pytest_hal_utils.py
Normal file
11
components/hal/test_apps/hal_utils/pytest_hal_utils.py
Normal file
@ -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()
|
2
components/hal/test_apps/hal_utils/sdkconfig.defaults
Normal file
2
components/hal/test_apps/hal_utils/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
Loading…
Reference in New Issue
Block a user