Просмотр исходного кода

Merge branch 'bugfix/fix_rmt_tx_multi_channel_test' into 'master'

rmt: simplify the clock configuration with clk_tree API

Closes IDF-6717, IDF-6810, and IDFCI-1606

See merge request espressif/esp-idf!22275
morris 3 лет назад
Родитель
Сommit
14b13e15ae

+ 6 - 15
components/driver/deprecated/rmt_legacy.c

@@ -21,7 +21,7 @@
 #include "soc/soc_memory_layout.h"
 #include "soc/rmt_periph.h"
 #include "soc/rmt_struct.h"
-#include "esp_private/esp_clk.h"
+#include "clk_tree.h"
 #include "hal/rmt_hal.h"
 #include "hal/rmt_ll.h"
 #include "hal/gpio_hal.h"
@@ -58,16 +58,6 @@ static const char *TAG = "rmt(legacy)";
 #define RMT_DECODE_RX_CHANNEL(encode_chan) ((encode_chan - RMT_RX_CHANNEL_ENCODING_START))
 #define RMT_ENCODE_RX_CHANNEL(decode_chan) ((decode_chan + RMT_RX_CHANNEL_ENCODING_START))
 
-#if SOC_RMT_SUPPORT_APB
-#define RMT_DEFAULT_CLOCK_FREQ esp_clk_apb_freq()
-#elif SOC_RMT_SUPPORT_PLL_F80M
-#define RMT_DEFAULT_CLOCK_FREQ (80*1000*1000)
-#elif SOC_RMT_SUPPORT_XTAL
-#define RMT_DEFAULT_CLOCK_FREQ esp_clk_xtal_freq()
-#else
-#error "RMT unknow default clock"
-#endif
-
 typedef struct {
     rmt_hal_context_t hal;
     _lock_t rmt_driver_isr_lock;
@@ -575,19 +565,20 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par
     rmt_ll_enable_mem_access_nonfifo(dev, true);
 
     if (rmt_param->flags & RMT_CHANNEL_FLAGS_AWARE_DFS) {
-        // [clk_tree] TODO: refactor the following code by clk_tree API
 #if SOC_RMT_SUPPORT_XTAL
         // clock src: XTAL_CLK
-        rmt_source_clk_hz = esp_clk_xtal_freq();
+        clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_XTAL, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rmt_source_clk_hz);
         rmt_ll_set_group_clock_src(dev, channel, (rmt_clock_source_t)RMT_BASECLK_XTAL, 1, 0, 0);
 #elif SOC_RMT_SUPPORT_REF_TICK
         // clock src: REF_CLK
-        rmt_source_clk_hz = REF_CLK_FREQ;
+        clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_REF, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rmt_source_clk_hz);
         rmt_ll_set_group_clock_src(dev, channel, (rmt_clock_source_t)RMT_BASECLK_REF, 1, 0, 0);
+#else
+#error "No clock source is aware of DFS"
 #endif
     } else {
         // fallback to use default clock source
-        rmt_source_clk_hz = RMT_DEFAULT_CLOCK_FREQ;
+        clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_DEFAULT, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rmt_source_clk_hz);
         rmt_ll_set_group_clock_src(dev, channel, (rmt_clock_source_t)RMT_BASECLK_DEFAULT, 1, 0, 0);
     }
     RMT_EXIT_CRITICAL();

+ 38 - 57
components/driver/rmt/rmt_common.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -19,7 +19,7 @@
 #include "soc/rmt_periph.h"
 #include "hal/rmt_ll.h"
 #include "driver/gpio.h"
-#include "esp_private/esp_clk.h"
+#include "clk_tree.h"
 #include "esp_private/periph_ctrl.h"
 
 static const char *TAG = "rmt";
@@ -122,65 +122,46 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
     ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_STATE, TAG,
                         "group clock conflict, already is %d but attempt to %d", group->clk_src, clk_src);
 
-    // [clk_tree] TODO: replace the following switch table by clk_tree API
-    switch (clk_src) {
-#if SOC_RMT_SUPPORT_APB
-    case RMT_CLK_SRC_APB:
-        periph_src_clk_hz = esp_clk_apb_freq();
-#if CONFIG_PM_ENABLE
-        sprintf(chan->pm_lock_name, "rmt_%d_%d", group->group_id, channel_id); // e.g. rmt_0_0
-        ret  = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, chan->pm_lock_name, &chan->pm_lock);
-        ESP_RETURN_ON_ERROR(ret, TAG, "create APB_FREQ_MAX lock failed");
-        ESP_LOGD(TAG, "install APB_FREQ_MAX lock for RMT channel (%d,%d)", group->group_id, channel_id);
-#endif // CONFIG_PM_ENABLE
-        break;
-#endif // SOC_RMT_SUPPORT_APB
-#if SOC_RMT_SUPPORT_PLL_F80M
-    case RMT_CLK_SRC_PLL_F80M:
-        periph_src_clk_hz = 80000000;
-#if CONFIG_PM_ENABLE
-        sprintf(chan->pm_lock_name, "rmt_%d_%d", group->group_id, channel_id); // e.g. rmt_0_0
-        // ESP32C6 PLL_F80M is available even when SOC_ROOT_CLK switches from PLL to XTAL, so using NO_LIGHT_SLEEP lock here is sufficient
-        ret  = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, chan->pm_lock_name, &chan->pm_lock);
-        ESP_RETURN_ON_ERROR(ret, TAG, "create NO_LIGHT_SLEEP lock failed");
-        ESP_LOGD(TAG, "install NO_LIGHT_SLEEP lock for RMT channel (%d,%d)", group->group_id, channel_id);
-#endif // CONFIG_PM_ENABLE
-        break;
-#endif // SOC_RMT_SUPPORT_PLL_F80M
-#if SOC_RMT_SUPPORT_AHB
-    case RMT_CLK_SRC_AHB:
-        // TODO: decide which kind of PM lock we should use for such clock
-        periph_src_clk_hz = 48 * 1000 * 1000;
-        break;
-#endif // SOC_RMT_SUPPORT_AHB
-#if SOC_RMT_SUPPORT_XTAL
-    case RMT_CLK_SRC_XTAL:
-        periph_src_clk_hz = esp_clk_xtal_freq();
-#if CONFIG_PM_ENABLE
-        sprintf(chan->pm_lock_name, "rmt_%d_%d", group->group_id, channel_id); // e.g. rmt_0_0
-        // XTAL will be power down in the light sleep (predefined low power modes)
-        // acquire a NO_LIGHT_SLEEP lock here to prevent the system go into light sleep automatically
-        ret  = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, chan->pm_lock_name, &chan->pm_lock);
-        ESP_RETURN_ON_ERROR(ret, TAG, "create NO_LIGHT_SLEEP lock failed");
-        ESP_LOGD(TAG, "install NO_LIGHT_SLEEP lock for RMT channel (%d,%d)", group->group_id, channel_id);
-#endif // CONFIG_PM_ENABLE
-        break;
-#endif // SOC_RMT_SUPPORT_XTAL
-#if SOC_RMT_SUPPORT_REF_TICK
-    case RMT_CLK_SRC_REF_TICK:
-        periph_src_clk_hz = REF_CLK_FREQ;
-        break;
-#endif // SOC_RMT_SUPPORT_REF_TICK
+    // TODO: [clk_tree] to use a generic clock enable/disable or acquire/release function for all clock source
 #if SOC_RMT_SUPPORT_RC_FAST
-    case RMT_CLK_SRC_RC_FAST:
+    if (clk_src == RMT_CLK_SRC_RC_FAST) {
+        // RC_FAST clock is not enabled automatically on start up, we enable it here manually.
+        // Note there's a ref count in the enable/disable function, we must call them in pair in the driver.
         periph_rtc_dig_clk8m_enable();
-        periph_src_clk_hz = periph_rtc_dig_clk8m_get_freq();
-        break;
+    }
 #endif // SOC_RMT_SUPPORT_RC_FAST
-    default:
-        ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "clock source %d is not supported", clk_src);
-        break;
+
+    // get clock source frequency
+    ESP_RETURN_ON_ERROR(clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz),
+                        TAG, "get clock source frequency failed");
+
+#if CONFIG_PM_ENABLE
+    bool need_pm_lock = true;
+    // to make the RMT work reliable, the source clock must stay alive and unchanged
+    // driver will create different pm lock for that purpose, according to different clock source
+    esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP;
+
+#if SOC_RMT_SUPPORT_RC_FAST
+    if (clk_src == RMT_CLK_SRC_RC_FAST) {
+        // RC_FAST won't be turn off in sleep and won't change its frequency during DFS
+        need_pm_lock = false;
+    }
+#endif // SOC_RMT_SUPPORT_RC_FAST
+
+#if SOC_RMT_SUPPORT_APB
+    if (clk_src == RMT_CLK_SRC_APB) {
+        // APB clock frequency can be changed during DFS
+        pm_lock_type = ESP_PM_APB_FREQ_MAX;
     }
+#endif // SOC_RMT_SUPPORT_APB
+
+    if (need_pm_lock) {
+        sprintf(chan->pm_lock_name, "rmt_%d_%d", group->group_id, channel_id); // e.g. rmt_0_0
+        ret  = esp_pm_lock_create(pm_lock_type, 0, chan->pm_lock_name, &chan->pm_lock);
+        ESP_RETURN_ON_ERROR(ret, TAG, "create pm lock failed");
+    }
+#endif // CONFIG_PM_ENABLE
+
     // no division for group clock source, to achieve highest resolution
     rmt_ll_set_group_clock_src(group->hal.regs, channel_id, clk_src, 1, 1, 0);
     group->resolution_hz = periph_src_clk_hz;

+ 2 - 2
components/driver/test_apps/gptimer/main/test_gptimer.c

@@ -90,7 +90,7 @@ TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]")
             TEST_ESP_OK(gptimer_get_raw_count(timers[i], &value));
             // convert the raw count to us
             value = value * 1000000 / timer_resolution_hz[i];
-            TEST_ASSERT_UINT_WITHIN(1000, 20000, value);
+            TEST_ASSERT_UINT_WITHIN(1100, 20000, value);
         }
         printf("stop timers\r\n");
         for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
@@ -139,7 +139,7 @@ TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]")
  * between the alarm triggering and the execution of the callback that actually stops the gptimer.
  */
 #if CONFIG_PM_ENABLE
-#define GPTIMER_STOP_ON_ALARM_COUNT_DELTA  100
+#define GPTIMER_STOP_ON_ALARM_COUNT_DELTA  150
 #else
 #define GPTIMER_STOP_ON_ALARM_COUNT_DELTA  50
 #endif // CONFIG_PM_ENABLE

+ 4 - 1
components/driver/test_apps/gptimer/sdkconfig.defaults

@@ -1,4 +1,7 @@
+# This file was generated using idf.py save-defconfig. It can be edited manually.
+# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
+#
+# CONFIG_ESP_TASK_WDT_INIT is not set
 CONFIG_FREERTOS_HZ=1000
-CONFIG_ESP_TASK_WDT=n
 # Disable nano printf, because we need to print the timer count in %llu format
 CONFIG_NEWLIB_NANO_FORMAT=n

+ 3 - 7
components/driver/test_apps/rmt/main/test_rmt_tx.c

@@ -464,13 +464,9 @@ static bool test_rmt_tx_done_cb_record_time(rmt_channel_handle_t channel, const
 static void test_rmt_multi_channels_trans(size_t channel0_mem_block_symbols, size_t channel1_mem_block_symbols, bool channel0_with_dma, bool channel1_with_dma)
 {
 #define TEST_RMT_CHANS 2
-#define TEST_LED_NUM   24
-#define TEST_STOP_TIME_NO_SYNCHRO_DELTA     150
-#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
-#define TEST_STOP_TIME_SYNCHRO_DELTA        400
-#else
-#define TEST_STOP_TIME_SYNCHRO_DELTA        10
-#endif // #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
+#define TEST_LED_NUM   1
+#define TEST_STOP_TIME_NO_SYNCHRO_DELTA     250
+#define TEST_STOP_TIME_SYNCHRO_DELTA        60
     rmt_tx_channel_config_t tx_channel_cfg = {
         .clk_src = RMT_CLK_SRC_DEFAULT,
         .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution)

+ 1 - 0
components/driver/test_apps/rmt/sdkconfig.ci.release

@@ -1,5 +1,6 @@
 CONFIG_PM_ENABLE=y
 CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
+CONFIG_PM_DFS_INIT_AUTO=y
 CONFIG_COMPILER_OPTIMIZATION_SIZE=y
 CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
 CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

+ 4 - 1
components/driver/test_apps/rmt/sdkconfig.defaults

@@ -1,4 +1,7 @@
+# This file was generated using idf.py save-defconfig. It can be edited manually.
+# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
+#
+# CONFIG_ESP_TASK_WDT_INIT is not set
 CONFIG_FREERTOS_HZ=1000
-CONFIG_ESP_TASK_WDT=n
 CONFIG_UNITY_ENABLE_64BIT=y
 CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096

+ 0 - 4
components/soc/esp32c6/include/soc/Kconfig.soc_caps.in

@@ -615,10 +615,6 @@ config SOC_RMT_SUPPORT_XTAL
     bool
     default y
 
-config SOC_RMT_SUPPORT_PLL_F80M
-    bool
-    default y
-
 config SOC_RMT_SUPPORT_RC_FAST
     bool
     default y

+ 0 - 1
components/soc/esp32c6/include/soc/soc_caps.h

@@ -262,7 +262,6 @@
 #define SOC_RMT_SUPPORT_TX_SYNCHRO            1  /*!< Support coordinate a group of TX channels to start simultaneously */
 #define SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY  1  /*!< TX carrier can be modulated to data phase only */
 #define SOC_RMT_SUPPORT_XTAL                  1  /*!< Support set XTAL clock as the RMT clock source */
-#define SOC_RMT_SUPPORT_PLL_F80M              1  /*!< Support set PLL_F80M as the RMT clock source */
 #define SOC_RMT_SUPPORT_RC_FAST               1  /*!< Support set RC_FAST as the RMT clock source */
 
 /*-------------------------- MCPWM CAPS --------------------------------------*/