]> granicus.if.org Git - esp-idf/commitdiff
i2s: test case for variation in apll clock rate
authorAjita Chavan <ajita.chavan@espressif.com>
Wed, 19 Jun 2019 10:36:20 +0000 (16:06 +0530)
committerbot <bot@espressif.com>
Thu, 20 Jun 2019 16:40:58 +0000 (16:40 +0000)
components/driver/i2s.c
components/driver/include/driver/i2s.h
components/driver/test/test_i2s.c

index 2056c43f1fd0c4266b478a86f7901046ddd61630..56c418d153bed7962b8f6fe9610c0d0ea8794d1e 100644 (file)
@@ -89,6 +89,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;
 #ifdef CONFIG_PM_ENABLE
     esp_pm_lock_handle_t pm_lock;
 #endif
@@ -178,6 +179,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);
@@ -465,6 +472,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 {
@@ -475,6 +483,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);
     }
index 59c11978e5daa31e5752665c29dd733f93faa126..c00be6632f9484408c61edadf2bd45549844125b 100644 (file)
@@ -501,6 +501,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.
index 3afb24412f470f653baca6483ad40e23fa94d75e..813a906cb5f960673442c3ba8b6e3a9d96e81a2e 100644 (file)
@@ -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());
+}