From cfc73a6de7e748842bcfce3057ac65e3bac26c73 Mon Sep 17 00:00:00 2001 From: redchenjs Date: Tue, 18 Jun 2019 13:52:36 +0800 Subject: [PATCH 1/2] i2s: fix a bug when calculating i2s apll parameters Closes https://github.com/espressif/esp-idf/issues/2634 Closes https://github.com/espressif/esp-idf/issues/3380 Fixes https://github.com/espressif/esp-idf/issues/3407 --- components/driver/i2s.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 085f19b89..4592c96bb 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -251,7 +251,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, 0); min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, 31); avg = (max_rate + min_rate)/2; - if(abs(avg - rate) < min_diff) { + if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *sdm2 = _sdm2; } @@ -261,11 +261,21 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, *sdm2, _odir); min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, *sdm2, _odir); avg = (max_rate + min_rate)/2; - if(abs(avg - rate) < min_diff) { + if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *odir = _odir; } } + min_diff = APLL_MAX_FREQ; + for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) { + max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, *odir); + min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, *odir); + avg = (max_rate + min_rate)/2; + if (abs(avg - rate) < min_diff) { + min_diff = abs(avg - rate); + *sdm2 = _sdm2; + } + } min_diff = APLL_MAX_FREQ; for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) { From 13e6e9f592cb25f98180dcb5bb4ddb0a9fad8013 Mon Sep 17 00:00:00 2001 From: Ajita Chavan Date: Wed, 19 Jun 2019 16:06:20 +0530 Subject: [PATCH 2/2] i2s: test case for variation in apll clock rate --- components/driver/i2s.c | 9 +++++ components/driver/include/driver/i2s.h | 10 +++++ components/driver/test/test_i2s.c | 53 ++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 4592c96bb..7559a6c56 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -90,6 +90,7 @@ typedef struct { bool use_apll; /*!< I2S use APLL clock */ bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */ int fixed_mclk; /*!< I2S fixed MLCK clock */ + double real_rate; } i2s_obj_t; static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0}; @@ -176,6 +177,12 @@ esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num) return ESP_OK; } +float i2s_get_clk(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + return p_i2s_obj[i2s_num]->real_rate; +} + static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle) { return esp_intr_alloc(ETS_I2S0_INTR_SOURCE + i2s_num, intr_alloc_flags, fn, arg, handle); @@ -463,6 +470,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = m_scale; I2S[i2s_num]->clkm_conf.clka_en = 1; double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir); + p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale; ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0); } else { @@ -473,6 +481,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck; I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck; double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2); + p_i2s_obj[i2s_num]->real_rate = real_rate; ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals); } diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 0957e10cc..6179ec3c1 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -503,6 +503,16 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); */ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch); +/** + * @brief get clock set on particular port number. + * + * @param i2s_num I2S_NUM_0, I2S_NUM_1 + * + * @return + * - actual clock set by i2s driver + */ +float i2s_get_clk(i2s_port_t i2s_num); + /** * @brief Set built-in ADC mode for I2S DMA, this function will initialize ADC pad, * and set ADC parameters. diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 3afb24412..813a906cb 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -9,6 +9,7 @@ #include "freertos/task.h" #include "driver/i2s.h" #include "unity.h" +#include "math.h" #define SAMPLE_RATE (36000) #define SAMPLE_BITS (16) @@ -18,6 +19,7 @@ #define SLAVE_WS_IO 26 #define DATA_IN_IO 21 #define DATA_OUT_IO 22 +#define PERCENT_DIFF 0.0001 /** * i2s initialize test @@ -267,3 +269,54 @@ TEST_CASE("I2S memory leaking test", "[i2s]") vTaskDelay(100 / portTICK_PERIOD_MS); TEST_ASSERT(initial_size == esp_get_free_heap_size()); } + +/* + * The I2S APLL clock variation test used to test the difference between the different sample rates, different bits per sample + * and the APLL clock generate for it. The TEST_CASE passes PERCENT_DIFF variation from the provided sample rate in APLL generated clock + * The percentage difference calculated as (mod((obtained clock rate - desired clock rate)/(desired clock rate))) * 100. + */ +TEST_CASE("I2S APLL clock variation test", "[i2s]") +{ + i2s_pin_config_t pin_config = { + .bck_io_num = MASTER_BCK_IO, + .ws_io_num = MASTER_WS_IO, + .data_out_num = DATA_OUT_IO, + .data_in_num = -1 + }; + + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_I2S, + .dma_buf_count = 6, + .dma_buf_len = 60, + .use_apll = true, + .intr_alloc_flags = 0, + }; + + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); + TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); + TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); + int initial_size = esp_get_free_heap_size(); + + uint32_t sample_rate_arr[8] = { 10675, 11025, 16000, 22050, 32000, 44100, 48000, 96000 }; + int bits_per_sample_arr[3] = { 16, 24, 32 }; + + for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) { + for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) { + i2s_config.sample_rate = sample_rate_arr[i]; + i2s_config.bits_per_sample = bits_per_sample_arr[j]; + + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); + TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); + TEST_ASSERT((fabs((i2s_get_clk(I2S_NUM_0) - sample_rate_arr[i]))/(sample_rate_arr[i]))*100 < PERCENT_DIFF); + TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); + TEST_ASSERT(initial_size == esp_get_free_heap_size()); + } + } + + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT(initial_size == esp_get_free_heap_size()); +}