From 219e4646f80a701578a312b96504cd30edaaf352 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Thu, 7 Sep 2023 09:36:01 +0200 Subject: [PATCH 01/71] docs(esp_eth): added Ethernet to Improving Network Speed section --- docs/en/api-guides/performance/speed.rst | 1 + examples/ethernet/iperf/sdkconfig.defaults | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/en/api-guides/performance/speed.rst b/docs/en/api-guides/performance/speed.rst index 24bac12cf7f..d48e18b74c9 100644 --- a/docs/en/api-guides/performance/speed.rst +++ b/docs/en/api-guides/performance/speed.rst @@ -245,6 +245,7 @@ Improving Network Speed :SOC_WIFI_SUPPORTED: * For Wi-Fi, see :ref:`How-to-improve-Wi-Fi-performance` and :ref:`wifi-buffer-usage` * For lwIP TCP/IP (Wi-Fi and Ethernet), see :ref:`lwip-performance` :SOC_WIFI_SUPPORTED: * The :example:`wifi/iperf` example contains a configuration that is heavily optimized for Wi-Fi TCP/IP throughput. Append the contents of the files :example_file:`wifi/iperf/sdkconfig.defaults`, :example_file:`wifi/iperf/sdkconfig.defaults.{IDF_TARGET_PATH_NAME}` and :example_file:`wifi/iperf/sdkconfig.ci.99` to the ``sdkconfig`` file in your project in order to add all of these options. Note that some of these options may have trade-offs in terms of reduced debuggability, increased firmware size, increased memory usage, or reduced performance of other features. To get the best result, read the documentation pages linked above and use related information to determine exactly which options are best suited for your app. + :SOC_EMAC_SUPPORTED: * The :example:`ethernet/iperf` example contains a configuration that is heavily optimized for Ethernet TCP/IP throughput. Examine :example_file:`ethernet/iperf/sdkconfig.defaults` for more details. Note that some of these options may have trade-offs in terms of reduced debuggability, increased firmware size, increased memory usage, or reduced performance of other features. To get the best result, read the documentation pages linked above and use related information to determine exactly which options are best suited for your app. Improving I/O Performance ------------------------- diff --git a/examples/ethernet/iperf/sdkconfig.defaults b/examples/ethernet/iperf/sdkconfig.defaults index efd490ca6d9..c6ad4c051eb 100644 --- a/examples/ethernet/iperf/sdkconfig.defaults +++ b/examples/ethernet/iperf/sdkconfig.defaults @@ -1,7 +1,8 @@ # Increase main task stack size CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168 -# Enable filesystem +# Enable filesystem for console commands history storage +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" @@ -10,11 +11,16 @@ CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" CONFIG_FREERTOS_USE_TRACE_FACILITY=y CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y +# -------------------------------- +# Performance optimization options +# -------------------------------- +# `lwIP` and `iperf` tasks have serial dependency to each other (i.e. `iperf` must wait for `lwIP` +# to process the packets). Therefore, you don't gain much performance improvement when running +# multi core mode. On the other hand, IRAM optimizations have greater effect for single core mode. + # Run FreeRTOS only on the first core CONFIG_FREERTOS_UNICORE=y -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y - # Disable watch dog CONFIG_ESP_INT_WDT=n CONFIG_ESP_TASK_WDT_EN=n From b2b305fd5d625961c5f5f5a8fb954bcb12d171c1 Mon Sep 17 00:00:00 2001 From: liqigan Date: Fri, 8 Sep 2023 11:53:41 +0800 Subject: [PATCH 02/71] change(bt/bluedroid): Limit sniff request when pending mode change event --- components/bt/host/bluedroid/stack/btm/btm_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_pm.c b/components/bt/host/bluedroid/stack/btm/btm_pm.c index 5f1950e02ab..4c52348ecd1 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_pm.c +++ b/components/bt/host/bluedroid/stack/btm/btm_pm.c @@ -243,7 +243,8 @@ tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p /* if mode == hold or pending, return */ if ( (p_cb->state == BTM_PM_STS_HOLD) || (p_cb->state == BTM_PM_STS_PENDING) || - (btm_cb.pm_pend_link_hdl != BTM_INVALID_HANDLE) ) { /* command pending */ + (btm_cb.pm_pend_link_hdl != BTM_INVALID_HANDLE) || + (p_cb->state & BTM_PM_STORED_MASK) ) { /* command pending */ if (p_acl_cb->hci_handle != btm_cb.pm_pend_link_hdl) { /* set the stored mask */ p_cb->state |= BTM_PM_STORED_MASK; From 77a303276a89a731901f5f4a8f7e93593f346185 Mon Sep 17 00:00:00 2001 From: hongshuqing Date: Thu, 17 Aug 2023 19:47:52 +0800 Subject: [PATCH 03/71] esp32/esp32s2/esp32s3 cpu freq to pll add assert for cpu_freq_to_8m update esp32 DBIAS_XTAL_80M_160M define delete modify of esp32 remove esp32 comment restore esp32 modify --- .../esp_hw_support/port/esp32/rtc_clk.c | 2 +- .../esp_hw_support/port/esp32s2/rtc_clk.c | 50 ++++++++++++-- .../esp_hw_support/port/esp32s3/rtc_clk.c | 68 ++++++++++--------- components/soc/esp32/include/soc/rtc.h | 2 +- components/soc/esp32s2/include/soc/rtc.h | 3 + 5 files changed, 86 insertions(+), 39 deletions(-) diff --git a/components/esp_hw_support/port/esp32/rtc_clk.c b/components/esp_hw_support/port/esp32/rtc_clk.c index 92d5550af63..384964e3d31 100644 --- a/components/esp_hw_support/port/esp32/rtc_clk.c +++ b/components/esp_hw_support/port/esp32/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/esp_hw_support/port/esp32s2/rtc_clk.c b/components/esp_hw_support/port/esp32s2/rtc_clk.c index bf53944bb4f..8c77c4cd88f 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s2/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -256,13 +256,39 @@ static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) */ static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz) { - int dbias = (cpu_freq_mhz == 240) ? DIG_DBIAS_240M : DIG_DBIAS_80M_160M; + /* To avoid the problem of insufficient voltage when the CPU frequency is switched: + * When the CPU frequency is switched from low to high, it is necessary to + * increase the voltage first and then increase the frequency, and the frequency + * needs to wait for the voltage to fully increase before proceeding. + * When the frequency of the CPU is switched from high to low, it is necessary + * to reduce the frequency first and then reduce the voltage. + */ + + rtc_cpu_freq_config_t cur_config; + rtc_clk_cpu_freq_get_config(&cur_config); + /* cpu_frequency < 240M: dbias = DIG_DBIAS_XTAL_80M_160M; + * cpu_frequency = 240M: dbias = DIG_DBIAS_240M; + */ + if (cpu_freq_mhz > cur_config.freq_mhz) { + if (cpu_freq_mhz == 240) { + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_240M); + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_WAK, RTC_DBIAS_240M); + esp_rom_delay_us(40); + } + } clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz); clk_ll_cpu_set_divider(1); - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias); clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL); rtc_clk_apb_freq_update(80 * MHZ); esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz); + + if (cpu_freq_mhz < cur_config.freq_mhz) { + if (cur_config.freq_mhz == 240) { + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL_80M_160M); + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_WAK, RTC_DBIAS_XTAL_80M_160M); + esp_rom_delay_us(40); + } + } } bool rtc_clk_cpu_freq_mhz_to_config(uint32_t freq_mhz, rtc_cpu_freq_config_t* out_config) @@ -411,6 +437,9 @@ void rtc_clk_cpu_set_to_default_config(void) */ static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { + rtc_cpu_freq_config_t cur_config; + rtc_clk_cpu_freq_get_config(&cur_config); + esp_rom_set_cpu_ticks_per_us(cpu_freq); /* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */ clk_ll_cpu_set_divider(1); @@ -419,15 +448,24 @@ static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) /* switch clock source */ clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL); rtc_clk_apb_freq_update(cpu_freq * MHZ); - /* lower the voltage */ - int dbias = (cpu_freq <= 2) ? DIG_DBIAS_2M : DIG_DBIAS_XTAL; - REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, dbias); + + /* lower the voltage + * cpu_frequency < 240M: dbias = DIG_DBIAS_XTAL_80M_160M; + * cpu_frequency = 240M: dbias = DIG_DBIAS_240M; + */ + if (cur_config.freq_mhz == 240) { + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL_80M_160M); + REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DBIAS_WAK, RTC_DBIAS_XTAL_80M_160M); + esp_rom_delay_us(40); + } } static void rtc_clk_cpu_freq_to_8m(void) { + assert(0 && "LDO dbias need to modified"); esp_rom_set_cpu_ticks_per_us(8); REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_DIG_DBIAS_WAK, DIG_DBIAS_XTAL); + esp_rom_delay_us(40); clk_ll_cpu_set_divider(1); clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST); rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX); diff --git a/components/esp_hw_support/port/esp32s3/rtc_clk.c b/components/esp_hw_support/port/esp32s3/rtc_clk.c index 29b96aac18a..bfa6fc79874 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s3/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -185,17 +185,6 @@ static void rtc_clk_bbpll_configure(rtc_xtal_freq_t xtal_freq, int pll_freq) */ static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz) { - /* cpu_frequency < 240M: dbias = pvt-dig + 2; - cpu_frequency = 240M: dbias = pvt-dig + 3; - */ - if (cpu_freq_mhz != 240) { - REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, g_rtc_dbias_pvt_non_240m); - REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, g_dig_dbias_pvt_non_240m); - } else { - REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, g_rtc_dbias_pvt_240m); - REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, g_dig_dbias_pvt_240m); - } - esp_rom_delay_us(40); /* There are totally 6 LDO slaves(all on by default). At the moment of swithing LDO slave, LDO voltage will also change instantaneously. * LDO slave can reduce the voltage change caused by switching frequency. @@ -207,21 +196,31 @@ static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz) int pd_slave = cpu_freq_mhz / 80; rtc_cpu_freq_config_t cur_config; rtc_clk_cpu_freq_get_config(&cur_config); + /* cpu_frequency < 240M: dbias = pvt-dig + 2; + * cpu_frequency = 240M: dbias = pvt-dig + 3; + */ if (cpu_freq_mhz > cur_config.freq_mhz) { + if (cpu_freq_mhz == 240) { + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, g_rtc_dbias_pvt_240m); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, g_dig_dbias_pvt_240m); + esp_rom_delay_us(40); + } REG_SET_FIELD(RTC_CNTL_DATE_REG, RTC_CNTL_SLAVE_PD, DEFAULT_LDO_SLAVE >> pd_slave); - clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz); - clk_ll_cpu_set_divider(1); - /* switch clock source */ - clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL); - rtc_clk_apb_freq_update(80 * MHZ); - esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz); - } else { - clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz); - clk_ll_cpu_set_divider(1); - /* switch clock source */ - clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL); - rtc_clk_apb_freq_update(80 * MHZ); - esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz); + } + + clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz); + clk_ll_cpu_set_divider(1); + /* switch clock source */ + clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL); + rtc_clk_apb_freq_update(80 * MHZ); + esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz); + + if (cpu_freq_mhz < cur_config.freq_mhz) { + if (cur_config.freq_mhz == 240) { + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, g_rtc_dbias_pvt_non_240m); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, g_dig_dbias_pvt_non_240m); + esp_rom_delay_us(40); + } REG_SET_FIELD(RTC_CNTL_DATE_REG, RTC_CNTL_SLAVE_PD, DEFAULT_LDO_SLAVE >> pd_slave); } } @@ -376,9 +375,9 @@ void rtc_clk_cpu_set_to_default_config(void) */ void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { - REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, g_rtc_dbias_pvt_non_240m); - REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, g_dig_dbias_pvt_non_240m); - esp_rom_delay_us(40); + rtc_cpu_freq_config_t cur_config; + rtc_clk_cpu_freq_get_config(&cur_config); + esp_rom_set_cpu_ticks_per_us(cpu_freq); /* Set divider from XTAL to APB clock. Need to set divider to 1 (reg. value 0) first. */ clk_ll_cpu_set_divider(1); @@ -386,18 +385,25 @@ void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) /* switch clock source */ clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL); rtc_clk_apb_freq_update(cpu_freq * MHZ); + + if (cur_config.freq_mhz == 240) { + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, g_rtc_dbias_pvt_non_240m); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, g_dig_dbias_pvt_non_240m); + esp_rom_delay_us(40); + } + REG_SET_FIELD(RTC_CNTL_DATE_REG, RTC_CNTL_SLAVE_PD, DEFAULT_LDO_SLAVE); } static void rtc_clk_cpu_freq_to_8m(void) { + assert(0 && "LDO dbias need to modified"); esp_rom_set_cpu_ticks_per_us(20); - REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, g_rtc_dbias_pvt_non_240m); - REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, g_dig_dbias_pvt_non_240m); - esp_rom_delay_us(40); clk_ll_cpu_set_divider(1); clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST); rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_RTC_DREG, g_rtc_dbias_pvt_non_240m); + REGI2C_WRITE_MASK(I2C_DIG_REG, I2C_DIG_REG_EXT_DIG_DREG, g_dig_dbias_pvt_non_240m); REG_SET_FIELD(RTC_CNTL_DATE_REG, RTC_CNTL_SLAVE_PD, DEFAULT_LDO_SLAVE); } diff --git a/components/soc/esp32/include/soc/rtc.h b/components/soc/esp32/include/soc/rtc.h index 813c98d9f1f..1832efb6f26 100644 --- a/components/soc/esp32/include/soc/rtc.h +++ b/components/soc/esp32/include/soc/rtc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/soc/esp32s2/include/soc/rtc.h b/components/soc/esp32s2/include/soc/rtc.h index e703c4c0bc0..174ca22d7bd 100644 --- a/components/soc/esp32s2/include/soc/rtc.h +++ b/components/soc/esp32s2/include/soc/rtc.h @@ -84,7 +84,10 @@ extern "C" { #define DIG_DBIAS_80M_160M RTC_CNTL_DBIAS_1V10 #endif #define DIG_DBIAS_240M RTC_CNTL_DBIAS_1V25 +#define RTC_DBIAS_240M RTC_CNTL_DBIAS_1V25 #define DIG_DBIAS_XTAL RTC_CNTL_DBIAS_1V10 +#define DIG_DBIAS_XTAL_80M_160M RTC_CNTL_DBIAS_1V10 +#define RTC_DBIAS_XTAL_80M_160M RTC_CNTL_DBIAS_1V10 #define DIG_DBIAS_2M RTC_CNTL_DBIAS_1V00 #define RTC_CNTL_PLL_BUF_WAIT_DEFAULT 20 From d905993e1ec8c220fa68902ea04fe0cdb45a88d6 Mon Sep 17 00:00:00 2001 From: baohongde Date: Thu, 3 Aug 2023 21:32:41 +0800 Subject: [PATCH 04/71] remove(bluedroid): Delete media stop command and audio stopped state --- .../bt/host/bluedroid/api/esp_a2dp_api.c | 5 +++++ .../bluedroid/api/include/api/esp_a2dp_api.h | 7 ++++--- .../bt/host/bluedroid/bta/av/bta_av_aact.c | 4 ++-- .../btc/profile/std/a2dp/btc_a2dp_control.c | 20 ------------------- .../bluedroid/btc/profile/std/a2dp/btc_av.c | 11 ++-------- .../btc/profile/std/include/btc_av.h | 1 - .../classic_bt/a2dp_source/main/main.c | 12 +++++------ 7 files changed, 19 insertions(+), 41 deletions(-) diff --git a/components/bt/host/bluedroid/api/esp_a2dp_api.c b/components/bt/host/bluedroid/api/esp_a2dp_api.c index fbf9ecd0495..be8adcf2dc6 100644 --- a/components/bt/host/bluedroid/api/esp_a2dp_api.c +++ b/components/bt/host/bluedroid/api/esp_a2dp_api.c @@ -208,6 +208,11 @@ esp_err_t esp_a2d_media_ctrl(esp_a2d_media_ctrl_t ctrl) return ESP_ERR_INVALID_STATE; } + if (ctrl == ESP_A2D_MEDIA_CTRL_STOP) { + LOG_WARN("ESP_A2D_MEDIA_CTRL_STOP is deprecated, using ESP_A2D_MEDIA_CTRL_SUSPEND instead.\n"); + ctrl = ESP_A2D_MEDIA_CTRL_SUSPEND; + } + bt_status_t stat; btc_av_args_t arg; btc_msg_t msg; diff --git a/components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h b/components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h index 99094d237aa..f319eb4d523 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_a2dp_api.h @@ -69,9 +69,10 @@ typedef enum { * @brief Bluetooth A2DP datapath states */ typedef enum { - ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND = 0, /*!< audio stream datapath suspended by remote device */ - ESP_A2D_AUDIO_STATE_STOPPED, /*!< audio stream datapath stopped */ + ESP_A2D_AUDIO_STATE_SUSPEND = 0, /*!< audio stream datapath suspended by remote device */ ESP_A2D_AUDIO_STATE_STARTED, /*!< audio stream datapath started */ + ESP_A2D_AUDIO_STATE_STOPPED = ESP_A2D_AUDIO_STATE_SUSPEND, /*!< @note Deprecated */ + ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND = ESP_A2D_AUDIO_STATE_SUSPEND, /*!< @note Deprecated */ } esp_a2d_audio_state_t; /** @@ -90,8 +91,8 @@ typedef enum { ESP_A2D_MEDIA_CTRL_NONE = 0, /*!< Not for application use, use inside stack only. */ ESP_A2D_MEDIA_CTRL_CHECK_SRC_RDY, /*!< check whether AVDTP is connected, only used in A2DP source */ ESP_A2D_MEDIA_CTRL_START, /*!< command to set up media transmission channel */ - ESP_A2D_MEDIA_CTRL_STOP, /*!< command to stop media transmission */ ESP_A2D_MEDIA_CTRL_SUSPEND, /*!< command to suspend media transmission */ + ESP_A2D_MEDIA_CTRL_STOP, /*!< @note Deprecated, Please use ESP_A2D_MEDIA_CTRL_SUSPEND */ } esp_a2d_media_ctrl_t; /** diff --git a/components/bt/host/bluedroid/bta/av/bta_av_aact.c b/components/bt/host/bluedroid/bta/av/bta_av_aact.c index f8595f3110e..33bb50cd6d0 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_aact.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_aact.c @@ -2020,7 +2020,7 @@ void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) BT_HDR *p_buf; UINT8 policy = HCI_ENABLE_SNIFF_MODE; - APPL_TRACE_ERROR("bta_av_str_stopped:audio_open_cnt=%d, p_data %p", + APPL_TRACE_DEBUG("bta_av_str_stopped:audio_open_cnt=%d, p_data %p", bta_av_cb.audio_open_cnt, p_data); bta_sys_idle(TSEP_TO_SYS_ID(p_scb->seps[p_scb->sep_idx].tsep), bta_av_cb.audio_open_cnt, p_scb->peer_addr); @@ -2071,7 +2071,7 @@ void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) } else { suspend_rsp.status = BTA_AV_SUCCESS; suspend_rsp.initiator = TRUE; - APPL_TRACE_EVENT("bta_av_str_stopped status %d", suspend_rsp.status); + APPL_TRACE_WARNING("bta_av_str_stopped status %d", suspend_rsp.status); /* send STOP_EVT event only if not in reconfiguring state */ if (p_scb->state != BTA_AV_RCFG_SST) { diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c index 814b408c9fb..ba264f93866 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.c @@ -137,26 +137,6 @@ void btc_a2dp_control_media_ctrl(esp_a2d_media_ctrl_t ctrl) btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE); } break; - case ESP_A2D_MEDIA_CTRL_STOP: - if (btc_av_is_connected() == FALSE) { - btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE); - break; - } -#if BTC_AV_SRC_INCLUDED - if (btc_av_get_peer_sep() == AVDT_TSEP_SNK && !btc_a2dp_source_is_streaming() && - btc_av_get_service_id() == BTA_A2DP_SOURCE_SERVICE_ID) { - /* we are already stopped, just ack back*/ - btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS); - break; - } -#endif /* BTC_AV_SRC_INCLUDED */ - btc_dispatch_sm_event(BTC_AV_STOP_STREAM_REQ_EVT, NULL, 0); -#if (BTC_AV_SINK_INCLUDED == TRUE) - if (btc_av_get_peer_sep() == AVDT_TSEP_SRC && btc_av_get_service_id() == BTA_A2DP_SINK_SERVICE_ID) { - btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS); - } -#endif - break; case ESP_A2D_MEDIA_CTRL_SUSPEND: /* local suspend */ if (btc_av_stream_started_ready()) { diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c index f274d89cb50..a1b7548a7b8 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c @@ -219,7 +219,6 @@ UNUSED_ATTR static const char *dump_av_sm_event_name(btc_av_sm_event_t event) CASE_RETURN_STR(BTC_AV_CONNECT_REQ_EVT) CASE_RETURN_STR(BTC_AV_DISCONNECT_REQ_EVT) CASE_RETURN_STR(BTC_AV_START_STREAM_REQ_EVT) - CASE_RETURN_STR(BTC_AV_STOP_STREAM_REQ_EVT) CASE_RETURN_STR(BTC_AV_SUSPEND_STREAM_REQ_EVT) CASE_RETURN_STR(BTC_AV_SINK_CONFIG_REQ_EVT) default: return "UNKNOWN_EVENT"; @@ -600,7 +599,6 @@ static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *p_data) break; case BTA_AV_STOP_EVT: - case BTC_AV_STOP_STREAM_REQ_EVT: #if BTC_AV_SRC_INCLUDED if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) { /* immediately flush any pending tx frames while suspend is pending */ @@ -882,8 +880,6 @@ static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data) #endif /* BTC_AV_SRC_INCLUDED */ break; - /* fixme -- use suspend = true always to work around issue with BTA AV */ - case BTC_AV_STOP_STREAM_REQ_EVT: case BTC_AV_SUSPEND_STREAM_REQ_EVT: /* set pending flag to ensure btc task is not trying to restart @@ -953,10 +949,8 @@ static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data) btc_av_cb.flags |= BTC_AV_FLAG_REMOTE_SUSPEND; } - btc_report_audio_state(ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND, &(btc_av_cb.peer_bda)); - } else { - btc_report_audio_state(ESP_A2D_AUDIO_STATE_STOPPED, &(btc_av_cb.peer_bda)); } + btc_report_audio_state(ESP_A2D_AUDIO_STATE_SUSPEND, &(btc_av_cb.peer_bda)); btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_OPENED); @@ -969,7 +963,7 @@ static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data) btc_av_cb.flags |= BTC_AV_FLAG_PENDING_STOP; btc_a2dp_on_stopped(&p_av->suspend); - btc_report_audio_state(ESP_A2D_AUDIO_STATE_STOPPED, &(btc_av_cb.peer_bda)); + btc_report_audio_state(ESP_A2D_AUDIO_STATE_SUSPEND, &(btc_av_cb.peer_bda)); /* if stop was successful, change state to open */ if (p_av->suspend.status == BTA_AV_SUCCESS) { @@ -1623,7 +1617,6 @@ void btc_a2dp_call_handler(btc_msg_t *msg) break; // case BTC_AV_DISCONNECT_REQ_EVT: case BTC_AV_START_STREAM_REQ_EVT: - case BTC_AV_STOP_STREAM_REQ_EVT: case BTC_AV_SUSPEND_STREAM_REQ_EVT: { btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, NULL); break; diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_av.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_av.h index c097ff008f2..3dd2ebe6c1c 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_av.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_av.h @@ -50,7 +50,6 @@ typedef enum { BTC_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT, BTC_AV_DISCONNECT_REQ_EVT, BTC_AV_START_STREAM_REQ_EVT, - BTC_AV_STOP_STREAM_REQ_EVT, BTC_AV_SUSPEND_STREAM_REQ_EVT, BTC_AV_SINK_CONFIG_REQ_EVT, } btc_av_sm_event_t; diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c index 18f0de815d1..1ea7348415f 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c @@ -508,8 +508,8 @@ static void bt_app_av_media_proc(uint16_t event, void *param) if (event == BT_APP_HEART_BEAT_EVT) { /* stop media after 10 heart beat intervals */ if (++s_intv_cnt >= 10) { - ESP_LOGI(BT_AV_TAG, "a2dp media stopping..."); - esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP); + ESP_LOGI(BT_AV_TAG, "a2dp media suspending..."); + esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_SUSPEND); s_media_state = APP_AV_MEDIA_STATE_STOPPING; s_intv_cnt = 0; } @@ -519,15 +519,15 @@ static void bt_app_av_media_proc(uint16_t event, void *param) case APP_AV_MEDIA_STATE_STOPPING: { if (event == ESP_A2D_MEDIA_CTRL_ACK_EVT) { a2d = (esp_a2d_cb_param_t *)(param); - if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_STOP && + if (a2d->media_ctrl_stat.cmd == ESP_A2D_MEDIA_CTRL_SUSPEND && a2d->media_ctrl_stat.status == ESP_A2D_MEDIA_CTRL_ACK_SUCCESS) { - ESP_LOGI(BT_AV_TAG, "a2dp media stopped successfully, disconnecting..."); + ESP_LOGI(BT_AV_TAG, "a2dp media suspend successfully, disconnecting..."); s_media_state = APP_AV_MEDIA_STATE_IDLE; esp_a2d_source_disconnect(s_peer_bda); s_a2d_state = APP_AV_STATE_DISCONNECTING; } else { - ESP_LOGI(BT_AV_TAG, "a2dp media stopping..."); - esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_STOP); + ESP_LOGI(BT_AV_TAG, "a2dp media suspending..."); + esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_SUSPEND); } } break; From c3ade2d54e1572997cf8a7b7289032ff2413d877 Mon Sep 17 00:00:00 2001 From: baohongde Date: Mon, 7 Aug 2023 16:20:57 +0800 Subject: [PATCH 05/71] change(bluedroid): Set AV is ready when suspended by remote --- components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c index a1b7548a7b8..4c237b1e509 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c @@ -710,7 +710,7 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data) */ if (!(btc_av_cb.flags & BTC_AV_FLAG_PENDING_START)) { if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) { - BTC_TRACE_DEBUG("%s: trigger suspend as remote initiated!!", __FUNCTION__); + BTC_TRACE_EVENT("%s: trigger suspend as remote initiated!!", __FUNCTION__); btc_dispatch_sm_event(BTC_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0); } } @@ -1263,7 +1263,7 @@ BOOLEAN btc_av_stream_ready(void) (int)btc_av_cb.sm_handle, state, btc_av_cb.flags); /* check if we are remotely suspended or stop is pending */ - if (btc_av_cb.flags & (BTC_AV_FLAG_REMOTE_SUSPEND | BTC_AV_FLAG_PENDING_STOP)) { + if (btc_av_cb.flags & BTC_AV_FLAG_PENDING_STOP) { return FALSE; } @@ -1288,7 +1288,7 @@ BOOLEAN btc_av_stream_started_ready(void) (int)btc_av_cb.sm_handle, state, btc_av_cb.flags); /* disallow media task to start if we have pending actions */ - if (btc_av_cb.flags & (BTC_AV_FLAG_LOCAL_SUSPEND_PENDING | BTC_AV_FLAG_REMOTE_SUSPEND + if (btc_av_cb.flags & (BTC_AV_FLAG_LOCAL_SUSPEND_PENDING | BTC_AV_FLAG_PENDING_STOP)) { return FALSE; } From 6421460c0ad98c081b696c9b5c9784598a14210c Mon Sep 17 00:00:00 2001 From: "wanglai@espressif.com" Date: Thu, 31 Aug 2023 18:20:11 +0800 Subject: [PATCH 06/71] feat(bt/bluedroid): Add avdt abort function for BQB test 1: add new AVDTP abort function for BQB test --- .../bt/host/bluedroid/bta/av/bta_av_aact.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/components/bt/host/bluedroid/bta/av/bta_av_aact.c b/components/bt/host/bluedroid/bta/av/bta_av_aact.c index f8595f3110e..9564f6a217c 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_aact.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_aact.c @@ -62,6 +62,11 @@ #define BTA_AV_RECONFIG_RETRY 6 #endif +/* avdt_handle to send abort command for AVDTP BQB test */ +#if A2D_SRC_BQB_INCLUDED +static uint8_t s_avdt_bqb_handle; +#endif /* CONFIG_BT_BQB_ENABLED */ + static void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); /* state machine states */ @@ -1415,6 +1420,10 @@ void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) } } +#if A2D_SRC_BQB_INCLUDED + s_avdt_bqb_handle = p_scb->avdt_handle; +#endif /* A2D_SRC_BQB_INCLUDED */ + #if 0 /* TODO: implement the property enable/disable */ // This code is used to pass PTS TC for AVDTP ABORT char value[PROPERTY_VALUE_MAX] = {0}; @@ -1426,6 +1435,22 @@ void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) #endif /* #if 0*/ } +/******************************************************************************* +** +** Function avdt_bqb_abort +** +** Description Send AVDT abort request for BQB test +** +** Returns void +** +*******************************************************************************/ +#if A2D_SRC_BQB_INCLUDED +void avdt_bqb_abort(void) +{ + AVDT_AbortReq(s_avdt_bqb_handle); +} +#endif /* A2D_SRC_BQB_INCLUDED */ + /******************************************************************************* ** ** Function bta_av_security_ind From c31f445754789457ca503004b0bd8b26ba5061a9 Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Fri, 25 Aug 2023 17:31:51 +0800 Subject: [PATCH 07/71] change(github): add chip revision into templates --- .github/ISSUE_TEMPLATE/02_runtime_bug.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/02_runtime_bug.yml b/.github/ISSUE_TEMPLATE/02_runtime_bug.yml index 8996025f2cf..7d8722fe283 100644 --- a/.github/ISSUE_TEMPLATE/02_runtime_bug.yml +++ b/.github/ISSUE_TEMPLATE/02_runtime_bug.yml @@ -22,6 +22,14 @@ body: placeholder: ex. v3.2-dev-1148-g96cd3b75c validations: required: true + - type: input + id: chip_revision + attributes: + label: Espressif SoC revision. + description: On which Espressif SoC revision does your application run on? Run `esptool chip_id` to find it. + placeholder: ex. ESP32-C3 (QFN32) (revision v0.3) + validations: + required: true - type: dropdown id: operating_system attributes: @@ -63,7 +71,7 @@ body: attributes: label: Development Kit. description: On which Development Kit does this issue occur on? - placeholder: ex. ESP32-Wrover-Kit v2 | Custom Board + placeholder: ex. ESP32-Wrover-Kit v2 | Custom Board | QEMU validations: required: true - type: dropdown From d0e0928138ab2b8f4e869d6669022910d8b9812e Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Fri, 1 Sep 2023 09:49:20 +0800 Subject: [PATCH 08/71] feat(bt/Bluedroid): Implemented esp_coex_status_set/clear using vendor HCI --- components/bt/host/bluedroid/Kconfig.in | 7 ++++ .../bt/host/bluedroid/api/esp_bt_device.c | 21 +++++++++++ .../bluedroid/api/include/api/esp_bt_device.h | 37 +++++++++++++++++++ .../bt/host/bluedroid/bta/dm/bta_dm_act.c | 19 ++++++++++ .../bt/host/bluedroid/bta/dm/bta_dm_api.c | 25 +++++++++++++ .../bt/host/bluedroid/bta/dm/bta_dm_main.c | 18 +++++++-- .../bluedroid/bta/dm/include/bta_dm_int.h | 18 +++++++++ .../host/bluedroid/bta/include/bta/bta_api.h | 14 +++++++ .../bt/host/bluedroid/btc/core/btc_dev.c | 11 ++++++ .../host/bluedroid/btc/include/btc/btc_dev.h | 14 ++++++- .../include/common/bluedroid_user_config.h | 7 ++++ .../common/include/common/bt_target.h | 6 +++ .../bt/host/bluedroid/stack/btm/btm_devctl.c | 13 +++++++ .../bluedroid/stack/include/stack/btm_api.h | 37 +++++++++++++++++++ 14 files changed, 242 insertions(+), 5 deletions(-) diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index c9a0c0f147a..079080bf3af 100644 --- a/components/bt/host/bluedroid/Kconfig.in +++ b/components/bt/host/bluedroid/Kconfig.in @@ -40,6 +40,13 @@ config BT_BLUEDROID_MEM_DEBUG help Bluedroid memory debug +config BT_BLUEDROID_ESP_COEX_VSC + bool "Enable Espressif Vendor-specific HCI commands for coexist status configuration" + depends on BT_BLUEDROID_ENABLED + default y + help + Enable Espressif Vendor-specific HCI commands for coexist status configuration + config BT_CLASSIC_ENABLED bool "Classic Bluetooth" depends on BT_BLUEDROID_ENABLED && IDF_TARGET_ESP32 diff --git a/components/bt/host/bluedroid/api/esp_bt_device.c b/components/bt/host/bluedroid/api/esp_bt_device.c index e9369b20fcc..0a323cfe299 100644 --- a/components/bt/host/bluedroid/api/esp_bt_device.c +++ b/components/bt/host/bluedroid/api/esp_bt_device.c @@ -47,3 +47,24 @@ esp_err_t esp_bt_dev_set_device_name(const char *name) return (btc_transfer_context(&msg, &arg, sizeof(btc_dev_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } + +#if (ESP_COEX_VSC_INCLUDED == TRUE) +esp_err_t esp_bt_dev_coex_status_config(esp_bt_dev_coex_type_t type, esp_bt_dev_coex_op_t op, uint8_t status) +{ + btc_msg_t msg = {0}; + btc_dev_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DEV; + msg.act = BTC_DEV_ACT_CFG_COEX_STATUS; + arg.cfg_coex_status.type = type; + arg.cfg_coex_status.op = op; + arg.cfg_coex_status.status = status; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_dev_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif diff --git a/components/bt/host/bluedroid/api/include/api/esp_bt_device.h b/components/bt/host/bluedroid/api/include/api/esp_bt_device.h index 20826b76ddd..997d827f652 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_bt_device.h +++ b/components/bt/host/bluedroid/api/include/api/esp_bt_device.h @@ -16,6 +16,27 @@ extern "C" { #endif +// coexist status for MESH +#define ESP_BT_DEV_COEX_BLE_ST_MESH_CONFIG 0x08 +#define ESP_BT_DEV_COEX_BLE_ST_MESH_TRAFFIC 0x10 +#define ESP_BT_DEV_COEX_BLE_ST_MESH_STANDBY 0x20 +// coexist status for A2DP +#define ESP_BT_DEV_COEX_BT_ST_A2DP_STREAMING 0x10 +#define ESP_BT_DEV_COEX_BT_ST_A2DP_PAUSED 0x20 + +// coexist operation +#define ESP_BT_DEV_COEX_OP_CLEAR 0x00 +#define ESP_BT_DEV_COEX_OP_SET 0x01 +typedef uint8_t esp_bt_dev_coex_op_t; + +/** + * @brief Bluetooth device coex type + */ +typedef enum { + ESP_BT_DEV_COEX_TYPE_BLE = 1, + ESP_BT_DEV_COEX_TYPE_BT, +} esp_bt_dev_coex_type_t; + /** * * @brief Get bluetooth device address. Must use after "esp_bluedroid_enable". @@ -42,6 +63,22 @@ const uint8_t *esp_bt_dev_get_address(void); */ esp_err_t esp_bt_dev_set_device_name(const char *name); +/** + * @brief Config bluetooth device coexis status. This function should be called after esp_bluedroid_enable() + * completes successfully. + * + * @param[in] type : coexist type to operate on + * @param[in] op : clear or set coexist status + * @param[in] status : coexist status to be configured + * + * @return + * - ESP_OK : Succeed + * - ESP_ERR_INVALID_ARG : if name is NULL pointer or empty, or string length out of limit + * - ESP_ERR_INVALID_STATE : if bluetooth stack is not yet enabled + * - ESP_FAIL : others + */ +esp_err_t esp_bt_dev_coex_status_config(esp_bt_dev_coex_type_t type, esp_bt_dev_coex_op_t op, uint8_t status); + #ifdef __cplusplus } #endif diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c index b967ba38891..c07bf996c1d 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -692,6 +692,25 @@ void bta_dm_get_dev_name (tBTA_DM_MSG *p_data) } } +/******************************************************************************* +** +** Function bta_dm_cfg_coex_status +** +** Description config coexistance status +** +** +** Returns void +** +*******************************************************************************/ +#if (ESP_COEX_VSC_INCLUDED == TRUE) +void bta_dm_cfg_coex_status (tBTA_DM_MSG *p_data) +{ + BTM_ConfigCoexStatus(p_data->cfg_coex_status.op, + p_data->cfg_coex_status.type, + p_data->cfg_coex_status.status); +} +#endif + /******************************************************************************* ** ** Function bta_dm_set_afh_channels diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_api.c b/components/bt/host/bluedroid/bta/dm/bta_dm_api.c index e896846e259..a214fa038bb 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_api.c @@ -202,6 +202,31 @@ void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback) } } +/******************************************************************************* +** +** Function BTA_DmCfgCoexStatus +** +** Description This function configures the coexist status +** +** +** Returns void +** +*******************************************************************************/ +#if (ESP_COEX_VSC_INCLUDED == TRUE) +void BTA_DmCfgCoexStatus(UINT8 op, UINT8 type, UINT8 status) +{ + tBTA_DM_API_CFG_COEX_STATUS *p_msg; + + if ((p_msg = (tBTA_DM_API_CFG_COEX_STATUS *) osi_malloc(sizeof(tBTA_DM_API_CFG_COEX_STATUS))) != NULL) { + p_msg->hdr.event = BTA_DM_API_CFG_COEX_ST_EVT; + p_msg->op = op; + p_msg->type = type; + p_msg->status = status; + bta_sys_sendmsg(p_msg); + } +} +#endif + #if (CLASSIC_BT_INCLUDED == TRUE) void BTA_DmConfigEir(tBTA_DM_EIR_CONF *eir_config) diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_main.c b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c index 51201c91712..81866380c6b 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c @@ -25,6 +25,9 @@ #include "bta/bta_api.h" #include "bta/bta_sys.h" #include "bta_dm_int.h" +#if (ESP_COEX_VSC_INCLUDED == TRUE) +#include "stack/btm_api.h" +#endif #include "osi/allocator.h" #include @@ -59,6 +62,9 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { bta_dm_disable, /* BTA_DM_API_DISABLE_EVT */ bta_dm_set_dev_name, /* BTA_DM_API_SET_NAME_EVT */ bta_dm_get_dev_name, /* BTA_DM_API_GET_NAME_EVT */ +#if (ESP_COEX_VSC_INCLUDED == TRUE) + bta_dm_cfg_coex_status, /* BTA_DM_API_CFG_COEX_ST_EVT */ +#endif #if (CLASSIC_BT_INCLUDED == TRUE) bta_dm_config_eir, /* BTA_DM_API_CONFIG_EIR_EVT */ bta_dm_set_page_timeout, /* BTA_DM_API_PAGE_TO_SET_EVT */ @@ -464,12 +470,16 @@ void BTA_DmCoexEventTrigger(uint32_t event) case BTA_COEX_EVT_ACL_DISCONNECTED: break; case BTA_COEX_EVT_STREAMING_STARTED: - esp_coex_status_bit_set(ESP_COEX_ST_TYPE_BT, ESP_COEX_BT_ST_A2DP_STREAMING); - esp_coex_status_bit_clear(ESP_COEX_ST_TYPE_BT, ESP_COEX_BT_ST_A2DP_PAUSED); +#if (ESP_COEX_VSC_INCLUDED == TRUE) + BTM_ConfigCoexStatus(BTM_COEX_OP_SET, BTM_COEX_TYPE_BT, BTM_COEX_BT_ST_A2DP_STREAMING); + BTM_ConfigCoexStatus(BTM_COEX_OP_CLEAR, BTM_COEX_TYPE_BT, BTM_COEX_BT_ST_A2DP_PAUSED); +#endif break; case BTA_COEX_EVT_STREAMING_STOPPED: - esp_coex_status_bit_clear(ESP_COEX_ST_TYPE_BT, ESP_COEX_BT_ST_A2DP_STREAMING); - esp_coex_status_bit_clear(ESP_COEX_ST_TYPE_BT, ESP_COEX_BT_ST_A2DP_PAUSED); +#if (ESP_COEX_VSC_INCLUDED == TRUE) + BTM_ConfigCoexStatus(BTM_COEX_OP_CLEAR, BTM_COEX_TYPE_BT, BTM_COEX_BT_ST_A2DP_STREAMING); + BTM_ConfigCoexStatus(BTM_COEX_OP_CLEAR, BTM_COEX_TYPE_BT, BTM_COEX_BT_ST_A2DP_PAUSED); +#endif break; default: break; diff --git a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h index 40b7e8e909f..386df1354c2 100644 --- a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h @@ -54,6 +54,9 @@ enum { BTA_DM_API_DISABLE_EVT, BTA_DM_API_SET_NAME_EVT, BTA_DM_API_GET_NAME_EVT, +#if (ESP_COEX_VSC_INCLUDED == TRUE) + BTA_DM_API_CFG_COEX_ST_EVT, +#endif #if (CLASSIC_BT_INCLUDED == TRUE) BTA_DM_API_CONFIG_EIR_EVT, BTA_DM_API_PAGE_TO_SET_EVT, @@ -244,6 +247,15 @@ typedef struct { tBTA_GET_DEV_NAME_CBACK *p_cback; } tBTA_DM_API_GET_NAME; +#if (ESP_COEX_VSC_INCLUDED == TRUE) +typedef struct { + BT_HDR hdr; + UINT8 op; + UINT8 type; + UINT8 status; +} tBTA_DM_API_CFG_COEX_STATUS; +#endif + /* data type for BTA_DM_API_CONFIG_EIR_EVT */ typedef struct { BT_HDR hdr; @@ -1090,6 +1102,9 @@ typedef union { tBTA_DM_API_SET_NAME set_name; tBTA_DM_API_GET_NAME get_name; +#if (ESP_COEX_VSC_INCLUDED == TRUE) + tBTA_DM_API_CFG_COEX_STATUS cfg_coex_status; +#endif tBTA_DM_API_CONFIG_EIR config_eir; tBTA_DM_API_SET_AFH_CHANNELS set_afh_channels; @@ -1593,6 +1608,9 @@ extern void bta_dm_enable (tBTA_DM_MSG *p_data); extern void bta_dm_disable (tBTA_DM_MSG *p_data); extern void bta_dm_set_dev_name (tBTA_DM_MSG *p_data); extern void bta_dm_get_dev_name (tBTA_DM_MSG *p_data); +#if (ESP_COEX_VSC_INCLUDED == TRUE) +extern void bta_dm_cfg_coex_status(tBTA_DM_MSG *p_data); +#endif #if (CLASSIC_BT_INCLUDED == TRUE) extern void bta_dm_config_eir (tBTA_DM_MSG *p_data); extern void bta_dm_set_page_timeout (tBTA_DM_MSG *p_data); diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_api.h index 5b8899fc6e4..fd0d2350aad 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_api.h @@ -1713,6 +1713,20 @@ extern void BTA_DmSetDeviceName(const char *p_name); *******************************************************************************/ extern void BTA_DmGetDeviceName(tBTA_GET_DEV_NAME_CBACK *p_cback); +/******************************************************************************* +** +** Function BTA_DmCfgCoexStatus +** +** Description This function configures coexist status. +** +** +** Returns void +** +*******************************************************************************/ +#if (ESP_COEX_VSC_INCLUDED == TRUE) +extern void BTA_DmCfgCoexStatus(UINT8 op, UINT8 type, UINT8 status); +#endif + /******************************************************************************* ** ** Function BTA_DmGetRemoteName diff --git a/components/bt/host/bluedroid/btc/core/btc_dev.c b/components/bt/host/bluedroid/btc/core/btc_dev.c index 88d15c85844..1aceface6a8 100644 --- a/components/bt/host/bluedroid/btc/core/btc_dev.c +++ b/components/bt/host/bluedroid/btc/core/btc_dev.c @@ -23,6 +23,10 @@ void btc_dev_arg_deep_free(btc_msg_t *msg) } break; } +#if (ESP_COEX_VSC_INCLUDED == TRUE) + case BTC_DEV_ACT_CFG_COEX_STATUS: + break; +#endif default: BTC_TRACE_DEBUG("Unhandled deep free %d\n", msg->act); break; @@ -39,6 +43,13 @@ void btc_dev_call_handler(btc_msg_t *msg) case BTC_DEV_ACT_SET_DEVICE_NAME: BTA_DmSetDeviceName(arg->set_dev_name.device_name); break; +#if (ESP_COEX_VSC_INCLUDED == TRUE) + case BTC_DEV_ACT_CFG_COEX_STATUS: + BTA_DmCfgCoexStatus(arg->cfg_coex_status.op, + arg->cfg_coex_status.type, + arg->cfg_coex_status.status); + break; +#endif default: break; } diff --git a/components/bt/host/bluedroid/btc/include/btc/btc_dev.h b/components/bt/host/bluedroid/btc/include/btc/btc_dev.h index e87766b9dc3..4cf085d7de9 100644 --- a/components/bt/host/bluedroid/btc/include/btc/btc_dev.h +++ b/components/bt/host/bluedroid/btc/include/btc/btc_dev.h @@ -12,7 +12,10 @@ #include "btc/btc_task.h" typedef enum { - BTC_DEV_ACT_SET_DEVICE_NAME + BTC_DEV_ACT_SET_DEVICE_NAME, +#if (ESP_COEX_VSC_INCLUDED == TRUE) + BTC_DEV_ACT_CFG_COEX_STATUS, +#endif } btc_dev_act_t; /* btc_dev_args_t */ @@ -21,6 +24,15 @@ typedef union { struct set_bt_dev_name_args { char *device_name; } set_dev_name; + +#if (ESP_COEX_VSC_INCLUDED == TRUE) + // BTC_DEV_ACT_CFG_COEX_STATUS + struct cfg_bt_dev_coex_st_args { + esp_bt_dev_coex_type_t type; + esp_bt_dev_coex_op_t op; + uint8_t status; + } cfg_coex_status; +#endif } btc_dev_args_t; void btc_dev_call_handler(btc_msg_t *msg); diff --git a/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h index 08034e4a90f..8b99588dfcd 100644 --- a/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h +++ b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h @@ -361,6 +361,13 @@ #define UC_BT_BLUEDROID_MEM_DEBUG FALSE #endif +//ESP COEXIST VSC +#ifdef CONFIG_BT_BLUEDROID_ESP_COEX_VSC +#define UC_BT_BLUEDROID_ESP_COEX_VSC CONFIG_BT_BLUEDROID_ESP_COEX_VSC +#else +#define UC_BT_BLUEDROID_ESP_COEX_VSC FALSE +#endif + /********************************************************** * Trace reference diff --git a/components/bt/host/bluedroid/common/include/common/bt_target.h b/components/bt/host/bluedroid/common/include/common/bt_target.h index d3b828ca0b7..75f128927e7 100644 --- a/components/bt/host/bluedroid/common/include/common/bt_target.h +++ b/components/bt/host/bluedroid/common/include/common/bt_target.h @@ -45,6 +45,12 @@ /* OS Configuration from User config (eg: sdkconfig) */ #define BT_BTU_TASK_STACK_SIZE UC_BTU_TASK_STACK_SIZE +#if (UC_BT_BLUEDROID_ESP_COEX_VSC == TRUE) +#define ESP_COEX_VSC_INCLUDED TRUE +#else +#define ESP_COEX_VSC_INCLUDED FALSE +#endif + /****************************************************************************** ** ** Classic BT features diff --git a/components/bt/host/bluedroid/stack/btm/btm_devctl.c b/components/bt/host/bluedroid/stack/btm/btm_devctl.c index 88a2bee956f..0656f18f99a 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_devctl.c @@ -688,6 +688,19 @@ tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len, } +#if (ESP_COEX_VSC_INCLUDED == TRUE) +tBTM_STATUS BTM_ConfigCoexStatus(tBTM_COEX_OPERATION op, tBTM_COEX_TYPE type, UINT8 status) +{ + UINT8 param[3]; + UINT8 *p = (UINT8 *)param; + + UINT8_TO_STREAM(p, type); + UINT8_TO_STREAM(p, op); + UINT8_TO_STREAM(p, status); + + return BTM_VendorSpecificCommand(HCI_VENDOR_COMMON_COEX_STATUS_CMD_OPCODE, 3, param, NULL); +} +#endif /******************************************************************************* ** diff --git a/components/bt/host/bluedroid/stack/include/stack/btm_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_api.h index 6db5e7d6297..5120259ecce 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btm_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/btm_api.h @@ -195,6 +195,28 @@ typedef void (tBTM_UPDATE_WHITELIST_CBACK) (UINT8 status, tBTM_WL_OPERATION wl_o typedef void (tBTM_SET_LOCAL_PRIVACY_CBACK) (UINT8 status); +/******************************* +** Device Coexist status +********************************/ +#if (ESP_COEX_VSC_INCLUDED == TRUE) +// coexist status for MESH +#define BTM_COEX_BLE_ST_MESH_CONFIG 0x08 +#define BTM_COEX_BLE_ST_MESH_TRAFFIC 0x10 +#define BTM_COEX_BLE_ST_MESH_STANDBY 0x20 +// coexist status for A2DP +#define BTM_COEX_BT_ST_A2DP_STREAMING 0x10 +#define BTM_COEX_BT_ST_A2DP_PAUSED 0x20 + +// coexist operation +#define BTM_COEX_OP_CLEAR 0x00 +#define BTM_COEX_OP_SET 0x01 +typedef UINT8 tBTM_COEX_OPERATION; + +typedef enum { + BTM_COEX_TYPE_BLE = 1, + BTM_COEX_TYPE_BT, +} tBTM_COEX_TYPE; +#endif /***************************************************************************** ** DEVICE DISCOVERY - Inquiry, Remote Name, Discovery, Class of Device @@ -2150,6 +2172,21 @@ tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 *p_param_buf, tBTM_VSC_CMPL_CB *p_cb); +/******************************************************************************* +** +** Function BTM_ConfigCoexStatus +** +** Description Config coexist status through vendor specific HCI command. +** +** Returns +** BTM_SUCCESS Command sent. Does not expect command complete +** event. (command cmpl callback param is NULL) +** BTM_NO_RESOURCES Command not sent. No resources. +** +*******************************************************************************/ +#if (ESP_COEX_VSC_INCLUDED == TRUE) +tBTM_STATUS BTM_ConfigCoexStatus(tBTM_COEX_OPERATION op, tBTM_COEX_TYPE type, UINT8 status); +#endif /******************************************************************************* ** From 31eda557e69bd51a4ac17f50f8c127b4311d7128 Mon Sep 17 00:00:00 2001 From: caixinying-git Date: Wed, 9 Aug 2023 10:20:40 +0800 Subject: [PATCH 09/71] docs: provide CN translation for api-reference/peripherals/usb_host.rst --- .../en/api-reference/peripherals/usb_host.rst | 149 +++--- .../api-reference/peripherals/usb_host.rst | 428 +++++++++++++++++- 2 files changed, 511 insertions(+), 66 deletions(-) diff --git a/docs/en/api-reference/peripherals/usb_host.rst b/docs/en/api-reference/peripherals/usb_host.rst index c4a10d46218..2f0756b43ff 100644 --- a/docs/en/api-reference/peripherals/usb_host.rst +++ b/docs/en/api-reference/peripherals/usb_host.rst @@ -1,6 +1,8 @@ USB Host ======== +:link_to_translation:`zh_CN:[中文]` + The document provides information regarding the USB Host Library. This document is split into the following sections: .. contents:: Sections @@ -11,29 +13,30 @@ The document provides information regarding the USB Host Library. This document Overview -------- -The USB Host Library (hereinafter referred to as the Host Library) is the lowest public facing API layer of the ESP-IDF USB Host Stack. In most cases, applications that require USB Host functionality will not need to interface with the Host Library directly. Instead, most applications will use the API provided by a host class driver that is implemented on top of the Host Library. +The USB Host Library (hereinafter referred to as the Host Library) is the lowest layer of the USB Host stack that exposes a public facing API. In most cases, applications that require USB Host functionality do not need to interface with the Host Library directly. Instead, most applications use the API provided by a host class driver that is implemented on top of the Host Library. -However, users may want to use the Host Library directly for some of (but not limited to) the following reasons: +However, you may want to use the Host Library directly for some of (but not limited to) the following reasons: -- The user needs to implement a custom host class driver such as a vendor specific class driver -- The user has a requirement for a lower level of abstraction due to resource/latency requirements +- Implementation of a custom host class driver +- Usage of lower level USB Host API Features & Limitations ^^^^^^^^^^^^^^^^^^^^^^ The Host Library has the following features: -- Supports Full Speed (FS) and Low Speed (LS) Devices -- Supports all four transfer types (Control, Bulk, Interrupt, and Isochronous) -- Allows multiple class drivers to run simultaneously (i.e., multiple clients of the Host Library) -- A single device can be used by multiple clients simultaneously (e.g., composite devices) -- The Host Library itself (and the underlying Host Stack) does not internally instantiate any OS tasks. The number of tasks are entirely controlled by how the Host Library interface is used. However, a general rule of thumb regarding the number of tasks is ``(the number of host class drivers running + 1)``. +- Supports Full Speed (FS) and Low Speed (LS) Devices. +- Supports all four transfer types, i.e., Control, Bulk, Interrupt, and Isochronous. +- Allows multiple class drivers to run simultaneously, i.e., multiple clients of the Host Library. +- A single device can be used by multiple clients simultaneously, e.g., composite devices. +- The Host Library itself and the underlying Host Stack does not internally instantiate any OS tasks. The number of tasks is entirely controlled by how the Host Library interface is used. However, a general rule of thumb regarding the number of tasks is ``(the number of host class drivers running + 1)``. -Currently, the Host Library (and the underlying Host Stack) has the following limitations: +Currently, the Host Library and the underlying Host Stack has the following limitations: - Only supports a single device, but the Host Library's API is designed for multiple device support. -- Only supports Asynchronous transfers -- Transfer timeouts are not supported yet +- Only supports Asynchronous transfers. +- Only supports using the first configuration found. Changing to other configurations is not supported yet. +- Transfer timeouts are not supported yet. .. -------------------------------------------------- Architecture ----------------------------------------------------- @@ -58,43 +61,43 @@ The diagram above shows the key entities that are involved when implementing USB Host Library ^^^^^^^^^^^^ -The Host Library is the a lowest public facing layer of the USB Host Stack. Any other IDF component (such as a class driver or a user component) that needs to communicate with a connected USB device can only do so using the Host Library API either directly or indirectly. +The Host Library is the lowest public-facing API layer of the ESP-IDF USB Host Stack. Any other ESP-IDF component (such as a class driver or a user component) that needs to communicate with a connected USB device can only do so using the Host Library API either directly or indirectly. The Host Library's API is split into two sub-sets, namely the **Library API** and **Client API**. - The Client API handles the communication between a client of the Host Library and one or more USB devices. The Client API should only be called by registered clients of the Host Library. -- The Library API handles all of the Host Library processing that is not specific to a single client (e.g., device enumeration). Usually, the library API is called by a Host Library Daemon Task. +- The Library API handles all of the Host Library processing that is not specific to a single client, such as device enumeration. Usually, the library API is called by a Host Library Daemon Task. Clients ^^^^^^^ -A client of the Host Library is a software component (such as a host class driver or user component) that uses the Host Library to communicate with a USB device. Generally each client has a one-to-one relation with a task, meaning that for a particular client, all of its Client API calls should be done from the context of the same task. +A client of the Host Library is a software component, such as a host class driver or user component, which utilizes the Host Library to establish communication with a USB device. Generally, each client has a one-to-one relation with a task. This implies that all Client API calls pertaining to a specific client must originate from the context of the same task. -By organizing the software components that use the Host Library's into clients, the Host Library can delegate the handling of all client events (i.e., the events specific to that client) to the client's task. In other words, each client task is responsible for all the required processing and event handling associated with the USB communication that the client initiates. +By organizing the software components that use the Host Library's into clients, the Host Library can delegate the handling of all events specific to that client to the client's task. In other words, each client task is responsible for all the required processing and event handling associated with the USB communication that the client initiates. Daemon Task ^^^^^^^^^^^ -Although the Host Library delegates the handling of client events to the clients themselves, there are still Library events (i.e., events that are not specific to a client) that need to be handled. Library event handling can include things such as: +Although the Host Library delegates the handling of client events to the clients themselves, there are still Library events – events that are not specific to any particular client – that need to be handled. Library event handling can include things such as: - Handling USB device connection, enumeration, and disconnection - Rerouting control transfers to/from clients - Forwarding events to clients -Therefore, in addition to the client tasks, the Host Library also requires a task (usually the Host Library Daemon Task) to handle all of the library events. +Therefore, in addition to the client tasks, the Host Library also requires a task, which is usually the Host Library Daemon Task, to handle all of the library events. Devices ^^^^^^^ -The Host Library hides the details of device handling (such as connection, memory allocation, and enumeration) from the clients. The clients are provided only with a list of already connected and enumerated devices to choose from. During enumeration, each device is automatically configured to use the first configuration found (i.e., the first configuration descriptor returned on a Get Configuration Descriptor request). For most standard devices, the first configuration will have a ``bConfigurationValue`` of ``1``. +The Host Library shields clients from the details of device handling, encompassing details such as connection, memory allocation, and enumeration. The clients are provided only with a list of already connected and enumerated devices to choose from. During enumeration, each device is automatically configured to use the first configuration found, namely, the first configuration descriptor returned on a Get Configuration Descriptor request. For most standard devices, the first configuration will have a ``bConfigurationValue`` of ``1``. -It is possible for a two or more clients to simultaneously communicate with the same device as long as they are not communicating to the same interface. However, multiple clients can simultaneously communicate with the same device's default endpoint (EP0), which will result in their control transfers being serialized. +It is possible for two or more clients to simultaneously communicate with the same device as long as they are not communicating to the same interface. However, multiple clients can simultaneously communicate with the same device's default endpoint (i.e., EP0), which will result in their control transfers being serialized. For a client to communicate with a device, the client must: #. Open the device using the device's address. This lets the Host Library know that the client is using that device. #. Claim the interface(s) that will be used for communication. This prevents other clients from claiming the same interface(s). -#. Send transfers to the endpoints in the claimed interface. The client's task is responsible for handling its own processing and events. +#. Send transfers to the endpoints of claimed interfaces. The client's task is responsible for handling its own processing and events related to USB device communication. .. ------------------------------------------------------ Usage -------------------------------------------------------- @@ -102,7 +105,7 @@ For a client to communicate with a device, the client must: Usage ----- -The Host Library (and the underlying Host Stack) will not create any tasks. All tasks (i.e., the client tasks and the Daemon Task) will need to be created by the class drivers or the user. Instead, the Host Library provides two event handler functions that will handle all of the required Host Library processing, thus these functions should be called repeatedly from the client tasks and the Daemon Task. Therefore, the implementation of client tasks and the Daemon Task will be the largely centered around the invocation of these event handler functions. +The Host Library and the underlying Host Stack will not create any tasks. All tasks, namely the client tasks and the Daemon Task, need to be created by the class drivers or the user. Instead, the Host Library provides two event handler functions that handle all of the required Host Library processing, thus these functions should be called repeatedly from the client tasks and the Daemon Task. Therefore, the implementation of client tasks and the Daemon Task will be largely centered around the invocation of these event handler functions. Host Library & Daemon Task ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,9 +113,9 @@ Host Library & Daemon Task Basic Usage """"""""""" -The Host Library API provides :cpp:func:`usb_host_lib_handle_events` to handle library events. This function should be called repeatedly, typically from the daemon task. Some notable features regarding :cpp:func:`usb_host_lib_handle_events` are: +The Host Library API provides :cpp:func:`usb_host_lib_handle_events` to handle library events. This function should be called repeatedly, typically from the Daemon Task. Some notable features regarding :cpp:func:`usb_host_lib_handle_events` are: -- The function can block until a library event needs handling +- The function can block until a library event needs handling. - Event flags are returned on each invocation. These event flags are useful for knowing when the Host Library can be uninstalled. A bare-bones Daemon Task would resemble something like the following code snippet: @@ -140,7 +143,8 @@ A bare-bones Daemon Task would resemble something like the following code snippe } .. note:: - See the :example:`peripherals/usb/host/usb_host_lib` example for a full implementation of the Daemon Task + + See the :example:`peripherals/usb/host/usb_host_lib` example for full implementation of the Daemon Task. Lifecycle """"""""" @@ -152,38 +156,38 @@ Lifecycle Graph of Typical USB Host Library Lifecycle -The graph above illustrates the typical lifecycle of the Host Library with multiple clients and devices. Specifically, the example involves... +The graph above illustrates the typical lifecycle of the Host Library with multiple clients and devices. Specifically, the example involves: -- two registered clients (Client 1 and Client 2) +- two registered clients (Client 1 and Client 2). - two connected devices (Device 1 and Device 2), where Client 1 communicates with Device 1 and Client 2 communicates with Device 2. -With reference the graph above, the typical lifecycle involves the following key stages. +With reference to the graph above, the typical lifecycle involves the following key stages. 1. The Host Library is installed by calling :cpp:func:`usb_host_install`. - Installation must be done before any other Host Library API is called. - - Where :cpp:func:`usb_host_install` is called (e.g., from the Daemon Task or another task) will depend on the synchronization logic between the Daemon Task, client tasks, and the rest of the system. + - Where :cpp:func:`usb_host_install` is called (e.g., from the Daemon Task or another task) depends on the synchronization logic between the Daemon Task, client tasks, and the rest of the system. 2. Once the Host Library is installed, the clients can be registered by calling :cpp:func:`usb_host_client_register`. - - This is typically called from the client task (where the client task waits for a signal from the Daemon Task). + - This is typically called from the client task, where the client task waits for a signal from the Daemon Task. - This can be called elsewhere if necessary as long it is called after :cpp:func:`usb_host_install`. 3. Device 1 connects and is then enumerated. - - Each registered client (in this case Client 1 and Client 2) are notified of the new device by way of the :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` event. + - Each registered client (in this case Client 1 and Client 2) is notified of the new device by way of the :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` event. - Client 1 opens Device 1 and begins communication with it. 4. Similarly Device 2 connects and is enumerated. - - Client 1 and 2 are notified of a new device (via a :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` event). + - Client 1 and 2 are notified of a new device via a :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` event. - Client 2 opens Device 2 and begins communication with it. 5. Device 1 suddenly disconnects. - Client 1 is notified by way of :cpp:enumerator:`USB_HOST_CLIENT_EVENT_DEV_GONE` and begins its cleanup. - Client 2 is not notified as it has not opened Device 1. -6. Client 1 completes its clean up and deregisters by calling :cpp:func:`usb_host_client_deregister`. +6. Client 1 completes its cleanup and deregisters by calling :cpp:func:`usb_host_client_deregister`. - This is typically called from the client task before the task exits. - - This can be called elsewhere if necessary as long as Client 1 has already completed its clean up. + - This can be called elsewhere if necessary as long as Client 1 has already completed its cleanup. 7. Client 2 completes its communication with Device 2. Client 2 then closes Device 2 and deregisters itself. - The Daemon Task is notified of the deregistration of all clients by way the :c:macro:`USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS` event flag as Client 2 is the last client to deregister. - - Device 2 is still allocated (i.e., not freed) as it is still connected albeit not currently opened by any client. -8. The Daemon Task decides to cleanup as there are no more clients. + - Device 2 is still allocated (i.e., not freed), as it is still connected albeit not currently opened by any client. +8. The Daemon Task decides to clean up as there are no more clients. - The Daemon Task must free Device 2 first by calling :cpp:func:`usb_host_device_free_all`. - If :cpp:func:`usb_host_device_free_all` was able to free all devices, the function will return `ESP_OK` indicating that all devices have been freed. - - If :cpp:func:`usb_host_device_free_all` was unable to free all devices (e.g., because the device is still opened by a client), the function will return `ESP_ERR_NOT_FINISHED`. + - If :cpp:func:`usb_host_device_free_all` was unable to free all devices for reasons like the device is still opened by a client, the function will return `ESP_ERR_NOT_FINISHED`. - The Daemon Task must wait for :cpp:func:`usb_host_lib_handle_events` to return the :c:macro:`USB_HOST_LIB_EVENT_FLAGS_ALL_FREE` event flag in order to know when all devices have been freed. 9. Once the Daemon Task has verified that all clients have deregistered and all devices have been freed, it can now uninstall the Host Library by calling :cpp:func:`usb_host_uninstall`. @@ -195,15 +199,16 @@ Basic Usage The Host Library API provides :cpp:func:`usb_host_client_handle_events` to handle a particular client's events. This function should be called repeatedly, typically from the client's task. Some notable features regarding :cpp:func:`usb_host_client_handle_events` are: -- The function can block until a client event needs handling +- The function can block until a client event needs handling. - The function's primary purpose is to call the various event handling callbacks when a client event occurs. The following callbacks are called from within :cpp:func:`usb_host_client_handle_events` thus allowing the client task to be notified of events. -- The client event callback of type :cpp:type:`usb_host_client_event_cb_t` which delivers client event messages to the client. Client event messages indicate events such as the addition or removal of a device. -- The USB transfer completion callback of type :cpp:type:`usb_transfer_cb_t` which indicates that a particular USB transfer previously submitted by the client has completed. +- The client event callback of type :cpp:type:`usb_host_client_event_cb_t` delivers client event messages to the client. Client event messages indicate events such as the addition or removal of a device. +- The USB transfer completion callback of type :cpp:type:`usb_transfer_cb_t` indicates that a particular USB transfer previously submitted by the client has been completed. .. note:: + Given that the callbacks are called from within :cpp:func:`usb_host_client_handle_events`, users should avoid blocking from within the callbacks as this will result in :cpp:func:`usb_host_client_handle_events` being blocked as well, thus preventing other pending client events from being handled. The following code snippet demonstrates a bare-bones host class driver and its client task. The code snippet contains: @@ -230,7 +235,7 @@ The following code snippet demonstrates a bare-bones host class driver and its c static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg) { - //This is function is called from within usb_host_client_handle_events(). Don't block and try to keep it short + // This function is called from within usb_host_client_handle_events(). Do not block and try to keep it short struct class_driver_control *class_driver_obj = (struct class_driver_control *)arg; switch (event_msg->event) { case USB_HOST_CLIENT_EVENT_NEW_DEV: @@ -247,7 +252,7 @@ The following code snippet demonstrates a bare-bones host class driver and its c static void transfer_cb(usb_transfer_t *transfer) { - //This is function is called from within usb_host_client_handle_events(). Don't block and try to keep it short + // This function is called from within usb_host_client_handle_events(). Do not block and try to keep it short struct class_driver_control *class_driver_obj = (struct class_driver_control *)transfer->context; printf("Transfer status %d, actual number of bytes transferred %d\n", transfer->status, transfer->actual_num_bytes); class_driver_obj->actions |= CLASS_DRIVER_ACTION_CLOSE_DEV; @@ -255,10 +260,10 @@ The following code snippet demonstrates a bare-bones host class driver and its c void client_task(void *arg) { - ... //Wait until Host Library is installed - //Initialize class driver objects + ... // Wait until Host Library is installed + // Initialize class driver objects struct class_driver_control class_driver_obj = {0}; - //Register the client + // Register the client usb_host_client_config_t client_config = { .is_synchronous = false, .max_num_event_msg = 5, @@ -275,16 +280,16 @@ The following code snippet demonstrates a bare-bones host class driver and its c //Event handling loop bool exit = false; while (!exit) { - //Call the client event handler function + // Call the client event handler function usb_host_client_handle_events(class_driver_obj.client_hdl, portMAX_DELAY); - //Execute pending class driver actions + // Execute pending class driver actions if (class_driver_obj.actions & CLASS_DRIVER_ACTION_OPEN_DEV) { - //Open the device and claim interface 1 + // Open the device and claim interface 1 usb_host_device_open(class_driver_obj.client_hdl, class_driver_obj.dev_addr, &class_driver_obj.dev_hdl); usb_host_interface_claim(class_driver_obj.client_hdl, class_driver_obj.dev_hdl, 1, 0); } if (class_driver_obj.actions & CLASS_DRIVER_ACTION_TRANSFER) { - //Send an OUT transfer to EP1 + // Send an OUT transfer to EP1 memset(transfer->data_buffer, 0xAA, 1024); transfer->num_bytes = 1024; transfer->device_handle = class_driver_obj.dev_hdl; @@ -294,22 +299,23 @@ The following code snippet demonstrates a bare-bones host class driver and its c usb_host_transfer_submit(transfer); } if (class_driver_obj.actions & CLASS_DRIVER_ACTION_CLOSE_DEV) { - //Release the interface and close the device + // Release the interface and close the device usb_host_interface_release(class_driver_obj.client_hdl, class_driver_obj.dev_hdl, 1); usb_host_device_close(class_driver_obj.client_hdl, class_driver_obj.dev_hdl); exit = true; } - ... //Handle any other actions required by the class driver + ... // Handle any other actions required by the class driver } - //Cleanup class driver + // Cleanup class driver usb_host_transfer_free(transfer); usb_host_client_deregister(class_driver_obj.client_hdl); - ... //Delete the task and any other signal Daemon Task if required + ... // Delete the client task. Signal the Daemon Task if necessary. } .. note:: - An actual host class driver will likely supported many more features, thus will have a much more complex state machine. A host class driver will likely also need to: + + An actual host class driver is likely to support many more features, thus will have a much more complex state machine. A host class driver is also likely to need to: - Be able to open multiple devices - Parse an opened device's descriptors to identify if the device is of the target class @@ -323,7 +329,7 @@ Lifecycle The typical life cycle of a client task and class driver will go through the following stages: #. Wait for some signal regarding the Host Library being installed. -#. Register the client via :cpp:func:`usb_host_client_register` and allocate any other class driver resources (e.g., allocating transfers using :cpp:func:`usb_host_transfer_alloc`). +#. Register the client via :cpp:func:`usb_host_client_register` and allocate any other class driver resources, such as allocating transfers using :cpp:func:`usb_host_transfer_alloc`. #. For each new device that the class driver needs to communicate with: a. Check if the device is already connected via :cpp:func:`usb_host_device_addr_list_fill`. @@ -333,7 +339,7 @@ The typical life cycle of a client task and class driver will go through the fol e. Claim the necessary interfaces of the device via :cpp:func:`usb_host_interface_claim`. #. Submit transfers to the device via :cpp:func:`usb_host_transfer_submit` or :cpp:func:`usb_host_transfer_submit_control`. -#. Once an opened device is no longer needed by the class driver, or has disconnected (as indicated by a :cpp:enumerator:`USB_HOST_CLIENT_EVENT_DEV_GONE` event): +#. Once an opened device is no longer needed by the class driver, or has disconnected, as indicated by a :cpp:enumerator:`USB_HOST_CLIENT_EVENT_DEV_GONE` event: a. Stop any previously submitted transfers to the device's endpoints by calling :cpp:func:`usb_host_endpoint_halt` and :cpp:func:`usb_host_endpoint_flush` on those endpoints. b. Release all previously claimed interfaces via :cpp:func:`usb_host_interface_release`. @@ -351,38 +357,50 @@ Examples Host Library Examples ^^^^^^^^^^^^^^^^^^^^^ -The :example:`peripherals/usb/host/usb_host_lib` demonstrates basic usage of the USB Host Library's API to implement a pseudo class driver. +The :example:`peripherals/usb/host/usb_host_lib` demonstrates basic usage of the USB Host Library's API to implement a pseudo-class driver. Class Driver Examples ^^^^^^^^^^^^^^^^^^^^^ -The USB Host Stack provides a number examples that implement host class drivers using the Host Library's API. +The USB Host Stack provides a number of examples that implement host class drivers using the Host Library's API. CDC-ACM """"""" -* A host class driver for the Communication Device Class (Abstract Control Model) is deployed to `IDF component registry `__. -* The :example:`peripherals/usb/host/cdc/cdc_acm_host` example uses the CDC-ACM host driver component to communicate with CDC-ACM devices +* A host class driver for the Communication Device Class (Abstract Control Model) is distributed as a managed component via the `ESP-IDF Component Registry `__. +* The :example:`peripherals/usb/host/cdc/cdc_acm_host` example uses the CDC-ACM host driver component to communicate with CDC-ACM devices. * The :example:`peripherals/usb/host/cdc/cdc_acm_vcp` example shows how can you extend the CDC-ACM host driver to interface Virtual COM Port devices. * The CDC-ACM driver is also used in `esp_modem examples `__, where it is used for communication with cellular modems. MSC """ -* A host class driver for the Mass Storage Class (Bulk-Only Transport) is deployed to `IDF component registry `__. You can find its example in :example:`peripherals/usb/host/msc`. +* A host class driver for the Mass Storage Class (Bulk-Only Transport) is deployed to `ESP-IDF Component Registry `__. +* The :example:`peripherals/usb/host/msc` example demonstrates the usage of the MSC host driver to read and write to a USB flash drive. + +HID +""" + +* A host class driver for the HID (Human interface device) is distributed as a managed component via the `ESP-IDF Component Registry `__. +* The :example:`peripherals/usb/host/hid` example demonstrates the possibility to receive reports from a USB HID device with several interfaces. +UVC +""" + +* A host class driver for the USB Video Device Class is distributed as a managed component via the `ESP-IDF Component Registry `__. +* The :example:`peripherals/usb/host/uvc` example demonstrates the usage of the UVC host driver to receive a video stream from a USB camera and optionally forward that stream over Wi-Fi. .. -------------------------------------------------- API Reference ---------------------------------------------------- API Reference ------------- -The API of the USB Host Library is separated into the following header files. However, it is sufficient for applications to only ``#include "usb/usb_host.h"`` and all of USB Host Library headers will also be included. +The API of the USB Host Library is separated into the following header files. However, it is sufficient for applications to only ``#include "usb/usb_host.h"`` and all USB Host Library headers will also be included. -- :component_file:`usb/include/usb/usb_host.h` contains the functions and types of the USB Host Library +- :component_file:`usb/include/usb/usb_host.h` contains the functions and types of the USB Host Library. - :component_file:`usb/include/usb/usb_helpers.h` contains various helper functions that are related to the USB protocol such as descriptor parsing. -- :component_file:`usb/include/usb/usb_types_stack.h` contains types that are are used across multiple layers of the USB Host stack. -- :component_file:`usb/include/usb/usb_types_ch9.h` contains types and macros related to Chapter 9 of the USB2.0 specification (i.e., descriptors and standard requests). +- :component_file:`usb/include/usb/usb_types_stack.h` contains types that are used across multiple layers of the USB Host stack. +- :component_file:`usb/include/usb/usb_types_ch9.h` contains types and macros related to Chapter 9 of the USB2.0 specification, i.e., descriptors and standard requests. .. include-build-file:: inc/usb_host.inc @@ -399,6 +417,7 @@ Maintainers Notes ----------------- .. note:: + For more details regarding the internal implementation details of the USB Host stack, please refer to :doc:`/api-reference/peripherals/usb_host/usb_host_notes_index`. .. toctree:: diff --git a/docs/zh_CN/api-reference/peripherals/usb_host.rst b/docs/zh_CN/api-reference/peripherals/usb_host.rst index 64ba8042f5c..8cc03b085b1 100644 --- a/docs/zh_CN/api-reference/peripherals/usb_host.rst +++ b/docs/zh_CN/api-reference/peripherals/usb_host.rst @@ -1 +1,427 @@ -.. include:: ../../../en/api-reference/peripherals/usb_host.rst \ No newline at end of file +USB 主机 +======== + +:link_to_translation:`en:[English]` + +本文档提供了 USB 主机库的相关信息,按以下章节展开: + +.. contents:: 章节 + :depth: 2 + +.. ---------------------------------------------------- Overview ------------------------------------------------------- + +概述 +-------- + +USB 主机库(以下简称主机库)是 USB 主机栈的最底层,提供面向公众开放的 API。应用程序使用 USB 主机功能时,通常无需与主机库直接交互,而是使用某个主机 Class 驱动提供的 API,这些主机 Class 驱动构建在主机库之上。 + +然而,由于以下的某些原因(但不仅限于此),有时你可能需要直接使用主机库: + +- 需要实现自定义主机 Class 驱动程序 +- 需要更低级别的抽象 + +特性和限制 +^^^^^^^^^^^^^^^^^^^^^^ + +主机库具有以下特性: + +- 支持全速 (FS) 和低速 (LS) 设备。 +- 支持四种传输类型,即控制传输、块传输、中断传输和同步传输。 +- 支持多个 Class 驱动程序同时运行,即主机的多个客户端同时运行。 +- 单个设备可以由多个客户端同时使用,如复合设备。 +- 主机库及其底层主机栈不会在内部自动创建操作系统任务,任务数量完全由主机库接口的使用方式决定。一般来说,任务数量为 ``(运行中的主机 Class 驱动程序数量 + 1)``。 + +目前,主机库及其底层主机栈存在以下限制: + +- 仅支持单个设备,而主机库的 API 支持多设备。 +- 仅支持异步传输。 +- 仅支持使用发现的首个配置,尚不支持变更为其他配置。 +- 尚不支持传输超时。 + + +.. -------------------------------------------------- Architecture ----------------------------------------------------- + +架构 +------------ + +.. figure:: ../../../_static/usb_host_lib_entities.png + :align: center + :alt: USB 主机功能的关键实体 + :figclass: align-center + + USB 主机功能涉及的关键实体 + +上图展示了使用 USB 主机功能时涉及的关键实体,包括: + +- **主机库** +- 主机库的 **客户端** +- **设备** +- 主机库的 **守护进程任务** + +主机库 +^^^^^^^^^^^^ + +主机库是 ESP-IDF USB 主机栈中面向公众开放的最底层的 API 层。任何其他 ESP-IDF 组件(如 Class 驱动程序或用户组件),如果需要与连接的 USB 设备通信,只能直接或间接使用主机库 API。 + +主机库 API 分为两类,即 **库 API** 和 **客户端 API**。 + +- 客户端 API 负责主机库的客户端与一或多个 USB 设备间的通信,该 API 只能由主机库的注册客户端调用。 +- 库 API 负责主机库处理的通信中不特定于单个客户端的通信,如设备枚举。该 API 通常由主机库的守护进程任务调用。 + +客户端 +^^^^^^^ + +主机库的客户端指使用主机库与 USB 设备通信的软件组件,如主机 Class 驱动程序或用户组件。每个客户端通常与任务间存在一对一关系,这表明,对特定客户端而言,其所有客户端 API 都应该在同一任务的上下文中调用。 + +通过将使用主机库的软件组件进行分类,划分为独立的客户端,主机库可以将所有客户端特定事件的处理委托给客户端对应的任务。换句话说,每个客户端任务负责管理与其对应的客户端之间的所有 USB 通信操作和事件处理,无需关心其他客户端的事件。 + +守护进程任务 +^^^^^^^^^^^^ + +尽管主机库将客户端事件的处理委托给客户端本身,但仍然需要处理主机库事件,即不特定于客户端的事件。主机库事件处理可能涉及以下内容: + +- 处理 USB 设备的连接、枚举和断连 +- 将控制传输从/向客户端进行重定向 +- 将事件转发给客户端 + +因此,除客户端任务外,主机库也需要一个任务来处理所有的库事件,这个任务通常是主机库守护进程任务。 + +设备 +^^^^^^^ + +主机库隔离了客户端与设备处理的细节,包括连接、内存分配和枚举等,客户端只需提供已连接且已枚举的设备列表供选择。在枚举过程中,每个设备都会自动配置为使用找到的第一个配置,即通过获取配置描述符请求返回的第一个配置描述符。对于大多数标准设备,通常将第一个配置的 ``bConfigurationValue`` 设置为 ``1``。 + +只要不与相同接口通信,两个及以上的客户端可以同时与同一设备通信。然而,多个客户端同时与相同设备的默认端点(即 EP0)通信,将导致它们的控制传输序列化。 + +要与设备通信,客户端必须满足以下条件: + +#. 使用设备地址打开设备,告知主机库,客户端正在使用该设备。 +#. 获取将用于通信的接口,防止其他客户端获取相同的接口。 +#. 通过已经获取了使用权的设备接口的端点通信通道发送数据传输。客户端的任务负责处理其与 USB 设备通信相关的操作和事件。 + + +.. ------------------------------------------------------ Usage -------------------------------------------------------- + +用法 +----- + +主机库及底层主机栈不会创建任何任务,客户端任务和守护进程任务等均需由 Class 驱动程序或用户自行创建。然而,主机库提供了两个事件处理函数,可以处理所有必要的主机库操作,这些函数应从客户端任务和守护进程任务中重复调用。因此,客户端任务和守护进程任务的使用将主要集中于调用这些事件处理函数。 + +主机库与守护进程任务 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +基本用法 +""""""""""" + +主机库 API 提供了 :cpp:func:`usb_host_lib_handle_events`,可以处理库事件。该函数需要反复调用,通常是从守护进程任务中调用。函数 :cpp:func:`usb_host_lib_handle_events` 有以下特点: + +- 该函数会持续阻塞,直至需要处理库事件。 +- 每次调用该函数都会返回事件标志,有助于了解卸载主机库的时机。 + +最基础的守护进程任务通常类似以下代码片段: + +.. code-block:: c + + #include "usb/usb_host.h" + + void daemon_task(void *arg) + { + ... + bool exit = false; + while (!exit) { + uint32_t event_flags; + usb_host_lib_handle_events(portMAX_DELAY, &event_flags); + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { + ... + } + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { + ... + } + ... + } + ... + } + +.. note:: + + 了解守护进程任务的完整示例,请前往 :example:`peripherals/usb/host/usb_host_lib`。 + +生命周期 +""""""""" + +.. figure:: ../../../_static/usb_host_lib_lifecycle.png + :align: center + :alt: USB 主机库典型生命周期 + :figclass: align-center + + USB 主机库典型生命周期 + +上图展示了 USB 主机库的典型生命周期,其中涉及多个客户端和设备。具体而言,示例涉及以下内容: + +- 两个已注册的客户端(客户端 1 和客户端 2)。 +- 两个已连接的设备(设备 1 和设备 2),其中客户端 1 与设备 1 通信,客户端 2 与设备 2 通信。 + +参考上图可知,典型 USB 主机库生命周期包括以下关键阶段: + +1. 调用 :cpp:func:`usb_host_install`,安装主机库。 + - 调用任意主机库 API 前,请确保已完成主机库安装。 + - 调用 :cpp:func:`usb_host_install` 的位置(如从守护进程任务或其他任务中调用)取决于守护系统任务、客户端任务和系统其余部分间的同步逻辑。 +2. 安装完主机库后,调用 :cpp:func:`usb_host_client_register` 注册客户端。 + - 该注册函数通常从客户端任务调用,而客户端任务需等待来自守护进程任务的信号。 + - 调用过 :cpp:func:`usb_host_install` 后,如有需要,也可以在其他地方调用该注册函数。 +3. 设备 1 连接,并进行枚举。 + - 每个已注册的客户端(本案例中为客户端 1 和客户端 2)都会通过 :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` 事件得到新设备的通知。 + - 客户端 1 开启设备 1,并与之通信。 +4. 设备 2 连接,并进行枚举。 + - 客户端 1 和 2 通过 :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` 事件得到新设备的通知。 + - 客户端 2 开启设备 2,并与之通信。 +5. 设备 1 突然断开连接。 + - 客户端 1 通过 :cpp:enumerator:`USB_HOST_CLIENT_EVENT_DEV_GONE` 得到通知,并开始清理,关闭和释放客户端 1 与设备 1 之间的关联资源。 + - 客户端 2 不会收到通知,因为它并未开启设备 1。 +6. 客户端 1 完成清理,调用 :cpp:func:`usb_host_client_deregister` 注销客户端。 + - 该注销函数通常在任务退出前,从客户端任务中调用。 + - 如有需要,只要客户端 1 已完成清理,也可以在其他地方调用该注销函数。 +7. 客户端 2 完成与设备 2 的通信,随后关闭设备 2,并自行注销。 + - 由于客户端 2 是最后一个注销的客户端,通过 :c:macro:`USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS` 事件标志,守护进程任务可以得知,所有客户端已注销。 + - 设备 2 未释放,仍会进行分配,因为虽然没有任何客户端打开设备 2,但它仍处于连接状态。 +8. 所有客户端注销后,守护进程任务开始清理。 + - 守护进程任务需要先调用 :cpp:func:`usb_host_device_free_all`,释放设备 2。 + - 如果 :cpp:func:`usb_host_device_free_all` 能够成功释放所有设备,函数将返回 `ESP_OK`,表明已释放所有设备。 + - 如果 :cpp:func:`usb_host_device_free_all` 无法成功释放所有设备,例如因为设备仍由某个客户端开启,函数将返回 `ESP_ERR_NOT_FINISHED`。 + - 守护进程任务必须等待 :cpp:func:`usb_host_lib_handle_events` 返回事件标志 :c:macro:`USB_HOST_LIB_EVENT_FLAGS_ALL_FREE`,方知何时所有设备均已释放。 +9. 一旦守护进程任务确认所有客户端均已注销,且所有设备均已释放,便可调用 :cpp:func:`usb_host_uninstall`,卸载主机库。 + +客户端与 Class 驱动程序 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +基本用法 +""""""""""" + +主机库 API 提供函数 :cpp:func:`usb_host_client_handle_events`,可以处理特定客户端事件。该函数需要反复调用,通常是从客户端任务中调用。函数 :cpp:func:`usb_host_client_handle_events` 有以下特点: + +- 该函数可以持续阻塞,直至需要处理客户端事件。 +- 该函数的主要目的是发生客户端事件时,调用多个事件处理回调函数。 + +以下回调函数均从 :cpp:func:`usb_host_client_handle_events` 中调用,因此客户端任务能够获取事件通知。 + +- 类型为 :cpp:type:`usb_host_client_event_cb_t` 的客户端事件回调函数会将客户端事件消息传递给客户端,提示添加、移除设备等事件。 +- 类型为 :cpp:type:`usb_transfer_cb_t` 的 USB 传输完成回调函数表明,先前由客户端提交的特定 USB 传输已完成。 + +.. note:: + + 考虑到上述回调函数从 :cpp:func:`usb_host_client_handle_events` 中调用,应避免在回调函数内部阻塞,否则将导致 :cpp:func:`usb_host_client_handle_events` 阻塞,阻止其他待处理的客户端事件得到处理。 + +以下代码片段展示了一个基础的主机 Class 驱动程序及其客户端任务,代码片段中包括: + +- 一个简单的客户端任务函数 ``client_task``,它会在循环中调用 :cpp:func:`usb_host_client_handle_events`。 +- 使用客户端事件回调函数和传输完成回调函数。 +- 一个用于 Class 驱动程序的简单状态机。该 Class 驱动程序仅支持打开设备,发送 OUT 传输到 EP1,然后关闭设备。 + +.. code-block:: c + + #include + #include "usb/usb_host.h" + + #define CLASS_DRIVER_ACTION_OPEN_DEV 0x01 + #define CLASS_DRIVER_ACTION_TRANSFER 0x02 + #define CLASS_DRIVER_ACTION_CLOSE_DEV 0x03 + + struct class_driver_control { + uint32_t actions; + uint8_t dev_addr; + usb_host_client_handle_t client_hdl; + usb_device_handle_t dev_hdl; + }; + + static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg) + { + //该函数从 usb_host_client_handle_events() 中调用,请勿在此阻塞,并尽量保持简洁 + struct class_driver_control *class_driver_obj = (struct class_driver_control *)arg; + switch (event_msg->event) { + case USB_HOST_CLIENT_EVENT_NEW_DEV: + class_driver_obj->actions |= CLASS_DRIVER_ACTION_OPEN_DEV; + class_driver_obj->dev_addr = event_msg->new_dev.address; //存储新设备的地址 + break; + case USB_HOST_CLIENT_EVENT_DEV_GONE: + class_driver_obj->actions |= CLASS_DRIVER_ACTION_CLOSE_DEV; + break; + default: + break; + } + } + + static void transfer_cb(usb_transfer_t *transfer) + { + //该函数从 usb_host_client_handle_events() 中调用,请勿在此阻塞,并尽量保持简洁 + struct class_driver_control *class_driver_obj = (struct class_driver_control *)transfer->context; + printf("Transfer status %d, actual number of bytes transferred %d\n", transfer->status, transfer->actual_num_bytes); + class_driver_obj->actions |= CLASS_DRIVER_ACTION_CLOSE_DEV; + } + + void client_task(void *arg) + { + ... //等待主机库安装 + //初始化 Class 驱动程序对象 + struct class_driver_control class_driver_obj = {0}; + //注册客户端 + usb_host_client_config_t client_config = { + .is_synchronous = false, + .max_num_event_msg = 5, + .async = { + .client_event_callback = client_event_cb, + .callback_arg = &class_driver_obj, + } + }; + usb_host_client_register(&client_config, &class_driver_obj.client_hdl); + //分配一个 USB 传输 + usb_transfer_t *transfer; + usb_host_transfer_alloc(1024, 0, &transfer); + + //事件处理循环 + bool exit = false; + while (!exit) { + //调用客户端事件处理函数 + usb_host_client_handle_events(class_driver_obj.client_hdl, portMAX_DELAY); + //执行待处理的 Class 驱动程序操作 + if (class_driver_obj.actions & CLASS_DRIVER_ACTION_OPEN_DEV) { + //开启设备,声明接口 1 + usb_host_device_open(class_driver_obj.client_hdl, class_driver_obj.dev_addr, &class_driver_obj.dev_hdl); + usb_host_interface_claim(class_driver_obj.client_hdl, class_driver_obj.dev_hdl, 1, 0); + } + if (class_driver_obj.actions & CLASS_DRIVER_ACTION_TRANSFER) { + //发送一个 OUT 传输到 EP1 + memset(transfer->data_buffer, 0xAA, 1024); + transfer->num_bytes = 1024; + transfer->device_handle = class_driver_obj.dev_hdl; + transfer->bEndpointAddress = 0x01; + transfer->callback = transfer_cb; + transfer->context = (void *)&class_driver_obj; + usb_host_transfer_submit(transfer); + } + if (class_driver_obj.actions & CLASS_DRIVER_ACTION_CLOSE_DEV) { + //释放接口,关闭设备 + usb_host_interface_release(class_driver_obj.client_hdl, class_driver_obj.dev_hdl, 1); + usb_host_device_close(class_driver_obj.client_hdl, class_driver_obj.dev_hdl); + exit = true; + } + ... //处理其他 Class 驱动程序要求的行为 + } + + //清理 Class 驱动程序 + usb_host_transfer_free(transfer); + usb_host_client_deregister(class_driver_obj.client_hdl); + ... //删除客户端任务。如有需要,向守护进程任务发送信号。 + } + +.. note:: + + 在实际应用中,主机 Class 驱动程序还能支持更多功能,因此也存在更复杂的状态机。主机 Class 驱动程序可能需要: + + - 能够开启多个设备 + - 解析已开启设备的描述符,确定设备是否是目标 Class + - 按特定顺序,与接口的多个端点通信 + - 声明设备的多个接口 + - 处理各种错误情况 + +生命周期 +""""""""" + +客户端任务与 Class 驱动程序的典型生命周期包括以下关键阶段: + +#. 等待与主机库有关的信号完成安装。 +#. 通过 :cpp:func:`usb_host_client_register` 注册客户端,并分配其他的 Class 驱动程序资源,如使用 :cpp:func:`usb_host_transfer_alloc` 分配传输。 +#. 对于 Class 驱动程序需要与之通信的各个新设备: + + a. 调用 :cpp:func:`usb_host_device_addr_list_fill`,检查设备是否已连接。 + b. 如果设备尚未连接,则等待客户端事件回调函数的 :cpp:enumerator:`USB_HOST_CLIENT_EVENT_NEW_DEV` 事件。 + c. 调用 :cpp:func:`usb_host_device_open` 开启设备。 + d. 分别调用 :cpp:func:`usb_host_get_device_descriptor` 和 :cpp:func:`usb_host_get_active_config_descriptor`,解析设备和配置描述符。 + e. 调用 :cpp:func:`usb_host_interface_claim`,声明设备的必要接口。 + +#. 调用 :cpp:func:`usb_host_transfer_submit` 或 :cpp:func:`usb_host_transfer_submit_control`,向设备提交传输。 +#. 一旦 :cpp:enumerator:`USB_HOST_CLIENT_EVENT_DEV_GONE` 事件表示,Class 驱动程序不再需要已打开的设备,或者设备断开连接: + + a. 在这些端点上调用 :cpp:func:`usb_host_endpoint_halt` 和 :cpp:func:`usb_host_endpoint_flush`,停止先前提交的传输。 + b. 调用 :cpp:func:`usb_host_interface_release`,释放先前声明的所有接口。 + c. 调用 :cpp:func:`usb_host_device_close`,关闭设备。 + +#. 调用 :cpp:func:`usb_host_client_deregister` 注销客户端,并释放其他 Class 驱动程序资源。 +#. 删除客户端任务。如有需要,向守护进程任务发送信号。 + + +.. ---------------------------------------------------- Examples ------------------------------------------------------- + +示例 +-------- + +主机库示例 +^^^^^^^^^^^^^^^^^^^^^ + +:example:`peripherals/usb/host/usb_host_lib` 展示了 USB 主机库 API 的基本用法,用于创建伪 Class 驱动程序。 + +Class 驱动程序示例 +^^^^^^^^^^^^^^^^^^^^^^^^ + +USB 主机栈提供了大量示例,展示了如何通过使用主机库 API 创建主机 Class 驱动程序。 + +CDC-ACM +""""""" + +* 通信设备 Class(抽象控制模型)的主机 Class 驱动程序通过 `ESP-IDF 组件注册器 `__ 作为受管理的组件分发。 +* 示例 :example:`peripherals/usb/host/cdc/cdc_acm_host` 使用 CDC-ACM 主机驱动程序组件,与 CDC-ACM 设备通信。 +* 示例 :example:`peripherals/usb/host/cdc/cdc_acm_vcp` 展示了如何扩展 CDC-ACM 主机驱动程序,与虚拟串口设备交互。 +* 示例 `esp_modem `__ 中也使用了 CDC-ACM 驱动程序,该程序在这些示例中与蜂窝模块通信。 + +MSC +""" + +* 大容量存储 Class(仅支持批量传输)的主机 Class 驱动程序已部署到 `ESP-IDF 组件注册器 `__。 +* 示例 :example:`peripherals/usb/host/msc` 展示了如何使用 MSC 主机驱动程序读写 USB flash 驱动。 + +HID +""" + +* HID(人机接口设备)的主机 class 驱动作为托管组件通过 `ESP-IDF 组件注册器 `__ 分发。 +* 示例 :example:`peripherals/usb/host/hid` 展示了从具有多个接口的 USB HID 设备接收报告的可能性。 + +UVC +""" + +* USB 视频设备 Class 的主机 Class 驱动程序作为托管组件通过 `ESP-IDF 组件注册器 `__ 分发。 +* 示例 :example:`peripherals/usb/host/uvc` 展示了如何使用 UVC 主机驱动程序接收来自 USB 摄像头的视频流,并可选择将该流通过 Wi-Fi 转发。 + +.. -------------------------------------------------- API Reference ---------------------------------------------------- + +API 参考 +------------- + +USB 主机库的 API 包含以下头文件,但应用程序调用该 API 时只需 ``#include "usb/usb_host.h"``,该头文件包含了所有 USB 主机库的头文件。 + +- :component_file:`usb/include/usb/usb_host.h` 包含 USB 主机库的函数和类型。 +- :component_file:`usb/include/usb/usb_helpers.h` 包含与 USB 协议相关的各种辅助函数,如描述符解析等。 +- :component_file:`usb/include/usb/usb_types_stack.h` 包含在 USB 主机栈的多个层次中使用的类型。 +- :component_file:`usb/include/usb/usb_types_ch9.h` 包含了与 USB 2.0 规范中第 9 章相关的类型和宏,即描述符和标准请求。 + + +.. include-build-file:: inc/usb_host.inc + +.. include-build-file:: inc/usb_helpers.inc + +.. include-build-file:: inc/usb_types_stack.inc + +.. include-build-file:: inc/usb_types_ch9.inc + +.. ------------------------------------------------ Maintainers Notes -------------------------------------------------- + +维护注意事项 +----------------- + +.. note:: + + 有关 USB 主机栈内部实现的更多细节,请参阅 :doc:`/api-reference/peripherals/usb_host/usb_host_notes_index`。 + +.. toctree:: + :hidden: + :maxdepth: 0 + + usb_host/usb_host_notes_index From 3981aae79f53c5d5876a5efa843110c1e1352b19 Mon Sep 17 00:00:00 2001 From: Peter Dragun Date: Tue, 8 Aug 2023 10:57:39 +0200 Subject: [PATCH 10/71] feat(tools/monitor): move target tests to monitor repo --- tools/ci/check_copyright_ignore.txt | 1 - tools/requirements/requirements.ttfw.txt | 3 - tools/test_apps/.build-test-rules.yml | 10 -- .../system/monitor_addr_lookup/CMakeLists.txt | 5 - .../system/monitor_addr_lookup/README.md | 2 - .../monitor_addr_lookup/main/CMakeLists.txt | 2 - .../main/Kconfig.projbuild | 7 -- .../system/monitor_addr_lookup/main/main.c | 54 ----------- .../pytest_monitor_addr_lookup.py | 60 ------------ .../sdkconfig.ci.addr_lookup_in_ROM | 1 - .../sdkconfig.ci.addr_lookup_in_app | 1 - .../monitor_ide_integration/CMakeLists.txt | 5 - .../system/monitor_ide_integration/README.md | 2 - .../main/CMakeLists.txt | 2 - .../monitor_ide_integration/main/main.c | 18 ---- .../pytest_monitor_ide_integration.py | 92 ------------------- .../sdkconfig.ci.coredump | 1 - .../sdkconfig.ci.gdb_stub | 1 - 18 files changed, 267 deletions(-) delete mode 100644 tools/test_apps/system/monitor_addr_lookup/CMakeLists.txt delete mode 100644 tools/test_apps/system/monitor_addr_lookup/README.md delete mode 100644 tools/test_apps/system/monitor_addr_lookup/main/CMakeLists.txt delete mode 100644 tools/test_apps/system/monitor_addr_lookup/main/Kconfig.projbuild delete mode 100644 tools/test_apps/system/monitor_addr_lookup/main/main.c delete mode 100644 tools/test_apps/system/monitor_addr_lookup/pytest_monitor_addr_lookup.py delete mode 100644 tools/test_apps/system/monitor_addr_lookup/sdkconfig.ci.addr_lookup_in_ROM delete mode 100644 tools/test_apps/system/monitor_addr_lookup/sdkconfig.ci.addr_lookup_in_app delete mode 100644 tools/test_apps/system/monitor_ide_integration/CMakeLists.txt delete mode 100644 tools/test_apps/system/monitor_ide_integration/README.md delete mode 100644 tools/test_apps/system/monitor_ide_integration/main/CMakeLists.txt delete mode 100644 tools/test_apps/system/monitor_ide_integration/main/main.c delete mode 100644 tools/test_apps/system/monitor_ide_integration/pytest_monitor_ide_integration.py delete mode 100644 tools/test_apps/system/monitor_ide_integration/sdkconfig.ci.coredump delete mode 100644 tools/test_apps/system/monitor_ide_integration/sdkconfig.ci.gdb_stub diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index c61514a2f44..e3e6149b53d 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1336,7 +1336,6 @@ tools/test_apps/system/cxx_no_except/main/main.cpp tools/test_apps/system/gdb_loadable_elf/main/hello_world_main.c tools/test_apps/system/longjmp_test/main/hello_world_main.c tools/test_apps/system/memprot/main/esp32s2/test_memprot_main.c -tools/test_apps/system/monitor_ide_integration/main/main.c tools/test_apps/system/no_embedded_paths/check_for_file_paths.py tools/test_apps/system/no_embedded_paths/main/test_no_embedded_paths_main.c tools/test_apps/system/startup/main/test_startup_main.c diff --git a/tools/requirements/requirements.ttfw.txt b/tools/requirements/requirements.ttfw.txt index fd64d0776f4..e94f844ac6c 100644 --- a/tools/requirements/requirements.ttfw.txt +++ b/tools/requirements/requirements.ttfw.txt @@ -22,6 +22,3 @@ pygobject; sys_platform != 'win32' # esp_prov bleak protobuf - -# tools/test_apps/system/monitor_ide_integration -SimpleWebSocketServer diff --git a/tools/test_apps/.build-test-rules.yml b/tools/test_apps/.build-test-rules.yml index beb2c40aae4..39cadd6f2a2 100644 --- a/tools/test_apps/.build-test-rules.yml +++ b/tools/test_apps/.build-test-rules.yml @@ -136,16 +136,6 @@ tools/test_apps/system/memprot: temporary: true reason: the other targets are not tested yet -tools/test_apps/system/monitor_ide_integration: - enable: - - if: IDF_TARGET == "esp32" or IDF_TARGET == "esp32s2" - temporary: true - reason: the other targets are not tested yet - disable_test: - - if: IDF_TARGET == "esp32s2" - temporary: true - reason: lack of runners - tools/test_apps/system/no_embedded_paths: enable: - if: IDF_TARGET in ["esp32", "esp32c3", "esp32s2"] diff --git a/tools/test_apps/system/monitor_addr_lookup/CMakeLists.txt b/tools/test_apps/system/monitor_addr_lookup/CMakeLists.txt deleted file mode 100644 index f3832d97d0c..00000000000 --- a/tools/test_apps/system/monitor_addr_lookup/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -set(COMPONENTS main) -project(monitor_addr_lookup) diff --git a/tools/test_apps/system/monitor_addr_lookup/README.md b/tools/test_apps/system/monitor_addr_lookup/README.md deleted file mode 100644 index bf47d80ec64..00000000000 --- a/tools/test_apps/system/monitor_addr_lookup/README.md +++ /dev/null @@ -1,2 +0,0 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/tools/test_apps/system/monitor_addr_lookup/main/CMakeLists.txt b/tools/test_apps/system/monitor_addr_lookup/main/CMakeLists.txt deleted file mode 100644 index 8a3ab692792..00000000000 --- a/tools/test_apps/system/monitor_addr_lookup/main/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -idf_component_register(SRCS "main.c" - INCLUDE_DIRS "") diff --git a/tools/test_apps/system/monitor_addr_lookup/main/Kconfig.projbuild b/tools/test_apps/system/monitor_addr_lookup/main/Kconfig.projbuild deleted file mode 100644 index c46107f6026..00000000000 --- a/tools/test_apps/system/monitor_addr_lookup/main/Kconfig.projbuild +++ /dev/null @@ -1,7 +0,0 @@ -config TEST_ADDR_LOOKUP_IN_APP - bool "TEST_ADDR_LOOKUP_IN_APP" - default n - -config TEST_ADDR_LOOKUP_IN_ROM - bool "TEST_ADDR_LOOKUP_IN_ROM" - default n diff --git a/tools/test_apps/system/monitor_addr_lookup/main/main.c b/tools/test_apps/system/monitor_addr_lookup/main/main.c deleted file mode 100644 index 1c14e060e34..00000000000 --- a/tools/test_apps/system/monitor_addr_lookup/main/main.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Unlicense OR CC0-1.0 - */ -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#if CONFIG_TEST_ADDR_LOOKUP_IN_APP -static volatile bool s_initialization_done = false; - -static void initialize(void) -{ - srand(time(0)); -} - -static int get_random_number(void) -{ - if (!s_initialization_done) { - initialize(); - s_initialization_done = true; - } - return rand(); -} -#endif // CONFIG_TEST_ADDR_LOOKUP_IN_APP - -void app_main(void) -{ - printf("app_main is running from 0x%x\n", (int) app_main); - -#if CONFIG_TEST_ADDR_LOOKUP_IN_APP - volatile int number = get_random_number(); - int *n = malloc(sizeof(int)); - - assert(n); - - *n = number; - - printf("Initializer function at 0x%x\n", (int) initialize); - printf("Got %d stored at 0x%x and 0x%x from a function from 0x%x\n", *n, (int) n, (int) (&number), (int) get_random_number); - printf("This is the end of the report\n"); - - free(n); -#endif // CONFIG_TEST_ADDR_LOOKUP_IN_APP - -#if CONFIG_TEST_ADDR_LOOKUP_IN_ROM - printf("Crashing now!\n"); - - esp_rom_install_channel_putc(1, (void (*)(char)) abort); - esp_rom_printf("a"); -#endif // CONFIG_TEST_ADDR_LOOKUP_IN_ROM -} diff --git a/tools/test_apps/system/monitor_addr_lookup/pytest_monitor_addr_lookup.py b/tools/test_apps/system/monitor_addr_lookup/pytest_monitor_addr_lookup.py deleted file mode 100644 index 0d35149d021..00000000000 --- a/tools/test_apps/system/monitor_addr_lookup/pytest_monitor_addr_lookup.py +++ /dev/null @@ -1,60 +0,0 @@ -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: Unlicense OR CC0-1.0 -import os -import re -import sys - -import pexpect -import pytest -from pytest_embedded import Dut - - -@pytest.mark.generic -@pytest.mark.supported_targets -@pytest.mark.parametrize('config', [ - 'addr_lookup_in_app', - 'addr_lookup_in_ROM', -], indirect=True) -def test_monitor_addr_lookup(config: str, dut: Dut) -> None: - # The port needs to be closed because esp_idf_monitor will connect to it - dut.serial.stop_redirect_thread() - - monitor_cmd = ' '.join([sys.executable, '-m', 'esp_idf_monitor', os.path.join(dut.app.binary_path, 'monitor_addr_lookup.elf'), - '--port', str(dut.serial.port)]) - monitor_log_path = os.path.join(dut.logdir, 'monitor.txt') - - with open(monitor_log_path, 'w') as log, pexpect.spawn(monitor_cmd, logfile=log, timeout=5, encoding='utf-8', codec_errors='ignore') as p: - p.expect_exact('main_task: Calling app_main()') - - ADDRESS = r'0x[a-f0-9]{8}' - FUNC_NAME = r'[a-zA-Z_][\w]*' - - p.expect(re.compile(rf'app_main is running from ({ADDRESS})')) - addr = p.match.group(1) - p.expect_exact(f'{addr}: app_main at') - - if config == 'addr_lookup_in_app': - p.expect(re.compile(rf'Initializer function at ({ADDRESS})')) - addr = p.match.group(1) - p.expect_exact(f'{addr}: initialize at') - - p.expect(re.compile(rf'Got \d+ stored at ({ADDRESS}) and ({ADDRESS}) from a function from ({ADDRESS})')) - var1 = p.match.group(1) - var2 = p.match.group(2) - func = p.match.group(3) - match_index = p.expect([str(var1), str(var2), pexpect.TIMEOUT]) - assert match_index == 2 # should be TIMEOUT because addr2line should not match addresses of variables - p.expect_exact(f'{func}: get_random_number at') - - p.expect_exact('This is the end of the report') - - elif config == 'addr_lookup_in_ROM': - p.expect_exact('Crashing now!') - - p.expect(re.compile(rf'abort\(\) was called at PC ({ADDRESS}) on core 0')) - addr = p.match.group(1) - p.expect_exact(f'abort() was called at PC {addr} on core 0') - - p.expect(re.compile(rf'({ADDRESS}): ({FUNC_NAME}) in ROM')) - addr, func = p.match.group(1), p.match.group(2) - p.expect_exact(f'{addr}: {func} in ROM') diff --git a/tools/test_apps/system/monitor_addr_lookup/sdkconfig.ci.addr_lookup_in_ROM b/tools/test_apps/system/monitor_addr_lookup/sdkconfig.ci.addr_lookup_in_ROM deleted file mode 100644 index 282db80b755..00000000000 --- a/tools/test_apps/system/monitor_addr_lookup/sdkconfig.ci.addr_lookup_in_ROM +++ /dev/null @@ -1 +0,0 @@ -CONFIG_TEST_ADDR_LOOKUP_IN_ROM=y diff --git a/tools/test_apps/system/monitor_addr_lookup/sdkconfig.ci.addr_lookup_in_app b/tools/test_apps/system/monitor_addr_lookup/sdkconfig.ci.addr_lookup_in_app deleted file mode 100644 index d56aeebea52..00000000000 --- a/tools/test_apps/system/monitor_addr_lookup/sdkconfig.ci.addr_lookup_in_app +++ /dev/null @@ -1 +0,0 @@ -CONFIG_TEST_ADDR_LOOKUP_IN_APP=y diff --git a/tools/test_apps/system/monitor_ide_integration/CMakeLists.txt b/tools/test_apps/system/monitor_ide_integration/CMakeLists.txt deleted file mode 100644 index ae472ee1a60..00000000000 --- a/tools/test_apps/system/monitor_ide_integration/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -set(COMPONENTS main esp_gdbstub espcoredump) -project(panic) diff --git a/tools/test_apps/system/monitor_ide_integration/README.md b/tools/test_apps/system/monitor_ide_integration/README.md deleted file mode 100644 index ac8bb22c88a..00000000000 --- a/tools/test_apps/system/monitor_ide_integration/README.md +++ /dev/null @@ -1,2 +0,0 @@ -| Supported Targets | ESP32 | ESP32-S2 | -| ----------------- | ----- | -------- | diff --git a/tools/test_apps/system/monitor_ide_integration/main/CMakeLists.txt b/tools/test_apps/system/monitor_ide_integration/main/CMakeLists.txt deleted file mode 100644 index 8a3ab692792..00000000000 --- a/tools/test_apps/system/monitor_ide_integration/main/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -idf_component_register(SRCS "main.c" - INCLUDE_DIRS "") diff --git a/tools/test_apps/system/monitor_ide_integration/main/main.c b/tools/test_apps/system/monitor_ide_integration/main/main.c deleted file mode 100644 index 5229715e7bb..00000000000 --- a/tools/test_apps/system/monitor_ide_integration/main/main.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Monitor-IDE integration test - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_system.h" - -void app_main(void) -{ - int *p = (int *)4; - vTaskDelay(2000 / portTICK_PERIOD_MS); - *p = 0; -} diff --git a/tools/test_apps/system/monitor_ide_integration/pytest_monitor_ide_integration.py b/tools/test_apps/system/monitor_ide_integration/pytest_monitor_ide_integration.py deleted file mode 100644 index ec66113bf1b..00000000000 --- a/tools/test_apps/system/monitor_ide_integration/pytest_monitor_ide_integration.py +++ /dev/null @@ -1,92 +0,0 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: Unlicense OR CC0-1.0 -import json -import logging -import multiprocessing -import os -import re -import sys -from types import TracebackType -from typing import Optional, Type, TypeVar - -import pexpect -import pytest -from pytest_embedded import Dut -from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket - -WebSocketServerType = TypeVar('WebSocketServerType') - - -class IDEWSProtocol(WebSocket): - - def handleMessage(self) -> None: - try: - j = json.loads(self.data) - except Exception as e: - logging.info(f'Server ignores error: {e}') - return - event = j.get('event') - if event and 'prog' in j and ((event == 'gdb_stub' and 'port' in j) or - (event == 'coredump' and 'file' in j)): - payload = {'event': 'debug_finished'} - self.sendMessage(json.dumps(payload)) - logging.info(f'Server sent: {payload}') - else: - logging.info(f'Server received: {j}') - - def handleConnected(self) -> None: - logging.info(f'{self.address} connected to server') - - def handleClose(self) -> None: - logging.info(f'{self.address} closed the connection') - - -class WebSocketServer(object): - HOST = '127.0.0.1' - PORT = 1123 - - def run(self) -> None: - server = SimpleWebSocketServer(self.HOST, self.PORT, IDEWSProtocol) - while not self.exit_event.is_set(): - server.serveonce() - - def __init__(self) -> None: - self.exit_event = multiprocessing.Event() - self.proc = multiprocessing.Process(target=self.run) - self.proc.start() - - def __enter__(self: WebSocketServerType) -> WebSocketServerType: - return self - - def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: - Optional[TracebackType]) -> None: - self.exit_event.set() - self.proc.join(10) - if self.proc.is_alive(): - logging.info('Process cannot be joined') - - -@pytest.mark.esp32 -@pytest.mark.generic -@pytest.mark.parametrize('config', ['gdb_stub', 'coredump'], indirect=True) -def test_monitor_ide_integration(config: str, dut: Dut) -> None: - # The port needs to be closed because esp_idf_monitor will connect to it - dut.serial.stop_redirect_thread() - - monitor_cmd = ' '.join([sys.executable, '-m', 'esp_idf_monitor', os.path.join(dut.app.binary_path, 'panic.elf'), - '--port', str(dut.serial.port), - '--ws', f'ws://{WebSocketServer.HOST}:{WebSocketServer.PORT}']) - monitor_log_path = os.path.join(dut.logdir, 'monitor.txt') - - with open(monitor_log_path, 'w') as log, WebSocketServer(), pexpect.spawn(monitor_cmd, - logfile=log, - timeout=5, - encoding='utf-8', - codec_errors='ignore') as p: - p.expect(re.compile(r'Guru Meditation Error'), timeout=10) - p.expect_exact('Communicating through WebSocket') - # The elements of dictionary can be printed in different order depending on the Python version. - p.expect(re.compile(r"WebSocket sent: \{.*'event': '" + config + "'")) - p.expect_exact('Waiting for debug finished event') - p.expect(re.compile(r"WebSocket received: \{'event': 'debug_finished'\}")) - p.expect_exact('Communications through WebSocket is finished') diff --git a/tools/test_apps/system/monitor_ide_integration/sdkconfig.ci.coredump b/tools/test_apps/system/monitor_ide_integration/sdkconfig.ci.coredump deleted file mode 100644 index 48ffbae9a2a..00000000000 --- a/tools/test_apps/system/monitor_ide_integration/sdkconfig.ci.coredump +++ /dev/null @@ -1 +0,0 @@ -CONFIG_ESP_COREDUMP_ENABLE_TO_UART=y diff --git a/tools/test_apps/system/monitor_ide_integration/sdkconfig.ci.gdb_stub b/tools/test_apps/system/monitor_ide_integration/sdkconfig.ci.gdb_stub deleted file mode 100644 index 38830f8dd68..00000000000 --- a/tools/test_apps/system/monitor_ide_integration/sdkconfig.ci.gdb_stub +++ /dev/null @@ -1 +0,0 @@ -CONFIG_ESP_SYSTEM_PANIC_GDBSTUB=y From 7a878bdc50741b7a129f44d8cdddcdfc58e7c5db Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Wed, 6 Sep 2023 19:33:39 +0800 Subject: [PATCH 11/71] feat(esp_system): Support IPC_ISR for ESP32P4 --- components/esp_system/Kconfig | 9 +- components/esp_system/include/esp_ipc_isr.h | 39 ++++-- .../include/esp_private/esp_ipc_isr.h | 2 +- components/esp_system/port/CMakeLists.txt | 15 ++- .../port/arch/riscv/esp_ipc_isr_handler.S | 78 +++++++++++ .../port/arch/riscv/esp_ipc_isr_port.c | 48 +++++++ .../port/arch/riscv/esp_ipc_isr_routines.c | 12 ++ .../port/arch/xtensa/esp_ipc_isr_port.c | 36 +++++ .../port/{arch/xtensa => }/esp_ipc_isr.c | 30 +---- .../private/esp_private/esp_ipc_isr_port.h | 39 ++++++ .../main/CMakeLists.txt | 7 +- .../main/port/arch/riscv/test_ipc_isr.c | 29 +++++ .../{ => port/arch/xtensa}/test_ipc_isr.S | 10 +- .../main/test_ipc_isr.c | 28 ++-- components/riscv/vectors_clic.S | 8 +- .../soc/esp32p4/include/soc/hp_system_reg.h | 1 - components/soc/esp32p4/include/soc/soc.h | 1 + docs/docs_not_updated/esp32p4.txt | 1 - docs/en/api-reference/system/index.rst | 2 +- docs/en/api-reference/system/ipc.rst | 123 +++++++++++------- examples/system/.build-test-rules.yml | 16 ++- .../ipc/ipc_isr/{ => riscv}/CMakeLists.txt | 0 examples/system/ipc/ipc_isr/riscv/README.md | 56 ++++++++ .../ipc/ipc_isr/riscv/main/CMakeLists.txt | 3 + .../system/ipc/ipc_isr/riscv/main/callbacks.c | 22 ++++ .../system/ipc/ipc_isr/riscv/main/callbacks.h | 15 +++ examples/system/ipc/ipc_isr/riscv/main/main.c | 43 ++++++ .../ipc/ipc_isr/riscv/pytest_ipc_isr_riscv.py | 20 +++ .../ipc_isr/{ => riscv}/sdkconfig.defaults | 0 .../system/ipc/ipc_isr/xtensa/CMakeLists.txt | 6 + .../system/ipc/ipc_isr/{ => xtensa}/README.md | 2 +- .../ipc_isr/{ => xtensa}/main/CMakeLists.txt | 0 .../ipc/ipc_isr/{ => xtensa}/main/asm_funcs.S | 0 .../ipc/ipc_isr/{ => xtensa}/main/main.c | 20 ++- .../pytest_ipc_isr_xtensa.py} | 2 +- .../ipc/ipc_isr/xtensa/sdkconfig.defaults | 0 tools/ci/check_copyright_ignore.txt | 1 - 37 files changed, 591 insertions(+), 133 deletions(-) create mode 100644 components/esp_system/port/arch/riscv/esp_ipc_isr_handler.S create mode 100644 components/esp_system/port/arch/riscv/esp_ipc_isr_port.c create mode 100644 components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c create mode 100644 components/esp_system/port/arch/xtensa/esp_ipc_isr_port.c rename components/esp_system/port/{arch/xtensa => }/esp_ipc_isr.c (85%) create mode 100644 components/esp_system/port/include/private/esp_private/esp_ipc_isr_port.h create mode 100644 components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/riscv/test_ipc_isr.c rename components/esp_system/test_apps/esp_system_unity_tests/main/{ => port/arch/xtensa}/test_ipc_isr.S (86%) rename examples/system/ipc/ipc_isr/{ => riscv}/CMakeLists.txt (100%) create mode 100644 examples/system/ipc/ipc_isr/riscv/README.md create mode 100644 examples/system/ipc/ipc_isr/riscv/main/CMakeLists.txt create mode 100644 examples/system/ipc/ipc_isr/riscv/main/callbacks.c create mode 100644 examples/system/ipc/ipc_isr/riscv/main/callbacks.h create mode 100644 examples/system/ipc/ipc_isr/riscv/main/main.c create mode 100644 examples/system/ipc/ipc_isr/riscv/pytest_ipc_isr_riscv.py rename examples/system/ipc/ipc_isr/{ => riscv}/sdkconfig.defaults (100%) create mode 100644 examples/system/ipc/ipc_isr/xtensa/CMakeLists.txt rename examples/system/ipc/ipc_isr/{ => xtensa}/README.md (97%) rename examples/system/ipc/ipc_isr/{ => xtensa}/main/CMakeLists.txt (100%) rename examples/system/ipc/ipc_isr/{ => xtensa}/main/asm_funcs.S (100%) rename examples/system/ipc/ipc_isr/{ => xtensa}/main/main.c (74%) rename examples/system/ipc/ipc_isr/{pytest_ipc_isr.py => xtensa/pytest_ipc_isr_xtensa.py} (92%) create mode 100644 examples/system/ipc/ipc_isr/xtensa/sdkconfig.defaults diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index 16ff40306f1..e202c51fbb9 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -530,19 +530,19 @@ menu "ESP System Settings" prompt "Interrupt level to use for Interrupt Watchdog and other system checks" default ESP_SYSTEM_CHECK_INT_LEVEL_4 help - Interrupt level to use for Interrupt Watchdog and other system checks. + Interrupt level to use for Interrupt Watchdog, IPC_ISR and other system checks. config ESP_SYSTEM_CHECK_INT_LEVEL_5 bool "Level 5 interrupt" depends on IDF_TARGET_ESP32 help - Using level 5 interrupt for Interrupt Watchdog and other system checks. + Using level 5 interrupt for Interrupt Watchdog, IPC_ISR and other system checks. config ESP_SYSTEM_CHECK_INT_LEVEL_4 bool "Level 4 interrupt" depends on !BTDM_CTRL_HLI help - Using level 4 interrupt for Interrupt Watchdog and other system checks. + Using level 4 interrupt for Interrupt Watchdog, IPC_ISR and other system checks. endchoice # Insert chip-specific system config @@ -595,11 +595,10 @@ menu "IPC (Inter-Processor Call)" config ESP_IPC_ISR_ENABLE bool - default n if IDF_TARGET_ESP32P4 # TODO: IDF-7769 default y if !FREERTOS_UNICORE help The IPC ISR feature is similar to the IPC feature except that the callback function is executed in the - context of a High Priority Interrupt. The IPC ISR feature is itended for low latency execution of simple + context of a High Priority Interrupt. The IPC ISR feature is intended for low latency execution of simple callbacks written in assembly on another CPU. Due to being run in a High Priority Interrupt, the assembly callbacks must be written with particular restrictions (see "IPC" and "High-Level Interrupt" docs for more details). diff --git a/components/esp_system/include/esp_ipc_isr.h b/components/esp_system/include/esp_ipc_isr.h index 70290ba5618..eb6919da9c3 100644 --- a/components/esp_system/include/esp_ipc_isr.h +++ b/components/esp_system/include/esp_ipc_isr.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,31 +17,44 @@ extern "C" { /** * @brief IPC ISR Callback * - * A callback of this type should be provided as an argument when calling esp_ipc_isr_asm_call() or - * esp_ipc_isr_asm_call_blocking(). + * The callback must be written: + * - in assembly for XTENSA chips (such as ESP32, ESP32S3). + * - in C or assembly for RISCV chips (such as ESP32P4). + * + * A callback of this type should be provided as an argument when calling esp_ipc_isr_call() or + * esp_ipc_isr_call_blocking(). */ typedef void (*esp_ipc_isr_func_t)(void* arg); /** - * @brief Execute an assembly callback on the other CPU + * @brief Execute an ISR callback on the other CPU * * Execute a given callback on the other CPU in the context of a High Priority Interrupt. * * - This function will busy-wait in a critical section until the other CPU has started execution of the callback - * - The callback must be written in assembly, is invoked using a CALLX0 instruction, and has a2, a3, a4 as scratch - * registers. See docs for more details + * - The callback must be written: + * - in assembly for XTENSA chips (such as ESP32, ESP32S3). + * The function is invoked using a CALLX0 instruction and can use only a2, a3, a4 registers. + * See :doc:`IPC in Interrupt Context ` doc for more details. + * - in C or assembly for RISCV chips (such as ESP32P4). * * @note This function is not available in single-core mode. * * @param[in] func Pointer to a function of type void func(void* arg) to be executed * @param[in] arg Arbitrary argument of type void* to be passed into the function */ -void esp_ipc_isr_asm_call(esp_ipc_isr_func_t func, void* arg); +void esp_ipc_isr_call(esp_ipc_isr_func_t func, void* arg) ; + +/** + * @brief Execute an ISR callback on the other CPU + * See esp_ipc_isr_call(). + */ +#define esp_ipc_isr_asm_call(func, arg) esp_ipc_isr_call(func, arg) /** - * @brief Execute an assembly callback on the other CPU and busy-wait until it completes + * @brief Execute an ISR callback on the other CPU and busy-wait until it completes * - * This function is identical to esp_ipc_isr_asm_call() except that this function will busy-wait until the execution of + * This function is identical to esp_ipc_isr_call() except that this function will busy-wait until the execution of * the callback completes. * * @note This function is not available in single-core mode. @@ -49,7 +62,13 @@ void esp_ipc_isr_asm_call(esp_ipc_isr_func_t func, void* arg); * @param[in] func Pointer to a function of type void func(void* arg) to be executed * @param[in] arg Arbitrary argument of type void* to be passed into the function */ -void esp_ipc_isr_asm_call_blocking(esp_ipc_isr_func_t func, void* arg); +void esp_ipc_isr_call_blocking(esp_ipc_isr_func_t func, void* arg); + +/** + * @brief Execute an ISR callback on the other CPU and busy-wait until it completes + * See esp_ipc_isr_call_blocking(). + */ +#define esp_ipc_isr_asm_call_blocking(func, arg) esp_ipc_isr_call_blocking(func, arg) /** * @brief Stall the other CPU diff --git a/components/esp_system/include/esp_private/esp_ipc_isr.h b/components/esp_system/include/esp_private/esp_ipc_isr.h index ccdfe1deaa2..6a6d9f8cd82 100644 --- a/components/esp_system/include/esp_private/esp_ipc_isr.h +++ b/components/esp_system/include/esp_private/esp_ipc_isr.h @@ -26,7 +26,7 @@ extern "C" { * - This function will register a High Priority Interrupt for a CPU where it is called. The priority of the interrupts is dependent on * the CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL option. * - Callbacks written in assembly can then run in context of the registered High Priority Interrupts - * - Callbacks can be executed by calling esp_ipc_isr_asm_call() or esp_ipc_isr_asm_call_blocking() + * - Callbacks can be executed by calling esp_ipc_isr_call() or esp_ipc_isr_call_blocking() */ void esp_ipc_isr_init(void); diff --git a/components/esp_system/port/CMakeLists.txt b/components/esp_system/port/CMakeLists.txt index 7a323b9ea2b..0ad54184289 100644 --- a/components/esp_system/port/CMakeLists.txt +++ b/components/esp_system/port/CMakeLists.txt @@ -17,11 +17,16 @@ if(CONFIG_ESP_CONSOLE_USB_CDC) endif() if(CONFIG_ESP_IPC_ISR_ENABLE) -if(CONFIG_IDF_TARGET_ARCH_XTENSA) - list(APPEND srcs "arch/xtensa/esp_ipc_isr.c" - "arch/xtensa/esp_ipc_isr_handler.S" - "arch/xtensa/esp_ipc_isr_routines.S") -endif() + list(APPEND srcs "esp_ipc_isr.c") + if(CONFIG_IDF_TARGET_ARCH_XTENSA) + list(APPEND srcs "arch/xtensa/esp_ipc_isr_port.c" + "arch/xtensa/esp_ipc_isr_handler.S" + "arch/xtensa/esp_ipc_isr_routines.S") + elseif(CONFIG_IDF_TARGET_ARCH_RISCV) + list(APPEND srcs "arch/riscv/esp_ipc_isr_port.c" + "arch/riscv/esp_ipc_isr_handler.S" + "arch/riscv/esp_ipc_isr_routines.c") + endif() endif() if(CONFIG_IDF_TARGET_ARCH_XTENSA) diff --git a/components/esp_system/port/arch/riscv/esp_ipc_isr_handler.S b/components/esp_system/port/arch/riscv/esp_ipc_isr_handler.S new file mode 100644 index 00000000000..c5a37174c8f --- /dev/null +++ b/components/esp_system/port/arch/riscv/esp_ipc_isr_handler.S @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/hp_system_reg.h" + +/* IPC_ISR handler */ + .equ SAVE_REGS, 16 /* count of saving regs: a0 - a7, t0 - t6, ra */ + .equ CONTEXT_SIZE, (SAVE_REGS * 4) + .section .iram1,"ax" + .global esp_ipc_isr_handler + .type esp_ipc_isr_handler,@function +esp_ipc_isr_handler: + + /* save a0 - a7, t0 - t6, ra */ + addi sp, sp, -(CONTEXT_SIZE) + sw a0, 0(sp) + sw a1, 4(sp) + sw a2, 8(sp) + sw a3, 12(sp) + sw a4, 16(sp) + sw a5, 20(sp) + sw a6, 24(sp) + sw a7, 28(sp) + sw t0, 32(sp) + sw t1, 36(sp) + sw t2, 40(sp) + sw t3, 44(sp) + sw t4, 48(sp) + sw t5, 52(sp) + sw t6, 56(sp) + sw ra, 60(sp) + + /* MIE is cleared, so nested interrupts are disabled */ + + /* Reset isr interrupt flags */ + li a1, HP_SYSTEM_CPU_INT_FROM_CPU_2_REG + csrr a0, mhartid # Get CORE_ID + beqz a0, 1f + li a1, HP_SYSTEM_CPU_INT_FROM_CPU_3_REG +1: + sw zero, (a1) + + /* Set the start flag */ + la a0, esp_ipc_isr_start_fl + sw a0, 0(a0) + + /* Call the esp_ipc_func(void* esp_ipc_func_arg) */ + lw a1, (esp_ipc_func) + lw a0, (esp_ipc_func_arg) + jalr a1 + + /* Set the end flag */ + la a0, esp_ipc_isr_end_fl + sw a0, 0(a0) + + /* Restore a0 - a7, t0 - t6, ra */ + lw a0, 0(sp) + lw a1, 4(sp) + lw a2, 8(sp) + lw a3, 12(sp) + lw a4, 16(sp) + lw a5, 20(sp) + lw a6, 24(sp) + lw a7, 28(sp) + lw t0, 32(sp) + lw t1, 36(sp) + lw t2, 40(sp) + lw t3, 44(sp) + lw t4, 48(sp) + lw t5, 52(sp) + lw t6, 56(sp) + lw ra, 60(sp) + addi sp, sp, (CONTEXT_SIZE) + + mret diff --git a/components/esp_system/port/arch/riscv/esp_ipc_isr_port.c b/components/esp_system/port/arch/riscv/esp_ipc_isr_port.c new file mode 100644 index 00000000000..181d6075f89 --- /dev/null +++ b/components/esp_system/port/arch/riscv/esp_ipc_isr_port.c @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "soc/interrupts.h" +#include "soc/hp_system_reg.h" +#include "esp_intr_alloc.h" +#include "riscv/interrupt.h" +#include "esp_rom_sys.h" +#include "esp_cpu.h" +#include "esp_attr.h" +#include "sdkconfig.h" + + +void esp_ipc_isr_port_init(const int cpuid) +{ + uint32_t intr_source = ETS_FROM_CPU_INTR2_SOURCE + cpuid; // ETS_FROM_CPU_INTR2_SOURCE and ETS_FROM_CPU_INTR3_SOURCE + + esp_intr_disable_source(ETS_IPC_ISR_INUM); + + esp_rom_route_intr_matrix(cpuid, intr_source, ETS_IPC_ISR_INUM); + + esp_cpu_intr_set_type(ETS_IPC_ISR_INUM, INTR_TYPE_LEVEL); + +#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 + esp_cpu_intr_set_priority(ETS_IPC_ISR_INUM, 5); +#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4 + esp_cpu_intr_set_priority(ETS_IPC_ISR_INUM, 4); +#else + #error "CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL is not defined!" +#endif + + esp_intr_enable_source(ETS_IPC_ISR_INUM); +} + +IRAM_ATTR void esp_ipc_isr_port_int_trigger(const int cpuid) +{ + if (cpuid == 0) { + // it runs an interrupt on cpu0 + REG_WRITE(HP_SYSTEM_CPU_INT_FROM_CPU_2_REG, HP_SYSTEM_CPU_INT_FROM_CPU_2); + } else { + // it runs an interrupt on cpu1 + REG_WRITE(HP_SYSTEM_CPU_INT_FROM_CPU_3_REG, HP_SYSTEM_CPU_INT_FROM_CPU_3); + } +} diff --git a/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c b/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c new file mode 100644 index 00000000000..27ea167f3d5 --- /dev/null +++ b/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "stdint.h" + +void esp_ipc_isr_waiting_for_finish_cmd(void* ipc_isr_finish_cmd) +{ + while (*(volatile uint32_t*)ipc_isr_finish_cmd == 0) { }; +} diff --git a/components/esp_system/port/arch/xtensa/esp_ipc_isr_port.c b/components/esp_system/port/arch/xtensa/esp_ipc_isr_port.c new file mode 100644 index 00000000000..7224c38ee92 --- /dev/null +++ b/components/esp_system/port/arch/xtensa/esp_ipc_isr_port.c @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc.h" +#include "soc/interrupts.h" +#include "soc/dport_reg.h" +#ifndef CONFIG_IDF_TARGET_ESP32 +#include "soc/system_reg.h" +#endif +#include "esp_rom_sys.h" +#include "esp_intr_alloc.h" +#include "esp_attr.h" +#include "sdkconfig.h" + + +void esp_ipc_isr_port_init(const int cpuid) +{ + uint32_t intr_source = ETS_FROM_CPU_INTR2_SOURCE + cpuid; // ETS_FROM_CPU_INTR2_SOURCE and ETS_FROM_CPU_INTR3_SOURCE + ESP_INTR_DISABLE(ETS_IPC_ISR_INUM); + esp_rom_route_intr_matrix(cpuid, intr_source, ETS_IPC_ISR_INUM); + ESP_INTR_ENABLE(ETS_IPC_ISR_INUM); +} + +IRAM_ATTR void esp_ipc_isr_port_int_trigger(const int cpuid) +{ + if (cpuid == 0) { + // it runs an interrupt on cpu0 + DPORT_REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_2_REG, SYSTEM_CPU_INTR_FROM_CPU_2); + } else { + // it runs an interrupt on cpu1 + DPORT_REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_3_REG, SYSTEM_CPU_INTR_FROM_CPU_3); + } +} diff --git a/components/esp_system/port/arch/xtensa/esp_ipc_isr.c b/components/esp_system/port/esp_ipc_isr.c similarity index 85% rename from components/esp_system/port/arch/xtensa/esp_ipc_isr.c rename to components/esp_system/port/esp_ipc_isr.c index 5ffcb76e21b..0e7c1cdbc71 100644 --- a/components/esp_system/port/arch/xtensa/esp_ipc_isr.c +++ b/components/esp_system/port/esp_ipc_isr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,19 +10,12 @@ #include #include "esp_err.h" #include "esp_attr.h" -#include "soc/soc.h" -#include "soc/dport_reg.h" -#ifndef CONFIG_IDF_TARGET_ESP32 -#include "soc/periph_defs.h" -#include "soc/system_reg.h" -#endif #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/portmacro.h" -#include "esp_intr_alloc.h" #include "esp_private/esp_ipc_isr.h" +#include "esp_private/esp_ipc_isr_port.h" #include "esp_ipc_isr.h" -#include "xtensa/core-macros.h" #include "sdkconfig.h" static portMUX_TYPE s_ipc_isr_mux = portMUX_INITIALIZER_UNLOCKED; @@ -61,10 +54,7 @@ static void esp_ipc_isr_call_and_wait(esp_ipc_isr_func_t func, void* arg, esp_ip void esp_ipc_isr_init(void) { const uint32_t cpuid = xPortGetCoreID(); - uint32_t intr_source = ETS_FROM_CPU_INTR2_SOURCE + cpuid; // ETS_FROM_CPU_INTR2_SOURCE and ETS_FROM_CPU_INTR3_SOURCE - ESP_INTR_DISABLE(ETS_IPC_ISR_INUM); - esp_rom_route_intr_matrix(cpuid, intr_source, ETS_IPC_ISR_INUM); - ESP_INTR_ENABLE(ETS_IPC_ISR_INUM); + esp_ipc_isr_port_init(cpuid); if (cpuid != 0) { s_stall_state = STALL_STATE_RUNNING; @@ -76,14 +66,14 @@ void esp_ipc_isr_init(void) /* Public API functions */ -void IRAM_ATTR esp_ipc_isr_asm_call(esp_ipc_isr_func_t func, void* arg) +void IRAM_ATTR esp_ipc_isr_call(esp_ipc_isr_func_t func, void* arg) { IPC_ISR_ENTER_CRITICAL(); esp_ipc_isr_call_and_wait(func, arg, IPC_ISR_WAIT_FOR_START); IPC_ISR_EXIT_CRITICAL(); } -void IRAM_ATTR esp_ipc_isr_asm_call_blocking(esp_ipc_isr_func_t func, void* arg) +void IRAM_ATTR esp_ipc_isr_call_blocking(esp_ipc_isr_func_t func, void* arg) { IPC_ISR_ENTER_CRITICAL(); esp_ipc_isr_call_and_wait(func, arg, IPC_ISR_WAIT_FOR_END); @@ -201,14 +191,8 @@ static void IRAM_ATTR esp_ipc_isr_call_and_wait(esp_ipc_isr_func_t func, void* a esp_ipc_isr_start_fl = 0; esp_ipc_isr_end_fl = 0; - if (cpu_id == 0) { - // it runs an interrupt on cpu1 - DPORT_REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_3_REG, SYSTEM_CPU_INTR_FROM_CPU_3); - } else { - // it runs an interrupt on cpu0 - DPORT_REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_2_REG, SYSTEM_CPU_INTR_FROM_CPU_2); - } - + // Trigger an interrupt on the opposite core. + esp_ipc_isr_port_int_trigger(!cpu_id); // IPC_ISR handler will be called and `...isr_start` and `...isr_end` will be updated there if (wait_for == IPC_ISR_WAIT_FOR_START) { diff --git a/components/esp_system/port/include/private/esp_private/esp_ipc_isr_port.h b/components/esp_system/port/include/private/esp_private/esp_ipc_isr_port.h new file mode 100644 index 00000000000..fc7ad95d568 --- /dev/null +++ b/components/esp_system/port/include/private/esp_private/esp_ipc_isr_port.h @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_ESP_IPC_ISR_ENABLE + +/** + * @brief Initialize the IPC ISR interrupt for a specific CPU. + * + * This function initializes the IPC ISR (Inter-Processor Communication Interrupt) + * for a specific CPU core. It configures the interrupt source and enables the + * IPC ISR interrupt for the specified CPU. + * + * @param[in] cpuid The ID of the CPU core to initialize IPC ISR for. + */ +void esp_ipc_isr_port_init(const int cpuid); + +/** + * @brief Trigger an interrupt on a specific CPU core. + * + * @param[in] cpuid The ID of the CPU core to trigger the interrupt on (0 or 1). + */ +void esp_ipc_isr_port_int_trigger(const int cpuid); + +#endif // CONFIG_ESP_IPC_ISR_ENABLE + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt b/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt index 46b79fa772f..3e822ddec19 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt @@ -16,7 +16,12 @@ set(SRC "test_app_main.c" "test_task_wdt.c") if(CONFIG_ESP_IPC_ISR_ENABLE) - list(APPEND SRC "test_ipc_isr.c" "test_ipc_isr.S") + list(APPEND SRC "test_ipc_isr.c") + if(CONFIG_IDF_TARGET_ARCH_XTENSA) + list(APPEND SRC "port/arch/xtensa/test_ipc_isr.S") + elseif(CONFIG_IDF_TARGET_ARCH_RISCV) + list(APPEND SRC "port/arch/riscv/test_ipc_isr.c") + endif() endif() idf_component_register(SRCS ${SRC} diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/riscv/test_ipc_isr.c b/components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/riscv/test_ipc_isr.c new file mode 100644 index 00000000000..7ef0bbbdca3 --- /dev/null +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/riscv/test_ipc_isr.c @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" + +#if CONFIG_ESP_IPC_ISR_ENABLE + +void esp_test_ipc_isr_callback(void *arg) { + uint32_t value = 0xa5a5; + *(volatile uint32_t*)arg = value; +} + +void esp_test_ipc_isr_get_other_core_id(void *arg) { + uint32_t core_id; + __asm volatile("csrr %0, mhartid" : "=r"(core_id)); + *(volatile uint32_t*)arg = core_id; +} + +void esp_test_ipc_isr_get_cycle_count_other_cpu(void *arg) { + uint32_t cycle_count; + __asm volatile("rdcycle %0;" : "=r"(cycle_count)); + *(volatile uint32_t*)arg = cycle_count; +} + +#endif // CONFIG_ESP_IPC_ISR_ENABLE diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/test_ipc_isr.S b/components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/xtensa/test_ipc_isr.S similarity index 86% rename from components/esp_system/test_apps/esp_system_unity_tests/main/test_ipc_isr.S rename to components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/xtensa/test_ipc_isr.S index b19a51c2020..700d0290f4c 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/test_ipc_isr.S +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/xtensa/test_ipc_isr.S @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,18 +13,18 @@ #include #include -/* esp_test_ipc_isr_asm(void *arg) +/* esp_test_ipc_isr_callback(void *arg) * * It should be called by the CALLX0 command from the handler of High-priority interrupt. * Only these registers [a2, a3, a4] can be used here. */ .section .iram1, "ax" .align 4 - .global esp_test_ipc_isr_asm - .type esp_test_ipc_isr_asm, @function + .global esp_test_ipc_isr_callback + .type esp_test_ipc_isr_callback, @function // Args: // a2 - void* arg -esp_test_ipc_isr_asm: +esp_test_ipc_isr_callback: movi a3, 0xa5a5 s32i a3, a2, 0 ret diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/test_ipc_isr.c b/components/esp_system/test_apps/esp_system_unity_tests/main/test_ipc_isr.c index c44ff581741..a17fade9ce2 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/test_ipc_isr.c +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/test_ipc_isr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,12 +17,18 @@ #ifdef CONFIG_ESP_IPC_ISR_ENABLE -void esp_test_ipc_isr_asm(void* arg); +#if CONFIG_IDF_TARGET_ARCH_RISCV + #define STORE_ERROR "Store access fault" +#else + #define STORE_ERROR "StoreProhibited" +#endif + +void esp_test_ipc_isr_callback(void* arg); TEST_CASE("Test ipc_isr blocking IPC function calls a ASM function", "[ipc]") { int val = 0x5a5a; - esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_asm, &val); + esp_ipc_isr_call_blocking(esp_test_ipc_isr_callback, &val); TEST_ASSERT_EQUAL_HEX(val, 0xa5a5); } @@ -32,13 +38,13 @@ void esp_test_ipc_isr_get_other_core_id(void* arg); TEST_CASE("Test ipc_isr blocking IPC function calls get_other_core_id", "[ipc]") { int val = 0x5a5a; - esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_get_other_core_id, &val); + esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_other_core_id, &val); TEST_ASSERT_EQUAL_HEX(val, 1); } -static void do_esp_ipc_isr_asm_call_blocking(void) +static void do_esp_ipc_isr_call_blocking(void) { - esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_asm, NULL); + esp_ipc_isr_call_blocking(esp_test_ipc_isr_callback, NULL); } static void check_reset_reason_panic(void) @@ -46,8 +52,8 @@ static void check_reset_reason_panic(void) TEST_ASSERT_EQUAL(ESP_RST_PANIC, esp_reset_reason()); } -TEST_CASE_MULTIPLE_STAGES("Test ipc_isr exception in asm func leads to StoreProhibited not to Unhandled debug exception", "[ipc][reset=StoreProhibited,SW_CPU_RESET]", - do_esp_ipc_isr_asm_call_blocking, +TEST_CASE_MULTIPLE_STAGES("Test ipc_isr exception in asm func leads to StoreProhibited not to Unhandled debug exception", "[ipc][reset="STORE_ERROR",SW_CPU_RESET]", + do_esp_ipc_isr_call_blocking, check_reset_reason_panic) void esp_test_ipc_isr_get_cycle_count_other_cpu(void* arg); @@ -55,7 +61,7 @@ void esp_test_ipc_isr_get_cycle_count_other_cpu(void* arg); TEST_CASE("Test ipc_isr blocking IPC function calls get_cycle_count_other_cpu", "[ipc]") { int val = 0x5a5a; - esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, &val); + esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, &val); esp_rom_printf("CCOUNT CPU0 = %d\n", esp_cpu_get_cycle_count()); esp_rom_printf("CCOUNT CPU1 = %d\n", val); } @@ -70,12 +76,12 @@ static void task_asm(void *arg) printf("task_asm\n"); while (s_stop == false) { val = 0x5a5a; - esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_asm, &val); + esp_ipc_isr_call_blocking(esp_test_ipc_isr_callback, &val); TEST_ASSERT_EQUAL_HEX(val, 0xa5a5); ++counter; } printf("task_asm counter = %d\n", counter); - TEST_ASSERT_GREATER_THAN(10000, counter); + TEST_ASSERT_GREATER_THAN(1000, counter); xSemaphoreGive(*sema); vTaskDelete(NULL); } diff --git a/components/riscv/vectors_clic.S b/components/riscv/vectors_clic.S index 2531a9e545e..e1b2ad0e35d 100644 --- a/components/riscv/vectors_clic.S +++ b/components/riscv/vectors_clic.S @@ -14,6 +14,12 @@ #define MEMPROT_ISR _interrupt_handler #endif // CONFIG_ESP_SYSTEM_MEMPROT_FEATURE +#if CONFIG_ESP_IPC_ISR_ENABLE + #define IPC_ISR_HANDLER esp_ipc_isr_handler +#else + #define IPC_ISR_HANDLER _interrupt_handler +#endif // CONFIG_ESP_IPC_ISR_ENABLE + /* The system interrupts are not used for now, so trigger a panic every time one occurs. */ #define _system_int_handler _panic_handler @@ -104,7 +110,7 @@ _mtvt_table: .word _panic_handler /* 41: ETS_CACHEERR_INUM (+16) panic-interrupt (soc-level panic) */ .word MEMPROT_ISR /* 42: ETS_MEMPROT_ERR_INUM (+16) handler (soc-level panic) */ .word _interrupt_handler /* 43: Free interrupt number */ - .word _interrupt_handler /* 44: Free interrupt number */ + .word IPC_ISR_HANDLER /* 44: ETS_IPC_ISR_INUM (+16) handler*/ .word _interrupt_handler /* 45: Free interrupt number */ .word _interrupt_handler /* 46: Free interrupt number */ .word _interrupt_handler /* 47: Free interrupt number */ diff --git a/components/soc/esp32p4/include/soc/hp_system_reg.h b/components/soc/esp32p4/include/soc/hp_system_reg.h index e44418cfbcc..ec9b55a793a 100644 --- a/components/soc/esp32p4/include/soc/hp_system_reg.h +++ b/components/soc/esp32p4/include/soc/hp_system_reg.h @@ -5,7 +5,6 @@ */ #pragma once -#include #include "soc/soc.h" #ifdef __cplusplus extern "C" { diff --git a/components/soc/esp32p4/include/soc/soc.h b/components/soc/esp32p4/include/soc/soc.h index ba2c157b2ca..735a0b7a59f 100644 --- a/components/soc/esp32p4/include/soc/soc.h +++ b/components/soc/esp32p4/include/soc/soc.h @@ -234,6 +234,7 @@ #define ETS_T1_WDT_INUM 24 #define ETS_CACHEERR_INUM 25 #define ETS_MEMPROT_ERR_INUM 26 +#define ETS_IPC_ISR_INUM 28 //CPU0 Max valid interrupt number #define ETS_MAX_INUM 31 diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 1080e580b8e..b9efff87434 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -183,7 +183,6 @@ api-reference/system/bootloader_image_format.rst api-reference/system/inc/power_management_esp32p4.rst api-reference/system/heap_debug.rst api-reference/system/mm.rst -api-reference/system/ipc.rst api-reference/system/esp_https_ota.rst api-reference/system/ulp-risc-v.rst api-reference/system/esp_err.rst diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 99d3457e2df..24e2bf0ad20 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -24,7 +24,7 @@ System API heap_debug esp_timer internal-unstable - :not CONFIG_FREERTOS_UNICORE or esp32p4: ipc + :not CONFIG_FREERTOS_UNICORE: ipc intr_alloc log misc_system_api diff --git a/docs/en/api-reference/system/ipc.rst b/docs/en/api-reference/system/ipc.rst index 6fea3b28163..35099e2ac4f 100644 --- a/docs/en/api-reference/system/ipc.rst +++ b/docs/en/api-reference/system/ipc.rst @@ -14,11 +14,7 @@ Due to the dual core nature of the {IDF_TARGET_NAME}, there are instances where - On particular chips (such as the ESP32), accessing memory that is exclusive to a particular CPU (such as RTC Fast Memory). - Reading the registers/state of another CPU. - -.. only:: not esp32p4 - - The IPC (Inter-Processor Call) feature allows a particular CPU (the calling CPU) to trigger the execution of a callback function on another CPU (the target CPU). The IPC feature allows execution of a callback function on the target CPU in either a task context, or a High Priority Interrupt context (see :doc:`/api-guides/hlinterrupts` for more details). Depending on the context that the callback function is executed in, different restrictions apply to the implementation of the callback function. - +The IPC (Inter-Processor Call) feature allows a particular CPU (the calling CPU) to trigger the execution of a callback function on another CPU (the target CPU). The IPC feature allows execution of a callback function on the target CPU in either ``a task context``, or ``an interrupt context``. Depending on the context that the callback function is executed in, different restrictions apply to the implementation of the callback function. IPC in Task Context ------------------- @@ -46,76 +42,103 @@ The IPC feature offers the API listed below to execute a callback in a task cont - :cpp:func:`esp_ipc_call` triggers an IPC call on the target CPU. This function will block until the target CPU's IPC task **begins** execution of the callback. - :cpp:func:`esp_ipc_call_blocking` triggers an IPC on the target CPU. This function will block until the target CPU's IPC task **completes** execution of the callback. -.. only:: not esp32p4 +IPC in Interrupt Context +------------------------ + +In some cases, we need to quickly obtain the state of another CPU such as in a core dump, GDB stub, various unit tests, and DPORT workaround. The IPC ISR feature implements the High Priority Interrupt context by reserving a High Priority Interrupt on each CPU for IPC usage. When a calling CPU needs to execute a callback on the target CPU, the callback will execute in the context of the High Priority Interrupt of the target CPU. + +.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA - IPC in ISR Context - ------------------ + For such scenarios, the IPC ISR feature supports execution of callbacks in a :doc:`High Priority Interrupt ` context. - In some cases, we need to quickly obtain the state of another CPU such as in a core dump, GDB stub, various unit tests, and DPORT workaround. For such scenarios, the IPC feature supports execution of callbacks in a :doc:`High Priority Interrupt ` context. The IPC feature implements the High Priority Interrupt context by reserving a High Priority Interrupt on each CPU for IPC usage. When a calling CPU needs to execute a callback on the target CPU, the callback will execute in the context of the High Priority Interrupt of the target CPU. +When using IPCs in High Priority Interrupt context, users need to consider the following: - When using IPCs in High Priority Interrupt context, users need to consider the following: +.. list:: - - Since the callback is executed in a High Priority Interrupt context, the callback must be written entirely in assembly. See the API Usage below for more details regarding writing assembly callbacks. - - The priority of the reserved High Priority Interrupt is dependent on the :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` option - - When the callback executes: + :CONFIG_IDF_TARGET_ARCH_XTENSA: - Since the callback is executed in a High Priority Interrupt context, the callback must be written entirely in assembly. See the API Usage below for more details regarding writing assembly callbacks. + - The priority of the reserved High Priority Interrupt is dependent on the :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` option. - - The calling CPU will disable interrupts of level 3 and lower - - Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution IPC ISR callback, the target CPU will disable interrupts of level 5 and lower regardless of what :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` is set to. +When the callback executes, users need to consider the following: + +.. list:: + + - The calling CPU will disable interrupts of level 3 and lower. + :CONFIG_IDF_TARGET_ARCH_XTENSA: - Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution IPC ISR callback, the target CPU will disable interrupts of level 5 and lower regardless of what :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` is set to. + :CONFIG_IDF_TARGET_ARCH_RISCV: - Although the priority of the reserved interrupt depends on :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`, during the execution IPC ISR callback, the target CPU will disable all interrupts. API Usage ^^^^^^^^^ -High Priority Interrupt IPC callbacks have the following restrictions: +.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA + + High Priority Interrupt IPC callbacks have the following restrictions: + + - The callback must be of type ``void func(void *arg)`` but implemented entirely in assembly + - The callback is invoked via the ``CALLX0`` instruction with register windowing disabled, thus the callback: + - Must not call any register window related instructions (e.g., ``entry`` and ``retw``). + - Must not call other C functions as register windowing is disabled + - The callback should be placed in IRAM at a 4-byte aligned address + - (On invocation of/after returning from) the callback, the registers ``a2, a3, a4`` are (saved/restored) automatically thus can be used in the callback. The callback should **ONLY** use those registers. + - ``a2`` contains the ``void *arg`` of the callback + - ``a3/a4`` are free to use as scratch registers + +.. only:: CONFIG_IDF_TARGET_ARCH_RISCV -- The callback must be of type ``void func(void *arg)`` but implemented entirely in assembly -- The callback is invoked via the ``CALLX0`` instruction with register windowing disabled, thus the callback: - - Must not call any register window related instructions (e.g., ``entry`` and ``retw``). - - Must not call other C functions as register windowing is disabled -- The callback should be placed in IRAM at a 4-byte aligned address -- (On invocation of/after returning from) the callback, the registers ``a2, a3, a4`` are (saved/restored) automatically thus can be used in the callback. The callback should **ONLY** use those registers. - - ``a2`` contains the ``void *arg`` of the callback - - ``a3/a4`` are free to use as scratch registers + High Priority Interrupt IPC callbacks have the same restrictions as for regular interrupt handlers. The callback function can be written in C. The IPC feature offers the API listed below to execute a callback in a High Priority Interrupt context. -- :cpp:func:`esp_ipc_isr_asm_call` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU begins execution of the callback. -- :cpp:func:`esp_ipc_isr_asm_call_blocking` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU completes execution of the callback. +- :cpp:func:`esp_ipc_isr_call` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU begins execution of the callback. +- :cpp:func:`esp_ipc_isr_call_blocking` triggers an IPC call on the target CPU. This function will busy-wait until the target CPU completes execution of the callback. -The following code-blocks demonstrates a High Priority Interrupt IPC callback written in assembly that simply reads the target CPU's cycle count. +.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA -.. code-block:: asm + The following code-blocks demonstrates a High Priority Interrupt IPC callback written in assembly that simply reads the target CPU's cycle count. - /* esp_test_ipc_isr_get_cycle_count_other_cpu(void *arg) */ - // this function reads CCOUNT of the target CPU and stores it in arg. - // use only a2, a3 and a4 regs here. - .section .iram1, "ax" - .align 4 - .global esp_test_ipc_isr_get_cycle_count_other_cpu - .type esp_test_ipc_isr_get_cycle_count_other_cpu, @function - // Args: - // a2 - void* arg - esp_test_ipc_isr_get_cycle_count_other_cpu: - rsr.ccount a3 - s32i a3, a2, 0 - ret + .. code-block:: asm -.. code-block:: c + /* esp_test_ipc_isr_get_cycle_count_other_cpu(void *arg) */ + // this function reads CCOUNT of the target CPU and stores it in arg. + // use only a2, a3 and a4 regs here. + .section .iram1, "ax" + .align 4 + .global esp_test_ipc_isr_get_cycle_count_other_cpu + .type esp_test_ipc_isr_get_cycle_count_other_cpu, @function + // Args: + // a2 - void* arg + esp_test_ipc_isr_get_cycle_count_other_cpu: + rsr.ccount a3 + s32i a3, a2, 0 + ret - unit32_t cycle_count; - esp_ipc_isr_asm_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)cycle_count); + .. code-block:: c -.. note:: + unit32_t cycle_count; + esp_ipc_isr_call_blocking(esp_test_ipc_isr_get_cycle_count_other_cpu, (void *)cycle_count); - The number of scratch registers available for use is sufficient for most simple use cases. But if your callback requires more scratch registers, ``void *arg`` can point to a buffer that is used as a register save area. The callback can then save and restore more registers. See the :example:`system/ipc/ipc_isr`. + .. note:: -.. note:: + The number of scratch registers available for use is sufficient for most simple use cases. But if your callback requires more scratch registers, ``void *arg`` can point to a buffer that is used as a register save area. The callback can then save and restore more registers. See the :example:`system/ipc/ipc_isr`. + + .. note:: + + For more examples of High Priority Interrupt IPC callbacks, see :idf_file:`components/esp_system/port/arch/xtensa/esp_ipc_isr_routines.S` and :idf_file:`components/esp_system/test_apps/esp_system_unity_tests/main/port/arch/xtensa/test_ipc_isr.S`. - For more examples of High Priority Interrupt IPC callbacks, see :idf_file:`components/esp_system/port/arch/xtensa/esp_ipc_isr_routines.S` and :`components/esp_system/test/test_ipc_isr.S` +.. only:: CONFIG_IDF_TARGET_ARCH_RISCV + + See :idf_file:`examples/system/ipc/ipc_isr/riscv/main/main.c` for an example of its use. + +.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA + + See :idf_file:`examples/system/ipc/ipc_isr/xtensa/main/main.c` for an example of its use. The High Priority Interrupt IPC API also provides the following convenience functions that can stall/resume the target CPU. These API utilize the High Priority Interrupt IPC, but supply their own internal callbacks: -- :cpp:func:`esp_ipc_isr_stall_other_cpu` stalls the target CPU. The calling CPU disables interrupts of level 3 and lower while the target CPU will busy-wait with interrupts of level 5 and lower disabled. The target CPU will busy-wait until :cpp:func:`esp_ipc_isr_release_other_cpu` is called. -- :cpp:func:`esp_ipc_isr_release_other_cpu` resumes the target CPU. +.. list:: + + :CONFIG_IDF_TARGET_ARCH_RISCV: - :cpp:func:`esp_ipc_isr_stall_other_cpu` stalls the target CPU. The calling CPU disables interrupts of level 3 and lower while the target CPU will busy-wait with all interrupts disabled. The target CPU will busy-wait until :cpp:func:`esp_ipc_isr_release_other_cpu` is called. + :CONFIG_IDF_TARGET_ARCH_XTENSA: - :cpp:func:`esp_ipc_isr_stall_other_cpu` stalls the target CPU. The calling CPU disables interrupts of level 3 and lower while the target CPU will busy-wait with interrupts of level 5 and lower disabled. The target CPU will busy-wait until :cpp:func:`esp_ipc_isr_release_other_cpu` is called. + - :cpp:func:`esp_ipc_isr_release_other_cpu` resumes the target CPU. API Reference ------------- diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index 22712a0391d..8d4f8c4a09a 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -80,11 +80,21 @@ examples/system/himem: temporary: true reason: the other targets are not tested yet -examples/system/ipc/ipc_isr: +examples/system/ipc/ipc_isr/riscv: enable: - - if: IDF_TARGET == "esp32" or IDF_TARGET == "esp32s3" + - if: IDF_TARGET_ARCH_RISCV == 1 and ESP_IPC_ISR_ENABLE == 1 temporary: true - reason: the other targets are not tested yet + reason: The test is intended only for multi-core chips + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners + +examples/system/ipc/ipc_isr/xtensa: + enable: + - if: IDF_TARGET_ARCH_XTENSA == 1 and ESP_IPC_ISR_ENABLE == 1 + temporary: true + reason: The test is intended only for multi-core chips examples/system/light_sleep: disable: diff --git a/examples/system/ipc/ipc_isr/CMakeLists.txt b/examples/system/ipc/ipc_isr/riscv/CMakeLists.txt similarity index 100% rename from examples/system/ipc/ipc_isr/CMakeLists.txt rename to examples/system/ipc/ipc_isr/riscv/CMakeLists.txt diff --git a/examples/system/ipc/ipc_isr/riscv/README.md b/examples/system/ipc/ipc_isr/riscv/README.md new file mode 100644 index 00000000000..df83241e9cf --- /dev/null +++ b/examples/system/ipc/ipc_isr/riscv/README.md @@ -0,0 +1,56 @@ +| Supported Targets | ESP32P4 | +| ----------------- | ------- | + +# IPC ISR Example + +This example demonstrates how to use the IPC ISR feature (which allows an IPC to run in the context of a High Priority Interrupt). The level of the IPC ISR interrupt depends on the `CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL` option. The IPC ISR feature can be useful in cases where users need to quickly get the state of the other CPU (consult the [IPC documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/ipc.html)). Unlike ESP32 or ESP32S3, for this chip, the callback function can be written in C. + +The first callback `get_mstatus_other_cpu()` demonstrates a callback that simply returns the `MSTATUS` register of other core. + +The second callback `extended_ipc_isr_func()` demonstrates how to return multiple values from the callback. The callback's `void *arg` points to a structure that contains the following: + - `uint32_t in[];` that gives the callback multiple input arguments + - `uint32_t out[];` that gives the callback multiple output arguments + +The `extended_ipc_isr_func()` callback uses the `in[]` arguments does some work and then writes to `out[]`. + +## How to use example + +### Hardware Required + +Example should be able to run on any commonly available ESP32P4 development board. The chip should have two cores. + +### Configure the project + +- `CONFIG_FREERTOS_UNICORE` - disabled, +- `CONFIG_ESP_IPC_ISR_ENABLE` - enabled. + +``` +idf.py menuconfig +``` + +### Build and Flash + +``` +idf.py build flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +## Example output + +``` +I (411) example: Start +I (421) example: call get_mstatus_other_cpu +I (421) example: MSTATUS = 0x3880 +I (421) example: call extended_ipc_isr_func +I (431) example: in[0] = 0x1 +I (431) example: in[1] = 0x2 +I (441) example: in[2] = 0x3 +I (441) example: out[0] = (in[0] | in[1] | in[2]) = 0x3 +I (451) example: out[1] = (in[0] + in[1] + in[2]) = 0x6 +I (451) example: out[2] = MCAUSE of other cpu = 0xb800002c +I (461) example: out[3] = MSTATUS of other cpu = 0x3880 +I (461) example: End +``` diff --git a/examples/system/ipc/ipc_isr/riscv/main/CMakeLists.txt b/examples/system/ipc/ipc_isr/riscv/main/CMakeLists.txt new file mode 100644 index 00000000000..8f8999c1abd --- /dev/null +++ b/examples/system/ipc/ipc_isr/riscv/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "main.c" + "callbacks.c" + INCLUDE_DIRS ".") diff --git a/examples/system/ipc/ipc_isr/riscv/main/callbacks.c b/examples/system/ipc/ipc_isr/riscv/main/callbacks.c new file mode 100644 index 00000000000..91a7286c0d0 --- /dev/null +++ b/examples/system/ipc/ipc_isr/riscv/main/callbacks.c @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "callbacks.h" + +void get_mstatus_other_cpu(void *arg) { + uint32_t mstatus_value; + asm volatile ("csrr %0, mstatus" : "=r" (mstatus_value)); + *(volatile uint32_t*)arg = mstatus_value; +} + +void extended_ipc_isr_func(void* arg) { + arg_data_t *a = (arg_data_t *)arg; + a->out[0] = a->in[0] | a->in[1] | a->in[2]; + a->out[1] = a->in[0] + a->in[1] + a->in[2]; + asm volatile ("csrr %0, mcause" : "=r" (a->out[2])); + asm volatile ("csrr %0, mstatus" : "=r" (a->out[3])); +} diff --git a/examples/system/ipc/ipc_isr/riscv/main/callbacks.h b/examples/system/ipc/ipc_isr/riscv/main/callbacks.h new file mode 100644 index 00000000000..207fa7b9f48 --- /dev/null +++ b/examples/system/ipc/ipc_isr/riscv/main/callbacks.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +typedef struct { + uint32_t in[3]; + uint32_t out[4]; +} arg_data_t; + +void get_mstatus_other_cpu(void *arg); +void extended_ipc_isr_func(void* arg); diff --git a/examples/system/ipc/ipc_isr/riscv/main/main.c b/examples/system/ipc/ipc_isr/riscv/main/main.c new file mode 100644 index 00000000000..b827efe7dc9 --- /dev/null +++ b/examples/system/ipc/ipc_isr/riscv/main/main.c @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include "esp_log.h" +#include "esp_ipc_isr.h" +#include "callbacks.h" +#include "sdkconfig.h" + +static const char* TAG = "example"; + +void app_main(void) +{ + ESP_LOGI(TAG, "Start"); + uint32_t mstatus_other_cpu = 0; + ESP_LOGI(TAG, "call get_mstatus_other_cpu"); + esp_ipc_isr_call_blocking(get_mstatus_other_cpu, &mstatus_other_cpu); + ESP_LOGI(TAG, "MSTATUS = 0x%"PRIx32, mstatus_other_cpu); + + ESP_LOGI(TAG, "call extended_ipc_isr_func"); + arg_data_t arg = { 0 }; + arg.in[0] = 0x01; + arg.in[1] = 0x02; + arg.in[2] = 0x03; + ESP_LOGI(TAG, "in[0] = 0x%"PRIx32, arg.in[0]); + ESP_LOGI(TAG, "in[1] = 0x%"PRIx32, arg.in[1]); + ESP_LOGI(TAG, "in[2] = 0x%"PRIx32, arg.in[2]); + esp_ipc_isr_call_blocking(extended_ipc_isr_func, (void*)&arg); + ESP_LOGI(TAG, "out[0] = (in[0] | in[1] | in[2]) = 0x%"PRIx32, arg.out[0]); + assert(0x03 == arg.out[0]); + ESP_LOGI(TAG, "out[1] = (in[0] + in[1] + in[2]) = 0x%"PRIx32, arg.out[1]); + assert(0x06 == arg.out[1]); + ESP_LOGI(TAG, "out[2] = MCAUSE of other cpu = 0x%"PRIx32, arg.out[2]); + assert(0xb800002c == arg.out[2]); + ESP_LOGI(TAG, "out[3] = MSTATUS of other cpu = 0x%"PRIx32, arg.out[3]); + assert(mstatus_other_cpu == arg.out[3]); + ESP_LOGI(TAG, "End"); +} diff --git a/examples/system/ipc/ipc_isr/riscv/pytest_ipc_isr_riscv.py b/examples/system/ipc/ipc_isr/riscv/pytest_ipc_isr_riscv.py new file mode 100644 index 00000000000..e0e831ce261 --- /dev/null +++ b/examples/system/ipc/ipc_isr/riscv/pytest_ipc_isr_riscv.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_ipc_isr(dut: Dut) -> None: + dut.expect_exact('example: Start') + dut.expect_exact('example: MSTATUS = 0x3880') + dut.expect_exact('example: in[0] = 0x1') + dut.expect_exact('example: in[1] = 0x2') + dut.expect_exact('example: in[2] = 0x3') + dut.expect_exact('example: out[0] = (in[0] | in[1] | in[2]) = 0x3') + dut.expect_exact('example: out[1] = (in[0] + in[1] + in[2]) = 0x6') + dut.expect_exact('example: out[2] = MCAUSE of other cpu = 0xb800002c') + dut.expect_exact('example: out[3] = MSTATUS of other cpu = 0x3880') + dut.expect_exact('example: End') diff --git a/examples/system/ipc/ipc_isr/sdkconfig.defaults b/examples/system/ipc/ipc_isr/riscv/sdkconfig.defaults similarity index 100% rename from examples/system/ipc/ipc_isr/sdkconfig.defaults rename to examples/system/ipc/ipc_isr/riscv/sdkconfig.defaults diff --git a/examples/system/ipc/ipc_isr/xtensa/CMakeLists.txt b/examples/system/ipc/ipc_isr/xtensa/CMakeLists.txt new file mode 100644 index 00000000000..0bb2e885b97 --- /dev/null +++ b/examples/system/ipc/ipc_isr/xtensa/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following 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) +project(ipc_isr) diff --git a/examples/system/ipc/ipc_isr/README.md b/examples/system/ipc/ipc_isr/xtensa/README.md similarity index 97% rename from examples/system/ipc/ipc_isr/README.md rename to examples/system/ipc/ipc_isr/xtensa/README.md index 0ee9ee4eb8a..3edce03dd62 100644 --- a/examples/system/ipc/ipc_isr/README.md +++ b/examples/system/ipc/ipc_isr/xtensa/README.md @@ -53,7 +53,7 @@ I (324) example: in[0] = 0x1 I (334) example: in[1] = 0x2 I (334) example: in[2] = 0x3 I (334) example: out[0] = (in[0] | in[1] | in[2]) = 0x3 -I (344) example: out[1] = (in[0] & in[1] & in[2]) = 0x6 +I (344) example: out[1] = (in[0] + in[1] + in[2]) = 0x6 I (354) example: out[2] = in[2] = 0x3 I (354) example: out[3] = PS of other cpu = 0x25 I (364) example: End diff --git a/examples/system/ipc/ipc_isr/main/CMakeLists.txt b/examples/system/ipc/ipc_isr/xtensa/main/CMakeLists.txt similarity index 100% rename from examples/system/ipc/ipc_isr/main/CMakeLists.txt rename to examples/system/ipc/ipc_isr/xtensa/main/CMakeLists.txt diff --git a/examples/system/ipc/ipc_isr/main/asm_funcs.S b/examples/system/ipc/ipc_isr/xtensa/main/asm_funcs.S similarity index 100% rename from examples/system/ipc/ipc_isr/main/asm_funcs.S rename to examples/system/ipc/ipc_isr/xtensa/main/asm_funcs.S diff --git a/examples/system/ipc/ipc_isr/main/main.c b/examples/system/ipc/ipc_isr/xtensa/main/main.c similarity index 74% rename from examples/system/ipc/ipc_isr/main/main.c rename to examples/system/ipc/ipc_isr/xtensa/main/main.c index f35eb896685..353b00118d6 100644 --- a/examples/system/ipc/ipc_isr/main/main.c +++ b/examples/system/ipc/ipc_isr/xtensa/main/main.c @@ -1,16 +1,12 @@ -/* ipc_isr example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ #include #include #include -#include "esp_timer.h" #include "esp_log.h" #include "esp_ipc_isr.h" #include "sdkconfig.h" @@ -36,7 +32,7 @@ void app_main(void) ESP_LOGI(TAG, "Start"); uint32_t ps_other_cpu = 0; ESP_LOGI(TAG, "call get_ps_other_cpu"); - esp_ipc_isr_asm_call_blocking(get_ps_other_cpu, &ps_other_cpu); + esp_ipc_isr_call_blocking(get_ps_other_cpu, &ps_other_cpu); ESP_LOGI(TAG, "PS_INTLEVEL = 0x%"PRIx32, ps_other_cpu & XCHAL_PS_INTLEVEL_MASK); ESP_LOGI(TAG, "PS_EXCM = 0x%"PRIx32, (ps_other_cpu & XCHAL_PS_EXCM_MASK) >> XCHAL_PS_EXCM_SHIFT); ESP_LOGI(TAG, "PS_UM = 0x%"PRIx32, (ps_other_cpu & XCHAL_PS_UM_MASK) >> XCHAL_PS_UM_SHIFT); @@ -49,10 +45,10 @@ void app_main(void) ESP_LOGI(TAG, "in[0] = 0x%"PRIx32, arg.in[0]); ESP_LOGI(TAG, "in[1] = 0x%"PRIx32, arg.in[1]); ESP_LOGI(TAG, "in[2] = 0x%"PRIx32, arg.in[2]); - esp_ipc_isr_asm_call_blocking(extended_ipc_isr_asm, (void*)&arg); + esp_ipc_isr_call_blocking(extended_ipc_isr_asm, (void*)&arg); ESP_LOGI(TAG, "out[0] = (in[0] | in[1] | in[2]) = 0x%"PRIx32, arg.out[0]); assert(0x03 == arg.out[0]); - ESP_LOGI(TAG, "out[1] = (in[0] & in[1] & in[2]) = 0x%"PRIx32, arg.out[1]); + ESP_LOGI(TAG, "out[1] = (in[0] + in[1] + in[2]) = 0x%"PRIx32, arg.out[1]); assert(0x06 == arg.out[1]); ESP_LOGI(TAG, "out[2] = in[2] = 0x%"PRIx32, arg.out[2]); assert(0x03 == arg.out[2]); diff --git a/examples/system/ipc/ipc_isr/pytest_ipc_isr.py b/examples/system/ipc/ipc_isr/xtensa/pytest_ipc_isr_xtensa.py similarity index 92% rename from examples/system/ipc/ipc_isr/pytest_ipc_isr.py rename to examples/system/ipc/ipc_isr/xtensa/pytest_ipc_isr_xtensa.py index 72fb939b841..cc3ce4ce804 100644 --- a/examples/system/ipc/ipc_isr/pytest_ipc_isr.py +++ b/examples/system/ipc/ipc_isr/xtensa/pytest_ipc_isr_xtensa.py @@ -18,7 +18,7 @@ def test_ipc_isr(dut: Dut) -> None: dut.expect_exact('example: in[1] = 0x2') dut.expect_exact('example: in[2] = 0x3') dut.expect_exact('example: out[0] = (in[0] | in[1] | in[2]) = 0x3') - dut.expect_exact('example: out[1] = (in[0] & in[1] & in[2]) = 0x6') + dut.expect_exact('example: out[1] = (in[0] + in[1] + in[2]) = 0x6') dut.expect_exact('example: out[2] = in[2] = 0x3') dut.expect_exact('example: out[3] = PS of other cpu = 0x25') dut.expect_exact('example: End') diff --git a/examples/system/ipc/ipc_isr/xtensa/sdkconfig.defaults b/examples/system/ipc/ipc_isr/xtensa/sdkconfig.defaults new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index c61514a2f44..c6e23c21366 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1271,7 +1271,6 @@ examples/system/gcov/main/gcov_example_main.c examples/system/gdbstub/main/gdbstub_main.c examples/system/heap_task_tracking/main/heap_task_tracking_main.c examples/system/himem/main/himem_example_main.c -examples/system/ipc/ipc_isr/main/main.c examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c examples/system/ota/native_ota_example/main/native_ota_example.c examples/system/ota/otatool/main/otatool_main.c From f781bf1c5c6eeddd9dc1790a38ff1ba5496171df Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 18 Sep 2023 10:22:11 +0800 Subject: [PATCH 12/71] ci(adc): increase adc performance test threshold on c6 --- components/idf_test/include/esp32c6/idf_performance_target.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/idf_test/include/esp32c6/idf_performance_target.h b/components/idf_test/include/esp32c6/idf_performance_target.h index f300dfc5784..dd0ffc1bb92 100644 --- a/components/idf_test/include/esp32c6/idf_performance_target.h +++ b/components/idf_test/include/esp32c6/idf_performance_target.h @@ -29,4 +29,4 @@ #define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_8 5 #define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_16 5 #define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_64 5 -#define IDF_PERFORMANCE_MAX_ADC_ONESHOT_STD_ATTEN3 5 +#define IDF_PERFORMANCE_MAX_ADC_ONESHOT_STD_ATTEN3 7 From 5b4469f973edbc48a21f03f6d797689cfa111d1e Mon Sep 17 00:00:00 2001 From: gaoxu Date: Wed, 13 Sep 2023 19:15:53 +0800 Subject: [PATCH 13/71] fix: remove wno format in esp_hw_support component --- components/esp_hw_support/CMakeLists.txt | 2 -- components/esp_hw_support/clk_ctrl_os.c | 2 +- components/esp_hw_support/dma/gdma.c | 2 +- components/esp_hw_support/intr_alloc.c | 2 +- .../mspi_timing_by_mspi_delay.c | 20 +++++++++---------- .../esp_hw_support/mspi_timing_tuning.c | 4 ++-- .../esp_hw_support/port/esp32/rtc_clk_init.c | 8 ++++---- .../esp_hw_support/port/esp32c3/esp_memprot.c | 9 +++++---- .../esp_hw_support/port/esp32s3/esp_memprot.c | 11 +++++----- .../esp_hw_support/port/esp_clk_tree_common.c | 2 +- components/esp_hw_support/sleep_cpu.c | 4 ++-- 11 files changed, 33 insertions(+), 33 deletions(-) diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 9bd322b0f78..c269eba0f34 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -153,5 +153,3 @@ if(NOT BOOTLOADER_BUILD) target_link_libraries(${COMPONENT_LIB} PRIVATE "-u esp_crypto_dpa_prot_include_impl") endif() endif() - -target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/esp_hw_support/clk_ctrl_os.c b/components/esp_hw_support/clk_ctrl_os.c index 4e580aa5131..f35932ed9eb 100644 --- a/components/esp_hw_support/clk_ctrl_os.c +++ b/components/esp_hw_support/clk_ctrl_os.c @@ -113,7 +113,7 @@ esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq) *real_freq = apll_freq; if (need_config) { - ESP_LOGD(TAG, "APLL will working at %d Hz with coefficients [sdm0] %d [sdm1] %d [sdm2] %d [o_div] %d", + ESP_LOGD(TAG, "APLL will working at %"PRIu32" Hz with coefficients [sdm0] %"PRIu32" [sdm1] %"PRIu32" [sdm2] %"PRIu32" [o_div] %"PRIu32"", apll_freq, sdm0, sdm1, sdm2, o_div); /* Set coefficients for APLL, notice that it doesn't mean APLL will start */ rtc_clk_apll_coeff_set(o_div, sdm0, sdm1, sdm2); diff --git a/components/esp_hw_support/dma/gdma.c b/components/esp_hw_support/dma/gdma.c index ac2b2a79346..fd7aa1686d9 100644 --- a/components/esp_hw_support/dma/gdma.c +++ b/components/esp_hw_support/dma/gdma.c @@ -364,7 +364,7 @@ esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_t } if (psram_alignment > data_cache_line_size) { ESP_RETURN_ON_FALSE(((psram_alignment % data_cache_line_size) == 0), ESP_ERR_INVALID_ARG, - TAG, "psram_alignment(%d) should be multiple of the data_cache_line_size(%d)", + TAG, "psram_alignment(%d) should be multiple of the data_cache_line_size(%"PRIu32")", psram_alignment, data_cache_line_size); } diff --git a/components/esp_hw_support/intr_alloc.c b/components/esp_hw_support/intr_alloc.c index a216a8e26e6..02d72ccd5d1 100644 --- a/components/esp_hw_support/intr_alloc.c +++ b/components/esp_hw_support/intr_alloc.c @@ -649,7 +649,7 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre free(ret); } - ESP_EARLY_LOGD(TAG, "Connected src %d to int %d (cpu %d)", source, intr, cpu); + ESP_EARLY_LOGD(TAG, "Connected src %d to int %d (cpu %"PRIu32")", source, intr, cpu); return ESP_OK; } diff --git a/components/esp_hw_support/mspi_timing_by_mspi_delay.c b/components/esp_hw_support/mspi_timing_by_mspi_delay.c index bc88d887830..efa5dbbd1ba 100644 --- a/components/esp_hw_support/mspi_timing_by_mspi_delay.c +++ b/components/esp_hw_support/mspi_timing_by_mspi_delay.c @@ -413,15 +413,15 @@ static uint32_t s_select_best_tuning_config_dtr(const mspi_timing_config_t *conf if (consecutive_length <= 2 || consecutive_length >= 6) { //tuning is FAIL, select default point, and generate a warning best_point = configs->default_config_id; - ESP_EARLY_LOGW(TAG, "tuning fail, best point is fallen back to index %d", best_point); + ESP_EARLY_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point); } else if (consecutive_length <= 4) { //consecutive length : 3 or 4 best_point = end - 1; - ESP_EARLY_LOGD(TAG, "tuning success, best point is index %d", best_point); + ESP_EARLY_LOGD(TAG, "tuning success, best point is index %"PRIu32"", best_point); } else { //consecutive point list length equals 5 best_point = end - 2; - ESP_EARLY_LOGD(TAG, "tuning success, best point is index %d", best_point); + ESP_EARLY_LOGD(TAG, "tuning success, best point is index %"PRIu32"", best_point); } return best_point; @@ -449,13 +449,13 @@ static uint32_t s_select_best_tuning_config_dtr(const mspi_timing_config_t *conf max_freq = temp_max_freq; best_point = current_point; } - ESP_EARLY_LOGD(TAG, "sample point %d, max pll is %d mhz, min pll is %d\n", current_point, temp_max_freq, temp_min_freq); + ESP_EARLY_LOGD(TAG, "sample point %"PRIu32", max pll is %"PRIu32" mhz, min pll is %"PRIu32"\n", current_point, temp_max_freq, temp_min_freq); } if (max_freq == 0) { - ESP_EARLY_LOGW(TAG, "freq scan tuning fail, best point is fallen back to index %d", end + 1 - consecutive_length); + ESP_EARLY_LOGW(TAG, "freq scan tuning fail, best point is fallen back to index %"PRIu32"", end + 1 - consecutive_length); best_point = end + 1 - consecutive_length; } else { - ESP_EARLY_LOGD(TAG, "freq scan success, max pll is %dmhz, best point is index %d", max_freq, best_point); + ESP_EARLY_LOGD(TAG, "freq scan success, max pll is %"PRIu32"mhz, best point is index %"PRIu32"", max_freq, best_point); } return best_point; @@ -477,11 +477,11 @@ static uint32_t s_select_best_tuning_config_str(const mspi_timing_config_t *conf if (consecutive_length <= 2|| consecutive_length >= 5) { //tuning is FAIL, select default point, and generate a warning best_point = configs->default_config_id; - ESP_EARLY_LOGW(TAG, "tuning fail, best point is fallen back to index %d", best_point); + ESP_EARLY_LOGW(TAG, "tuning fail, best point is fallen back to index %"PRIu32"", best_point); } else { //consecutive length : 3 or 4 best_point = end - consecutive_length / 2; - ESP_EARLY_LOGD(TAG, "tuning success, best point is index %d", best_point); + ESP_EARLY_LOGD(TAG, "tuning success, best point is index %"PRIu32"", best_point); } return best_point; @@ -507,7 +507,7 @@ uint32_t mspi_timing_flash_select_best_tuning_config(const void *configs, uint32 { const mspi_timing_config_t *timing_configs = (const mspi_timing_config_t *)configs; uint32_t best_point = s_select_best_tuning_config(timing_configs, consecutive_length, end, reference_data, is_ddr, true); - ESP_EARLY_LOGI(TAG, "Flash timing tuning index: %d", best_point); + ESP_EARLY_LOGI(TAG, "Flash timing tuning index: %"PRIu32"", best_point); return best_point; } @@ -516,7 +516,7 @@ uint32_t mspi_timing_psram_select_best_tuning_config(const void *configs, uint32 { const mspi_timing_config_t *timing_configs = (const mspi_timing_config_t *)configs; uint32_t best_point = s_select_best_tuning_config(timing_configs, consecutive_length, end, reference_data, is_ddr, false); - ESP_EARLY_LOGI(TAG, "PSRAM timing tuning index: %d", best_point); + ESP_EARLY_LOGI(TAG, "PSRAM timing tuning index: %"PRIu32"", best_point); return best_point; } diff --git a/components/esp_hw_support/mspi_timing_tuning.c b/components/esp_hw_support/mspi_timing_tuning.c index 246a565b556..2b524fb7e33 100644 --- a/components/esp_hw_support/mspi_timing_tuning.c +++ b/components/esp_hw_support/mspi_timing_tuning.c @@ -213,9 +213,9 @@ static void s_sweep_for_success_sample_points(uint8_t *reference_data, void *con #endif if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) { out_array[config_idx] = 1; - ESP_EARLY_LOGD(TAG, "%d, good", config_idx); + ESP_EARLY_LOGD(TAG, "%"PRIu32", good", config_idx); } else { - ESP_EARLY_LOGD(TAG, "%d, bad", config_idx); + ESP_EARLY_LOGD(TAG, "%"PRIu32", bad", config_idx); } } diff --git a/components/esp_hw_support/port/esp32/rtc_clk_init.c b/components/esp_hw_support/port/esp32/rtc_clk_init.c index 75e6fa8987e..aef313626ed 100644 --- a/components/esp_hw_support/port/esp32/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32/rtc_clk_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -163,18 +163,18 @@ static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate(void) xtal_freq = RTC_XTAL_FREQ_26M; break; case 32 ... 33: - ESP_HW_LOGW(TAG, "Potentially bogus XTAL frequency: %d MHz, guessing 26 MHz", freq_mhz); + ESP_HW_LOGW(TAG, "Potentially bogus XTAL frequency: %"PRIu32" MHz, guessing 26 MHz", freq_mhz); xtal_freq = RTC_XTAL_FREQ_26M; break; case 34 ... 35: - ESP_HW_LOGW(TAG, "Potentially bogus XTAL frequency: %d MHz, guessing 40 MHz", freq_mhz); + ESP_HW_LOGW(TAG, "Potentially bogus XTAL frequency: %"PRIu32" MHz, guessing 40 MHz", freq_mhz); xtal_freq = RTC_XTAL_FREQ_40M; break; case 36 ... 45: xtal_freq = RTC_XTAL_FREQ_40M; break; default: - ESP_HW_LOGW(TAG, "Bogus XTAL frequency: %d MHz", freq_mhz); + ESP_HW_LOGW(TAG, "Bogus XTAL frequency: %"PRIu32" MHz", freq_mhz); xtal_freq = RTC_XTAL_FREQ_AUTO; break; } diff --git a/components/esp_hw_support/port/esp32c3/esp_memprot.c b/components/esp_hw_support/port/esp32c3/esp_memprot.c index b6a073dc867..fc315281aed 100644 --- a/components/esp_hw_support/port/esp32c3/esp_memprot.c +++ b/components/esp_hw_support/port/esp32c3/esp_memprot.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,6 +17,7 @@ #include "hal/memprot_types.h" #include "esp_private/esp_memprot_internal.h" #include "esp_memprot.h" +#include extern int _iram_text_end; extern int _rtc_text_end; @@ -779,8 +780,8 @@ esp_err_t esp_mprot_dump_configuration(char **dump_info_string) sprintf(*dump_info_string, "Split line settings (lock=%u):\n" - " IRAM0:\n line ID (main): 0x%08X (cat=0x%08X)\n line I0: 0x%08X (cat=0x%08X)\n line I1: 0x%08X (cat=0x%08X)\n" - " DRAM0:\n line D0: 0x%08X (cat=0x%08X)\n line D1: 0x%08X (cat=0x%08X)\n", + " IRAM0:\n line ID (main): 0x%08"PRIX32" (cat=0x%08"PRIX32")\n line I0: 0x%08"PRIX32" (cat=0x%08"PRIX32")\n line I1: 0x%08"PRIX32" (cat=0x%08"PRIX32")\n" + " DRAM0:\n line D0: 0x%08"PRIX32" (cat=0x%08"PRIX32")\n line D1: 0x%08"PRIX32" (cat=0x%08"PRIX32")\n", line_lock, line_ID, line_ID_cat, line_I0, line_I0_cat, line_I1, line_I1_cat, line_D0, line_D0_cat, line_D1, line_D1_cat); uint32_t offset = strlen(*dump_info_string); @@ -790,7 +791,7 @@ esp_err_t esp_mprot_dump_configuration(char **dump_info_string) if (err != ESP_OK) { sprintf((*dump_info_string + offset), " RTCFAST:\n line main: N/A (world=0) - %s\n", esp_err_to_name(err)); } else { - sprintf((*dump_info_string + offset), " RTCFAST:\n line main: 0x%08X (world=0)\n", (uint32_t)line_RTC); + sprintf((*dump_info_string + offset), " RTCFAST:\n line main: 0x%08"PRIX32" (world=0)\n", (uint32_t)line_RTC); } offset = strlen(*dump_info_string); diff --git a/components/esp_hw_support/port/esp32s3/esp_memprot.c b/components/esp_hw_support/port/esp32s3/esp_memprot.c index a72a11c835e..34f49362e91 100644 --- a/components/esp_hw_support/port/esp32s3/esp_memprot.c +++ b/components/esp_hw_support/port/esp32s3/esp_memprot.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,6 +17,7 @@ #include "hal/memprot_types.h" #include "esp_private/esp_memprot_internal.h" #include "esp_memprot.h" +#include /* * LD section boundaries @@ -1251,7 +1252,7 @@ esp_err_t esp_mprot_dump_configuration(char **dump_info_string) sprintf(*dump_info_string, "Memory sections:\n" - " _iram_text_start: 0x%08X\n _iram_text_end: 0x%08X\n", + " _iram_text_start: 0x%08"PRIX32"\n _iram_text_end: 0x%08"PRIX32"\n", (uint32_t)&_iram_text_start, (uint32_t)&_iram_text_end); uint32_t offset = strlen(*dump_info_string); @@ -1270,8 +1271,8 @@ esp_err_t esp_mprot_dump_configuration(char **dump_info_string) sprintf((*dump_info_string + offset), "Split line settings (lock=%u):\n" - " IRAM0:\n line ID (main): 0x%08X (cat=0x%08X)\n line I0: 0x%08X (cat=0x%08X)\n line I1: 0x%08X (cat=0x%08X)\n" - " DRAM0:\n line D0: 0x%08X (cat=0x%08X)\n line D1: 0x%08X (cat=0x%08X)\n", + " IRAM0:\n line ID (main): 0x%08"PRIX32" (cat=0x%08"PRIX32")\n line I0: 0x%08"PRIX32" (cat=0x%08"PRIX32")\n line I1: 0x%08"PRIX32" (cat=0x%08"PRIX32")\n" + " DRAM0:\n line D0: 0x%08"PRIX32" (cat=0x%08"PRIX32")\n line D1: 0x%08"PRIX32" (cat=0x%08"PRIX32")\n", line_lock, line_ID, line_ID_cat, line_I0, line_I0_cat, line_I1, line_I1_cat, line_D0, line_D0_cat, line_D1, line_D1_cat); offset = strlen(*dump_info_string); @@ -1281,7 +1282,7 @@ esp_err_t esp_mprot_dump_configuration(char **dump_info_string) if (err != ESP_OK) { sprintf((*dump_info_string + offset), " RTCFAST:\n line main: N/A (world=0) - %s\n", esp_err_to_name(err)); } else { - sprintf((*dump_info_string + offset), " RTCFAST:\n line main: 0x%08X (world=0)\n", (uint32_t)line_RTC); + sprintf((*dump_info_string + offset), " RTCFAST:\n line main: 0x%08"PRIX32" (world=0)\n", (uint32_t)line_RTC); } offset = strlen(*dump_info_string); diff --git a/components/esp_hw_support/port/esp_clk_tree_common.c b/components/esp_hw_support/port/esp_clk_tree_common.c index 71a3ec507ce..a5e701f0c41 100644 --- a/components/esp_hw_support/port/esp_clk_tree_common.c +++ b/components/esp_hw_support/port/esp_clk_tree_common.c @@ -64,7 +64,7 @@ static uint32_t clk_tree_rtc_slow_calibration(uint32_t slowclk_cycles) cal_val = (uint32_t)(cal_dividend / source_approx_freq); } if (cal_val) { - ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %"PRIu32"", cal_val); // Update the calibration value of RTC_SLOW_CLK esp_clk_slowclk_cal_set(cal_val); } diff --git a/components/esp_hw_support/sleep_cpu.c b/components/esp_hw_support/sleep_cpu.c index 8ed524e74a4..39633d56e72 100644 --- a/components/esp_hw_support/sleep_cpu.c +++ b/components/esp_hw_support/sleep_cpu.c @@ -118,7 +118,7 @@ static uint32_t cache_tagmem_retention_setup(uint32_t code_seg_vaddr, uint32_t c s_cpu_retention.retent.tagmem.icache.enable = (code_seg_size != 0) ? 1 : 0; icache_tagmem_blk_gs = s_cpu_retention.retent.tagmem.icache.vld_size ? s_cpu_retention.retent.tagmem.icache.vld_size : sets * waysgrp; icache_tagmem_blk_gs = ALIGNUP(4, icache_tagmem_blk_gs); - ESP_LOGD(TAG, "I-cache size:%d KiB, line size:%d B, ways:%d, sets:%d, index:%d, tag block groups:%d", (imode.cache_size>>10), + ESP_LOGD(TAG, "I-cache size:%"PRIu32" KiB, line size:%d B, ways:%d, sets:%"PRIu32", index:%"PRIu32", tag block groups:%"PRIu32"", (imode.cache_size>>10), imode.cache_line_size, imode.cache_ways, sets, index, icache_tagmem_blk_gs); /* calculate/prepare d-cache tag memory retention parameters */ @@ -142,7 +142,7 @@ static uint32_t cache_tagmem_retention_setup(uint32_t code_seg_vaddr, uint32_t c #endif dcache_tagmem_blk_gs = s_cpu_retention.retent.tagmem.dcache.vld_size ? s_cpu_retention.retent.tagmem.dcache.vld_size : sets * waysgrp; dcache_tagmem_blk_gs = ALIGNUP(4, dcache_tagmem_blk_gs); - ESP_LOGD(TAG, "D-cache size:%d KiB, line size:%d B, ways:%d, sets:%d, index:%d, tag block groups:%d", (dmode.cache_size>>10), + ESP_LOGD(TAG, "D-cache size:%"PRIu32" KiB, line size:%d B, ways:%d, sets:%"PRIu32", index:%"PRIu32", tag block groups:%"PRIu32"", (dmode.cache_size>>10), dmode.cache_line_size, dmode.cache_ways, sets, index, dcache_tagmem_blk_gs); /* For I or D cache tagmem retention, backup and restore are performed through From 8c6ddb776c5fb69dcdb107caf5fb98e388543b6a Mon Sep 17 00:00:00 2001 From: gaoxu Date: Wed, 13 Sep 2023 19:16:14 +0800 Subject: [PATCH 14/71] fix: remove wno format in hal component --- components/hal/CMakeLists.txt | 1 - components/hal/adc_oneshot_hal.c | 4 ++-- components/hal/lcd_hal.c | 2 +- components/hal/sdio_slave_hal.c | 9 +++++---- components/hal/test/CMakeLists.txt | 1 - 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 0f9b9e4bdf7..e0bab96d2b5 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -261,7 +261,6 @@ idf_component_register(SRCS ${srcs} PRIV_INCLUDE_DIRS ${priv_include} REQUIRES soc esp_rom LDFRAGMENTS linker.lf) -target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") if(CONFIG_HAL_DEFAULT_ASSERTION_LEVEL EQUAL 1) target_link_libraries(${COMPONENT_LIB} INTERFACE "-u abort") diff --git a/components/hal/adc_oneshot_hal.c b/components/hal/adc_oneshot_hal.c index a51bbeaa66d..ce6cb193c66 100644 --- a/components/hal/adc_oneshot_hal.c +++ b/components/hal/adc_oneshot_hal.c @@ -94,14 +94,14 @@ static void adc_hal_onetime_start(adc_unit_t unit, uint32_t clk_src_freq_hz) delay = (1000 * 1000) / digi_clk + 1; //3 ADC digital controller clock cycle delay = delay * 3; - HAL_EARLY_LOGD("adc_hal", "clk_src_freq_hz: %d, digi_clk: %d, delay: %d", clk_src_freq_hz, digi_clk, delay); + HAL_EARLY_LOGD("adc_hal", "clk_src_freq_hz: %"PRIu32", digi_clk: %"PRIu32", delay: %"PRIu32"", clk_src_freq_hz, digi_clk, delay); //This coefficient (8) is got from test, and verified from DT. When digi_clk is not smaller than ``APB_CLK_FREQ/8``, no delay is needed. if (digi_clk >= APB_CLK_FREQ/8) { delay = 0; } - HAL_EARLY_LOGD("adc_hal", "delay: %d", delay); + HAL_EARLY_LOGD("adc_hal", "delay: %"PRIu32"", delay); adc_oneshot_ll_start(false); esp_rom_delay_us(delay); adc_oneshot_ll_start(true); diff --git a/components/hal/lcd_hal.c b/components/hal/lcd_hal.c index 08d332a7947..8dbe8d48513 100644 --- a/components/hal/lcd_hal.c +++ b/components/hal/lcd_hal.c @@ -56,7 +56,7 @@ uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uin b /= d; } - HAL_EARLY_LOGD("lcd_hal", "n=%d,a=%d,b=%d,mo=%d", n, a, b, 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_pixel_clock_prescale(hal->dev, mo); diff --git a/components/hal/sdio_slave_hal.c b/components/hal/sdio_slave_hal.c index 34c08d31bc3..be81ca8b150 100644 --- a/components/hal/sdio_slave_hal.c +++ b/components/hal/sdio_slave_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ // The HAL layer for SDIO slave (common part) #include +#include #include "soc/slc_struct.h" #include "soc/hinf_struct.h" #include "hal/sdio_slave_types.h" @@ -318,11 +319,11 @@ static void send_new_packet(sdio_slave_context_t *hal) // update pkt_len register to allow host reading. sdio_slave_ll_send_write_len(hal->slc, end_desc->pkt_len); - HAL_EARLY_LOGV(TAG, "send_length_write: %d, last_len: %08X", end_desc->pkt_len, sdio_slave_ll_send_read_len(hal->host)); + HAL_EARLY_LOGV(TAG, "send_length_write: %"PRIu32", last_len: %08"PRIX32"", end_desc->pkt_len, sdio_slave_ll_send_read_len(hal->host)); send_set_state(hal, STATE_SENDING); - HAL_EARLY_LOGD(TAG, "restart new send: %p->%p, pkt_len: %d", start_desc, end_desc, end_desc->pkt_len); + HAL_EARLY_LOGD(TAG, "restart new send: %p->%p, pkt_len: %"PRIu32"", start_desc, end_desc, end_desc->pkt_len); } static esp_err_t send_check_new_packet(sdio_slave_context_t *hal) @@ -668,7 +669,7 @@ void sdio_slave_hal_load_buf(sdio_slave_context_t *hal, sdio_slave_ll_desc_t *de static inline void show_queue_item(sdio_slave_ll_desc_t *item) { - HAL_EARLY_LOGI(TAG, "=> %p: size: %d(%d), eof: %d, owner: %d", item, item->size, item->length, item->eof, item->owner); + HAL_EARLY_LOGI(TAG, "=> %p: size: %"PRIu32"(%"PRIu32"), eof: %"PRIu32", owner: %"PRIu32"", item, item->size, item->length, item->eof, item->owner); HAL_EARLY_LOGI(TAG, " buf: %p, stqe_next: %p", item->buf, item->qe.stqe_next); } diff --git a/components/hal/test/CMakeLists.txt b/components/hal/test/CMakeLists.txt index 144d832d987..a06f271e1a9 100644 --- a/components/hal/test/CMakeLists.txt +++ b/components/hal/test/CMakeLists.txt @@ -1,4 +1,3 @@ idf_component_register(SRC_DIRS "." PRIV_INCLUDE_DIRS "${include_dirs}" PRIV_REQUIRES cmock test_utils) -target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") From 90698bf1f5912e116994fced9bfcdb86b274a2eb Mon Sep 17 00:00:00 2001 From: liuning Date: Wed, 2 Aug 2023 19:48:00 +0800 Subject: [PATCH 15/71] fix(sleep_modem): fix lightsleep failure if enable lightsleep at phy disabled --- .../include/esp_private/sleep_modem.h | 21 ++++++++++++++- components/esp_hw_support/sleep_modem.c | 7 +++-- components/esp_phy/src/phy_init.c | 27 +++++++++++++------ 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/sleep_modem.h b/components/esp_hw_support/include/esp_private/sleep_modem.h index 2e84830b6d4..b5a4f232061 100644 --- a/components/esp_hw_support/include/esp_private/sleep_modem.h +++ b/components/esp_hw_support/include/esp_private/sleep_modem.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -161,6 +161,25 @@ void esp_pm_register_light_sleep_default_params_config_callback(update_light_sle */ void esp_pm_unregister_light_sleep_default_params_config_callback(void); +#if SOC_PM_SUPPORT_PMU_MODEM_STATE +/** + * @brief Init Wi-Fi modem state. + * + * This function init wifi modem state. + * @return + * - ESP_OK on success + * - ESP_ERR_NO_MEM if no memory for link + */ +esp_err_t sleep_modem_wifi_modem_state_init(void); + +/** + * @brief Deinit Wi-Fi modem state. + * + * This function deinit wifi modem state. + */ +void sleep_modem_wifi_modem_state_deinit(void); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/sleep_modem.c b/components/esp_hw_support/sleep_modem.c index ccedf6a2453..c5eb4acbb50 100644 --- a/components/esp_hw_support/sleep_modem.c +++ b/components/esp_hw_support/sleep_modem.c @@ -167,7 +167,7 @@ typedef struct sleep_modem_config { static sleep_modem_config_t s_sleep_modem = { .wifi.phy_link = NULL, .wifi.flags = 0 }; -static __attribute__((unused)) esp_err_t sleep_modem_wifi_modem_state_init(void) +__attribute__((unused)) esp_err_t sleep_modem_wifi_modem_state_init(void) { esp_err_t err = ESP_OK; phy_i2c_master_command_attribute_t cmd; @@ -244,7 +244,7 @@ static __attribute__((unused)) esp_err_t sleep_modem_wifi_modem_state_init(void) return err; } -static __attribute__((unused)) void sleep_modem_wifi_modem_state_deinit(void) +__attribute__((unused)) void sleep_modem_wifi_modem_state_deinit(void) { if (s_sleep_modem.wifi.phy_link) { regdma_link_destroy(s_sleep_modem.wifi.phy_link, 0); @@ -319,14 +319,13 @@ esp_err_t sleep_modem_configure(int max_freq_mhz, int min_freq_mhz, bool light_s #if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP extern int esp_wifi_internal_mac_sleep_configure(bool, bool); if (light_sleep_enable) { - if (sleep_modem_wifi_modem_state_init() == ESP_OK) { + if (sleep_modem_wifi_modem_state_enabled() == ESP_OK) { esp_pm_register_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep); esp_wifi_internal_mac_sleep_configure(light_sleep_enable, true); /* require WiFi to enable automatically receives the beacon */ } } else { esp_wifi_internal_mac_sleep_configure(light_sleep_enable, false); /* require WiFi to disable automatically receives the beacon */ esp_pm_unregister_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep); - sleep_modem_wifi_modem_state_deinit(); } #endif #if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index a02146e63a6..505b0bfee17 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -85,8 +85,10 @@ static bool s_is_phy_calibrated = false; static bool s_is_phy_reg_stored = false; /* Memory to store PHY digital registers */ static uint32_t* s_phy_digital_regs_mem = NULL; -static uint8_t s_phy_modem_init_ref = 0; #endif // SOC_PM_MODEM_RETENTION_BY_BACKUPDMA +#if SOC_PM_MODEM_RETENTION_BY_BACKUPDMA || CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP +static uint8_t s_phy_modem_init_ref = 0; +#endif #if CONFIG_ESP_PHY_MULTIPLE_INIT_DATA_BIN @@ -349,23 +351,29 @@ void esp_wifi_bt_power_domain_off(void) void esp_phy_modem_init(void) { -#if SOC_PM_MODEM_RETENTION_BY_BACKUPDMA +#if SOC_PM_MODEM_RETENTION_BY_BACKUPDMA || CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP _lock_acquire(&s_phy_access_lock); s_phy_modem_init_ref++; +#if SOC_PM_MODEM_RETENTION_BY_BACKUPDMA if (s_phy_digital_regs_mem == NULL) { s_phy_digital_regs_mem = (uint32_t *)heap_caps_malloc(SOC_PHY_DIG_REGS_MEM_SIZE, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL); } - _lock_release(&s_phy_access_lock); #endif // SOC_PM_MODEM_RETENTION_BY_BACKUPDMA +#if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP + sleep_modem_wifi_modem_state_init(); +#endif // CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP + _lock_release(&s_phy_access_lock); +#endif // SOC_PM_MODEM_RETENTION_BY_BACKUPDMA || CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP } void esp_phy_modem_deinit(void) { -#if SOC_PM_MODEM_RETENTION_BY_BACKUPDMA +#if SOC_PM_MODEM_RETENTION_BY_BACKUPDMA || CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP _lock_acquire(&s_phy_access_lock); s_phy_modem_init_ref--; if (s_phy_modem_init_ref == 0) { +#if SOC_PM_MODEM_RETENTION_BY_BACKUPDMA s_is_phy_reg_stored = false; free(s_phy_digital_regs_mem); s_phy_digital_regs_mem = NULL; @@ -374,11 +382,14 @@ void esp_phy_modem_deinit(void) */ #if CONFIG_IDF_TARGET_ESP32C3 phy_init_flag(); -#endif +#endif // CONFIG_IDF_TARGET_ESP32C3 +#endif // SOC_PM_MODEM_RETENTION_BY_BACKUPDMA +#if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP + sleep_modem_wifi_modem_state_deinit(); +#endif // CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP } - _lock_release(&s_phy_access_lock); -#endif // SOC_PM_MODEM_RETENTION_BY_BACKUPDMA +#endif // SOC_PM_MODEM_RETENTION_BY_BACKUPDMA || CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP } #if CONFIG_MAC_BB_PD From c6db3068339b881875da4ba08bc808c7e5353ef9 Mon Sep 17 00:00:00 2001 From: liuning Date: Fri, 15 Sep 2023 11:34:03 +0800 Subject: [PATCH 16/71] sleep_modem: split esp_wifi_internal_mac_sleep_configure, add lock for pm functions --- .../include/esp_private/sleep_modem.h | 10 ++++++++++ components/esp_hw_support/sleep_modem.c | 16 ++++------------ components/esp_pm/pm_impl.c | 9 +++++++++ components/esp_wifi/include/esp_private/wifi.h | 16 ++++++++++++---- components/esp_wifi/src/wifi_init.c | 16 +++++++++++++--- 5 files changed, 48 insertions(+), 19 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/sleep_modem.h b/components/esp_hw_support/include/esp_private/sleep_modem.h index b5a4f232061..fe8e3ea2205 100644 --- a/components/esp_hw_support/include/esp_private/sleep_modem.h +++ b/components/esp_hw_support/include/esp_private/sleep_modem.h @@ -178,6 +178,16 @@ esp_err_t sleep_modem_wifi_modem_state_init(void); * This function deinit wifi modem state. */ void sleep_modem_wifi_modem_state_deinit(void); + +/** + * @brief Function to check Wi-Fi modem state to skip light sleep. + * + * This function is to check if light sleep should skip by Wi-Fi modem state . + * @return + * - true skip light sleep + * - false not skip light sleep + */ +bool sleep_modem_wifi_modem_state_skip_light_sleep(void); #endif #ifdef __cplusplus diff --git a/components/esp_hw_support/sleep_modem.c b/components/esp_hw_support/sleep_modem.c index c5eb4acbb50..7e963aa64d0 100644 --- a/components/esp_hw_support/sleep_modem.c +++ b/components/esp_hw_support/sleep_modem.c @@ -167,7 +167,7 @@ typedef struct sleep_modem_config { static sleep_modem_config_t s_sleep_modem = { .wifi.phy_link = NULL, .wifi.flags = 0 }; -__attribute__((unused)) esp_err_t sleep_modem_wifi_modem_state_init(void) +esp_err_t sleep_modem_wifi_modem_state_init(void) { esp_err_t err = ESP_OK; phy_i2c_master_command_attribute_t cmd; @@ -302,7 +302,7 @@ uint32_t IRAM_ATTR sleep_modem_reject_triggers(void) return reject_triggers; } -static __attribute__((unused)) bool IRAM_ATTR sleep_modem_wifi_modem_state_skip_light_sleep(void) +bool IRAM_ATTR sleep_modem_wifi_modem_state_skip_light_sleep(void) { bool skip = false; #if SOC_PM_SUPPORT_PMU_MODEM_STATE @@ -317,16 +317,8 @@ static __attribute__((unused)) bool IRAM_ATTR sleep_modem_wifi_modem_state_skip_ esp_err_t sleep_modem_configure(int max_freq_mhz, int min_freq_mhz, bool light_sleep_enable) { #if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP - extern int esp_wifi_internal_mac_sleep_configure(bool, bool); - if (light_sleep_enable) { - if (sleep_modem_wifi_modem_state_enabled() == ESP_OK) { - esp_pm_register_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep); - esp_wifi_internal_mac_sleep_configure(light_sleep_enable, true); /* require WiFi to enable automatically receives the beacon */ - } - } else { - esp_wifi_internal_mac_sleep_configure(light_sleep_enable, false); /* require WiFi to disable automatically receives the beacon */ - esp_pm_unregister_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep); - } + extern int esp_wifi_internal_light_sleep_configure(bool); + esp_wifi_internal_light_sleep_configure(light_sleep_enable); #endif #if CONFIG_PM_SLP_DEFAULT_PARAMS_OPT if (light_sleep_enable) { diff --git a/components/esp_pm/pm_impl.c b/components/esp_pm/pm_impl.c index 08547bd882b..417b046d309 100644 --- a/components/esp_pm/pm_impl.c +++ b/components/esp_pm/pm_impl.c @@ -123,6 +123,8 @@ static bool s_skipped_light_sleep[portNUM_PROCESSORS]; */ static bool s_skip_light_sleep[portNUM_PROCESSORS]; #endif // portNUM_PROCESSORS == 2 + +static _lock_t s_skip_light_sleep_lock; #endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE /* A flag indicating that Idle hook has run on a given CPU; @@ -547,25 +549,32 @@ static void IRAM_ATTR leave_idle(void) esp_err_t esp_pm_register_skip_light_sleep_callback(skip_light_sleep_cb_t cb) { + _lock_acquire(&s_skip_light_sleep_lock); for (int i = 0; i < PERIPH_SKIP_LIGHT_SLEEP_NO; i++) { if (s_periph_skip_light_sleep_cb[i] == cb) { + _lock_release(&s_skip_light_sleep_lock); return ESP_OK; } else if (s_periph_skip_light_sleep_cb[i] == NULL) { s_periph_skip_light_sleep_cb[i] = cb; + _lock_release(&s_skip_light_sleep_lock); return ESP_OK; } } + _lock_release(&s_skip_light_sleep_lock); return ESP_ERR_NO_MEM; } esp_err_t esp_pm_unregister_skip_light_sleep_callback(skip_light_sleep_cb_t cb) { + _lock_acquire(&s_skip_light_sleep_lock); for (int i = 0; i < PERIPH_SKIP_LIGHT_SLEEP_NO; i++) { if (s_periph_skip_light_sleep_cb[i] == cb) { s_periph_skip_light_sleep_cb[i] = NULL; + _lock_release(&s_skip_light_sleep_lock); return ESP_OK; } } + _lock_release(&s_skip_light_sleep_lock); return ESP_ERR_INVALID_STATE; } diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index acb18626ef8..fc7ae119b00 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -629,15 +629,23 @@ void esp_wifi_set_keep_alive_time(uint32_t keep_alive_time); void esp_wifi_beacon_monitor_configure(wifi_beacon_monitor_config_t *config); /** - * @brief Require WiFi to enable or disable Advanced DTIM sleep function + * @brief Set modem state mode to require WiFi to enable or disable Advanced DTIM sleep function * - * @param light_sleep_enable: true for light sleep mode is enabled, false for light sleep mode is disabled. - * @param modem_state_enable: true for require WiFi to enable Advanced DTIM sleep function, + * @param require_modem_state: true for require WiFi to enable Advanced DTIM sleep function, * false for require WiFi to disable Advanced DTIM sleep function. * @return * - ESP_OK: succeed */ -void esp_wifi_internal_mac_sleep_configure(bool light_sleep_enable, bool modem_state_enable); +void esp_wifi_internal_modem_state_configure(bool require_modem_state); + +/** + * @brief Set light sleep mode to require WiFi to enable or disable Advanced DTIM sleep function + * + * @param light_sleep_enable: true for light sleep mode is enabled, false for light sleep mode is disabled. + * @return + * - ESP_OK: succeed + */ +void esp_wifi_internal_light_sleep_configure(bool light_sleep_enable); /** * @brief Start Publishing a service in the NAN cluster diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index e67069a6a57..4473cfc4386 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -167,6 +167,10 @@ esp_err_t esp_wifi_deinit(void) #if CONFIG_MAC_BB_PD esp_wifi_internal_set_mac_sleep(false); esp_mac_bb_pd_mem_deinit(); +#endif +#if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP + esp_wifi_internal_modem_state_configure(false); + esp_pm_unregister_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep); #endif esp_phy_modem_deinit(); @@ -231,12 +235,12 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) #endif #if CONFIG_ESP_WIFI_SLP_IRAM_OPT - esp_pm_register_light_sleep_default_params_config_callback(esp_wifi_internal_update_light_sleep_default_params); - int min_freq_mhz = esp_pm_impl_get_cpu_freq(PM_MODE_LIGHT_SLEEP); int max_freq_mhz = esp_pm_impl_get_cpu_freq(PM_MODE_CPU_MAX); esp_wifi_internal_update_light_sleep_default_params(min_freq_mhz, max_freq_mhz); + esp_pm_register_light_sleep_default_params_config_callback(esp_wifi_internal_update_light_sleep_default_params); + uint32_t sleep_delay_us = CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME * 1000; esp_wifi_set_sleep_delay_time(sleep_delay_us); @@ -291,6 +295,12 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) esp_wifi_internal_set_mac_sleep(true); #endif esp_phy_modem_init(); +#if CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP + if (sleep_modem_wifi_modem_state_enabled()) { + esp_pm_register_skip_light_sleep_callback(sleep_modem_wifi_modem_state_skip_light_sleep); + esp_wifi_internal_modem_state_configure(true); /* require WiFi to enable automatically receives the beacon */ + } +#endif #if CONFIG_IDF_TARGET_ESP32 s_wifi_mac_time_update_cb = esp_wifi_internal_update_mac_time; #endif From 84d91e5bf96f05d336f0988899fd594ad892db49 Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Tue, 5 Sep 2023 21:22:37 +0530 Subject: [PATCH 17/71] fix(esp_hw_support/test_apps): fix redudancy in hmac and ds test apps --- .../esp_hw_support/.build-test-rules.yml | 6 - .../main/CMakeLists.txt | 3 + .../main/digital_signature_test_cases_3072.h | 0 .../main/digital_signature_test_cases_4096.h | 0 .../main/gen_digital_signature_tests.py | 0 .../main/test_app_main.c | 6 +- .../esp_hw_support_unity_tests/main/test_ds.c | 8 - .../main/test_hmac.c | 16 +- .../main/test_random.c | 0 .../pytest_esp_hw_support.py | 2 +- .../esp_hw_support_unity_tests/CMakeLists.txt | 10 - .../esp_hw_support_unity_tests/README.md | 2 - .../main/CMakeLists.txt | 11 - .../main/test_app_main.c | 75 --- .../main/test_config.h | 9 - .../esp_hw_support_unity_tests/main/test_ds.c | 450 ------------------ .../pytest_security_support.py | 18 - .../sdkconfig.ci.default | 1 - .../sdkconfig.ci.release | 6 - .../sdkconfig.defaults | 2 - .../sdkconfig.defaults.esp32 | 2 - .../sdkconfig.defaults.esp32s2 | 2 - 22 files changed, 16 insertions(+), 613 deletions(-) rename components/esp_hw_support/test_apps/{security_support => }/esp_hw_support_unity_tests/main/digital_signature_test_cases_3072.h (100%) rename components/esp_hw_support/test_apps/{security_support => }/esp_hw_support_unity_tests/main/digital_signature_test_cases_4096.h (100%) rename components/esp_hw_support/test_apps/{security_support => }/esp_hw_support_unity_tests/main/gen_digital_signature_tests.py (100%) rename components/esp_hw_support/test_apps/{security_support => }/esp_hw_support_unity_tests/main/test_hmac.c (99%) rename components/esp_hw_support/test_apps/{security_support => }/esp_hw_support_unity_tests/main/test_random.c (100%) delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/CMakeLists.txt delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/README.md delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/CMakeLists.txt delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_app_main.c delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_config.h delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_ds.c delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/pytest_security_support.py delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.ci.default delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.ci.release delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults.esp32 delete mode 100644 components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults.esp32s2 diff --git a/components/esp_hw_support/.build-test-rules.yml b/components/esp_hw_support/.build-test-rules.yml index 82119559a90..dcb1f22d885 100644 --- a/components/esp_hw_support/.build-test-rules.yml +++ b/components/esp_hw_support/.build-test-rules.yml @@ -41,9 +41,3 @@ components/esp_hw_support/test_apps/rtc_power_modes: - if: IDF_TARGET in ["esp32s2", "esp32s3", "esp32c2", "esp32c3"] temporary: true reason: the other targets are not tested yet - -components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests: - disable_test: - - if: IDF_TARGET in ["esp32h2"] - temporary: true - reason: H2 fails IDF-6898 diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt index 69f6c59261e..982a32fa205 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt @@ -3,6 +3,9 @@ set(srcs "test_app_main.c" "test_fp.c" "test_intr_alloc.c" "test_dport_xt_highint5.S" + "test_ds.c" + "test_hmac.c" + "test_random.c" ) # In order for the cases defined by `TEST_CASE` to be linked into the final elf, diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/digital_signature_test_cases_3072.h b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/digital_signature_test_cases_3072.h similarity index 100% rename from components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/digital_signature_test_cases_3072.h rename to components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/digital_signature_test_cases_3072.h diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/digital_signature_test_cases_4096.h b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/digital_signature_test_cases_4096.h similarity index 100% rename from components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/digital_signature_test_cases_4096.h rename to components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/digital_signature_test_cases_4096.h diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/gen_digital_signature_tests.py b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/gen_digital_signature_tests.py similarity index 100% rename from components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/gen_digital_signature_tests.py rename to components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/gen_digital_signature_tests.py diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_app_main.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_app_main.c index cec79807cb7..d127fae5c52 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_app_main.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_app_main.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 */ @@ -16,7 +16,9 @@ #include "esp_heap_trace.h" #endif -#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT -400 +/* During merging of DS and HMAC testapps to this directory, maximum memory leak during running is 404, +so, updating TEST_MEMORY_LEAK_THRESHOLD_DEFAULT */ +#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT -416 static int leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; void set_leak_threshold(int threshold) diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ds.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ds.c index aa5272993c3..216a9f6f75f 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ds.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ds.c @@ -415,11 +415,7 @@ TEST_CASE("Digital Signature Invalid Data (FPGA only)", "[hw_crypto] [ds]") esp_err_t ds_r = esp_ds_start_sign(test_messages[0], &ds_data, t->hmac_key_idx + 1, &esp_ds_ctx); TEST_ASSERT_EQUAL(ESP_OK, ds_r); ds_r = esp_ds_finish_sign(signature, esp_ds_ctx); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 TEST_ASSERT_EQUAL(ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r); -#elif CONFIG_IDF_TARGET_ESP32C3 - TEST_ASSERT_EQUAL(ESP32C3_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r); -#endif TEST_ASSERT_EQUAL_HEX8_ARRAY(zero, signature, DS_MAX_BITS / 8); ds_data.iv[bit / 8] ^= 1 << (bit % 8); @@ -435,11 +431,7 @@ TEST_CASE("Digital Signature Invalid Data (FPGA only)", "[hw_crypto] [ds]") esp_err_t ds_r = esp_ds_start_sign(test_messages[0], &ds_data, t->hmac_key_idx + 1, &esp_ds_ctx); TEST_ASSERT_EQUAL(ESP_OK, ds_r); ds_r = esp_ds_finish_sign(signature, esp_ds_ctx); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 TEST_ASSERT_EQUAL(ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r); -#elif CONFIG_IDF_TARGET_ESP32C3 - TEST_ASSERT_EQUAL(ESP32C3_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r); -#endif TEST_ASSERT_EQUAL_HEX8_ARRAY(zero, signature, DS_MAX_BITS / 8); ds_data.c[bit / 8] ^= 1 << (bit % 8); diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_hmac.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_hmac.c similarity index 99% rename from components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_hmac.c rename to components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_hmac.c index cf49bc19e33..8fa32e6d95a 100644 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_hmac.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_hmac.c @@ -41,7 +41,7 @@ TEST_CASE("HMAC 'downstream' JTAG Enable mode", "[hw_crypto]") { int ets_status; - setup_keyblock(EFUSE_BLK_KEY3, ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG); + setup_keyblock(EFUSE_BLK_KEY4, ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG); // Results calculated with Python: // @@ -64,7 +64,7 @@ TEST_CASE("HMAC 'downstream' JTAG Enable mode", "[hw_crypto]") TEST_ASSERT_MESSAGE(ESP_OK == esp_efuse_batch_write_commit(), "Error programming security efuse.\n"); - TEST_ASSERT_EQUAL_HEX32_MESSAGE(ESP_OK, esp_hmac_jtag_enable(HMAC_KEY3, token_data), + TEST_ASSERT_EQUAL_HEX32_MESSAGE(ESP_OK, esp_hmac_jtag_enable(HMAC_KEY4, token_data), "JTAG should be re-enabled now, please manually verify"); } @@ -78,7 +78,7 @@ TEST_CASE("HMAC 'upstream' MAC generation with zeroes", "[hw_crypto]") { uint8_t hmac[32]; - setup_keyblock(EFUSE_BLK_KEY4, ESP_EFUSE_KEY_PURPOSE_HMAC_UP); + setup_keyblock(EFUSE_BLK_KEY5, ESP_EFUSE_KEY_PURPOSE_HMAC_UP); const uint8_t zeroes[128] = { }; // Produce the HMAC of various numbers of zeroes @@ -163,7 +163,7 @@ TEST_CASE("HMAC 'upstream' MAC generation with zeroes", "[hw_crypto]") const size_t num_zero_results = sizeof(zero_results) / sizeof(hmac_result); for (int i = 0; i < num_zero_results; i++) { - TEST_ESP_OK(esp_hmac_calculate(HMAC_KEY4, zeroes, zero_results[i].msglen, hmac)); + TEST_ESP_OK(esp_hmac_calculate(HMAC_KEY5, zeroes, zero_results[i].msglen, hmac)); TEST_ASSERT_EQUAL_HEX8_ARRAY(zero_results[i].result, hmac, sizeof(hmac)); } } @@ -173,7 +173,7 @@ TEST_CASE("HMAC 'upstream' MAC generation from data", "[hw_crypto]") { uint8_t hmac[32]; - setup_keyblock(EFUSE_BLK_KEY4, ESP_EFUSE_KEY_PURPOSE_HMAC_UP); + setup_keyblock(EFUSE_BLK_KEY5, ESP_EFUSE_KEY_PURPOSE_HMAC_UP); // 257 characters of pseudo-Latin from lipsum.com (not Copyright) const char *message = "Deleniti voluptas explicabo et assumenda. Sed et aliquid minus quis. Praesentium cupiditate quia nemo est. Laboriosam pariatur ut distinctio tenetur. Sunt architecto iure aspernatur soluta ut recusandae. Ut quibusdam occaecati ut qui sit dignissimos eaque.."; @@ -961,7 +961,7 @@ TEST_CASE("HMAC 'upstream' MAC generation from data", "[hw_crypto]") }; for (int i = 0; i < sizeof(results)/sizeof(hmac_result); i++) { - TEST_ESP_OK(esp_hmac_calculate(HMAC_KEY4, message, results[i].msglen, hmac)); + TEST_ESP_OK(esp_hmac_calculate(HMAC_KEY5, message, results[i].msglen, hmac)); TEST_ASSERT_EQUAL_HEX8_ARRAY(results[i].result, hmac, sizeof(hmac)); } } @@ -973,7 +973,7 @@ TEST_CASE("HMAC 'upstream' wait lock", "[hw_crypto]") // 257 characters of pseudo-Latin from lipsum.com (not Copyright) const char *message = "Deleniti voluptas explicabo et assumenda. Sed et aliquid minus quis. Praesentium cupiditate quia nemo est. Laboriosam pariatur ut distinctio tenetur. Sunt architecto iure aspernatur soluta ut recusandae. Ut quibusdam occaecati ut qui sit dignissimos eaque.."; - setup_keyblock(EFUSE_BLK_KEY4, ESP_EFUSE_KEY_PURPOSE_HMAC_UP); + setup_keyblock(EFUSE_BLK_KEY5, ESP_EFUSE_KEY_PURPOSE_HMAC_UP); static const hmac_result results[] = { { .msglen = 255, @@ -985,7 +985,7 @@ TEST_CASE("HMAC 'upstream' wait lock", "[hw_crypto]") }; for (int i = 0; i < sizeof(results)/sizeof(hmac_result); i++) { - TEST_ESP_OK(esp_hmac_calculate(HMAC_KEY4, message, results[i].msglen, hmac)); + TEST_ESP_OK(esp_hmac_calculate(HMAC_KEY5, message, results[i].msglen, hmac)); TEST_ASSERT_EQUAL_HEX8_ARRAY(results[i].result, hmac, sizeof(hmac)); } } diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_random.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_random.c similarity index 100% rename from components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_random.c rename to components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_random.c diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py index e755803425a..e8523e104c2 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py @@ -16,4 +16,4 @@ indirect=True, ) def test_esp_hw_support(dut: Dut) -> None: - dut.run_all_single_board_cases(timeout=120) + dut.run_all_single_board_cases(timeout=180) diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/CMakeLists.txt b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/CMakeLists.txt deleted file mode 100644 index 64fba888719..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# This is the project CMakeLists.txt file for the test subproject -cmake_minimum_required(VERSION 3.16) - -set(COMPONENTS main) -set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") - -list(PREPEND SDKCONFIG_DEFAULTS "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" "sdkconfig.defaults") - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(test_app_security_support) diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/README.md b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/README.md deleted file mode 100644 index bf47d80ec64..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/README.md +++ /dev/null @@ -1,2 +0,0 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/CMakeLists.txt b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/CMakeLists.txt deleted file mode 100644 index 749d633ac2d..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set(srcs "test_app_main.c" - "test_ds.c" - "test_hmac.c" - "test_random.c" - ) - -# In order for the cases defined by `TEST_CASE` to be linked into the final elf, -# the component can be registered as WHOLE_ARCHIVE -idf_component_register(SRCS ${srcs} - REQUIRES unity driver test_utils efuse - WHOLE_ARCHIVE) diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_app_main.c b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_app_main.c deleted file mode 100644 index cec79807cb7..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_app_main.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "unity.h" -#include "unity_test_runner.h" -#include "esp_heap_caps.h" -#include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "test_config.h" -#ifdef CONFIG_HEAP_TRACING -#include "memory_checks.h" -#include "esp_heap_trace.h" -#endif - -#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT -400 -static int leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; - -void set_leak_threshold(int threshold) -{ - leak_threshold = threshold; -} - -static size_t before_free_8bit; -static size_t before_free_32bit; -static const char* TAG = "esp_hw_support_test_app"; - -static void check_leak(size_t before_free, size_t after_free, const char *type) -{ - ssize_t delta = after_free - before_free; - printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); - TEST_ASSERT_MESSAGE(delta >= leak_threshold, "memory leak"); -} - - -void setUp(void) -{ - // If heap tracing is enabled in kconfig, leak trace the test -#ifdef CONFIG_HEAP_TRACING - setup_heap_record(); - heap_trace_start(HEAP_TRACE_LEAKS); -#endif - - leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; - - before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); -} - -void tearDown(void) -{ - /*Give idle task time to clean up*/ - vTaskDelay(10); - -#ifdef CONFIG_HEAP_TRACING - heap_trace_stop(); - heap_trace_dump(); -#endif - - size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); - check_leak(before_free_8bit, after_free_8bit, "8BIT"); - check_leak(before_free_32bit, after_free_32bit, "32BIT"); - -} - -void app_main(void) -{ - vTaskPrioritySet(NULL, TEST_TASK_PRIORITY); - ESP_LOGI(TAG, "Running esp-hw-support test app"); - unity_run_menu(); -} diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_config.h b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_config.h deleted file mode 100644 index 1b5ec0d9ce8..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_config.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Unlicense OR CC0-1.0 - */ - -#pragma once - -#define TEST_TASK_PRIORITY 5 diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_ds.c b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_ds.c deleted file mode 100644 index aa5272993c3..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/main/test_ds.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "unity.h" - -#include "soc/soc_caps.h" - -#if SOC_DIG_SIGN_SUPPORTED -#if CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/rom/efuse.h" -#include "esp32s2/rom/digital_signature.h" -#include "esp32s2/rom/aes.h" -#include "esp32s2/rom/sha.h" -#elif CONFIG_IDF_TARGET_ESP32C3 -#include "esp32c3/rom/efuse.h" -#include "esp32c3/rom/digital_signature.h" -#include "esp32c3/rom/hmac.h" -#elif CONFIG_IDF_TARGET_ESP32S3 -#include "esp32s3/rom/efuse.h" -#include "esp32s3/rom/digital_signature.h" -#include "esp32s3/rom/aes.h" -#include "esp32s3/rom/sha.h" -#elif CONFIG_IDF_TARGET_ESP32C6 -#include "esp32c6/rom/efuse.h" -#include "esp32c6/rom/digital_signature.h" -#include "esp32c6/rom/aes.h" -#include "esp32c6/rom/sha.h" -#elif CONFIG_IDF_TARGET_ESP32H2 -#include "esp32h2/rom/efuse.h" -#include "esp32h2/rom/digital_signature.h" -#include "esp32h2/rom/aes.h" -#include "esp32h2/rom/sha.h" -#elif CONFIG_IDF_TARGET_ESP32P4 -#include "esp32p4/rom/efuse.h" -#include "esp32p4/rom/digital_signature.h" -#include "esp32p4/rom/aes.h" -#include "esp32p4/rom/sha.h" -#endif - -#include "esp_ds.h" - -#define NUM_RESULTS 10 - -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 -#define DS_MAX_BITS (4096) -#else -#define DS_MAX_BITS (ETS_DS_MAX_BITS) -#endif - -typedef struct { - uint8_t iv[ETS_DS_IV_LEN]; - ets_ds_p_data_t p_data; - uint8_t expected_c[ETS_DS_C_LEN]; - uint8_t hmac_key_idx; - uint32_t expected_results[NUM_RESULTS][DS_MAX_BITS / 32]; -} encrypt_testcase_t; - -// Generated header digital_signature_test_cases_.h (by gen_digital_signature_tests.py) defines -// NUM_HMAC_KEYS, test_hmac_keys, NUM_MESSAGES, NUM_CASES, test_messages[], test_cases[] -// Some adaptations were made: removed the 512 bit case and changed RSA lengths to the enums from esp_ds.h -#if DS_MAX_BITS == 4096 -#define RSA_LEN (ESP_DS_RSA_4096) -#include "digital_signature_test_cases_4096.h" -#elif DS_MAX_BITS == 3072 -#define RSA_LEN (ESP_DS_RSA_3072) -#include "digital_signature_test_cases_3072.h" -#endif - -_Static_assert(NUM_RESULTS == NUM_MESSAGES, "expected_results size should be the same as NUM_MESSAGES in generated header"); - -TEST_CASE("Digital Signature Parameter Encryption data NULL", "[hw_crypto] [ds]") -{ - const char iv [32] = {0}; - esp_ds_p_data_t p_data = {0}; - const char key [32] = {0}; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_encrypt_params(NULL, iv, &p_data, key)); -} - -TEST_CASE("Digital Signature Parameter Encryption iv NULL", "[hw_crypto] [ds]") -{ - esp_ds_data_t data = {0}; - esp_ds_p_data_t p_data = {0}; - const char key [32] = {0}; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_encrypt_params(&data, NULL, &p_data, key)); -} - -TEST_CASE("Digital Signature Parameter Encryption p_data NULL", "[hw_crypto] [ds]") -{ - esp_ds_data_t data = {0}; - const char iv [32] = {0}; - const char key [32] = {0}; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_encrypt_params(&data, iv, NULL, key)); -} - -TEST_CASE("Digital Signature Parameter Encryption key NULL", "[hw_crypto] [ds]") -{ - esp_ds_data_t data = {0}; - const char iv [32] = {0}; - esp_ds_p_data_t p_data = {0}; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_encrypt_params(&data, iv, &p_data, NULL)); -} - -TEST_CASE("Digital Signature Parameter Encryption", "[hw_crypto] [ds]") -{ - for (int i = 0; i < NUM_CASES; i++) { - printf("Encrypting test case %d...\n", i); - const encrypt_testcase_t *t = &test_cases[i]; - esp_ds_data_t result = { }; - esp_ds_p_data_t p_data; - - memcpy(p_data.Y, t->p_data.Y, DS_MAX_BITS / 8); - memcpy(p_data.M, t->p_data.M, DS_MAX_BITS / 8); - memcpy(p_data.Rb, t->p_data.Rb, DS_MAX_BITS / 8); - p_data.M_prime = t->p_data.M_prime; - p_data.length = t->p_data.length; - - esp_err_t r = esp_ds_encrypt_params(&result, t->iv, &p_data, - test_hmac_keys[t->hmac_key_idx]); - printf("Encrypting test case %d done\n", i); - TEST_ASSERT_EQUAL(ESP_OK, r); - TEST_ASSERT_EQUAL(t->p_data.length, result.rsa_length); - TEST_ASSERT_EQUAL_HEX8_ARRAY(t->iv, result.iv, ETS_DS_IV_LEN); - TEST_ASSERT_EQUAL_HEX8_ARRAY(t->expected_c, result.c, ETS_DS_C_LEN); - } -} - -TEST_CASE("Digital Signature start Invalid message", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = { }; - ds_data.rsa_length = RSA_LEN; - esp_ds_context_t *ctx; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(NULL, &ds_data, HMAC_KEY1, &ctx)); -} - -TEST_CASE("Digital Signature start Invalid data", "[hw_crypto] [ds]") -{ - const char *message = "test"; - esp_ds_context_t *ctx; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, NULL, HMAC_KEY1, &ctx)); -} - -TEST_CASE("Digital Signature start Invalid context", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = RSA_LEN; - const char *message = "test"; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY1, NULL)); -} - -TEST_CASE("Digital Signature RSA length 0", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = 0; - const char *message = "test"; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY1, NULL)); -} - -TEST_CASE("Digital Signature RSA length too long", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = 128; - const char *message = "test"; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY1, NULL)); -} - -TEST_CASE("Digital Signature start HMAC key out of range", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = RSA_LEN; - esp_ds_context_t *ctx; - const char *message = "test"; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY5 + 1, &ctx)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_start_sign(message, &ds_data, HMAC_KEY0 - 1, &ctx)); -} - -TEST_CASE("Digital Signature finish Invalid signature ptr", "[hw_crypto] [ds]") -{ - esp_ds_context_t *ctx = NULL; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_finish_sign(NULL, ctx)); -} - -TEST_CASE("Digital Signature finish Invalid context", "[hw_crypto] [ds]") -{ - uint8_t signature_data [128 * 4]; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_finish_sign(signature_data, NULL)); -} - -TEST_CASE("Digital Signature Blocking Invalid message", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = { }; - ds_data.rsa_length = RSA_LEN; - uint8_t signature_data [128 * 4]; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(NULL, &ds_data, HMAC_KEY1, signature_data)); -} - -TEST_CASE("Digital Signature Blocking Invalid data", "[hw_crypto] [ds]") -{ - const char *message = "test"; - uint8_t signature_data [128 * 4]; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, NULL, HMAC_KEY1, signature_data)); -} - -TEST_CASE("Digital Signature Blocking Invalid signature ptr", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = RSA_LEN; - const char *message = "test"; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY1, NULL)); -} - -TEST_CASE("Digital Signature Blocking RSA length 0", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = 0; - const char *message = "test"; - uint8_t signature_data [128 * 4]; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY1, signature_data)); -} - -TEST_CASE("Digital Signature Blocking RSA length too long", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = 128; - const char *message = "test"; - uint8_t signature_data [128 * 4]; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY1, signature_data)); -} - -TEST_CASE("Digital Signature Blocking HMAC key out of range", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = 127; - const char *message = "test"; - uint8_t signature_data [128 * 4]; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY5 + 1, signature_data)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_ds_sign(message, &ds_data, HMAC_KEY0 - 1, signature_data)); -} - -#if CONFIG_IDF_ENV_FPGA - -static void burn_hmac_keys(void) -{ - printf("Burning %d HMAC keys to efuse...\n", NUM_HMAC_KEYS); - for (int i = 0; i < NUM_HMAC_KEYS; i++) { - // TODO: vary the purpose across the keys - ets_efuse_purpose_t purpose = ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE; - - // starting from block 1, block 0 occupied with HMAC upstream test key - int __attribute__((unused)) ets_status = ets_efuse_write_key(ETS_EFUSE_BLOCK_KEY1 + i, - purpose, - test_hmac_keys[i], 32); - -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - if (ets_status == ESP_OK) { - printf("written DS test key to block [%d]!\n", ETS_EFUSE_BLOCK_KEY1 + i); - } else { - printf("writing DS test key to block [%d] failed, maybe written already\n", ETS_EFUSE_BLOCK_KEY1 + i); - } -#endif - } -#if CONFIG_IDF_TARGET_ESP32C3 - /* verify the keys are what we expect (possibly they're already burned, doesn't matter but they have to match) */ - uint8_t block_compare[32]; - for (int i = 0; i < NUM_HMAC_KEYS; i++) { - printf("Checking key %d...\n", i); - memcpy(block_compare, (void *)ets_efuse_get_read_register_address(ETS_EFUSE_BLOCK_KEY1 + i), 32); - TEST_ASSERT_EQUAL_HEX8_ARRAY(test_hmac_keys[i], block_compare, 32); - } -#endif -} - -// This test uses the HMAC_KEY0 eFuse key which hasn't been burned by burn_hmac_keys(). -// HMAC_KEY0 is usually used for HMAC upstream (user access) tests. -TEST_CASE("Digital Signature wrong HMAC key purpose (FPGA only)", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = RSA_LEN; - esp_ds_context_t *ctx; - const char *message = "test"; - - // HMAC fails in that case because it checks for the correct purpose - TEST_ASSERT_EQUAL(ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL, esp_ds_start_sign(message, &ds_data, HMAC_KEY0, &ctx)); -} - -// This test uses the HMAC_KEY0 eFuse key which hasn't been burned by burn_hmac_keys(). -// HMAC_KEY0 is usually used for HMAC upstream (user access) tests. -TEST_CASE("Digital Signature Blocking wrong HMAC key purpose (FPGA only)", "[hw_crypto] [ds]") -{ - esp_ds_data_t ds_data = {}; - ds_data.rsa_length = RSA_LEN; - const char *message = "test"; - uint8_t signature_data [128 * 4]; - - // HMAC fails in that case because it checks for the correct purpose - TEST_ASSERT_EQUAL(ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL, esp_ds_sign(message, &ds_data, HMAC_KEY0, signature_data)); -} - -TEST_CASE("Digital Signature Operation (FPGA only)", "[hw_crypto] [ds]") -{ - burn_hmac_keys(); - - for (int i = 0; i < NUM_CASES; i++) { - printf("Running test case %d...\n", i); - const encrypt_testcase_t *t = &test_cases[i]; - - // copy encrypt parameter test case into ds_data structure - esp_ds_data_t ds_data = { }; - memcpy(ds_data.iv, t->iv, ETS_DS_IV_LEN); - memcpy(ds_data.c, t->expected_c, ETS_DS_C_LEN); - ds_data.rsa_length = t->p_data.length; - - for (int j = 0; j < NUM_MESSAGES; j++) { - uint8_t signature[DS_MAX_BITS / 8] = { 0 }; - printf(" ... message %d\n", j); - - esp_ds_context_t *esp_ds_ctx; - - esp_err_t ds_r = esp_ds_start_sign(test_messages[j], - &ds_data, - t->hmac_key_idx + 1, - &esp_ds_ctx); - TEST_ASSERT_EQUAL(ESP_OK, ds_r); - - ds_r = esp_ds_finish_sign(signature, esp_ds_ctx); - TEST_ASSERT_EQUAL(ESP_OK, ds_r); - - TEST_ASSERT_EQUAL_HEX8_ARRAY(t->expected_results[j], signature, sizeof(signature)); - } -#if CONFIG_IDF_TARGET_ESP32C3 - ets_hmac_invalidate_downstream(ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE); -#endif - } -} - -TEST_CASE("Digital Signature Blocking Operation (FPGA only)", "[hw_crypto] [ds]") -{ - burn_hmac_keys(); - - for (int i = 0; i < NUM_CASES; i++) { - printf("Running test case %d...\n", i); - const encrypt_testcase_t *t = &test_cases[i]; - - // copy encrypt parameter test case into ds_data structure - esp_ds_data_t ds_data = { }; - memcpy(ds_data.iv, t->iv, ETS_DS_IV_LEN); - memcpy(ds_data.c, t->expected_c, ETS_DS_C_LEN); - ds_data.rsa_length = t->p_data.length; - - uint8_t signature[DS_MAX_BITS / 8] = { 0 }; -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - esp_ds_context_t *esp_ds_ctx; - - esp_err_t ds_r = esp_ds_start_sign(test_messages[0], - &ds_data, - t->hmac_key_idx + 1, - &esp_ds_ctx); - TEST_ASSERT_EQUAL(ESP_OK, ds_r); - - ds_r = esp_ds_finish_sign(signature, esp_ds_ctx); - TEST_ASSERT_EQUAL(ESP_OK, ds_r); -#else - esp_err_t ds_r = esp_ds_sign(test_messages[0], - &ds_data, - t->hmac_key_idx + 1, - signature); - TEST_ASSERT_EQUAL(ESP_OK, ds_r); -#endif - - TEST_ASSERT_EQUAL_HEX8_ARRAY(t->expected_results[0], signature, sizeof(signature)); - } -} - -TEST_CASE("Digital Signature Invalid Data (FPGA only)", "[hw_crypto] [ds]") -{ - burn_hmac_keys(); - - // Set up a valid test case - const encrypt_testcase_t *t = &test_cases[0]; - esp_ds_data_t ds_data = { }; - memcpy(ds_data.iv, t->iv, ETS_DS_IV_LEN); - memcpy(ds_data.c, t->expected_c, ETS_DS_C_LEN); - ds_data.rsa_length = t->p_data.length; - - uint8_t signature[DS_MAX_BITS / 8] = { 0 }; - const uint8_t zero[DS_MAX_BITS / 8] = { 0 }; - - // Corrupt the IV one bit at a time, rerun and expect failure - for (int bit = 0; bit < 128; bit++) { - printf("Corrupting IV bit %d...\n", bit); - ds_data.iv[bit / 8] ^= 1 << (bit % 8); - esp_ds_context_t *esp_ds_ctx; - - esp_err_t ds_r = esp_ds_start_sign(test_messages[0], &ds_data, t->hmac_key_idx + 1, &esp_ds_ctx); - TEST_ASSERT_EQUAL(ESP_OK, ds_r); - ds_r = esp_ds_finish_sign(signature, esp_ds_ctx); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - TEST_ASSERT_EQUAL(ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r); -#elif CONFIG_IDF_TARGET_ESP32C3 - TEST_ASSERT_EQUAL(ESP32C3_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r); -#endif - TEST_ASSERT_EQUAL_HEX8_ARRAY(zero, signature, DS_MAX_BITS / 8); - - ds_data.iv[bit / 8] ^= 1 << (bit % 8); - } - - // Corrupt encrypted key data one bit at a time, rerun and expect failure - printf("Corrupting C...\n"); - for (int bit = 0; bit < ETS_DS_C_LEN * 8; bit++) { - printf("Corrupting C bit %d...\n", bit); - ds_data.c[bit / 8] ^= 1 << (bit % 8); - esp_ds_context_t *esp_ds_ctx; - - esp_err_t ds_r = esp_ds_start_sign(test_messages[0], &ds_data, t->hmac_key_idx + 1, &esp_ds_ctx); - TEST_ASSERT_EQUAL(ESP_OK, ds_r); - ds_r = esp_ds_finish_sign(signature, esp_ds_ctx); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - TEST_ASSERT_EQUAL(ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r); -#elif CONFIG_IDF_TARGET_ESP32C3 - TEST_ASSERT_EQUAL(ESP32C3_ERR_HW_CRYPTO_DS_INVALID_DIGEST, ds_r); -#endif - TEST_ASSERT_EQUAL_HEX8_ARRAY(zero, signature, DS_MAX_BITS / 8); - - ds_data.c[bit / 8] ^= 1 << (bit % 8); - } -} - -#endif // CONFIG_IDF_ENV_FPGA -#endif // SOC_DIG_SIGN_SUPPORTED diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/pytest_security_support.py b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/pytest_security_support.py deleted file mode 100644 index 3d27fb1ad97..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/pytest_security_support.py +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: CC0-1.0 - -import pytest -from pytest_embedded import Dut - - -@pytest.mark.generic -@pytest.mark.parametrize( - 'config', - [ - pytest.param('default', marks=[pytest.mark.supported_targets, pytest.mark.temp_skip_ci(targets=['esp32h2'], reason='test failed IDF-6898')]), - pytest.param('release', marks=[pytest.mark.supported_targets, pytest.mark.temp_skip_ci(targets=['esp32h2'], reason='test failed IDF-6898')]), - ], - indirect=True, -) -def test_security_support(dut: Dut) -> None: - dut.run_all_single_board_cases(timeout=120) diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.ci.default b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.ci.default deleted file mode 100644 index 5324680c99c..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.ci.default +++ /dev/null @@ -1 +0,0 @@ -# Empty file to be able to parametrize "default" config diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.ci.release b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.ci.release deleted file mode 100644 index 8b0a31a9bcb..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.ci.release +++ /dev/null @@ -1,6 +0,0 @@ -# set compiler optimization level -CONFIG_COMPILER_OPTIMIZATION_SIZE=y -CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y - -# we can silent the assertion to save the binary footprint -CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults deleted file mode 100644 index b71277ca371..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_ESP_TASK_WDT_INIT=n -CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults.esp32 b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults.esp32 deleted file mode 100644 index 966c5e4f955..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults.esp32 +++ /dev/null @@ -1,2 +0,0 @@ -# Set CPU frequency to max for performance tests -# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y diff --git a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults.esp32s2 b/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults.esp32s2 deleted file mode 100644 index a28e22281dc..00000000000 --- a/components/esp_hw_support/test_apps/security_support/esp_hw_support_unity_tests/sdkconfig.defaults.esp32s2 +++ /dev/null @@ -1,2 +0,0 @@ -# Set CPU frequency to max for performance tests -CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y From 1314a9f8cf6e48c7b3f99797bcdc46af46ec969c Mon Sep 17 00:00:00 2001 From: liuning Date: Mon, 7 Aug 2023 14:40:29 +0800 Subject: [PATCH 18/71] esp_wifi: support connectionless manually pwr mgmt --- components/esp_wifi/include/esp_wifi.h | 26 ++++++++++++++++++++++++++ components/esp_wifi/lib | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 3df8585aed2..4a233406e59 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -1271,6 +1271,32 @@ esp_err_t esp_wifi_config_11b_rate(wifi_interface_t ifx, bool disable); */ esp_err_t esp_wifi_connectionless_module_set_wake_interval(uint16_t wake_interval); +/** + * @brief Request extra reference of Wi-Fi radio. + * Wi-Fi keep active state(RF opened) to be able to receive packets. + * + * @attention Please pair the use of `esp_wifi_force_wakeup_acquire` with `esp_wifi_force_wakeup_release`. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start + */ +esp_err_t esp_wifi_force_wakeup_acquire(void); + +/** + * @brief Release extra reference of Wi-Fi radio. + * Wi-Fi go to sleep state(RF closed) if no more use of radio. + * + * @attention Please pair the use of `esp_wifi_force_wakeup_acquire` with `esp_wifi_force_wakeup_release`. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start + */ +esp_err_t esp_wifi_force_wakeup_release(void); + /** * @brief configure country * diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index b74ee016063..d5352da6c4f 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit b74ee0160632978f0e36763f55be0ea6ee18f0c8 +Subproject commit d5352da6c4f6e5d460a8f5af957b4e47420e7782 From e2906504fbc20c64c27276d7c67165915236605c Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Fri, 15 Sep 2023 15:36:33 +0530 Subject: [PATCH 19/71] docs: Update maximum stack frames during heap memory debugging --- docs/en/api-reference/system/heap_debug.rst | 2 +- docs/zh_CN/api-reference/system/heap_debug.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/api-reference/system/heap_debug.rst b/docs/en/api-reference/system/heap_debug.rst index feb683b7605..4a4517a7d61 100644 --- a/docs/en/api-reference/system/heap_debug.rst +++ b/docs/en/api-reference/system/heap_debug.rst @@ -298,7 +298,7 @@ In ``HEAP_TRACE_LEAKS`` mode, for each traced memory allocation that has not alr .. only:: not CONFIG_IDF_TARGET_ARCH_RISCV - The depth of the call stack recorded for each trace entry can be configured in the project configuration menu, under ``Heap Memory Debugging`` > ``Enable heap tracing`` > ``Heap tracing stack depth``. Up to 10 stack frames can be recorded for each allocation (the default is 2). Each additional stack frame increases the memory usage of each ``heap_trace_record_t`` record by eight bytes. + The depth of the call stack recorded for each trace entry can be configured in the project configuration menu, under ``Heap Memory Debugging`` > ``Enable heap tracing`` > :ref:`CONFIG_HEAP_TRACING_STACK_DEPTH`. Up to 32 stack frames can be recorded for each allocation (the default is 2). Each additional stack frame increases the memory usage of each ``heap_trace_record_t`` record by eight bytes. Finally, the total number of the 'leaked' bytes (bytes allocated but not freed while the trace is running) is printed together with the total number of allocations it represents. diff --git a/docs/zh_CN/api-reference/system/heap_debug.rst b/docs/zh_CN/api-reference/system/heap_debug.rst index 6dde7c7cfda..6f14173f1f6 100644 --- a/docs/zh_CN/api-reference/system/heap_debug.rst +++ b/docs/zh_CN/api-reference/system/heap_debug.rst @@ -298,7 +298,7 @@ ESP-IDF 集成了用于请求 :ref:`堆内存信息 `、:ref:` .. only:: not CONFIG_IDF_TARGET_ARCH_RISCV - 每个跟踪条目记录的调用栈深度可以在项目配置菜单下进行配置,选择 ``Heap Memory Debugging`` > ``Enable heap tracing`` > ``Heap tracing stack depth``。每个内存分配最多可以记录 10 个栈帧(默认为 2),每增加一个栈帧,每个 ``heap_trace_record_t`` 记录的内存使用量将增加 8 个字节。 + 每个跟踪条目记录的调用栈深度可以在项目配置菜单下进行配置,选择 ``Heap Memory Debugging`` > ``Enable heap tracing`` > :ref:`CONFIG_HEAP_TRACING_STACK_DEPTH`。每个内存分配最多可以记录 32 个栈帧(默认为 2),每增加一个栈帧,每个 ``heap_trace_record_t`` 记录的内存使用量将增加 8 个字节。 最后,将打印“泄漏”的总字节数(即在跟踪期间分配但未释放的总字节数),以及它所代表的总分配次数。 From b15712025cf9cf3dab17e5f750c7470a26364f05 Mon Sep 17 00:00:00 2001 From: LiPeng Date: Fri, 15 Sep 2023 23:49:20 +0800 Subject: [PATCH 20/71] fix(vfs): Fix event_write may not exit critical section This commit fixes the event_write() function where the critical section was unbalanced. Merges https://github.com/espressif/esp-idf/pull/12258 --- components/vfs/vfs_eventfd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/vfs/vfs_eventfd.c b/components/vfs/vfs_eventfd.c index a4f088352b4..11ff2fb7e7c 100644 --- a/components/vfs/vfs_eventfd.c +++ b/components/vfs/vfs_eventfd.c @@ -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 */ @@ -267,14 +267,14 @@ static ssize_t event_write(int fd, const void *data, size_t size) s_events[fd].value += *val; ret = size; trigger_select_for_event(&s_events[fd]); - - if (s_events[fd].support_isr) { - portEXIT_CRITICAL(&s_events[fd].data_spin_lock); - } } else { errno = EBADF; ret = -1; } + + if (s_events[fd].support_isr) { + portEXIT_CRITICAL(&s_events[fd].data_spin_lock); + } _lock_release_recursive(&s_events[fd].lock); } return ret; From 287bdc5e61935bade4969b82017e9a484ab68711 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Wed, 6 Sep 2023 11:31:01 +0800 Subject: [PATCH 21/71] fix(test_apps): Trim builds of component test apps Some component test apps do not use the "set(COMPONENTS main)" command in their project level "CMakeLists.txt", thus leading to their builds pulling in all ESP-IDF components. This commit trims the build of multiple component test apps: - Add "set(COMPONENTS main ...)" to project level "CMakeLists.txt" - Add missing "PRIV_REQUIRES" in some "main" component "CMakeLists.txt" Also removed repeated configuraiton options in legacy_i2c_driver/sdkconfig.ci.defaults as they are already specified in legacy_i2c_driver/sdkconfig.defaults --- .../legacy_i2c_driver/CMakeLists.txt | 4 +++ .../legacy_i2c_driver/main/CMakeLists.txt | 1 + .../legacy_i2c_driver/sdkconfig.ci.defaults | 2 -- .../test_apps/dma/CMakeLists.txt | 5 ++++ .../test_apps/dma/main/CMakeLists.txt | 1 + .../test_apps/etm/CMakeLists.txt | 5 ++++ .../test_apps/etm/main/CMakeLists.txt | 1 + .../test_apps/mspi/CMakeLists.txt | 5 ++++ .../test_apps/mspi/main/CMakeLists.txt | 1 + .../mspi_psram_with_dfs/CMakeLists.txt | 8 ++++++ .../mspi_psram_with_dfs/main/CMakeLists.txt | 1 + .../test_apps/i2c_lcd_legacy/CMakeLists.txt | 4 +++ .../i2c_lcd_legacy/main/CMakeLists.txt | 1 + components/esp_mm/test_apps/mm/CMakeLists.txt | 4 +++ .../esp_mm/test_apps/mmap_hw/CMakeLists.txt | 3 ++ .../test_app_esp_netif/CMakeLists.txt | 3 ++ .../test_app_vfs_l2tap/CMakeLists.txt | 3 ++ .../esp_psram/test_apps/psram/CMakeLists.txt | 4 +++ .../test_apps/psram/main/CMakeLists.txt | 1 + .../test_apps/wifi_connect/CMakeLists.txt | 3 ++ .../test_apps/wifi_function/CMakeLists.txt | 3 ++ .../test_apps/freertos/CMakeLists.txt | 28 +++++++++---------- .../test_apps/freertos/main/CMakeLists.txt | 3 +- .../test_apps/freertos/misc/CMakeLists.txt | 2 +- .../freertos/performance/CMakeLists.txt | 2 +- .../test_apps/freertos/port/CMakeLists.txt | 2 +- .../test_apps/test_ieee802154/CMakeLists.txt | 4 +++ .../test_ieee802154/main/CMakeLists.txt | 1 + .../test_apps/esp_flash/CMakeLists.txt | 4 +++ .../test_apps/esp_flash/main/CMakeLists.txt | 1 + .../test_apps/esp_flash_stress/CMakeLists.txt | 4 +++ .../test_apps/flash_encryption/CMakeLists.txt | 5 ++++ .../flash_encryption/main/CMakeLists.txt | 1 + .../test_apps/flash_mmap/CMakeLists.txt | 4 +++ .../test_apps/flash_mmap/main/CMakeLists.txt | 1 + .../test_apps/flash_suspend/CMakeLists.txt | 3 ++ .../flash_suspend/main/CMakeLists.txt | 1 + .../test_apps/mspi_test/CMakeLists.txt | 4 +++ .../test_apps/mspi_test/main/CMakeLists.txt | 1 + .../ulp/test_apps/lp_core/CMakeLists.txt | 3 ++ .../ulp/test_apps/ulp_riscv/CMakeLists.txt | 3 ++ components/usb/test_apps/hcd/CMakeLists.txt | 5 ++++ .../usb/test_apps/usb_host/CMakeLists.txt | 5 ++++ 43 files changed, 130 insertions(+), 20 deletions(-) diff --git a/components/driver/test_apps/legacy_i2c_driver/CMakeLists.txt b/components/driver/test_apps/legacy_i2c_driver/CMakeLists.txt index 1864548037b..7f6a4ab7bc6 100644 --- a/components/driver/test_apps/legacy_i2c_driver/CMakeLists.txt +++ b/components/driver/test_apps/legacy_i2c_driver/CMakeLists.txt @@ -5,6 +5,10 @@ set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components" ) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_pm +# as we set CONFIG_PM_... options. +set(COMPONENTS main esp_pm) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(legacy_i2c_test) diff --git a/components/driver/test_apps/legacy_i2c_driver/main/CMakeLists.txt b/components/driver/test_apps/legacy_i2c_driver/main/CMakeLists.txt index 23741b95bc2..008413a5677 100644 --- a/components/driver/test_apps/legacy_i2c_driver/main/CMakeLists.txt +++ b/components/driver/test_apps/legacy_i2c_driver/main/CMakeLists.txt @@ -3,4 +3,5 @@ set(srcs "test_app_main.c" ) idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity test_utils driver WHOLE_ARCHIVE) diff --git a/components/driver/test_apps/legacy_i2c_driver/sdkconfig.ci.defaults b/components/driver/test_apps/legacy_i2c_driver/sdkconfig.ci.defaults index b308cb2ddda..e69de29bb2d 100644 --- a/components/driver/test_apps/legacy_i2c_driver/sdkconfig.ci.defaults +++ b/components/driver/test_apps/legacy_i2c_driver/sdkconfig.ci.defaults @@ -1,2 +0,0 @@ -CONFIG_FREERTOS_HZ=1000 -CONFIG_ESP_TASK_WDT=n diff --git a/components/esp_hw_support/test_apps/dma/CMakeLists.txt b/components/esp_hw_support/test_apps/dma/CMakeLists.txt index e87048a2116..42e63786a1c 100644 --- a/components/esp_hw_support/test_apps/dma/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/dma/CMakeLists.txt @@ -2,4 +2,9 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram +# as we set CONFIG_SPIRAM_... options. +set(COMPONENTS main esp_psram) + project(dma_test) diff --git a/components/esp_hw_support/test_apps/dma/main/CMakeLists.txt b/components/esp_hw_support/test_apps/dma/main/CMakeLists.txt index 0fb8a69f509..4088442971e 100644 --- a/components/esp_hw_support/test_apps/dma/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/dma/main/CMakeLists.txt @@ -11,4 +11,5 @@ endif() # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity WHOLE_ARCHIVE) diff --git a/components/esp_hw_support/test_apps/etm/CMakeLists.txt b/components/esp_hw_support/test_apps/etm/CMakeLists.txt index d5c75a52b3a..0d009db6795 100644 --- a/components/esp_hw_support/test_apps/etm/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/etm/CMakeLists.txt @@ -2,4 +2,9 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_pm +# as we set CONFIG_PM_... options. +set(COMPONENTS main esp_pm) + project(etm_test) diff --git a/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt b/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt index e824508d65e..14c910836c8 100644 --- a/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt @@ -24,4 +24,5 @@ endif() # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity esp_timer driver WHOLE_ARCHIVE) diff --git a/components/esp_hw_support/test_apps/mspi/CMakeLists.txt b/components/esp_hw_support/test_apps/mspi/CMakeLists.txt index ecada2191fe..af6aff96e79 100644 --- a/components/esp_hw_support/test_apps/mspi/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/mspi/CMakeLists.txt @@ -2,4 +2,9 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram +# as we set CONFIG_SPIRAM_... options. +set(COMPONENTS main esp_psram) + project(mspi_test_app) diff --git a/components/esp_hw_support/test_apps/mspi/main/CMakeLists.txt b/components/esp_hw_support/test_apps/mspi/main/CMakeLists.txt index 8d30280ddbb..f2dc595cbc6 100644 --- a/components/esp_hw_support/test_apps/mspi/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/mspi/main/CMakeLists.txt @@ -7,4 +7,5 @@ set(srcs # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity esp_timer spi_flash esp_partition WHOLE_ARCHIVE) diff --git a/components/esp_hw_support/test_apps/mspi_psram_with_dfs/CMakeLists.txt b/components/esp_hw_support/test_apps/mspi_psram_with_dfs/CMakeLists.txt index 493e4aa2edd..75826523ecf 100644 --- a/components/esp_hw_support/test_apps/mspi_psram_with_dfs/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/mspi_psram_with_dfs/CMakeLists.txt @@ -2,4 +2,12 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +list(APPEND EXTRA_COMPONENT_DIRS + "$ENV{IDF_PATH}/tools/unit-test-app/components") # For test_utils component + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on +# esptool_py and esp_psram as we set CONFIG_ESPTOOLPY_... and CONFIG_SPIRAM_... options. +set(COMPONENTS main esptool_py esp_psram) + project(mspi_psram_test_app) diff --git a/components/esp_hw_support/test_apps/mspi_psram_with_dfs/main/CMakeLists.txt b/components/esp_hw_support/test_apps/mspi_psram_with_dfs/main/CMakeLists.txt index a26b8b7aee6..1136a2b2378 100644 --- a/components/esp_hw_support/test_apps/mspi_psram_with_dfs/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/mspi_psram_with_dfs/main/CMakeLists.txt @@ -6,4 +6,5 @@ set(srcs # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity test_utils spi_flash esp_partition esp_pm WHOLE_ARCHIVE) diff --git a/components/esp_lcd/test_apps/i2c_lcd_legacy/CMakeLists.txt b/components/esp_lcd/test_apps/i2c_lcd_legacy/CMakeLists.txt index 9c62f764dc1..8c099ff31c5 100644 --- a/components/esp_lcd/test_apps/i2c_lcd_legacy/CMakeLists.txt +++ b/components/esp_lcd/test_apps/i2c_lcd_legacy/CMakeLists.txt @@ -2,4 +2,8 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + project(legacy_i2c_lcd_panel_test) diff --git a/components/esp_lcd/test_apps/i2c_lcd_legacy/main/CMakeLists.txt b/components/esp_lcd/test_apps/i2c_lcd_legacy/main/CMakeLists.txt index b969d9dbf92..a168fe90a07 100644 --- a/components/esp_lcd/test_apps/i2c_lcd_legacy/main/CMakeLists.txt +++ b/components/esp_lcd/test_apps/i2c_lcd_legacy/main/CMakeLists.txt @@ -4,4 +4,5 @@ set(srcs "test_app_main.c" # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity driver esp_lcd WHOLE_ARCHIVE) diff --git a/components/esp_mm/test_apps/mm/CMakeLists.txt b/components/esp_mm/test_apps/mm/CMakeLists.txt index e349686fc1f..3e976ca666d 100644 --- a/components/esp_mm/test_apps/mm/CMakeLists.txt +++ b/components/esp_mm/test_apps/mm/CMakeLists.txt @@ -3,6 +3,10 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/components/esp_mm/test_apps/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram +# as we set CONFIG_SPIRAM_... options. +set(COMPONENTS main esp_psram) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mm_test) diff --git a/components/esp_mm/test_apps/mmap_hw/CMakeLists.txt b/components/esp_mm/test_apps/mmap_hw/CMakeLists.txt index d1e1dbc25f5..fac8366284b 100644 --- a/components/esp_mm/test_apps/mmap_hw/CMakeLists.txt +++ b/components/esp_mm/test_apps/mmap_hw/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mmap_hw_test) diff --git a/components/esp_netif/test_apps/test_app_esp_netif/CMakeLists.txt b/components/esp_netif/test_apps/test_app_esp_netif/CMakeLists.txt index ff3764931cc..c90b2d947cf 100644 --- a/components/esp_netif/test_apps/test_app_esp_netif/CMakeLists.txt +++ b/components/esp_netif/test_apps/test_app_esp_netif/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(esp_netif_test) diff --git a/components/esp_netif/test_apps/test_app_vfs_l2tap/CMakeLists.txt b/components/esp_netif/test_apps/test_app_vfs_l2tap/CMakeLists.txt index 859cfa803c9..e046158b431 100644 --- a/components/esp_netif/test_apps/test_app_vfs_l2tap/CMakeLists.txt +++ b/components/esp_netif/test_apps/test_app_vfs_l2tap/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(esp_vfs_l2tap_test) diff --git a/components/esp_psram/test_apps/psram/CMakeLists.txt b/components/esp_psram/test_apps/psram/CMakeLists.txt index 1cfb1964109..f358f3276df 100644 --- a/components/esp_psram/test_apps/psram/CMakeLists.txt +++ b/components/esp_psram/test_apps/psram/CMakeLists.txt @@ -2,4 +2,8 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + project(psram_test) diff --git a/components/esp_psram/test_apps/psram/main/CMakeLists.txt b/components/esp_psram/test_apps/psram/main/CMakeLists.txt index f00ce1a11c2..d19067a3854 100644 --- a/components/esp_psram/test_apps/psram/main/CMakeLists.txt +++ b/components/esp_psram/test_apps/psram/main/CMakeLists.txt @@ -10,4 +10,5 @@ endif() # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity esp_psram spi_flash driver esp_partition WHOLE_ARCHIVE) diff --git a/components/esp_wifi/test_apps/wifi_connect/CMakeLists.txt b/components/esp_wifi/test_apps/wifi_connect/CMakeLists.txt index cf8c41f302c..4d7035c22bc 100644 --- a/components/esp_wifi/test_apps/wifi_connect/CMakeLists.txt +++ b/components/esp_wifi/test_apps/wifi_connect/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) if($ENV{CI_PIPELINE_ID}) diff --git a/components/esp_wifi/test_apps/wifi_function/CMakeLists.txt b/components/esp_wifi/test_apps/wifi_function/CMakeLists.txt index 7f6e55fa727..1707a7102cc 100644 --- a/components/esp_wifi/test_apps/wifi_function/CMakeLists.txt +++ b/components/esp_wifi/test_apps/wifi_function/CMakeLists.txt @@ -3,5 +3,8 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(wifi_test) diff --git a/components/freertos/test_apps/freertos/CMakeLists.txt b/components/freertos/test_apps/freertos/CMakeLists.txt index 3d41d57ac1e..02b26ae0acd 100644 --- a/components/freertos/test_apps/freertos/CMakeLists.txt +++ b/components/freertos/test_apps/freertos/CMakeLists.txt @@ -1,21 +1,21 @@ # This is the project CMakeLists.txt file for the test subproject cmake_minimum_required(VERSION 3.16) -# FreeRTOS tests of different types (e.g., kernel, port, performance etc.)are -# split into different directores in the test app's root directory. Each test -# type is treated as separate component -set(test_types - "kernel" - "misc" - "performance" - "port") +include($ENV{IDF_PATH}/tools/cmake/project.cmake) -list(APPEND EXTRA_COMPONENT_DIRS - ${test_types} # Add each test type as a component - "$ENV{IDF_PATH}/tools/unit-test-app/components") # For test_utils component +# Set extra component directories for +# - test_utils component +# - the different test types (e.g., kernel, port, performance, ...) that are organized as components +set(EXTRA_COMPONENT_DIRS + "$ENV{IDF_PATH}/tools/unit-test-app/components" + "./kernel" + "./misc" + "./performance" + "./port" +) -#"Trim" the build. Include the minimal set of components, main, and anything it depends on. -set(COMPONENTS main esp_psram ${test_types}) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram +# as we enable CONFIG_SPIRAM_... options. +set(COMPONENTS main esp_psram) -include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(freertos_test) diff --git a/components/freertos/test_apps/freertos/main/CMakeLists.txt b/components/freertos/test_apps/freertos/main/CMakeLists.txt index 0d8828ca143..f73b1906dbb 100644 --- a/components/freertos/test_apps/freertos/main/CMakeLists.txt +++ b/components/freertos/test_apps/freertos/main/CMakeLists.txt @@ -1,2 +1,3 @@ idf_component_register(SRCS "test_freertos_main.c" - PRIV_REQUIRES unity test_utils driver) + # Pull in the components containing each type of FreeRTOS test + PRIV_REQUIRES unity test_utils kernel misc performance port) diff --git a/components/freertos/test_apps/freertos/misc/CMakeLists.txt b/components/freertos/test_apps/freertos/misc/CMakeLists.txt index cb1b5fdeb84..40bb3aa087e 100644 --- a/components/freertos/test_apps/freertos/misc/CMakeLists.txt +++ b/components/freertos/test_apps/freertos/misc/CMakeLists.txt @@ -3,5 +3,5 @@ # In order for the cases defined by `TEST_CASE` in "misc" to be linked into # the final elf, the component can be registered as WHOLE_ARCHIVE idf_component_register(SRC_DIRS "." - PRIV_REQUIRES test_utils + PRIV_REQUIRES unity test_utils WHOLE_ARCHIVE) diff --git a/components/freertos/test_apps/freertos/performance/CMakeLists.txt b/components/freertos/test_apps/freertos/performance/CMakeLists.txt index 2fc8feb7395..d7be03bc1b3 100644 --- a/components/freertos/test_apps/freertos/performance/CMakeLists.txt +++ b/components/freertos/test_apps/freertos/performance/CMakeLists.txt @@ -3,5 +3,5 @@ # In order for the cases defined by `TEST_CASE` in "performance" to be linked into # the final elf, the component can be registered as WHOLE_ARCHIVE idf_component_register(SRC_DIRS "." - PRIV_REQUIRES test_utils + PRIV_REQUIRES unity test_utils WHOLE_ARCHIVE) diff --git a/components/freertos/test_apps/freertos/port/CMakeLists.txt b/components/freertos/test_apps/freertos/port/CMakeLists.txt index 04522f2caf7..6eb7eb8d09b 100644 --- a/components/freertos/test_apps/freertos/port/CMakeLists.txt +++ b/components/freertos/test_apps/freertos/port/CMakeLists.txt @@ -3,5 +3,5 @@ # In order for the cases defined by `TEST_CASE` in "port" to be linked into # the final elf, the component can be registered as WHOLE_ARCHIVE idf_component_register(SRC_DIRS "." - PRIV_REQUIRES test_utils + PRIV_REQUIRES unity test_utils WHOLE_ARCHIVE) diff --git a/components/ieee802154/test_apps/test_ieee802154/CMakeLists.txt b/components/ieee802154/test_apps/test_ieee802154/CMakeLists.txt index 6f32785a15e..b7ca706cb4c 100644 --- a/components/ieee802154/test_apps/test_ieee802154/CMakeLists.txt +++ b/components/ieee802154/test_apps/test_ieee802154/CMakeLists.txt @@ -2,4 +2,8 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + project(test_ieee802154) diff --git a/components/ieee802154/test_apps/test_ieee802154/main/CMakeLists.txt b/components/ieee802154/test_apps/test_ieee802154/main/CMakeLists.txt index d0a58e94a05..625a6175c9e 100644 --- a/components/ieee802154/test_apps/test_ieee802154/main/CMakeLists.txt +++ b/components/ieee802154/test_apps/test_ieee802154/main/CMakeLists.txt @@ -8,4 +8,5 @@ set(include "." # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} INCLUDE_DIRS include + PRIV_REQUIRES ieee802154 console fatfs nvs_flash esp_phy WHOLE_ARCHIVE) diff --git a/components/spi_flash/test_apps/esp_flash/CMakeLists.txt b/components/spi_flash/test_apps/esp_flash/CMakeLists.txt index b18abb0cd0a..91389d9e265 100644 --- a/components/spi_flash/test_apps/esp_flash/CMakeLists.txt +++ b/components/spi_flash/test_apps/esp_flash/CMakeLists.txt @@ -3,6 +3,10 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on +# esptool_py as we set CONFIG_ESPTOOLPY_... options. +set(COMPONENTS main esptool_py) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(test_esp_flash_drv) diff --git a/components/spi_flash/test_apps/esp_flash/main/CMakeLists.txt b/components/spi_flash/test_apps/esp_flash/main/CMakeLists.txt index f5377211c60..9e4bf2b0153 100644 --- a/components/spi_flash/test_apps/esp_flash/main/CMakeLists.txt +++ b/components/spi_flash/test_apps/esp_flash/main/CMakeLists.txt @@ -5,4 +5,5 @@ set(srcs "test_app_main.c" # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity test_utils spi_flash esp_timer driver bootloader_support WHOLE_ARCHIVE) diff --git a/components/spi_flash/test_apps/esp_flash_stress/CMakeLists.txt b/components/spi_flash/test_apps/esp_flash_stress/CMakeLists.txt index e5572915823..b650bb10c9c 100644 --- a/components/spi_flash/test_apps/esp_flash_stress/CMakeLists.txt +++ b/components/spi_flash/test_apps/esp_flash_stress/CMakeLists.txt @@ -3,6 +3,10 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/components/spi_flash/test_apps/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram +# and esptool_py as we set CONFIG_SPIRAM_... and CONFIG_ESPTOOLPY_... options. +set(COMPONENTS main esp_psram esptool_py) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(test_esp_flash_stress) diff --git a/components/spi_flash/test_apps/flash_encryption/CMakeLists.txt b/components/spi_flash/test_apps/flash_encryption/CMakeLists.txt index 6f1f0178937..941d38b996d 100644 --- a/components/spi_flash/test_apps/flash_encryption/CMakeLists.txt +++ b/components/spi_flash/test_apps/flash_encryption/CMakeLists.txt @@ -2,4 +2,9 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram +# and esptool_py as we set CONFIG_SPIRAM_... and CONFIG_ESPTOOLPY_... options. +set(COMPONENTS main esp_psram esptool_py) + project(test_flash_encryption) diff --git a/components/spi_flash/test_apps/flash_encryption/main/CMakeLists.txt b/components/spi_flash/test_apps/flash_encryption/main/CMakeLists.txt index df989b72747..491d7e107de 100644 --- a/components/spi_flash/test_apps/flash_encryption/main/CMakeLists.txt +++ b/components/spi_flash/test_apps/flash_encryption/main/CMakeLists.txt @@ -2,5 +2,6 @@ set(srcs "test_app_main.c" "test_flash_encryption.c") idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity spi_flash bootloader_support esp_partition WHOLE_ARCHIVE) target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/spi_flash/test_apps/flash_mmap/CMakeLists.txt b/components/spi_flash/test_apps/flash_mmap/CMakeLists.txt index 0bd6bf58022..716f502a832 100644 --- a/components/spi_flash/test_apps/flash_mmap/CMakeLists.txt +++ b/components/spi_flash/test_apps/flash_mmap/CMakeLists.txt @@ -3,5 +3,9 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram +# as we set CONFIG_SPIRAM_... options. +set(COMPONENTS main esp_psram) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(test_flash_mmap) diff --git a/components/spi_flash/test_apps/flash_mmap/main/CMakeLists.txt b/components/spi_flash/test_apps/flash_mmap/main/CMakeLists.txt index c75f516f7c4..903367c6e10 100644 --- a/components/spi_flash/test_apps/flash_mmap/main/CMakeLists.txt +++ b/components/spi_flash/test_apps/flash_mmap/main/CMakeLists.txt @@ -4,4 +4,5 @@ set(srcs "test_app_main.c" # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity test_utils spi_flash bootloader_support esp_partition WHOLE_ARCHIVE) diff --git a/components/spi_flash/test_apps/flash_suspend/CMakeLists.txt b/components/spi_flash/test_apps/flash_suspend/CMakeLists.txt index 46da0ba372b..03504ecd6a2 100644 --- a/components/spi_flash/test_apps/flash_suspend/CMakeLists.txt +++ b/components/spi_flash/test_apps/flash_suspend/CMakeLists.txt @@ -3,5 +3,8 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(test_flash_suspend) diff --git a/components/spi_flash/test_apps/flash_suspend/main/CMakeLists.txt b/components/spi_flash/test_apps/flash_suspend/main/CMakeLists.txt index e017e8371ec..3423bf3e020 100644 --- a/components/spi_flash/test_apps/flash_suspend/main/CMakeLists.txt +++ b/components/spi_flash/test_apps/flash_suspend/main/CMakeLists.txt @@ -4,4 +4,5 @@ set(srcs "test_app_main.c" # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity test_utils spi_flash driver esp_partition WHOLE_ARCHIVE) diff --git a/components/spi_flash/test_apps/mspi_test/CMakeLists.txt b/components/spi_flash/test_apps/mspi_test/CMakeLists.txt index be1acb2a34d..4f170010954 100644 --- a/components/spi_flash/test_apps/mspi_test/CMakeLists.txt +++ b/components/spi_flash/test_apps/mspi_test/CMakeLists.txt @@ -1,6 +1,10 @@ # This is the project CMakeLists.txt file for the test subproject cmake_minimum_required(VERSION 3.16) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. We also depend on esp_psram +# as we set CONFIG_SPIRAM_... options. +set(COMPONENTS main esp_psram) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mspi_test) diff --git a/components/spi_flash/test_apps/mspi_test/main/CMakeLists.txt b/components/spi_flash/test_apps/mspi_test/main/CMakeLists.txt index cfbf0f1b399..4e1e8bed59c 100644 --- a/components/spi_flash/test_apps/mspi_test/main/CMakeLists.txt +++ b/components/spi_flash/test_apps/mspi_test/main/CMakeLists.txt @@ -5,4 +5,5 @@ set(srcs "test_cache_disabled.c" "test_app_main.c") idf_component_register(SRCS ${srcs} + PRIV_REQUIRES unity spi_flash driver esp_partition bootloader_support app_update WHOLE_ARCHIVE) diff --git a/components/ulp/test_apps/lp_core/CMakeLists.txt b/components/ulp/test_apps/lp_core/CMakeLists.txt index 2a29e3574d3..5a16c97e491 100644 --- a/components/ulp/test_apps/lp_core/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/CMakeLists.txt @@ -7,5 +7,8 @@ set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components" ) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(lp_core_test) diff --git a/components/ulp/test_apps/ulp_riscv/CMakeLists.txt b/components/ulp/test_apps/ulp_riscv/CMakeLists.txt index eba0bce5584..a01a1701205 100644 --- a/components/ulp/test_apps/ulp_riscv/CMakeLists.txt +++ b/components/ulp/test_apps/ulp_riscv/CMakeLists.txt @@ -3,5 +3,8 @@ cmake_minimum_required(VERSION 3.16) list(PREPEND SDKCONFIG_DEFAULTS "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" "sdkconfig.defaults") +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ulp_riscv_test) diff --git a/components/usb/test_apps/hcd/CMakeLists.txt b/components/usb/test_apps/hcd/CMakeLists.txt index e0c09e31132..3294266f463 100644 --- a/components/usb/test_apps/hcd/CMakeLists.txt +++ b/components/usb/test_apps/hcd/CMakeLists.txt @@ -2,5 +2,10 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + set(EXTRA_COMPONENT_DIRS "../common") + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + project(test_app_usb_host) diff --git a/components/usb/test_apps/usb_host/CMakeLists.txt b/components/usb/test_apps/usb_host/CMakeLists.txt index e0c09e31132..3294266f463 100644 --- a/components/usb/test_apps/usb_host/CMakeLists.txt +++ b/components/usb/test_apps/usb_host/CMakeLists.txt @@ -2,5 +2,10 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + set(EXTRA_COMPONENT_DIRS "../common") + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + project(test_app_usb_host) From 0bea98c10363c3004f338c19397b8ade6347f8cd Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Thu, 31 Aug 2023 12:01:51 +0800 Subject: [PATCH 22/71] refactor(unity): improved unity task deletion function --- components/unity/unity_utils_freertos.c | 33 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/components/unity/unity_utils_freertos.c b/components/unity/unity_utils_freertos.c index a9616e46b2a..26155a2ca99 100644 --- a/components/unity/unity_utils_freertos.c +++ b/components/unity/unity_utils_freertos.c @@ -5,9 +5,12 @@ */ #include +#include #include "unity.h" #include "unity_test_utils.h" +#include "freertos/FreeRTOS.h" #include "freertos/semphr.h" +#include "freertos/task.h" #include "sdkconfig.h" #if !CONFIG_FREERTOS_UNICORE #include "esp_ipc.h" @@ -15,12 +18,13 @@ #endif #if !CONFIG_FREERTOS_UNICORE -static SemaphoreHandle_t test_sem; +static StaticSemaphore_t s_test_sem_buffer; +static SemaphoreHandle_t s_test_sem = NULL; static bool idle_hook_func(void) { - if (test_sem) { - xSemaphoreGive(test_sem); + if (s_test_sem) { + xSemaphoreGive(s_test_sem); } return true; } @@ -29,6 +33,10 @@ static void task_delete_func(void *arg) { vTaskDelete(arg); } + +#define SEMAPHORE_COUNT_MAX 2 +#define SEMAPHORE_COUNT_INITIAL 0 + #endif // !CONFIG_FREERTOS_UNICORE void unity_utils_task_delete(TaskHandle_t thandle) @@ -47,16 +55,25 @@ void unity_utils_task_delete(TaskHandle_t thandle) printf("Task_affinity: 0x%x, current_core: %d\n", tsk_affinity, core_id); if (tsk_affinity == tskNO_AFFINITY) { + // create the semaphore if not done yet, or else, make sure its count is 0 + if (s_test_sem == NULL) { + s_test_sem = xSemaphoreCreateCountingStatic(SEMAPHORE_COUNT_MAX, SEMAPHORE_COUNT_INITIAL, &s_test_sem_buffer); + } else { + while (xSemaphoreTake(s_test_sem, 0) == pdTRUE) { } + } + /* For no affinity case, we wait for idle hook to trigger on different core */ esp_err_t ret = esp_register_freertos_idle_hook_for_cpu(idle_hook_func, !core_id); TEST_ASSERT_EQUAL_MESSAGE(ret, ESP_OK, "unity_utils_task_delete: failed to register idle hook"); vTaskDelete(thandle); - test_sem = xSemaphoreCreateBinary(); - TEST_ASSERT_NOT_NULL_MESSAGE(test_sem, "unity_utils_task_delete: failed to create semaphore"); - xSemaphoreTake(test_sem, portMAX_DELAY); + + // We want to make sure that the entire idle task has run (including the part that removes remaining + // memory of deleted tasks). Since we don't know where the idle task has been stopped, we need to + // wait until the idle hook has run twice. This makes sure that the entire idle task has run at least once. + xSemaphoreTake(s_test_sem, portMAX_DELAY); + xSemaphoreTake(s_test_sem, portMAX_DELAY); + esp_deregister_freertos_idle_hook_for_cpu(idle_hook_func, !core_id); - vSemaphoreDelete(test_sem); - test_sem = NULL; } else if (tsk_affinity != core_id) { /* Task affinity and current core are differnt, schedule IPC call (to delete task) * on core where task is pinned to */ From ab695813182f652bcdaba0f99bc86241c28f595d Mon Sep 17 00:00:00 2001 From: renpeiying Date: Wed, 16 Aug 2023 16:47:43 +0800 Subject: [PATCH 23/71] docs: Provide Chinese translation for /protocols/esp_spi_slave_protocol.rst --- .../protocols/esp_spi_slave_protocol.rst | 28 ++-- .../protocols/esp_spi_slave_protocol.rst | 151 +++++++++++++++++- 2 files changed, 165 insertions(+), 14 deletions(-) diff --git a/docs/en/api-reference/protocols/esp_spi_slave_protocol.rst b/docs/en/api-reference/protocols/esp_spi_slave_protocol.rst index 52a35649fcc..f2695674017 100644 --- a/docs/en/api-reference/protocols/esp_spi_slave_protocol.rst +++ b/docs/en/api-reference/protocols/esp_spi_slave_protocol.rst @@ -1,11 +1,13 @@ ESP SPI Slave HD (Half Duplex) Mode Protocol ============================================ +:link_to_translation:`zh_CN:[中文]` + .. only:: esp32 .. warning:: - The driver for ESP32 has not been developed yet. + ESP32 does not support this feature. .. _esp_spi_slave_caps: @@ -31,7 +33,7 @@ SPI Slave Capabilities of Espressif Chips Introduction ------------ -In the half duplex mode, the master has to use the protocol defined by the slave to communicate with the slave. Each transaction may consist of the following phases (list by the order they should exist): +In the half duplex mode, the master has to use the protocol defined by the slave to communicate with the slave. Each transaction may consist of the following phases (listed by the order they should exist): - Command: 8-bit, master to slave @@ -39,7 +41,7 @@ In the half duplex mode, the master has to use the protocol defined by the slave - Address: 8-bit, master to slave, optional - For some commands (WRBUF, RDBUF), this phase specifies the address of the shared buffer to write to/read from. For other commands with this phase, they are meaningless but still have to exist in the transaction. + For some commands (WRBUF, RDBUF), this phase specifies the address of the shared register to write to/read from. For other commands with this phase, they are meaningless but still have to exist in the transaction. - Dummy: 8-bit, floating, optional @@ -54,10 +56,10 @@ The **direction** means which side (master or slave) controls the MOSI, MISO, WP Data IO Modes ------------- -In some IO modes, more data wires can be used to send the data. As a result, the SPI clock cycles required for the same amount of data will be less than in the 1-bit mode. For example, in QIO mode, address and data (IN and OUT) should be sent on all 4 data wires (MOSI, MISO, WP, and HD). Here are the modes supported by the ESP32-S2 SPI slave and the wire number used in corresponding modes. +In some IO modes, more data wires can be used to send the data. As a result, the SPI clock cycles required for the same amount of data will be less than in the 1-bit mode. For example, in QIO mode, address and data (IN and OUT) should be sent on all 4 data wires (MOSI, MISO, WP, and HD). Here are the modes supported by the ESP32-S2 SPI slave and the wire number (WN) used in corresponding modes. +-------+------------+------------+--------------+---------+ -| Mode | command WN | address WN | dummy cycles | data WN | +| Mode | Command WN | Address WN | Dummy cycles | Data WN | +=======+============+============+==============+=========+ | 1-bit | 1 | 1 | 1 | 1 | +-------+------------+------------+--------------+---------+ @@ -113,7 +115,7 @@ Supported Commands | EXQPI | Exit QPI mode | 0xDD | - | - | +----------+---------------------+---------+----------+----------------------------------------------------------+ -Moreover, WRBUF, RDBUF, WRDMA, RDDMA commands have their 2-bit and 4-bit version. To do transactions in 2-bit or 4-bit mode, send the original command ORed by the corresponding command mask below. For example, command 0xA1 means WRBUF in QIO mode. +Moreover, WRBUF, RDBUF, WRDMA, and RDDMA commands have their 2-bit and 4-bit version. To do transactions in 2-bit or 4-bit mode, send the original command ORed by the corresponding command mask below. For example, command 0xA1 means WRBUF in QIO mode. +-------+------+ | Mode | Mask | @@ -134,15 +136,15 @@ Moreover, WRBUF, RDBUF, WRDMA, RDDMA commands have their 2-bit and 4-bit version Segment Transaction Mode ------------------------ -Segment transaction mode is the only mode supported by the SPI Slave HD driver for now. In this mode, for a transaction the slave load onto the DMA, the master is allowed to read or write in segments. This way the master does not have to prepare a large buffer as the size of data provided by the slave. After the master finishes reading/writing a buffer, it has to send the corresponding termination command to the slave as a synchronization signal. The slave driver will update new data (if exist) onto the DMA upon seeing the termination command. +Segment transaction mode is the only mode supported by the SPI Slave HD driver for now. In this mode, for a transaction the slave loads onto the DMA, the master is allowed to read or write in segments. In this way, the master does not have to prepare a large buffer as the size of data provided by the slave. After the master finishes reading/writing a buffer, it has to send the corresponding termination command to the slave as a synchronization signal. The slave driver will update new data (if exist) onto the DMA upon seeing the termination command. -The termination command is WR_DONE (0x07) for the WRDMA and CMD8 (0x08) for the RDDMA. +The termination command is WR_DONE (0x07) for WRDMA and CMD8 (0x08) for RDDMA. Here is an example for the flow the master read data from the slave DMA: -1. The slave loads 4092 bytes of data onto the RDDMA -2. The master do seven RDDMA transactions, each of them is 512 bytes long, and reads the first 3584 bytes from the slave +1. The slave loads 4092 bytes of data onto the RDDMA. +2. The master do seven RDDMA transactions, each of them is 512 bytes long, and reads the first 3584 bytes from the slave. 3. The master do the last RDDMA transaction of 512 bytes (equal, longer, or shorter than the total length loaded by the slave are all allowed). The first 508 bytes are valid data from the slave, while the last 4 bytes are meaningless bytes. -4. The master sends CMD8 to the slave -5. The slave loads another 4092 bytes of data onto the RDDMA -6. The master can start new reading transactions after it sends the CMD8 +4. The master sends CMD8 to the slave. +5. The slave loads another 4092 bytes of data onto the RDDMA. +6. The master can start new reading transactions after it sends the CMD8. diff --git a/docs/zh_CN/api-reference/protocols/esp_spi_slave_protocol.rst b/docs/zh_CN/api-reference/protocols/esp_spi_slave_protocol.rst index 9aac000d85e..eecb538da62 100644 --- a/docs/zh_CN/api-reference/protocols/esp_spi_slave_protocol.rst +++ b/docs/zh_CN/api-reference/protocols/esp_spi_slave_protocol.rst @@ -1 +1,150 @@ -.. include:: ../../../en/api-reference/protocols/esp_spi_slave_protocol.rst \ No newline at end of file +ESP SPI 从机 HD(半双工)模式协议 +========================================== + +:link_to_translation:`en:[English]` + +.. only:: esp32 + + .. warning:: + + ESP32 不支持此功能。 + +.. _esp_spi_slave_caps: + +乐鑫芯片的 SPI 从机功能支持概况 +--------------------------------- + ++-------------+-------+----------+----------+----------+----------+----------+----------+ +| | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | ESP32-C2 | ESP32-C6 | ESP32-H2 | ++-------------+-------+----------+----------+----------+----------+----------+----------+ +| SPI 从机 HD | N | Y (v2) | Y (v2) | Y (v2) | Y (v2) | Y (v2) | Y (v2) | ++-------------+-------+----------+----------+----------+----------+----------+----------+ +| Tohost intr | | N | N | N | N | N | N | ++-------------+-------+----------+----------+----------+----------+----------+----------+ +| Frhost intr | | 2 * | 2 * | 2 * | 2 * | 2 * | 2 * | ++-------------+-------+----------+----------+----------+----------+----------+----------+ +| TX DMA | | Y | Y | Y | Y | Y | Y | ++-------------+-------+----------+----------+----------+----------+----------+----------+ +| RX DMA | | Y | Y | Y | Y | Y | Y | ++-------------+-------+----------+----------+----------+----------+----------+----------+ +| 共享寄存器 | | 72 | 64 | 64 | 64 | 64 | 64 | ++-------------+-------+----------+----------+----------+----------+----------+----------+ + +概述 +---- + +在半双工模式下,主机须使用从机定义的协议与从机通信。每个传输事务按顺序可能包括以下阶段: + +- 命令阶段:8 位,主机到从机 + + 此阶段决定事务的其它阶段。参见 :ref:`spi_slave_hd_supported_cmds`。 + +- 地址阶段:8 位,主机到从机,可选 + + 对于某些命令 (如 WRBUF、RDBUF),此阶段指定要写入/读取的共享寄存器地址。对于其他包括此阶段的命令,这没有实际意义,但仍必须存在于事务中。 + +- Dummy 阶段:8 位,浮动,可选 + + 此阶段是主机和从机在总线上的周转时间,并为从机向主机发送数据提供了充分的准备时间。 + +- 数据阶段:长度可变,方向由命令确定。 + + 这一阶段可以输出数据(OUT,方向为由从机向主机),或者输入数据(IN,方向为由主机向从机)。 + +**方向** 是指哪一方(主机或从机)控制 MOSI、MISO、WP 和 HD 管脚。 + +数据 IO 模式 +------------- + +在某些 IO 模式下,可以使用更多数据线来发送数据。因此,与 1 位模式相比,发送相同数据量所需的 SPI 时钟周期更少。例如,在 QIO 模式下,地址和数据 (IN 和 OUT) 应发送到全部 4 条数据线上 (MOSI、MISO、WP 和 HD)。下表展示了 ESP32-S2 SPI 从机支持的模式,以及相应模式下使用的数据线数量。 + ++-------+----------+----------+------------+----------+ +| Mode | 命令线数 | 地址线数 | dummy 次数 | 数据线数 | ++-------+----------+----------+------------+----------+ +| 1-bit | 1 | 1 | 1 | 1 | ++-------+----------+----------+------------+----------+ +| DOUT | 1 | 1 | 4 | 2 | ++-------+----------+----------+------------+----------+ +| DIO | 1 | 2 | 4 | 2 | ++-------+----------+----------+------------+----------+ +| QOUT | 1 | 1 | 4 | 4 | ++-------+----------+----------+------------+----------+ +| QIO | 1 | 4 | 4 | 4 | ++-------+----------+----------+------------+----------+ +| QPI | 4 | 4 | 4 | 4 | ++-------+----------+----------+------------+----------+ + +除 QPI 模式外,使用哪种模式通常取决于主机发送的命令(请参考 :ref:`spi_slave_hd_supported_cmds`)。 + +QPI 模式 +^^^^^^^^ + +QPI 模式是 SPI 从机的一种特殊状态。主机可发送 ENQPI 命令,使从机进入 QPI 模式。在 QPI 模式下,命令以 4 位形式发送,因此与其他正常模式不兼容。只有在从机处于 QPI 模式时,主机才能发送 QPI 命令。主机可发送 EXQPI 命令退出 QPI 模式。 + +.. _spi_slave_hd_supported_cmds: + +支持的命令 +---------- + +.. note:: + 命令名称是从主机视角确定的。例如,WRBUF 表示由主机向从机的缓冲区写入。 + ++----------+---------------+------+----------+------------------------------+ +| 名称 | 描述 | 命令 | 地址 | 数据 | ++----------+---------------+------+----------+------------------------------+ +| WRBUF | 写入缓冲区 | 0x01 | Buf addr | 主到从,不超过缓冲区大小 | ++----------+---------------+------+----------+------------------------------+ +| RDBUF | 读取缓冲区 | 0x02 | Buf addr | 从到主,不超过缓冲区大小 | ++----------+---------------+------+----------+------------------------------+ +| WRDMA | 写入 DMA | 0x03 | 8 位 | 主到从,不超过从机提供的长度 | ++----------+---------------+------+----------+------------------------------+ +| RDDMA | 读取 DMA | 0x04 | 8 位 | 从到主,不超过从机提供的长度 | ++----------+---------------+------+----------+------------------------------+ +| SEG_DONE | 段完成 | 0x05 | - | - | ++----------+---------------+------+----------+------------------------------+ +| ENQPI | 进入 QPI 模式 | 0x06 | - | - | ++----------+---------------+------+----------+------------------------------+ +| WR_DONE | 写入段完成 | 0x07 | - | - | ++----------+---------------+------+----------+------------------------------+ +| CMD8 | 中断 | 0x08 | - | - | ++----------+---------------+------+----------+------------------------------+ +| CMD9 | 中断 | 0x09 | - | - | ++----------+---------------+------+----------+------------------------------+ +| CMDA | 中断 | 0x0A | - | - | ++----------+---------------+------+----------+------------------------------+ +| EXQPI | 退出 QPI 模式 | 0xDD | - | - | ++----------+---------------+------+----------+------------------------------+ + +此外,WRBUF、RDBUF、WRDMA 和 RDDMA 命令都有 2 位和 4 位版本。要在 2 位或 4 位模式下操作,请用下表中的对应命令掩码与原始命令按位或(bit OR)后发送。例如,命令 0xA1 表示 QIO 模式下的 WRBUF。 + ++-------+------+ +| 模式 | 掩码 | ++-------+------+ +| 1-bit | 0x00 | ++-------+------+ +| DOUT | 0x10 | ++-------+------+ +| DIO | 0x50 | ++-------+------+ +| QOUT | 0x20 | ++-------+------+ +| QIO | 0xA0 | ++-------+------+ +| QPI | 0xA0 | ++-------+------+ + +段事务模式 +------------------ + +目前,SPI 从机 HD 驱动程序仅支持段事务模式。在此模式下,对于从机加载到 DMA 的事务,主机可以分段读取或写入。这样,主机就无需准备与从机数据大小相同的大缓冲区。主机在一个缓冲区的读取/写入完成后,须向从机发送相应的终止命令作为同步信号。在从机收到终止命令后,从机驱动程序会将新数据(如有)更新到 DMA 上。 + +WRDMA 的终止命令是 WR_DONE (0x07),RDDMA 的终止命令是 CMD8 (0x08)。 + +以下是主机自从机 DMA 读取数据的流程示例: + +1. 从机将 4092 字节数据加载到 RDDMA。 +2. 主机进行七次 RDDMA 事务,每个事务长 512 字节,并自从机读取前 3584 字节。 +3. 主机进行最后一次 RDDMA 事务,长度为 512 字节(长度可以与从机相同、更长或更短)。前 508 字节是从机发送的有效数据,最后 4 字节无意义。 +4. 主机向从机发送 CMD8。 +5. 从机将其他的 4092 字节数据加载到 RDDMA。 +6. 主机发送 CMD8 后,可以开始新的读取事务。 From db64e51e53ebed338a63bcda4798d7e60402b4fd Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Fri, 15 Sep 2023 00:35:31 +0800 Subject: [PATCH 24/71] feat(freertos): Add SMP kernel changes to FreeRTOS v10.5.1 This commit adds the key kernel changes to the v10.5.1 kernel to support dual-core SMP. These changes are temporarily documented in the `idf_changes.md` document. This commit... - Added changes to kernel data structures to support multiple cores - Changes to scheduling algorithm support SMP scheduling. - Changes to each FreeRTOS function to support multiple cores and SMP scheduling algorithm. --- .../FreeRTOS-Kernel-V10.5.1/idf_changes.md | 116 +- .../include/freertos/FreeRTOS.h | 49 + .../include/freertos/stack_macros.h | 62 +- .../include/freertos/task.h | 103 +- .../freertos/FreeRTOS-Kernel-V10.5.1/tasks.c | 1719 +++++++++++------ .../freertos/FreeRTOS-Kernel-V10.5.1/timers.c | 30 +- .../config/include/freertos/FreeRTOSConfig.h | 8 +- .../freertos_tasks_c_additions.h | 182 +- .../include/freertos/idf_additions.h | 82 +- components/freertos/linker.lf | 4 + components/freertos/linker_common.lf | 10 +- 11 files changed, 1659 insertions(+), 706 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/idf_changes.md b/components/freertos/FreeRTOS-Kernel-V10.5.1/idf_changes.md index 2187fd068f2..eb4094b4424 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/idf_changes.md +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/idf_changes.md @@ -2,6 +2,8 @@ This document is used to track all changes made the to FreeRTOS V10.5.1 source code when adding dual core SMP support or IDF additional features. +Todo: Add these to ESP-IDF docs once v10.5.1 becomes default kernel (IDF-8203) + ## License Headers - Added `SPDX-FileCopyrightText` and `SPDX-FileContributor` tags to all files to pass ESP-IDF pre-commit checks. @@ -13,4 +15,116 @@ This document is used to track all changes made the to FreeRTOS V10.5.1 source c ## Changes from Upstream Main Branch not Included in v10.5.1 -- Added ...GetStaticBuffers functions that were upstreamed but not included in v10.5.1 \ No newline at end of file +- Added ...GetStaticBuffers functions that were upstreamed but not included in v10.5.1 + +## Kernel SMP Changes + +List of changes to the Vanilla FreeRTOS V10.5.1 kernel in order to support dual-core SMP + +### Scheduling Behavior Changes + +- The kernel now executes two tasks concurrently +- The kernel now creates two IDLE tasks (pinned to each core) +- Tasks can be pinned to either core, or have no affinity (can run on both cores) +- Each core receives a tick interrupt, but only core 0 increments the tick count and unblocks timed out tasks + - Core 0 calls `xTaskIncrementTick()` + - Core 1 calls `xTaskIncrementTickOtherCores()` +- Each core independently calls `vTaskSwitchContext()` to pick the highest priority task it can currently run + - In single-core scheduling algorithm `taskSELECT_HIGHEST_PRIORITY_TASK()` unchanged + - In SMP, `prvSelectHighestPriorityTaskSMP()` is called. This will select the highest priority ready state task that... + - Has a compatible core affinity + - Is not being run by another core +- Each core can suspend scheduling independently (i.e., `vTaskSuspendAll()`) + +### Configuration + +Following configurations have been added + +- Added `configNUMBER_OF_CORES` to specify the number of cores to build. Can be `1` for vanilla, or `2` for SMP, error otherwise +- Disable `configUSE_PORT_OPTIMISED_TASK_SELECTION` for SMP + +### Data Structure Changes (`tasks.c`) + +The following data fields have been expanded to have `configNUMBER_OF_CORES` copies: + +- `pxCurrentTCBs`: Each core now has its own currently running task +- `xPendingReadyList`: Each core has its own list to pend ready tasks if the scheduler is suspended on the core +- `xYieldPending`: Each core has its own flag to track whether it has a pending yield +- `xIdleTaskHandle`: Each core now has its own idle task +- `uxSchedulerSuspended`: Each core can independently suspend scheduling on its core +- `ulTaskSwitchedInTime`: Each core tracks its own "task switched in" time + +Their access is now indexed by a `xCoreID` if in SMP, or set to `0` in single core. + +The following data structures have been added: + +- `TCB_t.xCoreID`: All tasks now store their core affinity in a TCB member. Always set to 0 in single-core + +### API Additions + +The following APIs have been added to support SMP + +- `xTaskCreatePinnedToCore()` and `xTaskCreateStaticPinnedToCore()` to create tasks with a core affinity + - In single-core, core affinity is ignored. Same behavior as `xTaskCreate()` +- `xTaskGetCoreID()` to get a task's affinity +- Add `ForCore()` versions of the following API + - `xTaskGetIdleTaskHandleForCore()` + - `xTaskGetCurrentTaskHandleForCore()` + - `ulTaskGetIdleRunTimeCounterForCore()` + +### API Modifications + +#### SMP Modifications + +Added the following macros that abstract away single-core and SMP differences: + +- `taskYIELD_CORE()` triggers a particular core to yield +- `taskIS_YIELD_REQUIRED()`/`taskIS_YIELD_REQUIRED_USING_PRIORITY()` check if current core requires a yield after a task is unblocked +- `taskIS_AFFINITY_COMPATIBLE()` check if a task has compatible affinity +- `taskIS_CURRENTLY_RUNNING()`/`taskIS_CURRENTLY_RUNNING_ON_CORE()` checks if a task is running on either core +- `taskCAN_BE_SCHEDULED()` checks if an unblocked task can be scheduled on any core +- `taskIS_SCHEDULER_SUSPENDED()` checks if the scheduler on the current core is suspended +- `taskSELECT_HIGHEST_PRIORITY_TASK()` selects the highest priority task to execute for the current core +- `prvGetTCBFromHandle()` updated in SMP to call `xTaskGetCurrentTaskHandle()` when the handle is `NULL`. Done so for thread safety (in case the current task switches cores at the same time). + +The following functions were modified to accommodate SMP behavior: + +- `prvInitialiseNewTask()` + - Added `xCoreID` argument to pin task on creation + - For single-core, `xCoreID` is hard coded to `0` +- `prvAddNewTaskToReadyList()` + - Checks if new task can be scheduled on core 1 +- `vTaskDelete()` + - Checks if the deleted task is currently running on the other core. + - If so, sends a yield to the other core. +- `vTaskPrioritySet()` + - Checks if the task is currently running on the both cores, and yields the appropriate core if so +- `vTaskSuspend()` + - Checks if the task is currently running on the other core, and yields the other core if so. +- `prvTaskIsTaskSuspended()` + - Checks the `xPendingReadyList` of both cores to see if a task is suspended +- `xTaskResumeAll()` + - Limit catching up of tick counts to core 0 (given only core 0 calls `xTaskIncrementTick()`) +- `xTaskIncrementTick()` + - Limited to core 0 +- `vTaskSwitchContext()` + - Switches context for current core +- `xTaskRemoveFromEventList()` + - Created SMP copy of the function + - Checks if `pxEventList` has already been emptied by the other core before removing + - Checks if task can be scheduled on both cores, adds it to the appropriate core's pending list if it can't be scheduled. +- `vTaskRemoveFromUnorderedEventList()` + - In SMP, check if the task can be scheduled before adding it to the appropriate list. Whereas in single-core, the scheduler is always suspended thus the unblocked task always goes onto the pending ready list. +- `eTaskConfirmSleepModeStatus()` + - Updated logic to determine whether sleep is possible in SMP by checking the status of both cores. +- `prvCheckTasksWaitingTermination()` + - Updated logic so that we don't delete tasks on `xTasksWaitingTermination` which are still currently running on the other core. +- `prvAddCurrentTaskToDelayedList()` + - Added extra check to see if current blocking task has already been deleted by the other core. + +#### Single-Core Modifications + + +## Single Core Differences + +List of differences between Vanilla FreeRTOS V10.5.1 and building the dual-core SMP kernel with `congigNUMBER_OF_CORES == 1`. \ No newline at end of file diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h index 5fca962bb7f..adf94251d86 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h @@ -135,6 +135,24 @@ * within FreeRTOSConfig.h. */ +#ifndef configNUMBER_OF_CORES + #error Missing definition: configNUMBER_OF_CORES must be defined in FreeRTOSConfig.h +#endif + +#if ( configNUMBER_OF_CORES > 1 ) + #ifndef portGET_CORE_ID + #error "Missing definition: portGET_CORE_ID() must be defined if in portmacro.h if configNUMBER_OF_CORES > 1" + #endif + #ifndef portYIELD_CORE + #error "Missing definition: portYIELD_CORE() must be defined if in portmacro.h if configNUMBER_OF_CORES > 1" + #endif +#elif ( configNUMBER_OF_CORES == 1 ) + #undef portGET_CORE_ID + #define portGET_CORE_ID() 0 +#else + #error configNUMBER_OF_CORES must be defined to either 1 or > 1. +#endif /* if ( configNUMBER_OF_CORES > 1 ) */ + #ifndef configMINIMAL_STACK_SIZE #error Missing definition: configMINIMAL_STACK_SIZE must be defined in FreeRTOSConfig.h. configMINIMAL_STACK_SIZE defines the size (in words) of the stack allocated to the idle task. Refer to the demo project provided for your port for a suitable value. #endif @@ -1007,6 +1025,10 @@ #error configUSE_MUTEXES must be set to 1 to use recursive mutexes #endif +#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PORT_OPTIMISED_TASK_SELECTION != 0 ) ) + #error configUSE_PORT_OPTIMISED_TASK_SELECTION is not supported in SMP +#endif + #ifndef configINITIAL_TICK_COUNT #define configINITIAL_TICK_COUNT 0 #endif @@ -1267,6 +1289,8 @@ typedef struct xSTATIC_TCB UBaseType_t uxDummy5; void * pxDummy6; uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; + /* Todo: Remove xCoreID for single core builds (IDF-7894) */ + BaseType_t xDummyCoreID; #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) void * pxDummy8; #endif @@ -1441,4 +1465,29 @@ typedef StaticStreamBuffer_t StaticMessageBuffer_t; #endif /* *INDENT-ON* */ +/*----------------------------------------------------------- +* IDF Compatibility +*----------------------------------------------------------*/ + +#ifdef ESP_PLATFORM + +/* + * Include ESP-IDF API additions implicitly for compatibility reasons. + * + * ESP-IDF API additions were previously added directly to FreeRTOS headers + * (e.g., task.h, queue.h). These APIs have now been moved to + * idf_additions.h. + * + * To ensure there are no breaking changes, we include idf_additions.h + * implicitly here so that those API additions are still accessible. Given + * that FreeRTOS.h must be included first before calling any FreeRTOS API, + * any existing source code can continue using these relocated APIs without + * any additional header inclusions via this implicit inclusion. + * + * Todo: Deprecate this implicit inclusion by ESP-IDF v6.0 (IDF-8126) + */ + #include "freertos/idf_additions.h" + +#endif /* ESP_PLATFORM */ + #endif /* INC_FREERTOS_H */ diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/stack_macros.h b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/stack_macros.h index ea8d23cb59b..741b8ad76ae 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/stack_macros.h +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/stack_macros.h @@ -60,13 +60,13 @@ #if ( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) ) /* Only the current stack state is to be checked. */ - #define taskCHECK_FOR_STACK_OVERFLOW() \ - { \ - /* Is the currently saved stack pointer within the stack limit? */ \ - if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack + portSTACK_LIMIT_PADDING ) \ - { \ - vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ - } \ + #define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) \ + { \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCBs[ xCurCoreID ]->pxTopOfStack <= pxCurrentTCBs[ xCurCoreID ]->pxStack + portSTACK_LIMIT_PADDING ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCBs[ xCurCoreID ], pxCurrentTCBs[ xCurCoreID ]->pcTaskName ); \ + } \ } #endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ @@ -75,14 +75,14 @@ #if ( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) ) /* Only the current stack state is to be checked. */ - #define taskCHECK_FOR_STACK_OVERFLOW() \ - { \ - \ - /* Is the currently saved stack pointer within the stack limit? */ \ - if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack - portSTACK_LIMIT_PADDING ) \ - { \ - vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ - } \ + #define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) \ + { \ + \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCBs[ xCurCoreID ]->pxTopOfStack >= pxCurrentTCBs[ xCurCoreID ]->pxEndOfStack - portSTACK_LIMIT_PADDING ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCBs[ xCurCoreID ], pxCurrentTCBs[ xCurCoreID ]->pcTaskName ); \ + } \ } #endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ @@ -90,18 +90,18 @@ #if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) - #define taskCHECK_FOR_STACK_OVERFLOW() \ - { \ - const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \ - const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ - \ - if( ( pulStack[ 0 ] != ulCheckValue ) || \ - ( pulStack[ 1 ] != ulCheckValue ) || \ - ( pulStack[ 2 ] != ulCheckValue ) || \ - ( pulStack[ 3 ] != ulCheckValue ) ) \ - { \ - vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ - } \ + #define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) \ + { \ + const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCBs[ xCurCoreID ]->pxStack; \ + const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ + \ + if( ( pulStack[ 0 ] != ulCheckValue ) || \ + ( pulStack[ 1 ] != ulCheckValue ) || \ + ( pulStack[ 2 ] != ulCheckValue ) || \ + ( pulStack[ 3 ] != ulCheckValue ) ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCBs[ xCurCoreID ], pxCurrentTCBs[ xCurCoreID ]->pcTaskName ); \ + } \ } #endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ @@ -109,9 +109,9 @@ #if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) - #define taskCHECK_FOR_STACK_OVERFLOW() \ + #define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) \ { \ - int8_t * pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \ + int8_t * pcEndOfStack = ( int8_t * ) pxCurrentTCBs[ xCurCoreID ]->pxEndOfStack; \ static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ @@ -124,7 +124,7 @@ /* Has the extremity of the task stack ever been written over? */ \ if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ { \ - vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCBs[ xCurCoreID ], pxCurrentTCBs[ xCurCoreID ]->pcTaskName ); \ } \ } @@ -133,7 +133,7 @@ /* Remove stack overflow macro if not being used. */ #ifndef taskCHECK_FOR_STACK_OVERFLOW - #define taskCHECK_FOR_STACK_OVERFLOW() + #define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) #endif diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/task.h b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/task.h index ff55eafb615..624285f3689 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/task.h +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/task.h @@ -170,6 +170,7 @@ typedef struct xTASK_STATUS StackType_t * pxEndOfStack; /* Points to the end address of the task's stack area. */ #endif configSTACK_DEPTH_TYPE usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ + BaseType_t xCoreID; /*!< Core this task is pinned to (0, 1, or tskNO_AFFINITY). If configNUMBER_OF_CORES == 1, this will always be 0. */ } TaskStatus_t; /* Possible return values for eTaskConfirmSleepModeStatus(). */ @@ -189,6 +190,14 @@ typedef enum */ #define tskIDLE_PRIORITY ( ( UBaseType_t ) 0U ) +/** + * Macro representing and unpinned (i.e., "no affinity") task in xCoreID parameters + * + * \ingroup Tasks + */ +#define tskNO_AFFINITY ( ( BaseType_t ) 0x7FFFFFFF ) +/* Todo: Update tskNO_AFFINITY value to -1 (IDF-7908) */ + /** * task. h * @@ -294,6 +303,9 @@ typedef enum * support can alternatively create an MPU constrained task using * xTaskCreateRestricted(). * + * @note If configNUMBER_OF_CORES > 1, this function will create an unpinned + * task (see tskNO_AFFINITY for more details). + * * @param pxTaskCode Pointer to the task entry function. Tasks * must be implemented to never return (i.e. continuous loop). * @@ -301,10 +313,8 @@ typedef enum * facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default * is 16. * - * @param usStackDepth The size of the task stack specified as the number of - * variables the stack can hold - not the number of bytes. For example, if - * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes - * will be allocated for stack storage. + * @param usStackDepth The size of the task stack specified as the NUMBER OF + * BYTES. Note that this differs from vanilla FreeRTOS. * * @param pvParameters Pointer that will be used as the parameter for the task * being created. @@ -321,6 +331,9 @@ typedef enum * @return pdPASS if the task was successfully created and added to a ready * list, otherwise an error code defined in the file projdefs.h * + * @note If program uses thread local variables (ones specified with "__thread" + * keyword) then storage for them will be allocated on the task's stack. + * * Example usage: * @code{c} * // Task to be created. @@ -356,13 +369,39 @@ typedef enum * \ingroup Tasks */ #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + static inline __attribute__( ( always_inline ) ) BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const configSTACK_DEPTH_TYPE usStackDepth, void * const pvParameters, UBaseType_t uxPriority, - TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; -#endif + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION + { + /* + * The idf_additions.h has not been included here yet due to inclusion + * order. Thus we manually declare the function here. + */ + extern BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode, + const char * const pcName, + const configSTACK_DEPTH_TYPE usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pvCreatedTask, + const BaseType_t xCoreID ); + + /* + * Call the "PinnedToCore" version with tskNO_AFFINITY to create + * an unpinned task. + */ + return xTaskCreatePinnedToCore( pxTaskCode, + pcName, + usStackDepth, + pvParameters, + uxPriority, + pxCreatedTask, + tskNO_AFFINITY ); + } +#endif /* configSUPPORT_DYNAMIC_ALLOCATION == 1 */ /** * task. h @@ -388,6 +427,9 @@ typedef enum * memory. xTaskCreateStatic() therefore allows a task to be created without * using any dynamic memory allocation. * + * @note If configNUMBER_OF_CORES > 1, this function will create an unpinned + * task (see tskNO_AFFINITY for more details). + * * @param pxTaskCode Pointer to the task entry function. Tasks * must be implemented to never return (i.e. continuous loop). * @@ -395,10 +437,8 @@ typedef enum * facilitate debugging. The maximum length of the string is defined by * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. * - * @param ulStackDepth The size of the task stack specified as the number of - * variables the stack can hold - not the number of bytes. For example, if - * the stack is 32-bits wide and ulStackDepth is defined as 100 then 400 bytes - * will be allocated for stack storage. + * @param ulStackDepth The size of the task stack specified as the NUMBER OF + * BYTES. Note that this differs from vanilla FreeRTOS. * * @param pvParameters Pointer that will be used as the parameter for the task * being created. @@ -418,6 +458,9 @@ typedef enum * puxStackBuffer or pxTaskBuffer are NULL then the task will not be created and * NULL is returned. * + * @note If program uses thread local variables (ones specified with "__thread" + * keyword) then storage for them will be allocated on the task's stack. + * * Example usage: * @code{c} * @@ -473,13 +516,41 @@ typedef enum * \ingroup Tasks */ #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + static inline __attribute__( ( always_inline ) ) TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, - StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; + StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION + { + /* + * The idf_additions.h has not been included here yet due to inclusion + * order. Thus we manually declare the function here. + */ + extern TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const pxStackBuffer, + StaticTask_t * const pxTaskBuffer, + const BaseType_t xCoreID ); + + /* + * Call the "PinnedToCore" version with tskNO_AFFINITY to create + * an unpinned task. + */ + return xTaskCreateStaticPinnedToCore( pxTaskCode, + pcName, + ulStackDepth, + pvParameters, + uxPriority, + puxStackBuffer, + pxTaskBuffer, + tskNO_AFFINITY ); + } #endif /* configSUPPORT_STATIC_ALLOCATION */ /** @@ -1737,8 +1808,8 @@ BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, * xTaskGetIdleTaskHandle() is only available if * INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h. * - * Simply returns the handle of the idle task. It is not valid to call - * xTaskGetIdleTaskHandle() before the scheduler has been started. + * Simply returns the handle of the idle task of the current core. It is not + * valid to call xTaskGetIdleTaskHandle() before the scheduler has been started. */ TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION; @@ -1979,6 +2050,9 @@ void vTaskGetRunTimeStats( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e * system if there are no other tasks executing at the idle priority, tickless * idle is not used, and configIDLE_SHOULD_YIELD is set to 0. * + * @note If configNUMBER_OF_CORES > 1, calling this function will query the idle + * task of the current core. + * * @return The total run time of the idle task or the percentage of the total * run time consumed by the idle task. This is the amount of time the * idle task has actually been executing. The unit of time is dependent on the @@ -2954,6 +3028,9 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) PRIVILEGED_FUNCTION; * or * + Time slicing is in use and there is a task of equal priority to the * currently running task. + * + * Note: If configNUMBER_OF_CORES > 1, this function must only be called by + * core 0. Other cores should call xTaskIncrementTickOtherCores() instead. */ BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION; diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c index f71ffdd63dc..47371e8ebdd 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c @@ -44,6 +44,7 @@ #include "task.h" #include "timers.h" #include "stack_macros.h" +#include "freertos/idf_additions.h" /* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined @@ -71,6 +72,10 @@ #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() #endif +#if ( configNUMBER_OF_CORES > 1 ) + #define taskYIELD_CORE( xCoreID ) portYIELD_CORE( xCoreID ) +#endif /* configNUMBER_OF_CORES > 1 */ + /* Values that can be assigned to the ucNotifyState member of the TCB. */ #define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* Must be zero as it is the initialised value. */ #define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 ) @@ -119,6 +124,80 @@ #define configIDLE_TASK_NAME "IDLE" #endif +/*-----------------------------------------------------------*/ + +/* Macros to check if an unblocked task causes a yield on the current core. + * - pxTCB is the TCB of the task to check + * - xCurCoreID is the current core's ID + * - xYieldEqualPriority indicates whether a yield should occur if the unblocked + * task's priority is equal to the priority of the task currently running on the + * current core. + * - uxTaskPriority is the task's priority + * - xTaskCoreID is the task's core affinity */ +#if ( configNUMBER_OF_CORES > 1 ) + #define taskIS_YIELD_REQUIRED( pxTCB, xCurCoreID, xYieldEqualPriority ) prvIsYieldUsingPrioritySMP( ( pxTCB )->uxPriority, ( pxTCB )->xCoreID, xCurCoreID, xYieldEqualPriority ) + #define taskIS_YIELD_REQUIRED_USING_PRIORITY( uxTaskPriority, xTaskCoreID, xCurCoreID, xYieldEqualPriority ) prvIsYieldUsingPrioritySMP( uxTaskPriority, xTaskCoreID, xCurCoreID, xYieldEqualPriority ) +#else + #define taskIS_YIELD_REQUIRED( pxTCB, xCurCoreID, xYieldEqualPriority ) ( ( ( ( pxTCB )->uxPriority + ( ( xYieldEqualPriority == pdTRUE ) ? 1 : 0 ) ) > pxCurrentTCBs[ 0 ]->uxPriority ) ? pdTRUE : pdFALSE ) + #define taskIS_YIELD_REQUIRED_USING_PRIORITY( uxTaskPriority, xTaskCoreID, xCurCoreID, xYieldEqualPriority ) ( ( ( uxTaskPriority + ( ( xYieldEqualPriority == pdTRUE ) ? 1 : 0 ) ) >= pxCurrentTCBs[ 0 ]->uxPriority ) ? pdTRUE : pdFALSE ) +#endif /* configNUMBER_OF_CORES > 1 */ +/*-----------------------------------------------------------*/ + +/* Macros to check if a task has a compatible affinity with a particular core. + * - xCore is the target core + * - xCoreID is the affinity of the task to check + * + * This macro will always return true on single core as the concept of core + * affinity doesn't exist. */ +#if ( configNUMBER_OF_CORES > 1 ) + #define taskIS_AFFINITY_COMPATIBLE( xCore, xCoreID ) ( ( ( ( xCoreID ) == xCore ) || ( ( xCoreID ) == tskNO_AFFINITY ) ) ? pdTRUE : pdFALSE ) +#else + #define taskIS_AFFINITY_COMPATIBLE( xCore, xCoreID ) ( pdTRUE ) +#endif /* configNUMBER_OF_CORES > 1 */ +/*-----------------------------------------------------------*/ + +/* Macros to check if a particular task is a currently running. */ +#if ( configNUMBER_OF_CORES > 1 ) + #define taskIS_CURRENTLY_RUNNING( pxTCB ) ( ( ( ( pxTCB ) == pxCurrentTCBs[ 0 ] ) || ( ( pxTCB ) == pxCurrentTCBs[ 1 ] ) ) ? pdTRUE : pdFALSE ) + #define taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, xCoreID ) ( ( ( pxTCB ) == pxCurrentTCBs[ ( xCoreID ) ] ) ? pdTRUE : pdFALSE ) +#else + #define taskIS_CURRENTLY_RUNNING( pxTCB ) ( ( ( pxTCB ) == pxCurrentTCBs[ 0 ] ) ? pdTRUE : pdFALSE ) + #define taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, xCoreID ) taskIS_CURRENTLY_RUNNING( pxTCB ) +#endif /* configNUMBER_OF_CORES > 1 */ +/*-----------------------------------------------------------*/ + +/* Macro to check if a particular task can currently be scheduled (i.e., is + * the scheduler suspended). */ +#if ( configNUMBER_OF_CORES > 1 ) + #define taskCAN_BE_SCHEDULED( pxTCB ) prvCheckTaskCanBeScheduledSMP( pxTCB ) +#else + #define taskCAN_BE_SCHEDULED( pxTCB ) ( ( ( uxSchedulerSuspended[ 0 ] == ( UBaseType_t ) 0U ) ) ? pdTRUE : pdFALSE ) +#endif /* configNUMBER_OF_CORES > 1 */ +/*-----------------------------------------------------------*/ + +/* Macro to check if the scheduler is suspended (on the current core) + * + * There are various blocking tasks.c APIs that call configASSERT() to check if + * the API is being called while the scheduler is suspended. However, these + * asserts are done outside a critical section or interrupt disabled block. + * Directly checking uxSchedulerSuspended[ portGET_CORE_ID() ] outside a + * critical section can lead to false positives in SMP. Thus for SMP, we call + * xTaskGetSchedulerState() instead. + * + * Take the following example of an unpinned Task A in SMP calling + * uxSchedulerSuspended[ portGET_CORE_ID() ]: + * - Task A calls portGET_CORE_ID() which is 0 + * - Task A gets preempted by Task B, Task A switches to core 1 + * - Task B on core 0 calls vTaskSuspendAll() + * - Task A checks uxSchedulerSuspended[ 0 ] leading to a false positive + */ +#if ( configNUMBER_OF_CORES > 1 ) + #define taskIS_SCHEDULER_SUSPENDED() ( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) ? pdTRUE : pdFALSE ) +#else + #define taskIS_SCHEDULER_SUSPENDED() ( ( ( uxSchedulerSuspended[ 0 ] != ( UBaseType_t ) 0U ) ) ? pdTRUE : pdFALSE ) +#endif /* configNUMBER_OF_CORES > 1 */ +/*-----------------------------------------------------------*/ + #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is @@ -137,7 +216,10 @@ /*-----------------------------------------------------------*/ - #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + #if ( configNUMBER_OF_CORES > 1 ) + #define taskSELECT_HIGHEST_PRIORITY_TASK() prvSelectHighestPriorityTaskSMP() + #else /* if ( configNUMBER_OF_CORES > 1 ) */ + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ { \ UBaseType_t uxTopPriority = uxTopReadyPriority; \ \ @@ -149,10 +231,11 @@ } \ \ /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ - * the same priority get an equal share of the processor time. */ \ - listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ - uxTopReadyPriority = uxTopPriority; \ + * the same priority get an equal share of the processor time. */ \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCBs[ 0 ], &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + uxTopReadyPriority = uxTopPriority; \ } /* taskSELECT_HIGHEST_PRIORITY_TASK */ + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ /*-----------------------------------------------------------*/ @@ -173,14 +256,14 @@ /*-----------------------------------------------------------*/ - #define taskSELECT_HIGHEST_PRIORITY_TASK() \ - { \ - UBaseType_t uxTopPriority; \ - \ - /* Find the highest priority list that contains ready tasks. */ \ - portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ - configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ - listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + UBaseType_t uxTopPriority; \ + \ + /* Find the highest priority list that contains ready tasks. */ \ + portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ + configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCBs[ 0 ], &( pxReadyTasksLists[ uxTopPriority ] ) ); \ } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ /*-----------------------------------------------------------*/ @@ -234,8 +317,14 @@ * where NULL is used to indicate that the handle of the currently executing * task should be used in place of the parameter. This macro simply checks to * see if the parameter is NULL and returns a pointer to the appropriate TCB. + * + * In SMP, calling xTaskGetCurrentTaskHandle() ensures atomic access to pxCurrentTCBs */ -#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? pxCurrentTCB : ( pxHandle ) ) +#if ( configNUMBER_OF_CORES > 1 ) + #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? xTaskGetCurrentTaskHandle() : ( pxHandle ) ) +#else + #define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? pxCurrentTCBs[ 0 ] : ( pxHandle ) ) +#endif /* The item value of the event list item is normally used to hold the priority * of the task to which it belongs (coded to allow it to be held in reverse @@ -270,6 +359,9 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to StackType_t * pxStack; /*< Points to the start of the stack. */ char pcTaskName[ configMAX_TASK_NAME_LEN ]; /*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + /* Todo: Remove xCoreID for single core builds (IDF-7894) */ + BaseType_t xCoreID; /*< The core that this task is pinned to */ + #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) StackType_t * pxEndOfStack; /*< Points to the highest valid address for the stack. */ #endif @@ -330,18 +422,18 @@ typedef tskTCB TCB_t; /*lint -save -e956 A manual analysis and inspection has been used to determine * which static variables must be declared volatile. */ -portDONT_DISCARD PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; +portDONT_DISCARD PRIVILEGED_DATA TCB_t * volatile pxCurrentTCBs[ configNUMBER_OF_CORES ] = { NULL }; /* Lists for ready and blocked tasks. -------------------- * xDelayedTaskList1 and xDelayedTaskList2 could be moved to function scope but * doing so breaks some kernel aware debuggers and debuggers that rely on removing * the static qualifier. */ -PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */ -PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ -PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ -PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ -PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ -PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ +PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ +PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t xPendingReadyList[ configNUMBER_OF_CORES ]; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ #if ( INCLUDE_vTaskDelete == 1 ) @@ -368,11 +460,11 @@ PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINI PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U; -PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; +PRIVILEGED_DATA static volatile BaseType_t xYieldPending[ configNUMBER_OF_CORES ] = { pdFALSE }; PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; -PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ -PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ +PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ +PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle[ configNUMBER_OF_CORES ] = { NULL }; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ /* Improve support for OpenOCD. The kernel tracks Ready tasks via priority lists. * For tracking the state of remote threads, OpenOCD uses uxTopUsedPriority @@ -387,14 +479,14 @@ const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U; * kernel to move the task from the pending ready list into the real ready list * when the scheduler is unsuspended. The pending ready list itself can only be * accessed from a critical section. */ -PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; +PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended[ configNUMBER_OF_CORES ] = { ( UBaseType_t ) pdFALSE }; #if ( configGENERATE_RUN_TIME_STATS == 1 ) /* Do not move these variables to function scope as doing so prevents the * code working with debuggers that need to remove the static qualifier. */ - PRIVILEGED_DATA static configRUN_TIME_COUNTER_TYPE ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ - PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ +PRIVILEGED_DATA static configRUN_TIME_COUNTER_TYPE ulTaskSwitchedInTime[ configNUMBER_OF_CORES ] = { 0UL }; /*< Holds the value of a timer/counter the last time a task was switched in. */ +PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ #endif @@ -404,6 +496,76 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t /* File private functions. --------------------------------*/ +/** + * Utility function to check whether a yield (on either core) is required after + * unblocking (or changing the priority of) a particular task. + * + * - This function is the SMP replacement for checking if an unblocked task has + * a higher (or equal) priority than the current task. + * - It should be called before calling taskYIELD_IF_USING_PREEMPTION() or + * before setting xYieldRequired + * - If it is the other core that requires a yield, this function will + * internally trigger the other core to yield + * + * Note: In some special instances, a yield is triggered if the unblocked task + * has an equal priority (such as in xTaskResumeAll). Thus the + * xYieldEqualPriority parameter specifies whether to yield if the current + * task has equal priority. + * + * Scheduling Algorithm: + * This function will bias towards yielding the current core. + * - If the unblocked task has a higher (or equal) priority than the current + * core, the current core is yielded regardless of the current priority of the + * other core. + * - A core (current or other) will only yield if their schedulers are not + * suspended. + * + * Todo: This can be optimized (IDF-5772) + * + * Entry: + * - This function must be called in a critical section + * - A task must just have been unblocked, or its priority raised + * Exit: + * - Returns pdTRUE if the current core requires yielding + * - The other core will be triggered to yield if required + */ +#if ( configNUMBER_OF_CORES > 1 ) + + static BaseType_t prvIsYieldUsingPrioritySMP( UBaseType_t uxTaskPriority, + BaseType_t xTaskCoreID, + BaseType_t xCurCoreID, + BaseType_t xYieldEqualPriority ) PRIVILEGED_FUNCTION; + +#endif /* configNUMBER_OF_CORES > 1 */ + +/** + * Utility function to check whether a task can currently be scheduled on one + * or more cores. This function is the SMP replacement for checking if + * `uxSchedulerSuspended == 0`. + * + * - If a task is pinned, check the scheduler suspension state on the task's + * pinned core. The task can be scheduled if the scheduler is not suspended on + * the pinned core. + * - If a task is unpinned, check the scheduler suspension state on both cores. + * The task can be scheduled if the scheduler is not suspended on either of + * the cores. + */ +#if ( configNUMBER_OF_CORES > 1 ) + + static BaseType_t prvCheckTaskCanBeScheduledSMP( TCB_t * pxTCB ) PRIVILEGED_FUNCTION; + +#endif /* configNUMBER_OF_CORES > 1 */ + +/** + * Utility function to select the highest priority and runnable task for the + * current core. + */ +#if ( configNUMBER_OF_CORES > 1 ) + + static void prvSelectHighestPriorityTaskSMP( void ) PRIVILEGED_FUNCTION; + +#endif /* configNUMBER_OF_CORES > 1 */ + /** * Utility task that simply returns pdTRUE if the task referenced by xTask is * currently in the Suspended state, or pdFALSE if the task referenced by xTask @@ -542,7 +704,8 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, TCB_t * pxNewTCB, - const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; + const MemoryRegion_t * const xRegions, + BaseType_t xCoreID ) PRIVILEGED_FUNCTION; /* * Called after a new task has been created and initialised to place the task @@ -563,65 +726,98 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; /*-----------------------------------------------------------*/ -#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) +#if ( configNUMBER_OF_CORES > 1 ) - TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, - const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - const uint32_t ulStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - StackType_t * const puxStackBuffer, - StaticTask_t * const pxTaskBuffer ) + static BaseType_t prvIsYieldUsingPrioritySMP( UBaseType_t uxTaskPriority, + BaseType_t xTaskCoreID, + BaseType_t xCurCoreID, + BaseType_t xYieldEqualPriority ) { - TCB_t * pxNewTCB; - TaskHandle_t xReturn; + configASSERT( uxTaskPriority < configMAX_PRIORITIES ); + + if( xYieldEqualPriority == pdTRUE ) + { + /* Increment the task priority to achieve the same affect as + * if( uxTaskPriority >= pxCurrentTCBs->uxPriority ). */ + uxTaskPriority++; + } - configASSERT( puxStackBuffer != NULL ); - configASSERT( pxTaskBuffer != NULL ); + /* Indicate whether the current core needs to yield */ + BaseType_t xYieldRequiredCurrentCore; - #if ( configASSERT_DEFINED == 1 ) + /* If the target task can run on the current core, and has a higher + * priority than the current core, and the core has not suspended + * scheduling, then yield the current core. + * Todo: Make fair scheduling a configurable option (IDF-5772). */ + if( ( taskIS_AFFINITY_COMPATIBLE( xCurCoreID, xTaskCoreID ) == pdTRUE ) && + ( uxTaskPriority > pxCurrentTCBs[ xCurCoreID ]->uxPriority ) && + ( uxSchedulerSuspended[ xCurCoreID ] == ( UBaseType_t ) 0U ) ) { - /* Sanity check that the size of the structure used to declare a - * variable of type StaticTask_t equals the size of the real task - * structure. */ - volatile size_t xSize = sizeof( StaticTask_t ); - configASSERT( xSize == sizeof( TCB_t ) ); - ( void ) xSize; /* Prevent lint warning when configASSERT() is not used. */ + /* Return true for the caller to yield the current core */ + xYieldRequiredCurrentCore = pdTRUE; } - #endif /* configASSERT_DEFINED */ - if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ) + /* If the target task can run on the other core, and has a higher + * priority then the other core, and the other core has not suspended + * scheduling, then yield the other core */ + else if( ( taskIS_AFFINITY_COMPATIBLE( !xCurCoreID, xTaskCoreID ) == pdTRUE ) && + ( uxTaskPriority > pxCurrentTCBs[ !xCurCoreID ]->uxPriority ) && + ( uxSchedulerSuspended[ !xCurCoreID ] == ( UBaseType_t ) 0U ) ) { - /* The memory used for the task's TCB and stack are passed into this - * function - use them. */ - pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 !e9087 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ - memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) ); - pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; + /* Signal the other core to yield */ + taskYIELD_CORE( !xCurCoreID ); + xYieldRequiredCurrentCore = pdFALSE; + } + else + { + xYieldRequiredCurrentCore = pdFALSE; + } + + return xYieldRequiredCurrentCore; + } + +#endif /* configNUMBER_OF_CORES > 1 */ +/*-----------------------------------------------------------*/ - #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ +#if ( configNUMBER_OF_CORES > 1 ) + + static BaseType_t prvCheckTaskCanBeScheduledSMP( TCB_t * pxTCB ) + { + BaseType_t xReturn; + + if( pxTCB->xCoreID == tskNO_AFFINITY ) + { + /* Task is unpinned. As long as one core has not suspended + * scheduling, the task can be scheduled. */ + if( ( uxSchedulerSuspended[ 0 ] == ( UBaseType_t ) 0U ) || ( uxSchedulerSuspended[ 1 ] == ( UBaseType_t ) 0U ) ) { - /* Tasks can be created statically or dynamically, so note this - * task was created statically in case the task is later deleted. */ - pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; } - #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ - - prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL ); - prvAddNewTaskToReadyList( pxNewTCB ); + } + else if( uxSchedulerSuspended[ pxTCB->xCoreID ] == ( UBaseType_t ) 0U ) + { + /* The task is pinned to a core. If it's pinned core has not + * suspended scheduling, the task can be scheduled. */ + xReturn = pdTRUE; } else { - xReturn = NULL; + xReturn = pdFALSE; } return xReturn; } -#endif /* SUPPORT_STATIC_ALLOCATION */ +#endif /* configNUMBER_OF_CORES > 1 */ /*-----------------------------------------------------------*/ #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) +/* Todo: Add support for task restricted API (IDF-7895) */ BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * pxCreatedTask ) { @@ -670,6 +866,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) +/* Todo: Add support for task restricted API (IDF-7895) */ BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * pxCreatedTask ) { @@ -720,103 +917,6 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; #endif /* portUSING_MPU_WRAPPERS */ /*-----------------------------------------------------------*/ -#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - - BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, - const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - const configSTACK_DEPTH_TYPE usStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - TaskHandle_t * const pxCreatedTask ) - { - TCB_t * pxNewTCB; - BaseType_t xReturn; - - /* If the stack grows down then allocate the stack then the TCB so the stack - * does not grow into the TCB. Likewise if the stack grows up then allocate - * the TCB then the stack. */ - #if ( portSTACK_GROWTH > 0 ) - { - /* Allocate space for the TCB. Where the memory comes from depends on - * the implementation of the port malloc function and whether or not static - * allocation is being used. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); - - if( pxNewTCB != NULL ) - { - memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) ); - - /* Allocate space for the stack used by the task being created. - * The base of the stack memory stored in the TCB so the task can - * be deleted later if required. */ - pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - - if( pxNewTCB->pxStack == NULL ) - { - /* Could not allocate the stack. Delete the allocated TCB. */ - vPortFree( pxNewTCB ); - pxNewTCB = NULL; - } - } - } - #else /* portSTACK_GROWTH */ - { - StackType_t * pxStack; - - /* Allocate space for the stack used by the task being created. */ - pxStack = pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */ - - if( pxStack != NULL ) - { - /* Allocate space for the TCB. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */ - - if( pxNewTCB != NULL ) - { - memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) ); - - /* Store the stack location in the TCB. */ - pxNewTCB->pxStack = pxStack; - } - else - { - /* The stack cannot be used as the TCB was not created. Free - * it again. */ - vPortFreeStack( pxStack ); - } - } - else - { - pxNewTCB = NULL; - } - } - #endif /* portSTACK_GROWTH */ - - if( pxNewTCB != NULL ) - { - #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e9029 !e731 Macro has been consolidated for readability reasons. */ - { - /* Tasks can be created statically or dynamically, so note this - * task was created dynamically in case it is later deleted. */ - pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; - } - #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ - - prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); - prvAddNewTaskToReadyList( pxNewTCB ); - xReturn = pdPASS; - } - else - { - xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; - } - - return xReturn; - } - -#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ -/*-----------------------------------------------------------*/ - static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const uint32_t ulStackDepth, @@ -824,11 +924,20 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, TCB_t * pxNewTCB, - const MemoryRegion_t * const xRegions ) + const MemoryRegion_t * const xRegions, + BaseType_t xCoreID ) { StackType_t * pxTopOfStack; UBaseType_t x; + #if ( configNUMBER_OF_CORES > 1 ) + /* Check that xCoreID is valid */ + configASSERT( ( ( xCoreID >= 0 ) && ( xCoreID < configNUMBER_OF_CORES ) ) || ( xCoreID == tskNO_AFFINITY ) ); + #else + /* Hard code xCoreID to 0 */ + xCoreID = 0; + #endif + #if ( portUSING_MPU_WRAPPERS == 1 ) /* Should the task be created in privileged mode? */ BaseType_t xRunPrivileged; @@ -927,6 +1036,7 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, } pxNewTCB->uxPriority = uxPriority; + pxNewTCB->xCoreID = xCoreID; /* Todo: Remove xCoreID for single core builds (IDF-7894) */ #if ( configUSE_MUTEXES == 1 ) { pxNewTCB->uxBasePriority = uxPriority; @@ -1035,24 +1145,33 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) { uxCurrentNumberOfTasks++; - if( pxCurrentTCB == NULL ) + if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) { - /* There are no other tasks, or all the other tasks are in - * the suspended state - make this the current task. */ - pxCurrentTCB = pxNewTCB; + /* This is the first task to be created so do the preliminary + * initialisation required. We will not recover if this call + * fails, but we will report the failure. */ + prvInitialiseTaskLists(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) - { - /* This is the first task to be created so do the preliminary - * initialisation required. We will not recover if this call - * fails, but we will report the failure. */ - prvInitialiseTaskLists(); - } - else + if( ( pxCurrentTCBs[ 0 ] == NULL ) && ( taskIS_AFFINITY_COMPATIBLE( 0, pxNewTCB->xCoreID ) == pdTRUE ) ) + { + /* On core 0, there are no other tasks, or all the other tasks + * are in the suspended state - make this the current task. */ + pxCurrentTCBs[ 0 ] = pxNewTCB; + } + + #if ( configNUMBER_OF_CORES > 1 ) + else if( ( pxCurrentTCBs[ 1 ] == NULL ) && ( taskIS_AFFINITY_COMPATIBLE( 1, pxNewTCB->xCoreID ) == pdTRUE ) ) { - mtCOVERAGE_TEST_MARKER(); + /* On core 1, there are no other tasks, or all the other tasks + * are in the suspended state - make this the current task. */ + pxCurrentTCBs[ 1 ] = pxNewTCB; } - } + #endif /* configNUMBER_OF_CORES > 1 */ else { /* If the scheduler is not already running, make this task the @@ -1060,10 +1179,21 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * so far. */ if( xSchedulerRunning == pdFALSE ) { - if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority ) + if( ( pxCurrentTCBs[ 0 ] != NULL ) && + ( taskIS_AFFINITY_COMPATIBLE( 0, pxNewTCB->xCoreID ) == pdTRUE ) && + ( pxCurrentTCBs[ 0 ]->uxPriority <= pxNewTCB->uxPriority ) ) { - pxCurrentTCB = pxNewTCB; + pxCurrentTCBs[ 0 ] = pxNewTCB; } + + #if ( configNUMBER_OF_CORES > 1 ) + else if( ( pxCurrentTCBs[ 1 ] != NULL ) && + ( taskIS_AFFINITY_COMPATIBLE( 1, pxNewTCB->xCoreID ) == pdTRUE ) && + ( pxCurrentTCBs[ 1 ]->uxPriority <= pxNewTCB->uxPriority ) ) + { + pxCurrentTCBs[ 1 ] = pxNewTCB; + } + #endif /* configNUMBER_OF_CORES > 1 */ else { mtCOVERAGE_TEST_MARKER(); @@ -1089,13 +1219,12 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) portSETUP_TCB( pxNewTCB ); } - taskEXIT_CRITICAL(); if( xSchedulerRunning != pdFALSE ) { /* If the created task is of a higher priority than the current task * then it should run now. */ - if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED( pxNewTCB, portGET_CORE_ID(), pdTRUE ) == pdTRUE ) { taskYIELD_IF_USING_PREEMPTION(); } @@ -1108,6 +1237,8 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) { mtCOVERAGE_TEST_MARKER(); } + + taskEXIT_CRITICAL(); } /*-----------------------------------------------------------*/ @@ -1116,9 +1247,14 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) void vTaskDelete( TaskHandle_t xTaskToDelete ) { TCB_t * pxTCB; + BaseType_t xSelfDelete; + BaseType_t xIsCurRunning; taskENTER_CRITICAL(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* If null is passed in here then it is the calling task that is * being deleted. */ pxTCB = prvGetTCBFromHandle( xTaskToDelete ); @@ -1149,13 +1285,35 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * not return. */ uxTaskNumber++; - if( pxTCB == pxCurrentTCB ) + /* Check if the task is deleting itself, or is currently running on + * the other core. */ + if( taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, xCurCoreID ) == pdTRUE ) + { + xSelfDelete = pdTRUE; + xIsCurRunning = pdTRUE; + } + + #if ( configNUMBER_OF_CORES > 1 ) + else if( taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, !xCurCoreID ) == pdTRUE ) + { + xSelfDelete = pdFALSE; + xIsCurRunning = pdTRUE; + } + #endif /* configNUMBER_OF_CORES > 1 */ + else + { + xSelfDelete = pdFALSE; + xIsCurRunning = pdFALSE; + } + + if( xIsCurRunning == pdTRUE ) { - /* A task is deleting itself. This cannot complete within the - * task itself, as a context switch to another task is required. - * Place the task in the termination list. The idle task will - * check the termination list and free up any memory allocated by - * the scheduler for the TCB and stack of the deleted task. */ + /* A task is deleting itself or is currently running. This + * cannot complete within the task itself, as a context switch + * to another task is required. Place the task in the + * termination list. The idle task will check the termination + * list and free up any memory allocated by the scheduler for + * the TCB and stack of the deleted task. */ vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) ); /* Increment the ucTasksDeleted variable so the idle task knows @@ -1172,7 +1330,20 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * after which it is not possible to yield away from this task - * hence xYieldPending is used to latch that a context switch is * required. */ - portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); + portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending[ xCurCoreID ] ); + + #if ( configNUMBER_OF_CORES > 1 ) + if( xSelfDelete == pdFALSE ) + { + /* The task that is being deleted is currently running + * on the other core. Send a yield request to the other + * core so that the task is swapped out. */ + taskYIELD_CORE( !xCurCoreID ); + } + #else /* configNUMBER_OF_CORES > 1 */ + /* xCurCoreID is unused */ + ( void ) xCurCoreID; + #endif /* configNUMBER_OF_CORES > 1 */ } else { @@ -1186,10 +1357,11 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) } taskEXIT_CRITICAL(); - /* If the task is not deleting itself, call prvDeleteTCB from outside of - * critical section. If a task deletes itself, prvDeleteTCB is called - * from prvCheckTasksWaitingTermination which is called from Idle task. */ - if( pxTCB != pxCurrentTCB ) + /* If the task is currently running, call prvDeleteTCB from outside of + * critical section. If a task is currently running, prvDeleteTCB is + * called from prvCheckTasksWaitingTermination which is called from + * Idle task. */ + if( xIsCurRunning == pdFALSE ) { prvDeleteTCB( pxTCB ); } @@ -1198,9 +1370,9 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * been deleted. */ if( xSchedulerRunning != pdFALSE ) { - if( pxTCB == pxCurrentTCB ) + if( xSelfDelete == pdTRUE ) { - configASSERT( uxSchedulerSuspended == 0 ); + configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE ); portYIELD_WITHIN_API(); } else @@ -1223,7 +1395,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) configASSERT( pxPreviousWakeTime ); configASSERT( ( xTimeIncrement > 0U ) ); - configASSERT( uxSchedulerSuspended == 0 ); + configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE ); vTaskSuspendAll(); { @@ -1309,7 +1481,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) /* A delay time of zero just forces a reschedule. */ if( xTicksToDelay > ( TickType_t ) 0U ) { - configASSERT( uxSchedulerSuspended == 0 ); + configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE ); vTaskSuspendAll(); { traceTASK_DELAY(); @@ -1357,86 +1529,86 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) configASSERT( pxTCB ); - if( pxTCB == pxCurrentTCB ) - { - /* The task calling this function is querying its own state. */ - eReturn = eRunning; - } - else + taskENTER_CRITICAL(); { - taskENTER_CRITICAL(); + if( taskIS_CURRENTLY_RUNNING( pxTCB ) == pdTRUE ) + { + /* The task calling this function is querying its own state. */ + eReturn = eRunning; + } + else { pxStateList = listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) ); pxDelayedList = pxDelayedTaskList; pxOverflowedDelayedList = pxOverflowDelayedTaskList; - } - taskEXIT_CRITICAL(); - if( ( pxStateList == pxDelayedList ) || ( pxStateList == pxOverflowedDelayedList ) ) - { - /* The task being queried is referenced from one of the Blocked - * lists. */ - eReturn = eBlocked; - } - - #if ( INCLUDE_vTaskSuspend == 1 ) - else if( pxStateList == &xSuspendedTaskList ) + if( ( pxStateList == pxDelayedList ) || ( pxStateList == pxOverflowedDelayedList ) ) { - /* The task being queried is referenced from the suspended - * list. Is it genuinely suspended or is it blocked - * indefinitely? */ - if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ) + /* The task being queried is referenced from one of the Blocked + * lists. */ + eReturn = eBlocked; + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + else if( pxStateList == &xSuspendedTaskList ) { - #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + /* The task being queried is referenced from the suspended + * list. Is it genuinely suspended or is it blocked + * indefinitely? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ) { - BaseType_t x; + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + { + BaseType_t x; - /* The task does not appear on the event list item of - * and of the RTOS objects, but could still be in the - * blocked state if it is waiting on its notification - * rather than waiting on an object. If not, is - * suspended. */ - eReturn = eSuspended; + /* The task does not appear on the event list item of + * and of the RTOS objects, but could still be in the + * blocked state if it is waiting on its notification + * rather than waiting on an object. If not, is + * suspended. */ + eReturn = eSuspended; - for( x = 0; x < configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ ) - { - if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION ) + for( x = 0; x < configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ ) { - eReturn = eBlocked; - break; + if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION ) + { + eReturn = eBlocked; + break; + } } } + #else /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */ + { + eReturn = eSuspended; + } + #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */ } - #else /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */ + else { - eReturn = eSuspended; + eReturn = eBlocked; } - #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */ } - else + #endif /* if ( INCLUDE_vTaskSuspend == 1 ) */ + + #if ( INCLUDE_vTaskDelete == 1 ) + else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) ) { - eReturn = eBlocked; + /* The task being queried is referenced from the deleted + * tasks list, or it is not referenced from any lists at + * all. */ + eReturn = eDeleted; } - } - #endif /* if ( INCLUDE_vTaskSuspend == 1 ) */ + #endif - #if ( INCLUDE_vTaskDelete == 1 ) - else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) ) + else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */ { - /* The task being queried is referenced from the deleted - * tasks list, or it is not referenced from any lists at - * all. */ - eReturn = eDeleted; + /* If the task is not in any other state, it must be in the + * Ready (including pending ready) state. */ + eReturn = eReady; } - #endif - - else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */ - { - /* If the task is not in any other state, it must be in the - * Ready (including pending ready) state. */ - eReturn = eReady; } } + taskEXIT_CRITICAL(); return eReturn; } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ @@ -1529,6 +1701,9 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) taskENTER_CRITICAL(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* If null is passed in here then it is the priority of the calling * task that is being changed. */ pxTCB = prvGetTCBFromHandle( xTask ); @@ -1551,12 +1726,12 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * priority than the calling task. */ if( uxNewPriority > uxCurrentBasePriority ) { - if( pxTCB != pxCurrentTCB ) + if( taskIS_CURRENTLY_RUNNING( pxTCB ) == pdFALSE ) { /* The priority of a task other than the currently * running task is being raised. Is the priority being * raised above that of the running task? */ - if( uxNewPriority >= pxCurrentTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED_USING_PRIORITY( uxNewPriority, pxTCB->xCoreID, portGET_CORE_ID(), pdTRUE ) == pdTRUE ) { xYieldRequired = pdTRUE; } @@ -1572,13 +1747,23 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * priority task able to run so no yield is required. */ } } - else if( pxTCB == pxCurrentTCB ) + else if( taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, xCurCoreID ) == pdTRUE ) { - /* Setting the priority of the running task down means - * there may now be another task of higher priority that - * is ready to execute. */ + /* Lowering the priority of task currently running on the + * current core means there may now be another task of + * higher priority that is ready to execute. */ xYieldRequired = pdTRUE; } + + #if ( configNUMBER_OF_CORES > 1 ) + else if( taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, !xCurCoreID ) == pdTRUE ) + { + /* Lowering the priority of task currently running on the + * other core also means there may now be another task of + * higher priority that is ready to execute. */ + taskYIELD_CORE( !xCurCoreID ); + } + #endif /* configNUMBER_OF_CORES > 1 */ else { /* Setting the priority of any other task down does not @@ -1680,6 +1865,9 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) taskENTER_CRITICAL(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* If null is passed in here then it is the running task that is * being suspended. */ pxTCB = prvGetTCBFromHandle( xTaskToSuspend ); @@ -1724,55 +1912,73 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) } } #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */ - } - taskEXIT_CRITICAL(); - if( xSchedulerRunning != pdFALSE ) - { - /* Reset the next expected unblock time in case it referred to the - * task that is now in the Suspended state. */ - taskENTER_CRITICAL(); + if( xSchedulerRunning != pdFALSE ) { + /* Reset the next expected unblock time in case it referred to the + * task that is now in the Suspended state. */ prvResetNextTaskUnblockTime(); } - taskEXIT_CRITICAL(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - if( pxTCB == pxCurrentTCB ) - { - if( xSchedulerRunning != pdFALSE ) + else { - /* The current task has just been suspended. */ - configASSERT( uxSchedulerSuspended == 0 ); - portYIELD_WITHIN_API(); + mtCOVERAGE_TEST_MARKER(); } - else + + if( taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, xCurCoreID ) == pdTRUE ) { - /* The scheduler is not running, but the task that was pointed - * to by pxCurrentTCB has just been suspended and pxCurrentTCB - * must be adjusted to point to a different task. */ - if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) /*lint !e931 Right has no side effect, just volatile. */ + if( xSchedulerRunning != pdFALSE ) { - /* No other tasks are ready, so set pxCurrentTCB back to - * NULL so when the next task is created pxCurrentTCB will - * be set to point to it no matter what its relative priority - * is. */ - pxCurrentTCB = NULL; + /* The current task has just been suspended. */ + configASSERT( uxSchedulerSuspended[ xCurCoreID ] == 0 ); + portYIELD_WITHIN_API(); } else { - vTaskSwitchContext(); + /* The scheduler is not running, but the task that was pointed + * to by pxCurrentTCBs has just been suspended and pxCurrentTCBs + * must be adjusted to point to a different task. */ + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) /*lint !e931 Right has no side effect, just volatile. */ + { + /* No other tasks are ready, so set pxCurrentTCBs back to + * NULL so when the next task is created pxCurrentTCBs will + * be set to point to it no matter what its relative priority + * is. */ + pxCurrentTCBs[ xCurCoreID ] = NULL; + } + else + { + vTaskSwitchContext(); + } } } + + #if ( configNUMBER_OF_CORES > 1 ) + else if( taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, !xCurCoreID ) == pdTRUE ) + { + /* The other core's current task has just been suspended */ + if( xSchedulerRunning != pdFALSE ) + { + taskYIELD_CORE( !xCurCoreID ); + } + else + { + /* The scheduler is not running, but the task that was + * pointed to by pxCurrentTCBs[ otherCore ] has just been + * suspended. We simply set the + * pxCurrentTCBs[ otherCore ] to NULL for now. + * + * Todo: Update vTaskSwitchContext() to be able to run + * on behalf of the other core. */ + pxCurrentTCBs[ !xCurCoreID ] = NULL; + } + } + #endif /* configNUMBER_OF_CORES > 1 */ + else + { + mtCOVERAGE_TEST_MARKER(); + } } - else - { - mtCOVERAGE_TEST_MARKER(); - } + taskEXIT_CRITICAL(); } #endif /* INCLUDE_vTaskSuspend */ @@ -1795,7 +2001,12 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE ) { /* Has the task already been resumed from within an ISR? */ - if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) + #if ( configNUMBER_OF_CORES > 1 ) + if( ( listIS_CONTAINED_WITHIN( &xPendingReadyList[ 0 ], &( pxTCB->xEventListItem ) ) == pdFALSE ) && + ( listIS_CONTAINED_WITHIN( &xPendingReadyList[ 1 ], &( pxTCB->xEventListItem ) ) == pdFALSE ) ) + #else + if( listIS_CONTAINED_WITHIN( &xPendingReadyList[ 0 ], &( pxTCB->xEventListItem ) ) == pdFALSE ) + #endif /* configNUMBER_OF_CORES > 1 */ { /* Is it in the suspended list because it is in the Suspended * state, or because is is blocked with no timeout? */ @@ -1833,11 +2044,11 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) /* It does not make sense to resume the calling task. */ configASSERT( xTaskToResume ); - /* The parameter cannot be NULL as it is impossible to resume the - * currently executing task. */ - if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) ) + taskENTER_CRITICAL(); { - taskENTER_CRITICAL(); + /* The parameter cannot be NULL as it is impossible to resume the + * currently executing task. */ + if( ( taskIS_CURRENTLY_RUNNING( pxTCB ) == pdFALSE ) && ( pxTCB != NULL ) ) { if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) { @@ -1849,7 +2060,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) prvAddTaskToReadyList( pxTCB ); /* A higher priority task may have just been resumed. */ - if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED( pxTCB, portGET_CORE_ID(), pdTRUE ) == pdTRUE ) { /* This yield may not cause the task just resumed to run, * but will leave the lists in the correct state for the @@ -1866,12 +2077,12 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); - } - else - { - mtCOVERAGE_TEST_MARKER(); + else + { + mtCOVERAGE_TEST_MARKER(); + } } + taskEXIT_CRITICAL(); } #endif /* INCLUDE_vTaskSuspend */ @@ -1910,21 +2121,24 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) { if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + traceTASK_RESUME_FROM_ISR( pxTCB ); /* Check the ready lists can be accessed. */ - if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + if( taskCAN_BE_SCHEDULED( pxTCB ) == pdTRUE ) { /* Ready lists can be accessed so move the task from the * suspended list to the ready list directly. */ - if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED( pxTCB, xCurCoreID, pdTRUE ) == pdTRUE ) { xYieldRequired = pdTRUE; /* Mark that a yield is pending in case the user is not * using the return value to initiate a context switch * from the ISR using portYIELD_FROM_ISR. */ - xYieldPending = pdTRUE; + xYieldPending[ xCurCoreID ] = pdTRUE; } else { @@ -1939,7 +2153,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) /* The delayed or ready lists cannot be accessed so the task * is held in the pending ready list until the scheduler is * unsuspended. */ - vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + vListInsertEnd( &( xPendingReadyList[ xCurCoreID ] ), &( pxTCB->xEventListItem ) ); } } else @@ -1958,45 +2172,57 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) void vTaskStartScheduler( void ) { BaseType_t xReturn; + UBaseType_t x; - /* Add the idle task at the lowest priority. */ - #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + /* Create idle tasks that are pinned to each core */ + for( x = 0; x < configNUMBER_OF_CORES; x++ ) { - StaticTask_t * pxIdleTaskTCBBuffer = NULL; - StackType_t * pxIdleTaskStackBuffer = NULL; - uint32_t ulIdleTaskStackSize; - - /* The Idle task is created using user provided RAM - obtain the - * address of the RAM then create the idle task. */ - vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); - xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, - configIDLE_TASK_NAME, - ulIdleTaskStackSize, - ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ - portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - pxIdleTaskStackBuffer, - pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ - - if( xIdleTaskHandle != NULL ) - { - xReturn = pdPASS; + /* Add the idle task at the lowest priority. */ + #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + StaticTask_t * pxIdleTaskTCBBuffer = NULL; + StackType_t * pxIdleTaskStackBuffer = NULL; + uint32_t ulIdleTaskStackSize; + + /* The Idle task is created using user provided RAM - obtain the + * address of the RAM then create the idle task. */ + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); + xIdleTaskHandle[ x ] = xTaskCreateStaticPinnedToCore( prvIdleTask, + configIDLE_TASK_NAME, + ulIdleTaskStackSize, + ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + pxIdleTaskStackBuffer, + pxIdleTaskTCBBuffer, /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + x ); + + if( xIdleTaskHandle[ x ] != NULL ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + break; + } } - else + #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ { - xReturn = pdFAIL; - } - } - #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ - { - /* The Idle task is being created using dynamically allocated RAM. */ - xReturn = xTaskCreate( prvIdleTask, - configIDLE_TASK_NAME, - configMINIMAL_STACK_SIZE, - ( void * ) NULL, - portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + /* The Idle task is being created using dynamically allocated RAM. */ + xReturn = xTaskCreatePinnedToCore( prvIdleTask, + configIDLE_TASK_NAME, + configMINIMAL_STACK_SIZE, + ( void * ) NULL, + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + &xIdleTaskHandle[ xCoreID ], /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + xCoreID ); + + if( xReturn == pdFAIL ) + { + break; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ } - #endif /* configSUPPORT_STATIC_ALLOCATION */ #if ( configUSE_TIMERS == 1 ) { @@ -2033,7 +2259,7 @@ void vTaskStartScheduler( void ) { /* Switch C-Runtime's TLS Block to point to the TLS * block specific to the task that will run first. */ - configSET_TLS_BLOCK( pxCurrentTCB->xTLSBlock ); + configSET_TLS_BLOCK( pxCurrentTCBs[ portGET_CORE_ID() ]->xTLSBlock ); } #endif @@ -2072,7 +2298,7 @@ void vTaskStartScheduler( void ) /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, * meaning xIdleTaskHandle is not used anywhere else. */ - ( void ) xIdleTaskHandle; + ( void ) xIdleTaskHandle[ 0 ]; /* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority * from getting optimized out as it is no longer used by the kernel. */ @@ -2104,7 +2330,7 @@ void vTaskSuspendAll( void ) /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment * is used to allow calls to vTaskSuspendAll() to nest. */ - ++uxSchedulerSuspended; + ++uxSchedulerSuspended[ portGET_CORE_ID() ]; /* Enforces ordering for ports and optimised compilers that may otherwise place * the above increment elsewhere. */ @@ -2146,11 +2372,11 @@ void vTaskSuspendAll( void ) } #endif /* if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) */ - if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ) + if( pxCurrentTCBs[ portGET_CORE_ID() ]->uxPriority > tskIDLE_PRIORITY ) { xReturn = 0; } - else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ) + else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > configNUMBER_OF_CORES ) { /* There are other idle priority tasks in the ready state. If * time slicing is used then the very next tick interrupt must be @@ -2182,7 +2408,7 @@ BaseType_t xTaskResumeAll( void ) /* If uxSchedulerSuspended is zero then this function does not match a * previous call to vTaskSuspendAll(). */ - configASSERT( uxSchedulerSuspended ); + configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdTRUE ); /* It is possible that an ISR caused a task to be removed from an event * list while the scheduler was suspended. If this was the case then the @@ -2191,17 +2417,20 @@ BaseType_t xTaskResumeAll( void ) * tasks from this list into their appropriate ready list. */ taskENTER_CRITICAL(); { - --uxSchedulerSuspended; + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); - if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + --uxSchedulerSuspended[ xCurCoreID ]; + + if( uxSchedulerSuspended[ xCurCoreID ] == ( UBaseType_t ) pdFALSE ) { if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ) { /* Move any readied tasks from the pending list into the * appropriate ready list. */ - while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) + while( listLIST_IS_EMPTY( &xPendingReadyList[ xCurCoreID ] ) == pdFALSE ) { - pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList[ xCurCoreID ] ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ listREMOVE_ITEM( &( pxTCB->xEventListItem ) ); portMEMORY_BARRIER(); listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); @@ -2209,9 +2438,9 @@ BaseType_t xTaskResumeAll( void ) /* If the moved task has a priority higher than or equal to * the current task then a yield must be performed. */ - if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED( pxTCB, xCurCoreID, pdTRUE ) == pdTRUE ) { - xYieldPending = pdTRUE; + xYieldPending[ xCurCoreID ] = pdTRUE; } else { @@ -2230,6 +2459,13 @@ BaseType_t xTaskResumeAll( void ) prvResetNextTaskUnblockTime(); } + #if ( configNUMBER_OF_CORES > 1 ) + + /* Core 0 is solely responsible for managing tick count, thus it + * must be the only core to unwind the pended ticks */ + if( xCurCoreID == 0 ) + #endif + /* If any ticks occurred while the scheduler was suspended then * they should be processed now. This ensures the tick count does * not slip, and that any delayed tasks are resumed at the correct @@ -2243,7 +2479,7 @@ BaseType_t xTaskResumeAll( void ) { if( xTaskIncrementTick() != pdFALSE ) { - xYieldPending = pdTRUE; + xYieldPending[ xCurCoreID ] = pdTRUE; } else { @@ -2261,7 +2497,7 @@ BaseType_t xTaskResumeAll( void ) } } - if( xYieldPending != pdFALSE ) + if( xYieldPending[ xCurCoreID ] != pdFALSE ) { #if ( configUSE_PREEMPTION != 0 ) { @@ -2615,10 +2851,7 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char TaskHandle_t xTaskGetIdleTaskHandle( void ) { - /* If xTaskGetIdleTaskHandle() is called before the scheduler has been - * started, then xIdleTaskHandle will be NULL. */ - configASSERT( ( xIdleTaskHandle != NULL ) ); - return xIdleTaskHandle; + return xTaskGetIdleTaskHandleForCore( portGET_CORE_ID() ); } #endif /* INCLUDE_xTaskGetIdleTaskHandle */ @@ -2632,34 +2865,35 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char void vTaskStepTick( TickType_t xTicksToJump ) { - /* Correct the tick count value after a period during which the tick - * was suppressed. Note this does *not* call the tick hook function for - * each stepped tick. */ - configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime ); - - if( ( xTickCount + xTicksToJump ) == xNextTaskUnblockTime ) + /* SINGLE-CORE MODIFICATION: Expanded critical section to ensure thread + * safe access to xTickCount between multiple cores. */ + taskENTER_CRITICAL(); { - /* Arrange for xTickCount to reach xNextTaskUnblockTime in - * xTaskIncrementTick() when the scheduler resumes. This ensures - * that any delayed tasks are resumed at the correct time. */ - configASSERT( uxSchedulerSuspended ); - configASSERT( xTicksToJump != ( TickType_t ) 0 ); + /* Correct the tick count value after a period during which the tick + * was suppressed. Note this does *not* call the tick hook function for + * each stepped tick. */ + configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime ); - /* Prevent the tick interrupt modifying xPendedTicks simultaneously. */ - taskENTER_CRITICAL(); + if( ( xTickCount + xTicksToJump ) == xNextTaskUnblockTime ) { + /* Arrange for xTickCount to reach xNextTaskUnblockTime in + * xTaskIncrementTick() when the scheduler resumes. This ensures + * that any delayed tasks are resumed at the correct time. */ + configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdTRUE ); + configASSERT( xTicksToJump != ( TickType_t ) 0 ); + xPendedTicks++; + xTicksToJump--; + } + else + { + mtCOVERAGE_TEST_MARKER(); } - taskEXIT_CRITICAL(); - xTicksToJump--; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - xTickCount += xTicksToJump; - traceINCREASE_TICK_COUNT( xTicksToJump ); + xTickCount += xTicksToJump; + traceINCREASE_TICK_COUNT( xTicksToJump ); + } + taskEXIT_CRITICAL(); } #endif /* configUSE_TICKLESS_IDLE */ @@ -2671,7 +2905,7 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) /* Must not be called with the scheduler suspended as the implementation * relies on xPendedTicks being wound down to 0 in xTaskResumeAll(). */ - configASSERT( uxSchedulerSuspended == 0 ); + configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE ); /* Use xPendedTicks to mimic xTicksToCatchUp number of ticks occurring when * the scheduler is suspended so the ticks are executed in xTaskResumeAll(). */ @@ -2740,14 +2974,17 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) * switch if preemption is turned off. */ #if ( configUSE_PREEMPTION == 1 ) { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* Preemption is on, but a context switch should only be * performed if the unblocked task has a priority that is * higher than the currently executing task. */ - if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED( pxTCB, xCurCoreID, pdFALSE ) == pdTRUE ) { /* Pend the yield to be performed when the scheduler * is unsuspended. */ - xYieldPending = pdTRUE; + xYieldPending[ xCurCoreID ] = pdTRUE; } else { @@ -2771,6 +3008,11 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) BaseType_t xTaskIncrementTick( void ) { + #if ( configNUMBER_OF_CORES > 1 ) + /* Only Core 0 should ever call this function. */ + configASSERT( portGET_CORE_ID() == 0 ); + #endif /* configNUMBER_OF_CORES > 1 */ + TCB_t * pxTCB; TickType_t xItemValue; BaseType_t xSwitchRequired = pdFALSE; @@ -2780,7 +3022,7 @@ BaseType_t xTaskIncrementTick( void ) * tasks to be unblocked. */ traceTASK_INCREMENT_TICK( xTickCount ); - if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + if( uxSchedulerSuspended[ 0 ] == ( UBaseType_t ) pdFALSE ) { /* Minor optimisation. The tick count cannot change in this * block. */ @@ -2864,14 +3106,15 @@ BaseType_t xTaskIncrementTick( void ) #if ( configUSE_PREEMPTION == 1 ) { /* Preemption is on, but a context switch should - * only be performed if the unblocked task's - * priority is higher than the currently executing - * task. - * The case of equal priority tasks sharing - * processing time (which happens when both - * preemption and time slicing are on) is - * handled below.*/ - if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + * only be performed if the unblocked task has a + * priority that is equal to or higher than the + * currently executing task. + * + * For SMP, since this function is only run on core + * 0, we only need to context switch if the unblocked + * task can run on core 0 and has a higher priority + * than the current task. */ + if( ( taskIS_AFFINITY_COMPATIBLE( 0, pxTCB->xCoreID ) == pdTRUE ) && ( pxTCB->uxPriority > pxCurrentTCBs[ 0 ]->uxPriority ) ) { xSwitchRequired = pdTRUE; } @@ -2890,7 +3133,7 @@ BaseType_t xTaskIncrementTick( void ) * writer has not explicitly turned time slicing off. */ #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) { - if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 ) + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCBs[ 0 ]->uxPriority ] ) ) > ( UBaseType_t ) 1 ) { xSwitchRequired = pdTRUE; } @@ -2905,7 +3148,7 @@ BaseType_t xTaskIncrementTick( void ) { /* Guard against the tick hook being called when the pended tick * count is being unwound (when the scheduler is being unlocked). */ - if( xPendedTicks == ( TickType_t ) 0 ) + if( xPendedTicksTemp == ( TickType_t ) 0 ) { vApplicationTickHook(); } @@ -2918,7 +3161,7 @@ BaseType_t xTaskIncrementTick( void ) #if ( configUSE_PREEMPTION == 1 ) { - if( xYieldPending != pdFALSE ) + if( xYieldPending[ 0 ] != pdFALSE ) { xSwitchRequired = pdTRUE; } @@ -2957,7 +3200,7 @@ BaseType_t xTaskIncrementTick( void ) * getting set. */ if( xTask == NULL ) { - xTCB = ( TCB_t * ) pxCurrentTCB; + xTCB = ( TCB_t * ) xTaskGetCurrentTaskHandle(); } else { @@ -3036,7 +3279,7 @@ BaseType_t xTaskIncrementTick( void ) /* If xTask is NULL then we are calling our own task hook. */ if( xTask == NULL ) { - xTCB = pxCurrentTCB; + xTCB = xTaskGetCurrentTaskHandle(); } else { @@ -3058,17 +3301,111 @@ BaseType_t xTaskIncrementTick( void ) #endif /* configUSE_APPLICATION_TASK_TAG */ /*-----------------------------------------------------------*/ +#if ( configNUMBER_OF_CORES > 1 ) + + static void prvSelectHighestPriorityTaskSMP( void ) + { + /* This function is called from a critical section. So some optimizations are made */ + BaseType_t uxCurPriority; + BaseType_t xTaskScheduled = pdFALSE; + BaseType_t xNewTopPrioritySet = pdFALSE; + BaseType_t xCurCoreID = portGET_CORE_ID(); + + /* Search for tasks, starting form the highest ready priority. If nothing is + * found, we eventually default to the IDLE tasks at priority 0 */ + + for( uxCurPriority = uxTopReadyPriority; uxCurPriority >= 0 && xTaskScheduled == pdFALSE; uxCurPriority-- ) + { + /* Check if current priority has one or more ready tasks. Skip if none */ + if( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxCurPriority ] ) ) ) + { + continue; + } + + /* Save a copy of highest priority that has a ready state task */ + if( xNewTopPrioritySet == pdFALSE ) + { + xNewTopPrioritySet = pdTRUE; + uxTopReadyPriority = uxCurPriority; + } + + /* We now search this priority's ready task list for a runnable task. + * We always start searching from the head of the list, so we reset + * pxIndex to point to the tail so that we start walking the list from + * the first item */ + pxReadyTasksLists[ uxCurPriority ].pxIndex = ( ListItem_t * ) &( pxReadyTasksLists[ uxCurPriority ].xListEnd ); + + /* Get the first item on the list */ + TCB_t * pxTCBCur; + TCB_t * pxTCBFirst; + listGET_OWNER_OF_NEXT_ENTRY( pxTCBCur, &( pxReadyTasksLists[ uxCurPriority ] ) ); + pxTCBFirst = pxTCBCur; + + do + { + /* Check if the current task is currently being executed. However, if + * it's being executed by the current core, we can still schedule it. + * Todo: Each task can store a xTaskRunState, instead of needing to + * check each core */ + UBaseType_t x; + + for( x = 0; x < configNUMBER_OF_CORES; x++ ) + { + if( x == xCurCoreID ) + { + continue; + } + else if( pxCurrentTCBs[ x ] == pxTCBCur ) + { + /* Current task is already being executed. Get the next task */ + goto get_next_task; + } + } + + /* Check if the current task has a compatible affinity */ + if( taskIS_AFFINITY_COMPATIBLE( xCurCoreID, pxTCBCur->xCoreID ) == pdFALSE ) + { + goto get_next_task; + } + + /* The current task is runnable. Schedule it */ + pxCurrentTCBs[ xCurCoreID ] = pxTCBCur; + xTaskScheduled = pdTRUE; + + /* Move the current tasks list item to the back of the list in order + * to implement best effort round robin. To do this, we need to reset + * the pxIndex to point to the tail again. */ + pxReadyTasksLists[ uxCurPriority ].pxIndex = ( ListItem_t * ) &( pxReadyTasksLists[ uxCurPriority ].xListEnd ); + listREMOVE_ITEM( &( pxTCBCur->xStateListItem ) ); + listINSERT_END( &( pxReadyTasksLists[ uxCurPriority ] ), &( pxTCBCur->xStateListItem ) ); + break; + +get_next_task: + /* The current task cannot be scheduled. Get the next task in the list */ + listGET_OWNER_OF_NEXT_ENTRY( pxTCBCur, &( pxReadyTasksLists[ uxCurPriority ] ) ); + } while( pxTCBCur != pxTCBFirst ); /* Check to see if we've walked the entire list */ + } + + configASSERT( xTaskScheduled == pdTRUE ); /* At this point, a task MUST have been scheduled */ + } + +#endif /* configNUMBER_OF_CORES > 1 */ +/*-----------------------------------------------------------*/ + void vTaskSwitchContext( void ) { - if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE ) + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + + if( uxSchedulerSuspended[ xCurCoreID ] != ( UBaseType_t ) pdFALSE ) { /* The scheduler is currently suspended - do not allow a context * switch. */ - xYieldPending = pdTRUE; + xYieldPending[ xCurCoreID ] = pdTRUE; } else { - xYieldPending = pdFALSE; + xYieldPending[ xCurCoreID ] = pdFALSE; traceTASK_SWITCHED_OUT(); #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -3086,26 +3423,26 @@ void vTaskSwitchContext( void ) * overflows. The guard against negative values is to protect * against suspect run time stat counter implementations - which * are provided by the application, not the kernel. */ - if( ulTotalRunTime > ulTaskSwitchedInTime ) + if( ulTotalRunTime > ulTaskSwitchedInTime[ xCurCoreID ] ) { - pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); + pxCurrentTCBs[ xCurCoreID ]->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime[ xCurCoreID ] ); } else { mtCOVERAGE_TEST_MARKER(); } - ulTaskSwitchedInTime = ulTotalRunTime; + ulTaskSwitchedInTime[ xCurCoreID ] = ulTotalRunTime; } #endif /* configGENERATE_RUN_TIME_STATS */ /* Check for stack overflow, if configured. */ - taskCHECK_FOR_STACK_OVERFLOW(); + taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ); /* Before the currently running task is switched out, save its errno. */ #if ( configUSE_POSIX_ERRNO == 1 ) { - pxCurrentTCB->iTaskErrno = FreeRTOS_errno; + pxCurrentTCBs[ xCurCoreID ]->iTaskErrno = FreeRTOS_errno; } #endif @@ -3117,7 +3454,7 @@ void vTaskSwitchContext( void ) /* After the new task is switched in, update the global errno. */ #if ( configUSE_POSIX_ERRNO == 1 ) { - FreeRTOS_errno = pxCurrentTCB->iTaskErrno; + FreeRTOS_errno = pxCurrentTCBs[ xCurCoreID ]->iTaskErrno; } #endif @@ -3125,7 +3462,7 @@ void vTaskSwitchContext( void ) { /* Switch C-Runtime's TLS Block to point to the TLS * Block specific to this task. */ - configSET_TLS_BLOCK( pxCurrentTCB->xTLSBlock ); + configSET_TLS_BLOCK( pxCurrentTCBs[ xCurCoreID ]->xTLSBlock ); } #endif } @@ -3151,7 +3488,7 @@ void vTaskPlaceOnEventList( List_t * const pxEventList, * * The queue that contains the event list is locked, preventing * simultaneous access from interrupts. */ - vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + vListInsert( pxEventList, &( pxCurrentTCBs[ portGET_CORE_ID() ]->xEventListItem ) ); prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); } @@ -3161,23 +3498,26 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + configASSERT( pxEventList ); /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by * the event groups implementation. */ - configASSERT( uxSchedulerSuspended != 0 ); + configASSERT( uxSchedulerSuspended[ xCurCoreID ] != 0 ); /* Store the item value in the event list item. It is safe to access the * event list item here as interrupts won't access the event list item of a * task that is not in the Blocked state. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); + listSET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); /* Place the event list item of the TCB at the end of the appropriate event * list. It is safe to access the event list here because it is part of an * event group implementation - and interrupts don't access event groups * directly (instead they access them indirectly by pending function calls to * the task level). */ - listINSERT_END( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + listINSERT_END( pxEventList, &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ) ); prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); } @@ -3201,7 +3541,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, * In this case it is assume that this is the only task that is going to * be waiting on this event list, so the faster vListInsertEnd() function * can be used in place of vListInsert. */ - listINSERT_END( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + listINSERT_END( pxEventList, &( pxCurrentTCBs[ portGET_CORE_ID() ]->xEventListItem ) ); /* If the task should block indefinitely then set the block time to a * value that will be recognised as an indefinite delay inside the @@ -3218,82 +3558,178 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, #endif /* configUSE_TIMERS */ /*-----------------------------------------------------------*/ -BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) -{ - TCB_t * pxUnblockedTCB; - BaseType_t xReturn; +#if ( configNUMBER_OF_CORES > 1 ) - /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be - * called from a critical section within an ISR. */ + BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) + { + TCB_t * pxUnblockedTCB; + BaseType_t xReturn; - /* The event list is sorted in priority order, so the first in the list can - * be removed as it is known to be the highest priority. Remove the TCB from - * the delayed list, and add it to the ready list. - * - * If an event is for a queue that is locked then this function will never - * get called - the lock count on the queue will get modified instead. This - * means exclusive access to the event list is guaranteed here. - * - * This function assumes that a check has already been made to ensure that - * pxEventList is not empty. */ - pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ - configASSERT( pxUnblockedTCB ); - listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) ); + /* Before taking the kernel lock, another task/ISR could have already + * emptied the pxEventList. So we insert a check here to see if + * pxEventList is empty before attempting to remove an item from it. */ + if( listLIST_IS_EMPTY( pxEventList ) == pdFALSE ) + { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); - if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) - { - listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); - prvAddTaskToReadyList( pxUnblockedTCB ); + /* Remove the task from its current event list */ + pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + configASSERT( pxUnblockedTCB ); + listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) ); - #if ( configUSE_TICKLESS_IDLE != 0 ) + /* Add the task to the ready list if a core with compatible affinity + * has NOT suspended its scheduler. This occurs when: + * - The task is pinned, and the pinned core's scheduler is running + * - The task is unpinned, and at least one of the core's scheduler is running */ + if( taskCAN_BE_SCHEDULED( pxUnblockedTCB ) == pdTRUE ) + { + listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + + #if ( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + * might be set to the blocked task's time out time. If the task is + * unblocked for a reason other than a timeout xNextTaskUnblockTime is + * normally left unchanged, because it is automatically reset to a new + * value when the tick count equals xNextTaskUnblockTime. However if + * tickless idling is used it might be more important to enter sleep mode + * at the earliest possible time - so reset xNextTaskUnblockTime here to + * ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + } + else + { + /* We arrive here due to one of the following possibilities: + * - The task is pinned to core X and core X has suspended its scheduler + * - The task is unpinned and both cores have suspend their schedulers + * Therefore, we add the task to one of the pending lists: + * - If the task is pinned to core X, add it to core X's pending list + * - If the task is unpinned, add it to the current core's pending list */ + UBaseType_t uxPendCore = ( ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) ? xCurCoreID : pxUnblockedTCB->xCoreID ); + configASSERT( uxSchedulerSuspended[ uxPendCore ] != ( UBaseType_t ) 0U ); + + /* Add the task to the current core's pending list */ + listINSERT_END( &( xPendingReadyList[ uxPendCore ] ), &( pxUnblockedTCB->xEventListItem ) ); + } + + if( taskIS_YIELD_REQUIRED( pxUnblockedTCB, xCurCoreID, pdFALSE ) == pdTRUE ) + { + /* The unblocked task requires a the current core to yield */ + xReturn = pdTRUE; + + /* Mark that a yield is pending in case the user is not using the + * "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + xYieldPending[ xCurCoreID ] = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + else { - /* If a task is blocked on a kernel object then xNextTaskUnblockTime - * might be set to the blocked task's time out time. If the task is - * unblocked for a reason other than a timeout xNextTaskUnblockTime is - * normally left unchanged, because it is automatically reset to a new - * value when the tick count equals xNextTaskUnblockTime. However if - * tickless idling is used it might be more important to enter sleep mode - * at the earliest possible time - so reset xNextTaskUnblockTime here to - * ensure it is updated at the earliest possible time. */ - prvResetNextTaskUnblockTime(); + /* The pxEventList was emptied before we entered the critical + * section, Nothing to do except return pdFALSE. */ + xReturn = pdFALSE; } - #endif - } - else - { - /* The delayed and ready lists cannot be accessed, so hold this task - * pending until the scheduler is resumed. */ - listINSERT_END( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); - } - if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) - { - /* Return true if the task removed from the event list has a higher - * priority than the calling task. This allows the calling task to know if - * it should force a context switch now. */ - xReturn = pdTRUE; - - /* Mark that a yield is pending in case the user is not using the - * "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ - xYieldPending = pdTRUE; + return xReturn; } - else + +#else /* configNUMBER_OF_CORES > 1 */ + + BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) { - xReturn = pdFALSE; + TCB_t * pxUnblockedTCB; + BaseType_t xReturn; + + /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be + * called from a critical section within an ISR. */ + + /* The event list is sorted in priority order, so the first in the list can + * be removed as it is known to be the highest priority. Remove the TCB from + * the delayed list, and add it to the ready list. + * + * If an event is for a queue that is locked then this function will never + * get called - the lock count on the queue will get modified instead. This + * means exclusive access to the event list is guaranteed here. + * + * This function assumes that a check has already been made to ensure that + * pxEventList is not empty. */ + pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ + configASSERT( pxUnblockedTCB ); + listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) ); + + if( uxSchedulerSuspended[ 0 ] == ( UBaseType_t ) pdFALSE ) + { + listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + + #if ( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + * might be set to the blocked task's time out time. If the task is + * unblocked for a reason other than a timeout xNextTaskUnblockTime is + * normally left unchanged, because it is automatically reset to a new + * value when the tick count equals xNextTaskUnblockTime. However if + * tickless idling is used it might be more important to enter sleep mode + * at the earliest possible time - so reset xNextTaskUnblockTime here to + * ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + } + else + { + /* The delayed and ready lists cannot be accessed, so hold this task + * pending until the scheduler is resumed. */ + listINSERT_END( &( xPendingReadyList[ 0 ] ), &( pxUnblockedTCB->xEventListItem ) ); + } + + if( pxUnblockedTCB->uxPriority > pxCurrentTCBs[ 0 ]->uxPriority ) + { + /* Return true if the task removed from the event list has a higher + * priority than the calling task. This allows the calling task to know if + * it should force a context switch now. */ + xReturn = pdTRUE; + + /* Mark that a yield is pending in case the user is not using the + * "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + xYieldPending[ 0 ] = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; } - return xReturn; -} +#endif /* configNUMBER_OF_CORES > 1 */ /*-----------------------------------------------------------*/ void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) { TCB_t * pxUnblockedTCB; + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); - /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by - * the event flags implementation. */ - configASSERT( uxSchedulerSuspended != pdFALSE ); + #if ( configNUM_CORES > 1 ) + + /* THIS FUNCTION MUST BE CALLED WITH THE KERNEL LOCK ALREADY TAKEN. + * It is used by the event flags implementation, thus those functions + * should call prvTakeKernelLock() before calling this function. */ + #else /* configNUM_CORES > 1 */ + + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by + * the event flags implementation. */ + configASSERT( uxSchedulerSuspended[ 0 ] != ( UBaseType_t ) 0U ); + #endif /* configNUM_CORES > 1 */ /* Store the new item value in the event list. */ listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); @@ -3318,19 +3754,50 @@ void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, } #endif - /* Remove the task from the delayed list and add it to the ready list. The - * scheduler is suspended so interrupts will not be accessing the ready - * lists. */ - listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); - prvAddTaskToReadyList( pxUnblockedTCB ); + #if ( configNUM_CORES > 1 ) - if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) + /* Add the task to the ready list if a core with compatible affinity + * has NOT suspended its scheduler. This occurs when: + * - The task is pinned, and the pinned core's scheduler is running + * - The task is unpinned, and at least one of the core's scheduler is + * running */ + if( taskCAN_BE_SCHEDULED( pxUnblockedTCB ) == pdFALSE ) + { + /* We arrive here due to one of the following possibilities: + * - The task is pinned to core X and core X has suspended its scheduler + * - The task is unpinned and both cores have suspend their schedulers + * Therefore, we add the task to one of the pending lists: + * - If the task is pinned to core X, add it to core X's pending list + * - If the task is unpinned, add it to the current core's pending list */ + BaseType_t xPendingListCore = ( ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) ? xCurCoreID : pxUnblockedTCB->xCoreID ); + configASSERT( uxSchedulerSuspended[ xPendingListCore ] != ( UBaseType_t ) 0U ); + + /* The delayed and ready lists cannot be accessed, so hold this task + * pending until the scheduler is resumed. */ + listINSERT_END( &( xPendingReadyList[ xPendingListCore ] ), &( pxUnblockedTCB->xEventListItem ) ); + } + else + #else /* configNUM_CORES > 1 */ + + /* In single core, the caller of this function has already suspended the + * scheduler, which means we have exclusive access to the ready list. + * We add the unblocked task to the ready list directly. */ + #endif /* configNUM_CORES > 1 */ { - /* The unblocked task has a priority above that of the calling task, so - * a context switch is required. This function is called with the - * scheduler suspended so xYieldPending is set so the context switch - * occurs immediately that the scheduler is resumed (unsuspended). */ - xYieldPending = pdTRUE; + /* Remove the task from the delayed list and add it to the ready list. The + * scheduler is suspended so interrupts will not be accessing the ready + * lists. */ + listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + + if( taskIS_YIELD_REQUIRED( pxUnblockedTCB, xCurCoreID, pdFALSE ) == pdTRUE ) + { + /* The unblocked task has a priority above that of the calling task, so + * a context switch is required. This function is called with the + * scheduler suspended so xYieldPending is set so the context switch + * occurs immediately that the scheduler is resumed (unsuspended). */ + xYieldPending[ xCurCoreID ] = pdTRUE; + } } } /*-----------------------------------------------------------*/ @@ -3368,13 +3835,15 @@ BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, /* Minor optimisation. The tick count cannot change in this block. */ const TickType_t xConstTickCount = xTickCount; const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering; + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); #if ( INCLUDE_xTaskAbortDelay == 1 ) - if( pxCurrentTCB->ucDelayAborted != ( uint8_t ) pdFALSE ) + if( pxCurrentTCBs[ xCurCoreID ]->ucDelayAborted != ( uint8_t ) pdFALSE ) { /* The delay was aborted, which is not the same as a time out, * but has the same result. */ - pxCurrentTCB->ucDelayAborted = pdFALSE; + pxCurrentTCBs[ xCurCoreID ]->ucDelayAborted = pdFALSE; xReturn = pdTRUE; } else @@ -3422,7 +3891,7 @@ BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, void vTaskMissedYield( void ) { - xYieldPending = pdTRUE; + xYieldPending[ portGET_CORE_ID() ] = pdTRUE; } /*-----------------------------------------------------------*/ @@ -3606,23 +4075,28 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) /* This function must be called from a critical section. */ - if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + + if( listCURRENT_LIST_LENGTH( &xPendingReadyList[ xCurCoreID ] ) != 0 ) { /* A task was made ready while the scheduler was suspended. */ eReturn = eAbortSleep; } - else if( xYieldPending != pdFALSE ) + else if( xYieldPending[ xCurCoreID ] != pdFALSE ) { /* A yield was pended while the scheduler was suspended. */ eReturn = eAbortSleep; } - else if( xPendedTicks != 0 ) - { - /* A tick interrupt has already occurred but was held pending - * because the scheduler is suspended. */ - eReturn = eAbortSleep; - } + #if ( configNUMBER_OF_CORES == 1 ) + else if( xPendedTicks != 0 ) + { + /* A tick interrupt has already occurred but was held pending + * because the scheduler is suspended. */ + eReturn = eAbortSleep; + } + #endif /* configNUMBER_OF_CORES == 1 */ #if ( INCLUDE_vTaskSuspend == 1 ) else if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) ) { @@ -3709,6 +4183,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) static void prvInitialiseTaskLists( void ) { UBaseType_t uxPriority; + UBaseType_t x; for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ ) { @@ -3717,7 +4192,11 @@ static void prvInitialiseTaskLists( void ) vListInitialise( &xDelayedTaskList1 ); vListInitialise( &xDelayedTaskList2 ); - vListInitialise( &xPendingReadyList ); + + for( x = 0; x < configNUMBER_OF_CORES; x++ ) + { + vListInitialise( &xPendingReadyList[ x ] ); + } #if ( INCLUDE_vTaskDelete == 1 ) { @@ -3750,16 +4229,58 @@ static void prvCheckTasksWaitingTermination( void ) * being called too often in the idle task. */ while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U ) { - taskENTER_CRITICAL(); + #if ( configNUMBER_OF_CORES > 1 ) { - pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ - ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); - --uxCurrentNumberOfTasks; - --uxDeletedTasksWaitingCleanUp; - } - taskEXIT_CRITICAL(); + pxTCB = NULL; + taskENTER_CRITICAL(); + { + /* List may have already been cleared by the other core. Check again */ + if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE ) + { + /* We can't delete a task if it is still running on + * the other core. Keep walking the list until we + * find a task we can free, or until we walk the + * entire list. */ + ListItem_t * xEntry; - prvDeleteTCB( pxTCB ); + for( xEntry = listGET_HEAD_ENTRY( &xTasksWaitingTermination ); xEntry != listGET_END_MARKER( &xTasksWaitingTermination ); xEntry = listGET_NEXT( xEntry ) ) + { + if( taskIS_CURRENTLY_RUNNING( ( ( TCB_t * ) listGET_LIST_ITEM_OWNER( xEntry ) ) ) == pdFALSE ) + { + pxTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( xEntry ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + --uxCurrentNumberOfTasks; + --uxDeletedTasksWaitingCleanUp; + break; + } + } + } + } + taskEXIT_CRITICAL(); + + if( pxTCB != NULL ) + { + prvDeleteTCB( pxTCB ); + } + else + { + /* No task found to delete, break out of loop */ + break; + } + } + #else /* configNUMBER_OF_CORES > 1 */ + { + taskENTER_CRITICAL(); + { + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + --uxCurrentNumberOfTasks; + --uxDeletedTasksWaitingCleanUp; + } + taskEXIT_CRITICAL(); + prvDeleteTCB( pxTCB ); + } + #endif /* configNUMBER_OF_CORES > 1 */ } } #endif /* INCLUDE_vTaskDelete */ @@ -3787,6 +4308,8 @@ static void prvCheckTasksWaitingTermination( void ) pxTaskStatus->pxEndOfStack = pxTCB->pxEndOfStack; #endif pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; + /* Todo: Remove xCoreID for single core builds (IDF-7894) */ + pxTaskStatus->xCoreID = pxTCB->xCoreID; #if ( configUSE_MUTEXES == 1 ) { @@ -3813,7 +4336,7 @@ static void prvCheckTasksWaitingTermination( void ) * state is just set to whatever is passed in. */ if( eState != eInvalid ) { - if( pxTCB == pxCurrentTCB ) + if( pxTCB == pxCurrentTCBs[ portGET_CORE_ID() ] ) { pxTaskStatus->eCurrentState = eRunning; } @@ -4005,7 +4528,8 @@ static void prvCheckTasksWaitingTermination( void ) #if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) ) { /* Free up the memory allocated for the task's TLS Block. */ - configDEINIT_TLS_BLOCK( pxCurrentTCB->xTLSBlock ); + /* Note: Fixed bug in upstream. Free TLS block of pxTCB, NOT pxCurrentTCBs */ + configDEINIT_TLS_BLOCK( pxTCB->xTLSBlock ); } #endif @@ -4073,14 +4597,7 @@ static void prvResetNextTaskUnblockTime( void ) TaskHandle_t xTaskGetCurrentTaskHandle( void ) { - TaskHandle_t xReturn; - - /* A critical section is not required as this is not called from - * an interrupt and the current TCB will always be the same for any - * individual execution thread. */ - xReturn = pxCurrentTCB; - - return xReturn; + return xTaskGetCurrentTaskHandleForCore( portGET_CORE_ID() ); } #endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ @@ -4098,7 +4615,7 @@ static void prvResetNextTaskUnblockTime( void ) } else { - if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + if( uxSchedulerSuspended[ portGET_CORE_ID() ] == ( UBaseType_t ) pdFALSE ) { xReturn = taskSCHEDULER_RUNNING; } @@ -4121,6 +4638,9 @@ static void prvResetNextTaskUnblockTime( void ) TCB_t * const pxMutexHolderTCB = pxMutexHolder; BaseType_t xReturn = pdFALSE; + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* If the mutex was given back by an interrupt while the queue was * locked then the mutex holder might now be NULL. _RB_ Is this still * needed as interrupts can no longer use mutexes? */ @@ -4129,14 +4649,14 @@ static void prvResetNextTaskUnblockTime( void ) /* If the holder of the mutex has a priority below the priority of * the task attempting to obtain the mutex then it will temporarily * inherit the priority of the task attempting to obtain the mutex. */ - if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority ) + if( pxMutexHolderTCB->uxPriority < pxCurrentTCBs[ xCurCoreID ]->uxPriority ) { /* Adjust the mutex holder state to account for its new * priority. Only reset the event list item value if the value is * not being used for anything else. */ if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) { - listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCBs[ xCurCoreID ]->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } else { @@ -4160,23 +4680,23 @@ static void prvResetNextTaskUnblockTime( void ) } /* Inherit the priority before being moved into the new list. */ - pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; + pxMutexHolderTCB->uxPriority = pxCurrentTCBs[ xCurCoreID ]->uxPriority; prvAddTaskToReadyList( pxMutexHolderTCB ); } else { /* Just inherit the priority. */ - pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; + pxMutexHolderTCB->uxPriority = pxCurrentTCBs[ xCurCoreID ]->uxPriority; } - traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority ); + traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCBs[ xCurCoreID ]->uxPriority ); /* Inheritance occurred. */ xReturn = pdTRUE; } else { - if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority ) + if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCBs[ xCurCoreID ]->uxPriority ) { /* The base priority of the mutex holder is lower than the * priority of the task attempting to take the mutex, but the @@ -4217,7 +4737,7 @@ static void prvResetNextTaskUnblockTime( void ) * If the mutex is held by a task then it cannot be given from an * interrupt, and if a mutex is given by the holding task then it must * be the running state task. */ - configASSERT( pxTCB == pxCurrentTCB ); + configASSERT( pxTCB == pxCurrentTCBs[ portGET_CORE_ID() ] ); configASSERT( pxTCB->uxMutexesHeld ); ( pxTCB->uxMutexesHeld )--; @@ -4324,7 +4844,7 @@ static void prvResetNextTaskUnblockTime( void ) /* If a task has timed out because it already holds the * mutex it was trying to obtain then it cannot of inherited * its own priority. */ - configASSERT( pxTCB != pxCurrentTCB ); + configASSERT( pxTCB != pxCurrentTCBs[ portGET_CORE_ID() ] ); /* Disinherit the priority, remembering the previous * priority to facilitate determining the subject task's @@ -4398,7 +4918,10 @@ static void prvResetNextTaskUnblockTime( void ) if( xSchedulerRunning != pdFALSE ) { - ( pxCurrentTCB->uxCriticalNesting )++; + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + + ( pxCurrentTCBs[ xCurCoreID ]->uxCriticalNesting )++; /* This is not the interrupt safe version of the enter critical * function so assert() if it is being called from an interrupt @@ -4406,7 +4929,7 @@ static void prvResetNextTaskUnblockTime( void ) * interrupt. Only assert if the critical nesting count is 1 to * protect against recursive calls if the assert function also uses a * critical section. */ - if( pxCurrentTCB->uxCriticalNesting == 1 ) + if( pxCurrentTCBs[ xCurCoreID ]->uxCriticalNesting == 1 ) { portASSERT_IF_IN_ISR(); } @@ -4426,11 +4949,14 @@ static void prvResetNextTaskUnblockTime( void ) { if( xSchedulerRunning != pdFALSE ) { - if( pxCurrentTCB->uxCriticalNesting > 0U ) + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + + if( pxCurrentTCBs[ xCurCoreID ]->uxCriticalNesting > 0U ) { - ( pxCurrentTCB->uxCriticalNesting )--; + ( pxCurrentTCBs[ xCurCoreID ]->uxCriticalNesting )--; - if( pxCurrentTCB->uxCriticalNesting == 0U ) + if( pxCurrentTCBs[ xCurCoreID ]->uxCriticalNesting == 0U ) { portENABLE_INTERRUPTS(); } @@ -4569,8 +5095,8 @@ static void prvResetNextTaskUnblockTime( void ) pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); /* Write the rest of the string. */ - sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */ - pcWriteBuffer += strlen( pcWriteBuffer ); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */ + sprintf( pcWriteBuffer, "\t%c\t%u\t%d\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, pxTaskStatusArray[ x ].xCoreID, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */ + pcWriteBuffer += strlen( pcWriteBuffer ); /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */ } /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION @@ -4711,11 +5237,14 @@ TickType_t uxTaskResetEventItemValue( void ) { TickType_t uxReturn; - uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) ); + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + + uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ) ); /* Reset the event list item to its normal value - so it can be used with * queues and semaphores. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCBs[ xCurCoreID ]->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ return uxReturn; } @@ -4725,14 +5254,21 @@ TickType_t uxTaskResetEventItemValue( void ) TaskHandle_t pvTaskIncrementMutexHeldCount( void ) { + TaskHandle_t xReturn; + + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* If xSemaphoreCreateMutex() is called before any tasks have been created - * then pxCurrentTCB will be NULL. */ - if( pxCurrentTCB != NULL ) + * then pxCurrentTCBs will be NULL. */ + if( pxCurrentTCBs[ xCurCoreID ] != NULL ) { - ( pxCurrentTCB->uxMutexesHeld )++; + ( pxCurrentTCBs[ xCurCoreID ]->uxMutexesHeld )++; } - return pxCurrentTCB; + xReturn = pxCurrentTCBs[ xCurCoreID ]; + + return xReturn; } #endif /* configUSE_MUTEXES */ @@ -4750,11 +5286,14 @@ TickType_t uxTaskResetEventItemValue( void ) taskENTER_CRITICAL(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* Only block if the notification count is not already non-zero. */ - if( pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] == 0UL ) + if( pxCurrentTCBs[ xCurCoreID ]->ulNotifiedValue[ uxIndexToWait ] == 0UL ) { /* Mark this task as waiting for a notification. */ - pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskWAITING_NOTIFICATION; + pxCurrentTCBs[ xCurCoreID ]->ucNotifyState[ uxIndexToWait ] = taskWAITING_NOTIFICATION; if( xTicksToWait > ( TickType_t ) 0 ) { @@ -4781,18 +5320,21 @@ TickType_t uxTaskResetEventItemValue( void ) taskENTER_CRITICAL(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + traceTASK_NOTIFY_TAKE( uxIndexToWait ); - ulReturn = pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ]; + ulReturn = pxCurrentTCBs[ xCurCoreID ]->ulNotifiedValue[ uxIndexToWait ]; if( ulReturn != 0UL ) { if( xClearCountOnExit != pdFALSE ) { - pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] = 0UL; + pxCurrentTCBs[ xCurCoreID ]->ulNotifiedValue[ uxIndexToWait ] = 0UL; } else { - pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] = ulReturn - ( uint32_t ) 1; + pxCurrentTCBs[ xCurCoreID ]->ulNotifiedValue[ uxIndexToWait ] = ulReturn - ( uint32_t ) 1; } } else @@ -4800,7 +5342,7 @@ TickType_t uxTaskResetEventItemValue( void ) mtCOVERAGE_TEST_MARKER(); } - pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION; + pxCurrentTCBs[ xCurCoreID ]->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION; } taskEXIT_CRITICAL(); @@ -4824,16 +5366,19 @@ TickType_t uxTaskResetEventItemValue( void ) taskENTER_CRITICAL(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* Only block if a notification is not already pending. */ - if( pxCurrentTCB->ucNotifyState[ uxIndexToWait ] != taskNOTIFICATION_RECEIVED ) + if( pxCurrentTCBs[ xCurCoreID ]->ucNotifyState[ uxIndexToWait ] != taskNOTIFICATION_RECEIVED ) { /* Clear bits in the task's notification value as bits may get * set by the notifying task or interrupt. This can be used to * clear the value to zero. */ - pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] &= ~ulBitsToClearOnEntry; + pxCurrentTCBs[ xCurCoreID ]->ulNotifiedValue[ uxIndexToWait ] &= ~ulBitsToClearOnEntry; /* Mark this task as waiting for a notification. */ - pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskWAITING_NOTIFICATION; + pxCurrentTCBs[ xCurCoreID ]->ucNotifyState[ uxIndexToWait ] = taskWAITING_NOTIFICATION; if( xTicksToWait > ( TickType_t ) 0 ) { @@ -4860,20 +5405,23 @@ TickType_t uxTaskResetEventItemValue( void ) taskENTER_CRITICAL(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + traceTASK_NOTIFY_WAIT( uxIndexToWait ); if( pulNotificationValue != NULL ) { /* Output the current notification value, which may or may not * have changed. */ - *pulNotificationValue = pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ]; + *pulNotificationValue = pxCurrentTCBs[ xCurCoreID ]->ulNotifiedValue[ uxIndexToWait ]; } /* If ucNotifyValue is set then either the task never entered the * blocked state (because a notification was already pending) or the * task unblocked because of a notification. Otherwise the task * unblocked because of a timeout. */ - if( pxCurrentTCB->ucNotifyState[ uxIndexToWait ] != taskNOTIFICATION_RECEIVED ) + if( pxCurrentTCBs[ xCurCoreID ]->ucNotifyState[ uxIndexToWait ] != taskNOTIFICATION_RECEIVED ) { /* A notification was not received. */ xReturn = pdFALSE; @@ -4882,11 +5430,11 @@ TickType_t uxTaskResetEventItemValue( void ) { /* A notification was already pending or a notification was * received while the task was waiting. */ - pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] &= ~ulBitsToClearOnExit; + pxCurrentTCBs[ xCurCoreID ]->ulNotifiedValue[ uxIndexToWait ] &= ~ulBitsToClearOnExit; xReturn = pdTRUE; } - pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION; + pxCurrentTCBs[ xCurCoreID ]->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION; } taskEXIT_CRITICAL(); @@ -4995,7 +5543,7 @@ TickType_t uxTaskResetEventItemValue( void ) } #endif - if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED( pxTCB, portGET_CORE_ID(), pdFALSE ) == pdTRUE ) { /* The notified task has a priority above the currently * executing task so a yield is required. */ @@ -5058,6 +5606,9 @@ TickType_t uxTaskResetEventItemValue( void ) uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + if( pulPreviousNotificationValue != NULL ) { *pulPreviousNotificationValue = pxTCB->ulNotifiedValue[ uxIndexToNotify ]; @@ -5118,7 +5669,7 @@ TickType_t uxTaskResetEventItemValue( void ) /* The task should not have been on an event list. */ configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); - if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + if( taskCAN_BE_SCHEDULED( pxTCB ) == pdTRUE ) { listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); @@ -5127,10 +5678,10 @@ TickType_t uxTaskResetEventItemValue( void ) { /* The delayed and ready lists cannot be accessed, so hold * this task pending until the scheduler is resumed. */ - listINSERT_END( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + listINSERT_END( &( xPendingReadyList[ xCurCoreID ] ), &( pxTCB->xEventListItem ) ); } - if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED( pxTCB, xCurCoreID, pdFALSE ) == pdTRUE ) { /* The notified task has a priority above the currently * executing task so a yield is required. */ @@ -5142,7 +5693,7 @@ TickType_t uxTaskResetEventItemValue( void ) /* Mark that a yield is pending in case the user is not * using the "xHigherPriorityTaskWoken" parameter to an ISR * safe FreeRTOS function. */ - xYieldPending = pdTRUE; + xYieldPending[ xCurCoreID ] = pdTRUE; } else { @@ -5193,6 +5744,9 @@ TickType_t uxTaskResetEventItemValue( void ) uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + ucOriginalNotifyState = pxTCB->ucNotifyState[ uxIndexToNotify ]; pxTCB->ucNotifyState[ uxIndexToNotify ] = taskNOTIFICATION_RECEIVED; @@ -5209,7 +5763,7 @@ TickType_t uxTaskResetEventItemValue( void ) /* The task should not have been on an event list. */ configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); - if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + if( taskCAN_BE_SCHEDULED( pxTCB ) == pdTRUE ) { listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); @@ -5218,10 +5772,10 @@ TickType_t uxTaskResetEventItemValue( void ) { /* The delayed and ready lists cannot be accessed, so hold * this task pending until the scheduler is resumed. */ - listINSERT_END( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + listINSERT_END( &( xPendingReadyList[ xCurCoreID ] ), &( pxTCB->xEventListItem ) ); } - if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + if( taskIS_YIELD_REQUIRED( pxTCB, xCurCoreID, pdFALSE ) == pdTRUE ) { /* The notified task has a priority above the currently * executing task so a yield is required. */ @@ -5233,7 +5787,7 @@ TickType_t uxTaskResetEventItemValue( void ) /* Mark that a yield is pending in case the user is not * using the "xHigherPriorityTaskWoken" parameter in an ISR * safe FreeRTOS function. */ - xYieldPending = pdTRUE; + xYieldPending[ xCurCoreID ] = pdTRUE; } else { @@ -5313,7 +5867,7 @@ TickType_t uxTaskResetEventItemValue( void ) configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimeCounter( void ) { - return xIdleTaskHandle->ulRunTimeCounter; + return ulTaskGetIdleRunTimeCounterForCore( portGET_CORE_ID() ); } #endif @@ -5323,24 +5877,7 @@ TickType_t uxTaskResetEventItemValue( void ) configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimePercent( void ) { - configRUN_TIME_COUNTER_TYPE ulTotalTime, ulReturn; - - ulTotalTime = portGET_RUN_TIME_COUNTER_VALUE(); - - /* For percentage calculations. */ - ulTotalTime /= ( configRUN_TIME_COUNTER_TYPE ) 100; - - /* Avoid divide by zero errors. */ - if( ulTotalTime > ( configRUN_TIME_COUNTER_TYPE ) 0 ) - { - ulReturn = xIdleTaskHandle->ulRunTimeCounter / ulTotalTime; - } - else - { - ulReturn = 0; - } - - return ulReturn; + return ulTaskGetIdleRunTimePercentForCore( portGET_CORE_ID() ); } #endif /* if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) */ @@ -5351,23 +5888,39 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, { TickType_t xTimeToWake; const TickType_t xConstTickCount = xTickCount; + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); + + #if ( configNUMBER_OF_CORES > 1 ) + { + if( listIS_CONTAINED_WITHIN( &xTasksWaitingTermination, &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ) ) == pdTRUE ) + { + /* In SMP, it is possible that another core has already deleted the + * current task (via vTaskDelete()) which will result in the current + * task being placed on the waiting termination list. In this case, + * we do nothing and return, the current task will yield as soon + * as it re-enables interrupts. */ + return; + } + } + #endif /* configNUMBER_OF_CORES > 1 */ #if ( INCLUDE_xTaskAbortDelay == 1 ) { /* About to enter a delayed list, so ensure the ucDelayAborted flag is * reset to pdFALSE so it can be detected as having been set to pdTRUE * when the task leaves the Blocked state. */ - pxCurrentTCB->ucDelayAborted = pdFALSE; + pxCurrentTCBs[ xCurCoreID ]->ucDelayAborted = pdFALSE; } #endif /* Remove the task from the ready list before adding it to the blocked list * as the same list item is used for both lists. */ - if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + if( uxListRemove( &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ) ) == ( UBaseType_t ) 0 ) { /* The current task must be in a ready list, so there is no need to * check, and the port reset macro can be called directly. */ - portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); /*lint !e931 pxCurrentTCB cannot change as it is the calling task. pxCurrentTCB->uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */ + portRESET_READY_PRIORITY( pxCurrentTCBs[ xCurCoreID ]->uxPriority, uxTopReadyPriority ); /*lint !e931 pxCurrentTCBs cannot change as it is the calling task. pxCurrentTCBs->uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */ } else { @@ -5381,7 +5934,7 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, /* Add the task to the suspended task list instead of a delayed task * list to ensure it is not woken by a timing event. It will block * indefinitely. */ - listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) ); + listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ) ); } else { @@ -5391,19 +5944,19 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, xTimeToWake = xConstTickCount + xTicksToWait; /* The list item will be inserted in wake time order. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); + listSET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ), xTimeToWake ); if( xTimeToWake < xConstTickCount ) { /* Wake time has overflowed. Place this item in the overflow * list. */ - vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ) ); } else { /* The wake time has not overflowed, so the current block list * is used. */ - vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + vListInsert( pxDelayedTaskList, &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ) ); /* If the task entering the blocked state was placed at the * head of the list of blocked tasks then xNextTaskUnblockTime @@ -5427,17 +5980,17 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, xTimeToWake = xConstTickCount + xTicksToWait; /* The list item will be inserted in wake time order. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); + listSET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ), xTimeToWake ); if( xTimeToWake < xConstTickCount ) { /* Wake time has overflowed. Place this item in the overflow list. */ - vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ) ); } else { /* The wake time has not overflowed, so the current block list is used. */ - vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + vListInsert( pxDelayedTaskList, &( pxCurrentTCBs[ xCurCoreID ]->xStateListItem ) ); /* If the task entering the blocked state was placed at the head of the * list of blocked tasks then xNextTaskUnblockTime needs to be updated diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/timers.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/timers.c index 6803cb8e63c..ba3a2841f2d 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/timers.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/timers.c @@ -252,14 +252,16 @@ StackType_t * pxTimerTaskStackBuffer = NULL; uint32_t ulTimerTaskStackSize; + /* Timer tasks is always pinned to core 0. Todo: IDF-7906 */ vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); - xTimerTaskHandle = xTaskCreateStatic( prvTimerTask, - configTIMER_SERVICE_TASK_NAME, - ulTimerTaskStackSize, - NULL, - ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, - pxTimerTaskStackBuffer, - pxTimerTaskTCBBuffer ); + xTimerTaskHandle = xTaskCreateStaticPinnedToCore( prvTimerTask, + configTIMER_SERVICE_TASK_NAME, + ulTimerTaskStackSize, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + pxTimerTaskStackBuffer, + pxTimerTaskTCBBuffer, + 0 ); if( xTimerTaskHandle != NULL ) { @@ -268,12 +270,14 @@ } #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ { - xReturn = xTaskCreate( prvTimerTask, - configTIMER_SERVICE_TASK_NAME, - configTIMER_TASK_STACK_DEPTH, - NULL, - ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, - &xTimerTaskHandle ); + /* Timer tasks is always pinned to core 0. Todo: IDF-7906 */ + xReturn = xTaskCreatePinnedToCore( prvTimerTask, + configTIMER_SERVICE_TASK_NAME, + configTIMER_TASK_STACK_DEPTH, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + &xTimerTaskHandle, + 0 ); } #endif /* configSUPPORT_STATIC_ALLOCATION */ } diff --git a/components/freertos/config/include/freertos/FreeRTOSConfig.h b/components/freertos/config/include/freertos/FreeRTOSConfig.h index 23c7e21bbea..bc92aad523c 100644 --- a/components/freertos/config/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/config/include/freertos/FreeRTOSConfig.h @@ -107,7 +107,7 @@ /* ----------------------- System -------------------------- */ -#define configMAX_TASK_NAME_LEN CONFIG_FREERTOS_MAX_TASK_NAME_LEN +#define configMAX_TASK_NAME_LEN CONFIG_FREERTOS_MAX_TASK_NAME_LEN /* If deletion callbacks are enabled, the number of TLSP's are doubled (i.e., * the length of the TCB's pvThreadLocalStoragePointersThis array). This allows @@ -257,10 +257,12 @@ #if !CONFIG_FREERTOS_SMP #ifdef CONFIG_FREERTOS_UNICORE - #define configNUM_CORES 1 + #define configNUMBER_OF_CORES 1 #else - #define configNUM_CORES 2 + #define configNUMBER_OF_CORES 2 #endif /* CONFIG_FREERTOS_UNICORE */ + /* For compatibility */ + #define configNUM_CORES configNUMBER_OF_CORES #ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID #define configTASKLIST_INCLUDE_COREID 1 #endif /* CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID */ diff --git a/components/freertos/esp_additions/freertos_tasks_c_additions.h b/components/freertos/esp_additions/freertos_tasks_c_additions.h index f93d36e04a6..e43dfbe071a 100644 --- a/components/freertos/esp_additions/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/freertos_tasks_c_additions.h @@ -405,48 +405,7 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt /* ------------------------------------------------- Task Utilities ------------------------------------------------- */ -#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) - - TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ) - { - configASSERT( xCoreID >= 0 && xCoreID < configNUM_CORES ); - configASSERT( ( xIdleTaskHandle[ xCoreID ] != NULL ) ); - return ( TaskHandle_t ) xIdleTaskHandle[ xCoreID ]; - } - -#endif /* INCLUDE_xTaskGetIdleTaskHandle */ -/*----------------------------------------------------------*/ - -#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) - - TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ) - { - TaskHandle_t xReturn; - - #if CONFIG_FREERTOS_SMP - { - xReturn = xTaskGetCurrentTaskHandleCPU( xCoreID ); - } - #else /* CONFIG_FREERTOS_SMP */ - { - if( xCoreID < configNUM_CORES ) - { - xReturn = pxCurrentTCB[ xCoreID ]; - } - else - { - xReturn = NULL; - } - } - #endif /* CONFIG_FREERTOS_SMP */ - - return xReturn; - } - -#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ -/*----------------------------------------------------------*/ - -BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) +BaseType_t xTaskGetCoreID( TaskHandle_t xTask ) { BaseType_t xReturn; @@ -472,11 +431,10 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) #else /* CONFIG_FREERTOS_SMP */ TCB_t * pxTCB; + /* Todo: Remove xCoreID for single core builds (IDF-7894) */ pxTCB = prvGetTCBFromHandle( xTask ); - /* Simply read the xCoreID member of the TCB */ - taskENTER_CRITICAL( &xKernelLock ); + xReturn = pxTCB->xCoreID; - taskEXIT_CRITICAL_ISR( &xKernelLock ); #endif /* CONFIG_FREERTOS_SMP */ } #else /* configNUM_CORES > 1 */ @@ -490,6 +448,140 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) } /*----------------------------------------------------------*/ +#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + + TaskHandle_t xTaskGetIdleTaskHandleForCore( BaseType_t xCoreID ) + { + #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + { + /* If xTaskGetIdleTaskHandle() is called before the scheduler has been + * started, then xIdleTaskHandle will be NULL. */ + configASSERT( ( xCoreID < configNUMBER_OF_CORES ) && ( xCoreID != tskNO_AFFINITY ) ); + configASSERT( ( xIdleTaskHandle[ xCoreID ] != NULL ) ); + return xIdleTaskHandle[ xCoreID ]; + } + #else /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + { + configASSERT( xCoreID >= 0 && xCoreID < configNUM_CORES ); + configASSERT( ( xIdleTaskHandle[ xCoreID ] != NULL ) ); + return ( TaskHandle_t ) xIdleTaskHandle[ xCoreID ]; + } + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + } + +#endif /* INCLUDE_xTaskGetIdleTaskHandle */ +/*----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) + + TaskHandle_t xTaskGetCurrentTaskHandleForCore( BaseType_t xCoreID ) + { + TaskHandle_t xReturn; + + #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + { + configASSERT( xCoreID < configNUMBER_OF_CORES ); + configASSERT( xCoreID != tskNO_AFFINITY ); + + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. For single core, a critical section is + * not required as this is not called from an interrupt and the current + * TCB will always be the same for any individual execution thread. */ + taskENTER_CRITICAL_SMP_ONLY(); + { + xReturn = pxCurrentTCBs[ xCoreID ]; + } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY(); + } + #else /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + { + #if CONFIG_FREERTOS_SMP + { + xReturn = xTaskGetCurrentTaskHandleCPU( xCoreID ); + } + #else /* CONFIG_FREERTOS_SMP */ + { + if( xCoreID < configNUM_CORES ) + { + xReturn = pxCurrentTCB[ xCoreID ]; + } + else + { + xReturn = NULL; + } + } + #endif /* CONFIG_FREERTOS_SMP */ + } + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + + return xReturn; + } + +#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ +/*----------------------------------------------------------*/ + +#if ( CONFIG_FREERTOS_USE_KERNEL_10_5_1 && ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) + + configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimeCounterForCore( BaseType_t xCoreID ) + { + uint32_t ulRunTimeCounter; + + configASSERT( xCoreID < configNUMBER_OF_CORES ); + configASSERT( xCoreID != tskNO_AFFINITY ); + + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY(); + { + ulRunTimeCounter = xIdleTaskHandle[ xCoreID ]->ulRunTimeCounter; + } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY(); + + return ulRunTimeCounter; + } + +#endif /* ( CONFIG_FREERTOS_USE_KERNEL_10_5_1 && ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) */ +/*----------------------------------------------------------*/ + +#if ( CONFIG_FREERTOS_USE_KERNEL_10_5_1 && ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) + + configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimePercentForCore( BaseType_t xCoreID ) + { + configRUN_TIME_COUNTER_TYPE ulTotalTime, ulReturn; + + configASSERT( xCoreID < configNUMBER_OF_CORES ); + configASSERT( xCoreID != tskNO_AFFINITY ); + + ulTotalTime = portGET_RUN_TIME_COUNTER_VALUE(); + + /* For percentage calculations. */ + ulTotalTime /= ( configRUN_TIME_COUNTER_TYPE ) 100; + + /* Avoid divide by zero errors. */ + if( ulTotalTime > ( configRUN_TIME_COUNTER_TYPE ) 0 ) + { + /* For SMP, we need to take the kernel lock here as we are about + * to access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY(); + { + ulReturn = xIdleTaskHandle[ xCoreID ]->ulRunTimeCounter / ulTotalTime; + } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY(); + } + else + { + ulReturn = 0; + } + + return ulReturn; + } + +#endif /* ( CONFIG_FREERTOS_USE_KERNEL_10_5_1 && ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) */ +/*-----------------------------------------------------------*/ + uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ) { TCB_t * pxTCB; diff --git a/components/freertos/esp_additions/include/freertos/idf_additions.h b/components/freertos/esp_additions/include/freertos/idf_additions.h index 5f2e431bcf9..3b39afe8087 100644 --- a/components/freertos/esp_additions/include/freertos/idf_additions.h +++ b/components/freertos/esp_additions/include/freertos/idf_additions.h @@ -31,6 +31,7 @@ #endif /* *INDENT-ON* */ + /* -------------------------------------------------- Task Creation ------------------------------------------------- */ #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) @@ -108,6 +109,35 @@ /* ------------------------------------------------- Task Utilities ------------------------------------------------- */ +/** + * @brief Get the current core ID of a particular task + * + * Helper function to get the core ID of a particular task. If the task is + * pinned to a particular core, the core ID is returned. If the task is not + * pinned to a particular core, tskNO_AFFINITY is returned. + * + * If CONFIG_FREERTOS_UNICORE is enabled, this function simply returns 0. + * + * [refactor-todo] See if this needs to be deprecated (IDF-8145)(IDF-8164) + * + * @note If CONFIG_FREERTOS_SMP is enabled, please call vTaskCoreAffinityGet() + * instead. + * @note In IDF FreerTOS when configNUMBER_OF_CORES == 1, this function will + * always return 0, + * @param xTask The task to query + * @return The task's core ID or tskNO_AFFINITY + */ +BaseType_t xTaskGetCoreID( TaskHandle_t xTask ); + +/** @cond */ +/* Todo: Deprecate this API in favor of xTaskGetIdleTaskHandleForCore (IDF-8163) */ +static inline __attribute__( ( always_inline ) ) +BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) +{ + return xTaskGetCoreID( xTask ); +} +/** @endcond */ + /** * @brief Get the handle of idle task for the given core. * @@ -118,7 +148,16 @@ * @param xCoreID The core to query * @return Handle of the idle task for the queried core */ -TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ); +TaskHandle_t xTaskGetIdleTaskHandleForCore( BaseType_t xCoreID ); + +/** @cond */ +/* Todo: Deprecate this API in favor of xTaskGetIdleTaskHandleForCore (IDF-8163) */ +static inline __attribute__( ( always_inline ) ) +TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ) +{ + return xTaskGetIdleTaskHandleForCore( xCoreID ); +} +/** @endcond */ /** * @brief Get the handle of the task currently running on a certain core @@ -134,25 +173,42 @@ TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID ); * @param xCoreID The core to query * @return Handle of the current task running on the queried core */ -TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ); +TaskHandle_t xTaskGetCurrentTaskHandleForCore( BaseType_t xCoreID ); + +/** @cond */ +/* Todo: Deprecate this API in favor of xTaskGetCurrentTaskHandleForCore (IDF-8163) */ +static inline __attribute__( ( always_inline ) ) +TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ) +{ + return xTaskGetCurrentTaskHandleForCore( xCoreID ); +} +/** @endcond */ + +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 /** - * @brief Get the current core affinity of a particular task + * @brief Get the total execution of a particular core's idle task * - * Helper function to get the core affinity of a particular task. If the task is - * pinned to a particular core, the core ID is returned. If the task is not - * pinned to a particular core, tskNO_AFFINITY is returned. + * This function is equivalent to ulTaskGetIdleRunTimeCounter() but queries the + * idle task of a particular core. * - * If CONFIG_FREERTOS_UNICORE is enabled, this function simply returns 0. + * @param xCoreID Core ID of the idle task to query + * @return The total run time of the idle task + */ + configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimeCounterForCore( BaseType_t xCoreID ); + +/** + * @brief Get the percentage run time of a particular core's idle task * - * [refactor-todo] See if this needs to be deprecated (IDF-8145)(IDF-8164) + * This function is equivalent to ulTaskGetIdleRunTimePercent() but queries the + * idle task of a particular core. * - * @note If CONFIG_FREERTOS_SMP is enabled, please call vTaskCoreAffinityGet() - * instead. - * @param xTask The task to query - * @return The tasks coreID or tskNO_AFFINITY + * @param xCoreID Core ID of the idle task to query + * @return The percentage run time of the idle task */ -BaseType_t xTaskGetAffinity( TaskHandle_t xTask ); + configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimePercentForCore( BaseType_t xCoreID ); + +#endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ /** * Returns the start of the stack associated with xTask. diff --git a/components/freertos/linker.lf b/components/freertos/linker.lf index 31a1b39cfb1..b66d99bb98e 100644 --- a/components/freertos/linker.lf +++ b/components/freertos/linker.lf @@ -171,6 +171,8 @@ entries: tasks:ulTaskGenericNotifyValueClear (default) if FREERTOS_GENERATE_RUN_TIME_STATS = y: tasks:ulTaskGetIdleRunTimeCounter (default) + if FREERTOS_USE_KERNEL_10_5_1 = y: + tasks:ulTaskGetIdleRunTimePercent (default) tasks:prvAddCurrentTaskToDelayedList (default) if FREERTOS_USE_TRACE_FACILITY = y: tasks:uxTaskGetSystemState (default) @@ -193,6 +195,8 @@ entries: timers:uxTimerGetReloadMode (default) timers:xTimerGetExpiryTime (default) timers:pcTimerGetName (default) + if FREERTOS_USE_KERNEL_10_5_1 = y: + timers:prvReloadTimer (default) timers:prvProcessExpiredTimer (default) timers:prvTimerTask (default) timers:prvProcessTimerOrBlockTask (default) diff --git a/components/freertos/linker_common.lf b/components/freertos/linker_common.lf index d836cf49021..c0824ed7e00 100644 --- a/components/freertos/linker_common.lf +++ b/components/freertos/linker_common.lf @@ -25,10 +25,12 @@ entries: tasks:xTaskCreatePinnedToCore (default) tasks:xTaskCreateStaticPinnedToCore (default) # Task Utilities - tasks:xTaskGetCurrentTaskHandleForCPU (default) - tasks:xTaskGetIdleTaskHandleForCPU (default) - tasks:xTaskGetCurrentTaskHandleForCPU (default) - tasks:xTaskGetAffinity (default) + tasks:xTaskGetCoreID (default) + tasks:xTaskGetIdleTaskHandleForCore (default) + tasks:xTaskGetCurrentTaskHandleForCore (default) + if FREERTOS_USE_KERNEL_10_5_1 = y && FREERTOS_GENERATE_RUN_TIME_STATS = y: + tasks:ulTaskGetIdleRunTimeCounterForCore (default) + tasks:ulTaskGetIdleRunTimePercentForCore (default) tasks:pxTaskGetStackStart (default) tasks:prvTaskPriorityRaise (default) tasks:prvTaskPriorityRestore (default) From 49af70506a969ae9cddc30341a33e7e521a59762 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Fri, 8 Sep 2023 00:29:57 +0800 Subject: [PATCH 25/71] feat(freertos): Add SMP critical section changes to FreeRTOS v10.5.1 This commit adds the SMP critical section changes to the v10.5.1 kernel. These changes are temporarily documented in the `idf_changes.md` document. This commit... - Adds granular spinlocks to each data group (e.g., kernel, queues, event_groups etc.) - Updates critical section macros to use those spinlocks - Add missing critical sections required in SMP --- .../FreeRTOS-Kernel-V10.5.1/event_groups.c | 60 +- .../FreeRTOS-Kernel-V10.5.1/idf_changes.md | 25 +- .../include/freertos/FreeRTOS.h | 3 + .../include/freertos/task.h | 6 +- .../freertos/FreeRTOS-Kernel-V10.5.1/queue.c | 1160 ++++++++----- .../FreeRTOS-Kernel-V10.5.1/stream_buffer.c | 88 +- .../freertos/FreeRTOS-Kernel-V10.5.1/tasks.c | 1543 ++++++++++------- .../freertos/FreeRTOS-Kernel-V10.5.1/timers.c | 38 +- .../freertos_tasks_c_additions.h | 12 +- 9 files changed, 1796 insertions(+), 1139 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/event_groups.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/event_groups.c index 6e4e23ea661..4ad031aefd3 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/event_groups.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/event_groups.c @@ -43,6 +43,8 @@ #include "task.h" #include "timers.h" #include "event_groups.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" /* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined @@ -77,6 +79,8 @@ typedef struct EventGroupDef_t #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */ #endif + + portMUX_TYPE xEventGroupLock; /* Spinlock required for SMP critical sections */ } EventGroup_t; /*-----------------------------------------------------------*/ @@ -131,6 +135,9 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, } #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + /* Initialize the event group's spinlock. */ + portMUX_INITIALIZE( &pxEventBits->xEventGroupLock ); + traceEVENT_GROUP_CREATE( pxEventBits ); } else @@ -182,6 +189,9 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, } #endif /* configSUPPORT_STATIC_ALLOCATION */ + /* Initialize the event group's spinlock. */ + portMUX_INITIALIZE( &pxEventBits->xEventGroupLock ); + traceEVENT_GROUP_CREATE( pxEventBits ); } else @@ -213,7 +223,7 @@ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, } #endif - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &( pxEventBits->xEventGroupLock ) ); { uxOriginalBitValue = pxEventBits->uxEventBits; @@ -256,7 +266,7 @@ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, } } } - xAlreadyYielded = xTaskResumeAll(); + xAlreadyYielded = prvEXIT_CRITICAL_OR_RESUME_ALL( &( pxEventBits->xEventGroupLock ) ); if( xTicksToWait != ( TickType_t ) 0 ) { @@ -278,7 +288,7 @@ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) { /* The task timed out, just return the current event bit value. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxEventBits->xEventGroupLock ) ); { uxReturn = pxEventBits->uxEventBits; @@ -295,7 +305,7 @@ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxEventBits->xEventGroupLock ) ); xTimeoutOccurred = pdTRUE; } @@ -340,7 +350,7 @@ EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, } #endif - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &( pxEventBits->xEventGroupLock ) ); { const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits; @@ -408,7 +418,7 @@ EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ); } } - xAlreadyYielded = xTaskResumeAll(); + xAlreadyYielded = prvEXIT_CRITICAL_OR_RESUME_ALL( &( pxEventBits->xEventGroupLock ) ); if( xTicksToWait != ( TickType_t ) 0 ) { @@ -429,7 +439,7 @@ EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) { - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxEventBits->xEventGroupLock ) ); { /* The task timed out, just return the current event bit value. */ uxReturn = pxEventBits->uxEventBits; @@ -454,7 +464,7 @@ EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, xTimeoutOccurred = pdTRUE; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxEventBits->xEventGroupLock ) ); } else { @@ -485,7 +495,7 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, configASSERT( xEventGroup ); configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxEventBits->xEventGroupLock ) ); { traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ); @@ -496,7 +506,7 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, /* Clear the bits. */ pxEventBits->uxEventBits &= ~uxBitsToClear; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxEventBits->xEventGroupLock ) ); return uxReturn; } @@ -552,7 +562,14 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, pxList = &( pxEventBits->xTasksWaitingForBits ); pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */ - vTaskSuspendAll(); + + prvENTER_CRITICAL_OR_SUSPEND_ALL( &( pxEventBits->xEventGroupLock ) ); + #if ( configNUMBER_OF_CORES > 1 ) + + /* We are about to traverse a task list which is a kernel data structure. + * Thus we need to call prvTakeKernelLock() to take the kernel lock. */ + prvTakeKernelLock(); + #endif /* configNUMBER_OF_CORES > 1 */ { traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ); @@ -624,7 +641,12 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, * bit was set in the control word. */ pxEventBits->uxEventBits &= ~uxBitsToClear; } - ( void ) xTaskResumeAll(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Release the previously taken kernel lock. */ + prvReleaseKernelLock(); + #endif /* configNUMBER_OF_CORES > 1 */ + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &( pxEventBits->xEventGroupLock ) ); + return pxEventBits->uxEventBits; } @@ -639,7 +661,13 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup ) pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &( pxEventBits->xEventGroupLock ) ); + #if ( configNUMBER_OF_CORES > 1 ) + + /* We are about to traverse a task list which is a kernel data structure. + * Thus we need to call prvTakeKernelLock() to take the kernel lock. */ + prvTakeKernelLock(); + #endif /* configNUMBER_OF_CORES > 1 */ { traceEVENT_GROUP_DELETE( xEventGroup ); @@ -651,7 +679,11 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup ) vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); } } - ( void ) xTaskResumeAll(); + #if ( configNUMBER_OF_CORES > 1 ) + /* Release the previously taken kernel lock. */ + prvReleaseKernelLock(); + #endif /* configNUMBER_OF_CORES > 1 */ + prvEXIT_CRITICAL_OR_RESUME_ALL( &( pxEventBits->xEventGroupLock ) ); #if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) { diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/idf_changes.md b/components/freertos/FreeRTOS-Kernel-V10.5.1/idf_changes.md index eb4094b4424..cbaf5d6e00c 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/idf_changes.md +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/idf_changes.md @@ -74,8 +74,6 @@ The following APIs have been added to support SMP ### API Modifications -#### SMP Modifications - Added the following macros that abstract away single-core and SMP differences: - `taskYIELD_CORE()` triggers a particular core to yield @@ -122,9 +120,26 @@ The following functions were modified to accommodate SMP behavior: - `prvAddCurrentTaskToDelayedList()` - Added extra check to see if current blocking task has already been deleted by the other core. -#### Single-Core Modifications - +### Critical Section Changes + +- Granular Locks: The following objects are now given their own spinlocks + - Kernel objects (i.e., `tasks.c`): `xKernelLock` + - Each queue: `xQueueLock` + - Queue Registry: `xQueueRegistryLock` + - Each event group: `xEventGroupLock` + - Each stream buffer: `xStreamBufferLock` + - All timers: `xTimerLock` +- Critical sections now target the appropriate spinlocks +- Added missing critical sections for SMP (see `..._SMP_ONLY()` critical section calls) +- Queues no longer use queue locks (see `queueUSE_LOCKS`) + - Queues now just use critical sections and skips queue locking + - Queue functions can now execute within a single critical section block ## Single Core Differences -List of differences between Vanilla FreeRTOS V10.5.1 and building the dual-core SMP kernel with `congigNUMBER_OF_CORES == 1`. \ No newline at end of file +List of differences between Vanilla FreeRTOS V10.5.1 and building the dual-core SMP kernel with `congigNUMBER_OF_CORES == 1`. + +- `prvAddNewTaskToReadyList()` + - Extended critical section so that SMP can check for yields while still inside critical section +- `vTaskStepTick()` + - Extended critical section so that SMP can access `xTickCount` while still inside critical section diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h index adf94251d86..ea168b1e9f7 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h @@ -1371,6 +1371,7 @@ typedef struct xSTATIC_QUEUE UBaseType_t uxDummy8; uint8_t ucDummy9; #endif + portMUX_TYPE xDummyQueueLock; } StaticQueue_t; typedef StaticQueue_t StaticSemaphore_t; @@ -1400,6 +1401,7 @@ typedef struct xSTATIC_EVENT_GROUP #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) uint8_t ucDummy4; #endif + portMUX_TYPE xDummyEventGroupLock; } StaticEventGroup_t; /* @@ -1454,6 +1456,7 @@ typedef struct xSTATIC_STREAM_BUFFER #if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) void * pvDummy5[ 2 ]; #endif + portMUX_TYPE xDummyStreamBufferLock; } StaticStreamBuffer_t; /* Message buffers are built on stream buffers. */ diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/task.h b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/task.h index 624285f3689..a3427087af6 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/task.h +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/task.h @@ -220,8 +220,9 @@ typedef enum * \defgroup taskENTER_CRITICAL taskENTER_CRITICAL * \ingroup SchedulerControl */ -#define taskENTER_CRITICAL() portENTER_CRITICAL() +#define taskENTER_CRITICAL( x ) portENTER_CRITICAL( x ) #define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() +#define taskENTER_CRITICAL_ISR( x ) portENTER_CRITICAL_ISR( x ) /** * task. h @@ -235,8 +236,9 @@ typedef enum * \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL * \ingroup SchedulerControl */ -#define taskEXIT_CRITICAL() portEXIT_CRITICAL() +#define taskEXIT_CRITICAL( x ) portEXIT_CRITICAL( x ) #define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) +#define taskEXIT_CRITICAL_ISR( x ) portEXIT_CRITICAL_ISR( x ) /** * task. h diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/queue.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/queue.c index fa36ad70e69..faa22ca5a5b 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/queue.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/queue.c @@ -41,6 +41,8 @@ #include "FreeRTOS.h" #include "task.h" #include "queue.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" #if ( configUSE_CO_ROUTINES == 1 ) #include "croutine.h" @@ -52,11 +54,71 @@ * correct privileged Vs unprivileged linkage and placement. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ +/* Some code sections require extra critical sections when building for SMP + * ( configNUMBER_OF_CORES > 1 ). */ +#if ( configNUMBER_OF_CORES > 1 ) +/* Macros that Enter/exit a critical section only when building for SMP */ + #define taskENTER_CRITICAL_SMP_ONLY( pxLock ) taskENTER_CRITICAL( pxLock ) + #define taskEXIT_CRITICAL_SMP_ONLY( pxLock ) taskEXIT_CRITICAL( pxLock ) + #define taskENTER_CRITICAL_SAFE_SMP_ONLY( pxLock ) prvTaskEnterCriticalSafeSMPOnly( pxLock ) + #define taskEXIT_CRITICAL_SAFE_SMP_ONLY( pxLock ) prvTaskExitCriticalSafeSMPOnly( pxLock ) -/* Constants used with the cRxLock and cTxLock structure members. */ -#define queueUNLOCKED ( ( int8_t ) -1 ) -#define queueLOCKED_UNMODIFIED ( ( int8_t ) 0 ) -#define queueINT8_MAX ( ( int8_t ) 127 ) + static inline __attribute__( ( always_inline ) ) + void prvTaskEnterCriticalSafeSMPOnly( portMUX_TYPE * pxLock ) + { + if( portCHECK_IF_IN_ISR() == pdFALSE ) + { + taskENTER_CRITICAL( pxLock ); + } + else + { + #ifdef __clang_analyzer__ + /* Teach clang-tidy that ISR version macro can be different */ + configASSERT( 1 ); + #endif + taskENTER_CRITICAL_ISR( pxLock ); + } + } + + static inline __attribute__( ( always_inline ) ) + void prvTaskExitCriticalSafeSMPOnly( portMUX_TYPE * pxLock ) + { + if( portCHECK_IF_IN_ISR() == pdFALSE ) + { + taskEXIT_CRITICAL( pxLock ); + } + else + { + #ifdef __clang_analyzer__ + /* Teach clang-tidy that ISR version macro can be different */ + configASSERT( 1 ); + #endif + taskEXIT_CRITICAL_ISR( pxLock ); + } + } +#else /* configNUMBER_OF_CORES > 1 */ + /* Macros that Enter/exit a critical section only when building for SMP */ + #define taskENTER_CRITICAL_SMP_ONLY( pxLock ) + #define taskEXIT_CRITICAL_SMP_ONLY( pxLock ) + #define taskENTER_CRITICAL_SAFE_SMP_ONLY( pxLock ) + #define taskEXIT_CRITICAL_SAFE_SMP_ONLY( pxLock ) +#endif /* configNUMBER_OF_CORES > 1 */ + +/* Single core FreeRTOS uses queue locks to ensure that vTaskPlaceOnEventList() + * calls are deterministic (as queue locks use scheduler suspension instead of + * critical sections). However, the SMP implementation is non-deterministic + * anyways, thus SMP can forego the use of queue locks (replaced with a critical + * sections) in exchange for better queue performance. */ +#if ( configNUMBER_OF_CORES > 1 ) + #define queueUSE_LOCKS 0 + #define queueUNLOCKED ( ( int8_t ) 0 ) +#else /* configNUMBER_OF_CORES > 1 */ + #define queueUSE_LOCKS 1 + /* Constants used with the cRxLock and cTxLock structure members. */ + #define queueUNLOCKED ( ( int8_t ) -1 ) + #define queueLOCKED_UNMODIFIED ( ( int8_t ) 0 ) + #define queueINT8_MAX ( ( int8_t ) 127 ) +#endif /* configNUMBER_OF_CORES > 1 */ /* When the Queue_t structure is used to represent a base queue its pcHead and * pcTail members are used as pointers into the queue storage area. When the @@ -67,8 +129,8 @@ * is maintained. The QueuePointers_t and SemaphoreData_t types are used to form * a union as their usage is mutually exclusive dependent on what the queue is * being used for. */ -#define uxQueueType pcHead -#define queueQUEUE_IS_MUTEX NULL +#define uxQueueType pcHead +#define queueQUEUE_IS_MUTEX NULL typedef struct QueuePointers { @@ -119,8 +181,10 @@ typedef struct QueueDefinition /* The old naming convention is used to prevent b UBaseType_t uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ UBaseType_t uxItemSize; /*< The size of each items that the queue will hold. */ - volatile int8_t cRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ - volatile int8_t cTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + #if ( queueUSE_LOCKS == 1 ) + volatile int8_t cRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + volatile int8_t cTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + #endif /* queueUSE_LOCKS == 1 */ #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */ @@ -134,6 +198,8 @@ typedef struct QueueDefinition /* The old naming convention is used to prevent b UBaseType_t uxQueueNumber; uint8_t ucQueueType; #endif + + portMUX_TYPE xQueueLock; /* Spinlock required for SMP critical sections */ } xQUEUE; /* The old xQUEUE name is maintained above then typedefed to the new Queue_t @@ -167,8 +233,15 @@ typedef xQUEUE Queue_t; * array position being vacant. */ PRIVILEGED_DATA QueueRegistryItem_t xQueueRegistry[ configQUEUE_REGISTRY_SIZE ]; + #if ( configNUMBER_OF_CORES > 1 ) +/* Spinlock required in SMP when accessing the queue registry */ + static portMUX_TYPE xQueueRegistryLock = portMUX_INITIALIZER_UNLOCKED; + #endif /* configNUMBER_OF_CORES > 1 */ + #endif /* configQUEUE_REGISTRY_SIZE */ +#if ( queueUSE_LOCKS == 1 ) + /* * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not * prevent an ISR from adding or removing items to the queue, but does prevent @@ -177,21 +250,22 @@ typedef xQUEUE Queue_t; * to indicate that a task may require unblocking. When the queue in unlocked * these lock counts are inspected, and the appropriate action taken. */ -static void prvUnlockQueue( Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; + static void prvUnlockQueue( Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; /* * Uses a critical section to determine if there is any data in a queue. * * @return pdTRUE if the queue contains no items, otherwise pdFALSE. */ -static BaseType_t prvIsQueueEmpty( const Queue_t * pxQueue ) PRIVILEGED_FUNCTION; + static BaseType_t prvIsQueueEmpty( const Queue_t * pxQueue ) PRIVILEGED_FUNCTION; /* * Uses a critical section to determine if there is any space in a queue. * * @return pdTRUE if there is no space, otherwise pdFALSE; */ -static BaseType_t prvIsQueueFull( const Queue_t * pxQueue ) PRIVILEGED_FUNCTION; + static BaseType_t prvIsQueueFull( const Queue_t * pxQueue ) PRIVILEGED_FUNCTION; +#endif /* queueUSE_LOCKS == 1 */ /* * Copies an item into the queue, either at the front of the queue or the @@ -248,12 +322,14 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, #endif /*-----------------------------------------------------------*/ +#if ( queueUSE_LOCKS == 1 ) + /* * Macro to mark a queue as locked. Locking a queue prevents an ISR from * accessing the queue event lists. */ -#define prvLockQueue( pxQueue ) \ - taskENTER_CRITICAL(); \ + #define prvLockQueue( pxQueue ) \ + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); \ { \ if( ( pxQueue )->cRxLock == queueUNLOCKED ) \ { \ @@ -264,14 +340,14 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, ( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \ } \ } \ - taskEXIT_CRITICAL() + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ) /* * Macro to increment cTxLock member of the queue data structure. It is * capped at the number of tasks in the system as we cannot unblock more * tasks than the number of tasks in the system. */ -#define prvIncrementQueueTxLock( pxQueue, cTxLock ) \ + #define prvIncrementQueueTxLock( pxQueue, cTxLock ) \ { \ const UBaseType_t uxNumberOfTasks = uxTaskGetNumberOfTasks(); \ if( ( UBaseType_t ) ( cTxLock ) < uxNumberOfTasks ) \ @@ -286,7 +362,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, * capped at the number of tasks in the system as we cannot unblock more * tasks than the number of tasks in the system. */ -#define prvIncrementQueueRxLock( pxQueue, cRxLock ) \ + #define prvIncrementQueueRxLock( pxQueue, cRxLock ) \ { \ const UBaseType_t uxNumberOfTasks = uxTaskGetNumberOfTasks(); \ if( ( UBaseType_t ) ( cRxLock ) < uxNumberOfTasks ) \ @@ -295,6 +371,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, ( pxQueue )->cRxLock = ( int8_t ) ( ( cRxLock ) + ( int8_t ) 1 ); \ } \ } +#endif /* queueUSE_LOCKS == 1 */ /*-----------------------------------------------------------*/ BaseType_t xQueueGenericReset( QueueHandle_t xQueue, @@ -305,19 +382,28 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue, configASSERT( pxQueue ); + if( xNewQueue == pdTRUE ) + { + portMUX_INITIALIZE( &( pxQueue->xQueueLock ) ); + } + if( ( pxQueue != NULL ) && ( pxQueue->uxLength >= 1U ) && /* Check for multiplication overflow. */ ( ( SIZE_MAX / pxQueue->uxLength ) >= pxQueue->uxItemSize ) ) { - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); { pxQueue->u.xQueue.pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */ pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U; pxQueue->pcWriteTo = pxQueue->pcHead; pxQueue->u.xQueue.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - 1U ) * pxQueue->uxItemSize ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */ - pxQueue->cRxLock = queueUNLOCKED; - pxQueue->cTxLock = queueUNLOCKED; + #if ( queueUSE_LOCKS == 1 ) + { + pxQueue->cRxLock = queueUNLOCKED; + pxQueue->cTxLock = queueUNLOCKED; + } + #endif /* queueUSE_LOCKS == 1 */ if( xNewQueue == pdFALSE ) { @@ -349,7 +435,7 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue, vListInitialise( &( pxQueue->xTasksWaitingToReceive ) ); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); } else { @@ -606,6 +692,9 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, /* In case this is a recursive mutex. */ pxNewQueue->u.xSemaphore.uxRecursiveCallCount = 0; + /* Initialize the mutex's spinlock */ + portMUX_INITIALIZE( &( pxNewQueue->xQueueLock ) ); + traceCREATE_MUTEX( pxNewQueue ); /* Start with the semaphore in the expected state. */ @@ -671,7 +760,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, * calling task is the mutex holder, but not a good way of determining the * identity of the mutex holder, as the holder may change between the * following critical section exiting and the function returning. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxSemaphore->xQueueLock ) ); { if( pxSemaphore->uxQueueType == queueQUEUE_IS_MUTEX ) { @@ -682,7 +771,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, pxReturn = NULL; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxSemaphore->xQueueLock ) ); return pxReturn; } /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */ @@ -908,7 +997,7 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, * interest of execution time efficiency. */ for( ; ; ) { - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); { /* Is there room on the queue now? The running task must be the * highest priority task wanting to access the queue. If the head item @@ -1014,7 +1103,7 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, } #endif /* configUSE_QUEUE_SETS */ - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); return pdPASS; } else @@ -1023,7 +1112,7 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, { /* The queue was full and no block time is specified (or * the block time has expired) so leave now. */ - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); /* Return to the original privilege level before exiting * the function. */ @@ -1043,56 +1132,88 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, mtCOVERAGE_TEST_MARKER(); } } + + /* If queue locks ARE NOT being used: + * - At this point, the queue is full and entry time has been set + * - We simply check for a time out, block if not timed out, or + * return an error if we have timed out. */ + #if ( queueUSE_LOCKS == 0 ) + { + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + /* Not timed out yet. Block the current task. */ + traceBLOCKING_ON_QUEUE_SEND( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); + portYIELD_WITHIN_API(); + } + else + { + /* We have timed out. Return an error. */ + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } + } + #endif /* queueUSE_LOCKS == 0 */ } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); - /* Interrupts and other tasks can send to and receive from the queue - * now the critical section has been exited. */ + /* If queue locks ARE being used: + * - At this point, the queue is full and entry time has been set + * - We follow the original procedure of locking the queue before + * attempting to block. */ + #if ( queueUSE_LOCKS == 1 ) + { + /* Interrupts and other tasks can send to and receive from the queue + * now the critical section has been exited. */ - vTaskSuspendAll(); - prvLockQueue( pxQueue ); + vTaskSuspendAll(); + prvLockQueue( pxQueue ); - /* Update the timeout state to see if it has expired yet. */ - if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) - { - if( prvIsQueueFull( pxQueue ) != pdFALSE ) + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { - traceBLOCKING_ON_QUEUE_SEND( pxQueue ); - vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); + if( prvIsQueueFull( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_SEND( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); - /* Unlocking the queue means queue events can effect the - * event list. It is possible that interrupts occurring now - * remove this task from the event list again - but as the - * scheduler is suspended the task will go onto the pending - * ready list instead of the actual ready list. */ - prvUnlockQueue( pxQueue ); + /* Unlocking the queue means queue events can effect the + * event list. It is possible that interrupts occurring now + * remove this task from the event list again - but as the + * scheduler is suspended the task will go onto the pending + * ready list instead of the actual ready list. */ + prvUnlockQueue( pxQueue ); - /* Resuming the scheduler will move tasks from the pending - * ready list into the ready list - so it is feasible that this - * task is already in the ready list before it yields - in which - * case the yield will not cause a context switch unless there - * is also a higher priority task in the pending ready list. */ - if( xTaskResumeAll() == pdFALSE ) + /* Resuming the scheduler will move tasks from the pending + * ready list into the ready list - so it is feasible that this + * task is already in the ready list before it yields - in which + * case the yield will not cause a context switch unless there + * is also a higher priority task in the pending ready list. */ + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + } + else { - portYIELD_WITHIN_API(); + /* Try again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); } } else { - /* Try again. */ + /* The timeout has expired. */ prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); - } - } - else - { - /* The timeout has expired. */ - prvUnlockQueue( pxQueue ); - ( void ) xTaskResumeAll(); - traceQUEUE_SEND_FAILED( pxQueue ); - return errQUEUE_FULL; + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } } + #endif /* queueUSE_LOCKS == 1 */ } /*lint -restore */ } /*-----------------------------------------------------------*/ @@ -1131,11 +1252,16 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, * read, instead return a flag to say whether a context switch is required or * not (i.e. has a task with a higher priority than us been woken by this * post). */ - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &( pxQueue->xQueueLock ), uxSavedInterruptStatus ); { if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) { - const int8_t cTxLock = pxQueue->cTxLock; + #if ( queueUSE_LOCKS == 1 ) + const int8_t cTxLock = pxQueue->cTxLock; + #else + /* Queue locks not used, so we treat it as unlocked. */ + const int8_t cTxLock = queueUNLOCKED; + #endif /* queueUSE_LOCKS == 1 */ const UBaseType_t uxPreviousMessagesWaiting = pxQueue->uxMessagesWaiting; traceQUEUE_SEND_FROM_ISR( pxQueue ); @@ -1243,9 +1369,13 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, } else { - /* Increment the lock count so the task that unlocks the queue - * knows that data was posted while it was locked. */ - prvIncrementQueueTxLock( pxQueue, cTxLock ); + #if ( queueUSE_LOCKS == 1 ) + { + /* Increment the lock count so the task that unlocks the queue + * knows that data was posted while it was locked. */ + prvIncrementQueueTxLock( pxQueue, cTxLock ); + } + #endif /* queueUSE_LOCKS == 1 */ } xReturn = pdPASS; @@ -1256,7 +1386,7 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, xReturn = errQUEUE_FULL; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &( pxQueue->xQueueLock ), uxSavedInterruptStatus ); return xReturn; } @@ -1302,7 +1432,7 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, * link: https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &( pxQueue->xQueueLock ), uxSavedInterruptStatus ); { const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; @@ -1311,7 +1441,12 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, * space'. */ if( uxMessagesWaiting < pxQueue->uxLength ) { - const int8_t cTxLock = pxQueue->cTxLock; + #if ( queueUSE_LOCKS == 1 ) + const int8_t cTxLock = pxQueue->cTxLock; + #else + /* Queue locks not used, so we treat it as unlocked. */ + const int8_t cTxLock = queueUNLOCKED; + #endif /* queueUSE_LOCKS == 1 */ traceQUEUE_SEND_FROM_ISR( pxQueue ); @@ -1409,9 +1544,13 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, } else { - /* Increment the lock count so the task that unlocks the queue - * knows that data was posted while it was locked. */ - prvIncrementQueueTxLock( pxQueue, cTxLock ); + #if ( queueUSE_LOCKS == 1 ) + { + /* Increment the lock count so the task that unlocks the queue + * knows that data was posted while it was locked. */ + prvIncrementQueueTxLock( pxQueue, cTxLock ); + } + #endif /* queueUSE_LOCKS == 1 */ } xReturn = pdPASS; @@ -1422,7 +1561,7 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, xReturn = errQUEUE_FULL; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &( pxQueue->xQueueLock ), uxSavedInterruptStatus ); return xReturn; } @@ -1455,7 +1594,7 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue, * interest of execution time efficiency. */ for( ; ; ) { - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); { const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; @@ -1487,7 +1626,7 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue, mtCOVERAGE_TEST_MARKER(); } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); return pdPASS; } else @@ -1496,7 +1635,7 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue, { /* The queue was empty and no block time is specified (or * the block time has expired) so leave now. */ - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); traceQUEUE_RECEIVE_FAILED( pxQueue ); return errQUEUE_EMPTY; } @@ -1513,60 +1652,92 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue, mtCOVERAGE_TEST_MARKER(); } } - } - taskEXIT_CRITICAL(); - - /* Interrupts and other tasks can send to and receive from the queue - * now the critical section has been exited. */ - - vTaskSuspendAll(); - prvLockQueue( pxQueue ); - /* Update the timeout state to see if it has expired yet. */ - if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) - { - /* The timeout has not expired. If the queue is still empty place - * the task on the list of tasks waiting to receive from the queue. */ - if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + /* If queue locks ARE NOT being used: + * - At this point, the queue is empty and entry time has been set + * - We simply check for a time out, block if not timed out, or + * return an error if we have timed out. */ + #if ( queueUSE_LOCKS == 0 ) { - traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); - vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); - prvUnlockQueue( pxQueue ); - - if( xTaskResumeAll() == pdFALSE ) + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { + /* Not timed out yet. Block the current task. */ + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); portYIELD_WITHIN_API(); } else { - mtCOVERAGE_TEST_MARKER(); + /* We have timed out. Return an error. */ + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; } } - else - { - /* The queue contains data again. Loop back to try and read the - * data. */ - prvUnlockQueue( pxQueue ); - ( void ) xTaskResumeAll(); - } + #endif /* queueUSE_LOCKS == 0 */ } - else + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); + + /* If queue locks ARE being used: + * - At this point, the queue is empty and entry time has been set + * - We follow the original procedure for locking the queue before + * attempting to block. */ + #if ( queueUSE_LOCKS == 1 ) { - /* Timed out. If there is no data in the queue exit, otherwise loop - * back and attempt to read the data. */ - prvUnlockQueue( pxQueue ); - ( void ) xTaskResumeAll(); + /* Interrupts and other tasks can send to and receive from the queue + * now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); - if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { - traceQUEUE_RECEIVE_FAILED( pxQueue ); - return errQUEUE_EMPTY; + /* The timeout has not expired. If the queue is still empty place + * the task on the list of tasks waiting to receive from the queue. */ + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + prvUnlockQueue( pxQueue ); + + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* The queue contains data again. Loop back to try and read the + * data. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } } else { - mtCOVERAGE_TEST_MARKER(); + /* Timed out. If there is no data in the queue exit, otherwise loop + * back and attempt to read the data. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } + #endif /* queueUSE_LOCKS == 1 */ } /*lint -restore */ } /*-----------------------------------------------------------*/ @@ -1601,7 +1772,7 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, * of execution time efficiency. */ for( ; ; ) { - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); { /* Semaphores are queues with an item size of 0, and where the * number of messages in the queue is the semaphore's count value. */ @@ -1650,7 +1821,7 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, mtCOVERAGE_TEST_MARKER(); } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); return pdPASS; } else @@ -1659,7 +1830,7 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, { /* The semaphore count was 0 and no block time is specified * (or the block time has expired) so exit now. */ - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); traceQUEUE_RECEIVE_FAILED( pxQueue ); return errQUEUE_EMPTY; } @@ -1676,107 +1847,165 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, mtCOVERAGE_TEST_MARKER(); } } - } - taskEXIT_CRITICAL(); - - /* Interrupts and other tasks can give to and take from the semaphore - * now the critical section has been exited. */ - vTaskSuspendAll(); - prvLockQueue( pxQueue ); - - /* Update the timeout state to see if it has expired yet. */ - if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) - { - /* A block time is specified and not expired. If the semaphore - * count is 0 then enter the Blocked state to wait for a semaphore to - * become available. As semaphores are implemented with queues the - * queue being empty is equivalent to the semaphore count being 0. */ - if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + /* If queue locks ARE NOT being used: + * - At this point, the semaphore/mutex is empty/held and entry time + * has been set. + * - We simply check for a time out, inherit priority and block if + * not timed out, or return an error if we have timed out. */ + #if ( queueUSE_LOCKS == 0 ) { - traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); - - #if ( configUSE_MUTEXES == 1 ) + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { - if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + /* Not timed out yet. If this is a mutex, make the holder + * inherit our priority, then block the current task. */ + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + #if ( configUSE_MUTEXES == 1 ) { - taskENTER_CRITICAL(); + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) { xInheritanceOccurred = xTaskPriorityInherit( pxQueue->u.xSemaphore.xMutexHolder ); } - taskEXIT_CRITICAL(); + else + { + mtCOVERAGE_TEST_MARKER(); + } } - else + #endif /* if ( configUSE_MUTEXES == 1 ) */ + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + portYIELD_WITHIN_API(); + } + else + { + /* We have timed out. If this is a mutex, make the holder + * disinherit our priority, then return an error. */ + #if ( configUSE_MUTEXES == 1 ) { - mtCOVERAGE_TEST_MARKER(); + if( xInheritanceOccurred != pdFALSE ) + { + UBaseType_t uxHighestWaitingPriority; + uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue ); + vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority ); + } } + #endif /* configUSE_MUTEXES */ + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; } - #endif /* if ( configUSE_MUTEXES == 1 ) */ + } + #endif /* queueUSE_LOCKS == 0 */ + } + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); - vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); - prvUnlockQueue( pxQueue ); + /* If queue locks ARE being used: + * - At this point, the semaphore/mutex is empty/held and entry time + * has been set. + * - We follow the original procedure for locking the queue, inheriting + * priority, then attempting to block. */ + #if ( queueUSE_LOCKS == 1 ) + { + /* Interrupts and other tasks can give to and take from the semaphore + * now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); - if( xTaskResumeAll() == pdFALSE ) + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + /* A block time is specified and not expired. If the semaphore + * count is 0 then enter the Blocked state to wait for a semaphore to + * become available. As semaphores are implemented with queues the + * queue being empty is equivalent to the semaphore count being 0. */ + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) { - portYIELD_WITHIN_API(); + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); + { + xInheritanceOccurred = xTaskPriorityInherit( pxQueue->u.xSemaphore.xMutexHolder ); + } + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* if ( configUSE_MUTEXES == 1 ) */ + + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + prvUnlockQueue( pxQueue ); + + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } else { - mtCOVERAGE_TEST_MARKER(); + /* There was no timeout and the semaphore count was not 0, so + * attempt to take the semaphore again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); } } else { - /* There was no timeout and the semaphore count was not 0, so - * attempt to take the semaphore again. */ + /* Timed out. */ prvUnlockQueue( pxQueue ); ( void ) xTaskResumeAll(); - } - } - else - { - /* Timed out. */ - prvUnlockQueue( pxQueue ); - ( void ) xTaskResumeAll(); - /* If the semaphore count is 0 exit now as the timeout has - * expired. Otherwise return to attempt to take the semaphore that is - * known to be available. As semaphores are implemented by queues the - * queue being empty is equivalent to the semaphore count being 0. */ - if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) - { - #if ( configUSE_MUTEXES == 1 ) + /* If the semaphore count is 0 exit now as the timeout has + * expired. Otherwise return to attempt to take the semaphore that is + * known to be available. As semaphores are implemented by queues the + * queue being empty is equivalent to the semaphore count being 0. */ + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) { - /* xInheritanceOccurred could only have be set if - * pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to - * test the mutex type again to check it is actually a mutex. */ - if( xInheritanceOccurred != pdFALSE ) + #if ( configUSE_MUTEXES == 1 ) { - taskENTER_CRITICAL(); + /* xInheritanceOccurred could only have be set if + * pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to + * test the mutex type again to check it is actually a mutex. */ + if( xInheritanceOccurred != pdFALSE ) { - UBaseType_t uxHighestWaitingPriority; - - /* This task blocking on the mutex caused another - * task to inherit this task's priority. Now this task - * has timed out the priority should be disinherited - * again, but only as low as the next highest priority - * task that is waiting for the same mutex. */ - uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue ); - vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority ); + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); + { + UBaseType_t uxHighestWaitingPriority; + + /* This task blocking on the mutex caused another + * task to inherit this task's priority. Now this task + * has timed out the priority should be disinherited + * again, but only as low as the next highest priority + * task that is waiting for the same mutex. */ + uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue ); + vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority ); + } + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); } - taskEXIT_CRITICAL(); } - } - #endif /* configUSE_MUTEXES */ + #endif /* configUSE_MUTEXES */ - traceQUEUE_RECEIVE_FAILED( pxQueue ); - return errQUEUE_EMPTY; - } - else - { - mtCOVERAGE_TEST_MARKER(); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } + #endif /* queueUSE_LOCKS == 1 */ } /*lint -restore */ } /*-----------------------------------------------------------*/ @@ -1809,7 +2038,7 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue, * interest of execution time efficiency. */ for( ; ; ) { - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); { const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; @@ -1847,7 +2076,7 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue, mtCOVERAGE_TEST_MARKER(); } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); return pdPASS; } else @@ -1856,7 +2085,7 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue, { /* The queue was empty and no block time is specified (or * the block time has expired) so leave now. */ - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); traceQUEUE_PEEK_FAILED( pxQueue ); return errQUEUE_EMPTY; } @@ -1874,60 +2103,92 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue, mtCOVERAGE_TEST_MARKER(); } } - } - taskEXIT_CRITICAL(); - /* Interrupts and other tasks can send to and receive from the queue - * now that the critical section has been exited. */ - - vTaskSuspendAll(); - prvLockQueue( pxQueue ); - - /* Update the timeout state to see if it has expired yet. */ - if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) - { - /* Timeout has not expired yet, check to see if there is data in the - * queue now, and if not enter the Blocked state to wait for data. */ - if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + /* If queue locks ARE NOT being used: + * - At this point, the queue is empty and entry time has been set + * - We simply check for a time out, block if not timed out, or + * return an error if we have timed out. */ + #if ( queueUSE_LOCKS == 0 ) { - traceBLOCKING_ON_QUEUE_PEEK( pxQueue ); - vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); - prvUnlockQueue( pxQueue ); - - if( xTaskResumeAll() == pdFALSE ) + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { + /* Not timed out yet. Block the current task. */ + traceBLOCKING_ON_QUEUE_PEEK( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); portYIELD_WITHIN_API(); } else { - mtCOVERAGE_TEST_MARKER(); + /* We have timed out. Return an error. */ + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); + traceQUEUE_PEEK_FAILED( pxQueue ); + return errQUEUE_EMPTY; } } - else - { - /* There is data in the queue now, so don't enter the blocked - * state, instead return to try and obtain the data. */ - prvUnlockQueue( pxQueue ); - ( void ) xTaskResumeAll(); - } + #endif /* queueUSE_LOCKS == 0 */ } - else + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); + + /* If queue locks ARE being used: + * - At this point, the queue is empty and entry time has been set + * - We follow the original procedure for locking the queue before + * attempting to block. */ + #if ( queueUSE_LOCKS == 1 ) { - /* The timeout has expired. If there is still no data in the queue - * exit, otherwise go back and try to read the data again. */ - prvUnlockQueue( pxQueue ); - ( void ) xTaskResumeAll(); + /* Interrupts and other tasks can send to and receive from the queue + * now that the critical section has been exited. */ - if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) { - traceQUEUE_PEEK_FAILED( pxQueue ); - return errQUEUE_EMPTY; + /* Timeout has not expired yet, check to see if there is data in the + * queue now, and if not enter the Blocked state to wait for data. */ + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_PEEK( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + prvUnlockQueue( pxQueue ); + + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* There is data in the queue now, so don't enter the blocked + * state, instead return to try and obtain the data. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } } else { - mtCOVERAGE_TEST_MARKER(); + /* The timeout has expired. If there is still no data in the queue + * exit, otherwise go back and try to read the data again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceQUEUE_PEEK_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } + #endif /* queueUSE_LOCKS == 1 */ } /*lint -restore */ } /*-----------------------------------------------------------*/ @@ -1959,14 +2220,19 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, * link: https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &( pxQueue->xQueueLock ), uxSavedInterruptStatus ); { const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; /* Cannot block in an ISR, so check there is data available. */ if( uxMessagesWaiting > ( UBaseType_t ) 0 ) { - const int8_t cRxLock = pxQueue->cRxLock; + #if ( queueUSE_LOCKS == 1 ) + const int8_t cRxLock = pxQueue->cRxLock; + #else + /* Queue locks not used, so we treat it as unlocked. */ + const int8_t cRxLock = queueUNLOCKED; + #endif /* queueUSE_LOCKS == 1 */ traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); @@ -2006,9 +2272,13 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, } else { - /* Increment the lock count so the task that unlocks the queue - * knows that data was removed while it was locked. */ - prvIncrementQueueRxLock( pxQueue, cRxLock ); + #if ( queueUSE_LOCKS == 1 ) + { + /* Increment the lock count so the task that unlocks the queue + * knows that data was removed while it was locked. */ + prvIncrementQueueRxLock( pxQueue, cRxLock ); + } + #endif /* queueUSE_LOCKS == 1 */ } xReturn = pdPASS; @@ -2019,7 +2289,7 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ); } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &( pxQueue->xQueueLock ), uxSavedInterruptStatus ); return xReturn; } @@ -2053,7 +2323,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, * link: https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &( pxQueue->xQueueLock ), uxSavedInterruptStatus ); { /* Cannot block in an ISR, so check there is data available. */ if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) @@ -2074,7 +2344,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ); } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &( pxQueue->xQueueLock ), uxSavedInterruptStatus ); return xReturn; } @@ -2086,11 +2356,11 @@ UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue ) configASSERT( xQueue ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( ( ( Queue_t * ) xQueue )->xQueueLock ) ); { uxReturn = ( ( Queue_t * ) xQueue )->uxMessagesWaiting; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( ( ( Queue_t * ) xQueue )->xQueueLock ) ); return uxReturn; } /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ @@ -2103,11 +2373,11 @@ UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue ) configASSERT( pxQueue ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); { uxReturn = pxQueue->uxLength - pxQueue->uxMessagesWaiting; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); return uxReturn; } /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ @@ -2329,50 +2599,74 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, } /*-----------------------------------------------------------*/ -static void prvUnlockQueue( Queue_t * const pxQueue ) -{ - /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */ - - /* The lock counts contains the number of extra data items placed or - * removed from the queue while the queue was locked. When a queue is - * locked items can be added or removed, but the event lists cannot be - * updated. */ - taskENTER_CRITICAL(); +#if ( queueUSE_LOCKS == 1 ) + static void prvUnlockQueue( Queue_t * const pxQueue ) { - int8_t cTxLock = pxQueue->cTxLock; + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */ - /* See if data was added to the queue while it was locked. */ - while( cTxLock > queueLOCKED_UNMODIFIED ) + /* The lock counts contains the number of extra data items placed or + * removed from the queue while the queue was locked. When a queue is + * locked items can be added or removed, but the event lists cannot be + * updated. */ + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); { - /* Data was posted while the queue was locked. Are any tasks - * blocked waiting for data to become available? */ - #if ( configUSE_QUEUE_SETS == 1 ) + int8_t cTxLock = pxQueue->cTxLock; + + /* See if data was added to the queue while it was locked. */ + while( cTxLock > queueLOCKED_UNMODIFIED ) { - if( pxQueue->pxQueueSetContainer != NULL ) + /* Data was posted while the queue was locked. Are any tasks + * blocked waiting for data to become available? */ + #if ( configUSE_QUEUE_SETS == 1 ) { - if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE ) + if( pxQueue->pxQueueSetContainer != NULL ) { - /* The queue is a member of a queue set, and posting to - * the queue set caused a higher priority task to unblock. - * A context switch is required. */ - vTaskMissedYield(); + if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE ) + { + /* The queue is a member of a queue set, and posting to + * the queue set caused a higher priority task to unblock. + * A context switch is required. */ + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } else { - mtCOVERAGE_TEST_MARKER(); + /* Tasks that are removed from the event list will get + * added to the pending ready list as the scheduler is still + * suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + * context switch is required. */ + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + break; + } } } - else + #else /* configUSE_QUEUE_SETS */ { - /* Tasks that are removed from the event list will get - * added to the pending ready list as the scheduler is still - * suspended. */ + /* Tasks that are removed from the event list will get added to + * the pending ready list as the scheduler is still suspended. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - /* The task waiting has a higher priority so record that a - * context switch is required. */ + /* The task waiting has a higher priority so record that + * a context switch is required. */ vTaskMissedYield(); } else @@ -2385,89 +2679,69 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) break; } } + #endif /* configUSE_QUEUE_SETS */ + + --cTxLock; } - #else /* configUSE_QUEUE_SETS */ + + pxQueue->cTxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); + + /* Do the same for the Rx lock. */ + taskENTER_CRITICAL( &( pxQueue->xQueueLock ) ); + { + int8_t cRxLock = pxQueue->cRxLock; + + while( cRxLock > queueLOCKED_UNMODIFIED ) { - /* Tasks that are removed from the event list will get added to - * the pending ready list as the scheduler is still suspended. */ - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { - /* The task waiting has a higher priority so record that - * a context switch is required. */ vTaskMissedYield(); } else { mtCOVERAGE_TEST_MARKER(); } + + --cRxLock; } else { break; } } - #endif /* configUSE_QUEUE_SETS */ - --cTxLock; + pxQueue->cRxLock = queueUNLOCKED; } - - pxQueue->cTxLock = queueUNLOCKED; + taskEXIT_CRITICAL( &( pxQueue->xQueueLock ) ); } - taskEXIT_CRITICAL(); +#endif /* queueUSE_LOCKS == 1 */ +/*-----------------------------------------------------------*/ - /* Do the same for the Rx lock. */ - taskENTER_CRITICAL(); +#if ( queueUSE_LOCKS == 1 ) + static BaseType_t prvIsQueueEmpty( const Queue_t * pxQueue ) { - int8_t cRxLock = pxQueue->cRxLock; + BaseType_t xReturn; - while( cRxLock > queueLOCKED_UNMODIFIED ) + taskENTER_CRITICAL( &( ( ( Queue_t * ) pxQueue )->xQueueLock ) ); { - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) - { - vTaskMissedYield(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - --cRxLock; + xReturn = pdTRUE; } else { - break; + xReturn = pdFALSE; } } + taskEXIT_CRITICAL( &( ( ( Queue_t * ) pxQueue )->xQueueLock ) ); - pxQueue->cRxLock = queueUNLOCKED; - } - taskEXIT_CRITICAL(); -} -/*-----------------------------------------------------------*/ - -static BaseType_t prvIsQueueEmpty( const Queue_t * pxQueue ) -{ - BaseType_t xReturn; - - taskENTER_CRITICAL(); - { - if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) - { - xReturn = pdTRUE; - } - else - { - xReturn = pdFALSE; - } + return xReturn; } - taskEXIT_CRITICAL(); - - return xReturn; -} +#endif /* queueUSE_LOCKS == 1 */ /*-----------------------------------------------------------*/ BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) @@ -2490,25 +2764,27 @@ BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) } /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ /*-----------------------------------------------------------*/ -static BaseType_t prvIsQueueFull( const Queue_t * pxQueue ) -{ - BaseType_t xReturn; - - taskENTER_CRITICAL(); +#if ( queueUSE_LOCKS == 1 ) + static BaseType_t prvIsQueueFull( const Queue_t * pxQueue ) { - if( pxQueue->uxMessagesWaiting == pxQueue->uxLength ) - { - xReturn = pdTRUE; - } - else + BaseType_t xReturn; + + taskENTER_CRITICAL( &( ( ( Queue_t * ) pxQueue )->xQueueLock ) ); { - xReturn = pdFALSE; + if( pxQueue->uxMessagesWaiting == pxQueue->uxLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } } - } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( ( ( Queue_t * ) pxQueue )->xQueueLock ) ); - return xReturn; -} + return xReturn; + } +#endif /* queueUSE_LOCKS == 1 */ /*-----------------------------------------------------------*/ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) @@ -2828,38 +3104,45 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) configASSERT( xQueue ); - if( pcQueueName != NULL ) + /* For SMP, we need to take the queue registry lock in case another + * core updates the register simultaneously. */ + taskENTER_CRITICAL_SMP_ONLY( &xQueueRegistryLock ); { - /* See if there is an empty space in the registry. A NULL name denotes - * a free slot. */ - for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + if( pcQueueName != NULL ) { - /* Replace an existing entry if the queue is already in the registry. */ - if( xQueue == xQueueRegistry[ ux ].xHandle ) - { - pxEntryToWrite = &( xQueueRegistry[ ux ] ); - break; - } - /* Otherwise, store in the next empty location */ - else if( ( pxEntryToWrite == NULL ) && ( xQueueRegistry[ ux ].pcQueueName == NULL ) ) - { - pxEntryToWrite = &( xQueueRegistry[ ux ] ); - } - else + /* See if there is an empty space in the registry. A NULL name denotes + * a free slot. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) { - mtCOVERAGE_TEST_MARKER(); + /* Replace an existing entry if the queue is already in the registry. */ + if( xQueue == xQueueRegistry[ ux ].xHandle ) + { + pxEntryToWrite = &( xQueueRegistry[ ux ] ); + break; + } + /* Otherwise, store in the next empty location */ + else if( ( pxEntryToWrite == NULL ) && ( xQueueRegistry[ ux ].pcQueueName == NULL ) ) + { + pxEntryToWrite = &( xQueueRegistry[ ux ] ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } - } - if( pxEntryToWrite != NULL ) - { - /* Store the information on this queue. */ - pxEntryToWrite->pcQueueName = pcQueueName; - pxEntryToWrite->xHandle = xQueue; + if( pxEntryToWrite != NULL ) + { + /* Store the information on this queue. */ + pxEntryToWrite->pcQueueName = pcQueueName; + pxEntryToWrite->xHandle = xQueue; - traceQUEUE_REGISTRY_ADD( xQueue, pcQueueName ); + traceQUEUE_REGISTRY_ADD( xQueue, pcQueueName ); + } } + /* Release the previously taken queue registry lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xQueueRegistryLock ); } #endif /* configQUEUE_REGISTRY_SIZE */ @@ -2874,21 +3157,28 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) configASSERT( xQueue ); - /* Note there is nothing here to protect against another task adding or - * removing entries from the registry while it is being searched. */ - - for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + /* For SMP, we need to take the queue registry lock in case another + * core updates the register simultaneously. */ + taskENTER_CRITICAL_SMP_ONLY( &xQueueRegistryLock ); { - if( xQueueRegistry[ ux ].xHandle == xQueue ) - { - pcReturn = xQueueRegistry[ ux ].pcQueueName; - break; - } - else + /* Note there is nothing here to protect against another task adding or + * removing entries from the registry while it is being searched. */ + + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) { - mtCOVERAGE_TEST_MARKER(); + if( xQueueRegistry[ ux ].xHandle == xQueue ) + { + pcReturn = xQueueRegistry[ ux ].pcQueueName; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } + /* Release the previously taken queue registry lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xQueueRegistryLock ); return pcReturn; } /*lint !e818 xQueue cannot be a pointer to const because it is a typedef. */ @@ -2904,26 +3194,33 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) configASSERT( xQueue ); - /* See if the handle of the queue being unregistered in actually in the - * registry. */ - for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + /* For SMP, we need to take the queue registry lock in case another + * core updates the register simultaneously. */ + taskENTER_CRITICAL_SMP_ONLY( &xQueueRegistryLock ); { - if( xQueueRegistry[ ux ].xHandle == xQueue ) + /* See if the handle of the queue being unregistered in actually in the + * registry. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) { - /* Set the name to NULL to show that this slot if free again. */ - xQueueRegistry[ ux ].pcQueueName = NULL; + if( xQueueRegistry[ ux ].xHandle == xQueue ) + { + /* Set the name to NULL to show that this slot if free again. */ + xQueueRegistry[ ux ].pcQueueName = NULL; - /* Set the handle to NULL to ensure the same queue handle cannot - * appear in the registry twice if it is added, removed, then - * added again. */ - xQueueRegistry[ ux ].xHandle = ( QueueHandle_t ) 0; - break; - } - else - { - mtCOVERAGE_TEST_MARKER(); + /* Set the handle to NULL to ensure the same queue handle cannot + * appear in the registry twice if it is added, removed, then + * added again. */ + xQueueRegistry[ ux ].xHandle = ( QueueHandle_t ) 0; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } + /* Release the previously taken queue registry lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xQueueRegistryLock ); } /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ #endif /* configQUEUE_REGISTRY_SIZE */ @@ -2945,25 +3242,40 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) * so it should be called with the scheduler locked and not from a critical * section. */ - /* Only do anything if there are no messages in the queue. This function - * will not actually cause the task to block, just place it on a blocked - * list. It will not block until the scheduler is unlocked - at which - * time a yield will be performed. If an item is added to the queue while - * the queue is locked, and the calling task blocks on the queue, then the - * calling task will be immediately unblocked when the queue is unlocked. */ - prvLockQueue( pxQueue ); - - if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U ) - { - /* There is nothing in the queue, block for the specified period. */ - vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely ); - } - else + /* For SMP, we need to take the queue's xQueueLock as we are about to + * access the queue. */ + taskENTER_CRITICAL_SMP_ONLY( &( pxQueue->xQueueLock ) ); { - mtCOVERAGE_TEST_MARKER(); - } + #if ( queueUSE_LOCKS == 1 ) + { + /* Only do anything if there are no messages in the queue. This function + * will not actually cause the task to block, just place it on a blocked + * list. It will not block until the scheduler is unlocked - at which + * time a yield will be performed. If an item is added to the queue while + * the queue is locked, and the calling task blocks on the queue, then the + * calling task will be immediately unblocked when the queue is unlocked. */ + prvLockQueue( pxQueue ); + } + #endif /* queueUSE_LOCKS == 1 */ - prvUnlockQueue( pxQueue ); + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U ) + { + /* There is nothing in the queue, block for the specified period. */ + vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + #if ( queueUSE_LOCKS == 1 ) + { + prvUnlockQueue( pxQueue ); + } + #endif /* queueUSE_LOCKS == 1 */ + } + /* Release the previously taken xQueueLock. */ + taskEXIT_CRITICAL_SMP_ONLY( &( pxQueue->xQueueLock ) ); } #endif /* configUSE_TIMERS */ @@ -2990,7 +3302,7 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) { BaseType_t xReturn; - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( ( ( Queue_t * ) xQueueOrSemaphore )->xQueueLock ) ); { if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL ) { @@ -3009,7 +3321,7 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) xReturn = pdPASS; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( ( ( Queue_t * ) xQueueOrSemaphore )->xQueueLock ) ); return xReturn; } @@ -3039,12 +3351,12 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) } else { - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( ( ( Queue_t * ) pxQueueOrSemaphore )->xQueueLock ) ); { /* The queue is no longer contained in the set. */ pxQueueOrSemaphore->pxQueueSetContainer = NULL; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( ( ( Queue_t * ) pxQueueOrSemaphore )->xQueueLock ) ); xReturn = pdPASS; } @@ -3096,23 +3408,37 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) configASSERT( pxQueueSetContainer ); /* LCOV_EXCL_BR_LINE */ configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); - if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) + /* In SMP, queue sets have their own xQueueLock. Thus we need to also + * acquire the queue set's xQueueLock before accessing it. */ + taskENTER_CRITICAL_SAFE_SMP_ONLY( &( pxQueueSetContainer->xQueueLock ) ); { - const int8_t cTxLock = pxQueueSetContainer->cTxLock; + if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) + { + #if ( queueUSE_LOCKS == 1 ) + const int8_t cTxLock = pxQueueSetContainer->cTxLock; + #else + /* Queue locks not used, so we treat it as unlocked. */ + const int8_t cTxLock = queueUNLOCKED; + #endif /* queueUSE_LOCKS == 1 */ - traceQUEUE_SET_SEND( pxQueueSetContainer ); + traceQUEUE_SET_SEND( pxQueueSetContainer ); - /* The data copied is the handle of the queue that contains data. */ - xReturn = prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, queueSEND_TO_BACK ); + /* The data copied is the handle of the queue that contains data. */ + xReturn = prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, queueSEND_TO_BACK ); - if( cTxLock == queueUNLOCKED ) - { - if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) + if( cTxLock == queueUNLOCKED ) { - if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) + if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) { - /* The task waiting has a higher priority. */ - xReturn = pdTRUE; + if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority. */ + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } else { @@ -3121,18 +3447,20 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) } else { - mtCOVERAGE_TEST_MARKER(); + #if ( queueUSE_LOCKS == 1 ) + { + prvIncrementQueueTxLock( pxQueueSetContainer, cTxLock ); + } + #endif /* queueUSE_LOCKS == 1 */ } } else { - prvIncrementQueueTxLock( pxQueueSetContainer, cTxLock ); + mtCOVERAGE_TEST_MARKER(); } } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Release the previously acquired queue set's xQueueLock. */ + taskEXIT_CRITICAL_SAFE_SMP_ONLY( &( pxQueueSetContainer->xQueueLock ) ); return xReturn; } diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/stream_buffer.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/stream_buffer.c index 236729cee6e..f474580ebcc 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/stream_buffer.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/stream_buffer.c @@ -43,6 +43,8 @@ #include "FreeRTOS.h" #include "task.h" #include "stream_buffer.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" #if ( configUSE_TASK_NOTIFICATIONS != 1 ) #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c @@ -63,18 +65,18 @@ * that uses task notifications. */ /*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */ #ifndef sbRECEIVE_COMPLETED - #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \ - vTaskSuspendAll(); \ - { \ - if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ - { \ - ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \ - ( uint32_t ) 0, \ - eNoAction ); \ - ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ - } \ - } \ - ( void ) xTaskResumeAll(); + #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \ + prvENTER_CRITICAL_OR_SUSPEND_ALL( &( pxStreamBuffer->xStreamBufferLock ) ); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ + { \ + ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \ + ( uint32_t ) 0, \ + eNoAction ); \ + ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ + } \ + } \ + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &( pxStreamBuffer->xStreamBufferLock ) ); #endif /* sbRECEIVE_COMPLETED */ /* If user has provided a per-instance receive complete callback, then @@ -140,18 +142,18 @@ * implementation that uses task notifications. */ #ifndef sbSEND_COMPLETED - #define sbSEND_COMPLETED( pxStreamBuffer ) \ - vTaskSuspendAll(); \ - { \ - if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ - { \ - ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \ - ( uint32_t ) 0, \ - eNoAction ); \ - ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ - } \ - } \ - ( void ) xTaskResumeAll(); + #define sbSEND_COMPLETED( pxStreamBuffer ) \ + prvENTER_CRITICAL_OR_SUSPEND_ALL( &( pxStreamBuffer->xStreamBufferLock ) ); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ + { \ + ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \ + ( uint32_t ) 0, \ + eNoAction ); \ + ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ + } \ + } \ + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &( pxStreamBuffer->xStreamBufferLock ) ); #endif /* sbSEND_COMPLETED */ /* If user has provided a per-instance send completed callback, then @@ -243,6 +245,8 @@ typedef struct StreamBufferDef_t /*lint !e9058 Style convention StreamBufferCallbackFunction_t pxSendCompletedCallback; /* Optional callback called on send complete. sbSEND_COMPLETED is called if this is NULL. */ StreamBufferCallbackFunction_t pxReceiveCompletedCallback; /* Optional callback called on receive complete. sbRECEIVE_COMPLETED is called if this is NULL. */ #endif + + portMUX_TYPE xStreamBufferLock; /* Spinlock required for SMP critical sections */ } StreamBuffer_t; /* @@ -385,6 +389,11 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, pxSendCompletedCallback, pxReceiveCompletedCallback ); + /* Initialize the stream buffer's spinlock separately, as + * prvInitialiseNewStreamBuffer() is also called from + * xStreamBufferReset(). */ + portMUX_INITIALIZE( &( ( ( StreamBuffer_t * ) pucAllocatedMemory )->xStreamBufferLock ) ); + traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer ); } else @@ -463,6 +472,11 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, * again. */ pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED; + /* Initialize the stream buffer's spinlock separately, as + * prvInitialiseNewStreamBuffer() is also called from + * xStreamBufferReset(). */ + portMUX_INITIALIZE( &( pxStreamBuffer->xStreamBufferLock ) ); + traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ); xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */ @@ -560,7 +574,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) #endif /* Can only reset a message buffer if there are no tasks blocked on it. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); { if( ( pxStreamBuffer->xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer->xTaskWaitingToSend == NULL ) ) { @@ -590,7 +604,7 @@ BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) xReturn = pdPASS; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); return xReturn; } @@ -736,7 +750,7 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, { /* Wait until the required number of bytes are free in the message * buffer. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); { xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); @@ -751,11 +765,11 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, } else { - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); break; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ); ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); @@ -932,7 +946,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, { /* Checking if there is data and clearing the notification state must be * performed atomically. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); { xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); @@ -955,7 +969,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &( pxStreamBuffer->xStreamBufferLock ) ); if( xBytesAvailable <= xBytesToStoreMessageLength ) { @@ -1409,7 +1423,17 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */ #endif - ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */ + /* This function could be called from xStreamBufferReset(), so we reset the + * stream buffer fields manually in order to avoid clearing + * xStreamBufferLock. The xStreamBufferLock is initialized separately on + * stream buffer creation. */ + pxStreamBuffer->xTail = ( size_t ) 0; + pxStreamBuffer->xHead = ( size_t ) 0; + pxStreamBuffer->xTaskWaitingToReceive = ( TaskHandle_t ) 0; + pxStreamBuffer->xTaskWaitingToSend = ( TaskHandle_t ) 0; + #if ( configUSE_TRACE_FACILITY == 1 ) + pxStreamBuffer->uxStreamBufferNumber = ( UBaseType_t ) 0; + #endif pxStreamBuffer->pucBuffer = pucBuffer; pxStreamBuffer->xLength = xBufferSizeBytes; pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes; diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c index 47371e8ebdd..5c25e0c129d 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c @@ -44,6 +44,8 @@ #include "task.h" #include "timers.h" #include "stack_macros.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" #include "freertos/idf_additions.h" /* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified @@ -63,6 +65,67 @@ #include #endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */ +/* Some code sections require extra critical sections when building for SMP + * ( configNUMBER_OF_CORES > 1 ). */ +#if ( configNUMBER_OF_CORES > 1 ) + /* Macros that Enter/exit a critical section only when building for SMP */ + #define taskENTER_CRITICAL_SMP_ONLY( pxLock ) taskENTER_CRITICAL( pxLock ) + #define taskEXIT_CRITICAL_SMP_ONLY( pxLock ) taskEXIT_CRITICAL( pxLock ) + #define taskENTER_CRITICAL_ISR_SMP_ONLY( pxLock ) taskENTER_CRITICAL_ISR( pxLock ) + #define taskEXIT_CRITICAL_ISR_SMP_ONLY( pxLock ) taskEXIT_CRITICAL_ISR( pxLock ) + #define taskENTER_CRITICAL_SAFE_SMP_ONLY( pxLock ) prvTaskEnterCriticalSafeSMPOnly( pxLock ) + #define taskEXIT_CRITICAL_SAFE_SMP_ONLY( pxLock ) prvTaskExitCriticalSafeSMPOnly( pxLock ) + /* Macros that Enter/exit a critical section only when building for single-core */ + #define taskENTER_CRITICAL_SC_ONLY( pxLock ) taskENTER_CRITICAL( pxLock ) + #define taskEXIT_CRITICAL_SC_ONLY( pxLock ) taskEXIT_CRITICAL( pxLock ) + + static inline __attribute__( ( always_inline ) ) + void prvTaskEnterCriticalSafeSMPOnly( portMUX_TYPE * pxLock ) + { + if( portCHECK_IF_IN_ISR() == pdFALSE ) + { + taskENTER_CRITICAL( pxLock ); + } + else + { + #ifdef __clang_analyzer__ + /* Teach clang-tidy that ISR version macro can be different */ + configASSERT( 1 ); + #endif + taskENTER_CRITICAL_ISR( pxLock ); + } + } + + static inline __attribute__( ( always_inline ) ) + void prvTaskExitCriticalSafeSMPOnly( portMUX_TYPE * pxLock ) + { + if( portCHECK_IF_IN_ISR() == pdFALSE ) + { + taskEXIT_CRITICAL( pxLock ); + } + else + { + #ifdef __clang_analyzer__ + /* Teach clang-tidy that ISR version macro can be different */ + configASSERT( 1 ); + #endif + taskEXIT_CRITICAL_ISR( pxLock ); + } + } + +#else /* configNUMBER_OF_CORES > 1 */ + /* Macros that Enter/exit a critical section only when building for SMP */ + #define taskENTER_CRITICAL_SMP_ONLY( pxLock ) + #define taskEXIT_CRITICAL_SMP_ONLY( pxLock ) + #define taskENTER_CRITICAL_ISR_SMP_ONLY( pxLock ) + #define taskEXIT_CRITICAL_ISR_SMP_ONLY( pxLock ) + #define taskENTER_CRITICAL_SAFE_SMP_ONLY( pxLock ) + #define taskEXIT_CRITICAL_SAFE_SMP_ONLY( pxLock ) + /* Macros that Enter/exit a critical section only when building for single-core */ + #define taskENTER_CRITICAL_SC_ONLY( pxLock ) taskENTER_CRITICAL( pxLock ) + #define taskEXIT_CRITICAL_SC_ONLY( pxLock ) taskEXIT_CRITICAL( pxLock ) +#endif /* configNUMBER_OF_CORES > 1 */ + #if ( configUSE_PREEMPTION == 0 ) /* If the cooperative scheduler is being used then a yield should not be @@ -490,6 +553,10 @@ PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0UL #endif +/* Spinlock required for SMP critical sections. This lock protects all of the + * kernel's data structures such as various tasks lists, flags, and tick counts. */ +PRIVILEGED_DATA static portMUX_TYPE xKernelLock = portMUX_INITIALIZER_UNLOCKED; + /*lint -restore */ /*-----------------------------------------------------------*/ @@ -1141,7 +1208,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) { /* Ensure interrupts don't access the task lists while the lists are being * updated. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { uxCurrentNumberOfTasks++; @@ -1218,27 +1285,29 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) prvAddTaskToReadyList( pxNewTCB ); portSETUP_TCB( pxNewTCB ); - } - if( xSchedulerRunning != pdFALSE ) - { - /* If the created task is of a higher priority than the current task - * then it should run now. */ - if( taskIS_YIELD_REQUIRED( pxNewTCB, portGET_CORE_ID(), pdTRUE ) == pdTRUE ) + if( xSchedulerRunning != pdFALSE ) { - taskYIELD_IF_USING_PREEMPTION(); + /* If the created task is of a higher priority than the current task + * then it should run now. */ + if( taskIS_YIELD_REQUIRED( pxNewTCB, portGET_CORE_ID(), pdTRUE ) == pdTRUE ) + { + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } else { mtCOVERAGE_TEST_MARKER(); } } - else - { - mtCOVERAGE_TEST_MARKER(); - } + taskEXIT_CRITICAL( &xKernelLock ); - taskEXIT_CRITICAL(); + /* SINGLE-CORE MODIFICATION: Extended critical section so that SMP can check + * for yield inside critical section. */ } /*-----------------------------------------------------------*/ @@ -1250,7 +1319,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) BaseType_t xSelfDelete; BaseType_t xIsCurRunning; - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -1355,7 +1424,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) prvResetNextTaskUnblockTime(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); /* If the task is currently running, call prvDeleteTCB from outside of * critical section. If a task is currently running, prvDeleteTCB is @@ -1366,20 +1435,27 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) prvDeleteTCB( pxTCB ); } - /* Force a reschedule if it is the currently running task that has just - * been deleted. */ - if( xSchedulerRunning != pdFALSE ) + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { - if( xSelfDelete == pdTRUE ) - { - configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE ); - portYIELD_WITHIN_API(); - } - else + /* Force a reschedule if it is the currently running task that has just + * been deleted. */ + if( xSchedulerRunning != pdFALSE ) { - mtCOVERAGE_TEST_MARKER(); + if( xSelfDelete == pdTRUE ) + { + configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE ); + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } #endif /* INCLUDE_vTaskDelete */ @@ -1397,7 +1473,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) configASSERT( ( xTimeIncrement > 0U ) ); configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE ); - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &xKernelLock ); { /* Minor optimisation. The tick count cannot change in this * block. */ @@ -1453,7 +1529,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) mtCOVERAGE_TEST_MARKER(); } } - xAlreadyYielded = xTaskResumeAll(); + xAlreadyYielded = prvEXIT_CRITICAL_OR_RESUME_ALL( &xKernelLock ); /* Force a reschedule if xTaskResumeAll has not already done so, we may * have put ourselves to sleep. */ @@ -1482,7 +1558,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) if( xTicksToDelay > ( TickType_t ) 0U ) { configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE ); - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &xKernelLock ); { traceTASK_DELAY(); @@ -1495,7 +1571,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * executing task. */ prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE ); } - xAlreadyYielded = xTaskResumeAll(); + xAlreadyYielded = prvEXIT_CRITICAL_OR_RESUME_ALL( &xKernelLock ); } else { @@ -1529,7 +1605,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) configASSERT( pxTCB ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { if( taskIS_CURRENTLY_RUNNING( pxTCB ) == pdTRUE ) { @@ -1608,7 +1684,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) } } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return eReturn; } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ @@ -1623,14 +1699,14 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) TCB_t const * pxTCB; UBaseType_t uxReturn; - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* If null is passed in here then it is the priority of the task * that called uxTaskPriorityGet() that is being queried. */ pxTCB = prvGetTCBFromHandle( xTask ); uxReturn = pxTCB->uxPriority; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return uxReturn; } @@ -1663,14 +1739,14 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &xKernelLock, uxSavedInterruptState ); { /* If null is passed in here then it is the priority of the calling * task that is being queried. */ pxTCB = prvGetTCBFromHandle( xTask ); uxReturn = pxTCB->uxPriority; } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &xKernelLock, uxSavedInterruptState ); return uxReturn; } @@ -1699,7 +1775,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) mtCOVERAGE_TEST_MARKER(); } - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -1851,7 +1927,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) ( void ) uxPriorityUsedOnEntry; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); } #endif /* INCLUDE_vTaskPrioritySet */ @@ -1863,7 +1939,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) { TCB_t * pxTCB; - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -1978,7 +2054,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); } #endif /* INCLUDE_vTaskSuspend */ @@ -2044,7 +2120,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) /* It does not make sense to resume the calling task. */ configASSERT( xTaskToResume ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* The parameter cannot be NULL as it is impossible to resume the * currently executing task. */ @@ -2082,7 +2158,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); } #endif /* INCLUDE_vTaskSuspend */ @@ -2117,7 +2193,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &xKernelLock, uxSavedInterruptStatus ); { if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) { @@ -2161,7 +2237,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) mtCOVERAGE_TEST_MARKER(); } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &xKernelLock, uxSavedInterruptStatus ); return xYieldRequired; } @@ -2255,17 +2331,24 @@ void vTaskStartScheduler( void ) * starts to run. */ portDISABLE_INTERRUPTS(); - #if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) ) + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { - /* Switch C-Runtime's TLS Block to point to the TLS - * block specific to the task that will run first. */ - configSET_TLS_BLOCK( pxCurrentTCBs[ portGET_CORE_ID() ]->xTLSBlock ); - } - #endif + #if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) ) + { + /* Switch C-Runtime's TLS Block to point to the TLS + * block specific to the task that will run first. */ + configSET_TLS_BLOCK( pxCurrentTCBs[ portGET_CORE_ID() ]->xTLSBlock ); + } + #endif - xNextTaskUnblockTime = portMAX_DELAY; - xSchedulerRunning = pdTRUE; - xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT; + xNextTaskUnblockTime = portMAX_DELAY; + xSchedulerRunning = pdTRUE; + xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT; + } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); /* If configGENERATE_RUN_TIME_STATS is defined then the following * macro must be defined to configure the timer/counter used to generate @@ -2312,7 +2395,15 @@ void vTaskEndScheduler( void ) * routine so the original ISRs can be restored if necessary. The port * layer must ensure interrupts enable bit is left in the correct state. */ portDISABLE_INTERRUPTS(); - xSchedulerRunning = pdFALSE; + + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); + { + xSchedulerRunning = pdFALSE; + } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); vPortEndScheduler(); } /*----------------------------------------------------------*/ @@ -2415,7 +2506,7 @@ BaseType_t xTaskResumeAll( void ) * removed task will have been added to the xPendingReadyList. Once the * scheduler has been resumed it is safe to move all the pending ready * tasks from this list into their appropriate ready list. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -2517,7 +2608,7 @@ BaseType_t xTaskResumeAll( void ) mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return xAlreadyYielded; } @@ -2559,11 +2650,18 @@ TickType_t xTaskGetTickCountFromISR( void ) * link: https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); - uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures. */ + taskENTER_CRITICAL_ISR_SMP_ONLY( &xKernelLock ); { - xReturn = xTickCount; + uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); + { + xReturn = xTickCount; + } + portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); } - portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_ISR_SMP_ONLY( &xKernelLock ); return xReturn; } @@ -2670,7 +2768,7 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char /* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */ configASSERT( strlen( pcNameToQuery ) < configMAX_TASK_NAME_LEN ); - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &xKernelLock ); { /* Search the ready lists. */ do @@ -2716,7 +2814,7 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char } #endif } - ( void ) xTaskResumeAll(); + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &xKernelLock ); return pxTCB; } @@ -2780,7 +2878,7 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char { UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES; - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &xKernelLock ); { /* Is there a space in the array for each task in the system? */ if( uxArraySize >= uxCurrentNumberOfTasks ) @@ -2839,7 +2937,7 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char mtCOVERAGE_TEST_MARKER(); } } - ( void ) xTaskResumeAll(); + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &xKernelLock ); return uxTask; } @@ -2865,9 +2963,9 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char void vTaskStepTick( TickType_t xTicksToJump ) { - /* SINGLE-CORE MODIFICATION: Expanded critical section to ensure thread - * safe access to xTickCount between multiple cores. */ - taskENTER_CRITICAL(); + /* SINGLE-CORE MODIFICATION: Expanded critical section so that SMP + * accesses xTickCount inside a critical section. */ + taskENTER_CRITICAL( &xKernelLock ); { /* Correct the tick count value after a period during which the tick * was suppressed. Note this does *not* call the tick hook function for @@ -2893,7 +2991,8 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char xTickCount += xTicksToJump; traceINCREASE_TICK_COUNT( xTicksToJump ); } - taskEXIT_CRITICAL(); + /* SINGLE-CORE MODIFICATION: Expanded critical section */ + taskEXIT_CRITICAL( &xKernelLock ); } #endif /* configUSE_TICKLESS_IDLE */ @@ -2912,11 +3011,11 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) vTaskSuspendAll(); /* Prevent the tick interrupt modifying xPendedTicks simultaneously. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { xPendedTicks += xTicksToCatchUp; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); xYieldOccurred = xTaskResumeAll(); return xYieldOccurred; @@ -2932,7 +3031,7 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) configASSERT( pxTCB ); - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &xKernelLock ); { /* A task can only be prematurely removed from the Blocked state if * it is actually in the Blocked state. */ @@ -2949,7 +3048,7 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) * the event list too. Interrupts can touch the event list item, * even though the scheduler is suspended, so a critical section * is used. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL_SC_ONLY( &xKernelLock ); { if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) { @@ -2965,7 +3064,7 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL_SC_ONLY( &xKernelLock ); /* Place the unblocked task into the appropriate ready list. */ prvAddTaskToReadyList( pxTCB ); @@ -2998,7 +3097,7 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) xReturn = pdFAIL; } } - ( void ) xTaskResumeAll(); + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &xKernelLock ); return xReturn; } @@ -3016,174 +3115,196 @@ BaseType_t xTaskIncrementTick( void ) TCB_t * pxTCB; TickType_t xItemValue; BaseType_t xSwitchRequired = pdFALSE; + #if ( configUSE_TICK_HOOK == 1 ) + BaseType_t xCallTickHook; + #endif /* configUSE_TICK_HOOK == 1 */ /* Called by the portable layer each time a tick interrupt occurs. * Increments the tick then checks to see if the new tick value will cause any * tasks to be unblocked. */ traceTASK_INCREMENT_TICK( xTickCount ); - if( uxSchedulerSuspended[ 0 ] == ( UBaseType_t ) pdFALSE ) + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures (unlike single core which calls this function with + * interrupts disabled). */ + taskENTER_CRITICAL_SAFE_SMP_ONLY( &xKernelLock ); { - /* Minor optimisation. The tick count cannot change in this - * block. */ - const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1; + if( uxSchedulerSuspended[ 0 ] == ( UBaseType_t ) pdFALSE ) + { + /* Minor optimisation. The tick count cannot change in this + * block. */ + const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1; - /* Increment the RTOS tick, switching the delayed and overflowed - * delayed lists if it wraps to 0. */ - xTickCount = xConstTickCount; + /* Increment the RTOS tick, switching the delayed and overflowed + * delayed lists if it wraps to 0. */ + xTickCount = xConstTickCount; - if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */ - { - taskSWITCH_DELAYED_LISTS(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */ + { + taskSWITCH_DELAYED_LISTS(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - /* See if this tick has made a timeout expire. Tasks are stored in - * the queue in the order of their wake time - meaning once one task - * has been found whose block time has not expired there is no need to - * look any further down the list. */ - if( xConstTickCount >= xNextTaskUnblockTime ) - { - for( ; ; ) + /* See if this tick has made a timeout expire. Tasks are stored in + * the queue in the order of their wake time - meaning once one task + * has been found whose block time has not expired there is no need to + * look any further down the list. */ + if( xConstTickCount >= xNextTaskUnblockTime ) { - if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) - { - /* The delayed list is empty. Set xNextTaskUnblockTime - * to the maximum possible value so it is extremely - * unlikely that the - * if( xTickCount >= xNextTaskUnblockTime ) test will pass - * next time through. */ - xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - break; - } - else + for( ; ; ) { - /* The delayed list is not empty, get the value of the - * item at the head of the delayed list. This is the time - * at which the task at the head of the delayed list must - * be removed from the Blocked state. */ - pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ - xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) ); - - if( xConstTickCount < xItemValue ) + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) { - /* It is not time to unblock this item yet, but the - * item value is the time at which the task at the head - * of the blocked list must be removed from the Blocked - * state - so record the item value in - * xNextTaskUnblockTime. */ - xNextTaskUnblockTime = xItemValue; - break; /*lint !e9011 Code structure here is deemed easier to understand with multiple breaks. */ - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - /* It is time to remove the item from the Blocked state. */ - listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); - - /* Is the task waiting on an event also? If so remove - * it from the event list. */ - if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) - { - listREMOVE_ITEM( &( pxTCB->xEventListItem ) ); + /* The delayed list is empty. Set xNextTaskUnblockTime + * to the maximum possible value so it is extremely + * unlikely that the + * if( xTickCount >= xNextTaskUnblockTime ) test will pass + * next time through. */ + xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + break; } else { - mtCOVERAGE_TEST_MARKER(); - } + /* The delayed list is not empty, get the value of the + * item at the head of the delayed list. This is the time + * at which the task at the head of the delayed list must + * be removed from the Blocked state. */ + pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ + xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) ); + + if( xConstTickCount < xItemValue ) + { + /* It is not time to unblock this item yet, but the + * item value is the time at which the task at the head + * of the blocked list must be removed from the Blocked + * state - so record the item value in + * xNextTaskUnblockTime. */ + xNextTaskUnblockTime = xItemValue; + break; /*lint !e9011 Code structure here is deemed easier to understand with multiple breaks. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - /* Place the unblocked task into the appropriate ready - * list. */ - prvAddTaskToReadyList( pxTCB ); + /* It is time to remove the item from the Blocked state. */ + listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); - /* A task being unblocked cannot cause an immediate - * context switch if preemption is turned off. */ - #if ( configUSE_PREEMPTION == 1 ) - { - /* Preemption is on, but a context switch should - * only be performed if the unblocked task has a - * priority that is equal to or higher than the - * currently executing task. - * - * For SMP, since this function is only run on core - * 0, we only need to context switch if the unblocked - * task can run on core 0 and has a higher priority - * than the current task. */ - if( ( taskIS_AFFINITY_COMPATIBLE( 0, pxTCB->xCoreID ) == pdTRUE ) && ( pxTCB->uxPriority > pxCurrentTCBs[ 0 ]->uxPriority ) ) + /* Is the task waiting on an event also? If so remove + * it from the event list. */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) { - xSwitchRequired = pdTRUE; + listREMOVE_ITEM( &( pxTCB->xEventListItem ) ); } else { mtCOVERAGE_TEST_MARKER(); } + + /* Place the unblocked task into the appropriate ready + * list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate + * context switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should + * only be performed if the unblocked task has a + * priority that is equal to or higher than the + * currently executing task. + * + * For SMP, since this function is only run on core + * 0, we only need to context switch if the unblocked + * task can run on core 0 and has a higher priority + * than the current task. */ + if( ( taskIS_AFFINITY_COMPATIBLE( 0, pxTCB->xCoreID ) == pdTRUE ) && ( pxTCB->uxPriority > pxCurrentTCBs[ 0 ]->uxPriority ) ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ } - #endif /* configUSE_PREEMPTION */ } } - } - /* Tasks of equal priority to the currently running task will share - * processing time (time slice) if preemption is on, and the application - * writer has not explicitly turned time slicing off. */ - #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) - { - if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCBs[ 0 ]->uxPriority ] ) ) > ( UBaseType_t ) 1 ) - { - xSwitchRequired = pdTRUE; - } - else + /* Tasks of equal priority to the currently running task will share + * processing time (time slice) if preemption is on, and the application + * writer has not explicitly turned time slicing off. */ + #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) { - mtCOVERAGE_TEST_MARKER(); + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCBs[ 0 ]->uxPriority ] ) ) > ( UBaseType_t ) 1 ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } - } - #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ - #if ( configUSE_TICK_HOOK == 1 ) - { - /* Guard against the tick hook being called when the pended tick - * count is being unwound (when the scheduler is being unlocked). */ - if( xPendedTicksTemp == ( TickType_t ) 0 ) + #if ( configUSE_TICK_HOOK == 1 ) { - vApplicationTickHook(); + /* Guard against the tick hook being called when the pended tick + * count is being unwound (when the scheduler is being unlocked). */ + if( xPendedTicksTemp == ( TickType_t ) 0 ) + { + xCallTickHook = pdTRUE; + } + else + { + xCallTickHook = pdFALSE; + } } - else + #endif /* configUSE_TICK_HOOK */ + + #if ( configUSE_PREEMPTION == 1 ) { - mtCOVERAGE_TEST_MARKER(); + if( xYieldPending[ 0 ] != pdFALSE ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } + #endif /* configUSE_PREEMPTION */ } - #endif /* configUSE_TICK_HOOK */ - - #if ( configUSE_PREEMPTION == 1 ) + else { - if( xYieldPending[ 0 ] != pdFALSE ) - { - xSwitchRequired = pdTRUE; - } - else + ++xPendedTicks; + + /* The tick hook gets called at regular intervals, even if the + * scheduler is locked. */ + #if ( configUSE_TICK_HOOK == 1 ) { - mtCOVERAGE_TEST_MARKER(); + xCallTickHook = pdTRUE; } + #endif } - #endif /* configUSE_PREEMPTION */ } - else - { - ++xPendedTicks; - /* The tick hook gets called at regular intervals, even if the - * scheduler is locked. */ - #if ( configUSE_TICK_HOOK == 1 ) + /* Release the previously taken kernel lock as we have finished accessing + * the kernel data structures. */ + taskEXIT_CRITICAL_SAFE_SMP_ONLY( &xKernelLock ); + + #if ( configUSE_TICK_HOOK == 1 ) + { + if( xCallTickHook == pdTRUE ) { vApplicationTickHook(); } - #endif } + #endif return xSwitchRequired; } @@ -3209,11 +3330,11 @@ BaseType_t xTaskIncrementTick( void ) /* Save the hook function in the TCB. A critical section is required as * the value can be accessed from an interrupt. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { xTCB->pxTaskTag = pxHookFunction; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); } #endif /* configUSE_APPLICATION_TASK_TAG */ @@ -3231,11 +3352,11 @@ BaseType_t xTaskIncrementTick( void ) /* Save the hook function in the TCB. A critical section is required as * the value can be accessed from an interrupt. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { xReturn = pxTCB->pxTaskTag; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return xReturn; } @@ -3256,11 +3377,11 @@ BaseType_t xTaskIncrementTick( void ) /* Save the hook function in the TCB. A critical section is required as * the value can be accessed from an interrupt. */ - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &xKernelLock, uxSavedInterruptStatus ); { xReturn = pxTCB->pxTaskTag; } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &xKernelLock, uxSavedInterruptStatus ); return xReturn; } @@ -3394,78 +3515,88 @@ BaseType_t xTaskIncrementTick( void ) void vTaskSwitchContext( void ) { - /* Get current core ID as we can no longer be preempted. */ - const BaseType_t xCurCoreID = portGET_CORE_ID(); - - if( uxSchedulerSuspended[ xCurCoreID ] != ( UBaseType_t ) pdFALSE ) - { - /* The scheduler is currently suspended - do not allow a context - * switch. */ - xYieldPending[ xCurCoreID ] = pdTRUE; - } - else + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures (unlike single core which calls this function with + * either interrupts disabled or when the scheduler hasn't started yet). */ + taskENTER_CRITICAL_SAFE_SMP_ONLY( &xKernelLock ); { - xYieldPending[ xCurCoreID ] = pdFALSE; - traceTASK_SWITCHED_OUT(); + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); - #if ( configGENERATE_RUN_TIME_STATS == 1 ) + if( uxSchedulerSuspended[ xCurCoreID ] != ( UBaseType_t ) pdFALSE ) { - #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE - portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); - #else - ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); - #endif + /* The scheduler is currently suspended - do not allow a context + * switch. */ + xYieldPending[ xCurCoreID ] = pdTRUE; + } + else + { + xYieldPending[ xCurCoreID ] = pdFALSE; + traceTASK_SWITCHED_OUT(); - /* Add the amount of time the task has been running to the - * accumulated time so far. The time the task started running was - * stored in ulTaskSwitchedInTime. Note that there is no overflow - * protection here so count values are only valid until the timer - * overflows. The guard against negative values is to protect - * against suspect run time stat counter implementations - which - * are provided by the application, not the kernel. */ - if( ulTotalRunTime > ulTaskSwitchedInTime[ xCurCoreID ] ) - { - pxCurrentTCBs[ xCurCoreID ]->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime[ xCurCoreID ] ); - } - else + #if ( configGENERATE_RUN_TIME_STATS == 1 ) { - mtCOVERAGE_TEST_MARKER(); - } + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); + #else + ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + #endif - ulTaskSwitchedInTime[ xCurCoreID ] = ulTotalRunTime; - } - #endif /* configGENERATE_RUN_TIME_STATS */ + /* Add the amount of time the task has been running to the + * accumulated time so far. The time the task started running was + * stored in ulTaskSwitchedInTime. Note that there is no overflow + * protection here so count values are only valid until the timer + * overflows. The guard against negative values is to protect + * against suspect run time stat counter implementations - which + * are provided by the application, not the kernel. */ + if( ulTotalRunTime > ulTaskSwitchedInTime[ xCurCoreID ] ) + { + pxCurrentTCBs[ xCurCoreID ]->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime[ xCurCoreID ] ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - /* Check for stack overflow, if configured. */ - taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ); + ulTaskSwitchedInTime[ xCurCoreID ] = ulTotalRunTime; + } + #endif /* configGENERATE_RUN_TIME_STATS */ - /* Before the currently running task is switched out, save its errno. */ - #if ( configUSE_POSIX_ERRNO == 1 ) - { - pxCurrentTCBs[ xCurCoreID ]->iTaskErrno = FreeRTOS_errno; - } - #endif + /* Check for stack overflow, if configured. */ + taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ); - /* Select a new task to run using either the generic C or port - * optimised asm code. */ - taskSELECT_HIGHEST_PRIORITY_TASK(); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ - traceTASK_SWITCHED_IN(); + /* Before the currently running task is switched out, save its errno. */ + #if ( configUSE_POSIX_ERRNO == 1 ) + { + pxCurrentTCBs[ xCurCoreID ]->iTaskErrno = FreeRTOS_errno; + } + #endif - /* After the new task is switched in, update the global errno. */ - #if ( configUSE_POSIX_ERRNO == 1 ) - { - FreeRTOS_errno = pxCurrentTCBs[ xCurCoreID ]->iTaskErrno; - } - #endif + /* Select a new task to run using either the generic C or port + * optimised asm code. */ + taskSELECT_HIGHEST_PRIORITY_TASK(); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ + traceTASK_SWITCHED_IN(); - #if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) ) - { - /* Switch C-Runtime's TLS Block to point to the TLS - * Block specific to this task. */ - configSET_TLS_BLOCK( pxCurrentTCBs[ xCurCoreID ]->xTLSBlock ); + /* After the new task is switched in, update the global errno. */ + #if ( configUSE_POSIX_ERRNO == 1 ) + { + FreeRTOS_errno = pxCurrentTCBs[ xCurCoreID ]->iTaskErrno; + } + #endif + + #if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) ) + { + /* Switch C-Runtime's TLS Block to point to the TLS + * Block specific to this task. */ + configSET_TLS_BLOCK( pxCurrentTCBs[ xCurCoreID ]->xTLSBlock ); + } + #endif } - #endif } + + /* Release the previously taken kernel lock as we have finished accessing + * the kernel data structures. */ + taskEXIT_CRITICAL_SAFE_SMP_ONLY( &xKernelLock ); } /*-----------------------------------------------------------*/ @@ -3474,23 +3605,31 @@ void vTaskPlaceOnEventList( List_t * const pxEventList, { configASSERT( pxEventList ); - /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE - * SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */ - - /* Place the event list item of the TCB in the appropriate event list. - * This is placed in the list in priority order so the highest priority task - * is the first to be woken by the event. - * - * Note: Lists are sorted in ascending order by ListItem_t.xItemValue. - * Normally, the xItemValue of a TCB's ListItem_t members is: - * xItemValue = ( configMAX_PRIORITIES - uxPriority ) - * Therefore, the event list is sorted in descending priority order. - * - * The queue that contains the event list is locked, preventing - * simultaneous access from interrupts. */ - vListInsert( pxEventList, &( pxCurrentTCBs[ portGET_CORE_ID() ]->xEventListItem ) ); - - prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + /* IN SINGLE-CORE THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED + * OR THE SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. IN SMP + * THIS FUNCTION MUST BE CALLED WITH THE QUEUE'S xQueueLock TAKEN. */ + + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); + { + /* Place the event list item of the TCB in the appropriate event list. + * This is placed in the list in priority order so the highest priority task + * is the first to be woken by the event. + * + * Note: Lists are sorted in ascending order by ListItem_t.xItemValue. + * Normally, the xItemValue of a TCB's ListItem_t members is: + * xItemValue = ( configMAX_PRIORITIES - uxPriority ) + * Therefore, the event list is sorted in descending priority order. + * + * The queue that contains the event list is locked, preventing + * simultaneous access from interrupts. */ + vListInsert( pxEventList, &( pxCurrentTCBs[ portGET_CORE_ID() ]->xEventListItem ) ); + + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } /*-----------------------------------------------------------*/ @@ -3503,23 +3642,39 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, configASSERT( pxEventList ); - /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by - * the event groups implementation. */ - configASSERT( uxSchedulerSuspended[ xCurCoreID ] != 0 ); - - /* Store the item value in the event list item. It is safe to access the - * event list item here as interrupts won't access the event list item of a - * task that is not in the Blocked state. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); - - /* Place the event list item of the TCB at the end of the appropriate event - * list. It is safe to access the event list here because it is part of an - * event group implementation - and interrupts don't access event groups - * directly (instead they access them indirectly by pending function calls to - * the task level). */ - listINSERT_END( pxEventList, &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ) ); + #if ( configNUMBER_OF_CORES > 1 ) + { + /* IN SMP, THIS FUNCTION MUST BE CALLED WITH THE EVENT GROUP'S + * xEventGroupLock ALREADY TAKEN. */ + } + #else /* configNUMBER_OF_CORES > 1 */ + { + /* IN SINGLE-CORE, THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. + * It is used by the event groups implementation. */ + configASSERT( uxSchedulerSuspended[ xCurCoreID ] != 0 ); + } + #endif /* configNUMBER_OF_CORES > 1 */ - prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); + { + /* Store the item value in the event list item. It is safe to access the + * event list item here as interrupts won't access the event list item of a + * task that is not in the Blocked state. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); + + /* Place the event list item of the TCB at the end of the appropriate event + * list. It is safe to access the event list here because it is part of an + * event group implementation - and interrupts don't access event groups + * directly (instead they access them indirectly by pending function calls to + * the task level). */ + listINSERT_END( pxEventList, &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ) ); + + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } /*-----------------------------------------------------------*/ @@ -3534,25 +3689,32 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, /* This function should not be called by application code hence the * 'Restricted' in its name. It is not part of the public API. It is * designed for use by kernel code, and has special calling requirements - - * it should be called with the scheduler suspended. */ + * it should be called with the scheduler suspended in single-core, or + * with the queue's xQueueLock already taken in SMP. */ + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); + { + /* Place the event list item of the TCB in the appropriate event list. + * In this case it is assume that this is the only task that is going to + * be waiting on this event list, so the faster vListInsertEnd() function + * can be used in place of vListInsert. */ + listINSERT_END( pxEventList, &( pxCurrentTCBs[ portGET_CORE_ID() ]->xEventListItem ) ); - /* Place the event list item of the TCB in the appropriate event list. - * In this case it is assume that this is the only task that is going to - * be waiting on this event list, so the faster vListInsertEnd() function - * can be used in place of vListInsert. */ - listINSERT_END( pxEventList, &( pxCurrentTCBs[ portGET_CORE_ID() ]->xEventListItem ) ); + /* If the task should block indefinitely then set the block time to a + * value that will be recognised as an indefinite delay inside the + * prvAddCurrentTaskToDelayedList() function. */ + if( xWaitIndefinitely != pdFALSE ) + { + xTicksToWait = portMAX_DELAY; + } - /* If the task should block indefinitely then set the block time to a - * value that will be recognised as an indefinite delay inside the - * prvAddCurrentTaskToDelayedList() function. */ - if( xWaitIndefinitely != pdFALSE ) - { - xTicksToWait = portMAX_DELAY; + traceTASK_DELAY_UNTIL( ( xTickCount + xTicksToWait ) ); + prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely ); } - - traceTASK_DELAY_UNTIL( ( xTickCount + xTicksToWait ) ); - prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely ); + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL( &xKernelLock ); } #endif /* configUSE_TIMERS */ @@ -3565,76 +3727,102 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, TCB_t * pxUnblockedTCB; BaseType_t xReturn; - /* Before taking the kernel lock, another task/ISR could have already - * emptied the pxEventList. So we insert a check here to see if - * pxEventList is empty before attempting to remove an item from it. */ - if( listLIST_IS_EMPTY( pxEventList ) == pdFALSE ) - { - /* Get current core ID as we can no longer be preempted. */ - const BaseType_t xCurCoreID = portGET_CORE_ID(); - /* Remove the task from its current event list */ - pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); - configASSERT( pxUnblockedTCB ); - listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) ); + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures. + * This function can also be called from an ISR context, so we + * need to check whether we are in an ISR.*/ + if( portCHECK_IF_IN_ISR() == pdFALSE ) + { + taskENTER_CRITICAL( &xKernelLock ); + } + else + { + taskENTER_CRITICAL_ISR( &xKernelLock ); + } - /* Add the task to the ready list if a core with compatible affinity - * has NOT suspended its scheduler. This occurs when: - * - The task is pinned, and the pinned core's scheduler is running - * - The task is unpinned, and at least one of the core's scheduler is running */ - if( taskCAN_BE_SCHEDULED( pxUnblockedTCB ) == pdTRUE ) + { + /* Before taking the kernel lock, another task/ISR could have already + * emptied the pxEventList. So we insert a check here to see if + * pxEventList is empty before attempting to remove an item from it. */ + if( listLIST_IS_EMPTY( pxEventList ) == pdFALSE ) { - listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); - prvAddTaskToReadyList( pxUnblockedTCB ); + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); - #if ( configUSE_TICKLESS_IDLE != 0 ) + /* Remove the task from its current event list */ + pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + configASSERT( pxUnblockedTCB ); + listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) ); + + /* Add the task to the ready list if a core with compatible affinity + * has NOT suspended its scheduler. This occurs when: + * - The task is pinned, and the pinned core's scheduler is running + * - The task is unpinned, and at least one of the core's scheduler is running */ + if( taskCAN_BE_SCHEDULED( pxUnblockedTCB ) == pdTRUE ) { - /* If a task is blocked on a kernel object then xNextTaskUnblockTime - * might be set to the blocked task's time out time. If the task is - * unblocked for a reason other than a timeout xNextTaskUnblockTime is - * normally left unchanged, because it is automatically reset to a new - * value when the tick count equals xNextTaskUnblockTime. However if - * tickless idling is used it might be more important to enter sleep mode - * at the earliest possible time - so reset xNextTaskUnblockTime here to - * ensure it is updated at the earliest possible time. */ - prvResetNextTaskUnblockTime(); - } - #endif - } - else - { - /* We arrive here due to one of the following possibilities: - * - The task is pinned to core X and core X has suspended its scheduler - * - The task is unpinned and both cores have suspend their schedulers - * Therefore, we add the task to one of the pending lists: - * - If the task is pinned to core X, add it to core X's pending list - * - If the task is unpinned, add it to the current core's pending list */ - UBaseType_t uxPendCore = ( ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) ? xCurCoreID : pxUnblockedTCB->xCoreID ); - configASSERT( uxSchedulerSuspended[ uxPendCore ] != ( UBaseType_t ) 0U ); + listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); - /* Add the task to the current core's pending list */ - listINSERT_END( &( xPendingReadyList[ uxPendCore ] ), &( pxUnblockedTCB->xEventListItem ) ); - } + #if ( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + * might be set to the blocked task's time out time. If the task is + * unblocked for a reason other than a timeout xNextTaskUnblockTime is + * normally left unchanged, because it is automatically reset to a new + * value when the tick count equals xNextTaskUnblockTime. However if + * tickless idling is used it might be more important to enter sleep mode + * at the earliest possible time - so reset xNextTaskUnblockTime here to + * ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + } + else + { + /* We arrive here due to one of the following possibilities: + * - The task is pinned to core X and core X has suspended its scheduler + * - The task is unpinned and both cores have suspend their schedulers + * Therefore, we add the task to one of the pending lists: + * - If the task is pinned to core X, add it to core X's pending list + * - If the task is unpinned, add it to the current core's pending list */ + UBaseType_t uxPendCore = ( ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) ? xCurCoreID : pxUnblockedTCB->xCoreID ); + configASSERT( uxSchedulerSuspended[ uxPendCore ] != ( UBaseType_t ) 0U ); + + /* Add the task to the current core's pending list */ + listINSERT_END( &( xPendingReadyList[ uxPendCore ] ), &( pxUnblockedTCB->xEventListItem ) ); + } - if( taskIS_YIELD_REQUIRED( pxUnblockedTCB, xCurCoreID, pdFALSE ) == pdTRUE ) - { - /* The unblocked task requires a the current core to yield */ - xReturn = pdTRUE; + if( taskIS_YIELD_REQUIRED( pxUnblockedTCB, xCurCoreID, pdFALSE ) == pdTRUE ) + { + /* The unblocked task requires a the current core to yield */ + xReturn = pdTRUE; - /* Mark that a yield is pending in case the user is not using the - * "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ - xYieldPending[ xCurCoreID ] = pdTRUE; + /* Mark that a yield is pending in case the user is not using the + * "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + xYieldPending[ xCurCoreID ] = pdTRUE; + } + else + { + xReturn = pdFALSE; + } } else { + /* The pxEventList was emptied before we entered the critical + * section, Nothing to do except return pdFALSE. */ xReturn = pdFALSE; } } + + /* Release the previously taken kernel lock. */ + if( portCHECK_IF_IN_ISR() == pdFALSE ) + { + taskEXIT_CRITICAL( &xKernelLock ); + } else { - /* The pxEventList was emptied before we entered the critical - * section, Nothing to do except return pdFALSE. */ - xReturn = pdFALSE; + taskEXIT_CRITICAL_ISR( &xKernelLock ); } return xReturn; @@ -3805,12 +3993,12 @@ void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) { configASSERT( pxTimeOut ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { pxTimeOut->xOverflowCount = xNumOfOverflows; pxTimeOut->xTimeOnEntering = xTickCount; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); } /*-----------------------------------------------------------*/ @@ -3830,7 +4018,7 @@ BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, configASSERT( pxTimeOut ); configASSERT( pxTicksToWait ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Minor optimisation. The tick count cannot change in this block. */ const TickType_t xConstTickCount = xTickCount; @@ -3883,7 +4071,7 @@ BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, xReturn = pdTRUE; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return xReturn; } @@ -4026,7 +4214,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) { - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &xKernelLock ); { /* Now the scheduler is suspended, the expected idle * time can be sampled again, and this time its value can @@ -4050,7 +4238,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) mtCOVERAGE_TEST_MARKER(); } } - ( void ) xTaskResumeAll(); + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &xKernelLock ); } else { @@ -4232,7 +4420,7 @@ static void prvCheckTasksWaitingTermination( void ) #if ( configNUMBER_OF_CORES > 1 ) { pxTCB = NULL; - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* List may have already been cleared by the other core. Check again */ if( listLIST_IS_EMPTY( &xTasksWaitingTermination ) == pdFALSE ) @@ -4256,7 +4444,7 @@ static void prvCheckTasksWaitingTermination( void ) } } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); if( pxTCB != NULL ) { @@ -4270,14 +4458,14 @@ static void prvCheckTasksWaitingTermination( void ) } #else /* configNUMBER_OF_CORES > 1 */ { - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); --uxCurrentNumberOfTasks; --uxDeletedTasksWaitingCleanUp; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); prvDeleteTCB( pxTCB ); } #endif /* configNUMBER_OF_CORES > 1 */ @@ -4299,94 +4487,111 @@ static void prvCheckTasksWaitingTermination( void ) /* xTask is NULL then get the state of the calling task. */ pxTCB = prvGetTCBFromHandle( xTask ); - pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB; - pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName[ 0 ] ); - pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority; - pxTaskStatus->pxStackBase = pxTCB->pxStack; - #if ( ( portSTACK_GROWTH > 0 ) && ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) - pxTaskStatus->pxTopOfStack = pxTCB->pxTopOfStack; - pxTaskStatus->pxEndOfStack = pxTCB->pxEndOfStack; - #endif - pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; - /* Todo: Remove xCoreID for single core builds (IDF-7894) */ - pxTaskStatus->xCoreID = pxTCB->xCoreID; - - #if ( configUSE_MUTEXES == 1 ) - { - pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority; - } - #else - { - pxTaskStatus->uxBasePriority = 0; - } - #endif + /* A critical section is required for SMP in case another core modifies + * the task simultaneously. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); + { + pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB; + pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName[ 0 ] ); + pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority; + pxTaskStatus->pxStackBase = pxTCB->pxStack; + #if ( ( portSTACK_GROWTH > 0 ) && ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) + pxTaskStatus->pxTopOfStack = pxTCB->pxTopOfStack; + pxTaskStatus->pxEndOfStack = pxTCB->pxEndOfStack; + #endif + pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; + /* Todo: Remove xCoreID for single core builds (IDF-7894) */ + pxTaskStatus->xCoreID = pxTCB->xCoreID; - #if ( configGENERATE_RUN_TIME_STATS == 1 ) - { - pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter; - } - #else - { - pxTaskStatus->ulRunTimeCounter = ( configRUN_TIME_COUNTER_TYPE ) 0; - } - #endif + #if ( configUSE_MUTEXES == 1 ) + { + pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority; + } + #else + { + pxTaskStatus->uxBasePriority = 0; + } + #endif - /* Obtaining the task state is a little fiddly, so is only done if the - * value of eState passed into this function is eInvalid - otherwise the - * state is just set to whatever is passed in. */ - if( eState != eInvalid ) - { - if( pxTCB == pxCurrentTCBs[ portGET_CORE_ID() ] ) + #if ( configGENERATE_RUN_TIME_STATS == 1 ) { - pxTaskStatus->eCurrentState = eRunning; + pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter; } - else + #else { - pxTaskStatus->eCurrentState = eState; + pxTaskStatus->ulRunTimeCounter = ( configRUN_TIME_COUNTER_TYPE ) 0; + } + #endif - #if ( INCLUDE_vTaskSuspend == 1 ) + /* Obtaining the task state is a little fiddly, so is only done if the + * value of eState passed into this function is eInvalid - otherwise the + * state is just set to whatever is passed in. */ + if( eState != eInvalid ) + { + if( pxTCB == pxCurrentTCBs[ portGET_CORE_ID() ] ) + { + pxTaskStatus->eCurrentState = eRunning; + } + else { - /* If the task is in the suspended list then there is a - * chance it is actually just blocked indefinitely - so really - * it should be reported as being in the Blocked state. */ - if( eState == eSuspended ) + pxTaskStatus->eCurrentState = eState; + + #if ( INCLUDE_vTaskSuspend == 1 ) { - vTaskSuspendAll(); + /* If the task is in the suspended list then there is a + * chance it is actually just blocked indefinitely - so really + * it should be reported as being in the Blocked state. */ + if( eState == eSuspended ) { - if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + #if ( configNUMBER_OF_CORES == 1 ) { - pxTaskStatus->eCurrentState = eBlocked; + /* Single core uses a scheduler suspension to + * atomically check if the task task is blocked. */ + vTaskSuspendAll(); } + #endif /* configNUMBER_OF_CORES == 1 */ + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + pxTaskStatus->eCurrentState = eBlocked; + } + } + #if ( configNUMBER_OF_CORES == 1 ) + { + ( void ) xTaskResumeAll(); + } + #endif /* configNUMBER_OF_CORES == 1 */ } - ( void ) xTaskResumeAll(); } + #endif /* INCLUDE_vTaskSuspend */ } - #endif /* INCLUDE_vTaskSuspend */ } - } - else - { - pxTaskStatus->eCurrentState = eTaskGetState( pxTCB ); - } + else + { + pxTaskStatus->eCurrentState = eTaskGetState( pxTCB ); + } - /* Obtaining the stack space takes some time, so the xGetFreeStackSpace - * parameter is provided to allow it to be skipped. */ - if( xGetFreeStackSpace != pdFALSE ) - { - #if ( portSTACK_GROWTH > 0 ) + /* Obtaining the stack space takes some time, so the xGetFreeStackSpace + * parameter is provided to allow it to be skipped. */ + if( xGetFreeStackSpace != pdFALSE ) { - pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack ); + #if ( portSTACK_GROWTH > 0 ) + { + pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack ); + } + #else + { + pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack ); + } + #endif } - #else + else { - pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack ); + pxTaskStatus->usStackHighWaterMark = 0; } - #endif - } - else - { - pxTaskStatus->usStackHighWaterMark = 0; } + /* Exit the previously entered critical section. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } #endif /* configUSE_TRACE_FACILITY */ @@ -4609,21 +4814,28 @@ static void prvResetNextTaskUnblockTime( void ) { BaseType_t xReturn; - if( xSchedulerRunning == pdFALSE ) - { - xReturn = taskSCHEDULER_NOT_STARTED; - } - else + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { - if( uxSchedulerSuspended[ portGET_CORE_ID() ] == ( UBaseType_t ) pdFALSE ) + if( xSchedulerRunning == pdFALSE ) { - xReturn = taskSCHEDULER_RUNNING; + xReturn = taskSCHEDULER_NOT_STARTED; } else { - xReturn = taskSCHEDULER_SUSPENDED; + if( uxSchedulerSuspended[ portGET_CORE_ID() ] == ( UBaseType_t ) pdFALSE ) + { + xReturn = taskSCHEDULER_RUNNING; + } + else + { + xReturn = taskSCHEDULER_SUSPENDED; + } } } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); return xReturn; } @@ -4638,85 +4850,92 @@ static void prvResetNextTaskUnblockTime( void ) TCB_t * const pxMutexHolderTCB = pxMutexHolder; BaseType_t xReturn = pdFALSE; - /* Get current core ID as we can no longer be preempted. */ - const BaseType_t xCurCoreID = portGET_CORE_ID(); - - /* If the mutex was given back by an interrupt while the queue was - * locked then the mutex holder might now be NULL. _RB_ Is this still - * needed as interrupts can no longer use mutexes? */ - if( pxMutexHolder != NULL ) + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { - /* If the holder of the mutex has a priority below the priority of - * the task attempting to obtain the mutex then it will temporarily - * inherit the priority of the task attempting to obtain the mutex. */ - if( pxMutexHolderTCB->uxPriority < pxCurrentTCBs[ xCurCoreID ]->uxPriority ) - { - /* Adjust the mutex holder state to account for its new - * priority. Only reset the event list item value if the value is - * not being used for anything else. */ - if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) - { - listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCBs[ xCurCoreID ]->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); - /* If the task being modified is in the ready state it will need - * to be moved into a new list. */ - if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE ) + /* If the mutex was given back by an interrupt while the queue was + * locked then the mutex holder might now be NULL. _RB_ Is this still + * needed as interrupts can no longer use mutexes? */ + if( pxMutexHolder != NULL ) + { + /* If the holder of the mutex has a priority below the priority of + * the task attempting to obtain the mutex then it will temporarily + * inherit the priority of the task attempting to obtain the mutex. */ + if( pxMutexHolderTCB->uxPriority < pxCurrentTCBs[ xCurCoreID ]->uxPriority ) { - if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + /* Adjust the mutex holder state to account for its new + * priority. Only reset the event list item value if the value is + * not being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) { - /* It is known that the task is in its ready list so - * there is no need to check again and the port level - * reset macro can be called directly. */ - portRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority, uxTopReadyPriority ); + listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCBs[ xCurCoreID ]->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } else { mtCOVERAGE_TEST_MARKER(); } - /* Inherit the priority before being moved into the new list. */ - pxMutexHolderTCB->uxPriority = pxCurrentTCBs[ xCurCoreID ]->uxPriority; - prvAddTaskToReadyList( pxMutexHolderTCB ); - } - else - { - /* Just inherit the priority. */ - pxMutexHolderTCB->uxPriority = pxCurrentTCBs[ xCurCoreID ]->uxPriority; - } + /* If the task being modified is in the ready state it will need + * to be moved into a new list. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE ) + { + if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + * there is no need to check again and the port level + * reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Inherit the priority before being moved into the new list. */ + pxMutexHolderTCB->uxPriority = pxCurrentTCBs[ xCurCoreID ]->uxPriority; + prvAddTaskToReadyList( pxMutexHolderTCB ); + } + else + { + /* Just inherit the priority. */ + pxMutexHolderTCB->uxPriority = pxCurrentTCBs[ xCurCoreID ]->uxPriority; + } - traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCBs[ xCurCoreID ]->uxPriority ); + traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCBs[ xCurCoreID ]->uxPriority ); - /* Inheritance occurred. */ - xReturn = pdTRUE; - } - else - { - if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCBs[ xCurCoreID ]->uxPriority ) - { - /* The base priority of the mutex holder is lower than the - * priority of the task attempting to take the mutex, but the - * current priority of the mutex holder is not lower than the - * priority of the task attempting to take the mutex. - * Therefore the mutex holder must have already inherited a - * priority, but inheritance would have occurred if that had - * not been the case. */ + /* Inheritance occurred. */ xReturn = pdTRUE; } else { - mtCOVERAGE_TEST_MARKER(); + if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCBs[ xCurCoreID ]->uxPriority ) + { + /* The base priority of the mutex holder is lower than the + * priority of the task attempting to take the mutex, but the + * current priority of the mutex holder is not lower than the + * priority of the task attempting to take the mutex. + * Therefore the mutex holder must have already inherited a + * priority, but inheritance would have occurred if that had + * not been the case. */ + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } + else + { + mtCOVERAGE_TEST_MARKER(); + } } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); return xReturn; } @@ -4731,57 +4950,66 @@ static void prvResetNextTaskUnblockTime( void ) TCB_t * const pxTCB = pxMutexHolder; BaseType_t xReturn = pdFALSE; - if( pxMutexHolder != NULL ) + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { - /* A task can only have an inherited priority if it holds the mutex. - * If the mutex is held by a task then it cannot be given from an - * interrupt, and if a mutex is given by the holding task then it must - * be the running state task. */ - configASSERT( pxTCB == pxCurrentTCBs[ portGET_CORE_ID() ] ); - configASSERT( pxTCB->uxMutexesHeld ); - ( pxTCB->uxMutexesHeld )--; - - /* Has the holder of the mutex inherited the priority of another - * task? */ - if( pxTCB->uxPriority != pxTCB->uxBasePriority ) + if( pxMutexHolder != NULL ) { - /* Only disinherit if no other mutexes are held. */ - if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ) + /* A task can only have an inherited priority if it holds the mutex. + * If the mutex is held by a task then it cannot be given from an + * interrupt, and if a mutex is given by the holding task then it must + * be the running state task. */ + configASSERT( pxTCB == pxCurrentTCBs[ portGET_CORE_ID() ] ); + configASSERT( pxTCB->uxMutexesHeld ); + ( pxTCB->uxMutexesHeld )--; + + /* Has the holder of the mutex inherited the priority of another + * task? */ + if( pxTCB->uxPriority != pxTCB->uxBasePriority ) { - /* A task can only have an inherited priority if it holds - * the mutex. If the mutex is held by a task then it cannot be - * given from an interrupt, and if a mutex is given by the - * holding task then it must be the running state task. Remove - * the holding task from the ready list. */ - if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + /* Only disinherit if no other mutexes are held. */ + if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ) { - portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + /* A task can only have an inherited priority if it holds + * the mutex. If the mutex is held by a task then it cannot be + * given from an interrupt, and if a mutex is given by the + * holding task then it must be the running state task. Remove + * the holding task from the ready list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Disinherit the priority before adding the task into the + * new ready list. */ + traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); + pxTCB->uxPriority = pxTCB->uxBasePriority; + + /* Reset the event list item value. It cannot be in use for + * any other purpose if this task is running, and it must be + * running to give back the mutex. */ + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + prvAddTaskToReadyList( pxTCB ); + + /* Return true to indicate that a context switch is required. + * This is only actually required in the corner case whereby + * multiple mutexes were held and the mutexes were given back + * in an order different to that in which they were taken. + * If a context switch did not occur when the first mutex was + * returned, even if a task was waiting on it, then a context + * switch should occur when the last mutex is returned whether + * a task is waiting on it or not. */ + xReturn = pdTRUE; } else { mtCOVERAGE_TEST_MARKER(); } - - /* Disinherit the priority before adding the task into the - * new ready list. */ - traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); - pxTCB->uxPriority = pxTCB->uxBasePriority; - - /* Reset the event list item value. It cannot be in use for - * any other purpose if this task is running, and it must be - * running to give back the mutex. */ - listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - prvAddTaskToReadyList( pxTCB ); - - /* Return true to indicate that a context switch is required. - * This is only actually required in the corner case whereby - * multiple mutexes were held and the mutexes were given back - * in an order different to that in which they were taken. - * If a context switch did not occur when the first mutex was - * returned, even if a task was waiting on it, then a context - * switch should occur when the last mutex is returned whether - * a task is waiting on it or not. */ - xReturn = pdTRUE; } else { @@ -4793,10 +5021,8 @@ static void prvResetNextTaskUnblockTime( void ) mtCOVERAGE_TEST_MARKER(); } } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); return xReturn; } @@ -4813,78 +5039,87 @@ static void prvResetNextTaskUnblockTime( void ) UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse; const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1; - if( pxMutexHolder != NULL ) + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { - /* If pxMutexHolder is not NULL then the holder must hold at least - * one mutex. */ - configASSERT( pxTCB->uxMutexesHeld ); - - /* Determine the priority to which the priority of the task that - * holds the mutex should be set. This will be the greater of the - * holding task's base priority and the priority of the highest - * priority task that is waiting to obtain the mutex. */ - if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask ) - { - uxPriorityToUse = uxHighestPriorityWaitingTask; - } - else + if( pxMutexHolder != NULL ) { - uxPriorityToUse = pxTCB->uxBasePriority; - } + /* If pxMutexHolder is not NULL then the holder must hold at least + * one mutex. */ + configASSERT( pxTCB->uxMutexesHeld ); - /* Does the priority need to change? */ - if( pxTCB->uxPriority != uxPriorityToUse ) - { - /* Only disinherit if no other mutexes are held. This is a - * simplification in the priority inheritance implementation. If - * the task that holds the mutex is also holding other mutexes then - * the other mutexes may have caused the priority inheritance. */ - if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld ) + /* Determine the priority to which the priority of the task that + * holds the mutex should be set. This will be the greater of the + * holding task's base priority and the priority of the highest + * priority task that is waiting to obtain the mutex. */ + if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask ) { - /* If a task has timed out because it already holds the - * mutex it was trying to obtain then it cannot of inherited - * its own priority. */ - configASSERT( pxTCB != pxCurrentTCBs[ portGET_CORE_ID() ] ); - - /* Disinherit the priority, remembering the previous - * priority to facilitate determining the subject task's - * state. */ - traceTASK_PRIORITY_DISINHERIT( pxTCB, uxPriorityToUse ); - uxPriorityUsedOnEntry = pxTCB->uxPriority; - pxTCB->uxPriority = uxPriorityToUse; - - /* Only reset the event list item value if the value is not - * being used for anything else. */ - if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) - { - listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + uxPriorityToUse = uxHighestPriorityWaitingTask; + } + else + { + uxPriorityToUse = pxTCB->uxBasePriority; + } - /* If the running task is not the task that holds the mutex - * then the task that holds the mutex could be in either the - * Ready, Blocked or Suspended states. Only remove the task - * from its current state list if it is in the Ready state as - * the task's priority is going to change and there is one - * Ready list per priority. */ - if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + /* Does the priority need to change? */ + if( pxTCB->uxPriority != uxPriorityToUse ) + { + /* Only disinherit if no other mutexes are held. This is a + * simplification in the priority inheritance implementation. If + * the task that holds the mutex is also holding other mutexes then + * the other mutexes may have caused the priority inheritance. */ + if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld ) { - if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + /* If a task has timed out because it already holds the + * mutex it was trying to obtain then it cannot of inherited + * its own priority. */ + configASSERT( pxTCB != pxCurrentTCBs[ portGET_CORE_ID() ] ); + + /* Disinherit the priority, remembering the previous + * priority to facilitate determining the subject task's + * state. */ + traceTASK_PRIORITY_DISINHERIT( pxTCB, uxPriorityToUse ); + uxPriorityUsedOnEntry = pxTCB->uxPriority; + pxTCB->uxPriority = uxPriorityToUse; + + /* Only reset the event list item value if the value is not + * being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) { - /* It is known that the task is in its ready list so - * there is no need to check again and the port level - * reset macro can be called directly. */ - portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } else { mtCOVERAGE_TEST_MARKER(); } - prvAddTaskToReadyList( pxTCB ); + /* If the running task is not the task that holds the mutex + * then the task that holds the mutex could be in either the + * Ready, Blocked or Suspended states. Only remove the task + * from its current state list if it is in the Ready state as + * the task's priority is going to change and there is one + * Ready list per priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + * there is no need to check again and the port level + * reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + prvAddTaskToReadyList( pxTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } else { @@ -4901,10 +5136,8 @@ static void prvResetNextTaskUnblockTime( void ) mtCOVERAGE_TEST_MARKER(); } } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } #endif /* configUSE_MUTEXES */ @@ -5237,14 +5470,21 @@ TickType_t uxTaskResetEventItemValue( void ) { TickType_t uxReturn; - /* Get current core ID as we can no longer be preempted. */ - const BaseType_t xCurCoreID = portGET_CORE_ID(); + /* For SMP, we need to take the kernel lock here to ensure nothing else + * modifies the task's event item value simultaneously. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); + { + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); - uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ) ); + uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ) ); - /* Reset the event list item to its normal value - so it can be used with - * queues and semaphores. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCBs[ xCurCoreID ]->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + /* Reset the event list item to its normal value - so it can be used with + * queues and semaphores. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCBs[ xCurCoreID ]->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCBs[ xCurCoreID ]->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); + /* Release the previously taken kernel lock. */ return uxReturn; } @@ -5256,17 +5496,24 @@ TickType_t uxTaskResetEventItemValue( void ) { TaskHandle_t xReturn; - /* Get current core ID as we can no longer be preempted. */ - const BaseType_t xCurCoreID = portGET_CORE_ID(); - - /* If xSemaphoreCreateMutex() is called before any tasks have been created - * then pxCurrentTCBs will be NULL. */ - if( pxCurrentTCBs[ xCurCoreID ] != NULL ) + /* For SMP, we need to take the kernel lock here as we are about to + * access kernel data structures. */ + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { - ( pxCurrentTCBs[ xCurCoreID ]->uxMutexesHeld )++; - } + /* Get current core ID as we can no longer be preempted. */ + const BaseType_t xCurCoreID = portGET_CORE_ID(); - xReturn = pxCurrentTCBs[ xCurCoreID ]; + /* If xSemaphoreCreateMutex() is called before any tasks have been created + * then pxCurrentTCBs will be NULL. */ + if( pxCurrentTCBs[ xCurCoreID ] != NULL ) + { + ( pxCurrentTCBs[ xCurCoreID ]->uxMutexesHeld )++; + } + + xReturn = pxCurrentTCBs[ xCurCoreID ]; + } + /* Release the previously taken kernel lock. */ + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); return xReturn; } @@ -5284,7 +5531,7 @@ TickType_t uxTaskResetEventItemValue( void ) configASSERT( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -5316,9 +5563,9 @@ TickType_t uxTaskResetEventItemValue( void ) mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -5344,7 +5591,7 @@ TickType_t uxTaskResetEventItemValue( void ) pxCurrentTCBs[ xCurCoreID ]->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return ulReturn; } @@ -5364,7 +5611,7 @@ TickType_t uxTaskResetEventItemValue( void ) configASSERT( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -5401,9 +5648,9 @@ TickType_t uxTaskResetEventItemValue( void ) mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -5436,7 +5683,7 @@ TickType_t uxTaskResetEventItemValue( void ) pxCurrentTCBs[ xCurCoreID ]->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return xReturn; } @@ -5460,7 +5707,7 @@ TickType_t uxTaskResetEventItemValue( void ) configASSERT( xTaskToNotify ); pxTCB = xTaskToNotify; - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { if( pulPreviousNotificationValue != NULL ) { @@ -5559,7 +5806,7 @@ TickType_t uxTaskResetEventItemValue( void ) mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return xReturn; } @@ -5604,7 +5851,7 @@ TickType_t uxTaskResetEventItemValue( void ) pxTCB = xTaskToNotify; - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &xKernelLock, uxSavedInterruptStatus ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -5701,7 +5948,7 @@ TickType_t uxTaskResetEventItemValue( void ) } } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &xKernelLock, uxSavedInterruptStatus ); return xReturn; } @@ -5742,7 +5989,7 @@ TickType_t uxTaskResetEventItemValue( void ) pxTCB = xTaskToNotify; - uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + prvENTER_CRITICAL_OR_MASK_ISR( &xKernelLock, uxSavedInterruptStatus ); { /* Get current core ID as we can no longer be preempted. */ const BaseType_t xCurCoreID = portGET_CORE_ID(); @@ -5795,7 +6042,7 @@ TickType_t uxTaskResetEventItemValue( void ) } } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + prvEXIT_CRITICAL_OR_UNMASK_ISR( &xKernelLock, uxSavedInterruptStatus ); } #endif /* configUSE_TASK_NOTIFICATIONS */ @@ -5815,7 +6062,7 @@ TickType_t uxTaskResetEventItemValue( void ) * its notification state cleared. */ pxTCB = prvGetTCBFromHandle( xTask ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { if( pxTCB->ucNotifyState[ uxIndexToClear ] == taskNOTIFICATION_RECEIVED ) { @@ -5827,7 +6074,7 @@ TickType_t uxTaskResetEventItemValue( void ) xReturn = pdFAIL; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return xReturn; } @@ -5848,14 +6095,14 @@ TickType_t uxTaskResetEventItemValue( void ) * its notification state cleared. */ pxTCB = prvGetTCBFromHandle( xTask ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xKernelLock ); { /* Return the notification as it was before the bits were cleared, * then clear the bit mask. */ ulReturn = pxTCB->ulNotifiedValue[ uxIndexToClear ]; pxTCB->ulNotifiedValue[ uxIndexToClear ] &= ~ulBitsToClear; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xKernelLock ); return ulReturn; } diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/timers.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/timers.c index ba3a2841f2d..084c7d9b48b 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/timers.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/timers.c @@ -42,6 +42,8 @@ #include "task.h" #include "queue.h" #include "timers.h" +/* Include private IDF API additions for critical thread safety macros */ +#include "esp_private/freertos_idf_additions_priv.h" #if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 ) #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available. @@ -147,6 +149,10 @@ PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; +/* Spinlock required in SMP when accessing the timers. For now we use a single lock + * Todo: Each timer could possible have its own lock for increased granularity. */ + PRIVILEGED_DATA static portMUX_TYPE xTimerLock = portMUX_INITIALIZER_UNLOCKED; + /*lint -restore */ /*-----------------------------------------------------------*/ @@ -462,7 +468,7 @@ Timer_t * pxTimer = xTimer; configASSERT( xTimer ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xTimerLock ); { if( xAutoReload != pdFALSE ) { @@ -473,7 +479,7 @@ pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_AUTORELOAD ); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xTimerLock ); } /*-----------------------------------------------------------*/ @@ -483,7 +489,7 @@ BaseType_t xReturn; configASSERT( xTimer ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xTimerLock ); { if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) == 0 ) { @@ -496,7 +502,7 @@ xReturn = pdTRUE; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xTimerLock ); return xReturn; } @@ -639,7 +645,7 @@ TickType_t xTimeNow; BaseType_t xTimerListsWereSwitched; - vTaskSuspendAll(); + prvENTER_CRITICAL_OR_SUSPEND_ALL( &xTimerLock ); { /* Obtain the time now to make an assessment as to whether the timer * has expired or not. If obtaining the time causes the lists to switch @@ -653,7 +659,7 @@ /* The tick count has not overflowed, has the timer expired? */ if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) ) { - ( void ) xTaskResumeAll(); + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &xTimerLock ); prvProcessExpiredTimer( xNextExpireTime, xTimeNow ); } else @@ -673,7 +679,7 @@ vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty ); - if( xTaskResumeAll() == pdFALSE ) + if( prvEXIT_CRITICAL_OR_RESUME_ALL( &xTimerLock ) == pdFALSE ) { /* Yield to wait for either a command to arrive, or the * block time to expire. If a command arrived between the @@ -689,7 +695,7 @@ } else { - ( void ) xTaskResumeAll(); + ( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &xTimerLock ); } } } @@ -967,7 +973,7 @@ /* Check that the list from which active timers are referenced, and the * queue used to communicate with the timer service, have been * initialised. */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xTimerLock ); { if( xTimerQueue == NULL ) { @@ -1009,7 +1015,7 @@ mtCOVERAGE_TEST_MARKER(); } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xTimerLock ); } /*-----------------------------------------------------------*/ @@ -1021,7 +1027,7 @@ configASSERT( xTimer ); /* Is the timer in the list of active timers? */ - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xTimerLock ); { if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0 ) { @@ -1032,7 +1038,7 @@ xReturn = pdTRUE; } } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xTimerLock ); return xReturn; } /*lint !e818 Can't be pointer to const due to the typedef. */ @@ -1045,11 +1051,11 @@ configASSERT( xTimer ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xTimerLock ); { pvReturn = pxTimer->pvTimerID; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xTimerLock ); return pvReturn; } @@ -1062,11 +1068,11 @@ configASSERT( xTimer ); - taskENTER_CRITICAL(); + taskENTER_CRITICAL( &xTimerLock ); { pxTimer->pvTimerID = pvNewID; } - taskEXIT_CRITICAL(); + taskEXIT_CRITICAL( &xTimerLock ); } /*-----------------------------------------------------------*/ diff --git a/components/freertos/esp_additions/freertos_tasks_c_additions.h b/components/freertos/esp_additions/freertos_tasks_c_additions.h index e43dfbe071a..c7e08d0af1d 100644 --- a/components/freertos/esp_additions/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/freertos_tasks_c_additions.h @@ -487,12 +487,12 @@ BaseType_t xTaskGetCoreID( TaskHandle_t xTask ) * access kernel data structures. For single core, a critical section is * not required as this is not called from an interrupt and the current * TCB will always be the same for any individual execution thread. */ - taskENTER_CRITICAL_SMP_ONLY(); + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { xReturn = pxCurrentTCBs[ xCoreID ]; } /* Release the previously taken kernel lock. */ - taskEXIT_CRITICAL_SMP_ONLY(); + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } #else /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ { @@ -532,12 +532,12 @@ BaseType_t xTaskGetCoreID( TaskHandle_t xTask ) /* For SMP, we need to take the kernel lock here as we are about to * access kernel data structures. */ - taskENTER_CRITICAL_SMP_ONLY(); + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { ulRunTimeCounter = xIdleTaskHandle[ xCoreID ]->ulRunTimeCounter; } /* Release the previously taken kernel lock. */ - taskEXIT_CRITICAL_SMP_ONLY(); + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); return ulRunTimeCounter; } @@ -564,12 +564,12 @@ BaseType_t xTaskGetCoreID( TaskHandle_t xTask ) { /* For SMP, we need to take the kernel lock here as we are about * to access kernel data structures. */ - taskENTER_CRITICAL_SMP_ONLY(); + taskENTER_CRITICAL_SMP_ONLY( &xKernelLock ); { ulReturn = xIdleTaskHandle[ xCoreID ]->ulRunTimeCounter / ulTotalTime; } /* Release the previously taken kernel lock. */ - taskEXIT_CRITICAL_SMP_ONLY(); + taskEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } else { From a7436ac82c7ba0395477ba0de9ff3117d4e67421 Mon Sep 17 00:00:00 2001 From: Chip Weinberger Date: Mon, 8 May 2023 20:37:06 -0700 Subject: [PATCH 26/71] [Usb Serial JTAG] printing to console could sometimes skip bytes --- .../driver/usb_serial_jtag/usb_serial_jtag.c | 61 ++++++++++++++++--- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/components/driver/usb_serial_jtag/usb_serial_jtag.c b/components/driver/usb_serial_jtag/usb_serial_jtag.c index 4de3e7261f8..19268338cb2 100644 --- a/components/driver/usb_serial_jtag/usb_serial_jtag.c +++ b/components/driver/usb_serial_jtag/usb_serial_jtag.c @@ -32,16 +32,19 @@ typedef struct{ // TX parameters uint32_t tx_buf_size; /*!< TX buffer size */ RingbufHandle_t tx_ring_buf; /*!< TX ring buffer handler */ + uint8_t tx_data_buf[USB_SER_JTAG_ENDP_SIZE]; /*!< Data buffer to stash TX FIFO data */ + size_t tx_stash_cnt; /*!< Number of stashed TX FIFO bytes */ } usb_serial_jtag_obj_t; static usb_serial_jtag_obj_t *p_usb_serial_jtag_obj = NULL; static const char* USB_SERIAL_JTAG_TAG = "usb_serial_jtag"; -static void usb_serial_jtag_write_and_flush(const uint8_t *buf, uint32_t wr_len) +static int usb_serial_jtag_write_and_flush(const uint8_t *buf, uint32_t wr_len) { - usb_serial_jtag_ll_write_txfifo(buf, wr_len); + int size = usb_serial_jtag_ll_write_txfifo(buf, wr_len); usb_serial_jtag_ll_txfifo_flush(); + return size; } static void usb_serial_jtag_isr_handler_default(void *arg) { @@ -50,19 +53,54 @@ static void usb_serial_jtag_isr_handler_default(void *arg) { usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask(); if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) { - // Interrupt tells us the host picked up the data we sent. If we have more data, we can put it in the buffer and the host will pick that up next. + // Interrupt tells us the host picked up the data we sent. + // If we have more data, we can put it in the buffer and the host will pick that up next. // Send data in isr. + // If the hardware fifo is avaliable, write in it. Otherwise, do nothing. if (usb_serial_jtag_ll_txfifo_writable() == 1) { // We disable the interrupt here so that the interrupt won't be triggered if there is no data to send. usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); size_t queued_size; - uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(p_usb_serial_jtag_obj->tx_ring_buf, &queued_size, 64); - // If the hardware fifo is avaliable, write in it. Otherwise, do nothing. - if (queued_buff != NULL) { //Although tx_queued_bytes may be larger than 0. We may have interrupt before xRingbufferSend() was called. - //Copy the queued buffer into the TX FIFO - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); - usb_serial_jtag_write_and_flush(queued_buff, queued_size); - vRingbufferReturnItemFromISR(p_usb_serial_jtag_obj->tx_ring_buf, queued_buff, &xTaskWoken); + uint8_t *queued_buff = NULL; + bool is_stashed_data = false; + if (p_usb_serial_jtag_obj->tx_stash_cnt != 0) { + // Send stashed tx bytes before reading bytes from ring buffer + queued_buff = p_usb_serial_jtag_obj->tx_data_buf; + queued_size = p_usb_serial_jtag_obj->tx_stash_cnt; + is_stashed_data = true; + } + else { + // Max 64 data payload size in a single EndPoint + queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(p_usb_serial_jtag_obj->tx_ring_buf, &queued_size, USB_SER_JTAG_ENDP_SIZE); + } + + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + + if (queued_buff != NULL) { + + // Although tx_queued_bytes may be larger than 0, we may have + // interrupted before xRingbufferSend() was called. + // Copy the queued buffer into the TX FIFO + + // On ringbuffer wrap-around the size can be 0 even though the buffer returned is not NULL + if (queued_size > 0) { + uint32_t sent_size = usb_serial_jtag_write_and_flush(queued_buff, queued_size); + + if (sent_size < queued_size) { + // Not all bytes could be sent at once, stash the unwritten bytes in a tx buffer + size_t stash_size = MIN(USB_SER_JTAG_ENDP_SIZE, queued_size - sent_size); + + // Copy the missed bytes to tx stash buffer. May copy from stash buffer to itself + memcpy(p_usb_serial_jtag_obj->tx_data_buf, &queued_buff[sent_size], stash_size); + p_usb_serial_jtag_obj->tx_stash_cnt = stash_size; + } + else { + p_usb_serial_jtag_obj->tx_stash_cnt = 0; + } + } + if (is_stashed_data == false) { + vRingbufferReturnItemFromISR(p_usb_serial_jtag_obj->tx_ring_buf, queued_buff, &xTaskWoken); + } usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); } } else { @@ -93,6 +131,7 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se p_usb_serial_jtag_obj = (usb_serial_jtag_obj_t*) heap_caps_calloc(1, sizeof(usb_serial_jtag_obj_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); p_usb_serial_jtag_obj->rx_buf_size = usb_serial_jtag_config->rx_buffer_size; p_usb_serial_jtag_obj->tx_buf_size = usb_serial_jtag_config->tx_buffer_size; + p_usb_serial_jtag_obj->tx_stash_cnt = 0; if (p_usb_serial_jtag_obj == NULL) { ESP_LOGE(USB_SERIAL_JTAG_TAG, "memory allocate error"); err = ESP_ERR_NO_MEM; @@ -161,6 +200,8 @@ int usb_serial_jtag_write_bytes(const void* src, size_t size, TickType_t ticks_t ESP_RETURN_ON_FALSE(src != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "Invalid buffer pointer."); ESP_RETURN_ON_FALSE(p_usb_serial_jtag_obj != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "The driver hasn't been initialized"); + int ret_size = 0; + const uint8_t *buff = (const uint8_t *)src; // Blocking method, Sending data to ringbuffer, and handle the data in ISR. BaseType_t result = xRingbufferSend(p_usb_serial_jtag_obj->tx_ring_buf, (void*) (buff), size, ticks_to_wait); From b09462eae87e95167e604062c184dc7f283c4b05 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 5 Sep 2023 01:07:23 +0800 Subject: [PATCH 27/71] feat(freertos): Add beta support for FreeRTOS v10.5.1 kernel This commit adds beta support for the FreeRTOS v10.5.1 kernel which can be enabled by enabling the CONFIG_FREERTOS_USE_KERNEL_10_5_1 option. The following changes have been made: - Updated freertos/CMakeLists.txt to build v10.5.1 kernel with v10.4.3. ports - Updated existing Xtensa and RISC-V ports to work with V10.5.1 - Modifications to other ESP-IDF components to work with v10.5.1 - Added some ESP-IDF specific tracing changes to v10.5.1 kernel - Make CONFIG_FREERTOS_USE_KERNEL_10_5_1 a public option Note: The beta release is missing some minor fixes, performance improvements, and features. Using this beta release for production is not recommended. Closes https://github.com/espressif/esp-idf/issues/7137 --- .../src/port/riscv/gdbstub_riscv.c | 13 +++- components/freertos/CMakeLists.txt | 71 +++++++++++++----- .../include/freertos/FreeRTOS.h | 40 +++++++++++ .../include/freertos/projdefs.h | 9 +++ .../freertos/FreeRTOS-Kernel-V10.5.1/queue.c | 9 ++- .../freertos/FreeRTOS-Kernel-V10.5.1/tasks.c | 4 ++ .../riscv/include/freertos/portmacro.h | 5 ++ .../FreeRTOS-Kernel/portable/riscv/portasm.S | 7 ++ .../xtensa/include/freertos/portmacro.h | 5 ++ .../FreeRTOS-Kernel/portable/xtensa/portasm.S | 8 ++- components/freertos/Kconfig | 7 +- .../config/include/freertos/FreeRTOSConfig.h | 1 + .../include/freertos/FreeRTOSConfig_arch.h | 2 +- .../include/freertos/FreeRTOSConfig_arch.h | 29 +++++--- .../include/freertos/FreeRTOSConfig_arch.h | 29 +++++--- .../freertos_tasks_c_additions.h | 72 ++++++++++++++++--- .../include/freertos/idf_additions.h | 11 +++ tools/ci/check_public_headers_exceptions.txt | 1 + 18 files changed, 268 insertions(+), 55 deletions(-) diff --git a/components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c b/components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c index 7a405d6edb1..9e2d1b7846a 100644 --- a/components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c +++ b/components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -85,8 +85,15 @@ void esp_gdbstub_int(__attribute__((unused)) void *frame) /* Pointer to saved frame is in pxCurrentTCB * See rtos_int_enter function */ - extern void *pxCurrentTCB; - dummy_tcb_t *tcb = pxCurrentTCB; + /* Todo: Provide IDF interface for getting pxCurrentTCB (IDF-8182) */ + int core_id = esp_cpu_get_core_id(); +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + extern void **pxCurrentTCBs; + dummy_tcb_t *tcb = pxCurrentTCBs[core_id]; +#else + extern void **pxCurrentTCB; + dummy_tcb_t *tcb = pxCurrentTCB[core_id]; +#endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ gdbstub_handle_uart_int((esp_gdbstub_frame_t *)tcb->top_of_stack); } diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 9ac34ce96a3..39a96344323 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -32,7 +32,7 @@ if(CONFIG_FREERTOS_SMP) set(kernel_impl "FreeRTOS-Kernel-SMP") else() if(CONFIG_FREERTOS_USE_KERNEL_10_5_1) - message(FATAL_ERROR "FreeRTOS v10.5.1 is not buildable yet. Still under development") + set(kernel_impl "FreeRTOS-Kernel-V10.5.1") else() set(kernel_impl "FreeRTOS-Kernel") endif() @@ -71,30 +71,54 @@ list(APPEND srcs "${kernel_impl}/queue.c" "${kernel_impl}/tasks.c" "${kernel_impl}/timers.c" - "${kernel_impl}/croutine.c" "${kernel_impl}/event_groups.c" "${kernel_impl}/stream_buffer.c") +if(NOT CONFIG_FREERTOS_USE_KERNEL_10_5_1) + list(APPEND srcs "${kernel_impl}/croutine.c") +endif() # Add port source files -list(APPEND srcs - "${kernel_impl}/portable/${arch}/port.c") +if(CONFIG_FREERTOS_USE_KERNEL_10_5_1) + list(APPEND srcs + "FreeRTOS-Kernel/portable/${arch}/port.c") +else() + list(APPEND srcs + "${kernel_impl}/portable/${arch}/port.c") +endif() if(arch STREQUAL "linux") - list(APPEND srcs - "${kernel_impl}/portable/${arch}/utils/wait_for_event.c") - if(kernel_impl STREQUAL "FreeRTOS-Kernel") + if(CONFIG_FREERTOS_USE_KERNEL_10_5_1) list(APPEND srcs - "${kernel_impl}/portable/${arch}/port_idf.c") + "FreeRTOS-Kernel/portable/${arch}/utils/wait_for_event.c" + "FreeRTOS-Kernel/portable/${arch}/port_idf.c") + else() + list(APPEND srcs + "${kernel_impl}/portable/${arch}/utils/wait_for_event.c") + if(kernel_impl STREQUAL "FreeRTOS-Kernel") + list(APPEND srcs + "${kernel_impl}/portable/${arch}/port_idf.c") + endif() endif() else() - list(APPEND srcs - "${kernel_impl}/portable/${arch}/portasm.S") + if(CONFIG_FREERTOS_USE_KERNEL_10_5_1) + list(APPEND srcs + "FreeRTOS-Kernel/portable/${arch}/portasm.S") + else() + list(APPEND srcs + "${kernel_impl}/portable/${arch}/portasm.S") + endif() endif() if(arch STREQUAL "xtensa") - list(APPEND srcs - "${kernel_impl}/portable/${arch}/xtensa_init.c" - "${kernel_impl}/portable/${arch}/xtensa_overlay_os_hook.c") + if(CONFIG_FREERTOS_USE_KERNEL_10_5_1) + list(APPEND srcs + "FreeRTOS-Kernel/portable/${arch}/xtensa_init.c" + "FreeRTOS-Kernel/portable/${arch}/xtensa_overlay_os_hook.c") + else() + list(APPEND srcs + "${kernel_impl}/portable/${arch}/xtensa_init.c" + "${kernel_impl}/portable/${arch}/xtensa_overlay_os_hook.c") + endif() endif() # Add ESP-additions source files @@ -127,9 +151,15 @@ list(APPEND include_dirs "${kernel_impl}/include") # FreeRTOS headers via `#include "freertos/xxx.h"` # Add port public include directories -list(APPEND include_dirs - "${kernel_impl}/portable/${arch}/include" # For port headers via `#include "freertos/...h"` - "${kernel_impl}/portable/${arch}/include/freertos") # For port headers via `#include "...h"` +if(CONFIG_FREERTOS_USE_KERNEL_10_5_1) + list(APPEND include_dirs + "FreeRTOS-Kernel/portable/${arch}/include" # For port headers via `#include "freertos/...h"` + "FreeRTOS-Kernel/portable/${arch}/include/freertos") # For port headers via `#include "...h"` +else() + list(APPEND include_dirs + "${kernel_impl}/portable/${arch}/include" # For port headers via `#include "freertos/...h"` + "${kernel_impl}/portable/${arch}/include/freertos") # For port headers via `#include "...h"` +endif() # Add ESP-additions public include directories list(APPEND include_dirs @@ -151,8 +181,13 @@ list(APPEND private_include_dirs # Add port private include directories if(arch STREQUAL "linux") - list(APPEND private_include_dirs - "${kernel_impl}/portable/${arch}/") # Linux port `#include "utils/wait_for_event.h"` + if(CONFIG_FREERTOS_USE_KERNEL_10_5_1) + list(APPEND private_include_dirs + "FreeRTOS-Kernel/portable/${arch}/") # Linux port `#include "utils/wait_for_event.h"` + else() + list(APPEND private_include_dirs + "${kernel_impl}/portable/${arch}/") # Linux port `#include "utils/wait_for_event.h"` + endif() endif() # Add ESP-additions private include directories diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h index ea168b1e9f7..dd8a67905af 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/FreeRTOS.h @@ -1474,6 +1474,46 @@ typedef StaticStreamBuffer_t StaticMessageBuffer_t; #ifdef ESP_PLATFORM +/* *INDENT-OFF* */ +#ifdef __cplusplus + extern "C" { +#endif +/* *INDENT-ON* */ + +/* + * Default values for trace macros added by ESP-IDF and are not part of Vanilla FreeRTOS + */ + + #ifndef traceISR_EXIT_TO_SCHEDULER + #define traceISR_EXIT_TO_SCHEDULER() + #endif + + #ifndef traceISR_EXIT + #define traceISR_EXIT() + #endif + + #ifndef traceISR_ENTER + #define traceISR_ENTER( _n_ ) + #endif + + #ifndef traceQUEUE_SEMAPHORE_RECEIVE + #define traceQUEUE_SEMAPHORE_RECEIVE( pxQueue ) + #endif + + #ifndef traceQUEUE_GIVE_FROM_ISR + #define traceQUEUE_GIVE_FROM_ISR( pxQueue ) + #endif + + #ifndef traceQUEUE_GIVE_FROM_ISR_FAILED + #define traceQUEUE_GIVE_FROM_ISR_FAILED( pxQueue ) + #endif + +/* *INDENT-OFF* */ +#ifdef __cplusplus + } +#endif +/* *INDENT-ON* */ + /* * Include ESP-IDF API additions implicitly for compatibility reasons. * diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/projdefs.h b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/projdefs.h index c234d4f2a40..eac820910b8 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/projdefs.h +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/projdefs.h @@ -46,6 +46,15 @@ typedef void (* TaskFunction_t)( void * ); #define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000U ) ) #endif +/* Converts a time in ticks to milliseconds. This macro can be + * overridden by a macro of the same name defined in FreeRTOSConfig.h in case the + * definition here is not suitable for your application. + * + * Todo: Upstream this macro (IDF-8181) */ +#ifndef pdTICKS_TO_MS + #define pdTICKS_TO_MS( xTicks ) ( ( TickType_t ) ( ( uint64_t ) ( xTicks ) * 1000 / configTICK_RATE_HZ ) ) +#endif + #define pdFALSE ( ( BaseType_t ) 0 ) #define pdTRUE ( ( BaseType_t ) 1 ) diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/queue.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/queue.c index faa22ca5a5b..32e787a26d7 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/queue.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/queue.c @@ -1448,7 +1448,8 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, const int8_t cTxLock = queueUNLOCKED; #endif /* queueUSE_LOCKS == 1 */ - traceQUEUE_SEND_FROM_ISR( pxQueue ); + /* Todo: Reconcile tracing differences (IDF-8183) */ + traceQUEUE_GIVE_FROM_ISR( pxQueue ); /* A task can only have an inherited priority if it is a mutex * holder - and if there is a mutex holder then the mutex cannot be @@ -1557,7 +1558,8 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, } else { - traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); + /* Todo: Reconcile tracing differences (IDF-8183) */ + traceQUEUE_GIVE_FROM_ISR_FAILED( pxQueue ); xReturn = errQUEUE_FULL; } } @@ -1782,7 +1784,8 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, * must be the highest priority task wanting to access the queue. */ if( uxSemaphoreCount > ( UBaseType_t ) 0 ) { - traceQUEUE_RECEIVE( pxQueue ); + /* Todo: Reconcile tracing differences (IDF-8183) */ + traceQUEUE_SEMAPHORE_RECEIVE( pxQueue ); /* Semaphores are queues with a data size of zero and where the * messages waiting is the semaphore's count. Reduce the count. */ diff --git a/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c b/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c index 5c25e0c129d..2644f5c1e4c 100644 --- a/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c +++ b/components/freertos/FreeRTOS-Kernel-V10.5.1/tasks.c @@ -4197,6 +4197,10 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) } #endif /* configUSE_IDLE_HOOK */ + /* Call the esp-idf idle hook system. Todo IDF-8180 */ + extern void esp_vApplicationIdleHook( void ); + esp_vApplicationIdleHook(); + /* This conditional compilation should use inequality to 0, not equality * to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when * user defined low power mode implementations require diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h index 08e489d3c0e..b026bf49b90 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h @@ -444,6 +444,11 @@ void vPortTCBPreDeleteHook( void *pxTCB ); * - Maps to forward declared functions * ------------------------------------------------------------------------------------------------------------------ */ +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 +#define portGET_CORE_ID() xPortGetCoreID() +#define portYIELD_CORE( x ) vPortYieldOtherCore( x ) +#endif + // --------------------- Interrupts ------------------------ #define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK_FROM_ISR() diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S index 214303e4f82..2b215156c72 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S @@ -8,6 +8,13 @@ #include "freertos/FreeRTOSConfig.h" #include "soc/soc_caps.h" +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 +#define pxCurrentTCB pxCurrentTCBs +.extern pxCurrentTCBs +#else +.extern pxCurrentTCB +#endif + #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD #include "esp_private/hw_stack_guard.h" #endif diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h index 6a44c2817a6..2c107da0273 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h @@ -427,6 +427,11 @@ void vPortTCBPreDeleteHook( void *pxTCB ); * - Maps to forward declared functions * ------------------------------------------------------------------------------------------------------------------ */ +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 +#define portGET_CORE_ID() xPortGetCoreID() +#define portYIELD_CORE( x ) vPortYieldOtherCore( x ) +#endif + // --------------------- Interrupts ------------------------ /** diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S b/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S index b7fe0f36a7c..931aa3dc311 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD */ /* * Copyright (c) 2015-2019 Cadence Design Systems, Inc. @@ -33,7 +33,13 @@ #define TOPOFSTACK_OFFS 0x00 /* StackType_t *pxTopOfStack */ +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 +#define pxCurrentTCB pxCurrentTCBs +.extern pxCurrentTCBs +#else .extern pxCurrentTCB +#endif + #if XCHAL_CP_NUM > 0 /* Offsets used to get a task's coprocessor save area (CPSA) from its TCB */ .extern offset_pxEndOfStack diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 678ba052fc2..ebe716b4831 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -4,11 +4,12 @@ menu "FreeRTOS" # Upstream FreeRTOS configurations go here config FREERTOS_USE_KERNEL_10_5_1 - bool "Use v10.5.1 Kernel (EXPERIMENTAL)" - depends on IDF_EXPERIMENTAL_FEATURES + bool "Use v10.5.1 Kernel (BETA)" default n help - Hidden option for development/testing purposes to enable building with the v10.5.1 kernel + This option enables building for FreeRTOS v10.5.1 kernel. + + Note: The v10.5.1 kernel is still in BETA, thus is not production ready. config FREERTOS_SMP bool "Run the Amazon SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)" diff --git a/components/freertos/config/include/freertos/FreeRTOSConfig.h b/components/freertos/config/include/freertos/FreeRTOSConfig.h index bc92aad523c..83f337af7d6 100644 --- a/components/freertos/config/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/config/include/freertos/FreeRTOSConfig.h @@ -199,6 +199,7 @@ #define INCLUDE_xTaskResumeFromISR 1 #define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 /* -------------------- Trace Macros ----------------------- */ diff --git a/components/freertos/config/linux/include/freertos/FreeRTOSConfig_arch.h b/components/freertos/config/linux/include/freertos/FreeRTOSConfig_arch.h index 4530bc0fd35..bd0276b06b1 100644 --- a/components/freertos/config/linux/include/freertos/FreeRTOSConfig_arch.h +++ b/components/freertos/config/linux/include/freertos/FreeRTOSConfig_arch.h @@ -52,7 +52,7 @@ /* -------------------- API Includes ----------------------- */ -#define INCLUDE_xTaskGetCurrentTaskHandle 0 /* not defined in POSIX simulator */ +/* Todo: Reconcile INCLUDE_option differences (IDF-8186) */ #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_uxTaskGetStackHighWaterMark2 0 diff --git a/components/freertos/config/riscv/include/freertos/FreeRTOSConfig_arch.h b/components/freertos/config/riscv/include/freertos/FreeRTOSConfig_arch.h index 75e4e759481..e0288dd5c84 100644 --- a/components/freertos/config/riscv/include/freertos/FreeRTOSConfig_arch.h +++ b/components/freertos/config/riscv/include/freertos/FreeRTOSConfig_arch.h @@ -28,20 +28,31 @@ /* ---------------- Amazon SMP FreeRTOS -------------------- */ #if CONFIG_FREERTOS_SMP - #define configUSE_CORE_AFFINITY 1 + #define configUSE_CORE_AFFINITY 1 /* This is always enabled to call IDF style idle hooks, by can be "--Wl,--wrap" * if users enable CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK. */ - #define configUSE_MINIMAL_IDLE_HOOK 1 + #define configUSE_MINIMAL_IDLE_HOOK 1 - /* IDF Newlib supports dynamic reentrancy. We provide our own __getreent() - * function. */ - #define configNEWLIB_REENTRANT_IS_DYNAMIC 1 +/* IDF Newlib supports dynamic reentrancy. We provide our own __getreent() + * function. */ + #define configNEWLIB_REENTRANT_IS_DYNAMIC 1 #endif /* ----------------------- System -------------------------- */ -#define configUSE_NEWLIB_REENTRANT 1 +#define configUSE_NEWLIB_REENTRANT 1 +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + +/* - FreeRTOS provides default for configTLS_BLOCK_TYPE. + * - We simply provide our own INIT and DEINIT functions + * - We set "SET" to a blank macro since there is no need to set the reentrancy + * pointer. All newlib functions calls __getreent. */ + #define configINIT_TLS_BLOCK( xTLSBlock ) esp_reent_init( &( xTLSBlock ) ) + #define configSET_TLS_BLOCK( xTLSBlock ) + #define configDEINIT_TLS_BLOCK( xTLSBlock ) _reclaim_reent( &( xTLSBlock ) ) + +#endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ #define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 @@ -61,9 +72,9 @@ /* -------------------- API Includes ----------------------- */ -#define INCLUDE_xTaskDelayUntil 1 -#define INCLUDE_xTaskGetCurrentTaskHandle 1 -#define INCLUDE_uxTaskGetStackHighWaterMark2 1 +/* Todo: Reconcile INCLUDE_option differences (IDF-8186) */ +#define INCLUDE_xTaskDelayUntil 1 +#define INCLUDE_uxTaskGetStackHighWaterMark2 1 /* ------------------------------------------------ ESP-IDF Additions -------------------------------------------------- * diff --git a/components/freertos/config/xtensa/include/freertos/FreeRTOSConfig_arch.h b/components/freertos/config/xtensa/include/freertos/FreeRTOSConfig_arch.h index c93bb977e58..2349c6d49bc 100644 --- a/components/freertos/config/xtensa/include/freertos/FreeRTOSConfig_arch.h +++ b/components/freertos/config/xtensa/include/freertos/FreeRTOSConfig_arch.h @@ -55,20 +55,31 @@ /* ---------------- Amazon SMP FreeRTOS -------------------- */ #if CONFIG_FREERTOS_SMP - #define configUSE_CORE_AFFINITY 1 + #define configUSE_CORE_AFFINITY 1 /* This is always enabled to call IDF style idle hooks, by can be "--Wl,--wrap" * if users enable CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK. */ - #define configUSE_MINIMAL_IDLE_HOOK 1 + #define configUSE_MINIMAL_IDLE_HOOK 1 - /* IDF Newlib supports dynamic reentrancy. We provide our own __getreent() - * function. */ - #define configNEWLIB_REENTRANT_IS_DYNAMIC 1 +/* IDF Newlib supports dynamic reentrancy. We provide our own __getreent() + * function. */ + #define configNEWLIB_REENTRANT_IS_DYNAMIC 1 #endif /* ----------------------- System -------------------------- */ -#define configUSE_NEWLIB_REENTRANT 1 +#define configUSE_NEWLIB_REENTRANT 1 +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + +/* - FreeRTOS provides default for configTLS_BLOCK_TYPE. + * - We simply provide our own INIT and DEINIT functions + * - We set "SET" to a blank macro since there is no need to set the reentrancy + * pointer. All newlib functions calls __getreent. */ + #define configINIT_TLS_BLOCK( xTLSBlock ) esp_reent_init( &( xTLSBlock ) ) + #define configSET_TLS_BLOCK( xTLSBlock ) + #define configDEINIT_TLS_BLOCK( xTLSBlock ) _reclaim_reent( &( xTLSBlock ) ) + +#endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ #define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 @@ -88,9 +99,9 @@ /* -------------------- API Includes ----------------------- */ -#define INCLUDE_xTaskDelayUntil 1 -#define INCLUDE_xTaskGetCurrentTaskHandle 1 -#define INCLUDE_uxTaskGetStackHighWaterMark2 1 +/* Todo: Reconcile INCLUDE_option differences (IDF-8186) */ +#define INCLUDE_xTaskDelayUntil 1 +#define INCLUDE_uxTaskGetStackHighWaterMark2 1 /* ------------------------------------------------ ESP-IDF Additions -------------------------------------------------- * diff --git a/components/freertos/esp_additions/freertos_tasks_c_additions.h b/components/freertos/esp_additions/freertos_tasks_c_additions.h index c7e08d0af1d..e0266a53ef9 100644 --- a/components/freertos/esp_additions/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/freertos_tasks_c_additions.h @@ -20,6 +20,11 @@ * additional API. */ +#if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + #define pxCurrentTCB pxCurrentTCBs +#else +#endif + /* ------------------------------------------------- Static Asserts ------------------------------------------------- */ /* @@ -222,10 +227,23 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt if( pxNewTCB != NULL ) { - /* Allocate space for the stack used by the task being created. - * The base of the stack memory stored in the TCB so the task can - * be deleted later if required. */ - pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + { + memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) ); + + /* Allocate space for the stack used by the task being created. + * The base of the stack memory stored in the TCB so the task can + * be deleted later if required. */ + pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + #else /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + { + /* Allocate space for the stack used by the task being created. + * The base of the stack memory stored in the TCB so the task can + * be deleted later if required. */ + pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ if( pxNewTCB->pxStack == NULL ) { @@ -239,8 +257,17 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt { StackType_t * pxStack; - /* Allocate space for the stack used by the task being created. */ - pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */ + #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + { + /* Allocate space for the stack used by the task being created. */ + pxStack = pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */ + } + #else /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + { + /* Allocate space for the stack used by the task being created. */ + pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */ + } + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ if( pxStack != NULL ) { @@ -249,6 +276,12 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt if( pxNewTCB != NULL ) { + #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + { + memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) ); + } + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + /* Store the stack location in the TCB. */ pxNewTCB->pxStack = pxStack; } @@ -256,7 +289,15 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt { /* The stack cannot be used as the TCB was not created. Free * it again. */ - vPortFree( pxStack ); + #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + { + vPortFreeStack( pxStack ); + } + #else /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + { + vPortFree( pxStack ); + } + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ } } else @@ -356,6 +397,13 @@ _Static_assert( offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfSt /* The memory used for the task's TCB and stack are passed into this * function - use them. */ pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 !e9087 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + + #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + { + memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) ); + } + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ @@ -892,7 +940,15 @@ uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ) else { /* We have a task; return its reentrant struct. */ - ret = &pxCurTask->xNewLib_reent; + #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 + { + ret = &pxCurTask->xTLSBlock; + } + #else /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + { + ret = &pxCurTask->xNewLib_reent; + } + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ } return ret; diff --git a/components/freertos/esp_additions/include/freertos/idf_additions.h b/components/freertos/esp_additions/include/freertos/idf_additions.h index 3b39afe8087..0da84064d6e 100644 --- a/components/freertos/esp_additions/include/freertos/idf_additions.h +++ b/components/freertos/esp_additions/include/freertos/idf_additions.h @@ -208,6 +208,17 @@ TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID ) */ configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimePercentForCore( BaseType_t xCoreID ); +#else /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ + +/* CMock Workaround: CMock currently doesn't preprocess files, thus functions + * guarded by ifdef still get mocked. We provide a dummy define here so that + * functions using configRUN_TIME_COUNTER_TYPE can still be mocked. + * + * Todo: Will be removed when V10.5.1 becomes the default kernel. */ + #ifndef configRUN_TIME_COUNTER_TYPE + #define configRUN_TIME_COUNTER_TYPE unsigned int + #endif + #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ /** diff --git a/tools/ci/check_public_headers_exceptions.txt b/tools/ci/check_public_headers_exceptions.txt index 39ddc166435..2167932fe25 100644 --- a/tools/ci/check_public_headers_exceptions.txt +++ b/tools/ci/check_public_headers_exceptions.txt @@ -12,6 +12,7 @@ components/freertos/FreeRTOS-Kernel/include/freertos/ components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/ components/freertos/FreeRTOS-Kernel-SMP/include/freertos/ components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/ +components/freertos/FreeRTOS-Kernel-V10.5.1/include/freertos/ components/log/include/esp_log_internal.h From 4940cfaa889d5f1fe676a5229b0c8d25f6545ad5 Mon Sep 17 00:00:00 2001 From: Abhik Roy Date: Fri, 16 Dec 2022 02:51:13 +0530 Subject: [PATCH 28/71] feat: Added option to enable or disable Port mapping in NAPT --- components/lwip/Kconfig | 7 +++++++ components/lwip/lwip | 2 +- components/lwip/port/include/lwipopts.h | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index f455c28fb7b..d3be4246d01 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -227,6 +227,13 @@ menu "LWIP" help Enabling this option allows Network Address and Port Translation. + config LWIP_IPV4_NAPT_PORTMAP + bool "Enable NAT Port Mapping (new/experimental)" + depends on LWIP_IPV4_NAPT + default y + help + Enabling this option allows Port Forwarding or Port mapping. + config LWIP_STATS bool "Enable LWIP statistics" default n diff --git a/components/lwip/lwip b/components/lwip/lwip index 7896c6cad02..90009cc2b0b 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit 7896c6cad020d17a986f7e850f603e084e319328 +Subproject commit 90009cc2b0b487ab12688778f5fffc27e9b2b8c3 diff --git a/components/lwip/port/include/lwipopts.h b/components/lwip/port/include/lwipopts.h index 7dca4af288c..183b7be80aa 100644 --- a/components/lwip/port/include/lwipopts.h +++ b/components/lwip/port/include/lwipopts.h @@ -216,6 +216,13 @@ extern "C" { */ #ifdef CONFIG_LWIP_IPV4_NAPT #define IP_NAPT 1 + +#ifdef CONFIG_LWIP_IPV4_NAPT_PORTMAP +#define IP_NAPT_PORTMAP 1 +#else +#define IP_NAPT_PORTMAP 0 +#endif + #else #define IP_NAPT 0 #endif From 88364b8b119785f39fac63eb10ce4a67a0afe78c Mon Sep 17 00:00:00 2001 From: Lou Tianhao Date: Thu, 14 Sep 2023 15:42:35 +0800 Subject: [PATCH 29/71] feat(pm): add internal pull-up/downs option for gpio used for deepsleep wakeup stash --- components/esp_hw_support/Kconfig | 6 ++++++ components/esp_hw_support/include/esp_sleep.h | 10 +++++++--- components/esp_hw_support/sleep_modes.c | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 4a9b2d226b5..b2ba043f4b9 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -170,6 +170,12 @@ menu "Hardware Settings" help Enable esp sleep debug. + config ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS + bool "Allow to enable internal pull-up/downs for the Deep-Sleep wakeup IOs" + default y + help + When using rtc gpio wakeup source during deepsleep without external pull-up/downs, you may want to + make use of the internal ones. endmenu menu "ESP_SLEEP_WORKAROUND" diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index fc311581bad..71325754c68 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -340,9 +340,13 @@ esp_err_t esp_sleep_enable_ext1_wakeup_with_level_mask(uint64_t io_mask, uint64_ * @note This function does not modify pin configuration. The pins are * configured inside esp_deep_sleep_start, immediately before entering sleep mode. * - * @note You don't need to care to pull-up or pull-down before using this - * function, because this will be set internally in esp_deep_sleep_start - * based on the wakeup mode. BTW, when you use low level to wake up the + * @note You don't need to worry about pull-up or pull-down resistors before + * using this function because the ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS + * option is enabled by default. It will automatically set pull-up or pull-down + * resistors internally in esp_deep_sleep_start based on the wakeup mode. However, + * when using external pull-up or pull-down resistors, please be sure to disable + * the ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS option, as the combination of internal + * and external resistors may cause interference. BTW, when you use low level to wake up the * chip, we strongly recommend you to add external resistors (pull-up). * * @param gpio_pin_mask Bit mask of GPIO numbers which will cause wakeup. Only GPIOs diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 723a82d1fa9..a4f920890b4 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1531,6 +1531,7 @@ static void gpio_deep_sleep_wakeup_prepare(void) if (((1ULL << gpio_idx) & s_config.gpio_wakeup_mask) == 0) { continue; } +#if CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS if (s_config.gpio_trigger_mode & BIT(gpio_idx)) { ESP_ERROR_CHECK(gpio_pullup_dis(gpio_idx)); ESP_ERROR_CHECK(gpio_pulldown_en(gpio_idx)); @@ -1538,6 +1539,7 @@ static void gpio_deep_sleep_wakeup_prepare(void) ESP_ERROR_CHECK(gpio_pullup_en(gpio_idx)); ESP_ERROR_CHECK(gpio_pulldown_dis(gpio_idx)); } +#endif ESP_ERROR_CHECK(gpio_hold_en(gpio_idx)); } // Clear state from previous wakeup From fbce971ccdac041056977a5287b63c0bca7ffe7b Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Mon, 18 Sep 2023 15:06:46 +0800 Subject: [PATCH 30/71] docs(compatibility): update recommended version for ESP32-S2 v1.0 --- COMPATIBILITY.md | 6 ++++-- COMPATIBILITY_CN.md | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 7743d46b535..440277835dd 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -54,8 +54,10 @@ Supported since ESP-IDF v4.2. |------------------------|-------------|----------| | release/v4.2 | v4.2.3 | v4.2.3 | | release/v4.3 | v4.3.3 | v4.3.3 | -| release/v4.4 | v4.4.1 | v4.4.1 | -| release/v5.0 and above | v5.0 | v5.0 | +| release/v4.4 | v4.4.6 | v4.4.1 | +| release/v5.0 | v5.0.4 | v5.0 | +| release/v5.1 | v5.1.2 | v5.1 | +| release/v5.2 and above | v5.2 | v5.2 | ### ESP32-C3 diff --git a/COMPATIBILITY_CN.md b/COMPATIBILITY_CN.md index 2240fac6e83..a72aa6cb94e 100644 --- a/COMPATIBILITY_CN.md +++ b/COMPATIBILITY_CN.md @@ -54,8 +54,10 @@ |------------------------|-------------|----------| | release/v4.2 | v4.2.3 | v4.2.3 | | release/v4.3 | v4.3.3 | v4.3.3 | -| release/v4.4 | v4.4.1 | v4.4.1 | -| release/v5.0 及以上 | v5.0 | v5.0 | +| release/v4.4 | v4.4.6 | v4.4.1 | +| release/v5.0 | v5.0.4 | v5.0 | +| release/v5.1 | v5.1.2 | v5.1 | +| release/v5.2 及以上 | v5.2 | v5.2 | ### ESP32-C3 From 6bb05cccdd59355cfc85e9495138823c75a971aa Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 1 Aug 2023 17:32:26 +0800 Subject: [PATCH 31/71] feat(rmt): add driver support for esp32p4 including DMA feature --- components/driver/Kconfig | 27 +- components/driver/deprecated/rmt_legacy.c | 44 +- components/driver/deprecated/timer_legacy.c | 2 +- components/driver/gptimer/gptimer.c | 2 +- components/driver/rmt/Kconfig.rmt | 26 + components/driver/rmt/rmt_common.c | 46 +- components/driver/rmt/rmt_encoder.c | 44 +- components/driver/rmt/rmt_private.h | 32 +- components/driver/rmt/rmt_rx.c | 65 +- components/driver/rmt/rmt_tx.c | 99 +- .../test_apps/legacy_rmt_driver/README.md | 4 +- .../legacy_rmt_driver/main/test_legacy_rmt.c | 12 +- components/driver/test_apps/rmt/README.md | 4 +- .../driver/test_apps/rmt/main/test_board.h | 9 + .../test_apps/rmt/main/test_rmt_common.c | 62 +- .../driver/test_apps/rmt/main/test_rmt_iram.c | 7 +- .../driver/test_apps/rmt/main/test_rmt_rx.c | 64 +- .../driver/test_apps/rmt/main/test_rmt_tx.c | 54 +- .../rmt/main/test_util_rmt_encoders.c | 11 +- .../esp_hw_support/dma/async_memcpy_gdma.c | 6 +- components/hal/esp32/include/hal/rmt_ll.h | 38 +- components/hal/esp32c3/include/hal/rmt_ll.h | 35 +- components/hal/esp32c6/include/hal/rmt_ll.h | 24 + components/hal/esp32h2/include/hal/rmt_ll.h | 24 + .../hal/esp32p4/include/hal/clk_gate_ll.h | 6 - components/hal/esp32p4/include/hal/rmt_ll.h | 923 ++++++++++++++++++ components/hal/esp32s2/include/hal/rmt_ll.h | 39 +- components/hal/esp32s3/include/hal/rmt_ll.h | 33 + components/hal/rmt_hal.c | 2 - .../esp32p4/include/soc/Kconfig.soc_caps.in | 20 +- .../soc/esp32p4/include/soc/clk_tree_defs.h | 36 + .../soc/esp32p4/include/soc/rmt_struct.h | 586 +++++------ components/soc/esp32p4/include/soc/soc_caps.h | 15 +- .../soc/esp32p4/ld/esp32p4.peripherals.ld | 4 +- components/soc/esp32p4/rmt_periph.c | 41 +- docs/docs_not_updated/esp32p4.txt | 1 - examples/peripherals/rmt/dshot_esc/README.md | 4 +- .../rmt/ir_nec_transceiver/README.md | 4 +- examples/peripherals/rmt/led_strip/README.md | 4 +- .../peripherals/rmt/musical_buzzer/README.md | 4 +- examples/peripherals/rmt/onewire/README.md | 4 +- .../peripherals/rmt/stepper_motor/README.md | 4 +- 42 files changed, 1880 insertions(+), 591 deletions(-) create mode 100644 components/driver/rmt/Kconfig.rmt create mode 100644 components/driver/test_apps/rmt/main/test_board.h create mode 100644 components/hal/esp32p4/include/hal/rmt_ll.h diff --git a/components/driver/Kconfig b/components/driver/Kconfig index 46f2d0b979a..65f29bd8e7e 100644 --- a/components/driver/Kconfig +++ b/components/driver/Kconfig @@ -299,32 +299,7 @@ menu "Driver Configurations" orsource "./pcnt/Kconfig.pcnt" - menu "RMT Configuration" - depends on SOC_RMT_SUPPORTED - config RMT_ISR_IRAM_SAFE - bool "RMT ISR IRAM-Safe" - default n - select GDMA_ISR_IRAM_SAFE if SOC_RMT_SUPPORT_DMA # RMT basic functionality relies on GDMA callback - select GDMA_CTRL_FUNC_IN_IRAM if SOC_RMT_SUPPORT_DMA # RMT needs to restart the GDMA in the interrupt - help - Ensure the RMT interrupt is IRAM-Safe by allowing the interrupt handler to be - executable when the cache is disabled (e.g. SPI Flash write). - - config RMT_SUPPRESS_DEPRECATE_WARN - bool "Suppress legacy driver deprecated warning" - default n - help - Wether to suppress the deprecation warnings when using legacy rmt driver (driver/rmt.h). - If you want to continue using the legacy driver, and don't want to see related deprecation warnings, - you can enable this option. - - config RMT_ENABLE_DEBUG_LOG - bool "Enable debug log" - default n - help - Wether to enable the debug log message for RMT driver. - Note that, this option only controls the RMT driver log, won't affect other drivers. - endmenu # RMT Configuration + orsource "./rmt/Kconfig.rmt" orsource "./mcpwm/Kconfig.mcpwm" diff --git a/components/driver/deprecated/rmt_legacy.c b/components/driver/deprecated/rmt_legacy.c index 66950f7b60f..e485420a7bd 100644 --- a/components/driver/deprecated/rmt_legacy.c +++ b/components/driver/deprecated/rmt_legacy.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -58,6 +58,18 @@ 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_PERIPH_CLK_CTRL_SHARED +#define RMT_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define RMT_CLOCK_SRC_ATOMIC() +#endif + +#if !SOC_RCC_IS_INDEPENDENT +#define RMT_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define RMT_RCC_ATOMIC() +#endif + typedef struct { rmt_hal_context_t hal; _lock_t rmt_driver_isr_lock; @@ -125,8 +137,10 @@ static void rmt_module_enable(void) { RMT_ENTER_CRITICAL(); if (rmt_contex.rmt_module_enabled == false) { - periph_module_reset(rmt_periph_signals.groups[0].module); - periph_module_enable(rmt_periph_signals.groups[0].module); + RMT_RCC_ATOMIC() { + rmt_ll_enable_bus_clock(0, true); + rmt_ll_reset_register(0); + } rmt_contex.rmt_module_enabled = true; } RMT_EXIT_CRITICAL(); @@ -137,7 +151,9 @@ static void rmt_module_disable(void) { RMT_ENTER_CRITICAL(); if (rmt_contex.rmt_module_enabled == true) { - periph_module_disable(rmt_periph_signals.groups[0].module); + RMT_RCC_ATOMIC() { + rmt_ll_enable_bus_clock(0, false); + } rmt_contex.rmt_module_enabled = false; } RMT_EXIT_CRITICAL(); @@ -415,7 +431,9 @@ esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk) ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); // `rmt_clock_source_t` and `rmt_source_clk_t` are binary compatible, as the underlying enum entries come from the same `soc_module_clk_t` - rmt_ll_set_group_clock_src(rmt_contex.hal.regs, channel, (rmt_clock_source_t)base_clk, 1, 0, 0); + RMT_CLOCK_SRC_ATOMIC() { + rmt_ll_set_group_clock_src(rmt_contex.hal.regs, channel, (rmt_clock_source_t)base_clk, 1, 0, 0); + } RMT_EXIT_CRITICAL(); return ESP_OK; } @@ -552,6 +570,7 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par uint32_t carrier_freq_hz = rmt_param->tx_config.carrier_freq_hz; bool carrier_en = rmt_param->tx_config.carrier_en; uint32_t rmt_source_clk_hz; + rmt_clock_source_t clk_src = RMT_BASECLK_DEFAULT; ESP_RETURN_ON_FALSE(rmt_is_channel_number_valid(channel, mode), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); ESP_RETURN_ON_FALSE(mem_cnt + channel <= SOC_RMT_CHANNELS_PER_GROUP && mem_cnt > 0, ESP_ERR_INVALID_ARG, TAG, RMT_MEM_CNT_ERROR_STR); @@ -567,19 +586,18 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par if (rmt_param->flags & RMT_CHANNEL_FLAGS_AWARE_DFS) { #if SOC_RMT_SUPPORT_XTAL // clock src: XTAL_CLK - esp_clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_XTAL, ESP_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); + clk_src = RMT_BASECLK_XTAL; #elif SOC_RMT_SUPPORT_REF_TICK // clock src: REF_CLK - esp_clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_REF, ESP_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); + clk_src = RMT_BASECLK_REF; #else #error "No clock source is aware of DFS" #endif - } else { - // fallback to use default clock source - esp_clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_DEFAULT, ESP_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); + } + esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rmt_source_clk_hz); + RMT_CLOCK_SRC_ATOMIC() { + rmt_ll_set_group_clock_src(dev, channel, clk_src, 1, 0, 0); + rmt_ll_enable_group_clock(dev, true); } RMT_EXIT_CRITICAL(); diff --git a/components/driver/deprecated/timer_legacy.c b/components/driver/deprecated/timer_legacy.c index 43f42336d05..7df292bdf3c 100644 --- a/components/driver/deprecated/timer_legacy.c +++ b/components/driver/deprecated/timer_legacy.c @@ -34,7 +34,7 @@ static const char *TIMER_TAG = "timer_group"; #define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux); #define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL_SAFE(mux); -#if CONFIG_IDF_TARGET_ESP32P4 +#if SOC_PERIPH_CLK_CTRL_SHARED #define GPTIMER_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() #else #define GPTIMER_CLOCK_SRC_ATOMIC() diff --git a/components/driver/gptimer/gptimer.c b/components/driver/gptimer/gptimer.c index cf1b2ec797e..61978935b1e 100644 --- a/components/driver/gptimer/gptimer.c +++ b/components/driver/gptimer/gptimer.c @@ -32,7 +32,7 @@ static const char *TAG = "gptimer"; -#if CONFIG_IDF_TARGET_ESP32P4 +#if SOC_PERIPH_CLK_CTRL_SHARED #define GPTIMER_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() #else #define GPTIMER_CLOCK_SRC_ATOMIC() diff --git a/components/driver/rmt/Kconfig.rmt b/components/driver/rmt/Kconfig.rmt new file mode 100644 index 00000000000..76605b75757 --- /dev/null +++ b/components/driver/rmt/Kconfig.rmt @@ -0,0 +1,26 @@ +menu "RMT Configuration" + depends on SOC_RMT_SUPPORTED + config RMT_ISR_IRAM_SAFE + bool "RMT ISR IRAM-Safe" + default n + select GDMA_ISR_IRAM_SAFE if SOC_RMT_SUPPORT_DMA # RMT basic functionality relies on GDMA callback + select GDMA_CTRL_FUNC_IN_IRAM if SOC_RMT_SUPPORT_DMA # RMT needs to restart the GDMA in the interrupt + help + Ensure the RMT interrupt is IRAM-Safe by allowing the interrupt handler to be + executable when the cache is disabled (e.g. SPI Flash write). + + config RMT_SUPPRESS_DEPRECATE_WARN + bool "Suppress legacy driver deprecated warning" + default n + help + Wether to suppress the deprecation warnings when using legacy rmt driver (driver/rmt.h). + If you want to continue using the legacy driver, and don't want to see related deprecation warnings, + you can enable this option. + + config RMT_ENABLE_DEBUG_LOG + bool "Enable debug log" + default n + help + Wether to enable the debug log message for RMT driver. + Note that, this option only controls the RMT driver log, won't affect other drivers. +endmenu # RMT Configuration diff --git a/components/driver/rmt/rmt_common.c b/components/driver/rmt/rmt_common.c index 2a95f4b61f5..0cb834d9597 100644 --- a/components/driver/rmt/rmt_common.c +++ b/components/driver/rmt/rmt_common.c @@ -24,6 +24,18 @@ static const char *TAG = "rmt"; +#if SOC_PERIPH_CLK_CTRL_SHARED +#define RMT_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define RMT_CLOCK_SRC_ATOMIC() +#endif + +#if !SOC_RCC_IS_INDEPENDENT +#define RMT_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define RMT_RCC_ATOMIC() +#endif + typedef struct rmt_platform_t { _lock_t mutex; // platform level mutex lock rmt_group_t *groups[SOC_RMT_GROUPS]; // array of RMT group instances @@ -50,11 +62,13 @@ rmt_group_t *rmt_acquire_group_handle(int group_id) group->occupy_mask = UINT32_MAX & ~((1 << SOC_RMT_CHANNELS_PER_GROUP) - 1); // group clock won't be configured at this stage, it will be set when allocate the first channel group->clk_src = 0; - // enable APB access RMT registers - periph_module_enable(rmt_periph_signals.groups[group_id].module); - periph_module_reset(rmt_periph_signals.groups[group_id].module); - // "uninitialize" group intr_priority, read comments in `rmt_new_tx_channel()` for detail - group->intr_priority = RMT_GROUP_INTR_PRIORITY_UNINITALIZED; + // group interrupt priority is shared between all channels, it will be set when allocate the first channel + group->intr_priority = RMT_GROUP_INTR_PRIORITY_UNINITIALIZED; + // enable the bus clock for the RMT peripheral + RMT_RCC_ATOMIC() { + rmt_ll_enable_bus_clock(group_id, true); + rmt_ll_reset_register(group_id); + } // hal layer initialize rmt_hal_init(&group->hal); } @@ -78,15 +92,23 @@ void rmt_release_group_handle(rmt_group_t *group) int group_id = group->group_id; rmt_clock_source_t clk_src = group->clk_src; bool do_deinitialize = false; + rmt_hal_context_t *hal = &group->hal; _lock_acquire(&s_platform.mutex); s_platform.group_ref_counts[group_id]--; if (s_platform.group_ref_counts[group_id] == 0) { do_deinitialize = true; s_platform.groups[group_id] = NULL; + // disable core clock + RMT_CLOCK_SRC_ATOMIC() { + rmt_ll_enable_group_clock(hal->regs, false); + } // hal layer deinitialize - rmt_hal_deinit(&group->hal); - periph_module_disable(rmt_periph_signals.groups[group_id].module); + rmt_hal_deinit(hal); + // disable bus clock + RMT_RCC_ATOMIC() { + rmt_ll_enable_bus_clock(group_id, false); + } free(group); } _lock_release(&s_platform.mutex); @@ -165,7 +187,10 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t #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); + RMT_CLOCK_SRC_ATOMIC() { + rmt_ll_set_group_clock_src(group->hal.regs, channel_id, clk_src, 1, 1, 0); + rmt_ll_enable_group_clock(group->hal.regs, true); + } group->resolution_hz = periph_src_clk_hz; ESP_LOGD(TAG, "group clock resolution:%"PRIu32, group->resolution_hz); return ret; @@ -211,7 +236,7 @@ bool rmt_set_intr_priority_to_group(rmt_group_t *group, int intr_priority) { bool priority_conflict = false; portENTER_CRITICAL(&group->spinlock); - if (group->intr_priority == RMT_GROUP_INTR_PRIORITY_UNINITALIZED) { + if (group->intr_priority == RMT_GROUP_INTR_PRIORITY_UNINITIALIZED) { // intr_priority never allocated, accept user's value unconditionally // intr_priority could only be set once here group->intr_priority = intr_priority; @@ -240,7 +265,8 @@ bool rmt_set_intr_priority_to_group(rmt_group_t *group, int intr_priority) return priority_conflict; } -int rmt_get_isr_flags(rmt_group_t *group) { +int rmt_get_isr_flags(rmt_group_t *group) +{ int isr_flags = RMT_INTR_ALLOC_FLAG; if (group->intr_priority) { // Use user-specified priority bit diff --git a/components/driver/rmt/rmt_encoder.c b/components/driver/rmt/rmt_encoder.c index f6c5939b741..f261862878d 100644 --- a/components/driver/rmt/rmt_encoder.c +++ b/components/driver/rmt/rmt_encoder.c @@ -62,8 +62,8 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base); const uint8_t *nd = (const uint8_t *)primary_data; rmt_encode_state_t state = RMT_ENCODING_RESET; - dma_descriptor_t *desc0 = NULL; - dma_descriptor_t *desc1 = NULL; + rmt_dma_descriptor_t *desc0 = NULL; + rmt_dma_descriptor_t *desc1 = NULL; size_t byte_index = bytes_encoder->last_byte_index; size_t bit_index = bytes_encoder->last_bit_index; @@ -72,7 +72,12 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han // how many symbols we can save for this round size_t mem_have = tx_chan->mem_end - tx_chan->mem_off; // where to put the encoded symbols? DMA buffer or RMT HW memory - rmt_symbol_word_t *mem_to = channel->dma_chan ? channel->dma_mem_base : channel->hw_mem_base; + rmt_symbol_word_t *mem_to_nc = NULL; + if (channel->dma_chan) { + mem_to_nc = (rmt_symbol_word_t *)RMT_GET_NON_CACHE_ADDR(channel->dma_mem_base); + } else { + mem_to_nc = channel->hw_mem_base; + } // how many symbols will be encoded in this round size_t encode_len = MIN(mem_want, mem_have); bool encoding_truncated = mem_have < mem_want; @@ -81,9 +86,9 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han if (channel->dma_chan) { // mark the start descriptor if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { - desc0 = &tx_chan->dma_nodes[0]; + desc0 = &tx_chan->dma_nodes_nc[0]; } else { - desc0 = &tx_chan->dma_nodes[1]; + desc0 = &tx_chan->dma_nodes_nc[1]; } } @@ -97,9 +102,9 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han } while ((len > 0) && (bit_index < 8)) { if (cur_byte & (1 << bit_index)) { - mem_to[tx_chan->mem_off++] = bytes_encoder->bit1; + mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit1; } else { - mem_to[tx_chan->mem_off++] = bytes_encoder->bit0; + mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit0; } len--; bit_index++; @@ -113,9 +118,9 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han if (channel->dma_chan) { // mark the end descriptor if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { - desc1 = &tx_chan->dma_nodes[0]; + desc1 = &tx_chan->dma_nodes_nc[0]; } else { - desc1 = &tx_chan->dma_nodes[1]; + desc1 = &tx_chan->dma_nodes_nc[1]; } // cross line, means desc0 has prepared with sufficient data buffer @@ -168,8 +173,8 @@ static size_t IRAM_ATTR rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_hand rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base); rmt_symbol_word_t *symbols = (rmt_symbol_word_t *)primary_data; rmt_encode_state_t state = RMT_ENCODING_RESET; - dma_descriptor_t *desc0 = NULL; - dma_descriptor_t *desc1 = NULL; + rmt_dma_descriptor_t *desc0 = NULL; + rmt_dma_descriptor_t *desc1 = NULL; size_t symbol_index = copy_encoder->last_symbol_index; // how many symbols will be copied by the encoder @@ -177,7 +182,12 @@ static size_t IRAM_ATTR rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_hand // how many symbols we can save for this round size_t mem_have = tx_chan->mem_end - tx_chan->mem_off; // where to put the encoded symbols? DMA buffer or RMT HW memory - rmt_symbol_word_t *mem_to = channel->dma_chan ? channel->dma_mem_base : channel->hw_mem_base; + rmt_symbol_word_t *mem_to_nc = NULL; + if (channel->dma_chan) { + mem_to_nc = (rmt_symbol_word_t *)RMT_GET_NON_CACHE_ADDR(channel->dma_mem_base); + } else { + mem_to_nc = channel->hw_mem_base; + } // how many symbols will be encoded in this round size_t encode_len = MIN(mem_want, mem_have); bool encoding_truncated = mem_have < mem_want; @@ -186,24 +196,24 @@ static size_t IRAM_ATTR rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_hand if (channel->dma_chan) { // mark the start descriptor if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { - desc0 = &tx_chan->dma_nodes[0]; + desc0 = &tx_chan->dma_nodes_nc[0]; } else { - desc0 = &tx_chan->dma_nodes[1]; + desc0 = &tx_chan->dma_nodes_nc[1]; } } size_t len = encode_len; while (len > 0) { - mem_to[tx_chan->mem_off++] = symbols[symbol_index++]; + mem_to_nc[tx_chan->mem_off++] = symbols[symbol_index++]; len--; } if (channel->dma_chan) { // mark the end descriptor if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { - desc1 = &tx_chan->dma_nodes[0]; + desc1 = &tx_chan->dma_nodes_nc[0]; } else { - desc1 = &tx_chan->dma_nodes[1]; + desc1 = &tx_chan->dma_nodes_nc[1]; } // cross line, means desc0 has prepared with sufficient data buffer diff --git a/components/driver/rmt/rmt_private.h b/components/driver/rmt/rmt_private.h index 4fb4406a899..c68d67cfcfb 100644 --- a/components/driver/rmt/rmt_private.h +++ b/components/driver/rmt/rmt_private.h @@ -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 */ @@ -13,9 +13,11 @@ #include "freertos/idf_additions.h" #include "esp_err.h" #include "soc/soc_caps.h" +#include "soc/gdma_channel.h" #include "hal/rmt_types.h" #include "hal/rmt_hal.h" #include "hal/dma_types.h" +#include "hal/cache_ll.h" #include "esp_intr_alloc.h" #include "esp_heap_caps.h" #include "esp_pm.h" @@ -44,16 +46,27 @@ extern "C" { #define RMT_TX_CHANNEL_OFFSET_IN_GROUP 0 #define RMT_RX_CHANNEL_OFFSET_IN_GROUP (SOC_RMT_CHANNELS_PER_GROUP - SOC_RMT_TX_CANDIDATES_PER_GROUP) - #define RMT_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED // DMA buffer size must align to `rmt_symbol_word_t` #define RMT_DMA_DESC_BUF_MAX_SIZE (DMA_DESCRIPTOR_BUFFER_MAX_SIZE & ~(sizeof(rmt_symbol_word_t) - 1)) -#define RMT_DMA_NODES_PING_PONG 2 // two nodes ping-pong -#define RMT_PM_LOCK_NAME_LEN_MAX 16 +#define RMT_DMA_NODES_PING_PONG 2 // two nodes ping-pong +#define RMT_PM_LOCK_NAME_LEN_MAX 16 +#define RMT_GROUP_INTR_PRIORITY_UNINITIALIZED (-1) -#define RMT_GROUP_INTR_PRIORITY_UNINITALIZED (-1) +#if SOC_GDMA_TRIG_PERIPH_RMT0_BUS == SOC_GDMA_BUS_AHB +#define RMT_DMA_DESC_ALIGN 32 +typedef dma_descriptor_align4_t rmt_dma_descriptor_t; +#else +#error "Unsupported RMT DMA bus" +#endif + +#ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR +#define RMT_GET_NON_CACHE_ADDR(addr) ((addr) ? CACHE_LL_L2MEM_NON_CACHE_ADDR(addr) : 0) +#else +#define RMT_GET_NON_CACHE_ADDR(addr) (addr) +#endif typedef struct { struct { @@ -151,7 +164,8 @@ struct rmt_tx_channel_t { rmt_tx_trans_desc_t *cur_trans; // points to current transaction void *user_data; // user context rmt_tx_done_callback_t on_trans_done; // callback, invoked on trans done - dma_descriptor_t dma_nodes[RMT_DMA_NODES_PING_PONG]; // DMA descriptor nodes, make up a circular link list + rmt_dma_descriptor_t *dma_nodes; // DMA descriptor nodes + rmt_dma_descriptor_t *dma_nodes_nc; // DMA descriptor nodes accessed in non-cached way rmt_tx_trans_desc_t trans_desc_pool[]; // transfer descriptor pool }; @@ -164,13 +178,14 @@ typedef struct { struct rmt_rx_channel_t { rmt_channel_t base; // channel base class - size_t mem_off; // starting offset to fetch the symbols in RMTMEM + size_t mem_off; // starting offset to fetch the symbols in RMT-MEM size_t ping_pong_symbols; // ping-pong size (half of the RMT channel memory) rmt_rx_done_callback_t on_recv_done; // callback, invoked on receive done void *user_data; // user context rmt_rx_trans_desc_t trans_desc; // transaction description size_t num_dma_nodes; // number of DMA nodes, determined by how big the memory block that user configures - dma_descriptor_t dma_nodes[]; // DMA link nodes + rmt_dma_descriptor_t *dma_nodes; // DMA link nodes + rmt_dma_descriptor_t *dma_nodes_nc; // DMA descriptor nodes accessed in non-cached way }; /** @@ -201,7 +216,6 @@ void rmt_release_group_handle(rmt_group_t *group); */ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t clk_src); - /** * @brief Set interrupt priority to RMT group * @param group RMT group to set interrupt priority to diff --git a/components/driver/rmt/rmt_rx.c b/components/driver/rmt/rmt_rx.c index 03c3d1de5b5..9ee7d1ad16a 100644 --- a/components/driver/rmt/rmt_rx.c +++ b/components/driver/rmt/rmt_rx.c @@ -21,10 +21,12 @@ #include "soc/rmt_periph.h" #include "soc/rtc.h" #include "hal/rmt_ll.h" +#include "hal/cache_hal.h" #include "hal/gpio_hal.h" #include "driver/gpio.h" #include "driver/rmt_rx.h" #include "rmt_private.h" +#include "rom/cache.h" #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) @@ -39,26 +41,26 @@ static void rmt_rx_default_isr(void *args); #if SOC_RMT_SUPPORT_DMA static bool rmt_dma_rx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data); -static void rmt_rx_mount_dma_buffer(dma_descriptor_t *desc_array, size_t array_size, const void *buffer, size_t buffer_size) +static void rmt_rx_mount_dma_buffer(rmt_dma_descriptor_t *desc_array, rmt_dma_descriptor_t *desc_array_nc, size_t array_size, const void *buffer, size_t buffer_size) { size_t prepared_length = 0; uint8_t *data = (uint8_t *)buffer; int dma_node_i = 0; - dma_descriptor_t *desc = NULL; + rmt_dma_descriptor_t *desc = NULL; while (buffer_size > RMT_DMA_DESC_BUF_MAX_SIZE) { - desc = &desc_array[dma_node_i]; + desc = &desc_array_nc[dma_node_i]; desc->dw0.suc_eof = 0; desc->dw0.size = RMT_DMA_DESC_BUF_MAX_SIZE; desc->dw0.length = 0; desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; desc->buffer = &data[prepared_length]; - desc->next = &desc_array[dma_node_i + 1]; + desc->next = &desc_array[dma_node_i + 1]; // note, we must use the cache address for the "next" pointer prepared_length += RMT_DMA_DESC_BUF_MAX_SIZE; buffer_size -= RMT_DMA_DESC_BUF_MAX_SIZE; dma_node_i++; } if (buffer_size) { - desc = &desc_array[dma_node_i]; + desc = &desc_array_nc[dma_node_i]; desc->dw0.suc_eof = 0; desc->dw0.size = buffer_size; desc->dw0.length = 0; @@ -77,11 +79,6 @@ static esp_err_t rmt_rx_init_dma_link(rmt_rx_channel_t *rx_channel, const rmt_rx #if SOC_GDMA_TRIG_PERIPH_RMT0_BUS == SOC_GDMA_BUS_AHB ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &rx_channel->base.dma_chan), TAG, "allocate RX DMA channel failed"); #endif - gdma_strategy_config_t gdma_strategy_conf = { - .auto_update_desc = true, - .owner_check = true, - }; - gdma_apply_strategy(rx_channel->base.dma_chan, &gdma_strategy_conf); gdma_rx_event_callbacks_t cbs = { .on_recv_eof = rmt_dma_rx_eof_cb, }; @@ -173,6 +170,9 @@ static esp_err_t rmt_rx_destroy(rmt_rx_channel_t *rx_channel) // de-register channel from RMT group rmt_rx_unregister_from_group(&rx_channel->base, rx_channel->base.group); } + if (rx_channel->dma_nodes) { + free(rx_channel->dma_nodes); + } free(rx_channel); return ESP_OK; } @@ -197,18 +197,21 @@ esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_ ESP_GOTO_ON_FALSE(config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "DMA not supported"); #endif // SOC_RMT_SUPPORT_DMA - size_t num_dma_nodes = 0; - if (config->flags.with_dma) { - num_dma_nodes = config->mem_block_symbols * sizeof(rmt_symbol_word_t) / RMT_DMA_DESC_BUF_MAX_SIZE + 1; - } // malloc channel memory uint32_t mem_caps = RMT_MEM_ALLOC_CAPS; + rx_channel = heap_caps_calloc(1, sizeof(rmt_rx_channel_t), mem_caps); + ESP_GOTO_ON_FALSE(rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel"); + // create DMA descriptor + size_t num_dma_nodes = 0; if (config->flags.with_dma) { - // DMA descriptors must be placed in internal SRAM mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA; + num_dma_nodes = config->mem_block_symbols * sizeof(rmt_symbol_word_t) / RMT_DMA_DESC_BUF_MAX_SIZE + 1; + // DMA descriptors must be placed in internal SRAM + rx_channel->dma_nodes = heap_caps_aligned_calloc(RMT_DMA_DESC_ALIGN, num_dma_nodes, sizeof(rmt_dma_descriptor_t), mem_caps); + ESP_GOTO_ON_FALSE(rx_channel->dma_nodes, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel DMA nodes"); + // we will use the non-cached address to manipulate the DMA descriptor, for simplicity + rx_channel->dma_nodes_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(rx_channel->dma_nodes); } - rx_channel = heap_caps_calloc(1, sizeof(rmt_rx_channel_t) + num_dma_nodes * sizeof(dma_descriptor_t), mem_caps); - ESP_GOTO_ON_FALSE(rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel"); rx_channel->num_dma_nodes = num_dma_nodes; // register the channel to group ESP_GOTO_ON_ERROR(rmt_rx_register_to_group(rx_channel, config), err, TAG, "register channel failed"); @@ -348,6 +351,12 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_ if (channel->dma_chan) { ESP_RETURN_ON_FALSE(esp_ptr_internal(buffer), ESP_ERR_INVALID_ARG, TAG, "buffer must locate in internal RAM for DMA use"); + +#if CONFIG_IDF_TARGET_ESP32P4 + uint32_t data_cache_line_mask = cache_hal_get_cache_line_size(CACHE_TYPE_DATA) - 1; + ESP_RETURN_ON_FALSE(((uintptr_t)buffer & data_cache_line_mask) == 0, ESP_ERR_INVALID_ARG, TAG, "buffer must be aligned to cache line size"); + ESP_RETURN_ON_FALSE((buffer_size & data_cache_line_mask) == 0, ESP_ERR_INVALID_ARG, TAG, "buffer size must be aligned to cache line size"); +#endif } if (channel->dma_chan) { ESP_RETURN_ON_FALSE(buffer_size <= rx_chan->num_dma_nodes * RMT_DMA_DESC_BUF_MAX_SIZE, @@ -371,9 +380,9 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_ if (channel->dma_chan) { #if SOC_RMT_SUPPORT_DMA - rmt_rx_mount_dma_buffer(rx_chan->dma_nodes, rx_chan->num_dma_nodes, buffer, buffer_size); + rmt_rx_mount_dma_buffer(rx_chan->dma_nodes, rx_chan->dma_nodes_nc, rx_chan->num_dma_nodes, buffer, buffer_size); gdma_reset(channel->dma_chan); - gdma_start(channel->dma_chan, (intptr_t)rx_chan->dma_nodes); + gdma_start(channel->dma_chan, (intptr_t)rx_chan->dma_nodes); // note, we must use the cached descriptor address to start the DMA #endif } @@ -624,12 +633,12 @@ static void IRAM_ATTR rmt_rx_default_isr(void *args) } #if SOC_RMT_SUPPORT_DMA -static size_t IRAM_ATTR rmt_rx_get_received_symbol_num_from_dma(dma_descriptor_t *desc) +static size_t IRAM_ATTR rmt_rx_get_received_symbol_num_from_dma(rmt_dma_descriptor_t *desc_nc) { size_t received_bytes = 0; - while (desc) { - received_bytes += desc->dw0.length; - desc = desc->next; + while (desc_nc) { + received_bytes += desc_nc->dw0.length; + desc_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(desc_nc->next); } received_bytes = ALIGN_UP(received_bytes, sizeof(rmt_symbol_word_t)); return received_bytes / sizeof(rmt_symbol_word_t); @@ -650,10 +659,18 @@ static bool IRAM_ATTR rmt_dma_rx_eof_cb(gdma_channel_handle_t dma_chan, gdma_eve rmt_ll_rx_enable(hal->regs, channel_id, false); portEXIT_CRITICAL_ISR(&channel->spinlock); +#if CONFIG_IDF_TARGET_ESP32P4 + int invalidate_map = CACHE_MAP_L1_DCACHE; + if (esp_ptr_external_ram((const void *)trans_desc->buffer)) { + invalidate_map |= CACHE_MAP_L2_CACHE; + } + Cache_Invalidate_Addr(invalidate_map, (uint32_t)trans_desc->buffer, trans_desc->buffer_size); +#endif + if (rx_chan->on_recv_done) { rmt_rx_done_event_data_t edata = { .received_symbols = trans_desc->buffer, - .num_symbols = rmt_rx_get_received_symbol_num_from_dma(rx_chan->dma_nodes), + .num_symbols = rmt_rx_get_received_symbol_num_from_dma(rx_chan->dma_nodes_nc), }; if (rx_chan->on_recv_done(channel, &edata, rx_chan->user_data)) { need_yield = true; diff --git a/components/driver/rmt/rmt_tx.c b/components/driver/rmt/rmt_tx.c index 1c0c1c21d11..31a53bec3f4 100644 --- a/components/driver/rmt/rmt_tx.c +++ b/components/driver/rmt/rmt_tx.c @@ -46,29 +46,26 @@ static bool rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t static esp_err_t rmt_tx_init_dma_link(rmt_tx_channel_t *tx_channel, const rmt_tx_channel_config_t *config) { - rmt_symbol_word_t *dma_mem_base = heap_caps_calloc(1, sizeof(rmt_symbol_word_t) * config->mem_block_symbols, RMT_MEM_ALLOC_CAPS | MALLOC_CAP_DMA); + rmt_symbol_word_t *dma_mem_base = heap_caps_calloc(1, sizeof(rmt_symbol_word_t) * config->mem_block_symbols, + RMT_MEM_ALLOC_CAPS | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); ESP_RETURN_ON_FALSE(dma_mem_base, ESP_ERR_NO_MEM, TAG, "no mem for tx DMA buffer"); tx_channel->base.dma_mem_base = dma_mem_base; for (int i = 0; i < RMT_DMA_NODES_PING_PONG; i++) { // each descriptor shares half of the DMA buffer - tx_channel->dma_nodes[i].buffer = dma_mem_base + tx_channel->ping_pong_symbols * i; - tx_channel->dma_nodes[i].dw0.size = tx_channel->ping_pong_symbols * sizeof(rmt_symbol_word_t); + tx_channel->dma_nodes_nc[i].buffer = dma_mem_base + tx_channel->ping_pong_symbols * i; + tx_channel->dma_nodes_nc[i].dw0.size = tx_channel->ping_pong_symbols * sizeof(rmt_symbol_word_t); // the ownership will be switched to DMA in `rmt_tx_do_transaction()` - tx_channel->dma_nodes[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU; + tx_channel->dma_nodes_nc[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU; // each node can generate the DMA eof interrupt, and the driver will do a ping-pong trick in the eof callback - tx_channel->dma_nodes[i].dw0.suc_eof = 1; + tx_channel->dma_nodes_nc[i].dw0.suc_eof = 1; } + gdma_channel_alloc_config_t dma_chan_config = { .direction = GDMA_CHANNEL_DIRECTION_TX, }; #if SOC_GDMA_TRIG_PERIPH_RMT0_BUS == SOC_GDMA_BUS_AHB ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &tx_channel->base.dma_chan), TAG, "allocate TX DMA channel failed"); #endif - gdma_strategy_config_t gdma_strategy_conf = { - .auto_update_desc = true, - .owner_check = true, - }; - gdma_apply_strategy(tx_channel->base.dma_chan, &gdma_strategy_conf); gdma_tx_event_callbacks_t cbs = { .on_trans_eof = rmt_dma_tx_eof_cb, }; @@ -199,6 +196,9 @@ static esp_err_t rmt_tx_destroy(rmt_tx_channel_t *tx_channel) // de-register channel from RMT group rmt_tx_unregister_from_group(&tx_channel->base, tx_channel->base.group); } + if (tx_channel->dma_nodes) { + free(tx_channel->dma_nodes); + } free(tx_channel); return ESP_OK; } @@ -231,12 +231,17 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_ // malloc channel memory uint32_t mem_caps = RMT_MEM_ALLOC_CAPS; + tx_channel = heap_caps_calloc(1, sizeof(rmt_tx_channel_t) + sizeof(rmt_tx_trans_desc_t) * config->trans_queue_depth, mem_caps); + ESP_GOTO_ON_FALSE(tx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for tx channel"); + // create DMA descriptors if (config->flags.with_dma) { // DMA descriptors must be placed in internal SRAM mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA; + tx_channel->dma_nodes = heap_caps_aligned_calloc(RMT_DMA_DESC_ALIGN, RMT_DMA_NODES_PING_PONG, sizeof(rmt_dma_descriptor_t), mem_caps); + ESP_GOTO_ON_FALSE(tx_channel->dma_nodes, ESP_ERR_NO_MEM, err, TAG, "no mem for tx DMA nodes"); + // we will use the non-cached address to manipulate the DMA descriptor, for simplicity + tx_channel->dma_nodes_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(tx_channel->dma_nodes); } - tx_channel = heap_caps_calloc(1, sizeof(rmt_tx_channel_t) + sizeof(rmt_tx_trans_desc_t) * config->trans_queue_depth, mem_caps); - ESP_GOTO_ON_FALSE(tx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for tx channel"); // create transaction queues ESP_GOTO_ON_ERROR(rmt_tx_create_trans_queue(tx_channel, config), err, TAG, "install trans queues failed"); // register the channel to group @@ -318,9 +323,9 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_ tx_channel->base.disable = rmt_tx_disable; // return general channel handle *ret_chan = &tx_channel->base; - ESP_LOGD(TAG, "new tx channel(%d,%d) at %p, gpio=%d, res=%"PRIu32"Hz, hw_mem_base=%p, dma_mem_base=%p, ping_pong_size=%zu, queue_depth=%zu", + ESP_LOGD(TAG, "new tx channel(%d,%d) at %p, gpio=%d, res=%"PRIu32"Hz, hw_mem_base=%p, dma_mem_base=%p, dma_nodes_nc=%p,ping_pong_size=%zu, queue_depth=%zu", group_id, channel_id, tx_channel, config->gpio_num, tx_channel->base.resolution_hz, - tx_channel->base.hw_mem_base, tx_channel->base.dma_mem_base, tx_channel->ping_pong_symbols, tx_channel->queue_size); + tx_channel->base.hw_mem_base, tx_channel->base.dma_mem_base, tx_channel->dma_nodes_nc, tx_channel->ping_pong_symbols, tx_channel->queue_size); return ESP_OK; err: @@ -548,12 +553,17 @@ static void IRAM_ATTR rmt_tx_mark_eof(rmt_tx_channel_t *tx_chan) rmt_channel_t *channel = &tx_chan->base; rmt_group_t *group = channel->group; int channel_id = channel->channel_id; - rmt_symbol_word_t *mem_to = channel->dma_chan ? channel->dma_mem_base : channel->hw_mem_base; + rmt_symbol_word_t *mem_to_nc = NULL; rmt_tx_trans_desc_t *cur_trans = tx_chan->cur_trans; - dma_descriptor_t *desc = NULL; + rmt_dma_descriptor_t *desc_nc = NULL; + if (channel->dma_chan) { + mem_to_nc = (rmt_symbol_word_t *)RMT_GET_NON_CACHE_ADDR(channel->dma_mem_base); + } else { + mem_to_nc = channel->hw_mem_base; + } // a RMT word whose duration is zero means a "stop" pattern - mem_to[tx_chan->mem_off++] = (rmt_symbol_word_t) { + mem_to_nc[tx_chan->mem_off++] = (rmt_symbol_word_t) { .duration0 = 0, .level0 = cur_trans->flags.eot_level, .duration1 = 0, @@ -563,16 +573,16 @@ static void IRAM_ATTR rmt_tx_mark_eof(rmt_tx_channel_t *tx_chan) size_t off = 0; if (channel->dma_chan) { if (tx_chan->mem_off <= tx_chan->ping_pong_symbols) { - desc = &tx_chan->dma_nodes[0]; + desc_nc = &tx_chan->dma_nodes_nc[0]; off = tx_chan->mem_off; } else { - desc = &tx_chan->dma_nodes[1]; + desc_nc = &tx_chan->dma_nodes_nc[1]; off = tx_chan->mem_off - tx_chan->ping_pong_symbols; } - desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - desc->dw0.length = off * sizeof(rmt_symbol_word_t); + desc_nc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + desc_nc->dw0.length = off * sizeof(rmt_symbol_word_t); // break down the DMA descriptor link - desc->next = NULL; + desc_nc->next = NULL; } else { portENTER_CRITICAL_ISR(&group->spinlock); // This is the end of a sequence of encoding sessions, disable the threshold interrupt as no more data will be put into RMT memory block @@ -586,6 +596,7 @@ static size_t IRAM_ATTR rmt_encode_check_result(rmt_tx_channel_t *tx_chan, rmt_t rmt_encode_state_t encode_state = RMT_ENCODING_RESET; rmt_encoder_handle_t encoder = t->encoder; size_t encoded_symbols = encoder->encode(encoder, &tx_chan->base, t->payload, t->payload_bytes, &encode_state); + if (encode_state & RMT_ENCODING_COMPLETE) { t->flags.encoding_done = true; // inserting EOF symbol if there's extra space @@ -615,12 +626,12 @@ static void IRAM_ATTR rmt_tx_do_transaction(rmt_tx_channel_t *tx_chan, rmt_tx_tr #if SOC_RMT_SUPPORT_DMA if (channel->dma_chan) { gdma_reset(channel->dma_chan); - // chain the descritpros into a ring, and will break it in `rmt_encode_eof()` + // chain the descriptors into a ring, and will break it in `rmt_encode_eof()` for (int i = 0; i < RMT_DMA_NODES_PING_PONG; i++) { - tx_chan->dma_nodes[i].next = &tx_chan->dma_nodes[i + 1]; - tx_chan->dma_nodes[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU; + tx_chan->dma_nodes_nc[i].next = &tx_chan->dma_nodes[i + 1]; // note, we must use the cache address for the next pointer + tx_chan->dma_nodes_nc[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU; } - tx_chan->dma_nodes[1].next = &tx_chan->dma_nodes[0]; + tx_chan->dma_nodes_nc[1].next = &tx_chan->dma_nodes[0]; } #endif // SOC_RMT_SUPPORT_DMA @@ -672,7 +683,7 @@ static void IRAM_ATTR rmt_tx_do_transaction(rmt_tx_channel_t *tx_chan, rmt_tx_tr #if SOC_RMT_SUPPORT_DMA if (channel->dma_chan) { - gdma_start(channel->dma_chan, (intptr_t)tx_chan->dma_nodes); + gdma_start(channel->dma_chan, (intptr_t)tx_chan->dma_nodes); // note, we must use the cached descriptor address to start the DMA // delay a while, wait for DMA data going to RMT memory block esp_rom_delay_us(1); } @@ -1040,22 +1051,26 @@ static void IRAM_ATTR rmt_tx_default_isr(void *args) static bool IRAM_ATTR rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) { rmt_tx_channel_t *tx_chan = (rmt_tx_channel_t *)user_data; - dma_descriptor_t *eof_desc = (dma_descriptor_t *)event_data->tx_eof_desc_addr; - // if the DMA descriptor link is still a ring (i.e. hasn't broken down by `rmt_tx_mark_eof()`), then we treat it as a valid ping-pong event - if (eof_desc->next && eof_desc->next->next) { - // continue pingpong transmission - rmt_tx_trans_desc_t *t = tx_chan->cur_trans; - size_t encoded_symbols = t->transmitted_symbol_num; - if (t->flags.encoding_done) { - rmt_tx_mark_eof(tx_chan); - encoded_symbols += 1; - } else { - encoded_symbols += rmt_encode_check_result(tx_chan, t); + rmt_dma_descriptor_t *eof_desc_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(event_data->tx_eof_desc_addr); + rmt_dma_descriptor_t *n = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(eof_desc_nc->next); // next points to a cache address, needs to convert it to a non-cached one + if (n) { + rmt_dma_descriptor_t *nn = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(n->next); + // if the DMA descriptor link is still a ring (i.e. hasn't broken down by `rmt_tx_mark_eof()`), then we treat it as a valid ping-pong event + if (nn) { + // continue ping-pong transmission + rmt_tx_trans_desc_t *t = tx_chan->cur_trans; + size_t encoded_symbols = t->transmitted_symbol_num; + if (t->flags.encoding_done) { + rmt_tx_mark_eof(tx_chan); + encoded_symbols += 1; + } else { + encoded_symbols += rmt_encode_check_result(tx_chan, t); + } + t->transmitted_symbol_num = encoded_symbols; + tx_chan->mem_end = tx_chan->ping_pong_symbols * 3 - tx_chan->mem_end; // mem_end equals to either ping_pong_symbols or ping_pong_symbols*2 + // tell DMA that we have a new descriptor attached + gdma_append(dma_chan); } - t->transmitted_symbol_num = encoded_symbols; - tx_chan->mem_end = tx_chan->ping_pong_symbols * 3 - tx_chan->mem_end; // mem_end equals to either ping_pong_symbols or ping_pong_symbols*2 - // tell DMA that we have a new descriptor attached - gdma_append(dma_chan); } return false; } diff --git a/components/driver/test_apps/legacy_rmt_driver/README.md b/components/driver/test_apps/legacy_rmt_driver/README.md index 19f1d19a549..a79fcf4c5ea 100644 --- a/components/driver/test_apps/legacy_rmt_driver/README.md +++ b/components/driver/test_apps/legacy_rmt_driver/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/legacy_rmt_driver/main/test_legacy_rmt.c b/components/driver/test_apps/legacy_rmt_driver/main/test_legacy_rmt.c index b73d40ec649..39027ce8bb7 100644 --- a/components/driver/test_apps/legacy_rmt_driver/main/test_legacy_rmt.c +++ b/components/driver/test_apps/legacy_rmt_driver/main/test_legacy_rmt.c @@ -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 */ @@ -17,6 +17,7 @@ #include "esp_rom_gpio.h" #include "ir_tools.h" #include "driver/rmt.h" +#include "soc/rmt_periph.h" #define RMT_RX_CHANNEL_ENCODING_START (SOC_RMT_CHANNELS_PER_GROUP-SOC_RMT_TX_CANDIDATES_PER_GROUP) #define RMT_TX_CHANNEL_ENCODING_END (SOC_RMT_TX_CANDIDATES_PER_GROUP-1) @@ -72,8 +73,12 @@ static void rmt_setup_testbench(int tx_channel, int rx_channel, uint32_t flags) // Routing internal signals by IO Matrix (bind rmt tx and rx signal on the same GPIO) gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[RMT_DATA_IO], PIN_FUNC_GPIO); TEST_ESP_OK(gpio_set_direction(RMT_DATA_IO, GPIO_MODE_INPUT_OUTPUT)); - esp_rom_gpio_connect_out_signal(RMT_DATA_IO, RMT_SIG_OUT0_IDX + tx_channel, 0, 0); - esp_rom_gpio_connect_in_signal(RMT_DATA_IO, RMT_SIG_IN0_IDX + rx_channel, 0); + if (tx_channel >= 0) { + esp_rom_gpio_connect_out_signal(RMT_DATA_IO, rmt_periph_signals.groups[0].channels[tx_channel].tx_sig, 0, 0); + } + if (rx_channel >= 0) { + esp_rom_gpio_connect_in_signal(RMT_DATA_IO, rmt_periph_signals.groups[0].channels[rx_channel].rx_sig, 0); + } // install driver if (tx_channel >= 0) { @@ -161,7 +166,6 @@ TEST_CASE("RMT miscellaneous functions", "[rmt]") TEST_ASSERT_EQUAL_INT(RMT_BASECLK_XTAL, src_clk); #endif - TEST_ESP_OK(rmt_set_tx_carrier(channel, 0, 10, 10, 1)); TEST_ESP_OK(rmt_set_idle_level(channel, 1, 0)); diff --git a/components/driver/test_apps/rmt/README.md b/components/driver/test_apps/rmt/README.md index 19f1d19a549..a79fcf4c5ea 100644 --- a/components/driver/test_apps/rmt/README.md +++ b/components/driver/test_apps/rmt/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/rmt/main/test_board.h b/components/driver/test_apps/rmt/main/test_board.h new file mode 100644 index 00000000000..2dca5205af9 --- /dev/null +++ b/components/driver/test_apps/rmt/main/test_board.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#define TEST_RMT_GPIO_NUM_A 0 +#define TEST_RMT_GPIO_NUM_B 2 diff --git a/components/driver/test_apps/rmt/main/test_rmt_common.c b/components/driver/test_apps/rmt/main/test_rmt_common.c index 8944a545ff3..9f80e0e29f1 100644 --- a/components/driver/test_apps/rmt/main/test_rmt_common.c +++ b/components/driver/test_apps/rmt/main/test_rmt_common.c @@ -12,12 +12,13 @@ #include "driver/rmt_tx.h" #include "driver/rmt_rx.h" #include "soc/soc_caps.h" +#include "test_board.h" TEST_CASE("rmt channel install & uninstall", "[rmt]") { rmt_tx_channel_config_t tx_channel_cfg = { .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 1000000, .trans_queue_depth = 1, @@ -25,7 +26,7 @@ TEST_CASE("rmt channel install & uninstall", "[rmt]") rmt_channel_handle_t tx_channels[SOC_RMT_TX_CANDIDATES_PER_GROUP] = {}; rmt_rx_channel_config_t rx_channel_cfg = { .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, - .gpio_num = 2, + .gpio_num = TEST_RMT_GPIO_NUM_B, .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 1000000, }; @@ -98,3 +99,60 @@ TEST_CASE("rmt channel install & uninstall", "[rmt]") } #endif // SOC_RMT_SUPPORT_DMA } + +TEST_CASE("RMT interrupt priority", "[rmt]") +{ + rmt_tx_channel_config_t tx_channel_cfg = { + .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, + .clk_src = RMT_CLK_SRC_DEFAULT, + .resolution_hz = 1000000, // 1MHz, 1 tick = 1us + .trans_queue_depth = 4, + .gpio_num = 0, + .intr_priority = 3 + }; + // --- Check if specifying interrupt priority works + printf("install tx channel\r\n"); + rmt_channel_handle_t tx_channel = NULL; + TEST_ESP_OK(rmt_new_tx_channel(&tx_channel_cfg, &tx_channel)); + + rmt_channel_handle_t another_tx_channel = NULL; + rmt_tx_channel_config_t another_tx_channel_cfg = tx_channel_cfg; + // --- Check if rmt interrupt priority valid check works + another_tx_channel_cfg.intr_priority = 4; + TEST_ESP_ERR(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel), ESP_ERR_INVALID_ARG); + // --- Check if rmt interrupt priority conflict check works + another_tx_channel_cfg.intr_priority = 1; ///< Specifying a conflict intr_priority + TEST_ESP_ERR(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel), ESP_ERR_INVALID_ARG); + another_tx_channel_cfg.intr_priority = 0; ///< Do not specify an intr_priority, should not conflict + TEST_ESP_OK(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel)); + + rmt_rx_channel_config_t rx_channel_cfg = { + .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, + .clk_src = RMT_CLK_SRC_DEFAULT, + .resolution_hz = 1000000, // 1MHz, 1 tick = 1us + .gpio_num = 0, + .flags.with_dma = false, // Interrupt will only be allocated when dma disabled + .flags.io_loop_back = true, // the GPIO will act like a loopback + .intr_priority = 3, + }; + // --- Check if specifying interrupt priority works + printf("install rx channel\r\n"); + rmt_channel_handle_t rx_channel = NULL; + TEST_ESP_OK(rmt_new_rx_channel(&rx_channel_cfg, &rx_channel)); + + rmt_channel_handle_t another_rx_channel = NULL; + rmt_rx_channel_config_t another_rx_channel_cfg = rx_channel_cfg; + // --- Check if rmt interrupt priority valid check works + another_rx_channel_cfg.intr_priority = 4; ///< Specifying a invalid intr_priority + TEST_ESP_ERR(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel), ESP_ERR_INVALID_ARG); + // --- Check if rmt interrupt priority conflict check works + another_rx_channel_cfg.intr_priority = 1; ///< Specifying a conflict intr_priority + TEST_ESP_ERR(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel), ESP_ERR_INVALID_ARG); + another_rx_channel_cfg.intr_priority = 0; ///< Do not specify an intr_priority, should not conflict + TEST_ESP_OK(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel)); + + TEST_ESP_OK(rmt_del_channel(tx_channel)); + TEST_ESP_OK(rmt_del_channel(another_tx_channel)); + TEST_ESP_OK(rmt_del_channel(rx_channel)); + TEST_ESP_OK(rmt_del_channel(another_rx_channel)); +} diff --git a/components/driver/test_apps/rmt/main/test_rmt_iram.c b/components/driver/test_apps/rmt/main/test_rmt_iram.c index 755e360bfa5..f772de8beb2 100644 --- a/components/driver/test_apps/rmt/main/test_rmt_iram.c +++ b/components/driver/test_apps/rmt/main/test_rmt_iram.c @@ -16,6 +16,7 @@ #include "esp_timer.h" #include "soc/soc_caps.h" #include "test_util_rmt_encoders.h" +#include "test_board.h" static void IRAM_ATTR test_delay_post_cache_disable(void *args) { @@ -29,7 +30,7 @@ static void test_rmt_tx_iram_safe(size_t mem_block_symbols, bool with_dma) .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .trans_queue_depth = 4, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .flags.with_dma = with_dma, }; printf("install tx channel\r\n"); @@ -86,8 +87,6 @@ TEST_CASE("rmt tx iram safe", "[rmt]") #endif } - - static void IRAM_ATTR test_simulate_input_post_cache_disable(void *args) { int gpio_num = (int)args; @@ -121,7 +120,7 @@ static void test_rmt_rx_iram_safe(size_t mem_block_symbols, bool with_dma, rmt_c .clk_src = clk_src, .resolution_hz = 1000000, // 1MHz, 1 tick = 1us .mem_block_symbols = mem_block_symbols, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .flags.with_dma = with_dma, .flags.io_loop_back = true, // the GPIO will act like a loopback }; diff --git a/components/driver/test_apps/rmt/main/test_rmt_rx.c b/components/driver/test_apps/rmt/main/test_rmt_rx.c index 562731c66d2..22958a3c719 100644 --- a/components/driver/test_apps/rmt/main/test_rmt_rx.c +++ b/components/driver/test_apps/rmt/main/test_rmt_rx.c @@ -13,6 +13,7 @@ #include "driver/rmt_rx.h" #include "soc/soc_caps.h" #include "test_util_rmt_encoders.h" +#include "test_board.h" #if CONFIG_RMT_ISR_IRAM_SAFE #define TEST_RMT_CALLBACK_ATTR IRAM_ATTR @@ -42,11 +43,16 @@ static bool test_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt_clock_source_t clk_src) { + uint32_t const test_rx_buffer_symbols = 128; + rmt_symbol_word_t *remote_codes = heap_caps_aligned_calloc(64, test_rx_buffer_symbols, sizeof(rmt_symbol_word_t), + MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(remote_codes); + rmt_rx_channel_config_t rx_channel_cfg = { .clk_src = clk_src, .resolution_hz = 1000000, // 1MHz, 1 tick = 1us .mem_block_symbols = mem_block_symbols, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .flags.with_dma = with_dma, .flags.io_loop_back = true, // the GPIO will act like a loopback }; @@ -67,7 +73,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt .resolution_hz = 1000000, // 1MHz, 1 tick = 1us .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, .trans_queue_depth = 4, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .flags.io_loop_back = true, // TX channel and RX channel will bounded to the same GPIO }; printf("install tx channel\r\n"); @@ -86,15 +92,13 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt printf("enable rx channel\r\n"); TEST_ESP_OK(rmt_enable(rx_channel)); - rmt_symbol_word_t remote_codes[128]; - rmt_receive_config_t receive_config = { .signal_range_min_ns = 1250, .signal_range_max_ns = 12000000, }; // ready to receive - TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); + TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config)); printf("send NEC frame without carrier\r\n"); TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { 0x0440, 0x3003 // address, command @@ -102,7 +106,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000))); TEST_ASSERT_EQUAL(34, test_user_data.received_symbol_num); - TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); + TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config)); printf("send NEC frame without carrier\r\n"); TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { 0x0440, 0x3003 // address, command @@ -112,7 +116,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt #if SOC_RMT_SUPPORT_RX_PINGPONG // ready to receive - TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); + TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config)); printf("send customized NEC frame without carrier\r\n"); TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { 0xFF00, 0xFF00, 0xFF00, 0xFF00 @@ -121,7 +125,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt TEST_ASSERT_EQUAL(66, test_user_data.received_symbol_num); #else // ready to receive - TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); + TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config)); printf("send customized NEC frame without carrier\r\n"); // the maximum symbols can receive is its memory block capacity TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { @@ -144,7 +148,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt carrier_cfg.frequency_hz = 25000; TEST_ESP_OK(rmt_apply_carrier(rx_channel, &carrier_cfg)); - TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); + TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config)); printf("send NEC frame with carrier\r\n"); TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { 0x0440, 0x3003 // address, command @@ -153,7 +157,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt TEST_ASSERT_EQUAL(34, test_user_data.received_symbol_num); #if SOC_RMT_SUPPORT_RX_PINGPONG - TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); + TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config)); printf("send customized frame with carrier\r\n"); TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { 0xFF00, 0xFF00, 0xFF00, 0xFF00 @@ -167,7 +171,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt TEST_ESP_OK(rmt_apply_carrier(rx_channel, NULL)); #endif // SOC_RMT_SUPPORT_RX_DEMODULATION - TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); + TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config)); printf("send NEC frame without carrier\r\n"); TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { 0x0440, 0x3003 // address, command @@ -183,6 +187,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt TEST_ESP_OK(rmt_del_channel(rx_channel)); TEST_ESP_OK(rmt_del_channel(tx_channel)); TEST_ESP_OK(rmt_del_encoder(nec_encoder)); + free(remote_codes); } TEST_CASE("rmt rx nec with carrier", "[rmt]") @@ -196,40 +201,3 @@ TEST_CASE("rmt rx nec with carrier", "[rmt]") test_rmt_rx_nec_carrier(128, true, RMT_CLK_SRC_DEFAULT); #endif } - -TEST_CASE("RMT RX test specifying interrupt priority", "[rmt]") -{ - rmt_clock_source_t clk_srcs[] = SOC_RMT_CLKS; - rmt_rx_channel_config_t rx_channel_cfg = { - .clk_src = clk_srcs[0], - .resolution_hz = 1000000, // 1MHz, 1 tick = 1us - .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, - .gpio_num = 0, - .flags.with_dma = false, // Interrupt will only be allocated when dma disabled - .flags.io_loop_back = true, // the GPIO will act like a loopback - .intr_priority = 3, - }; - // --- Check if specifying interrupt priority works - printf("install rx channel\r\n"); - rmt_channel_handle_t rx_channel = NULL; - TEST_ESP_OK(rmt_new_rx_channel(&rx_channel_cfg, &rx_channel)); - - rmt_channel_handle_t another_rx_channel = NULL; - rmt_rx_channel_config_t another_rx_channel_cfg = rx_channel_cfg; - // --- Check if rmt interrupt priority valid check works - another_rx_channel_cfg.intr_priority = 4; ///< Specifying a invalid intr_priority - TEST_ESP_ERR(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel), ESP_ERR_INVALID_ARG); - // --- Check if rmt interrupt priority conflict check works - another_rx_channel_cfg.intr_priority = 1; ///< Specifying a conflict intr_priority - TEST_ESP_ERR(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel), ESP_ERR_INVALID_ARG); - another_rx_channel_cfg.intr_priority = 0; ///< Do not specify an intr_priority, should not conflict - TEST_ESP_OK(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel)); - // --- Check if channel works - TEST_ESP_OK(rmt_enable(rx_channel)); - TEST_ESP_OK(rmt_enable(another_rx_channel)); - // --- Post-test - TEST_ESP_OK(rmt_disable(rx_channel)); - TEST_ESP_OK(rmt_disable(another_rx_channel)); - TEST_ESP_OK(rmt_del_channel(rx_channel)); - TEST_ESP_OK(rmt_del_channel(another_rx_channel)); -} diff --git a/components/driver/test_apps/rmt/main/test_rmt_tx.c b/components/driver/test_apps/rmt/main/test_rmt_tx.c index 03ede412af6..8da964f1c34 100644 --- a/components/driver/test_apps/rmt/main/test_rmt_tx.c +++ b/components/driver/test_apps/rmt/main/test_rmt_tx.c @@ -13,6 +13,7 @@ #include "esp_timer.h" #include "soc/soc_caps.h" #include "test_util_rmt_encoders.h" +#include "test_board.h" #if CONFIG_RMT_ISR_IRAM_SAFE #define TEST_RMT_CALLBACK_ATTR IRAM_ATTR @@ -27,7 +28,7 @@ TEST_CASE("rmt bytes encoder", "[rmt]") .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 1000000, // 1MHz, 1 tick = 1us .trans_queue_depth = 4, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .intr_priority = 3 }; printf("install tx channel\r\n"); @@ -89,7 +90,7 @@ static void test_rmt_channel_single_trans(size_t mem_block_symbols, bool with_dm .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .trans_queue_depth = 4, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .flags.with_dma = with_dma, .intr_priority = 2 }; @@ -144,7 +145,7 @@ static void test_rmt_ping_pong_trans(size_t mem_block_symbols, bool with_dma) .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .trans_queue_depth = 4, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .flags.with_dma = with_dma, .intr_priority = 1 }; @@ -215,7 +216,6 @@ TEST_CASE("rmt ping-pong transaction", "[rmt]") #endif } - TEST_RMT_CALLBACK_ATTR static bool test_rmt_tx_done_cb_check_event_data(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_data) { @@ -231,7 +231,7 @@ static void test_rmt_trans_done_event(size_t mem_block_symbols, bool with_dma) .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .trans_queue_depth = 1, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .flags.with_dma = with_dma, .intr_priority = 3 }; @@ -305,7 +305,7 @@ static void test_rmt_loop_trans(size_t mem_block_symbols, bool with_dma) .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .trans_queue_depth = 4, - .gpio_num = 0, + .gpio_num = TEST_RMT_GPIO_NUM_A, .flags.with_dma = with_dma, .intr_priority = 2 }; @@ -365,7 +365,7 @@ TEST_CASE("rmt infinite loop transaction", "[rmt]") .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 1000000, // 1MHz, 1 tick = 1us .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, - .gpio_num = 2, + .gpio_num = TEST_RMT_GPIO_NUM_B, .trans_queue_depth = 3, .intr_priority = 1 }; @@ -444,7 +444,7 @@ static void test_rmt_tx_nec_carrier(size_t mem_block_symbols, bool with_dma) .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 1000000, // 1MHz, 1 tick = 1us .mem_block_symbols = mem_block_symbols, - .gpio_num = 2, + .gpio_num = TEST_RMT_GPIO_NUM_B, .trans_queue_depth = 4, .flags.with_dma = with_dma, .intr_priority = 3 @@ -503,7 +503,6 @@ TEST_CASE("rmt tx nec with carrier", "[rmt]") #endif } - TEST_RMT_CALLBACK_ATTR static bool test_rmt_tx_done_cb_record_time(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_data) { @@ -526,7 +525,7 @@ static void test_rmt_multi_channels_trans(size_t channel0_mem_block_symbols, siz }; printf("install tx channels\r\n"); rmt_channel_handle_t tx_channels[TEST_RMT_CHANS] = {NULL}; - int gpio_nums[TEST_RMT_CHANS] = {0, 2}; + int gpio_nums[TEST_RMT_CHANS] = {TEST_RMT_GPIO_NUM_A, TEST_RMT_GPIO_NUM_B}; size_t mem_blk_syms[TEST_RMT_CHANS] = {channel0_mem_block_symbols, channel1_mem_block_symbols}; bool dma_flags[TEST_RMT_CHANS] = {channel0_with_dma, channel1_with_dma}; for (int i = 0; i < TEST_RMT_CHANS; i++) { @@ -655,38 +654,3 @@ TEST_CASE("rmt multiple channels transaction", "[rmt]") test_rmt_multi_channels_trans(1024, SOC_RMT_MEM_WORDS_PER_CHANNEL, true, false); #endif } - -TEST_CASE("RMT TX test specifying interrupt priority", "[rmt]") -{ - rmt_tx_channel_config_t tx_channel_cfg = { - .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, - .clk_src = RMT_CLK_SRC_DEFAULT, - .resolution_hz = 1000000, // 1MHz, 1 tick = 1us - .trans_queue_depth = 4, - .gpio_num = 0, - .intr_priority = 3 - }; - // --- Check if specifying interrupt priority works - printf("install tx channel\r\n"); - rmt_channel_handle_t tx_channel = NULL; - TEST_ESP_OK(rmt_new_tx_channel(&tx_channel_cfg, &tx_channel)); - - rmt_channel_handle_t another_tx_channel = NULL; - rmt_tx_channel_config_t another_tx_channel_cfg = tx_channel_cfg; - // --- Check if rmt interrupt priority valid check works - another_tx_channel_cfg.intr_priority = 4; - TEST_ESP_ERR(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel), ESP_ERR_INVALID_ARG); - // --- Check if rmt interrupt priority conflict check works - another_tx_channel_cfg.intr_priority = 1; ///< Specifying a conflict intr_priority - TEST_ESP_ERR(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel), ESP_ERR_INVALID_ARG); - another_tx_channel_cfg.intr_priority = 0; ///< Do not specify an intr_priority, should not conflict - TEST_ESP_OK(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel)); - // --- Check if channel works - TEST_ESP_OK(rmt_enable(tx_channel)); - TEST_ESP_OK(rmt_enable(another_tx_channel)); - // --- Post-test - TEST_ESP_OK(rmt_disable(tx_channel)); - TEST_ESP_OK(rmt_disable(another_tx_channel)); - TEST_ESP_OK(rmt_del_channel(tx_channel)); - TEST_ESP_OK(rmt_del_channel(another_tx_channel)); -} diff --git a/components/driver/test_apps/rmt/main/test_util_rmt_encoders.c b/components/driver/test_apps/rmt/main/test_util_rmt_encoders.c index 5cfadd4097d..6c95e5d6317 100644 --- a/components/driver/test_apps/rmt/main/test_util_rmt_encoders.c +++ b/components/driver/test_apps/rmt/main/test_util_rmt_encoders.c @@ -11,12 +11,6 @@ #include "driver/rmt_encoder.h" #include "esp_attr.h" -#if CONFIG_RMT_ISR_IRAM_SAFE -#define TEST_RMT_ENCODER_ATTR IRAM_ATTR -#else -#define TEST_RMT_ENCODER_ATTR -#endif - typedef struct { rmt_encoder_t base; rmt_encoder_t *bytes_encoder; @@ -25,8 +19,7 @@ typedef struct { rmt_symbol_word_t reset_code; } rmt_led_strip_encoder_t; -TEST_RMT_ENCODER_ATTR -static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) +IRAM_ATTR static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) { rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); rmt_encode_state_t session_state = RMT_ENCODING_RESET; @@ -119,7 +112,7 @@ typedef struct { int state; } rmt_nec_protocol_encoder_t; -static size_t rmt_encode_nec_protocol(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) +IRAM_ATTR static size_t rmt_encode_nec_protocol(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) { rmt_nec_protocol_encoder_t *nec_encoder = __containerof(encoder, rmt_nec_protocol_encoder_t, base); rmt_encode_state_t session_state = RMT_ENCODING_RESET; diff --git a/components/esp_hw_support/dma/async_memcpy_gdma.c b/components/esp_hw_support/dma/async_memcpy_gdma.c index 2538ece16c9..a19f61cefba 100644 --- a/components/esp_hw_support/dma/async_memcpy_gdma.c +++ b/components/esp_hw_support/dma/async_memcpy_gdma.c @@ -447,11 +447,11 @@ static bool mcp_gdma_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_ if (atomic_compare_exchange_strong(&mcp_gdma->fsm, &expected_fsm, MCP_FSM_IDLE_WAIT)) { // if the data is in the cache, invalidate, then CPU can see the latest data #if MCP_NEEDS_INVALIDATE_DST_CACHE - int write_back_map = CACHE_MAP_L1_DCACHE; + int invalidate_map = CACHE_MAP_L1_DCACHE; if (esp_ptr_external_ram((const void *)trans->memcpy_dst_addr)) { - write_back_map |= CACHE_MAP_L2_CACHE; + invalidate_map |= CACHE_MAP_L2_CACHE; } - Cache_Invalidate_Addr(write_back_map, (uint32_t)trans->memcpy_dst_addr, trans->memcpy_size); + Cache_Invalidate_Addr(invalidate_map, (uint32_t)trans->memcpy_dst_addr, trans->memcpy_size); #endif // invoked callback registered by user diff --git a/components/hal/esp32/include/hal/rmt_ll.h b/components/hal/esp32/include/hal/rmt_ll.h index 68de11d8d1c..c410ffc16f1 100644 --- a/components/hal/esp32/include/hal/rmt_ll.h +++ b/components/hal/esp32/include/hal/rmt_ll.h @@ -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 */ @@ -16,6 +16,7 @@ #include "hal/misc.h" #include "hal/assert.h" #include "soc/rmt_struct.h" +#include "soc/dport_reg.h" #include "hal/rmt_types.h" #ifdef __cplusplus @@ -40,6 +41,41 @@ typedef enum { RMT_LL_MEM_OWNER_HW = 1, } rmt_ll_mem_owner_t; +/** + * @brief Enable the bus clock for RMT module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void rmt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + uint32_t reg_val = DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); + reg_val &= ~DPORT_RMT_CLK_EN; + reg_val |= enable << 9; + DPORT_WRITE_PERI_REG(DPORT_PERIP_CLK_EN_REG, reg_val); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the RMT module + * + * @param group_id Group ID + */ +static inline void rmt_ll_reset_register(int group_id) +{ + (void)group_id; + DPORT_WRITE_PERI_REG(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST); + DPORT_WRITE_PERI_REG(DPORT_PERIP_RST_EN_REG, 0); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__) + /** * @brief Enable clock gate for register and memory * diff --git a/components/hal/esp32c3/include/hal/rmt_ll.h b/components/hal/esp32c3/include/hal/rmt_ll.h index 1c3c4c907f6..e70a0bf4353 100644 --- a/components/hal/esp32c3/include/hal/rmt_ll.h +++ b/components/hal/esp32c3/include/hal/rmt_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,7 @@ #include "hal/misc.h" #include "hal/assert.h" #include "soc/rmt_struct.h" +#include "soc/system_struct.h" #include "hal/rmt_types.h" #ifdef __cplusplus @@ -41,6 +42,38 @@ typedef enum { RMT_LL_MEM_OWNER_HW = 1, } rmt_ll_mem_owner_t; +/** + * @brief Enable the bus clock for RMT module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void rmt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + SYSTEM.perip_clk_en0.reg_rmt_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the RMT module + * + * @param group_id Group ID + */ +static inline void rmt_ll_reset_register(int group_id) +{ + (void)group_id; + SYSTEM.perip_rst_en0.reg_rmt_rst = 1; + SYSTEM.perip_rst_en0.reg_rmt_rst = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__) + /** * @brief Enable clock gate for register and memory * diff --git a/components/hal/esp32c6/include/hal/rmt_ll.h b/components/hal/esp32c6/include/hal/rmt_ll.h index 7f7f24f9be3..9db5a5109c2 100644 --- a/components/hal/esp32c6/include/hal/rmt_ll.h +++ b/components/hal/esp32c6/include/hal/rmt_ll.h @@ -42,6 +42,30 @@ typedef enum { RMT_LL_MEM_OWNER_HW = 1, } rmt_ll_mem_owner_t; +/** + * @brief Enable the bus clock for RMT module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void rmt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.rmt_conf.rmt_clk_en = enable; +} + +/** + * @brief Reset the RMT module + * + * @param group_id Group ID + */ +static inline void rmt_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.rmt_conf.rmt_rst_en = 1; + PCR.rmt_conf.rmt_rst_en = 0; +} + /** * @brief Enable clock gate for register and memory * diff --git a/components/hal/esp32h2/include/hal/rmt_ll.h b/components/hal/esp32h2/include/hal/rmt_ll.h index d290163f597..bc7b29ed40c 100644 --- a/components/hal/esp32h2/include/hal/rmt_ll.h +++ b/components/hal/esp32h2/include/hal/rmt_ll.h @@ -42,6 +42,30 @@ typedef enum { RMT_LL_MEM_OWNER_HW = 1, } rmt_ll_mem_owner_t; +/** + * @brief Enable the bus clock for RMT module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void rmt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.rmt_conf.rmt_clk_en = enable; +} + +/** + * @brief Reset the RMT module + * + * @param group_id Group ID + */ +static inline void rmt_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.rmt_conf.rmt_rst_en = 1; + PCR.rmt_conf.rmt_rst_en = 0; +} + /** * @brief Enable clock gate for register and memory * diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index b33031bedb5..566a112b400 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -76,8 +76,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return HP_SYS_CLKRST_REG_SYSTIMER_CLK_EN; case PERIPH_LEDC_MODULE: return HP_SYS_CLKRST_REG_LEDC_CLK_EN; - case PERIPH_RMT_MODULE: - return HP_SYS_CLKRST_REG_RMT_CLK_EN; case PERIPH_SARADC_MODULE: return HP_SYS_CLKRST_REG_ADC_CLK_EN; case PERIPH_PVT_MODULE: @@ -147,8 +145,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en return HP_SYS_CLKRST_REG_RST_EN_I2C0; case PERIPH_I2C1_MODULE: return HP_SYS_CLKRST_REG_RST_EN_I2C1; - case PERIPH_RMT_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_RMT; case PERIPH_TWAI0_MODULE: return HP_SYS_CLKRST_REG_RST_EN_CAN0; case PERIPH_TWAI1_MODULE: @@ -253,7 +249,6 @@ static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph) return HP_SYS_CLKRST_PERI_CLK_CTRL119_REG; case PERIPH_SYSTIMER_MODULE: case PERIPH_LEDC_MODULE: - case PERIPH_RMT_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL21_REG; case PERIPH_SARADC_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL22_REG; @@ -299,7 +294,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) case PERIPH_I2C0_MODULE: case PERIPH_I2C1_MODULE: return HP_SYS_CLKRST_HP_RST_EN1_REG; - case PERIPH_RMT_MODULE: case PERIPH_TWAI0_MODULE: case PERIPH_TWAI1_MODULE: case PERIPH_TWAI2_MODULE: diff --git a/components/hal/esp32p4/include/hal/rmt_ll.h b/components/hal/esp32p4/include/hal/rmt_ll.h new file mode 100644 index 00000000000..46667223f9b --- /dev/null +++ b/components/hal/esp32p4/include/hal/rmt_ll.h @@ -0,0 +1,923 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @note TX and RX channels are index from 0 in the LL driver, i.e. tx_channel = [0,3], rx_channel = [0,3] + */ + +#pragma once + +#include +#include +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "hal/rmt_types.h" +#include "soc/rmt_struct.h" +#include "soc/hp_sys_clkrst_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RMT_LL_EVENT_TX_DONE(channel) (1 << (channel)) +#define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 8)) +#define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 12)) +#define RMT_LL_EVENT_TX_ERROR(channel) (1 << ((channel) + 4)) +#define RMT_LL_EVENT_RX_DONE(channel) (1 << ((channel) + 16)) +#define RMT_LL_EVENT_RX_THRES(channel) (1 << ((channel) + 24)) +#define RMT_LL_EVENT_RX_ERROR(channel) (1 << ((channel) + 20)) +#define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel)) +#define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel)) + +#define RMT_LL_MAX_LOOP_COUNT_PER_BATCH 1023 +#define RMT_LL_MAX_FILTER_VALUE 255 +#define RMT_LL_MAX_IDLE_VALUE 32767 + +typedef enum { + RMT_LL_MEM_OWNER_SW = 0, + RMT_LL_MEM_OWNER_HW = 1, +} rmt_ll_mem_owner_t; + +/** + * @brief Enable the bus clock for RMT module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void rmt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + HP_SYS_CLKRST.soc_clk_ctrl2.reg_rmt_sys_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the RMT module + * + * @param group_id Group ID + */ +static inline void rmt_ll_reset_register(int group_id) +{ + (void)group_id; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_rmt = 1; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_rmt = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__) + +/** + * @brief Set clock source and divider for RMT channel group + * + * @param dev Peripheral instance address + * @param channel not used as clock source is set for all channels + * @param src Clock source + * @param divider_integral Integral part of the divider + * @param divider_denominator Denominator part of the divider + * @param divider_numerator Numerator part of the divider + */ +static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) +{ + (void)dev; + // Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b) + (void)channel; // the source clock is set for all channels + HAL_ASSERT(divider_integral >= 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl22, reg_rmt_clk_div_num, divider_integral - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl22, reg_rmt_clk_div_numerator, divider_numerator); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl22, reg_rmt_clk_div_denominator, divider_denominator); + switch (src) { + case RMT_CLK_SRC_PLL_F80M: + HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_src_sel = 2; + break; + case RMT_CLK_SRC_RC_FAST: + HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_src_sel = 1; + break; + case RMT_CLK_SRC_XTAL: + HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_src_sel = 0; + break; + default: + HAL_ASSERT(false && "unsupported RMT clock source"); + break; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_set_group_clock_src(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_set_group_clock_src(__VA_ARGS__) + +/** + * @brief Enable RMT peripheral source clock + * + * @param dev Peripheral instance address + * @param en True to enable, False to disable + */ +static inline void rmt_ll_enable_group_clock(rmt_dev_t *dev, bool en) +{ + (void)dev; + HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_en = en; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_enable_group_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_group_clock(__VA_ARGS__) + +/** + * @brief Enable clock gate for register and memory + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) +{ + dev->sys_conf.clk_en = enable; // register clock gating + dev->sys_conf.mem_clk_force_on = enable; // memory clock gating +} + +/** + * @brief Power down memory + * + * @param dev Peripheral instance address + * @param enable True to power down, False to power up + */ +static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +{ + dev->sys_conf.mem_force_pu = !enable; + dev->sys_conf.mem_force_pd = enable; +} + +/** + * @brief Enable APB accessing RMT memory in nonfifo mode + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) +{ + dev->sys_conf.apb_fifo_mask = enable; +} + +////////////////////////////////////////TX Channel Specific///////////////////////////////////////////////////////////// + +/** + * @brief Reset clock divider for TX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels + */ +static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) +{ + // write 1 to reset + dev->ref_cnt_rst.val |= channel_mask & 0x0F; +} + +/** + * @brief Set TX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param div Division value + */ +static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +{ + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chnconf0[channel], div_cnt_chn, div); +} + +/** + * @brief Reset RMT reading pointer for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) +{ + dev->chnconf0[channel].mem_rd_rst_chn = 1; + dev->chnconf0[channel].mem_rd_rst_chn = 0; + dev->chnconf0[channel].apb_mem_rst_chn = 1; + dev->chnconf0[channel].apb_mem_rst_chn = 0; +} + +/** + * @brief Enable DMA access for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_dma(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + HAL_ASSERT(channel == 3 && "only TX channel 3 has DMA ability"); + dev->chnconf0[channel].dma_access_en_chn = enable; +} + +/** + * @brief Start transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) +{ + // update other configuration registers before start transmitting + dev->chnconf0[channel].conf_update_chn = 1; + dev->chnconf0[channel].tx_start_chn = 1; +} + +/** + * @brief Stop transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) +{ + dev->chnconf0[channel].tx_stop_chn = 1; + // stop won't take place until configurations updated + dev->chnconf0[channel].conf_update_chn = 1; +} + +/** + * @brief Set memory block number for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param block_num memory block number + */ +static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) +{ + dev->chnconf0[channel].mem_size_chn = block_num; +} + +/** + * @brief Enable TX wrap + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chnconf0[channel].mem_tx_wrap_en_chn = enable; +} + +/** + * @brief Enable transmitting in a loop + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chnconf0[channel].tx_conti_mode_chn = enable; +} + +/** + * @brief Set loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param count TX loop count + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) +{ + HAL_ASSERT(count <= RMT_LL_MAX_LOOP_COUNT_PER_BATCH && "loop count out of range"); + dev->chn_tx_lim[channel].tx_loop_num_chn = count; +} + +/** + * @brief Reset loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_reset_loop_count(rmt_dev_t *dev, uint32_t channel) +{ + dev->chn_tx_lim[channel].loop_count_reset_chn = 1; + dev->chn_tx_lim[channel].loop_count_reset_chn = 0; +} + +/** + * @brief Enable loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chn_tx_lim[channel].tx_loop_cnt_en_chn = enable; +} + +/** + * @brief Enable loop stop at count value automatically + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_enable_loop_autostop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chn_tx_lim[channel].loop_stop_en_chn = enable; +} + +/** + * @brief Enable transmit multiple channels synchronously + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) +{ + dev->tx_sim.tx_sim_en = enable; +} + +/** + * @brief Clear the TX channels synchronous group + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_tx_clear_sync_group(rmt_dev_t *dev) +{ + dev->tx_sim.val &= ~(0x0F); +} + +/** + * @brief Add TX channels to the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be added to the synchronous group + */ +static inline void rmt_ll_tx_sync_group_add_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val |= (channel_mask & 0x0F); +} + +/** + * @brief Remove TX channels from the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be removed from the synchronous group + */ +static inline void rmt_ll_tx_sync_group_remove_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val &= ~channel_mask; +} + +/** + * @brief Fix the output level when TX channel is in IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level IDLE level (1 => high, 0 => low) + * @param enable True to fix the IDLE level, otherwise the IDLE level is determined by EOF encoder + */ +__attribute__((always_inline)) +static inline void rmt_ll_tx_fix_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level, bool enable) +{ + dev->chnconf0[channel].idle_out_en_chn = enable; + dev->chnconf0[channel].idle_out_lv_chn = level; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->chn_tx_lim[channel].tx_lim_chn = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + // ticks=0 means 65536 in hardware + if (high_ticks >= 65536) { + high_ticks = 0; + } + if (low_ticks >= 65536) { + low_ticks = 0; + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chncarrier_duty[channel], carrier_high_chn, high_ticks); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chncarrier_duty[channel], carrier_low_chn, low_ticks); +} + +/** + * @brief Enable modulating carrier signal to TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chnconf0[channel].carrier_en_chn = enable; +} + +/** + * @brief Set on high or low to modulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level Which level to modulate on (0=>low level, 1=>high level) + */ +static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->chnconf0[channel].carrier_out_lv_chn = level; +} + +/** + * @brief Enable to always output carrier signal, regardless of a valid data transmission + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + */ +static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chnconf0[channel].carrier_eff_en_chn = !enable; +} + +////////////////////////////////////////RX Channel Specific///////////////////////////////////////////////////////////// + +/** + * @brief Reset clock divider for RX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of RX channels + */ +static inline void rmt_ll_rx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->ref_cnt_rst.val |= ((channel_mask & 0x0F) << 4); +} + +/** + * @brief Set RX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param div Division value + */ +static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +{ + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf0, div_cnt_chm, div); +} + +/** + * @brief Reset RMT writing pointer for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + */ +static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) +{ + dev->chmconf[channel].conf1.mem_wr_rst_chm = 1; + dev->chmconf[channel].conf1.mem_wr_rst_chm = 0; + dev->chmconf[channel].conf1.apb_mem_rst_chm = 1; + dev->chmconf[channel].conf1.apb_mem_rst_chm = 0; +} + +/** + * @brief Enable DMA access for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_dma(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + HAL_ASSERT(channel == 3 && "only RX channel 3 has DMA ability"); + dev->chmconf[channel].conf0.dma_access_en_chm = enable; +} + +/** + * @brief Enable receiving for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +__attribute__((always_inline)) +static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chmconf[channel].conf1.rx_en_chm = enable; + // rx won't be enabled until configurations updated + dev->chmconf[channel].conf1.conf_update_chm = 1; +} + +/** + * @brief Set memory block number for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param block_num memory block number + */ +static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) +{ + dev->chmconf[channel].conf0.mem_size_chm = block_num; +} + +/** + * @brief Set the time length for RX channel before going into IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Time length threshold + */ +static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + dev->chmconf[channel].conf0.idle_thres_chm = thres; +} + +/** + * @brief Set RMT memory owner for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param owner Memory owner + */ +__attribute__((always_inline)) +static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt_ll_mem_owner_t owner) +{ + dev->chmconf[channel].conf1.mem_owner_chm = owner; +} + +/** + * @brief Enable filter for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX chanenl number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chmconf[channel].conf1.rx_filter_en_chm = enable; +} + +/** + * @brief Set RX channel filter threshold (i.e. the maximum width of one pulse signal that would be treated as a noise) + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Filter threshold + */ +static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf1, rx_filter_thres_chm, thres); +} + +/** + * @brief Get RMT memory write cursor offset + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return writer offset + */ +__attribute__((always_inline)) +static inline uint32_t rmt_ll_rx_get_memory_writer_offset(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chmstatus[channel].mem_waddr_ex_chm - (channel + 4) * 48; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->chm_rx_lim[channel].rx_lim_chm = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chm_rx_carrier_rm[channel], carrier_high_thres_chm, high_ticks - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chm_rx_carrier_rm[channel], carrier_low_thres_chm, low_ticks - 1); +} + +/** + * @brief Enable demodulating the carrier on RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chmconf[channel].conf0.carrier_en_chm = enable; +} + +/** + * @brief Set on high or low to demodulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param level Which level to demodulate (0=>low level, 1=>high level) + */ +static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->chmconf[channel].conf0.carrier_out_lv_chm = level; +} + +/** + * @brief Enable RX wrap + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chmconf[channel].conf1.mem_rx_wrap_en_chm = enable; +} + +//////////////////////////////////////////Interrupt Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable RMT interrupt for specific event mask + * + * @param dev Peripheral instance address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +__attribute__((always_inline)) +static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +/** + * @brief Clear RMT interrupt status by mask + * + * @param dev Peripheral instance address + * @param mask Interupt status mask + */ +__attribute__((always_inline)) +static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) +{ + dev->int_clr.val = mask; +} + +/** + * @brief Get interrupt status register address + * + * @param dev Peripheral instance address + * @return Register address + */ +static inline volatile void *rmt_ll_get_interrupt_status_reg(rmt_dev_t *dev) +{ + return &dev->int_st; +} + +/** + * @brief Get interrupt status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt status + */ +__attribute__((always_inline)) +static inline uint32_t rmt_ll_tx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt raw status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt raw status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_raw.val & (RMT_LL_EVENT_TX_MASK(channel) | RMT_LL_EVENT_TX_ERROR(channel)); +} + +/** + * @brief Get interrupt raw status for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return Interrupt raw status + */ +static inline uint32_t rmt_ll_rx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_raw.val & (RMT_LL_EVENT_RX_MASK(channel) | RMT_LL_EVENT_RX_ERROR(channel)); +} + +/** + * @brief Get interrupt status for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return Interrupt status + */ +__attribute__((always_inline)) +static inline uint32_t rmt_ll_rx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_RX_MASK(channel); +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_tx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chnstatus[channel].val; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_rx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chmstatus[channel].val; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +{ + uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->chnconf0[channel], div_cnt_chn); + return div == 0 ? 256 : div; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +{ + uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->chmconf[channel].conf0, div_cnt_chm); + return div == 0 ? 256 : div; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chmconf[channel].conf0.idle_thres_chm; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chnconf0[channel].mem_size_chn; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chmconf[channel].conf0.mem_size_chm; +} + +__attribute__((always_inline)) +static inline bool rmt_ll_tx_is_loop_enabled(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chnconf0[channel].tx_conti_mode_chn; +} + +__attribute__((always_inline)) +static inline rmt_clock_source_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) +{ + rmt_clock_source_t clk_src = RMT_CLK_SRC_PLL_F80M; + switch (HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_src_sel) { + case 0: + clk_src = RMT_CLK_SRC_XTAL; + break; + case 1: + clk_src = RMT_CLK_SRC_RC_FAST; + break; + case 2: + clk_src = RMT_CLK_SRC_PLL_F80M; + break; + } + return clk_src; +} + +__attribute__((always_inline)) +static inline bool rmt_ll_tx_is_idle_enabled(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chnconf0[channel].idle_out_en_chn; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chnconf0[channel].idle_out_lv_chn; +} + +static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +{ + // the RTC domain can also power down RMT memory + // so it's probably not enough to detect whether it's powered down or not + // mem_force_pd has higher priority than mem_force_pu + return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chmconf[channel].conf1.mem_owner_chm; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chm_rx_lim[channel].rx_lim_chm; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev) +{ + return dev->int_st.val & 0x0F; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_get_rx_end_interrupt_status(rmt_dev_t *dev) +{ + return (dev->int_st.val >> 16) & 0x0F; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_get_tx_err_interrupt_status(rmt_dev_t *dev) +{ + return (dev->int_st.val >> 4) & 0x0F; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_get_rx_err_interrupt_status(rmt_dev_t *dev) +{ + return (dev->int_st.val >> 20) & 0x0F; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev) +{ + return (dev->int_st.val >> 8) & 0x0F; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_get_rx_thres_interrupt_status(rmt_dev_t *dev) +{ + return (dev->int_st.val >> 24) & 0x0F; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_get_tx_loop_interrupt_status(rmt_dev_t *dev) +{ + return (dev->int_st.val >> 12) & 0x0F; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s2/include/hal/rmt_ll.h b/components/hal/esp32s2/include/hal/rmt_ll.h index fe8028802c0..e20f6de9579 100644 --- a/components/hal/esp32s2/include/hal/rmt_ll.h +++ b/components/hal/esp32s2/include/hal/rmt_ll.h @@ -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 */ @@ -16,13 +16,13 @@ #include "hal/misc.h" #include "hal/assert.h" #include "soc/rmt_struct.h" +#include "soc/system_reg.h" #include "hal/rmt_types.h" #ifdef __cplusplus extern "C" { #endif - #define RMT_LL_EVENT_TX_DONE(channel) (1 << ((channel) * 3)) #define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 12)) #define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 16)) @@ -42,6 +42,41 @@ typedef enum { RMT_LL_MEM_OWNER_HW = 1, } rmt_ll_mem_owner_t; +/** + * @brief Enable the bus clock for RMT module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void rmt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + uint32_t reg_val = READ_PERI_REG(DPORT_PERIP_CLK_EN0_REG); + reg_val &= ~DPORT_RMT_CLK_EN_M; + reg_val |= enable << DPORT_RMT_CLK_EN_S; + WRITE_PERI_REG(DPORT_PERIP_CLK_EN0_REG, reg_val); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the RMT module + * + * @param group_id Group ID + */ +static inline void rmt_ll_reset_register(int group_id) +{ + (void)group_id; + WRITE_PERI_REG(DPORT_PERIP_RST_EN0_REG, DPORT_RMT_RST_M); + WRITE_PERI_REG(DPORT_PERIP_RST_EN0_REG, 0); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__) + /** * @brief Enable clock gate for register and memory * diff --git a/components/hal/esp32s3/include/hal/rmt_ll.h b/components/hal/esp32s3/include/hal/rmt_ll.h index 70812539f09..223f24dc5e8 100644 --- a/components/hal/esp32s3/include/hal/rmt_ll.h +++ b/components/hal/esp32s3/include/hal/rmt_ll.h @@ -16,6 +16,7 @@ #include "hal/misc.h" #include "hal/assert.h" #include "soc/rmt_struct.h" +#include "soc/system_struct.h" #include "hal/rmt_types.h" #ifdef __cplusplus @@ -41,6 +42,38 @@ typedef enum { RMT_LL_MEM_OWNER_HW = 1, } rmt_ll_mem_owner_t; +/** + * @brief Enable the bus clock for RMT module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void rmt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + SYSTEM.perip_clk_en0.rmt_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the RMT module + * + * @param group_id Group ID + */ +static inline void rmt_ll_reset_register(int group_id) +{ + (void)group_id; + SYSTEM.perip_rst_en0.rmt_rst = 1; + SYSTEM.perip_rst_en0.rmt_rst = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__) + /** * @brief Enable clock gate for register and memory * diff --git a/components/hal/rmt_hal.c b/components/hal/rmt_hal.c index c14c8501cce..d83e5952dac 100644 --- a/components/hal/rmt_hal.c +++ b/components/hal/rmt_hal.c @@ -14,7 +14,6 @@ void rmt_hal_init(rmt_hal_context_t *hal) rmt_ll_enable_mem_access_nonfifo(hal->regs, true); // APB access the RMTMEM in nonfifo mode rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events - rmt_ll_enable_group_clock(hal->regs, true); // enable clock source #if SOC_RMT_SUPPORT_TX_SYNCHRO rmt_ll_tx_clear_sync_group(hal->regs); #endif // SOC_RMT_SUPPORT_TX_SYNCHRO @@ -25,7 +24,6 @@ void rmt_hal_deinit(rmt_hal_context_t *hal) rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events rmt_ll_power_down_mem(hal->regs, true); // turn off RMTMEM power domain - rmt_ll_enable_group_clock(hal->regs, false); // disable clock source hal->regs = NULL; } diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index f31edf192f3..428c5f571c4 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -55,6 +55,10 @@ config SOC_RTC_MEM_SUPPORTED bool default y +config SOC_RMT_SUPPORTED + bool + default y + config SOC_I2C_SUPPORTED bool default y @@ -489,15 +493,15 @@ config SOC_RMT_GROUPS config SOC_RMT_TX_CANDIDATES_PER_GROUP int - default 2 + default 4 config SOC_RMT_RX_CANDIDATES_PER_GROUP int - default 2 + default 4 config SOC_RMT_CHANNELS_PER_GROUP int - default 4 + default 8 config SOC_RMT_MEM_WORDS_PER_CHANNEL int @@ -515,6 +519,14 @@ config SOC_RMT_SUPPORT_TX_ASYNC_STOP bool default y +config SOC_RMT_SUPPORT_TX_LOOP_COUNT + bool + default y + +config SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP + bool + default y + config SOC_RMT_SUPPORT_TX_SYNCHRO bool default y @@ -527,7 +539,7 @@ config SOC_RMT_SUPPORT_XTAL bool default y -config SOC_RMT_SUPPORT_RC_FAST +config SOC_RMT_SUPPORT_DMA bool default y diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 25e71bf90ee..8e3e34bc9c3 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -213,6 +213,42 @@ typedef enum { //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// +/** + * @brief Array initializer for all supported clock sources of RMT + */ +#if SOC_CLK_TREE_SUPPORTED +#define SOC_RMT_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} +#else +#define SOC_RMT_CLKS {SOC_MOD_CLK_XTAL} +#endif + +/** + * @brief Type of RMT clock source + */ +typedef enum { + RMT_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ + RMT_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + RMT_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ +#if SOC_CLK_TREE_SUPPORTED + RMT_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ +#else + RMT_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default choice */ +#endif +} soc_periph_rmt_clk_src_t; + +/** + * @brief Type of RMT clock source, reserved for the legacy RMT driver + */ +typedef enum { + RMT_BASECLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock is PLL_F80M */ + RMT_BASECLK_XTAL = SOC_MOD_CLK_XTAL, /*!< RMT source clock is XTAL */ +#if SOC_CLK_TREE_SUPPORTED + RMT_BASECLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock default choice is PLL_F80M */ +#else + RMT_BASECLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< RMT source clock default choice is XTAL */ +#endif +} soc_periph_rmt_clk_src_legacy_t; + //////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32p4/include/soc/rmt_struct.h b/components/soc/esp32p4/include/soc/rmt_struct.h index d64239ae588..efe4281c3bb 100644 --- a/components/soc/esp32p4/include/soc/rmt_struct.h +++ b/components/soc/esp32p4/include/soc/rmt_struct.h @@ -1,11 +1,12 @@ /** * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * - * SPDX-License-Identifier: Apache-2.0 + * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include + #ifdef __cplusplus extern "C" { #endif @@ -16,10 +17,10 @@ extern "C" { */ typedef union { struct { - /** chndata : HRO; bitpos: [31:0]; default: 0; + /** chndata : RO; bitpos: [31:0]; default: 0; * Read and write data for channel n via APB FIFO. */ - uint32_t chndata:32; + uint32_t chndata: 32; }; uint32_t val; } rmt_chndata_reg_t; @@ -29,86 +30,93 @@ typedef union { */ typedef union { struct { - /** chmdata : HRO; bitpos: [31:0]; default: 0; + /** chmdata : RO; bitpos: [31:0]; default: 0; * Read and write data for channel $n via APB FIFO. */ - uint32_t chmdata:32; + uint32_t chmdata: 32; }; uint32_t val; } rmt_chmdata_reg_t; - /** Group: Configuration registers */ /** Type of chnconf0 register * Channel n configure register 0 */ typedef union { struct { - /** tx_start_ch0 : WT; bitpos: [0]; default: 0; + /** tx_start_chn : WT; bitpos: [0]; default: 0; * Set this bit to start sending data on CHANNELn. */ - uint32_t tx_start_ch0:1; - /** mem_rd_rst_ch0 : WT; bitpos: [1]; default: 0; + uint32_t tx_start_chn: 1; + /** mem_rd_rst_chn : WT; bitpos: [1]; default: 0; * Set this bit to reset read ram address for CHANNELn by accessing transmitter. */ - uint32_t mem_rd_rst_ch0:1; - /** apb_mem_rst_ch0 : WT; bitpos: [2]; default: 0; + uint32_t mem_rd_rst_chn: 1; + /** apb_mem_rst_chn : WT; bitpos: [2]; default: 0; * Set this bit to reset W/R ram address for CHANNELn by accessing apb fifo. */ - uint32_t apb_mem_rst_ch0:1; - /** tx_conti_mode_ch0 : R/W; bitpos: [3]; default: 0; + uint32_t apb_mem_rst_chn: 1; + /** tx_conti_mode_chn : R/W; bitpos: [3]; default: 0; * Set this bit to restart transmission from the first data to the last data in * CHANNELn. */ - uint32_t tx_conti_mode_ch0:1; - /** mem_tx_wrap_en_ch0 : R/W; bitpos: [4]; default: 0; + uint32_t tx_conti_mode_chn: 1; + /** mem_tx_wrap_en_chn : R/W; bitpos: [4]; default: 0; * This is the channel n enable bit for wraparound mode: it will resume sending at the * start when the data to be sent is more than its memory size. */ - uint32_t mem_tx_wrap_en_ch0:1; - /** idle_out_lv_ch0 : R/W; bitpos: [5]; default: 0; + uint32_t mem_tx_wrap_en_chn: 1; + /** idle_out_lv_chn : R/W; bitpos: [5]; default: 0; * This bit configures the level of output signal in CHANNELn when the latter is in * IDLE state. */ - uint32_t idle_out_lv_ch0:1; - /** idle_out_en_ch0 : R/W; bitpos: [6]; default: 0; + uint32_t idle_out_lv_chn: 1; + /** idle_out_en_chn : R/W; bitpos: [6]; default: 0; * This is the output enable-control bit for CHANNELn in IDLE state. */ - uint32_t idle_out_en_ch0:1; - /** tx_stop_ch0 : R/W/SC; bitpos: [7]; default: 0; + uint32_t idle_out_en_chn: 1; + /** tx_stop_chn : R/W/SC; bitpos: [7]; default: 0; * Set this bit to stop the transmitter of CHANNELn sending data out. */ - uint32_t tx_stop_ch0:1; - /** div_cnt_ch0 : R/W; bitpos: [15:8]; default: 2; + uint32_t tx_stop_chn: 1; + /** div_cnt_chn : R/W; bitpos: [15:8]; default: 2; * This register is used to configure the divider for clock of CHANNELn. */ - uint32_t div_cnt_ch0:8; - /** mem_size_ch0 : R/W; bitpos: [19:16]; default: 1; + uint32_t div_cnt_chn: 8; + /** mem_size_chn : R/W; bitpos: [19:16]; default: 1; * This register is used to configure the maximum size of memory allocated to CHANNELn. */ - uint32_t mem_size_ch0:4; - /** carrier_eff_en_ch0 : R/W; bitpos: [20]; default: 1; + uint32_t mem_size_chn: 4; + /** carrier_eff_en_chn : R/W; bitpos: [20]; default: 1; * 1: Add carrier modulation on the output signal only at the send data state for * CHANNELn. 0: Add carrier modulation on the output signal at all state for CHANNELn. * Only valid when RMT_CARRIER_EN_CHn is 1. */ - uint32_t carrier_eff_en_ch0:1; - /** carrier_en_ch0 : R/W; bitpos: [21]; default: 1; + uint32_t carrier_eff_en_chn: 1; + /** carrier_en_chn : R/W; bitpos: [21]; default: 1; * This is the carrier modulation enable-control bit for CHANNELn. 1: Add carrier * modulation in the output signal. 0: No carrier modulation in sig_out. */ - uint32_t carrier_en_ch0:1; - /** carrier_out_lv_ch0 : R/W; bitpos: [22]; default: 1; - * This bit is used to configure the position of carrier wave for CHANNELn.1'h0: add - * carrier wave on low level.1'h1: add carrier wave on high level. + uint32_t carrier_en_chn: 1; + /** carrier_out_lv_chn : R/W; bitpos: [22]; default: 1; + * This bit is used to configure the position of carrier wave for CHANNELn. + * 1'h0: add carrier wave on low level. + * 1'h1: add carrier wave on high level. */ - uint32_t carrier_out_lv_ch0:1; - uint32_t reserved_23:1; - /** conf_update_ch0 : WT; bitpos: [24]; default: 0; + uint32_t carrier_out_lv_chn: 1; + /** afifo_rst_chn : WT; bitpos: [23]; default: 0; + * Reserved + */ + uint32_t afifo_rst_chn: 1; + /** conf_update_chn : WT; bitpos: [24]; default: 0; * synchronization bit for CHANNELn */ - uint32_t conf_update_ch0:1; - uint32_t reserved_25:7; + uint32_t conf_update_chn: 1; + /** dma_access_en_chn : WT; bitpos: [25]; default: 0; + * DMA access control bit for CHANNELn (only CHANNEL3 has this control bit) + */ + uint32_t dma_access_en_chn: 1; + uint32_t reserved_26: 6; }; uint32_t val; } rmt_chnconf0_reg_t; @@ -118,31 +126,35 @@ typedef union { */ typedef union { struct { - /** div_cnt_ch4 : R/W; bitpos: [7:0]; default: 2; + /** div_cnt_chm : R/W; bitpos: [7:0]; default: 2; * This register is used to configure the divider for clock of CHANNELm. */ - uint32_t div_cnt_ch4:8; - /** idle_thres_ch4 : R/W; bitpos: [22:8]; default: 32767; + uint32_t div_cnt_chm: 8; + /** idle_thres_chm : R/W; bitpos: [22:8]; default: 32767; * When no edge is detected on the input signal and continuous clock cycles is longer * than this register value, received process is finished. */ - uint32_t idle_thres_ch4:15; - uint32_t reserved_23:1; - /** mem_size_ch4 : R/W; bitpos: [27:24]; default: 1; + uint32_t idle_thres_chm: 15; + /** dma_access_en_m : WT; bitpos: [23]; default: 0; + * DMA access control bit for CHANNELm (only channel7 has this control bit) + */ + uint32_t dma_access_en_chm: 1; + /** mem_size_chm : R/W; bitpos: [27:24]; default: 1; * This register is used to configure the maximum size of memory allocated to CHANNELm. */ - uint32_t mem_size_ch4:4; - /** carrier_en_ch4 : R/W; bitpos: [28]; default: 1; + uint32_t mem_size_chm: 4; + /** carrier_en_chm : R/W; bitpos: [28]; default: 1; * This is the carrier modulation enable-control bit for CHANNELm. 1: Add carrier * modulation in the output signal. 0: No carrier modulation in sig_out. */ - uint32_t carrier_en_ch4:1; - /** carrier_out_lv_ch4 : R/W; bitpos: [29]; default: 1; - * This bit is used to configure the position of carrier wave for CHANNELm.1'h0: add - * carrier wave on low level.1'h1: add carrier wave on high level. + uint32_t carrier_en_chm: 1; + /** carrier_out_lv_chm : R/W; bitpos: [29]; default: 1; + * This bit is used to configure the position of carrier wave for CHANNELm. + * 1'h0: add carrier wave on low level. + * 1'h1: add carrier wave on high level. */ - uint32_t carrier_out_lv_ch4:1; - uint32_t reserved_30:2; + uint32_t carrier_out_lv_chm: 1; + uint32_t reserved_30: 2; }; uint32_t val; } rmt_chmconf0_reg_t; @@ -152,43 +164,47 @@ typedef union { */ typedef union { struct { - /** rx_en_ch4 : R/W; bitpos: [0]; default: 0; + /** rx_en_chm : R/W; bitpos: [0]; default: 0; * Set this bit to enable receiver to receive data on CHANNELm. */ - uint32_t rx_en_ch4:1; - /** mem_wr_rst_ch4 : WT; bitpos: [1]; default: 0; + uint32_t rx_en_chm: 1; + /** mem_wr_rst_chm : WT; bitpos: [1]; default: 0; * Set this bit to reset write ram address for CHANNELm by accessing receiver. */ - uint32_t mem_wr_rst_ch4:1; - /** apb_mem_rst_ch4 : WT; bitpos: [2]; default: 0; + uint32_t mem_wr_rst_chm: 1; + /** apb_mem_rst_chm : WT; bitpos: [2]; default: 0; * Set this bit to reset W/R ram address for CHANNELm by accessing apb fifo. */ - uint32_t apb_mem_rst_ch4:1; - /** mem_owner_ch4 : R/W/SC; bitpos: [3]; default: 1; - * This register marks the ownership of CHANNELm's ram block.1'h1: Receiver is using - * the ram. 1'h0: APB bus is using the ram. + uint32_t apb_mem_rst_chm: 1; + /** mem_owner_chm : R/W/SC; bitpos: [3]; default: 1; + * This register marks the ownership of CHANNELm's ram block. + * 1'h1: Receiver is using the ram. + * 1'h0: APB bus is using the ram. */ - uint32_t mem_owner_ch4:1; - /** rx_filter_en_ch4 : R/W; bitpos: [4]; default: 0; + uint32_t mem_owner_chm: 1; + /** rx_filter_en_chm : R/W; bitpos: [4]; default: 0; * This is the receive filter's enable bit for CHANNELm. */ - uint32_t rx_filter_en_ch4:1; - /** rx_filter_thres_ch4 : R/W; bitpos: [12:5]; default: 15; + uint32_t rx_filter_en_chm: 1; + /** rx_filter_thres_chm : R/W; bitpos: [12:5]; default: 15; * Ignores the input pulse when its width is smaller than this register value in APB * clock periods (in receive mode). */ - uint32_t rx_filter_thres_ch4:8; - /** mem_rx_wrap_en_ch4 : R/W; bitpos: [13]; default: 0; + uint32_t rx_filter_thres_chm: 8; + /** mem_rx_wrap_en_chm : R/W; bitpos: [13]; default: 0; * This is the channel m enable bit for wraparound mode: it will resume receiving at * the start when the data to be received is more than its memory size. */ - uint32_t mem_rx_wrap_en_ch4:1; - uint32_t reserved_14:1; - /** conf_update_ch4 : WT; bitpos: [15]; default: 0; + uint32_t mem_rx_wrap_en_chm: 1; + /** afifo_rst_chm : WT; bitpos: [14]; default: 0; + * Reserved + */ + uint32_t afifo_rst_chm: 1; + /** conf_update_chm : WT; bitpos: [15]; default: 0; * synchronization bit for CHANNELm */ - uint32_t conf_update_ch4:1; - uint32_t reserved_16:16; + uint32_t conf_update_chm: 1; + uint32_t reserved_16: 16; }; uint32_t val; } rmt_chmconf1_reg_t; @@ -198,16 +214,16 @@ typedef union { */ typedef union { struct { - /** carrier_low_thres_ch4 : R/W; bitpos: [15:0]; default: 0; + /** carrier_low_thres_chm : R/W; bitpos: [15:0]; default: 0; * The low level period in a carrier modulation mode is * (REG_RMT_REG_CARRIER_LOW_THRES_CHm + 1) for channel m. */ - uint32_t carrier_low_thres_ch4:16; - /** carrier_high_thres_ch4 : R/W; bitpos: [31:16]; default: 0; + uint32_t carrier_low_thres_chm: 16; + /** carrier_high_thres_chm : R/W; bitpos: [31:16]; default: 0; * The high level period in a carrier modulation mode is * (REG_RMT_REG_CARRIER_HIGH_THRES_CHm + 1) for channel m. */ - uint32_t carrier_high_thres_ch4:16; + uint32_t carrier_high_thres_chm: 16; }; uint32_t val; } rmt_chm_rx_carrier_rm_reg_t; @@ -220,46 +236,46 @@ typedef union { /** apb_fifo_mask : R/W; bitpos: [0]; default: 0; * 1'h1: access memory directly. 1'h0: access memory by FIFO. */ - uint32_t apb_fifo_mask:1; + uint32_t apb_fifo_mask: 1; /** mem_clk_force_on : R/W; bitpos: [1]; default: 0; * Set this bit to enable the clock for RMT memory. */ - uint32_t mem_clk_force_on:1; + uint32_t mem_clk_force_on: 1; /** mem_force_pd : R/W; bitpos: [2]; default: 0; * Set this bit to power down RMT memory. */ - uint32_t mem_force_pd:1; + uint32_t mem_force_pd: 1; /** mem_force_pu : R/W; bitpos: [3]; default: 0; * 1: Disable RMT memory light sleep power down function. 0: Power down RMT memory * when RMT is in light sleep mode. */ - uint32_t mem_force_pu:1; + uint32_t mem_force_pu: 1; /** sclk_div_num : R/W; bitpos: [11:4]; default: 1; * the integral part of the fractional divisor */ - uint32_t sclk_div_num:8; + uint32_t sclk_div_num: 8; /** sclk_div_a : R/W; bitpos: [17:12]; default: 0; * the numerator of the fractional part of the fractional divisor */ - uint32_t sclk_div_a:6; + uint32_t sclk_div_a: 6; /** sclk_div_b : R/W; bitpos: [23:18]; default: 0; * the denominator of the fractional part of the fractional divisor */ - uint32_t sclk_div_b:6; + uint32_t sclk_div_b: 6; /** sclk_sel : R/W; bitpos: [25:24]; default: 1; * choose the clock source of rmt_sclk. 1:CLK_80Mhz.2:CLK_8MHz.3:XTAL */ - uint32_t sclk_sel:2; + uint32_t sclk_sel: 2; /** sclk_active : R/W; bitpos: [26]; default: 1; * rmt_sclk switch */ - uint32_t sclk_active:1; - uint32_t reserved_27:4; + uint32_t sclk_active: 1; + uint32_t reserved_27: 4; /** clk_en : R/W; bitpos: [31]; default: 0; * RMT register clock gate enable signal. 1: Power up the drive clock of registers. 0: * Power down the drive clock of registers */ - uint32_t clk_en:1; + uint32_t clk_en: 1; }; uint32_t val; } rmt_sys_conf_reg_t; @@ -272,73 +288,72 @@ typedef union { /** ref_cnt_rst_ch0 : WT; bitpos: [0]; default: 0; * This register is used to reset the clock divider of CHANNEL0. */ - uint32_t ref_cnt_rst_ch0:1; + uint32_t ref_cnt_rst_ch0: 1; /** ref_cnt_rst_ch1 : WT; bitpos: [1]; default: 0; * This register is used to reset the clock divider of CHANNEL1. */ - uint32_t ref_cnt_rst_ch1:1; + uint32_t ref_cnt_rst_ch1: 1; /** ref_cnt_rst_ch2 : WT; bitpos: [2]; default: 0; * This register is used to reset the clock divider of CHANNEL2. */ - uint32_t ref_cnt_rst_ch2:1; + uint32_t ref_cnt_rst_ch2: 1; /** ref_cnt_rst_ch3 : WT; bitpos: [3]; default: 0; * This register is used to reset the clock divider of CHANNEL3. */ - uint32_t ref_cnt_rst_ch3:1; + uint32_t ref_cnt_rst_ch3: 1; /** ref_cnt_rst_ch4 : WT; bitpos: [4]; default: 0; * This register is used to reset the clock divider of CHANNEL4. */ - uint32_t ref_cnt_rst_ch4:1; + uint32_t ref_cnt_rst_ch4: 1; /** ref_cnt_rst_ch5 : WT; bitpos: [5]; default: 0; * This register is used to reset the clock divider of CHANNEL5. */ - uint32_t ref_cnt_rst_ch5:1; + uint32_t ref_cnt_rst_ch5: 1; /** ref_cnt_rst_ch6 : WT; bitpos: [6]; default: 0; * This register is used to reset the clock divider of CHANNEL6. */ - uint32_t ref_cnt_rst_ch6:1; + uint32_t ref_cnt_rst_ch6: 1; /** ref_cnt_rst_ch7 : WT; bitpos: [7]; default: 0; * This register is used to reset the clock divider of CHANNEL7. */ - uint32_t ref_cnt_rst_ch7:1; - uint32_t reserved_8:24; + uint32_t ref_cnt_rst_ch7: 1; + uint32_t reserved_8: 24; }; uint32_t val; } rmt_ref_cnt_rst_reg_t; - /** Group: Status registers */ /** Type of chnstatus register * Channel n status register */ typedef union { struct { - /** mem_raddr_ex_ch0 : RO; bitpos: [9:0]; default: 0; + /** mem_raddr_ex_chn : RO; bitpos: [9:0]; default: 0; * This register records the memory address offset when transmitter of CHANNELn is * using the RAM. */ - uint32_t mem_raddr_ex_ch0:10; - uint32_t reserved_10:1; - /** apb_mem_waddr_ch0 : RO; bitpos: [20:11]; default: 0; + uint32_t mem_raddr_ex_chn: 10; + uint32_t reserved_10: 1; + /** apb_mem_waddr_chn : RO; bitpos: [20:11]; default: 0; * This register records the memory address offset when writes RAM over APB bus. */ - uint32_t apb_mem_waddr_ch0:10; - uint32_t reserved_21:1; - /** state_ch0 : RO; bitpos: [24:22]; default: 0; + uint32_t apb_mem_waddr_chn: 10; + uint32_t reserved_21: 1; + /** state_chn : RO; bitpos: [24:22]; default: 0; * This register records the FSM status of CHANNELn. */ - uint32_t state_ch0:3; - /** mem_empty_ch0 : RO; bitpos: [25]; default: 0; + uint32_t state_chn: 3; + /** mem_empty_chn : RO; bitpos: [25]; default: 0; * This status bit will be set when the data to be set is more than memory size and * the wraparound mode is disabled. */ - uint32_t mem_empty_ch0:1; - /** apb_mem_wr_err_ch0 : RO; bitpos: [26]; default: 0; + uint32_t mem_empty_chn: 1; + /** apb_mem_wr_err_chn : RO; bitpos: [26]; default: 0; * This status bit will be set if the offset address out of memory size when writes * via APB bus. */ - uint32_t apb_mem_wr_err_ch0:1; - uint32_t reserved_27:5; + uint32_t apb_mem_wr_err_chn: 1; + uint32_t reserved_27: 5; }; uint32_t val; } rmt_chnstatus_reg_t; @@ -348,40 +363,39 @@ typedef union { */ typedef union { struct { - /** mem_waddr_ex_ch4 : RO; bitpos: [9:0]; default: 192; + /** mem_waddr_ex_chm : RO; bitpos: [9:0]; default: 192; * This register records the memory address offset when receiver of CHANNELm is using * the RAM. */ - uint32_t mem_waddr_ex_ch4:10; - uint32_t reserved_10:1; - /** apb_mem_raddr_ch4 : RO; bitpos: [20:11]; default: 192; + uint32_t mem_waddr_ex_chm: 10; + uint32_t reserved_10: 1; + /** apb_mem_raddr_chm : RO; bitpos: [20:11]; default: 192; * This register records the memory address offset when reads RAM over APB bus. */ - uint32_t apb_mem_raddr_ch4:10; - uint32_t reserved_21:1; - /** state_ch4 : RO; bitpos: [24:22]; default: 0; + uint32_t apb_mem_raddr_chm: 10; + uint32_t reserved_21: 1; + /** state_chm : RO; bitpos: [24:22]; default: 0; * This register records the FSM status of CHANNELm. */ - uint32_t state_ch4:3; - /** mem_owner_err_ch4 : RO; bitpos: [25]; default: 0; + uint32_t state_chm: 3; + /** mem_owner_err_chm : RO; bitpos: [25]; default: 0; * This status bit will be set when the ownership of memory block is wrong. */ - uint32_t mem_owner_err_ch4:1; - /** mem_full_ch4 : RO; bitpos: [26]; default: 0; + uint32_t mem_owner_err_chm: 1; + /** mem_full_chm : RO; bitpos: [26]; default: 0; * This status bit will be set if the receiver receives more data than the memory size. */ - uint32_t mem_full_ch4:1; - /** apb_mem_rd_err_ch4 : RO; bitpos: [27]; default: 0; + uint32_t mem_full_chm: 1; + /** apb_mem_rd_err_chm : RO; bitpos: [27]; default: 0; * This status bit will be set if the offset address out of memory size when reads via * APB bus. */ - uint32_t apb_mem_rd_err_ch4:1; - uint32_t reserved_28:4; + uint32_t apb_mem_rd_err_chm: 1; + uint32_t reserved_28: 4; }; uint32_t val; } rmt_chmstatus_reg_t; - /** Group: Interrupt registers */ /** Type of int_raw register * Raw interrupt status @@ -391,136 +405,136 @@ typedef union { /** ch0_tx_end_int_raw : R/WTC/SS; bitpos: [0]; default: 0; * The interrupt raw bit for CHANNEL0. Triggered when transmission done. */ - uint32_t ch0_tx_end_int_raw:1; + uint32_t ch0_tx_end_int_raw: 1; /** ch1_tx_end_int_raw : R/WTC/SS; bitpos: [1]; default: 0; * The interrupt raw bit for CHANNEL1. Triggered when transmission done. */ - uint32_t ch1_tx_end_int_raw:1; + uint32_t ch1_tx_end_int_raw: 1; /** ch2_tx_end_int_raw : R/WTC/SS; bitpos: [2]; default: 0; * The interrupt raw bit for CHANNEL2. Triggered when transmission done. */ - uint32_t ch2_tx_end_int_raw:1; + uint32_t ch2_tx_end_int_raw: 1; /** ch3_tx_end_int_raw : R/WTC/SS; bitpos: [3]; default: 0; * The interrupt raw bit for CHANNEL3. Triggered when transmission done. */ - uint32_t ch3_tx_end_int_raw:1; + uint32_t ch3_tx_end_int_raw: 1; /** ch0_err_int_raw : R/WTC/SS; bitpos: [4]; default: 0; * The interrupt raw bit for CHANNEL0. Triggered when error occurs. */ - uint32_t ch0_err_int_raw:1; + uint32_t ch0_err_int_raw: 1; /** ch1_err_int_raw : R/WTC/SS; bitpos: [5]; default: 0; * The interrupt raw bit for CHANNEL1. Triggered when error occurs. */ - uint32_t ch1_err_int_raw:1; + uint32_t ch1_err_int_raw: 1; /** ch2_err_int_raw : R/WTC/SS; bitpos: [6]; default: 0; * The interrupt raw bit for CHANNEL2. Triggered when error occurs. */ - uint32_t ch2_err_int_raw:1; + uint32_t ch2_err_int_raw: 1; /** ch3_err_int_raw : R/WTC/SS; bitpos: [7]; default: 0; * The interrupt raw bit for CHANNEL3. Triggered when error occurs. */ - uint32_t ch3_err_int_raw:1; + uint32_t ch3_err_int_raw: 1; /** ch0_tx_thr_event_int_raw : R/WTC/SS; bitpos: [8]; default: 0; * The interrupt raw bit for CHANNEL0. Triggered when transmitter sent more data than * configured value. */ - uint32_t ch0_tx_thr_event_int_raw:1; + uint32_t ch0_tx_thr_event_int_raw: 1; /** ch1_tx_thr_event_int_raw : R/WTC/SS; bitpos: [9]; default: 0; * The interrupt raw bit for CHANNEL1. Triggered when transmitter sent more data than * configured value. */ - uint32_t ch1_tx_thr_event_int_raw:1; + uint32_t ch1_tx_thr_event_int_raw: 1; /** ch2_tx_thr_event_int_raw : R/WTC/SS; bitpos: [10]; default: 0; * The interrupt raw bit for CHANNEL2. Triggered when transmitter sent more data than * configured value. */ - uint32_t ch2_tx_thr_event_int_raw:1; + uint32_t ch2_tx_thr_event_int_raw: 1; /** ch3_tx_thr_event_int_raw : R/WTC/SS; bitpos: [11]; default: 0; * The interrupt raw bit for CHANNEL3. Triggered when transmitter sent more data than * configured value. */ - uint32_t ch3_tx_thr_event_int_raw:1; + uint32_t ch3_tx_thr_event_int_raw: 1; /** ch0_tx_loop_int_raw : R/WTC/SS; bitpos: [12]; default: 0; * The interrupt raw bit for CHANNEL0. Triggered when the loop count reaches the * configured threshold value. */ - uint32_t ch0_tx_loop_int_raw:1; + uint32_t ch0_tx_loop_int_raw: 1; /** ch1_tx_loop_int_raw : R/WTC/SS; bitpos: [13]; default: 0; * The interrupt raw bit for CHANNEL1. Triggered when the loop count reaches the * configured threshold value. */ - uint32_t ch1_tx_loop_int_raw:1; + uint32_t ch1_tx_loop_int_raw: 1; /** ch2_tx_loop_int_raw : R/WTC/SS; bitpos: [14]; default: 0; * The interrupt raw bit for CHANNEL2. Triggered when the loop count reaches the * configured threshold value. */ - uint32_t ch2_tx_loop_int_raw:1; + uint32_t ch2_tx_loop_int_raw: 1; /** ch3_tx_loop_int_raw : R/WTC/SS; bitpos: [15]; default: 0; * The interrupt raw bit for CHANNEL3. Triggered when the loop count reaches the * configured threshold value. */ - uint32_t ch3_tx_loop_int_raw:1; + uint32_t ch3_tx_loop_int_raw: 1; /** ch4_rx_end_int_raw : R/WTC/SS; bitpos: [16]; default: 0; * The interrupt raw bit for CHANNEL4. Triggered when reception done. */ - uint32_t ch4_rx_end_int_raw:1; + uint32_t ch4_rx_end_int_raw: 1; /** ch5_rx_end_int_raw : R/WTC/SS; bitpos: [17]; default: 0; * The interrupt raw bit for CHANNEL5. Triggered when reception done. */ - uint32_t ch5_rx_end_int_raw:1; + uint32_t ch5_rx_end_int_raw: 1; /** ch6_rx_end_int_raw : R/WTC/SS; bitpos: [18]; default: 0; * The interrupt raw bit for CHANNEL6. Triggered when reception done. */ - uint32_t ch6_rx_end_int_raw:1; + uint32_t ch6_rx_end_int_raw: 1; /** ch7_rx_end_int_raw : R/WTC/SS; bitpos: [19]; default: 0; * The interrupt raw bit for CHANNEL7. Triggered when reception done. */ - uint32_t ch7_rx_end_int_raw:1; + uint32_t ch7_rx_end_int_raw: 1; /** ch4_err_int_raw : R/WTC/SS; bitpos: [20]; default: 0; * The interrupt raw bit for CHANNEL4. Triggered when error occurs. */ - uint32_t ch4_err_int_raw:1; + uint32_t ch4_err_int_raw: 1; /** ch5_err_int_raw : R/WTC/SS; bitpos: [21]; default: 0; * The interrupt raw bit for CHANNEL5. Triggered when error occurs. */ - uint32_t ch5_err_int_raw:1; + uint32_t ch5_err_int_raw: 1; /** ch6_err_int_raw : R/WTC/SS; bitpos: [22]; default: 0; * The interrupt raw bit for CHANNEL6. Triggered when error occurs. */ - uint32_t ch6_err_int_raw:1; + uint32_t ch6_err_int_raw: 1; /** ch7_err_int_raw : R/WTC/SS; bitpos: [23]; default: 0; * The interrupt raw bit for CHANNEL7. Triggered when error occurs. */ - uint32_t ch7_err_int_raw:1; + uint32_t ch7_err_int_raw: 1; /** ch4_rx_thr_event_int_raw : R/WTC/SS; bitpos: [24]; default: 0; * The interrupt raw bit for CHANNEL4. Triggered when receiver receive more data than * configured value. */ - uint32_t ch4_rx_thr_event_int_raw:1; + uint32_t ch4_rx_thr_event_int_raw: 1; /** ch5_rx_thr_event_int_raw : R/WTC/SS; bitpos: [25]; default: 0; * The interrupt raw bit for CHANNEL5. Triggered when receiver receive more data than * configured value. */ - uint32_t ch5_rx_thr_event_int_raw:1; + uint32_t ch5_rx_thr_event_int_raw: 1; /** ch6_rx_thr_event_int_raw : R/WTC/SS; bitpos: [26]; default: 0; * The interrupt raw bit for CHANNEL6. Triggered when receiver receive more data than * configured value. */ - uint32_t ch6_rx_thr_event_int_raw:1; + uint32_t ch6_rx_thr_event_int_raw: 1; /** ch7_rx_thr_event_int_raw : R/WTC/SS; bitpos: [27]; default: 0; * The interrupt raw bit for CHANNEL7. Triggered when receiver receive more data than * configured value. */ - uint32_t ch7_rx_thr_event_int_raw:1; + uint32_t ch7_rx_thr_event_int_raw: 1; /** ch3_dma_access_fail_int_raw : R/WTC/SS; bitpos: [28]; default: 0; * The interrupt raw bit for CHANNEL3. Triggered when dma accessing CHANNEL3 fails. */ - uint32_t ch3_dma_access_fail_int_raw:1; + uint32_t ch3_dma_access_fail_int_raw: 1; /** ch7_dma_access_fail_int_raw : R/WTC/SS; bitpos: [29]; default: 0; * The interrupt raw bit for CHANNEL7. Triggered when dma accessing CHANNEL7 fails. */ - uint32_t ch7_dma_access_fail_int_raw:1; - uint32_t reserved_30:2; + uint32_t ch7_dma_access_fail_int_raw: 1; + uint32_t reserved_30: 2; }; uint32_t val; } rmt_int_raw_reg_t; @@ -533,124 +547,124 @@ typedef union { /** ch0_tx_end_int_st : RO; bitpos: [0]; default: 0; * The masked interrupt status bit for CH0_TX_END_INT. */ - uint32_t ch0_tx_end_int_st:1; + uint32_t ch0_tx_end_int_st: 1; /** ch1_tx_end_int_st : RO; bitpos: [1]; default: 0; * The masked interrupt status bit for CH1_TX_END_INT. */ - uint32_t ch1_tx_end_int_st:1; + uint32_t ch1_tx_end_int_st: 1; /** ch2_tx_end_int_st : RO; bitpos: [2]; default: 0; * The masked interrupt status bit for CH2_TX_END_INT. */ - uint32_t ch2_tx_end_int_st:1; + uint32_t ch2_tx_end_int_st: 1; /** ch3_tx_end_int_st : RO; bitpos: [3]; default: 0; * The masked interrupt status bit for CH3_TX_END_INT. */ - uint32_t ch3_tx_end_int_st:1; + uint32_t ch3_tx_end_int_st: 1; /** ch0_err_int_st : RO; bitpos: [4]; default: 0; * The masked interrupt status bit for CH0_ERR_INT. */ - uint32_t ch0_err_int_st:1; + uint32_t ch0_err_int_st: 1; /** ch1_err_int_st : RO; bitpos: [5]; default: 0; * The masked interrupt status bit for CH1_ERR_INT. */ - uint32_t ch1_err_int_st:1; + uint32_t ch1_err_int_st: 1; /** ch2_err_int_st : RO; bitpos: [6]; default: 0; * The masked interrupt status bit for CH2_ERR_INT. */ - uint32_t ch2_err_int_st:1; + uint32_t ch2_err_int_st: 1; /** ch3_err_int_st : RO; bitpos: [7]; default: 0; * The masked interrupt status bit for CH3_ERR_INT. */ - uint32_t ch3_err_int_st:1; + uint32_t ch3_err_int_st: 1; /** ch0_tx_thr_event_int_st : RO; bitpos: [8]; default: 0; * The masked interrupt status bit for CH0_TX_THR_EVENT_INT. */ - uint32_t ch0_tx_thr_event_int_st:1; + uint32_t ch0_tx_thr_event_int_st: 1; /** ch1_tx_thr_event_int_st : RO; bitpos: [9]; default: 0; * The masked interrupt status bit for CH1_TX_THR_EVENT_INT. */ - uint32_t ch1_tx_thr_event_int_st:1; + uint32_t ch1_tx_thr_event_int_st: 1; /** ch2_tx_thr_event_int_st : RO; bitpos: [10]; default: 0; * The masked interrupt status bit for CH2_TX_THR_EVENT_INT. */ - uint32_t ch2_tx_thr_event_int_st:1; + uint32_t ch2_tx_thr_event_int_st: 1; /** ch3_tx_thr_event_int_st : RO; bitpos: [11]; default: 0; * The masked interrupt status bit for CH3_TX_THR_EVENT_INT. */ - uint32_t ch3_tx_thr_event_int_st:1; + uint32_t ch3_tx_thr_event_int_st: 1; /** ch0_tx_loop_int_st : RO; bitpos: [12]; default: 0; * The masked interrupt status bit for CH0_TX_LOOP_INT. */ - uint32_t ch0_tx_loop_int_st:1; + uint32_t ch0_tx_loop_int_st: 1; /** ch1_tx_loop_int_st : RO; bitpos: [13]; default: 0; * The masked interrupt status bit for CH1_TX_LOOP_INT. */ - uint32_t ch1_tx_loop_int_st:1; + uint32_t ch1_tx_loop_int_st: 1; /** ch2_tx_loop_int_st : RO; bitpos: [14]; default: 0; * The masked interrupt status bit for CH2_TX_LOOP_INT. */ - uint32_t ch2_tx_loop_int_st:1; + uint32_t ch2_tx_loop_int_st: 1; /** ch3_tx_loop_int_st : RO; bitpos: [15]; default: 0; * The masked interrupt status bit for CH3_TX_LOOP_INT. */ - uint32_t ch3_tx_loop_int_st:1; + uint32_t ch3_tx_loop_int_st: 1; /** ch4_rx_end_int_st : RO; bitpos: [16]; default: 0; * The masked interrupt status bit for CH4_RX_END_INT. */ - uint32_t ch4_rx_end_int_st:1; + uint32_t ch4_rx_end_int_st: 1; /** ch5_rx_end_int_st : RO; bitpos: [17]; default: 0; * The masked interrupt status bit for CH5_RX_END_INT. */ - uint32_t ch5_rx_end_int_st:1; + uint32_t ch5_rx_end_int_st: 1; /** ch6_rx_end_int_st : RO; bitpos: [18]; default: 0; * The masked interrupt status bit for CH6_RX_END_INT. */ - uint32_t ch6_rx_end_int_st:1; + uint32_t ch6_rx_end_int_st: 1; /** ch7_rx_end_int_st : RO; bitpos: [19]; default: 0; * The masked interrupt status bit for CH7_RX_END_INT. */ - uint32_t ch7_rx_end_int_st:1; + uint32_t ch7_rx_end_int_st: 1; /** ch4_err_int_st : RO; bitpos: [20]; default: 0; * The masked interrupt status bit for CH4_ERR_INT. */ - uint32_t ch4_err_int_st:1; + uint32_t ch4_err_int_st: 1; /** ch5_err_int_st : RO; bitpos: [21]; default: 0; * The masked interrupt status bit for CH5_ERR_INT. */ - uint32_t ch5_err_int_st:1; + uint32_t ch5_err_int_st: 1; /** ch6_err_int_st : RO; bitpos: [22]; default: 0; * The masked interrupt status bit for CH6_ERR_INT. */ - uint32_t ch6_err_int_st:1; + uint32_t ch6_err_int_st: 1; /** ch7_err_int_st : RO; bitpos: [23]; default: 0; * The masked interrupt status bit for CH7_ERR_INT. */ - uint32_t ch7_err_int_st:1; + uint32_t ch7_err_int_st: 1; /** ch4_rx_thr_event_int_st : RO; bitpos: [24]; default: 0; * The masked interrupt status bit for CH4_RX_THR_EVENT_INT. */ - uint32_t ch4_rx_thr_event_int_st:1; + uint32_t ch4_rx_thr_event_int_st: 1; /** ch5_rx_thr_event_int_st : RO; bitpos: [25]; default: 0; * The masked interrupt status bit for CH5_RX_THR_EVENT_INT. */ - uint32_t ch5_rx_thr_event_int_st:1; + uint32_t ch5_rx_thr_event_int_st: 1; /** ch6_rx_thr_event_int_st : RO; bitpos: [26]; default: 0; * The masked interrupt status bit for CH6_RX_THR_EVENT_INT. */ - uint32_t ch6_rx_thr_event_int_st:1; + uint32_t ch6_rx_thr_event_int_st: 1; /** ch7_rx_thr_event_int_st : RO; bitpos: [27]; default: 0; * The masked interrupt status bit for CH7_RX_THR_EVENT_INT. */ - uint32_t ch7_rx_thr_event_int_st:1; + uint32_t ch7_rx_thr_event_int_st: 1; /** ch3_dma_access_fail_int_st : RO; bitpos: [28]; default: 0; * The masked interrupt status bit for CH3_DMA_ACCESS_FAIL_INT. */ - uint32_t ch3_dma_access_fail_int_st:1; + uint32_t ch3_dma_access_fail_int_st: 1; /** ch7_dma_access_fail_int_st : RO; bitpos: [29]; default: 0; * The masked interrupt status bit for CH7_DMA_ACCESS_FAIL_INT. */ - uint32_t ch7_dma_access_fail_int_st:1; - uint32_t reserved_30:2; + uint32_t ch7_dma_access_fail_int_st: 1; + uint32_t reserved_30: 2; }; uint32_t val; } rmt_int_st_reg_t; @@ -663,124 +677,124 @@ typedef union { /** ch0_tx_end_int_ena : R/W; bitpos: [0]; default: 0; * The interrupt enable bit for CH0_TX_END_INT. */ - uint32_t ch0_tx_end_int_ena:1; + uint32_t ch0_tx_end_int_ena: 1; /** ch1_tx_end_int_ena : R/W; bitpos: [1]; default: 0; * The interrupt enable bit for CH1_TX_END_INT. */ - uint32_t ch1_tx_end_int_ena:1; + uint32_t ch1_tx_end_int_ena: 1; /** ch2_tx_end_int_ena : R/W; bitpos: [2]; default: 0; * The interrupt enable bit for CH2_TX_END_INT. */ - uint32_t ch2_tx_end_int_ena:1; + uint32_t ch2_tx_end_int_ena: 1; /** ch3_tx_end_int_ena : R/W; bitpos: [3]; default: 0; * The interrupt enable bit for CH3_TX_END_INT. */ - uint32_t ch3_tx_end_int_ena:1; + uint32_t ch3_tx_end_int_ena: 1; /** ch0_err_int_ena : R/W; bitpos: [4]; default: 0; * The interrupt enable bit for CH0_ERR_INT. */ - uint32_t ch0_err_int_ena:1; + uint32_t ch0_err_int_ena: 1; /** ch1_err_int_ena : R/W; bitpos: [5]; default: 0; * The interrupt enable bit for CH1_ERR_INT. */ - uint32_t ch1_err_int_ena:1; + uint32_t ch1_err_int_ena: 1; /** ch2_err_int_ena : R/W; bitpos: [6]; default: 0; * The interrupt enable bit for CH2_ERR_INT. */ - uint32_t ch2_err_int_ena:1; + uint32_t ch2_err_int_ena: 1; /** ch3_err_int_ena : R/W; bitpos: [7]; default: 0; * The interrupt enable bit for CH3_ERR_INT. */ - uint32_t ch3_err_int_ena:1; + uint32_t ch3_err_int_ena: 1; /** ch0_tx_thr_event_int_ena : R/W; bitpos: [8]; default: 0; * The interrupt enable bit for CH0_TX_THR_EVENT_INT. */ - uint32_t ch0_tx_thr_event_int_ena:1; + uint32_t ch0_tx_thr_event_int_ena: 1; /** ch1_tx_thr_event_int_ena : R/W; bitpos: [9]; default: 0; * The interrupt enable bit for CH1_TX_THR_EVENT_INT. */ - uint32_t ch1_tx_thr_event_int_ena:1; + uint32_t ch1_tx_thr_event_int_ena: 1; /** ch2_tx_thr_event_int_ena : R/W; bitpos: [10]; default: 0; * The interrupt enable bit for CH2_TX_THR_EVENT_INT. */ - uint32_t ch2_tx_thr_event_int_ena:1; + uint32_t ch2_tx_thr_event_int_ena: 1; /** ch3_tx_thr_event_int_ena : R/W; bitpos: [11]; default: 0; * The interrupt enable bit for CH3_TX_THR_EVENT_INT. */ - uint32_t ch3_tx_thr_event_int_ena:1; + uint32_t ch3_tx_thr_event_int_ena: 1; /** ch0_tx_loop_int_ena : R/W; bitpos: [12]; default: 0; * The interrupt enable bit for CH0_TX_LOOP_INT. */ - uint32_t ch0_tx_loop_int_ena:1; + uint32_t ch0_tx_loop_int_ena: 1; /** ch1_tx_loop_int_ena : R/W; bitpos: [13]; default: 0; * The interrupt enable bit for CH1_TX_LOOP_INT. */ - uint32_t ch1_tx_loop_int_ena:1; + uint32_t ch1_tx_loop_int_ena: 1; /** ch2_tx_loop_int_ena : R/W; bitpos: [14]; default: 0; * The interrupt enable bit for CH2_TX_LOOP_INT. */ - uint32_t ch2_tx_loop_int_ena:1; + uint32_t ch2_tx_loop_int_ena: 1; /** ch3_tx_loop_int_ena : R/W; bitpos: [15]; default: 0; * The interrupt enable bit for CH3_TX_LOOP_INT. */ - uint32_t ch3_tx_loop_int_ena:1; + uint32_t ch3_tx_loop_int_ena: 1; /** ch4_rx_end_int_ena : R/W; bitpos: [16]; default: 0; * The interrupt enable bit for CH4_RX_END_INT. */ - uint32_t ch4_rx_end_int_ena:1; + uint32_t ch4_rx_end_int_ena: 1; /** ch5_rx_end_int_ena : R/W; bitpos: [17]; default: 0; * The interrupt enable bit for CH5_RX_END_INT. */ - uint32_t ch5_rx_end_int_ena:1; + uint32_t ch5_rx_end_int_ena: 1; /** ch6_rx_end_int_ena : R/W; bitpos: [18]; default: 0; * The interrupt enable bit for CH6_RX_END_INT. */ - uint32_t ch6_rx_end_int_ena:1; + uint32_t ch6_rx_end_int_ena: 1; /** ch7_rx_end_int_ena : R/W; bitpos: [19]; default: 0; * The interrupt enable bit for CH7_RX_END_INT. */ - uint32_t ch7_rx_end_int_ena:1; + uint32_t ch7_rx_end_int_ena: 1; /** ch4_err_int_ena : R/W; bitpos: [20]; default: 0; * The interrupt enable bit for CH4_ERR_INT. */ - uint32_t ch4_err_int_ena:1; + uint32_t ch4_err_int_ena: 1; /** ch5_err_int_ena : R/W; bitpos: [21]; default: 0; * The interrupt enable bit for CH5_ERR_INT. */ - uint32_t ch5_err_int_ena:1; + uint32_t ch5_err_int_ena: 1; /** ch6_err_int_ena : R/W; bitpos: [22]; default: 0; * The interrupt enable bit for CH6_ERR_INT. */ - uint32_t ch6_err_int_ena:1; + uint32_t ch6_err_int_ena: 1; /** ch7_err_int_ena : R/W; bitpos: [23]; default: 0; * The interrupt enable bit for CH7_ERR_INT. */ - uint32_t ch7_err_int_ena:1; + uint32_t ch7_err_int_ena: 1; /** ch4_rx_thr_event_int_ena : R/W; bitpos: [24]; default: 0; * The interrupt enable bit for CH4_RX_THR_EVENT_INT. */ - uint32_t ch4_rx_thr_event_int_ena:1; + uint32_t ch4_rx_thr_event_int_ena: 1; /** ch5_rx_thr_event_int_ena : R/W; bitpos: [25]; default: 0; * The interrupt enable bit for CH5_RX_THR_EVENT_INT. */ - uint32_t ch5_rx_thr_event_int_ena:1; + uint32_t ch5_rx_thr_event_int_ena: 1; /** ch6_rx_thr_event_int_ena : R/W; bitpos: [26]; default: 0; * The interrupt enable bit for CH6_RX_THR_EVENT_INT. */ - uint32_t ch6_rx_thr_event_int_ena:1; + uint32_t ch6_rx_thr_event_int_ena: 1; /** ch7_rx_thr_event_int_ena : R/W; bitpos: [27]; default: 0; * The interrupt enable bit for CH7_RX_THR_EVENT_INT. */ - uint32_t ch7_rx_thr_event_int_ena:1; + uint32_t ch7_rx_thr_event_int_ena: 1; /** ch3_dma_access_fail_int_ena : R/W; bitpos: [28]; default: 0; * The interrupt enable bit for CH3_DMA_ACCESS_FAIL_INT. */ - uint32_t ch3_dma_access_fail_int_ena:1; + uint32_t ch3_dma_access_fail_int_ena: 1; /** ch7_dma_access_fail_int_ena : R/W; bitpos: [29]; default: 0; * The interrupt enable bit for CH7_DMA_ACCESS_FAIL_INT. */ - uint32_t ch7_dma_access_fail_int_ena:1; - uint32_t reserved_30:2; + uint32_t ch7_dma_access_fail_int_ena: 1; + uint32_t reserved_30: 2; }; uint32_t val; } rmt_int_ena_reg_t; @@ -793,179 +807,177 @@ typedef union { /** ch0_tx_end_int_clr : WT; bitpos: [0]; default: 0; * Set this bit to clear theCH0_TX_END_INT interrupt. */ - uint32_t ch0_tx_end_int_clr:1; + uint32_t ch0_tx_end_int_clr: 1; /** ch1_tx_end_int_clr : WT; bitpos: [1]; default: 0; * Set this bit to clear theCH1_TX_END_INT interrupt. */ - uint32_t ch1_tx_end_int_clr:1; + uint32_t ch1_tx_end_int_clr: 1; /** ch2_tx_end_int_clr : WT; bitpos: [2]; default: 0; * Set this bit to clear theCH2_TX_END_INT interrupt. */ - uint32_t ch2_tx_end_int_clr:1; + uint32_t ch2_tx_end_int_clr: 1; /** ch3_tx_end_int_clr : WT; bitpos: [3]; default: 0; * Set this bit to clear theCH3_TX_END_INT interrupt. */ - uint32_t ch3_tx_end_int_clr:1; + uint32_t ch3_tx_end_int_clr: 1; /** ch0_err_int_clr : WT; bitpos: [4]; default: 0; * Set this bit to clear theCH0_ERR_INT interrupt. */ - uint32_t ch0_err_int_clr:1; + uint32_t ch0_err_int_clr: 1; /** ch1_err_int_clr : WT; bitpos: [5]; default: 0; * Set this bit to clear theCH1_ERR_INT interrupt. */ - uint32_t ch1_err_int_clr:1; + uint32_t ch1_err_int_clr: 1; /** ch2_err_int_clr : WT; bitpos: [6]; default: 0; * Set this bit to clear theCH2_ERR_INT interrupt. */ - uint32_t ch2_err_int_clr:1; + uint32_t ch2_err_int_clr: 1; /** ch3_err_int_clr : WT; bitpos: [7]; default: 0; * Set this bit to clear theCH3_ERR_INT interrupt. */ - uint32_t ch3_err_int_clr:1; + uint32_t ch3_err_int_clr: 1; /** ch0_tx_thr_event_int_clr : WT; bitpos: [8]; default: 0; * Set this bit to clear theCH0_TX_THR_EVENT_INT interrupt. */ - uint32_t ch0_tx_thr_event_int_clr:1; + uint32_t ch0_tx_thr_event_int_clr: 1; /** ch1_tx_thr_event_int_clr : WT; bitpos: [9]; default: 0; * Set this bit to clear theCH1_TX_THR_EVENT_INT interrupt. */ - uint32_t ch1_tx_thr_event_int_clr:1; + uint32_t ch1_tx_thr_event_int_clr: 1; /** ch2_tx_thr_event_int_clr : WT; bitpos: [10]; default: 0; * Set this bit to clear theCH2_TX_THR_EVENT_INT interrupt. */ - uint32_t ch2_tx_thr_event_int_clr:1; + uint32_t ch2_tx_thr_event_int_clr: 1; /** ch3_tx_thr_event_int_clr : WT; bitpos: [11]; default: 0; * Set this bit to clear theCH3_TX_THR_EVENT_INT interrupt. */ - uint32_t ch3_tx_thr_event_int_clr:1; + uint32_t ch3_tx_thr_event_int_clr: 1; /** ch0_tx_loop_int_clr : WT; bitpos: [12]; default: 0; * Set this bit to clear theCH0_TX_LOOP_INT interrupt. */ - uint32_t ch0_tx_loop_int_clr:1; + uint32_t ch0_tx_loop_int_clr: 1; /** ch1_tx_loop_int_clr : WT; bitpos: [13]; default: 0; * Set this bit to clear theCH1_TX_LOOP_INT interrupt. */ - uint32_t ch1_tx_loop_int_clr:1; + uint32_t ch1_tx_loop_int_clr: 1; /** ch2_tx_loop_int_clr : WT; bitpos: [14]; default: 0; * Set this bit to clear theCH2_TX_LOOP_INT interrupt. */ - uint32_t ch2_tx_loop_int_clr:1; + uint32_t ch2_tx_loop_int_clr: 1; /** ch3_tx_loop_int_clr : WT; bitpos: [15]; default: 0; * Set this bit to clear theCH3_TX_LOOP_INT interrupt. */ - uint32_t ch3_tx_loop_int_clr:1; + uint32_t ch3_tx_loop_int_clr: 1; /** ch4_rx_end_int_clr : WT; bitpos: [16]; default: 0; * Set this bit to clear theCH4_RX_END_INT interrupt. */ - uint32_t ch4_rx_end_int_clr:1; + uint32_t ch4_rx_end_int_clr: 1; /** ch5_rx_end_int_clr : WT; bitpos: [17]; default: 0; * Set this bit to clear theCH5_RX_END_INT interrupt. */ - uint32_t ch5_rx_end_int_clr:1; + uint32_t ch5_rx_end_int_clr: 1; /** ch6_rx_end_int_clr : WT; bitpos: [18]; default: 0; * Set this bit to clear theCH6_RX_END_INT interrupt. */ - uint32_t ch6_rx_end_int_clr:1; + uint32_t ch6_rx_end_int_clr: 1; /** ch7_rx_end_int_clr : WT; bitpos: [19]; default: 0; * Set this bit to clear theCH7_RX_END_INT interrupt. */ - uint32_t ch7_rx_end_int_clr:1; + uint32_t ch7_rx_end_int_clr: 1; /** ch4_err_int_clr : WT; bitpos: [20]; default: 0; * Set this bit to clear theCH4_ERR_INT interrupt. */ - uint32_t ch4_err_int_clr:1; + uint32_t ch4_err_int_clr: 1; /** ch5_err_int_clr : WT; bitpos: [21]; default: 0; * Set this bit to clear theCH5_ERR_INT interrupt. */ - uint32_t ch5_err_int_clr:1; + uint32_t ch5_err_int_clr: 1; /** ch6_err_int_clr : WT; bitpos: [22]; default: 0; * Set this bit to clear theCH6_ERR_INT interrupt. */ - uint32_t ch6_err_int_clr:1; + uint32_t ch6_err_int_clr: 1; /** ch7_err_int_clr : WT; bitpos: [23]; default: 0; * Set this bit to clear theCH7_ERR_INT interrupt. */ - uint32_t ch7_err_int_clr:1; + uint32_t ch7_err_int_clr: 1; /** ch4_rx_thr_event_int_clr : WT; bitpos: [24]; default: 0; * Set this bit to clear theCH4_RX_THR_EVENT_INT interrupt. */ - uint32_t ch4_rx_thr_event_int_clr:1; + uint32_t ch4_rx_thr_event_int_clr: 1; /** ch5_rx_thr_event_int_clr : WT; bitpos: [25]; default: 0; * Set this bit to clear theCH5_RX_THR_EVENT_INT interrupt. */ - uint32_t ch5_rx_thr_event_int_clr:1; + uint32_t ch5_rx_thr_event_int_clr: 1; /** ch6_rx_thr_event_int_clr : WT; bitpos: [26]; default: 0; * Set this bit to clear theCH6_RX_THR_EVENT_INT interrupt. */ - uint32_t ch6_rx_thr_event_int_clr:1; + uint32_t ch6_rx_thr_event_int_clr: 1; /** ch7_rx_thr_event_int_clr : WT; bitpos: [27]; default: 0; * Set this bit to clear theCH7_RX_THR_EVENT_INT interrupt. */ - uint32_t ch7_rx_thr_event_int_clr:1; + uint32_t ch7_rx_thr_event_int_clr: 1; /** ch3_dma_access_fail_int_clr : WT; bitpos: [28]; default: 0; * Set this bit to clear the CH3_DMA_ACCESS_FAIL_INT interrupt. */ - uint32_t ch3_dma_access_fail_int_clr:1; + uint32_t ch3_dma_access_fail_int_clr: 1; /** ch7_dma_access_fail_int_clr : WT; bitpos: [29]; default: 0; * Set this bit to clear the CH7_DMA_ACCESS_FAIL_INT interrupt. */ - uint32_t ch7_dma_access_fail_int_clr:1; - uint32_t reserved_30:2; + uint32_t ch7_dma_access_fail_int_clr: 1; + uint32_t reserved_30: 2; }; uint32_t val; } rmt_int_clr_reg_t; - /** Group: Carrier wave duty cycle registers */ /** Type of chncarrier_duty register * Channel n duty cycle configuration register */ typedef union { struct { - /** carrier_low_ch0 : R/W; bitpos: [15:0]; default: 64; + /** carrier_low_chn : R/W; bitpos: [15:0]; default: 64; * This register is used to configure carrier wave 's low level clock period for * CHANNELn. */ - uint32_t carrier_low_ch0:16; - /** carrier_high_ch0 : R/W; bitpos: [31:16]; default: 64; + uint32_t carrier_low_chn: 16; + /** carrier_high_chn : R/W; bitpos: [31:16]; default: 64; * This register is used to configure carrier wave 's high level clock period for * CHANNELn. */ - uint32_t carrier_high_ch0:16; + uint32_t carrier_high_chn: 16; }; uint32_t val; } rmt_chncarrier_duty_reg_t; - /** Group: Tx event configuration registers */ /** Type of chn_tx_lim register * Channel n Tx event configuration register */ typedef union { struct { - /** tx_lim_ch0 : R/W; bitpos: [8:0]; default: 128; + /** tx_lim_chn : R/W; bitpos: [8:0]; default: 128; * This register is used to configure the maximum entries that CHANNELn can send out. */ - uint32_t tx_lim_ch0:9; - /** tx_loop_num_ch0 : R/W; bitpos: [18:9]; default: 0; + uint32_t tx_lim_chn: 9; + /** tx_loop_num_chn : R/W; bitpos: [18:9]; default: 0; * This register is used to configure the maximum loop count when tx_conti_mode is * valid. */ - uint32_t tx_loop_num_ch0:10; - /** tx_loop_cnt_en_ch0 : R/W; bitpos: [19]; default: 0; + uint32_t tx_loop_num_chn: 10; + /** tx_loop_cnt_en_chn : R/W; bitpos: [19]; default: 0; * This register is the enabled bit for loop count. */ - uint32_t tx_loop_cnt_en_ch0:1; - /** loop_count_reset_ch0 : WT; bitpos: [20]; default: 0; + uint32_t tx_loop_cnt_en_chn: 1; + /** loop_count_reset_chn : WT; bitpos: [20]; default: 0; * This register is used to reset the loop count when tx_conti_mode is valid. */ - uint32_t loop_count_reset_ch0:1; - /** loop_stop_en_ch0 : R/W; bitpos: [21]; default: 0; + uint32_t loop_count_reset_chn: 1; + /** loop_stop_en_chn : R/W; bitpos: [21]; default: 0; * This bit is used to enable the loop send stop function after the loop counter * counts to loop number for CHANNELn. */ - uint32_t loop_stop_en_ch0:1; - uint32_t reserved_22:10; + uint32_t loop_stop_en_chn: 1; + uint32_t reserved_22: 10; }; uint32_t val; } rmt_chn_tx_lim_reg_t; @@ -979,49 +991,47 @@ typedef union { * Set this bit to enable CHANNEL0 to start sending data synchronously with other * enabled channels. */ - uint32_t tx_sim_ch0:1; + uint32_t tx_sim_ch0: 1; /** tx_sim_ch1 : R/W; bitpos: [1]; default: 0; * Set this bit to enable CHANNEL1 to start sending data synchronously with other * enabled channels. */ - uint32_t tx_sim_ch1:1; + uint32_t tx_sim_ch1: 1; /** tx_sim_ch2 : R/W; bitpos: [2]; default: 0; * Set this bit to enable CHANNEL2 to start sending data synchronously with other * enabled channels. */ - uint32_t tx_sim_ch2:1; + uint32_t tx_sim_ch2: 1; /** tx_sim_ch3 : R/W; bitpos: [3]; default: 0; * Set this bit to enable CHANNEL3 to start sending data synchronously with other * enabled channels. */ - uint32_t tx_sim_ch3:1; + uint32_t tx_sim_ch3: 1; /** tx_sim_en : R/W; bitpos: [4]; default: 0; * This register is used to enable multiple of channels to start sending data * synchronously. */ - uint32_t tx_sim_en:1; - uint32_t reserved_5:27; + uint32_t tx_sim_en: 1; + uint32_t reserved_5: 27; }; uint32_t val; } rmt_tx_sim_reg_t; - /** Group: Rx event configuration registers */ /** Type of chm_rx_lim register * Channel m Rx event configuration register */ typedef union { struct { - /** rx_lim_ch4 : R/W; bitpos: [8:0]; default: 128; + /** rx_lim_chm : R/W; bitpos: [8:0]; default: 128; * This register is used to configure the maximum entries that CHANNELm can receive. */ - uint32_t rx_lim_ch4:9; - uint32_t reserved_9:23; + uint32_t rx_lim_chm: 9; + uint32_t reserved_9: 23; }; uint32_t val; } rmt_chm_rx_lim_reg_t; - /** Group: Version register */ /** Type of date register * RMT version register @@ -1031,25 +1041,20 @@ typedef union { /** date : R/W; bitpos: [27:0]; default: 35655953; * This is the version register. */ - uint32_t date:28; - uint32_t reserved_28:4; + uint32_t date: 28; + uint32_t reserved_28: 4; }; uint32_t val; } rmt_date_reg_t; - -typedef struct { +typedef struct rmt_dev_t { volatile rmt_chndata_reg_t chndata[4]; volatile rmt_chmdata_reg_t chmdata[4]; volatile rmt_chnconf0_reg_t chnconf0[4]; - volatile rmt_chmconf0_reg_t ch4conf0; - volatile rmt_chmconf1_reg_t ch4conf1; - volatile rmt_chmconf0_reg_t ch5conf0; - volatile rmt_chmconf1_reg_t ch5conf1; - volatile rmt_chmconf0_reg_t ch6conf0; - volatile rmt_chmconf1_reg_t ch6conf1; - volatile rmt_chmconf0_reg_t ch7conf0; - volatile rmt_chmconf1_reg_t ch7conf1; + volatile struct { + rmt_chmconf0_reg_t conf0; + rmt_chmconf1_reg_t conf1; + } chmconf[4]; volatile rmt_chnstatus_reg_t chnstatus[4]; volatile rmt_chmstatus_reg_t chmstatus[4]; volatile rmt_int_raw_reg_t int_raw; @@ -1066,6 +1071,7 @@ typedef struct { volatile rmt_date_reg_t date; } rmt_dev_t; +extern rmt_dev_t RMT; #ifndef __cplusplus _Static_assert(sizeof(rmt_dev_t) == 0xd0, "Invalid size of rmt_dev_t structure"); diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8c2ef769b84..aba4e39aa3e 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -49,7 +49,7 @@ #define SOC_RTC_FAST_MEM_SUPPORTED 1 #define SOC_RTC_MEM_SUPPORTED 1 // #define SOC_I2S_SUPPORTED 1 //TODO: IDF-6508 -// #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476 +#define SOC_RMT_SUPPORTED 1 // #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551 // #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503 // #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510 @@ -271,19 +271,20 @@ /*--------------------------- RMT CAPS ---------------------------------------*/ #define SOC_RMT_GROUPS 1U /*!< One RMT group */ -#define SOC_RMT_TX_CANDIDATES_PER_GROUP 2 /*!< Number of channels that capable of Transmit */ -#define SOC_RMT_RX_CANDIDATES_PER_GROUP 2 /*!< Number of channels that capable of Receive */ -#define SOC_RMT_CHANNELS_PER_GROUP 4 /*!< Total 4 channels */ +#define SOC_RMT_TX_CANDIDATES_PER_GROUP 4 /*!< Number of channels that capable of Transmit in each group */ +#define SOC_RMT_RX_CANDIDATES_PER_GROUP 4 /*!< Number of channels that capable of Receive in each group */ +#define SOC_RMT_CHANNELS_PER_GROUP 8 /*!< Total 8 channels */ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ #define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ -// #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ -// #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ //TODO: IDF-7476 +#define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ +#define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ #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_RC_FAST 1 /*!< Support set RC_FAST as the RMT clock source */ +// #define SOC_RMT_SUPPORT_RC_FAST 1 /*!< Support set RC_FAST clock as the RMT clock source */ +#define SOC_RMT_SUPPORT_DMA 1 /*!< RMT peripheral can connect to DMA channel */ /*-------------------------- MCPWM CAPS --------------------------------------*/ #define SOC_MCPWM_GROUPS (2U) ///< 2 MCPWM groups on the chip (i.e., the number of independent MCPWM peripherals) diff --git a/components/soc/esp32p4/ld/esp32p4.peripherals.ld b/components/soc/esp32p4/ld/esp32p4.peripherals.ld index 4d395a30b61..4085a915e41 100644 --- a/components/soc/esp32p4/ld/esp32p4.peripherals.ld +++ b/components/soc/esp32p4/ld/esp32p4.peripherals.ld @@ -17,8 +17,8 @@ PROVIDE ( SPIMEM3 = 0x5008F000 ); PROVIDE ( I2C0 = 0x500C4000 ); PROVIDE ( I2C1 = 0x500C5000 ); PROVIDE ( UHCI0 = 0x500DF000 ); -PROVIDE ( RMT = 0x500D4000 ); -PROVIDE ( RMTMEM = 0x500D4800 ); +PROVIDE ( RMT = 0x500A2000 ); +PROVIDE ( RMTMEM = 0x500A2800 ); PROVIDE ( LEDC = 0x500D3000 ); PROVIDE ( TIMERG0 = 0x500C2000 ); PROVIDE ( TIMERG1 = 0x500C3000 ); diff --git a/components/soc/esp32p4/rmt_periph.c b/components/soc/esp32p4/rmt_periph.c index 650b4ddcf1f..74d73690c9c 100644 --- a/components/soc/esp32p4/rmt_periph.c +++ b/components/soc/esp32p4/rmt_periph.c @@ -8,5 +8,44 @@ #include "soc/gpio_sig_map.h" const rmt_signal_conn_t rmt_periph_signals = { - + .groups = { + [0] = { + .module = PERIPH_RMT_MODULE, + .irq = ETS_RMT_INTR_SOURCE, + .channels = { + [0] = { + .tx_sig = RMT_SIG_PAD_OUT0_IDX, + .rx_sig = -1 + }, + [1] = { + .tx_sig = RMT_SIG_PAD_OUT1_IDX, + .rx_sig = -1 + }, + [2] = { + .tx_sig = RMT_SIG_PAD_OUT2_IDX, + .rx_sig = -1 + }, + [3] = { + .tx_sig = RMT_SIG_PAD_OUT3_IDX, + .rx_sig = -1 + }, + [4] = { + .tx_sig = -1, + .rx_sig = RMT_SIG_PAD_IN0_IDX + }, + [5] = { + .tx_sig = -1, + .rx_sig = RMT_SIG_PAD_IN1_IDX + }, + [6] = { + .tx_sig = -1, + .rx_sig = RMT_SIG_PAD_IN2_IDX + }, + [7] = { + .tx_sig = -1, + .rx_sig = RMT_SIG_PAD_IN3_IDX + } + } + } + } }; diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 16372cc25ef..d5ceea9dbc9 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -141,7 +141,6 @@ api-reference/peripherals/spi_master.rst api-reference/peripherals/index.rst api-reference/peripherals/sdmmc_host.rst api-reference/peripherals/uart.rst -api-reference/peripherals/rmt.rst api-reference/kconfig.rst api-reference/network/esp_openthread.rst api-reference/network/esp_eth.rst diff --git a/examples/peripherals/rmt/dshot_esc/README.md b/examples/peripherals/rmt/dshot_esc/README.md index defe8146369..01d634c3d5c 100644 --- a/examples/peripherals/rmt/dshot_esc/README.md +++ b/examples/peripherals/rmt/dshot_esc/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # RMT Infinite Loop Transmit Example -- Dshot ESC (Electronic Speed Controller) (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/rmt/ir_nec_transceiver/README.md b/examples/peripherals/rmt/ir_nec_transceiver/README.md index 6f21c50abec..fee7164d27c 100644 --- a/examples/peripherals/rmt/ir_nec_transceiver/README.md +++ b/examples/peripherals/rmt/ir_nec_transceiver/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # IR NEC Encoding and Decoding Example (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/rmt/led_strip/README.md b/examples/peripherals/rmt/led_strip/README.md index 774838a81b0..23e42f040da 100644 --- a/examples/peripherals/rmt/led_strip/README.md +++ b/examples/peripherals/rmt/led_strip/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # RMT Transmit Example -- LED Strip (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/rmt/musical_buzzer/README.md b/examples/peripherals/rmt/musical_buzzer/README.md index 7b16fd241d8..a458a070b6d 100644 --- a/examples/peripherals/rmt/musical_buzzer/README.md +++ b/examples/peripherals/rmt/musical_buzzer/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | # RMT Transmit Loop Count Example -- Musical Buzzer diff --git a/examples/peripherals/rmt/onewire/README.md b/examples/peripherals/rmt/onewire/README.md index f218e4689ba..1cb065eafae 100644 --- a/examples/peripherals/rmt/onewire/README.md +++ b/examples/peripherals/rmt/onewire/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # Advanced RMT Transmit & Receive Example -- Simulate 1-Wire Bus diff --git a/examples/peripherals/rmt/stepper_motor/README.md b/examples/peripherals/rmt/stepper_motor/README.md index 772a888393b..b1048c08cde 100644 --- a/examples/peripherals/rmt/stepper_motor/README.md +++ b/examples/peripherals/rmt/stepper_motor/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # RMT Based Stepper Motor Smooth Controller From cb4b7988678e7ff0e723477cc6f152eda2d0e96e Mon Sep 17 00:00:00 2001 From: xuxiao Date: Thu, 14 Sep 2023 11:21:49 +0800 Subject: [PATCH 32/71] fix(wifi): fix some esp32c6 wifi bugs --- components/esp_wifi/include/esp_now.h | 4 +++- .../include/esp_private/esp_wifi_he_types_private.h | 8 ++++---- components/esp_wifi/include/esp_wifi_he_types.h | 7 +++---- components/esp_wifi/lib | 2 +- examples/common_components/iperf/wifi_stats.c | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/components/esp_wifi/include/esp_now.h b/components/esp_wifi/include/esp_now.h index 2a398566010..728c69ba5e5 100644 --- a/components/esp_wifi/include/esp_now.h +++ b/components/esp_wifi/include/esp_now.h @@ -264,7 +264,9 @@ esp_err_t esp_now_mod_peer(const esp_now_peer_info_t *peer); * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_wifi_config_espnow_rate(wifi_interface_t ifx, wifi_phy_rate_t rate); +esp_err_t esp_wifi_config_espnow_rate(wifi_interface_t ifx, wifi_phy_rate_t rate) + __attribute__((deprecated("This API can be only used when rate is non-HE rate, \ + please use esp_now_set_peer_rate_config if you want full support of the rate."))); /** * @brief Set ESPNOW rate config for each peer diff --git a/components/esp_wifi/include/esp_private/esp_wifi_he_types_private.h b/components/esp_wifi/include/esp_private/esp_wifi_he_types_private.h index f807cd60aaf..4aa855fbda9 100644 --- a/components/esp_wifi/include/esp_private/esp_wifi_he_types_private.h +++ b/components/esp_wifi/include/esp_private/esp_wifi_he_types_private.h @@ -235,10 +235,10 @@ typedef struct { int64_t tx_start_time; int64_t tx_seqno_time; int64_t tx_muedca_time; - int64_t tx_max_muedca_time; - int64_t tx_min_muedca_time; - int64_t tx_tot_muedca_time; - int64_t muedca_times; + uint32_t tx_max_muedca_time; + uint32_t tx_min_muedca_time; + uint32_t tx_tot_muedca_time; + uint32_t muedca_times; uint32_t tx_muedca_enable; /* count TX times within mu-timer working */ uint32_t collision; uint32_t timeout; diff --git a/components/esp_wifi/include/esp_wifi_he_types.h b/components/esp_wifi/include/esp_wifi_he_types.h index f7c1b9a59ed..01f753dddb1 100644 --- a/components/esp_wifi/include/esp_wifi_he_types.h +++ b/components/esp_wifi/include/esp_wifi_he_types.h @@ -158,12 +158,11 @@ typedef struct { unsigned : 15; /**< reserved */ unsigned : 2; /**< reserved */ unsigned noise_floor : 8; /**< the noise floor of the reception frame */ - signed data_rssi : 8; /**< the RSSI of the DATA field */ - unsigned : 8; /**< reserved */ - unsigned : 8; /**< reserved */ unsigned channel : 4; /**< the primary channel */ unsigned second : 4; /**< the second channel if in HT40 */ - unsigned : 24; /**< reserved */ + unsigned : 8; /**< reserved */ + unsigned : 8; /**< reserved */ + unsigned : 32; /**< reserved */ unsigned : 32; /**< reserved */ unsigned : 2; /**< reserved */ unsigned : 4; /**< reserved */ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index d5352da6c4f..7759f9bdf08 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit d5352da6c4f6e5d460a8f5af957b4e47420e7782 +Subproject commit 7759f9bdf087eb7fb31e4a612b4d310633fb4dcb diff --git a/examples/common_components/iperf/wifi_stats.c b/examples/common_components/iperf/wifi_stats.c index 5fe1aa52993..e3b6d934631 100644 --- a/examples/common_components/iperf/wifi_stats.c +++ b/examples/common_components/iperf/wifi_stats.c @@ -210,7 +210,7 @@ int wifi_cmd_get_tx_statistics(int argc, char **argv) tx_stats.collision, tx_stats.timeout); float tot_rtt_ms = (float) tx_stats.tx_tot_rtt / (float) 1000; - printf("(test)aci:%" PRIu8 ", seqno_rtt[%" PRIu32 ",%" PRIu32 "], hw_rtt[%" PRIu32 ", %" PRIu32 "], muedca[enable:%" PRIu32 ", times:%" PRIi64 ", %.2f, %.2f, tot:%.2f], avg:%.3f ms, tot:%.3f secs\n", + printf("(test)aci:%" PRIu8 ", seqno_rtt[%" PRIu32 ",%" PRIu32 "], hw_rtt[%" PRIu32 ", %" PRIu32 "], muedca[enable:%" PRIu32 ", times:%" PRIu32 ", %.2f, %.2f, tot:%.2f], avg:%.3f ms, tot:%.3f secs\n", i, tx_stats.tx_seq_min_rtt, tx_stats.tx_seq_max_rtt, From 6d87100a7053196b704686083cb287ef0c3aaaab Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 4 Aug 2023 15:00:15 +0200 Subject: [PATCH 33/71] feat(examples): add local components via idf_component.yml Specifying all the dependencies (managed and local) in the manifest makes it easier for users to see every component the example depends on. --- .../bluetooth/esp_ble_mesh/aligenie_demo/CMakeLists.txt | 5 ----- .../esp_ble_mesh/aligenie_demo/main/idf_component.yml | 9 +++++++++ .../directed_forwarding/df_client/CMakeLists.txt | 5 ----- .../directed_forwarding/df_client/main/idf_component.yml | 9 +++++++++ .../directed_forwarding/df_server/CMakeLists.txt | 4 ---- .../directed_forwarding/df_server/main/idf_component.yml | 9 +++++++++ .../fast_provisioning/fast_prov_client/CMakeLists.txt | 3 --- .../fast_prov_client/main/idf_component.yml | 5 +++++ .../fast_provisioning/fast_prov_server/CMakeLists.txt | 3 --- .../fast_prov_server/main/idf_component.yml | 5 +++++ .../onoff_models/onoff_client/CMakeLists.txt | 4 ---- .../onoff_models/onoff_client/main/idf_component.yml | 7 +++++++ .../onoff_models/onoff_server/CMakeLists.txt | 2 -- .../onoff_models/onoff_server/main/idf_component.yml | 3 +++ .../bluetooth/esp_ble_mesh/provisioner/CMakeLists.txt | 2 -- .../esp_ble_mesh/provisioner/main/idf_component.yml | 3 +++ .../remote_provisioning/rpr_client/CMakeLists.txt | 5 ----- .../rpr_client/main/idf_component.yml | 9 +++++++++ .../remote_provisioning/rpr_server/CMakeLists.txt | 4 ---- .../rpr_server/main/idf_component.yml | 7 +++++++ .../remote_provisioning/unprov_dev/CMakeLists.txt | 4 ---- .../unprov_dev/main/idf_component.yml | 7 +++++++ .../sensor_models/sensor_client/CMakeLists.txt | 3 --- .../sensor_models/sensor_client/main/idf_component.yml | 5 +++++ .../sensor_models/sensor_server/CMakeLists.txt | 2 -- .../sensor_models/sensor_server/main/idf_component.yml | 3 +++ .../vendor_models/vendor_client/CMakeLists.txt | 4 ---- .../vendor_models/vendor_client/main/idf_component.yml | 7 +++++++ .../vendor_models/vendor_server/CMakeLists.txt | 2 -- .../vendor_models/vendor_server/main/idf_component.yml | 3 +++ .../bluetooth/esp_ble_mesh/wifi_coexist/CMakeLists.txt | 4 ---- .../esp_ble_mesh/wifi_coexist/main/idf_component.yml | 7 +++++++ .../bluetooth/hci/ble_adv_scan_combined/CMakeLists.txt | 3 --- .../hci/ble_adv_scan_combined/main/idf_component.yml | 3 +++ .../bluetooth/hci/controller_vhci_ble_adv/CMakeLists.txt | 3 --- .../hci/controller_vhci_ble_adv/main/idf_component.yml | 3 +++ .../bluetooth/nimble/ble_dynamic_service/CMakeLists.txt | 2 -- .../nimble/ble_dynamic_service/main/idf_component.yml | 3 +++ .../ble_enc_adv_data/enc_adv_data_cent/CMakeLists.txt | 2 -- .../enc_adv_data_cent/main/idf_component.yml | 3 +++ .../ble_enc_adv_data/enc_adv_data_prph/CMakeLists.txt | 2 -- .../enc_adv_data_prph/main/idf_component.yml | 3 +++ .../bluetooth/nimble/ble_htp/htp_cent/CMakeLists.txt | 2 -- .../nimble/ble_htp/htp_cent/main/idf_component.yml | 3 +++ .../nimble/ble_l2cap_coc/coc_blecent/CMakeLists.txt | 2 -- .../ble_l2cap_coc/coc_blecent/main/idf_component.yml | 3 +++ .../nimble/ble_l2cap_coc/coc_bleprph/CMakeLists.txt | 2 -- .../ble_l2cap_coc/coc_bleprph/main/idf_component.yml | 3 +++ examples/bluetooth/nimble/ble_multi_adv/CMakeLists.txt | 2 -- .../nimble/ble_multi_adv/main/idf_component.yml | 3 +++ .../ble_multi_conn/ble_multi_conn_cent/CMakeLists.txt | 2 -- .../ble_multi_conn_cent/main/idf_component.yml | 3 +++ .../ble_multi_conn/ble_multi_conn_prph/CMakeLists.txt | 2 -- .../ble_multi_conn_prph/main/idf_component.yml | 3 +++ .../bluetooth/nimble/ble_periodic_adv/CMakeLists.txt | 1 - .../nimble/ble_periodic_adv/main/idf_component.yml | 3 +++ .../bluetooth/nimble/ble_periodic_sync/CMakeLists.txt | 1 - .../nimble/ble_periodic_sync/main/idf_component.yml | 3 +++ .../bluetooth/nimble/ble_phy/phy_cent/CMakeLists.txt | 2 -- .../nimble/ble_phy/phy_cent/main/idf_component.yml | 3 +++ .../bluetooth/nimble/ble_phy/phy_prph/CMakeLists.txt | 2 -- .../nimble/ble_phy/phy_prph/main/idf_component.yml | 3 +++ .../proximity_sensor_cent/CMakeLists.txt | 2 -- .../proximity_sensor_cent/main/idf_component.yml | 3 +++ .../bluetooth/nimble/ble_spp/spp_client/CMakeLists.txt | 2 -- .../nimble/ble_spp/spp_client/main/idf_component.yml | 3 +++ .../bluetooth/nimble/ble_spp/spp_server/CMakeLists.txt | 2 -- .../nimble/ble_spp/spp_server/main/idf_component.yml | 3 +++ examples/bluetooth/nimble/blecent/CMakeLists.txt | 2 -- examples/bluetooth/nimble/blecent/main/idf_component.yml | 3 +++ examples/bluetooth/nimble/bleprph/CMakeLists.txt | 2 -- examples/bluetooth/nimble/bleprph/main/idf_component.yml | 3 +++ examples/bluetooth/nimble/power_save/CMakeLists.txt | 2 -- .../bluetooth/nimble/power_save/main/idf_component.yml | 3 +++ .../protocol_examples_tapif_io/README.md | 8 +++++--- examples/ethernet/iperf/CMakeLists.txt | 4 ---- examples/ethernet/iperf/main/idf_component.yml | 7 +++++++ examples/network/bridge/CMakeLists.txt | 2 -- examples/network/bridge/main/idf_component.yml | 3 +++ examples/network/eth2ap/CMakeLists.txt | 2 -- examples/network/eth2ap/main/idf_component.yml | 3 +++ examples/network/simple_sniffer/CMakeLists.txt | 2 -- examples/network/simple_sniffer/main/idf_component.yml | 2 ++ examples/network/sta2eth/CMakeLists.txt | 4 ---- examples/network/sta2eth/main/idf_component.yml | 4 ++++ examples/network/vlan_support/CMakeLists.txt | 2 -- examples/network/vlan_support/main/idf_component.yml | 3 +++ examples/openthread/ot_br/CMakeLists.txt | 5 ----- examples/openthread/ot_br/main/idf_component.yml | 4 ++++ examples/openthread/ot_cli/CMakeLists.txt | 2 -- examples/openthread/ot_cli/main/idf_component.yml | 2 ++ examples/peripherals/i2c/i2c_tools/CMakeLists.txt | 2 -- .../peripherals/i2c/i2c_tools/main/idf_component.yml | 7 +++++++ examples/peripherals/usb/host/uvc/CMakeLists.txt | 2 -- examples/peripherals/usb/host/uvc/main/idf_component.yml | 2 ++ examples/phy/cert_test/CMakeLists.txt | 2 -- examples/phy/cert_test/main/idf_component.yml | 7 +++++++ examples/protocols/esp_http_client/CMakeLists.txt | 3 --- .../protocols/esp_http_client/main/idf_component.yml | 7 +++++++ examples/protocols/esp_local_ctrl/CMakeLists.txt | 3 --- examples/protocols/esp_local_ctrl/main/idf_component.yml | 2 ++ examples/protocols/http_request/CMakeLists.txt | 3 --- examples/protocols/http_request/main/idf_component.yml | 3 +++ .../protocols/http_server/advanced_tests/CMakeLists.txt | 3 --- .../http_server/advanced_tests/main/idf_component.yml | 3 +++ .../protocols/http_server/async_handlers/CMakeLists.txt | 3 --- .../http_server/async_handlers/main/idf_component.yml | 3 +++ .../protocols/http_server/file_serving/CMakeLists.txt | 3 --- .../http_server/file_serving/main/idf_component.yml | 3 +++ .../http_server/persistent_sockets/CMakeLists.txt | 3 --- .../persistent_sockets/main/idf_component.yml | 3 +++ .../protocols/http_server/restful_server/CMakeLists.txt | 2 -- .../http_server/restful_server/main/idf_component.yml | 2 ++ examples/protocols/http_server/simple/CMakeLists.txt | 3 --- .../protocols/http_server/simple/main/idf_component.yml | 7 +++++++ .../protocols/http_server/ws_echo_server/CMakeLists.txt | 3 --- .../http_server/ws_echo_server/main/idf_component.yml | 3 +++ examples/protocols/https_mbedtls/CMakeLists.txt | 3 --- examples/protocols/https_mbedtls/main/idf_component.yml | 3 +++ examples/protocols/https_request/CMakeLists.txt | 3 --- examples/protocols/https_request/main/idf_component.yml | 3 +++ examples/protocols/https_server/simple/CMakeLists.txt | 3 --- .../protocols/https_server/simple/main/idf_component.yml | 3 +++ .../protocols/https_server/wss_server/CMakeLists.txt | 3 --- .../https_server/wss_server/main/idf_component.yml | 3 +++ examples/protocols/https_x509_bundle/CMakeLists.txt | 3 --- .../protocols/https_x509_bundle/main/idf_component.yml | 3 +++ examples/protocols/icmp_echo/CMakeLists.txt | 3 --- examples/protocols/icmp_echo/main/idf_component.yml | 3 +++ examples/protocols/l2tap/CMakeLists.txt | 2 -- examples/protocols/l2tap/main/idf_component.yml | 3 +++ .../protocols/modbus/serial/mb_master/CMakeLists.txt | 2 -- .../modbus/serial/mb_master/main/idf_component.yml | 2 ++ examples/protocols/modbus/serial/mb_slave/CMakeLists.txt | 2 -- .../modbus/serial/mb_slave/main/idf_component.yml | 2 ++ .../protocols/modbus/tcp/mb_tcp_master/CMakeLists.txt | 5 ----- .../modbus/tcp/mb_tcp_master/main/idf_component.yml | 4 ++++ .../protocols/modbus/tcp/mb_tcp_slave/CMakeLists.txt | 4 ---- .../modbus/tcp/mb_tcp_slave/main/idf_component.yml | 4 ++++ examples/protocols/mqtt/ssl/CMakeLists.txt | 3 --- examples/protocols/mqtt/ssl/main/idf_component.yml | 3 +++ examples/protocols/mqtt/ssl_ds/CMakeLists.txt | 3 --- examples/protocols/mqtt/ssl_ds/main/idf_component.yml | 2 ++ examples/protocols/mqtt/ssl_mutual_auth/CMakeLists.txt | 3 --- .../mqtt/ssl_mutual_auth/main/idf_component.yml | 3 +++ examples/protocols/mqtt/ssl_psk/CMakeLists.txt | 3 --- examples/protocols/mqtt/ssl_psk/main/idf_component.yml | 3 +++ examples/protocols/mqtt/tcp/CMakeLists.txt | 3 --- examples/protocols/mqtt/tcp/main/idf_component.yml | 3 +++ examples/protocols/mqtt/ws/CMakeLists.txt | 3 --- examples/protocols/mqtt/ws/main/idf_component.yml | 3 +++ examples/protocols/mqtt/wss/CMakeLists.txt | 3 --- examples/protocols/mqtt/wss/main/idf_component.yml | 3 +++ examples/protocols/mqtt5/CMakeLists.txt | 3 --- examples/protocols/mqtt5/main/idf_component.yml | 3 +++ examples/protocols/smtp_client/CMakeLists.txt | 2 -- examples/protocols/smtp_client/main/idf_component.yml | 3 +++ examples/protocols/sntp/CMakeLists.txt | 3 --- examples/protocols/sntp/main/idf_component.yml | 3 +++ examples/protocols/sockets/icmpv6_ping/CMakeLists.txt | 2 -- .../protocols/sockets/icmpv6_ping/main/idf_component.yml | 3 +++ examples/protocols/sockets/non_blocking/CMakeLists.txt | 3 --- .../sockets/non_blocking/main/idf_component.yml | 3 +++ examples/protocols/sockets/tcp_client/CMakeLists.txt | 2 -- .../protocols/sockets/tcp_client/main/idf_component.yml | 7 +++++++ .../sockets/tcp_client_multi_net/CMakeLists.txt | 3 --- .../sockets/tcp_client_multi_net/main/idf_component.yml | 3 +++ examples/protocols/sockets/tcp_server/CMakeLists.txt | 3 --- .../protocols/sockets/tcp_server/main/idf_component.yml | 3 +++ .../sockets/tcp_transport_client/CMakeLists.txt | 3 --- .../sockets/tcp_transport_client/main/idf_component.yml | 3 +++ examples/protocols/sockets/udp_client/CMakeLists.txt | 5 ----- .../protocols/sockets/udp_client/main/idf_component.yml | 9 +++++++++ examples/protocols/sockets/udp_multicast/CMakeLists.txt | 3 --- .../sockets/udp_multicast/main/idf_component.yml | 3 +++ examples/protocols/sockets/udp_server/CMakeLists.txt | 3 --- .../protocols/sockets/udp_server/main/idf_component.yml | 3 +++ examples/system/console/advanced_usb_cdc/CMakeLists.txt | 2 -- .../console/advanced_usb_cdc/main/idf_component.yml | 7 +++++++ examples/system/console/basic/CMakeLists.txt | 2 -- examples/system/console/basic/main/idf_component.yml | 7 +++++++ examples/system/ota/advanced_https_ota/CMakeLists.txt | 3 --- .../system/ota/advanced_https_ota/main/idf_component.yml | 3 +++ examples/system/ota/native_ota_example/CMakeLists.txt | 3 --- .../system/ota/native_ota_example/main/idf_component.yml | 3 +++ examples/system/ota/pre_encrypted_ota/CMakeLists.txt | 1 - .../system/ota/pre_encrypted_ota/main/idf_component.yml | 2 ++ examples/system/ota/simple_ota_example/CMakeLists.txt | 3 --- .../system/ota/simple_ota_example/main/idf_component.yml | 3 +++ examples/wifi/ftm/CMakeLists.txt | 2 -- examples/wifi/ftm/main/idf_component.yml | 7 +++++++ examples/wifi/iperf/CMakeLists.txt | 3 --- examples/wifi/iperf/main/idf_component.yml | 5 +++++ examples/wifi/itwt/CMakeLists.txt | 2 -- examples/wifi/itwt/main/idf_component.yml | 9 +++++++++ examples/wifi/wifi_aware/nan_console/CMakeLists.txt | 2 -- .../wifi/wifi_aware/nan_console/main/idf_component.yml | 7 +++++++ examples/zigbee/esp_zigbee_gateway/CMakeLists.txt | 1 - .../zigbee/esp_zigbee_gateway/main/idf_component.yml | 2 ++ 199 files changed, 400 insertions(+), 272 deletions(-) create mode 100644 examples/bluetooth/esp_ble_mesh/aligenie_demo/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/provisioner/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/main/idf_component.yml create mode 100644 examples/bluetooth/esp_ble_mesh/wifi_coexist/main/idf_component.yml create mode 100644 examples/bluetooth/hci/ble_adv_scan_combined/main/idf_component.yml create mode 100644 examples/bluetooth/hci/controller_vhci_ble_adv/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_dynamic_service/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_htp/htp_cent/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_multi_adv/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_periodic_adv/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_periodic_sync/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_phy/phy_cent/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_phy/phy_prph/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_spp/spp_client/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/ble_spp/spp_server/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/blecent/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/bleprph/main/idf_component.yml create mode 100644 examples/bluetooth/nimble/power_save/main/idf_component.yml create mode 100644 examples/ethernet/iperf/main/idf_component.yml create mode 100644 examples/network/bridge/main/idf_component.yml create mode 100644 examples/network/eth2ap/main/idf_component.yml create mode 100644 examples/network/vlan_support/main/idf_component.yml create mode 100644 examples/peripherals/i2c/i2c_tools/main/idf_component.yml create mode 100644 examples/phy/cert_test/main/idf_component.yml create mode 100644 examples/protocols/esp_http_client/main/idf_component.yml create mode 100644 examples/protocols/http_request/main/idf_component.yml create mode 100644 examples/protocols/http_server/advanced_tests/main/idf_component.yml create mode 100644 examples/protocols/http_server/async_handlers/main/idf_component.yml create mode 100644 examples/protocols/http_server/file_serving/main/idf_component.yml create mode 100644 examples/protocols/http_server/persistent_sockets/main/idf_component.yml create mode 100644 examples/protocols/http_server/simple/main/idf_component.yml create mode 100644 examples/protocols/http_server/ws_echo_server/main/idf_component.yml create mode 100644 examples/protocols/https_mbedtls/main/idf_component.yml create mode 100644 examples/protocols/https_request/main/idf_component.yml create mode 100644 examples/protocols/https_server/simple/main/idf_component.yml create mode 100644 examples/protocols/https_server/wss_server/main/idf_component.yml create mode 100644 examples/protocols/https_x509_bundle/main/idf_component.yml create mode 100644 examples/protocols/icmp_echo/main/idf_component.yml create mode 100644 examples/protocols/l2tap/main/idf_component.yml create mode 100644 examples/protocols/mqtt/ssl/main/idf_component.yml create mode 100644 examples/protocols/mqtt/ssl_mutual_auth/main/idf_component.yml create mode 100644 examples/protocols/mqtt/ssl_psk/main/idf_component.yml create mode 100644 examples/protocols/mqtt/tcp/main/idf_component.yml create mode 100644 examples/protocols/mqtt/ws/main/idf_component.yml create mode 100644 examples/protocols/mqtt/wss/main/idf_component.yml create mode 100644 examples/protocols/mqtt5/main/idf_component.yml create mode 100644 examples/protocols/smtp_client/main/idf_component.yml create mode 100644 examples/protocols/sntp/main/idf_component.yml create mode 100644 examples/protocols/sockets/icmpv6_ping/main/idf_component.yml create mode 100644 examples/protocols/sockets/non_blocking/main/idf_component.yml create mode 100644 examples/protocols/sockets/tcp_client/main/idf_component.yml create mode 100644 examples/protocols/sockets/tcp_client_multi_net/main/idf_component.yml create mode 100644 examples/protocols/sockets/tcp_server/main/idf_component.yml create mode 100644 examples/protocols/sockets/tcp_transport_client/main/idf_component.yml create mode 100644 examples/protocols/sockets/udp_client/main/idf_component.yml create mode 100644 examples/protocols/sockets/udp_multicast/main/idf_component.yml create mode 100644 examples/protocols/sockets/udp_server/main/idf_component.yml create mode 100644 examples/system/console/advanced_usb_cdc/main/idf_component.yml create mode 100644 examples/system/console/basic/main/idf_component.yml create mode 100644 examples/system/ota/advanced_https_ota/main/idf_component.yml create mode 100644 examples/system/ota/native_ota_example/main/idf_component.yml create mode 100644 examples/system/ota/simple_ota_example/main/idf_component.yml create mode 100644 examples/wifi/ftm/main/idf_component.yml create mode 100644 examples/wifi/iperf/main/idf_component.yml create mode 100644 examples/wifi/itwt/main/idf_component.yml create mode 100644 examples/wifi/wifi_aware/nan_console/main/idf_component.yml diff --git a/examples/bluetooth/esp_ble_mesh/aligenie_demo/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/aligenie_demo/CMakeLists.txt index cc65be4c416..ef3d39b8447 100644 --- a/examples/bluetooth/esp_ble_mesh/aligenie_demo/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/aligenie_demo/CMakeLists.txt @@ -2,11 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(aligenie_demo) diff --git a/examples/bluetooth/esp_ble_mesh/aligenie_demo/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/aligenie_demo/main/idf_component.yml new file mode 100644 index 00000000000..b0da63e6f24 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/aligenie_demo/main/idf_component.yml @@ -0,0 +1,9 @@ +dependencies: + button: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + light_driver: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + example_nvs: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/CMakeLists.txt index b3ad88ab5a9..dcb999f2ef7 100644 --- a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/CMakeLists.txt @@ -2,10 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(onoff_client) diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/idf_component.yml new file mode 100644 index 00000000000..b0da63e6f24 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_client/main/idf_component.yml @@ -0,0 +1,9 @@ +dependencies: + button: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + light_driver: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + example_nvs: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/CMakeLists.txt index 884a4ed7dfb..c2e123e7689 100644 --- a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/CMakeLists.txt @@ -2,9 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(onoff_server) diff --git a/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/idf_component.yml new file mode 100644 index 00000000000..b0da63e6f24 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/directed_forwarding/df_server/main/idf_component.yml @@ -0,0 +1,9 @@ +dependencies: + button: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + light_driver: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + example_nvs: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/CMakeLists.txt index ed5bc4e1697..e3d91badd22 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/CMakeLists.txt @@ -2,8 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/fast_prov) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(fast_prov_client) diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/idf_component.yml new file mode 100644 index 00000000000..41f62627c0a --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + fast_prov: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/fast_prov diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/CMakeLists.txt index 8a4ec34714f..9191b78100a 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/CMakeLists.txt @@ -2,8 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/fast_prov) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(fast_prov_server) diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/idf_component.yml new file mode 100644 index 00000000000..41f62627c0a --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + fast_prov: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/fast_prov diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/CMakeLists.txt index 3409d2f1081..dcb999f2ef7 100644 --- a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/CMakeLists.txt @@ -2,9 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(onoff_client) diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/idf_component.yml new file mode 100644 index 00000000000..db1bab92c3d --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + button: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + example_nvs: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/CMakeLists.txt index 956058f4a96..c2e123e7689 100644 --- a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(onoff_server) diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/main/idf_component.yml new file mode 100644 index 00000000000..43c11335694 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_server/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init diff --git a/examples/bluetooth/esp_ble_mesh/provisioner/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/provisioner/CMakeLists.txt index a9f36c1a916..bb23642349b 100644 --- a/examples/bluetooth/esp_ble_mesh/provisioner/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/provisioner/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(provisioner) diff --git a/examples/bluetooth/esp_ble_mesh/provisioner/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/provisioner/main/idf_component.yml new file mode 100644 index 00000000000..43c11335694 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/provisioner/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/CMakeLists.txt index 0f89672c6d1..2fc83bab6bb 100644 --- a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/CMakeLists.txt @@ -2,10 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_mesh_provisioner) diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/idf_component.yml new file mode 100644 index 00000000000..b0da63e6f24 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/idf_component.yml @@ -0,0 +1,9 @@ +dependencies: + button: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + light_driver: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + example_nvs: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/CMakeLists.txt index 47d782116b7..c2e123e7689 100644 --- a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/CMakeLists.txt @@ -2,9 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(onoff_server) diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/idf_component.yml new file mode 100644 index 00000000000..ed186e502a0 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_server/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + light_driver: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + example_nvs: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/CMakeLists.txt index 47d782116b7..c2e123e7689 100644 --- a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/CMakeLists.txt @@ -2,9 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(onoff_server) diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/idf_component.yml new file mode 100644 index 00000000000..ed186e502a0 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/unprov_dev/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + light_driver: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/light_driver + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + example_nvs: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs diff --git a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/CMakeLists.txt index 6a63bb5acb6..df8cdc2a6f7 100644 --- a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/CMakeLists.txt @@ -2,8 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(sensor_client) diff --git a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/idf_component.yml new file mode 100644 index 00000000000..36733fdcb37 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + button: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init diff --git a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/CMakeLists.txt index 42b0863956e..a6d68ca161b 100644 --- a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(sensor_server) diff --git a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/main/idf_component.yml new file mode 100644 index 00000000000..43c11335694 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_server/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init diff --git a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/CMakeLists.txt index dfaac35fe23..aa900088996 100644 --- a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/CMakeLists.txt @@ -2,9 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(vendor_client) diff --git a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/idf_component.yml new file mode 100644 index 00000000000..db1bab92c3d --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + button: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/button + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + example_nvs: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs diff --git a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/CMakeLists.txt index 66a55b876dc..a389de923f1 100644 --- a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(vendor_server) diff --git a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/main/idf_component.yml new file mode 100644 index 00000000000..43c11335694 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_server/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init diff --git a/examples/bluetooth/esp_ble_mesh/wifi_coexist/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/wifi_coexist/CMakeLists.txt index bf5448c6527..63fc9622bd5 100644 --- a/examples/bluetooth/esp_ble_mesh/wifi_coexist/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/wifi_coexist/CMakeLists.txt @@ -2,9 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init - $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/fast_prov - $ENV{IDF_PATH}/examples/common_components/iperf) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(wifi_coexist) diff --git a/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/idf_component.yml b/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/idf_component.yml new file mode 100644 index 00000000000..9f4c98345f3 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + fast_prov: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/fast_prov + example_init: + path: ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init + iperf: + path: ${IDF_PATH}/examples/common_components/iperf diff --git a/examples/bluetooth/hci/ble_adv_scan_combined/CMakeLists.txt b/examples/bluetooth/hci/ble_adv_scan_combined/CMakeLists.txt index e0ff215dba9..f5e3555891e 100644 --- a/examples/bluetooth/hci/ble_adv_scan_combined/CMakeLists.txt +++ b/examples/bluetooth/hci/ble_adv_scan_combined/CMakeLists.txt @@ -2,8 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# This example uses an extra component for common functions for Bluetooth HCI layer. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/hci/hci_common_component) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_adv_scan) diff --git a/examples/bluetooth/hci/ble_adv_scan_combined/main/idf_component.yml b/examples/bluetooth/hci/ble_adv_scan_combined/main/idf_component.yml new file mode 100644 index 00000000000..99657414326 --- /dev/null +++ b/examples/bluetooth/hci/ble_adv_scan_combined/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + hci_common_component: + path: ${IDF_PATH}/examples/bluetooth/hci/hci_common_component diff --git a/examples/bluetooth/hci/controller_vhci_ble_adv/CMakeLists.txt b/examples/bluetooth/hci/controller_vhci_ble_adv/CMakeLists.txt index 0f6afaadc4a..f10daca8a72 100644 --- a/examples/bluetooth/hci/controller_vhci_ble_adv/CMakeLists.txt +++ b/examples/bluetooth/hci/controller_vhci_ble_adv/CMakeLists.txt @@ -2,8 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# This example uses an extra component for common functions for Bluetooth HCI layer. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/hci/hci_common_component) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_adv) diff --git a/examples/bluetooth/hci/controller_vhci_ble_adv/main/idf_component.yml b/examples/bluetooth/hci/controller_vhci_ble_adv/main/idf_component.yml new file mode 100644 index 00000000000..99657414326 --- /dev/null +++ b/examples/bluetooth/hci/controller_vhci_ble_adv/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + hci_common_component: + path: ${IDF_PATH}/examples/bluetooth/hci/hci_common_component diff --git a/examples/bluetooth/nimble/ble_dynamic_service/CMakeLists.txt b/examples/bluetooth/nimble/ble_dynamic_service/CMakeLists.txt index 28cd09e5371..ec090376e97 100644 --- a/examples/bluetooth/nimble/ble_dynamic_service/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_dynamic_service/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_dynamic_service) diff --git a/examples/bluetooth/nimble/ble_dynamic_service/main/idf_component.yml b/examples/bluetooth/nimble/ble_dynamic_service/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/ble_dynamic_service/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/CMakeLists.txt b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/CMakeLists.txt index 9fd41ea1d8e..3e162616436 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(enc_adv_data_cent) diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/idf_component.yml b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/CMakeLists.txt b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/CMakeLists.txt index 603a43c5098..ca984ef42ac 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(enc_adv_data_prph) diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/idf_component.yml b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/ble_htp/htp_cent/CMakeLists.txt b/examples/bluetooth/nimble/ble_htp/htp_cent/CMakeLists.txt index 5464a4ed1b4..598618f67c0 100644 --- a/examples/bluetooth/nimble/ble_htp/htp_cent/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_htp/htp_cent/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(htp_cent) diff --git a/examples/bluetooth/nimble/ble_htp/htp_cent/main/idf_component.yml b/examples/bluetooth/nimble/ble_htp/htp_cent/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/ble_htp/htp_cent/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/CMakeLists.txt b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/CMakeLists.txt index 2bd3526463c..6265291deca 100644 --- a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(coc_blecent) diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/idf_component.yml b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/CMakeLists.txt b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/CMakeLists.txt index 54e37540548..74e67340373 100644 --- a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(coc_bleprph) diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/idf_component.yml b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/ble_multi_adv/CMakeLists.txt b/examples/bluetooth/nimble/ble_multi_adv/CMakeLists.txt index 13fcb1c54dc..1870d856d78 100644 --- a/examples/bluetooth/nimble/ble_multi_adv/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_multi_adv/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_multi_adv) diff --git a/examples/bluetooth/nimble/ble_multi_adv/main/idf_component.yml b/examples/bluetooth/nimble/ble_multi_adv/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/ble_multi_adv/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/CMakeLists.txt b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/CMakeLists.txt index 06382888f1e..f443dbefda4 100644 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(blecent) diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/main/idf_component.yml b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/CMakeLists.txt b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/CMakeLists.txt index 59f95346232..0e8a4553f95 100644 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(bleprph) diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/idf_component.yml b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/ble_periodic_adv/CMakeLists.txt b/examples/bluetooth/nimble/ble_periodic_adv/CMakeLists.txt index a11db0a8cb2..eb90d28ab6c 100644 --- a/examples/bluetooth/nimble/ble_periodic_adv/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_periodic_adv/CMakeLists.txt @@ -1,7 +1,6 @@ # The following 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) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_periodic_adv) diff --git a/examples/bluetooth/nimble/ble_periodic_adv/main/idf_component.yml b/examples/bluetooth/nimble/ble_periodic_adv/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/ble_periodic_adv/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/ble_periodic_sync/CMakeLists.txt b/examples/bluetooth/nimble/ble_periodic_sync/CMakeLists.txt index 0cfa53d6f5a..74095c0ea8b 100644 --- a/examples/bluetooth/nimble/ble_periodic_sync/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_periodic_sync/CMakeLists.txt @@ -1,6 +1,5 @@ # The following 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) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_periodic_sync) diff --git a/examples/bluetooth/nimble/ble_periodic_sync/main/idf_component.yml b/examples/bluetooth/nimble/ble_periodic_sync/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/ble_periodic_sync/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/ble_phy/phy_cent/CMakeLists.txt b/examples/bluetooth/nimble/ble_phy/phy_cent/CMakeLists.txt index 585df842c55..b72760eacf7 100644 --- a/examples/bluetooth/nimble/ble_phy/phy_cent/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_phy/phy_cent/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(phy_cent) diff --git a/examples/bluetooth/nimble/ble_phy/phy_cent/main/idf_component.yml b/examples/bluetooth/nimble/ble_phy/phy_cent/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/ble_phy/phy_cent/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/ble_phy/phy_prph/CMakeLists.txt b/examples/bluetooth/nimble/ble_phy/phy_prph/CMakeLists.txt index ae9a5b0e9c9..793e1a330aa 100644 --- a/examples/bluetooth/nimble/ble_phy/phy_prph/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_phy/phy_prph/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(phy_prph) diff --git a/examples/bluetooth/nimble/ble_phy/phy_prph/main/idf_component.yml b/examples/bluetooth/nimble/ble_phy/phy_prph/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/ble_phy/phy_prph/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/CMakeLists.txt b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/CMakeLists.txt index 855567dfb7b..bfb3c5c81bb 100644 --- a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(proximity_sensor_cent) diff --git a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/idf_component.yml b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/ble_spp/spp_client/CMakeLists.txt b/examples/bluetooth/nimble/ble_spp/spp_client/CMakeLists.txt index 487f50656f9..615f271b6ca 100644 --- a/examples/bluetooth/nimble/ble_spp/spp_client/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_spp/spp_client/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(spp_client) diff --git a/examples/bluetooth/nimble/ble_spp/spp_client/main/idf_component.yml b/examples/bluetooth/nimble/ble_spp/spp_client/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/ble_spp/spp_client/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/ble_spp/spp_server/CMakeLists.txt b/examples/bluetooth/nimble/ble_spp/spp_server/CMakeLists.txt index 32da2da9a7e..99cadaff235 100644 --- a/examples/bluetooth/nimble/ble_spp/spp_server/CMakeLists.txt +++ b/examples/bluetooth/nimble/ble_spp/spp_server/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(spp_server) diff --git a/examples/bluetooth/nimble/ble_spp/spp_server/main/idf_component.yml b/examples/bluetooth/nimble/ble_spp/spp_server/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/ble_spp/spp_server/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/blecent/CMakeLists.txt b/examples/bluetooth/nimble/blecent/CMakeLists.txt index 06382888f1e..f443dbefda4 100644 --- a/examples/bluetooth/nimble/blecent/CMakeLists.txt +++ b/examples/bluetooth/nimble/blecent/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(blecent) diff --git a/examples/bluetooth/nimble/blecent/main/idf_component.yml b/examples/bluetooth/nimble/blecent/main/idf_component.yml new file mode 100644 index 00000000000..db8886afea4 --- /dev/null +++ b/examples/bluetooth/nimble/blecent/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_central_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils diff --git a/examples/bluetooth/nimble/bleprph/CMakeLists.txt b/examples/bluetooth/nimble/bleprph/CMakeLists.txt index 59f95346232..0e8a4553f95 100644 --- a/examples/bluetooth/nimble/bleprph/CMakeLists.txt +++ b/examples/bluetooth/nimble/bleprph/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(bleprph) diff --git a/examples/bluetooth/nimble/bleprph/main/idf_component.yml b/examples/bluetooth/nimble/bleprph/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/bleprph/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/bluetooth/nimble/power_save/CMakeLists.txt b/examples/bluetooth/nimble/power_save/CMakeLists.txt index 41d9ebf1290..908aa9b15a8 100644 --- a/examples/bluetooth/nimble/power_save/CMakeLists.txt +++ b/examples/bluetooth/nimble/power_save/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(power_save) diff --git a/examples/bluetooth/nimble/power_save/main/idf_component.yml b/examples/bluetooth/nimble/power_save/main/idf_component.yml new file mode 100644 index 00000000000..d6e735fe770 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + nimble_peripheral_utils: + path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils diff --git a/examples/common_components/protocol_examples_tapif_io/README.md b/examples/common_components/protocol_examples_tapif_io/README.md index c39394aa476..61566dcccf9 100644 --- a/examples/common_components/protocol_examples_tapif_io/README.md +++ b/examples/common_components/protocol_examples_tapif_io/README.md @@ -7,9 +7,11 @@ It could be used to route lwip traffic to host side network, typically when work ### Usage of the API -1) Add the path to this component to the `EXTRA_COMPONENT_DIRS` in your project makefile -```cmake -list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/common_components/tapif_io") +1) Add the path to this component to as a dependency to the `main` component of your project using the following idf_component.yml file: +```yaml +dependencies: + tapif_io: + path: ${IDF_PATH}/examples/common_components/tapif_io ``` 2) Include lwip and linux side of the configuration ```cpp diff --git a/examples/ethernet/iperf/CMakeLists.txt b/examples/ethernet/iperf/CMakeLists.txt index ff4d488339f..773736ed190 100644 --- a/examples/ethernet/iperf/CMakeLists.txt +++ b/examples/ethernet/iperf/CMakeLists.txt @@ -2,9 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components - $ENV{IDF_PATH}/examples/common_components/iperf - $ENV{IDF_PATH}/examples/ethernet/basic/components/ethernet_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ethernet_iperf) diff --git a/examples/ethernet/iperf/main/idf_component.yml b/examples/ethernet/iperf/main/idf_component.yml new file mode 100644 index 00000000000..8b9ecd9116b --- /dev/null +++ b/examples/ethernet/iperf/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + ethernet_init: + path: ${IDF_PATH}/examples/ethernet/basic/components/ethernet_init + iperf: + path: ${IDF_PATH}/examples/common_components/iperf diff --git a/examples/network/bridge/CMakeLists.txt b/examples/network/bridge/CMakeLists.txt index 3161df5b0dd..774bc527d7e 100644 --- a/examples/network/bridge/CMakeLists.txt +++ b/examples/network/bridge/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/ethernet/basic/components/ethernet_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(bridge) diff --git a/examples/network/bridge/main/idf_component.yml b/examples/network/bridge/main/idf_component.yml new file mode 100644 index 00000000000..8453ecc2191 --- /dev/null +++ b/examples/network/bridge/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + ethernet_init: + path: ${IDF_PATH}/examples/ethernet/basic/components/ethernet_init diff --git a/examples/network/eth2ap/CMakeLists.txt b/examples/network/eth2ap/CMakeLists.txt index daf2d1f3185..ec2b0f57d9b 100644 --- a/examples/network/eth2ap/CMakeLists.txt +++ b/examples/network/eth2ap/CMakeLists.txt @@ -1,6 +1,4 @@ cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/ethernet/basic/components/ethernet_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(eth2ap) diff --git a/examples/network/eth2ap/main/idf_component.yml b/examples/network/eth2ap/main/idf_component.yml new file mode 100644 index 00000000000..8453ecc2191 --- /dev/null +++ b/examples/network/eth2ap/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + ethernet_init: + path: ${IDF_PATH}/examples/ethernet/basic/components/ethernet_init diff --git a/examples/network/simple_sniffer/CMakeLists.txt b/examples/network/simple_sniffer/CMakeLists.txt index a314a64c390..5097b1500a4 100644 --- a/examples/network/simple_sniffer/CMakeLists.txt +++ b/examples/network/simple_sniffer/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/ethernet/basic/components/ethernet_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(simple_sniffer) diff --git a/examples/network/simple_sniffer/main/idf_component.yml b/examples/network/simple_sniffer/main/idf_component.yml index c407c54eb46..45810f2f6bc 100644 --- a/examples/network/simple_sniffer/main/idf_component.yml +++ b/examples/network/simple_sniffer/main/idf_component.yml @@ -1,2 +1,4 @@ dependencies: pcap: "^1.0.0" + ethernet_init: + path: ${IDF_PATH}/examples/ethernet/basic/components/ethernet_init diff --git a/examples/network/sta2eth/CMakeLists.txt b/examples/network/sta2eth/CMakeLists.txt index 11459c67f20..a565b19f348 100644 --- a/examples/network/sta2eth/CMakeLists.txt +++ b/examples/network/sta2eth/CMakeLists.txt @@ -2,9 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# This example needs a DNS server: let's use the simple DNS server implementation from captive portal example -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/http_server/captive_portal/components/dns_server - $ENV{IDF_PATH}/examples/ethernet/basic/components/ethernet_init) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(sta_to_eth) diff --git a/examples/network/sta2eth/main/idf_component.yml b/examples/network/sta2eth/main/idf_component.yml index bff20c669a8..21db5940d05 100644 --- a/examples/network/sta2eth/main/idf_component.yml +++ b/examples/network/sta2eth/main/idf_component.yml @@ -5,5 +5,9 @@ dependencies: rules: - if: "idf_version >=4.4" - if: "target in [esp32s2, esp32s3]" + dns_server: + path: ${IDF_PATH}/examples/protocols/http_server/captive_portal/components/dns_server + ethernet_init: + path: ${IDF_PATH}/examples/ethernet/basic/components/ethernet_init idf: "^5.0" diff --git a/examples/network/vlan_support/CMakeLists.txt b/examples/network/vlan_support/CMakeLists.txt index 4ed01ae191c..c70832fdbb2 100644 --- a/examples/network/vlan_support/CMakeLists.txt +++ b/examples/network/vlan_support/CMakeLists.txt @@ -3,8 +3,6 @@ # 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) - -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/ethernet/basic/components/ethernet_init) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(vlan_support) diff --git a/examples/network/vlan_support/main/idf_component.yml b/examples/network/vlan_support/main/idf_component.yml new file mode 100644 index 00000000000..8453ecc2191 --- /dev/null +++ b/examples/network/vlan_support/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + ethernet_init: + path: ${IDF_PATH}/examples/ethernet/basic/components/ethernet_init diff --git a/examples/openthread/ot_br/CMakeLists.txt b/examples/openthread/ot_br/CMakeLists.txt index 509229d9b07..93545935493 100644 --- a/examples/openthread/ot_br/CMakeLists.txt +++ b/examples/openthread/ot_br/CMakeLists.txt @@ -2,10 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common - $ENV{IDF_PATH}/examples/common_components/iperf) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(esp_ot_br) diff --git a/examples/openthread/ot_br/main/idf_component.yml b/examples/openthread/ot_br/main/idf_component.yml index 947edba2ddd..98376227fe3 100644 --- a/examples/openthread/ot_br/main/idf_component.yml +++ b/examples/openthread/ot_br/main/idf_component.yml @@ -6,3 +6,7 @@ dependencies: ## Required IDF version idf: version: ">=5.0" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common + iperf: + path: ${IDF_PATH}/examples/common_components/iperf diff --git a/examples/openthread/ot_cli/CMakeLists.txt b/examples/openthread/ot_cli/CMakeLists.txt index d677a901c98..b12d49bfa30 100644 --- a/examples/openthread/ot_cli/CMakeLists.txt +++ b/examples/openthread/ot_cli/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/iperf) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(esp_ot_cli) diff --git a/examples/openthread/ot_cli/main/idf_component.yml b/examples/openthread/ot_cli/main/idf_component.yml index 9d13c3b6159..ea2b9511152 100644 --- a/examples/openthread/ot_cli/main/idf_component.yml +++ b/examples/openthread/ot_cli/main/idf_component.yml @@ -4,3 +4,5 @@ dependencies: version: "~0.4.0" idf: version: ">=4.1.0" + iperf: + path: ${IDF_PATH}/examples/common_components/iperf diff --git a/examples/peripherals/i2c/i2c_tools/CMakeLists.txt b/examples/peripherals/i2c/i2c_tools/CMakeLists.txt index e482e2aaf57..c44548e53b3 100644 --- a/examples/peripherals/i2c/i2c_tools/CMakeLists.txt +++ b/examples/peripherals/i2c/i2c_tools/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(i2c_tools) diff --git a/examples/peripherals/i2c/i2c_tools/main/idf_component.yml b/examples/peripherals/i2c/i2c_tools/main/idf_component.yml new file mode 100644 index 00000000000..aacef0f4000 --- /dev/null +++ b/examples/peripherals/i2c/i2c_tools/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + cmd_nvs: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_nvs + cmd_wifi: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_wifi diff --git a/examples/peripherals/usb/host/uvc/CMakeLists.txt b/examples/peripherals/usb/host/uvc/CMakeLists.txt index e85e1a87120..9cab8a3bcb8 100644 --- a/examples/peripherals/usb/host/uvc/CMakeLists.txt +++ b/examples/peripherals/usb/host/uvc/CMakeLists.txt @@ -2,7 +2,5 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(usb-uvc) diff --git a/examples/peripherals/usb/host/uvc/main/idf_component.yml b/examples/peripherals/usb/host/uvc/main/idf_component.yml index 8b906ef6cfb..09a14cfce76 100644 --- a/examples/peripherals/usb/host/uvc/main/idf_component.yml +++ b/examples/peripherals/usb/host/uvc/main/idf_component.yml @@ -5,3 +5,5 @@ dependencies: mdns: rules: - if: "idf_version >= 5.0" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/phy/cert_test/CMakeLists.txt b/examples/phy/cert_test/CMakeLists.txt index 607964536c9..c34a1147cde 100644 --- a/examples/phy/cert_test/CMakeLists.txt +++ b/examples/phy/cert_test/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(cert_test) diff --git a/examples/phy/cert_test/main/idf_component.yml b/examples/phy/cert_test/main/idf_component.yml new file mode 100644 index 00000000000..aacef0f4000 --- /dev/null +++ b/examples/phy/cert_test/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + cmd_nvs: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_nvs + cmd_wifi: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_wifi diff --git a/examples/protocols/esp_http_client/CMakeLists.txt b/examples/protocols/esp_http_client/CMakeLists.txt index cf0ca4da7ad..e012d1a3fd0 100644 --- a/examples/protocols/esp_http_client/CMakeLists.txt +++ b/examples/protocols/esp_http_client/CMakeLists.txt @@ -2,10 +2,7 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) - if(${IDF_TARGET} STREQUAL "linux") - list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs) set(COMPONENTS main) endif() diff --git a/examples/protocols/esp_http_client/main/idf_component.yml b/examples/protocols/esp_http_client/main/idf_component.yml new file mode 100644 index 00000000000..c17c116c4bd --- /dev/null +++ b/examples/protocols/esp_http_client/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common + esp_stubs: + path: ${IDF_PATH}/examples/protocols/linux_stubs/esp_stubs + rules: + - if: "target in [linux]" diff --git a/examples/protocols/esp_local_ctrl/CMakeLists.txt b/examples/protocols/esp_local_ctrl/CMakeLists.txt index 507a362b520..ce8a5b0ba40 100644 --- a/examples/protocols/esp_local_ctrl/CMakeLists.txt +++ b/examples/protocols/esp_local_ctrl/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(esp_local_ctrl) diff --git a/examples/protocols/esp_local_ctrl/main/idf_component.yml b/examples/protocols/esp_local_ctrl/main/idf_component.yml index 39fbd718299..7bddebc1aa7 100644 --- a/examples/protocols/esp_local_ctrl/main/idf_component.yml +++ b/examples/protocols/esp_local_ctrl/main/idf_component.yml @@ -4,3 +4,5 @@ dependencies: ## Required IDF version idf: version: ">=5.0" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/http_request/CMakeLists.txt b/examples/protocols/http_request/CMakeLists.txt index cc403d31225..428aa223d18 100644 --- a/examples/protocols/http_request/CMakeLists.txt +++ b/examples/protocols/http_request/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(http_request) diff --git a/examples/protocols/http_request/main/idf_component.yml b/examples/protocols/http_request/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/http_request/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/http_server/advanced_tests/CMakeLists.txt b/examples/protocols/http_server/advanced_tests/CMakeLists.txt index 5b8311cf839..ced9a1e677d 100644 --- a/examples/protocols/http_server/advanced_tests/CMakeLists.txt +++ b/examples/protocols/http_server/advanced_tests/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(tests) diff --git a/examples/protocols/http_server/advanced_tests/main/idf_component.yml b/examples/protocols/http_server/advanced_tests/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/http_server/advanced_tests/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/http_server/async_handlers/CMakeLists.txt b/examples/protocols/http_server/async_handlers/CMakeLists.txt index 62cb350dd49..3ada908f263 100644 --- a/examples/protocols/http_server/async_handlers/CMakeLists.txt +++ b/examples/protocols/http_server/async_handlers/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(simple) diff --git a/examples/protocols/http_server/async_handlers/main/idf_component.yml b/examples/protocols/http_server/async_handlers/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/http_server/async_handlers/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/http_server/file_serving/CMakeLists.txt b/examples/protocols/http_server/file_serving/CMakeLists.txt index d9592f04410..b4edc23832f 100644 --- a/examples/protocols/http_server/file_serving/CMakeLists.txt +++ b/examples/protocols/http_server/file_serving/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(file_server) diff --git a/examples/protocols/http_server/file_serving/main/idf_component.yml b/examples/protocols/http_server/file_serving/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/http_server/file_serving/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/http_server/persistent_sockets/CMakeLists.txt b/examples/protocols/http_server/persistent_sockets/CMakeLists.txt index 11a6e8bb9d9..c2f23bebcd1 100644 --- a/examples/protocols/http_server/persistent_sockets/CMakeLists.txt +++ b/examples/protocols/http_server/persistent_sockets/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(persistent_sockets) diff --git a/examples/protocols/http_server/persistent_sockets/main/idf_component.yml b/examples/protocols/http_server/persistent_sockets/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/http_server/persistent_sockets/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/http_server/restful_server/CMakeLists.txt b/examples/protocols/http_server/restful_server/CMakeLists.txt index a077eb8fcca..7d7eaa220cc 100644 --- a/examples/protocols/http_server/restful_server/CMakeLists.txt +++ b/examples/protocols/http_server/restful_server/CMakeLists.txt @@ -1,7 +1,5 @@ cmake_minimum_required(VERSION 3.16) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(restful_server) diff --git a/examples/protocols/http_server/restful_server/main/idf_component.yml b/examples/protocols/http_server/restful_server/main/idf_component.yml index 39fbd718299..7bddebc1aa7 100644 --- a/examples/protocols/http_server/restful_server/main/idf_component.yml +++ b/examples/protocols/http_server/restful_server/main/idf_component.yml @@ -4,3 +4,5 @@ dependencies: ## Required IDF version idf: version: ">=5.0" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/http_server/simple/CMakeLists.txt b/examples/protocols/http_server/simple/CMakeLists.txt index e6994a73fdf..42acdd7cc75 100644 --- a/examples/protocols/http_server/simple/CMakeLists.txt +++ b/examples/protocols/http_server/simple/CMakeLists.txt @@ -2,10 +2,7 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) - if(${IDF_TARGET} STREQUAL "linux") - list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs") set(COMPONENTS main) endif() diff --git a/examples/protocols/http_server/simple/main/idf_component.yml b/examples/protocols/http_server/simple/main/idf_component.yml new file mode 100644 index 00000000000..c17c116c4bd --- /dev/null +++ b/examples/protocols/http_server/simple/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common + esp_stubs: + path: ${IDF_PATH}/examples/protocols/linux_stubs/esp_stubs + rules: + - if: "target in [linux]" diff --git a/examples/protocols/http_server/ws_echo_server/CMakeLists.txt b/examples/protocols/http_server/ws_echo_server/CMakeLists.txt index 7bbaf6c8f5d..f2f53ffd025 100644 --- a/examples/protocols/http_server/ws_echo_server/CMakeLists.txt +++ b/examples/protocols/http_server/ws_echo_server/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ws_echo_server) diff --git a/examples/protocols/http_server/ws_echo_server/main/idf_component.yml b/examples/protocols/http_server/ws_echo_server/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/http_server/ws_echo_server/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/https_mbedtls/CMakeLists.txt b/examples/protocols/https_mbedtls/CMakeLists.txt index e22321ac008..0233bc37e73 100644 --- a/examples/protocols/https_mbedtls/CMakeLists.txt +++ b/examples/protocols/https_mbedtls/CMakeLists.txt @@ -2,9 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(https_mbedtls) diff --git a/examples/protocols/https_mbedtls/main/idf_component.yml b/examples/protocols/https_mbedtls/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/https_mbedtls/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/https_request/CMakeLists.txt b/examples/protocols/https_request/CMakeLists.txt index d4e0c6a1dec..7222b1adf51 100644 --- a/examples/protocols/https_request/CMakeLists.txt +++ b/examples/protocols/https_request/CMakeLists.txt @@ -2,9 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(https_request) diff --git a/examples/protocols/https_request/main/idf_component.yml b/examples/protocols/https_request/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/https_request/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/https_server/simple/CMakeLists.txt b/examples/protocols/https_server/simple/CMakeLists.txt index 6fd8ca3926b..4cd82ede085 100644 --- a/examples/protocols/https_server/simple/CMakeLists.txt +++ b/examples/protocols/https_server/simple/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(https_server) diff --git a/examples/protocols/https_server/simple/main/idf_component.yml b/examples/protocols/https_server/simple/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/https_server/simple/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/https_server/wss_server/CMakeLists.txt b/examples/protocols/https_server/wss_server/CMakeLists.txt index 20c974ed16d..360d5db7794 100644 --- a/examples/protocols/https_server/wss_server/CMakeLists.txt +++ b/examples/protocols/https_server/wss_server/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(wss_server) diff --git a/examples/protocols/https_server/wss_server/main/idf_component.yml b/examples/protocols/https_server/wss_server/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/https_server/wss_server/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/https_x509_bundle/CMakeLists.txt b/examples/protocols/https_x509_bundle/CMakeLists.txt index 0c0444024ee..b911200e6bb 100644 --- a/examples/protocols/https_x509_bundle/CMakeLists.txt +++ b/examples/protocols/https_x509_bundle/CMakeLists.txt @@ -2,9 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(https_x509_bundle) diff --git a/examples/protocols/https_x509_bundle/main/idf_component.yml b/examples/protocols/https_x509_bundle/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/https_x509_bundle/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/icmp_echo/CMakeLists.txt b/examples/protocols/icmp_echo/CMakeLists.txt index 731a0c1b1ad..c63cf2a8299 100644 --- a/examples/protocols/icmp_echo/CMakeLists.txt +++ b/examples/protocols/icmp_echo/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(icmp_echo) diff --git a/examples/protocols/icmp_echo/main/idf_component.yml b/examples/protocols/icmp_echo/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/icmp_echo/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/l2tap/CMakeLists.txt b/examples/protocols/l2tap/CMakeLists.txt index b0c52c89c45..c978d634446 100644 --- a/examples/protocols/l2tap/CMakeLists.txt +++ b/examples/protocols/l2tap/CMakeLists.txt @@ -2,8 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(l2tap_example) diff --git a/examples/protocols/l2tap/main/idf_component.yml b/examples/protocols/l2tap/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/l2tap/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/modbus/serial/mb_master/CMakeLists.txt b/examples/protocols/modbus/serial/mb_master/CMakeLists.txt index 1b30d1a529f..7bfc34d3390 100644 --- a/examples/protocols/modbus/serial/mb_master/CMakeLists.txt +++ b/examples/protocols/modbus/serial/mb_master/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/modbus/mb_example_common) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(modbus_master) diff --git a/examples/protocols/modbus/serial/mb_master/main/idf_component.yml b/examples/protocols/modbus/serial/mb_master/main/idf_component.yml index caf4c18da77..3eb79f2560c 100644 --- a/examples/protocols/modbus/serial/mb_master/main/idf_component.yml +++ b/examples/protocols/modbus/serial/mb_master/main/idf_component.yml @@ -2,3 +2,5 @@ dependencies: idf: ">=4.1" espressif/esp-modbus: version: "^1.0" + mb_example_common: + path: ${IDF_PATH}/examples/protocols/modbus/mb_example_common diff --git a/examples/protocols/modbus/serial/mb_slave/CMakeLists.txt b/examples/protocols/modbus/serial/mb_slave/CMakeLists.txt index b74657d27e2..c45d418b469 100644 --- a/examples/protocols/modbus/serial/mb_slave/CMakeLists.txt +++ b/examples/protocols/modbus/serial/mb_slave/CMakeLists.txt @@ -2,8 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/modbus/mb_example_common) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(modbus_slave) diff --git a/examples/protocols/modbus/serial/mb_slave/main/idf_component.yml b/examples/protocols/modbus/serial/mb_slave/main/idf_component.yml index caf4c18da77..3eb79f2560c 100644 --- a/examples/protocols/modbus/serial/mb_slave/main/idf_component.yml +++ b/examples/protocols/modbus/serial/mb_slave/main/idf_component.yml @@ -2,3 +2,5 @@ dependencies: idf: ">=4.1" espressif/esp-modbus: version: "^1.0" + mb_example_common: + path: ${IDF_PATH}/examples/protocols/modbus/mb_example_common diff --git a/examples/protocols/modbus/tcp/mb_tcp_master/CMakeLists.txt b/examples/protocols/modbus/tcp/mb_tcp_master/CMakeLists.txt index 48d38dd32c2..6364c3599ae 100644 --- a/examples/protocols/modbus/tcp/mb_tcp_master/CMakeLists.txt +++ b/examples/protocols/modbus/tcp/mb_tcp_master/CMakeLists.txt @@ -2,10 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/modbus/mb_example_common) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(modbus_tcp_master) diff --git a/examples/protocols/modbus/tcp/mb_tcp_master/main/idf_component.yml b/examples/protocols/modbus/tcp/mb_tcp_master/main/idf_component.yml index 542ec33e55c..f4bde51446b 100644 --- a/examples/protocols/modbus/tcp/mb_tcp_master/main/idf_component.yml +++ b/examples/protocols/modbus/tcp/mb_tcp_master/main/idf_component.yml @@ -4,3 +4,7 @@ dependencies: version: ">=4.1.0" espressif/esp-modbus: version: "^1.0" + mb_example_common: + path: ${IDF_PATH}/examples/protocols/modbus/mb_example_common + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/modbus/tcp/mb_tcp_slave/CMakeLists.txt b/examples/protocols/modbus/tcp/mb_tcp_slave/CMakeLists.txt index 8707de641aa..7af78457dc8 100644 --- a/examples/protocols/modbus/tcp/mb_tcp_slave/CMakeLists.txt +++ b/examples/protocols/modbus/tcp/mb_tcp_slave/CMakeLists.txt @@ -3,11 +3,7 @@ cmake_minimum_required(VERSION 3.16) # This component includes modbus example common definitions -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/modbus/mb_example_common) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(modbus_tcp_slave) diff --git a/examples/protocols/modbus/tcp/mb_tcp_slave/main/idf_component.yml b/examples/protocols/modbus/tcp/mb_tcp_slave/main/idf_component.yml index debc03c5c4d..08bd2149921 100644 --- a/examples/protocols/modbus/tcp/mb_tcp_slave/main/idf_component.yml +++ b/examples/protocols/modbus/tcp/mb_tcp_slave/main/idf_component.yml @@ -3,3 +3,7 @@ dependencies: idf: ">=4.1" espressif/esp-modbus: version: "^1.0" + mb_example_common: + path: ${IDF_PATH}/examples/protocols/modbus/mb_example_common + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/mqtt/ssl/CMakeLists.txt b/examples/protocols/mqtt/ssl/CMakeLists.txt index 3d2fba104d5..994f2f23798 100644 --- a/examples/protocols/mqtt/ssl/CMakeLists.txt +++ b/examples/protocols/mqtt/ssl/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mqtt_ssl) diff --git a/examples/protocols/mqtt/ssl/main/idf_component.yml b/examples/protocols/mqtt/ssl/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/mqtt/ssl/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/mqtt/ssl_ds/CMakeLists.txt b/examples/protocols/mqtt/ssl_ds/CMakeLists.txt index 144cf8b4db6..ce04bb08b7d 100644 --- a/examples/protocols/mqtt/ssl_ds/CMakeLists.txt +++ b/examples/protocols/mqtt/ssl_ds/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mqtt_ssl_ds) diff --git a/examples/protocols/mqtt/ssl_ds/main/idf_component.yml b/examples/protocols/mqtt/ssl_ds/main/idf_component.yml index 8dd90a3b089..947ec180420 100644 --- a/examples/protocols/mqtt/ssl_ds/main/idf_component.yml +++ b/examples/protocols/mqtt/ssl_ds/main/idf_component.yml @@ -1,3 +1,5 @@ ## IDF Component Manager Manifest File dependencies: espressif/esp_secure_cert_mgr: "^2.0.2" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/mqtt/ssl_mutual_auth/CMakeLists.txt b/examples/protocols/mqtt/ssl_mutual_auth/CMakeLists.txt index 14512ad0c55..fc3d759049f 100644 --- a/examples/protocols/mqtt/ssl_mutual_auth/CMakeLists.txt +++ b/examples/protocols/mqtt/ssl_mutual_auth/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mqtt_ssl_mutual_auth) diff --git a/examples/protocols/mqtt/ssl_mutual_auth/main/idf_component.yml b/examples/protocols/mqtt/ssl_mutual_auth/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/mqtt/ssl_mutual_auth/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/mqtt/ssl_psk/CMakeLists.txt b/examples/protocols/mqtt/ssl_psk/CMakeLists.txt index a4e8aa6016f..d9c1a5fe373 100644 --- a/examples/protocols/mqtt/ssl_psk/CMakeLists.txt +++ b/examples/protocols/mqtt/ssl_psk/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mqtt_ssl_psk) diff --git a/examples/protocols/mqtt/ssl_psk/main/idf_component.yml b/examples/protocols/mqtt/ssl_psk/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/mqtt/tcp/CMakeLists.txt b/examples/protocols/mqtt/tcp/CMakeLists.txt index 7dd960dccf7..d6d9432990c 100644 --- a/examples/protocols/mqtt/tcp/CMakeLists.txt +++ b/examples/protocols/mqtt/tcp/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mqtt_tcp) diff --git a/examples/protocols/mqtt/tcp/main/idf_component.yml b/examples/protocols/mqtt/tcp/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/mqtt/tcp/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/mqtt/ws/CMakeLists.txt b/examples/protocols/mqtt/ws/CMakeLists.txt index 6c84eb79985..475dd9e41e7 100644 --- a/examples/protocols/mqtt/ws/CMakeLists.txt +++ b/examples/protocols/mqtt/ws/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mqtt_websocket) diff --git a/examples/protocols/mqtt/ws/main/idf_component.yml b/examples/protocols/mqtt/ws/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/mqtt/ws/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/mqtt/wss/CMakeLists.txt b/examples/protocols/mqtt/wss/CMakeLists.txt index 2a624407b4e..20c1fde634c 100644 --- a/examples/protocols/mqtt/wss/CMakeLists.txt +++ b/examples/protocols/mqtt/wss/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mqtt_websocket_secure) diff --git a/examples/protocols/mqtt/wss/main/idf_component.yml b/examples/protocols/mqtt/wss/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/mqtt/wss/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/mqtt5/CMakeLists.txt b/examples/protocols/mqtt5/CMakeLists.txt index 7764590fc99..19304b42f07 100644 --- a/examples/protocols/mqtt5/CMakeLists.txt +++ b/examples/protocols/mqtt5/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mqtt5) diff --git a/examples/protocols/mqtt5/main/idf_component.yml b/examples/protocols/mqtt5/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/mqtt5/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/smtp_client/CMakeLists.txt b/examples/protocols/smtp_client/CMakeLists.txt index ccdf57e202a..8ebc8738776 100644 --- a/examples/protocols/smtp_client/CMakeLists.txt +++ b/examples/protocols/smtp_client/CMakeLists.txt @@ -2,8 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(smtp_client) diff --git a/examples/protocols/smtp_client/main/idf_component.yml b/examples/protocols/smtp_client/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/smtp_client/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/sntp/CMakeLists.txt b/examples/protocols/sntp/CMakeLists.txt index 3a794c8b4ff..62443a677a7 100644 --- a/examples/protocols/sntp/CMakeLists.txt +++ b/examples/protocols/sntp/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(sntp) diff --git a/examples/protocols/sntp/main/idf_component.yml b/examples/protocols/sntp/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/sntp/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/sockets/icmpv6_ping/CMakeLists.txt b/examples/protocols/sockets/icmpv6_ping/CMakeLists.txt index a9fe701648a..40b7d39e252 100644 --- a/examples/protocols/sockets/icmpv6_ping/CMakeLists.txt +++ b/examples/protocols/sockets/icmpv6_ping/CMakeLists.txt @@ -1,8 +1,6 @@ # 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) - -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(icmpv6_ping) diff --git a/examples/protocols/sockets/icmpv6_ping/main/idf_component.yml b/examples/protocols/sockets/icmpv6_ping/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/sockets/icmpv6_ping/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/sockets/non_blocking/CMakeLists.txt b/examples/protocols/sockets/non_blocking/CMakeLists.txt index cb60cfd9662..e6f06b5f080 100644 --- a/examples/protocols/sockets/non_blocking/CMakeLists.txt +++ b/examples/protocols/sockets/non_blocking/CMakeLists.txt @@ -2,9 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(non_blocking_socket) diff --git a/examples/protocols/sockets/non_blocking/main/idf_component.yml b/examples/protocols/sockets/non_blocking/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/sockets/non_blocking/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/sockets/tcp_client/CMakeLists.txt b/examples/protocols/sockets/tcp_client/CMakeLists.txt index cf2f5a88958..425e07bf164 100644 --- a/examples/protocols/sockets/tcp_client/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_client/CMakeLists.txt @@ -1,10 +1,8 @@ # The following 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) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) if("${IDF_TARGET}" STREQUAL "linux") - list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs") set(COMPONENTS main) endif() diff --git a/examples/protocols/sockets/tcp_client/main/idf_component.yml b/examples/protocols/sockets/tcp_client/main/idf_component.yml new file mode 100644 index 00000000000..c17c116c4bd --- /dev/null +++ b/examples/protocols/sockets/tcp_client/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common + esp_stubs: + path: ${IDF_PATH}/examples/protocols/linux_stubs/esp_stubs + rules: + - if: "target in [linux]" diff --git a/examples/protocols/sockets/tcp_client_multi_net/CMakeLists.txt b/examples/protocols/sockets/tcp_client_multi_net/CMakeLists.txt index cb5c3f05812..2a1c0af6360 100644 --- a/examples/protocols/sockets/tcp_client_multi_net/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_client_multi_net/CMakeLists.txt @@ -2,9 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(tcp_client_multiple) diff --git a/examples/protocols/sockets/tcp_client_multi_net/main/idf_component.yml b/examples/protocols/sockets/tcp_client_multi_net/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/sockets/tcp_client_multi_net/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/sockets/tcp_server/CMakeLists.txt b/examples/protocols/sockets/tcp_server/CMakeLists.txt index 1214842ddab..22ae003fdfd 100644 --- a/examples/protocols/sockets/tcp_server/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_server/CMakeLists.txt @@ -2,9 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(tcp_server) diff --git a/examples/protocols/sockets/tcp_server/main/idf_component.yml b/examples/protocols/sockets/tcp_server/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/sockets/tcp_server/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/sockets/tcp_transport_client/CMakeLists.txt b/examples/protocols/sockets/tcp_transport_client/CMakeLists.txt index 888ca62b162..79462a3ee54 100644 --- a/examples/protocols/sockets/tcp_transport_client/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_transport_client/CMakeLists.txt @@ -2,9 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(tcp_transport_client) diff --git a/examples/protocols/sockets/tcp_transport_client/main/idf_component.yml b/examples/protocols/sockets/tcp_transport_client/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/sockets/tcp_transport_client/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/sockets/udp_client/CMakeLists.txt b/examples/protocols/sockets/udp_client/CMakeLists.txt index c2559179e10..2db190c9d1e 100644 --- a/examples/protocols/sockets/udp_client/CMakeLists.txt +++ b/examples/protocols/sockets/udp_client/CMakeLists.txt @@ -3,12 +3,7 @@ cmake_minimum_required(VERSION 3.16) if("${IDF_TARGET}" STREQUAL "linux") - # This example uses an extra component with common functionality for lwip's port on linux target - set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_tapif_io) set(COMPONENTS main esp_netif lwip protocol_examples_tapif_io startup esp_hw_support esp_system nvs_flash) -else() - # This example uses an extra component for common functions such as Wi-Fi and Ethernet connection on ESP target - set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) endif() include($ENV{IDF_PATH}/tools/cmake/project.cmake) diff --git a/examples/protocols/sockets/udp_client/main/idf_component.yml b/examples/protocols/sockets/udp_client/main/idf_component.yml new file mode 100644 index 00000000000..d51e66f1022 --- /dev/null +++ b/examples/protocols/sockets/udp_client/main/idf_component.yml @@ -0,0 +1,9 @@ +dependencies: + protocol_examples_tapif_io: + path: ${IDF_PATH}/examples/common_components/protocol_examples_tapif_io + rules: + - if: "target in [linux]" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common + rules: + - if: "target not in [linux]" diff --git a/examples/protocols/sockets/udp_multicast/CMakeLists.txt b/examples/protocols/sockets/udp_multicast/CMakeLists.txt index c93ac423e5b..c8d4f163a68 100644 --- a/examples/protocols/sockets/udp_multicast/CMakeLists.txt +++ b/examples/protocols/sockets/udp_multicast/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(udp_multicast) diff --git a/examples/protocols/sockets/udp_multicast/main/idf_component.yml b/examples/protocols/sockets/udp_multicast/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/sockets/udp_multicast/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/protocols/sockets/udp_server/CMakeLists.txt b/examples/protocols/sockets/udp_server/CMakeLists.txt index c27ec68ef46..adc2de90861 100644 --- a/examples/protocols/sockets/udp_server/CMakeLists.txt +++ b/examples/protocols/sockets/udp_server/CMakeLists.txt @@ -2,9 +2,6 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(udp_server) diff --git a/examples/protocols/sockets/udp_server/main/idf_component.yml b/examples/protocols/sockets/udp_server/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/protocols/sockets/udp_server/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/system/console/advanced_usb_cdc/CMakeLists.txt b/examples/system/console/advanced_usb_cdc/CMakeLists.txt index 3b15392ae80..b005ae74da6 100644 --- a/examples/system/console/advanced_usb_cdc/CMakeLists.txt +++ b/examples/system/console/advanced_usb_cdc/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(console_usb) diff --git a/examples/system/console/advanced_usb_cdc/main/idf_component.yml b/examples/system/console/advanced_usb_cdc/main/idf_component.yml new file mode 100644 index 00000000000..aacef0f4000 --- /dev/null +++ b/examples/system/console/advanced_usb_cdc/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + cmd_nvs: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_nvs + cmd_wifi: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_wifi diff --git a/examples/system/console/basic/CMakeLists.txt b/examples/system/console/basic/CMakeLists.txt index d514ee420de..5247b367e92 100644 --- a/examples/system/console/basic/CMakeLists.txt +++ b/examples/system/console/basic/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(console) diff --git a/examples/system/console/basic/main/idf_component.yml b/examples/system/console/basic/main/idf_component.yml new file mode 100644 index 00000000000..aacef0f4000 --- /dev/null +++ b/examples/system/console/basic/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + cmd_nvs: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_nvs + cmd_wifi: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_wifi diff --git a/examples/system/ota/advanced_https_ota/CMakeLists.txt b/examples/system/ota/advanced_https_ota/CMakeLists.txt index 8f47db83ebe..f89de5e6b1b 100644 --- a/examples/system/ota/advanced_https_ota/CMakeLists.txt +++ b/examples/system/ota/advanced_https_ota/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(advanced_https_ota) diff --git a/examples/system/ota/advanced_https_ota/main/idf_component.yml b/examples/system/ota/advanced_https_ota/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/system/ota/advanced_https_ota/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/system/ota/native_ota_example/CMakeLists.txt b/examples/system/ota/native_ota_example/CMakeLists.txt index cf72f28f09c..0fcc1e5b00c 100644 --- a/examples/system/ota/native_ota_example/CMakeLists.txt +++ b/examples/system/ota/native_ota_example/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(native_ota) diff --git a/examples/system/ota/native_ota_example/main/idf_component.yml b/examples/system/ota/native_ota_example/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/system/ota/native_ota_example/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/system/ota/pre_encrypted_ota/CMakeLists.txt b/examples/system/ota/pre_encrypted_ota/CMakeLists.txt index 8cdeb45f711..df49470c0df 100644 --- a/examples/system/ota/pre_encrypted_ota/CMakeLists.txt +++ b/examples/system/ota/pre_encrypted_ota/CMakeLists.txt @@ -3,7 +3,6 @@ # 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) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(pre_encrypted_ota) diff --git a/examples/system/ota/pre_encrypted_ota/main/idf_component.yml b/examples/system/ota/pre_encrypted_ota/main/idf_component.yml index e0dcbd50a13..eb11ca8debe 100644 --- a/examples/system/ota/pre_encrypted_ota/main/idf_component.yml +++ b/examples/system/ota/pre_encrypted_ota/main/idf_component.yml @@ -1,2 +1,4 @@ dependencies: espressif/esp_encrypted_img: "^2.0.1" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/system/ota/simple_ota_example/CMakeLists.txt b/examples/system/ota/simple_ota_example/CMakeLists.txt index 5467820f592..37106afe8a3 100644 --- a/examples/system/ota/simple_ota_example/CMakeLists.txt +++ b/examples/system/ota/simple_ota_example/CMakeLists.txt @@ -2,9 +2,6 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -# (Not part of the boilerplate) -# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(simple_ota) diff --git a/examples/system/ota/simple_ota_example/main/idf_component.yml b/examples/system/ota/simple_ota_example/main/idf_component.yml new file mode 100644 index 00000000000..718194867b7 --- /dev/null +++ b/examples/system/ota/simple_ota_example/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/examples/wifi/ftm/CMakeLists.txt b/examples/wifi/ftm/CMakeLists.txt index 28882679278..3ab48fa49b5 100644 --- a/examples/wifi/ftm/CMakeLists.txt +++ b/examples/wifi/ftm/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ftm) diff --git a/examples/wifi/ftm/main/idf_component.yml b/examples/wifi/ftm/main/idf_component.yml new file mode 100644 index 00000000000..aacef0f4000 --- /dev/null +++ b/examples/wifi/ftm/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + cmd_nvs: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_nvs + cmd_wifi: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_wifi diff --git a/examples/wifi/iperf/CMakeLists.txt b/examples/wifi/iperf/CMakeLists.txt index 40c237b98fb..1913ec8a9df 100644 --- a/examples/wifi/iperf/CMakeLists.txt +++ b/examples/wifi/iperf/CMakeLists.txt @@ -2,8 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components - $ENV{IDF_PATH}/examples/common_components/iperf) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(iperf) diff --git a/examples/wifi/iperf/main/idf_component.yml b/examples/wifi/iperf/main/idf_component.yml new file mode 100644 index 00000000000..1c70392e2d3 --- /dev/null +++ b/examples/wifi/iperf/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + iperf: + path: ${IDF_PATH}/examples/common_components/iperf diff --git a/examples/wifi/itwt/CMakeLists.txt b/examples/wifi/itwt/CMakeLists.txt index de90c341878..3b0a05216b1 100644 --- a/examples/wifi/itwt/CMakeLists.txt +++ b/examples/wifi/itwt/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components - $ENV{IDF_PATH}/examples/common_components/iperf) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(itwt) diff --git a/examples/wifi/itwt/main/idf_component.yml b/examples/wifi/itwt/main/idf_component.yml new file mode 100644 index 00000000000..da61b1e507f --- /dev/null +++ b/examples/wifi/itwt/main/idf_component.yml @@ -0,0 +1,9 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + cmd_nvs: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_nvs + cmd_wifi: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_wifi + iperf: + path: ${IDF_PATH}/examples/common_components/iperf diff --git a/examples/wifi/wifi_aware/nan_console/CMakeLists.txt b/examples/wifi/wifi_aware/nan_console/CMakeLists.txt index 4805700b81e..b08fb7cd937 100644 --- a/examples/wifi/wifi_aware/nan_console/CMakeLists.txt +++ b/examples/wifi/wifi_aware/nan_console/CMakeLists.txt @@ -2,7 +2,5 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components) - include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(nan_console) diff --git a/examples/wifi/wifi_aware/nan_console/main/idf_component.yml b/examples/wifi/wifi_aware/nan_console/main/idf_component.yml new file mode 100644 index 00000000000..aacef0f4000 --- /dev/null +++ b/examples/wifi/wifi_aware/nan_console/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + cmd_system: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system + cmd_nvs: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_nvs + cmd_wifi: + path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_wifi diff --git a/examples/zigbee/esp_zigbee_gateway/CMakeLists.txt b/examples/zigbee/esp_zigbee_gateway/CMakeLists.txt index eac8c5c438a..4d579709261 100644 --- a/examples/zigbee/esp_zigbee_gateway/CMakeLists.txt +++ b/examples/zigbee/esp_zigbee_gateway/CMakeLists.txt @@ -3,6 +3,5 @@ # 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) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(esp_zigbee_gateway) diff --git a/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml b/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml index 1d60ab3792f..b02a13eaeca 100644 --- a/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml +++ b/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml @@ -5,3 +5,5 @@ dependencies: ## Required IDF version idf: version: ">=5.0.0" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common From 8c26ddf4a1c456cfeffa19e22a371bbba7d7bcc9 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 18 Sep 2023 13:37:18 +0200 Subject: [PATCH 34/71] feat(ci): add CI check for EXTRA_COMPONENT_DIRS in examples --- .gitlab/ci/pre_check.yml | 3 ++- .../ci/check_examples_extra_component_dirs.sh | 25 +++++++++++++++++++ tools/ci/executable-list.txt | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100755 tools/ci/check_examples_extra_component_dirs.sh diff --git a/.gitlab/ci/pre_check.yml b/.gitlab/ci/pre_check.yml index aeee0b3cf7d..b18c20d7980 100644 --- a/.gitlab/ci/pre_check.yml +++ b/.gitlab/ci/pre_check.yml @@ -64,11 +64,12 @@ check_version: - export IDF_PATH=$PWD - tools/ci/check_idf_version.sh -check_rom_api_header: +check_api_usage: extends: .pre_check_template script: - tools/ci/check_examples_rom_header.sh - tools/ci/check_api_violation.sh + - tools/ci/check_examples_extra_component_dirs.sh test_check_kconfigs: extends: .pre_check_template diff --git a/tools/ci/check_examples_extra_component_dirs.sh b/tools/ci/check_examples_extra_component_dirs.sh new file mode 100755 index 00000000000..207efff7f4d --- /dev/null +++ b/tools/ci/check_examples_extra_component_dirs.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -uo pipefail + +# Examples shouldn't use EXTRA_COMPONENT_DIRS, instead the dependencies should be specified in idf_component.yml files + +output=$(find ${IDF_PATH}/examples -name "CMakeLists.txt" -not -path "**/managed_components/**" -not -path "**/build/**") +files=$(egrep "set\(EXTRA_COMPONENT_DIRS" ${output} | cut -d ":" -f 1) +found_issues=0 +for file in ${files} +do + if [ "$file" == "${IDF_PATH}/examples/system/unit_test/test/CMakeLists.txt" ]; then + # this specific one is okay + continue + fi + echo "${file} uses EXTRA_COMPONENT_DIRS. Change it to reference the component using idf_component.yml file." + ((found_issues++)) +done + +if [ $found_issues -eq 0 ]; then + echo "No examples use EXTRA_COMPONENT_DIRS" + exit 0 +fi + +exit 1 diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 59bf4162b97..6d27152c5fd 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -55,6 +55,7 @@ tools/ci/check_callgraph.py tools/ci/check_codeowners.py tools/ci/check_deprecated_kconfigs.py tools/ci/check_esp_memory_utils_headers.sh +tools/ci/check_examples_extra_component_dirs.sh tools/ci/check_examples_rom_header.sh tools/ci/check_executables.py tools/ci/check_idf_version.sh From 61cf4b2da5dac0df79a760027613ae76abe8575d Mon Sep 17 00:00:00 2001 From: renpeiying Date: Thu, 31 Aug 2023 18:02:12 +0800 Subject: [PATCH 35/71] docs: Provide Chinese translation for api-reference/system/freertos.rst --- docs/en/api-reference/system/freertos.rst | 48 ++++--- docs/zh_CN/api-reference/system/freertos.rst | 143 ++++++++++++++++++- 2 files changed, 168 insertions(+), 23 deletions(-) diff --git a/docs/en/api-reference/system/freertos.rst b/docs/en/api-reference/system/freertos.rst index 526507bb263..bb8bbaf1d91 100644 --- a/docs/en/api-reference/system/freertos.rst +++ b/docs/en/api-reference/system/freertos.rst @@ -1,10 +1,14 @@ -FreeRTOS (Overview) -=================== +FreeRTOS Overview +================= + +:link_to_translation:`zh_CN:[中文]` Overview -------- -FreeRTOS is an open source real-time operating system kernel that acts as the operating system for ESP-IDF applications and is integrated into ESP-IDF as a component. The FreeRTOS component in ESP-IDF contains ports of the FreeRTOS kernel for all the CPU architectures used by ESP targets (i.e., Xtensa and RISC-V). Furthermore, ESP-IDF provides different implementations of FreeRTOS in order to support SMP (Symmetric Multiprocessing) on multi-core ESP targets. This document provides an overview of the FreeRTOS component, the FreeRTOS implementations offered by ESP-IDF, and the common aspects across all implementations. +FreeRTOS is an open source RTOS (real-time operating system) kernel that is integrated into ESP-IDF as a component. Thus, all ESP-IDF applications and many ESP-IDF components are written based on FreeRTOS. The FreeRTOS kernel is ported to all architectures (i.e., Xtensa and RISC-V) available of ESP chips. + +Furthermore, ESP-IDF provides different implementations of FreeRTOS in order to support SMP (Symmetric Multiprocessing) on multi-core ESP chips. This document provides an overview of the FreeRTOS component, the different FreeRTOS implementations offered by ESP-IDF, and the common aspects across all implementations. Implementations --------------- @@ -14,11 +18,11 @@ The `official FreeRTOS `_ (henceforth refer ESP-IDF FreeRTOS ^^^^^^^^^^^^^^^^ - ESP-IDF FreeRTOS is a FreeRTOS implementation based on Vanilla FreeRTOS v10.4.3, but contains significant modifications to support SMP. ESP-IDF FreeRTOS only supports two cores at most (i.e., dual core SMP), but is more optimized for this scenario by design. For more details regarding ESP-IDF FreeRTOS and its modifications, please refer to the :doc:`freertos_idf` document. +ESP-IDF FreeRTOS is a FreeRTOS implementation based on Vanilla FreeRTOS v10.4.3, but contains significant modifications to support SMP. ESP-IDF FreeRTOS only supports two cores at most (i.e., dual core SMP), but is more optimized for this scenario by design. For more details regarding ESP-IDF FreeRTOS and its modifications, please refer to the :doc:`freertos_idf` document. - .. note:: +.. note:: - ESP-IDF FreeRTOS is currently the default FreeRTOS implementation for ESP-IDF. + ESP-IDF FreeRTOS is currently the default FreeRTOS implementation for ESP-IDF. .. only:: not esp32p4 @@ -27,11 +31,11 @@ ESP-IDF FreeRTOS Amazon SMP FreeRTOS ^^^^^^^^^^^^^^^^^^^ - Amazon SMP FreeRTOS is an SMP implementation of FreeRTOS that is officially supported by Amazon. Amazon SMP FreeRTOS is able to support N-cores (i.e., more than two cores). Amazon SMP FreeRTOS can be enabled via the :ref:`CONFIG_FREERTOS_SMP` option. For more details regarding Amazon SMP FreeRTOS, please refer to the `official Amazon SMP FreeRTOS documentation `_. + Amazon SMP FreeRTOS is an SMP implementation of FreeRTOS that is officially supported by Amazon. Amazon SMP FreeRTOS is able to support N-cores (i.e., more than two cores). Amazon SMP FreeRTOS can be enabled via the :ref:`CONFIG_FREERTOS_SMP` option. For more details regarding Amazon SMP FreeRTOS, please refer to the `official Amazon SMP FreeRTOS documentation `_. - .. warning:: + .. warning:: - The Amazon SMP FreeRTOS implementation (and its port in ESP-IDF) are currently in experimental/beta state. Therefore, significant behavioral changes and breaking API changes can occur. + The Amazon SMP FreeRTOS implementation (and its port in ESP-IDF) are currently in experimental/beta state. Therefore, significant behavioral changes and breaking API changes can occur. Configuration ------------- @@ -39,9 +43,9 @@ Configuration Kernel Configuration ^^^^^^^^^^^^^^^^^^^^ -Vanilla FreeRTOS requires that ports and applications configure the kernel by adding various ``#define config...`` macros to ``FreeRTOSConfig.h``. Vanilla FreeRTOS supports a list of kernel configuration options which allow various kernel behaviors and features to be enabled or disabled. +Vanilla FreeRTOS requires that ports and applications configure the kernel by adding various ``#define config...`` macro definitions to the ``FreeRTOSConfig.h`` header file. Vanilla FreeRTOS supports a list of kernel configuration options which allow various kernel behaviors and features to be enabled or disabled. -**However, for all FreeRTOS ports in ESP-IDF, the ``FreeRTOSConfig.h`` file is considered private and must not be modified by users**. A large number of kernel configuration options in ``FreeRTOSConfig.h`` are hard coded as they are either required or not supported in ESP-IDF. All kernel configuration options that are configurable by the user are exposed via menuconfig under ``Component Config/FreeRTOS/Kernel``. +**However, for all FreeRTOS ports in ESP-IDF, the FreeRTOSConfig.h header file is considered private and must not be modified by users**. A large number of kernel configuration options in ``FreeRTOSConfig.h`` are hard-coded as they are either required/not supported by ESP-IDF. All kernel configuration options that are configurable by the user are exposed via menuconfig under ``Component Config/FreeRTOS/Kernel``. For the full list of user configurable kernel options, see :doc:`/api-reference/kconfig`. The list below highlights some commonly used kernel configuration options: @@ -68,7 +72,7 @@ Using FreeRTOS Application Entry Point ^^^^^^^^^^^^^^^^^^^^^^^ -Unlike Vanilla FreeRTOS, users of FreeRTOS in ESP-IDF **must never call** :cpp:func:`vTaskStartScheduler` and :cpp:func:`vTaskEndScheduler`. Instead, ESP-IDF starts FreeRTOS automatically. Users must define a ``void app_main(void)`` function which acts as the entry point for user's application and is automatically called on ESP-IDF startup. +Unlike Vanilla FreeRTOS, users of FreeRTOS in ESP-IDF **must never call** :cpp:func:`vTaskStartScheduler` and :cpp:func:`vTaskEndScheduler`. Instead, ESP-IDF starts FreeRTOS automatically. Users must define a ``void app_main(void)`` function which acts as the entry point for user's application and is automatically invoked on ESP-IDF startup. - Typically, users would spawn the rest of their application's task from ``app_main``. - The ``app_main`` function is allowed to return at any point (i.e., before the application terminates). @@ -91,14 +95,14 @@ During startup, ESP-IDF and the FreeRTOS kernel automatically create multiple ta - Affinity - Priority * - Idle Tasks (``IDLEx``) - - An idle task (``IDLEx``) is created for (and pinned to) each CPU, where ``x`` is the CPU's number. + - An idle task (``IDLEx``) is created for (and pinned to) each CPU core, where ``x`` is the CPU core's number - :ref:`CONFIG_FREERTOS_IDLE_TASK_STACKSIZE` - - CPUx + - Core x - ``0`` * - FreeRTOS Timer Task (``Tmr Svc``) - - FreeRTOS will create the Timer Service/Daemon Task if any FreeRTOS Timer APIs are called by the application. + - FreeRTOS will create the Timer Service/Daemon Task if any FreeRTOS Timer APIs are called by the application - :ref:`CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH` - - CPU0 + - Core 0 - :ref:`CONFIG_FREERTOS_TIMER_TASK_PRIORITY` * - Main Task (``main``) - Task that simply calls ``app_main``. This task will self delete when ``app_main`` returns @@ -106,14 +110,14 @@ During startup, ESP-IDF and the FreeRTOS kernel automatically create multiple ta - :ref:`CONFIG_ESP_MAIN_TASK_AFFINITY` - ``1`` * - IPC Tasks (``ipcx``) - - When :ref:`CONFIG_FREERTOS_UNICORE` is false, an IPC task (``ipcx``) is created for (and pinned to) each CPU. IPC tasks are used to implement the Inter-processor Call (IPC) feature. + - When :ref:`CONFIG_FREERTOS_UNICORE` is false, an IPC task (``ipcx``) is created for (and pinned to) each CPU core. IPC tasks are used to implement the Inter-processor Call (IPC) feature. - :ref:`CONFIG_ESP_IPC_TASK_STACK_SIZE` - - CPUx + - Core x - ``24`` * - ESP Timer Task (``esp_timer``) - - ESP-IDF creates the ESP Timer Task used to process ESP Timer callbacks. + - ESP-IDF creates the ESP Timer Task used to process ESP Timer callbacks - :ref:`CONFIG_ESP_TIMER_TASK_STACK_SIZE` - - CPU0 + - Core 0 - ``22`` .. note:: @@ -129,10 +133,10 @@ ESP-IDF provides some supplemental features to FreeRTOS such as Ring Buffers, ES FreeRTOS Heap ------------- -Vanilla FreeRTOS provides its own `selection of heap implementations `_. However, ESP-IDF already implements its own heap (see :doc:`/api-reference/system/mem_alloc`), thus ESP-IDF does not make use of the heap implementations provided by Vanilla FreeRTOS. All FreeRTOS ports in ESP-IDF map FreeRTOS memory allocation/free calls (e.g., ``pvPortMalloc()`` and ``pvPortFree()``) to ESP-IDF heap API (i.e., :cpp:func:`heap_caps_malloc` and :cpp:func:`heap_caps_free`). However, the FreeRTOS ports ensure that all dynamic memory allocated by FreeRTOS is placed in internal memory. +Vanilla FreeRTOS provides its own `selection of heap implementations `_. However, ESP-IDF already implements its own heap (see :doc:`/api-reference/system/mem_alloc`), thus ESP-IDF does not make use of the heap implementations provided by Vanilla FreeRTOS. All FreeRTOS ports in ESP-IDF map FreeRTOS memory allocation or free calls (e.g., ``pvPortMalloc()`` and ``pvPortFree()``) to ESP-IDF heap API (i.e., :cpp:func:`heap_caps_malloc` and :cpp:func:`heap_caps_free`). However, the FreeRTOS ports ensure that all dynamic memory allocated by FreeRTOS is placed in internal memory. .. note:: If users wish to place FreeRTOS tasks/objects in external memory, users can use the following methods: - - Allocate the task/object using one of the ``...CreateWithCaps()`` API such as :cpp:func:`xTaskCreateWithCaps` and :cpp:func:`xQueueCreateWithCaps` (see :ref:`freertos-idf-additional-api` for more details). + - Allocate the task or object using one of the ``...CreateWithCaps()`` API, such as :cpp:func:`xTaskCreateWithCaps` and :cpp:func:`xQueueCreateWithCaps` (see :ref:`freertos-idf-additional-api` for more details). - Manually allocate external memory for those objects using :cpp:func:`heap_caps_malloc`, then create the objects from the allocated memory using on of the ``...CreateStatic()`` FreeRTOS functions. diff --git a/docs/zh_CN/api-reference/system/freertos.rst b/docs/zh_CN/api-reference/system/freertos.rst index 67f97f5056a..d32ac2ef978 100644 --- a/docs/zh_CN/api-reference/system/freertos.rst +++ b/docs/zh_CN/api-reference/system/freertos.rst @@ -1 +1,142 @@ -.. include:: ../../../en/api-reference/system/freertos.rst \ No newline at end of file +FreeRTOS 概述 +=================== + +:link_to_translation:`en:[English]` + +概述 +-------- + +FreeRTOS 是一个开源的 RTOS(实时操作系统)内核,它以组件的形式集成到 ESP-IDF 中。因此,所有的 ESP-IDF 应用程序及多种 ESP-IDF 组件都基于 FreeRTOS 编写。FreeRTOS 内核已移植到 ESP 芯片的所有 CPU 架构(即 Xtensa 和 RISC-V)中。 + +此外,ESP-IDF 还提供了不同的 FreeRTOS 实现,支持在多核 ESP 目标芯片上的 SMP(对称多处理)。本文档主要介绍了 FreeRTOS 组件、ESP-IDF 提供的 FreeRTOS 实现,并简要介绍了这些实现的共同之处。 + +实现 +--------------- + +`官方 FreeRTOS `__ (下文称为原生 FreeRTOS)是一个单核 RTOS。为了支持各种多核 ESP 目标芯片,ESP-IDF 支持下述不同的 FreeRTOS 实现。 + +ESP-IDF FreeRTOS +^^^^^^^^^^^^^^^^ + + ESP-IDF FreeRTOS 是基于原生 FreeRTOS v10.4.3 的 FreeRTOS 实现,其中包含支持 SMP 的大量更新。ESP-IDF FreeRTOS 最多支持两个核(即双核 SMP),但在设计上对这种场景进行了优化。关于 ESP-IDF FreeRTOS 及具体更新内容,请参考 :doc:`freertos_idf` 文档。 + + .. note:: + + ESP-IDF FreeRTOS 是目前 ESP-IDF 默认的 FreeRTOS 实现。 + +.. only:: not esp32p4 + + .. _amazon_smp_freertos: + + Amazon SMP FreeRTOS + ^^^^^^^^^^^^^^^^^^^ + + Amazon SMP FreeRTOS 是由 Amazon 官方支持的 FreeRTOS SMP 实现。Amazon SMP FreeRTOS 能够支持 N 核,即双核以上。通过 :ref:`CONFIG_FREERTOS_SMP` 选项能够启用 Amazon SMP FreeRTOS。关于 Amazon SMP FreeRTOS 的更多细节,请参考 `官方 Amazon SMP FreeRTOS 文档 `__。 + + .. warning:: + + Amazon SMP FreeRTOS 实现(及其在 ESP-IDF 中的移植)目前处于试验/测试状态,因此,可能会发生重大的行为变化及 API 变更。 + +配置 +------------- + +内核配置 +^^^^^^^^^^^^^^^^^^^^ + +原生 FreeRTOS 要求移植工具和应用程序通过在 ``FreeRTOSConfig.h`` 头文件中添加各种 ``#define config...`` 宏定义来配置内核。原生 FreeRTOS 支持一系列内核配置选项,允许启用或禁用各种内核行为和功能。 + +**然而,对于 ESP-IDF 中的所有 FreeRTOS 移植,FreeRTOSConfig.h 头文件被视为私有文件,用户不得修改。** 由于该选项在 ESP-IDF 中是必选项或不被支持,``FreeRTOSConfig.h`` 中的大量内核配置选项均为硬编码。所有用户可配置的内核配置选项都在 ``Component Config/FreeRTOS/Kernel`` 下的 menuconfig 中。 + +关于用户可配置内核选项的完整列表,参见 :doc:`/api-reference/kconfig`。下列为常用的内核配置选项: + +- :ref:`CONFIG_FREERTOS_UNICORE`:仅在 CPU0 上运行 FreeRTOS。注意,这 **不等同于运行原生 FreeRTOS。** 另外,此选项还可能影响除 :component:`freertos` 外其他组件的行为。关于在单核上运行 FreeRTOS 的更多内容,请参考 :ref:`freertos-smp-single-core` (使用 ESP-IDF FreeRTOS 时)或参考 Amazon SMP FreeRTOS 的官方文档,还可以在 ESP-IDF 组件中搜索 ``CONFIG_FREERTOS_UNICORE``。 + +.. only:: CONFIG_FREERTOS_UNICORE + + .. note:: + 由于 {IDF_TARGET_NAME} 是一个单核 SoC,所以总是会启用 :ref:`CONFIG_FREERTOS_UNICORE` 配置。 + +- :ref:`CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY` 可以向后兼容某些 FreeRTOS 宏、类型或函数,这些宏、类型或函数已在 v8.0 及以上版本中弃用。 + +端口配置 +^^^^^^^^^^^^^^^^^^ + +其他不属于内核配置的 FreeRTOS 相关配置选项都在 ``Component Config/FreeRTOS/Port`` 下的 menuconfig 中。这些选项可以配置以下内容: + +- FreeRTOS 端口本身(如 tick 定时器选择,ISR 堆栈大小) +- 其他添加到 FreeRTOS 实现或端口的功能 + +使用 FreeRTOS +---------------- + +应用程序入口点 +^^^^^^^^^^^^^^^^^^^^^^^ + +与原生 FreeRTOS 不同,在 ESP-IDF 中使用 FreeRTOS 的用户 **永远不应调用** :cpp:func:`vTaskStartScheduler` 和 :cpp:func:`vTaskEndScheduler`。相反,ESP-IDF 会自动启动 FreeRTOS。用户必须定义一个 ``void app_main(void)`` 函数作为用户应用程序的入口点,并在 ESP-IDF 启动时被自动调用。 + +- 通常,用户会从 ``app_main`` 中启动应用程序的其他任务。 +- ``app_main`` 函数可以在任何时候返回(应用终止前)。 +- ``app_main`` 函数由 ``main`` 任务调用。 + +.. _freertos_system_tasks: + +后台任务 +^^^^^^^^^^^^^^^^ + +在启动过程中,ESP-IDF 和 FreeRTOS 内核会自动创建多个在后台运行的任务,如下表所示。 + +.. list-table:: 启动过程创建任务列表 + :widths: 10 75 5 5 5 + :header-rows: 1 + + * - 任务名称 + - 描述 + - 堆栈大小 + - 亲和性 + - 优先级 + * - 空闲任务 (``IDLEx``) + - 为每个 CPU 核创建并固定一个空闲任务 (``IDLEx``),其中 ``x`` 是 CPU 核的编号 + - :ref:`CONFIG_FREERTOS_IDLE_TASK_STACKSIZE` + - Core x + - ``0`` + * - FreeRTOS 定时器任务 (``Tmr Svc``) + - 如果应用程序调用了任何 FreeRTOS 定时器 API,FreeRTOS 会创建定时器服务或守护任务 + - :ref:`CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH` + - Core 0 + - :ref:`CONFIG_FREERTOS_TIMER_TASK_PRIORITY` + * - 主任务 (``main``) + - 简单调用 ``app_main`` 的任务在 ``app_main`` 返回时会自我删除 + - :ref:`CONFIG_ESP_MAIN_TASK_STACK_SIZE` + - :ref:`CONFIG_ESP_MAIN_TASK_AFFINITY` + - ``1`` + * - IPC 任务 (``ipcx``) + - 当 :ref:`CONFIG_FREERTOS_UNICORE` 为假时,为每个 CPU 核创建并固定一个 IPC 任务 (``ipcx``)。IPC 任务用于实现处理器间调用 (IPC) 功能 + - :ref:`CONFIG_ESP_IPC_TASK_STACK_SIZE` + - Core x + - ``24`` + * - ESP 定时器任务 (``esp_timer``) + - ESP-IDF 创建 ESP 定时器任务用于处理 ESP 定时器回调 + - :ref:`CONFIG_ESP_TIMER_TASK_STACK_SIZE` + - Core 0 + - ``22`` + +.. note:: + 注意,如果应用程序使用了其他 ESP-IDF 功能(如 Wi-Fi 或蓝牙),那么这些功能可能会在上表的任务之外创建自己的后台任务。 + +FreeRTOS 附加功能 +------------------ + +ESP-IDF 还为 FreeRTOS 提供了一些补充功能,如环形缓冲区、ESP-IDF 风格的 Tick 和 Idle 钩子、以及 TLSP 删除回调。要了解更多信息,请参见 :doc:`freertos_additions`。 + +.. _freertos-heap: + +FreeRTOS 堆 +------------- + +原生 FreeRTOS 自带 `堆实现选择 `_,然而 ESP-IDF 已经实现了自己的堆(参见 :doc:`/api-reference/system/mem_alloc`),因此不使用原生 FreeRTOS 的堆实现。ESP-IDF 中的所有 FreeRTOS 端口都将 FreeRTOS 内存分配或释放调用(例如 ``pvPortMalloc()`` 和 ``pvPortFree()``)映射到 ESP-IDF 堆 API(即 :cpp:func:`heap_caps_malloc` 和 :cpp:func:`heap_caps_free`)。然而 FreeRTOS 端口可以确保 FreeRTOS 分配的所有动态内存都放在内部内存中。 + +.. note:: + 如果希望将 FreeRTOS 任务或对象放在外部内存中,可以使用以下方法: + + - 使用一个 ``...CreateWithCaps()`` API,如 :cpp:func:`xTaskCreateWithCaps` 和 :cpp:func:`xQueueCreateWithCaps` 来分配任务或对象(参见 :ref:`freertos-idf-additional-api` 获取更多详细信息)。 + - 使用 :cpp:func:`heap_caps_malloc` 为这些对象手动分配外部内存,然后使用 FreeRTOS 的一个 ``...CreateStatic()`` 函数从分配的内存中创建对象。 From d1593b82b09951983e1a779b8154fb1a235a367b Mon Sep 17 00:00:00 2001 From: "sonika.rathi" Date: Thu, 17 Aug 2023 09:36:32 +0200 Subject: [PATCH 36/71] fix(vfs/uart): Add support for multi-task call to uart select --- .../vfs/test_apps/main/test_vfs_select.c | 108 ++++++++++++++++-- components/vfs/vfs_uart.c | 24 ++-- 2 files changed, 113 insertions(+), 19 deletions(-) diff --git a/components/vfs/test_apps/main/test_vfs_select.c b/components/vfs/test_apps/main/test_vfs_select.c index ceab7004f7e..08b04728064 100644 --- a/components/vfs/test_apps/main/test_vfs_select.c +++ b/components/vfs/test_apps/main/test_vfs_select.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -101,6 +101,23 @@ static void uart1_init(void) uart_param_config(UART_NUM_1, &uart_config); } +static void read_task(void *param) +{ + char recv_message[sizeof(message)]; + const test_task_param_t *test_task_param = param; + vTaskDelay(test_task_param->delay_ms / portTICK_PERIOD_MS); + read(test_task_param->fd, recv_message, sizeof(message)); + if (test_task_param->sem) { + xSemaphoreGive(test_task_param->sem); + } + vTaskDelete(NULL); +} + +static inline void start_read_task(const test_task_param_t *test_task_param) +{ + xTaskCreate(read_task, "read_task", 8*1024, (void *) test_task_param, 5, NULL); +} + static void send_task(void *param) { const test_task_param_t *test_task_param = param; @@ -112,7 +129,7 @@ static void send_task(void *param) vTaskDelete(NULL); } -static inline void start_task(const test_task_param_t *test_task_param) +static inline void start_write_task(const test_task_param_t *test_task_param) { xTaskCreate(send_task, "send_task", 8*1024, (void *) test_task_param, 5, NULL); } @@ -165,7 +182,7 @@ TEST_CASE("UART can do select()", "[vfs]") .sem = xSemaphoreCreateBinary(), }; TEST_ASSERT_NOT_NULL(test_task_param.sem); - start_task(&test_task_param); + start_write_task(&test_task_param); int s = select(uart_fd + 1, &rfds, NULL, NULL, &tv); TEST_ASSERT_EQUAL(s, 1); @@ -182,7 +199,7 @@ TEST_CASE("UART can do select()", "[vfs]") FD_SET(uart_fd, &rfds); FD_SET(socket_fd, &rfds); - start_task(&test_task_param); + start_write_task(&test_task_param); s = select(MAX(uart_fd, socket_fd) + 1, &rfds, NULL, NULL, &tv); TEST_ASSERT_EQUAL(s, 1); @@ -223,7 +240,7 @@ TEST_CASE("UART can do poll() with POLLIN event", "[vfs]") .sem = xSemaphoreCreateBinary(), }; TEST_ASSERT_NOT_NULL(test_task_param.sem); - start_task(&test_task_param); + start_write_task(&test_task_param); int s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100); TEST_ASSERT_EQUAL(s, 1); @@ -241,7 +258,7 @@ TEST_CASE("UART can do poll() with POLLIN event", "[vfs]") poll_fds[1].fd = socket_fd; poll_fds[1].events = POLLIN; - start_task(&test_task_param); + start_write_task(&test_task_param); s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100); TEST_ASSERT_EQUAL(s, 1); @@ -284,7 +301,7 @@ TEST_CASE("UART can do poll() with POLLOUT event", "[vfs]") .sem = xSemaphoreCreateBinary(), }; TEST_ASSERT_NOT_NULL(test_task_param.sem); - start_task(&test_task_param); + start_write_task(&test_task_param); poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100); TEST_ASSERT_EQUAL(uart_fd, poll_fds[0].fd); @@ -330,7 +347,7 @@ TEST_CASE("socket can do select()", "[vfs]") .sem = xSemaphoreCreateBinary(), }; TEST_ASSERT_NOT_NULL(test_task_param.sem); - start_task(&test_task_param); + start_write_task(&test_task_param); const int s = select(MAX(MAX(uart_fd, socket_fd), dummy_socket_fd) + 1, &rfds, NULL, NULL, &tv); TEST_ASSERT_EQUAL(1, s); @@ -379,7 +396,7 @@ TEST_CASE("socket can do poll()", "[vfs]") .sem = xSemaphoreCreateBinary(), }; TEST_ASSERT_NOT_NULL(test_task_param.sem); - start_task(&test_task_param); + start_write_task(&test_task_param); int s = poll(poll_fds, sizeof(poll_fds)/sizeof(poll_fds[0]), 100); TEST_ASSERT_EQUAL(s, 1); @@ -474,8 +491,7 @@ static void select_task(void *task_param) { const test_select_task_param_t *param = task_param; - int s = select(param->maxfds, param->rdfds, param->wrfds, param->errfds, param->tv); - TEST_ASSERT_EQUAL(param->select_ret, s); + select(param->maxfds, param->rdfds, param->wrfds, param->errfds, param->tv); if (param->sem) { xSemaphoreGive(param->sem); @@ -489,6 +505,74 @@ static void inline start_select_task(test_select_task_param_t *param) } #if !CONFIG_IDF_TARGET_ESP32H2 // IDF-6782 +TEST_CASE("concurrent selects work for UART", "[vfs]") +{ + // This test case initiates two select tasks on the same UART FD, + // One task will wait for a write operation, while the other will wait for a read operation to occur. + // The first task will complete its operation before the second task proceeds with its operation on the same FD + // In this scenario, the write operation will be performed initially, + // followed by the subsequent continuation of the read operation. + + int uart_fd, socket_fd; + init(&uart_fd, &socket_fd); + + const test_task_param_t send_param = { + .fd = uart_fd, + .delay_ms = 0, + .sem = NULL, + }; + + fd_set wrfds1; + FD_ZERO(&wrfds1); + FD_SET(uart_fd, &wrfds1); + + test_select_task_param_t param_write = { + .rdfds = NULL, + .wrfds = &wrfds1, + .errfds = NULL, + .maxfds = uart_fd + 1, + .tv = NULL, + .select_ret = 1, + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(param_write.sem); + //Start first task which will wait on select call for write operation on the UART FD + start_select_task(¶m_write); + + fd_set rdfds2; + FD_ZERO(&rdfds2); + FD_SET(uart_fd, &rdfds2); + + test_select_task_param_t param_read = { + .rdfds = &rdfds2, + .wrfds = NULL, + .errfds = NULL, + .maxfds = uart_fd + 1, + .tv = NULL, + .select_ret = 2, + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(param_read.sem); + //Start second task which will wait on another select call for read operation on the same UART FD + start_select_task(¶m_read); + + //Start writing operation on the UART port + start_write_task(&send_param); + //Confirm the completion of the write operation + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param_write.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(param_write.sem); + TEST_ASSERT(FD_ISSET(uart_fd, &wrfds1)); + + //Start reading operation on the same UART port + start_read_task(&send_param); + //Confirm the completion of the read operation + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param_read.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(param_read.sem); + TEST_ASSERT(FD_ISSET(uart_fd, &rdfds2)); + + deinit(uart_fd, socket_fd); +} + TEST_CASE("concurrent selects work", "[vfs]") { int uart_fd, socket_fd; @@ -564,7 +648,7 @@ TEST_CASE("concurrent selects work", "[vfs]") .sem = xSemaphoreCreateBinary(), }; TEST_ASSERT_NOT_NULL(send_param.sem); - start_task(&send_param); // This task will write to UART which will be detected by select() + start_write_task(&send_param); // This task will write to UART which will be detected by select() start_select_task(¶m); vTaskDelay(100 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index 3e1fcf4a74b..9e96d138c91 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,6 +21,7 @@ #include "esp_rom_uart.h" #include "soc/soc_caps.h" #include "hal/uart_ll.h" +#include "freertos/semphr.h" #define UART_NUM SOC_UART_HP_NUM @@ -55,6 +56,7 @@ static int uart_rx_char(int fd); // Functions for sending and receiving bytes which use UART driver static void uart_tx_char_via_driver(int fd, int c); static int uart_rx_char_via_driver(int fd); +static SemaphoreHandle_t uart_select_mutex[UART_NUM]; typedef struct { // Pointers to UART peripherals @@ -150,6 +152,8 @@ static int uart_open(const char *path, int flags, int mode) return -1; } + uart_select_mutex[fd] = xSemaphoreCreateMutex(); + xSemaphoreGive(uart_select_mutex[fd]); s_ctx[fd]->non_blocking = ((flags & O_NONBLOCK) == O_NONBLOCK); return fd; @@ -298,6 +302,7 @@ static int uart_fstat(int fd, struct stat * st) static int uart_close(int fd) { assert(fd >=0 && fd < 3); + vSemaphoreDelete(uart_select_mutex[fd]); return 0; } @@ -437,6 +442,7 @@ static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, esp_vfs_select_sem_t select_sem, void **end_select_args) { const int max_fds = MIN(nfds, UART_NUM); + int fd = -1; *end_select_args = NULL; for (int i = 0; i < max_fds; ++i) { @@ -444,6 +450,7 @@ static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, if (!uart_is_driver_installed(i)) { return ESP_ERR_INVALID_STATE; } + fd = i; } } @@ -464,14 +471,11 @@ static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, FD_ZERO(writefds); FD_ZERO(exceptfds); + xSemaphoreTake(uart_select_mutex[fd], portMAX_DELAY); portENTER_CRITICAL(uart_get_selectlock()); //uart_set_select_notif_callback sets the callbacks in UART ISR - for (int i = 0; i < max_fds; ++i) { - if (FD_ISSET(i, &args->readfds_orig) || FD_ISSET(i, &args->writefds_orig) || FD_ISSET(i, &args->errorfds_orig)) { - uart_set_select_notif_callback(i, select_notif_callback_isr); - } - } + uart_set_select_notif_callback(fd, select_notif_callback_isr); for (int i = 0; i < max_fds; ++i) { if (FD_ISSET(i, &args->readfds_orig)) { @@ -500,17 +504,23 @@ static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, static esp_err_t uart_end_select(void *end_select_args) { uart_select_args_t *args = end_select_args; + int fd = -1; portENTER_CRITICAL(uart_get_selectlock()); esp_err_t ret = unregister_select(args); for (int i = 0; i < UART_NUM; ++i) { - uart_set_select_notif_callback(i, NULL); + if (FD_ISSET(i, &args->readfds_orig) || FD_ISSET(i, &args->writefds_orig) || FD_ISSET(i, &args->errorfds_orig)) { + uart_set_select_notif_callback(i, NULL); + fd = i; + break; + } } portEXIT_CRITICAL(uart_get_selectlock()); if (args) { free(args); } + xSemaphoreGive(uart_select_mutex[fd]); return ret; } From d22387b698db7d54a4f4cbd887a961dc76d88973 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Mon, 18 Sep 2023 12:07:18 +0200 Subject: [PATCH 37/71] docs(readme): Add video tutorial from the Devcon23 conference --- README.md | 2 ++ README_CN.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 7cf41fb39c7..ae564cb49e9 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,8 @@ This can be combined with other targets, ie `idf.py -p PORT erase-flash flash` w * Documentation for the latest version: https://docs.espressif.com/projects/esp-idf/. This documentation is built from the [docs directory](docs) of this repository. +* [Beginner's Guide to Key Concepts and Resources of ESP-IDF](https://youtu.be/J8zc8mMNKtc?feature=shared) + * The [esp32.com forum](https://esp32.com/) is a place to ask questions and find community resources. * [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one. diff --git a/README_CN.md b/README_CN.md index 933cc5f9e7a..6e9dc4d8750 100644 --- a/README_CN.md +++ b/README_CN.md @@ -120,6 +120,8 @@ ESP-IDF 中的子模块采用相对路径([详见 .gitmodules 文件](.gitmodu * 最新版的文档:https://docs.espressif.com/projects/esp-idf/ ,该文档是由本仓库 [docs 目录](docs) 构建得到。 +* [初学者指南:主要概念和资源](https://www.bilibili.com/video/BV1114y1r7du/) + * 可以前往 [esp32.com 论坛](https://esp32.com/) 提问,挖掘社区资源。 * 如果你在使用中发现了错误或者需要新的功能,请先[查看 GitHub Issues](https://github.com/espressif/esp-idf/issues),确保该问题没有重复提交。 From 96cf03659a21373ab7a8bc2b01ae31db99cbd8f2 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Mon, 18 Sep 2023 12:11:56 +0200 Subject: [PATCH 38/71] docs(readme): Remove unsupported versions and add new chip --- README.md | 15 ++++++++------- README_CN.md | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index ae564cb49e9..9e9581d966c 100644 --- a/README.md +++ b/README.md @@ -15,15 +15,16 @@ ESP-IDF is the development framework for Espressif SoCs supported on Windows, Li The following table shows ESP-IDF support of Espressif SoCs where ![alt text][preview] and ![alt text][supported] denote preview status and support, respectively. The preview support is usually limited in time and intended for beta versions of chips. Please use an ESP-IDF release where the desired SoC is already supported. -|Chip | v4.2 | v4.3 | v4.4 | v5.0 | v5.1 | | -|:----------- | :---------------------:| :---------------------:| :---------------------:| :---------------------:| :--------------------: | :----------------------------------------------------------| +|Chip | v4.3 | v4.4 | v5.0 | v5.1 | v5.2 | | +|:----------- | :---------------------:| :---------------------:| :---------------------:| :--------------------: | :--------------------: | :----------------------------------------------------------| |ESP32 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | |ESP32-S2 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | -|ESP32-C3 | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | -|ESP32-S3 | | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32_S3) | -|ESP32-C2 | | | | ![alt text][supported] | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32-C2) | -|ESP32-C6 | | | | | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32_C6) | -|ESP32-H2 | | | | | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32_H2) | +|ESP32-C3 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | +|ESP32-S3 | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32_S3) | +|ESP32-C2 | | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32-C2) | +|ESP32-C6 | | | | ![alt text][supported] | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32_C6) | +|ESP32-H2 | | | | ![alt text][supported] | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32_H2) | +|ESP32-P4 | | | | | ![alt text][preview] | [Announcement](https://www.espressif.com/en/news/ESP32-P4) | [supported]: https://img.shields.io/badge/-supported-green "supported" [preview]: https://img.shields.io/badge/-preview-orange "preview" diff --git a/README_CN.md b/README_CN.md index 6e9dc4d8750..9c6ee6d8b4e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -15,15 +15,16 @@ ESP-IDF 是乐鑫官方推出的物联网开发框架,支持 Windows、Linux 下表总结了乐鑫芯片在 ESP-IDF 各版本中的支持状态,其中 ![alt text][supported] 代表已支持,![alt text][preview] 代表目前处于预览支持状态。预览支持状态通常有时间限制,而且仅适用于测试版芯片。请确保使用与芯片相匹配的 ESP-IDF 版本。 -|芯片 | v4.2 | v4.3 | v4.4 | v5.0 | v5.1 | | -|:----------- |:---------------------:| :---------------------:| :---------------------:| :---------------------:| :--------------------: | :-------------------------------------------------------------- | -|ESP32 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | -|ESP32-S2 |![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | -|ESP32-C3 | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | -|ESP32-S3 | | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_S3) | -|ESP32-C2 | | | | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32-C2) | -|ESP32-C6 | | | | | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_C6) | -|ESP32-H2 | | | | | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_H2) | +|芯片 | v4.3 | v4.4 | v5.0 | v5.1 | v5.2 | | +|:----------- | :---------------------:| :---------------------:| :---------------------:| :--------------------: | :--------------------: | :-------------------------------------------------------------- | +|ESP32 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | +|ESP32-S2 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | +|ESP32-C3 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | | +|ESP32-S3 | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_S3) | +|ESP32-C2 | | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32-C2) | +|ESP32-C6 | | | | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_C6) | +|ESP32-H2 | | | | ![alt text][supported] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/zh-hans/news/ESP32_H2) | +|ESP32-P4 | | | | | ![alt text][preview] | [芯片发布公告](https://www.espressif.com/en/news/ESP32-P4) | [supported]: https://img.shields.io/badge/-%E6%94%AF%E6%8C%81-green "supported" [preview]: https://img.shields.io/badge/-%E9%A2%84%E8%A7%88-orange "preview" From bb6feca7a9495ddcb4fb3ba75f235d717f0e99d4 Mon Sep 17 00:00:00 2001 From: Cai Xinying Date: Tue, 8 Aug 2023 11:46:12 +0800 Subject: [PATCH 39/71] docs: provide CN translation for api-reference/peripherals/adc_continuous.rst --- .../peripherals/adc_continuous.rst | 219 ++++++----- .../peripherals/adc_continuous.rst | 360 +++++++++++++++++- 2 files changed, 487 insertions(+), 92 deletions(-) diff --git a/docs/en/api-reference/peripherals/adc_continuous.rst b/docs/en/api-reference/peripherals/adc_continuous.rst index e88a0f4c665..a22c733430b 100644 --- a/docs/en/api-reference/peripherals/adc_continuous.rst +++ b/docs/en/api-reference/peripherals/adc_continuous.rst @@ -1,27 +1,29 @@ Analog to Digital Converter (ADC) Continuous Mode Driver ======================================================== +:link_to_translation:`zh_CN:[中文]` + {IDF_TARGET_ADC_NUM:default="two", esp32c2="one", esp32c6="one", esp32h2="one"} Introduction ------------ -The Analog to Digital Converter is an on-chip sensor which is able to measure analog signals from specific analog IO pads. +The Analog to Digital Converter is integrated on the chip and is capable of measuring analog signals from specific analog IO pads. Additionally, the Direct Memory Access (DMA) functionality is utilized to efficiently retrieve ADC conversion results. -{IDF_TARGET_NAME} has {IDF_TARGET_ADC_NUM} ADC unit(s), which can be used in scenario(s) like: +{IDF_TARGET_NAME} has {IDF_TARGET_ADC_NUM} ADC unit(s), which can be used in scenarios like: - Generate one-shot ADC conversion result - Generate continuous ADC conversion results -This guide will introduce ADC continuous mode conversion. +This guide introduces ADC continuous mode conversion. Driver Concepts ^^^^^^^^^^^^^^^ -ADC continuous mode conversion is made up with multiple Conversion Frames. +ADC continuous mode conversion is made up of multiple conversion frames. -- Conversion Frame: One Conversion Frame contains multiple Conversion Results. Conversion Frame size is configured in :cpp:func:`adc_continuous_new_handle`, in bytes. -- Conversion Result: One Conversion Result contains multiple bytes (see :c:macro:`SOC_ADC_DIGI_RESULT_BYTES`). Its structure is :cpp:type:`adc_digi_output_data_t`, including ADC unit, ADC channel and raw data. +- Conversion Frame: One conversion frame contains multiple conversion results. Conversion frame size is configured in :cpp:func:`adc_continuous_new_handle` in bytes. +- Conversion Result: One conversion result contains multiple bytes, see :c:macro:`SOC_ADC_DIGI_RESULT_BYTES`. Its structure is :cpp:type:`adc_digi_output_data_t`, including ADC unit, ADC channel, and raw data. .. image:: /../_static/diagrams/adc/adc_conversion_frame.png :scale: 100 % @@ -30,40 +32,44 @@ ADC continuous mode conversion is made up with multiple Conversion Frames. Functional Overview ------------------- -The following sections of this document cover the typical steps to install the ADC continuous mode driver, and read ADC conversion results from group of ADC channels continuously: +The following sections of this document cover the typical steps to install the ADC continuous mode driver, and read ADC conversion results from a group of ADC channels continuously: + +- :ref:`adc-continuous-resource-allocation`: covers which parameters should be set up to initialize the ADC continuous mode driver and how to deinitialize it. +- :ref:`adc-continuous-adc-configurations`: describes how to configure the ADC(s) to make it work under continuous mode. +- :ref:`adc-continuous-adc-control`: describes ADC control functions. +- :ref:`adc-continuous-register-event-callbacks`: describes how to hook user-specific code to an ADC continuous mode event callback function. +- :ref:`adc-continuous-read-conversion-result`: covers how to get ADC conversion result. +- :ref:`adc-continuous-hardware-limitations`: describes the ADC-related hardware limitations. +- :ref:`adc-continuous-power-management`: covers power management-related information. +- :ref:`adc-continuous-iram-safe`: covers the IRAM safe functions. +- :ref:`adc-continuous-thread-safety`: lists which APIs are guaranteed to be thread-safe by the driver. -- `Resource Allocation <#resource-allocation>`__ - covers which parameters should be set up to initialize the ADC continuous mode driver and how to deinitialize it. -- `ADC Configurations <#adc-configurations>`__ - describes how to configure the ADC(s) to make it work under continuous mode. -- `ADC Control <#adc-control>`__ - describes ADC control functions. -- `Register Event Callbacks <#register-event-callbacks>`__ - describes how to hook user specific code to an ADC continuous mode event callback function. -- `Read Conversion Result <#read-conversion-result>`__ - covers how to get ADC conversion result. -- `Hardware Limitations <#hardware-limitations>`__ - describes the ADC related hardware limitations. -- `Power Management <#power-management>`__ - covers power management related. -- `IRAM Safe <#iram-safe>`__ - covers the IRAM safe functions. -- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. +.. _adc-continuous-resource-allocation: Resource Allocation ^^^^^^^^^^^^^^^^^^^ -The ADC continuous mode driver is implemented based on {IDF_TARGET_NAME} SAR ADC module. Different ESP targets might have different number of independent ADCs. +The ADC continuous mode driver is implemented based on {IDF_TARGET_NAME} SAR ADC module. Different ESP targets might have different numbers of independent ADCs. To create an ADC continuous mode driver handle, set up the required configuration structure :cpp:type:`adc_continuous_handle_cfg_t`: -- :cpp:member:`adc_continuous_handle_cfg_t::max_store_buf_size` set the maximum size (in bytes) of the pool that the driver saves ADC conversion result into. If this pool is full, new conversion results will be lost. -- :cpp:member:`adc_continuous_handle_cfg_t::conv_frame_size` set the size of the ADC conversion frame, in bytes. -- :cpp:member:`adc_continuous_handle_cfg_t::flags` set the flags that can change the driver behaviour. +- :cpp:member:`adc_continuous_handle_cfg_t::max_store_buf_size`: set the maximum size of the pool in bytes, and the driver saves ADC conversion result into the pool. If this pool is full, new conversion results will be lost. +- :cpp:member:`adc_continuous_handle_cfg_t::conv_frame_size`: set the size of the ADC conversion frame, in bytes. +- :cpp:member:`adc_continuous_handle_cfg_t::flags`: set the flags that can change the driver's behavior. + + - ``flush_pool``: auto flush the pool when it's full. -After setting up above configurations for the ADC, call :cpp:func:`adc_continuous_new_handle` with the prepared :cpp:type:`adc_continuous_handle_cfg_t`. This function may fail due to various errors such as invalid argumemts, insufficient memory, etc. +After setting up the above configurations for the ADC, call :cpp:func:`adc_continuous_new_handle` with the prepared :cpp:type:`adc_continuous_handle_cfg_t`. This function may fail due to various errors such as invalid arguments, insufficient memory, etc. .. only:: esp32 - Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means the I2S0 peripheral is in use. See `Hardware Limitations <#hardware-limitations>`__ for more information. + Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means the I2S0 peripheral is in use. See :ref:`adc-continuous-hardware-limitations` for more information. .. only:: esp32s2 - Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means the SPI3 peripheral is in use. See `Hardware Limitations <#hardware-limitations>`__ for more information. + Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means the SPI3 peripheral is in use. See :ref:`adc-continuous-hardware-limitations` for more information. .. only:: SOC_GDMA_SUPPORTED @@ -77,15 +83,15 @@ If the ADC continuous mode driver is no longer used, you should deinitialize the IIR filter ~~~~~~~~~~ - Two IIR filters are available when ADC is working under continuous mode. To create an ADC IIR filter, you should set up the :cpp:type:`adc_continuous_iir_filter_config_t`, and call :cpp:func:`adc_new_continuous_iir_filter`. + Two IIR filters are available when ADC is working in continuous mode. To create an ADC IIR filter, you should set up :cpp:type:`adc_continuous_iir_filter_config_t` and call :cpp:func:`adc_new_continuous_iir_filter`. - - :cpp:member:`adc_digi_filter_config_t::unit`, ADC unit. - - :cpp:member:`adc_digi_filter_config_t::channel`, ADC channel to be filtered. - - :cpp:member:`adc_digi_filter_config_t::coeff`, filter coefficient. + - :cpp:member:`adc_digi_filter_config_t::unit`: ADC unit. + - :cpp:member:`adc_digi_filter_config_t::channel`: ADC channel to be filtered. + - :cpp:member:`adc_digi_filter_config_t::coeff`: Filter coefficient. .. only:: SOC_ADC_DIG_IIR_FILTER_UNIT_BINDED - On ESP32S2, the filter is per ADC unit. Once a filter is enabled, all the enabled ADC channels in this ADC unit will be filtered. However, we suggest only enabling one ADC channel per unit, when using the filter feature. Because the filtered results depend on the previous filtered result. So you should not enable multiple ADC channels, to avoid mixing the filtered results. + On {IDF_TARGET_NAME}, the filter is per ADC unit. Once a filter is enabled, all the enabled ADC channels in this ADC unit will be filtered. However, we suggest only enabling one ADC channel per unit, when using the filter feature. Because the filtered results depend on the previous filtered result. So you should not enable multiple ADC channels, to avoid mixing the filtered results. To recycle a filter, you should call :cpp:func:`adc_del_continuous_iir_filter`. @@ -93,34 +99,35 @@ If the ADC continuous mode driver is no longer used, you should deinitialize the .. note:: - If you use both the filters on a same ADC channel, then only the first one will take effect. + If you use both filters on the same ADC channel, then only the first one will take effect. .. only:: SOC_ADC_MONITOR_SUPPORTED Monitor ~~~~~~~ - {IDF_TARGET_SOC_ADC_DIGI_MONITOR_NUM} monitors are available when ADC is working under continuous mode, you can set one or two threshold(s) of a monitor on a working ADC channel, then monitor will invoke interrupts every sample loop if converted value outranges of the threshold. To create an ADC monitor, you need setup the :cpp:type:`adc_monitor_config_t` and call :cpp:func:`adc_new_continuous_monitor`. - - :cpp:member:`adc_monitor_config_t::adc_unit`, What ADC unit the channel you want to monit belongs to. - - :cpp:member:`adc_monitor_config_t::channel`, The channel you want to monit. - - :cpp:member:`adc_monitor_config_t::h_threshold`, The high threshold, convert value lager than this value will invoke interrupt, set to -1 if don't use. - - :cpp:member:`adc_monitor_config_t::l_threshold`, The low threshold, convert value less than this value will invoke interrupt, set to -1 if don't use. + {IDF_TARGET_SOC_ADC_DIGI_MONITOR_NUM} monitors are available when ADC is working under continuous mode, you can set one or two threshold(s) of a monitor on a working ADC channel, then the monitor will invoke interrupts every sample loop if conversion result outranges of the threshold. To create an ADC monitor, you need to set up the :cpp:type:`adc_monitor_config_t` and call :cpp:func:`adc_new_continuous_monitor`. + + - :cpp:member:`adc_monitor_config_t::adc_unit`: Configures which ADC unit the channel you want to monitor belongs to. + - :cpp:member:`adc_monitor_config_t::channel`: The channel you want to monitor. + - :cpp:member:`adc_monitor_config_t::h_threshold`: The high threshold, conversion result larger than this value invokes interrupt, set to -1 if do not use. + - :cpp:member:`adc_monitor_config_t::l_threshold`: The low threshold, conversion result less than this value invokes interrupt, set to -1 if do not use. Once a monitor is created, you can operate it by following APIs to construct your apps. - - :cpp:func:`adc_continuous_monitor_enable`, Enable a monitor. - - :cpp:func:`adc_continuous_monitor_disable`, Disable a monitor. - - :cpp:func:`adc_monitor_register_callbacks`, Register user callbacks to do something when ADC value outrange of the threshold. - - :cpp:func:`adc_del_continuous_monitor`, Delete a created monitor, free resources. + - :cpp:func:`adc_continuous_monitor_enable`: Enable a monitor. + - :cpp:func:`adc_continuous_monitor_disable`: Disable a monitor. + - :cpp:func:`adc_monitor_register_callbacks`: register user callbacks to take action when the ADC value exceeds of the threshold. + - :cpp:func:`adc_del_continuous_monitor`: Delete a created monitor and free resources. .. only:: esp32s2 .. NOTE:: - There are some hardware limitations on ESP32S2: - 1. Only one threshold supported for one monitor. - 2. Only one monitor supported for one adc unit. - 3. All enabled channel(s) of a certain adc unit in adc continuous mode driver will be monitored, param :cpp:member:`adc_monitor_config_t::channel` will not used. + There are some hardware limitations on {IDF_TARGET_NAME}: + 1. Only one threshold is supported for one monitor. + 2. Only one monitor is supported for one ADC unit. + 3. All enabled channel(s) of a certain ADC unit in ADC continuous mode driver will be monitored. The :cpp:member:`adc_monitor_config_t::channel` parameter will not be used. Initialize the ADC Continuous Mode Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -142,38 +149,44 @@ Recycle the ADC Unit ESP_ERROR_CHECK(adc_continuous_deinit()); +.. _adc-continuous-adc-configurations: + ADC Configurations ^^^^^^^^^^^^^^^^^^ After the ADC continuous mode driver is initialized, set up the :cpp:type:`adc_continuous_config_t` to configure ADC IOs to measure analog signal: -- :cpp:member:`adc_continuous_config_t::pattern_num`, number of ADC channels that will be used. -- :cpp:member:`adc_continuous_config_t::adc_pattern`, list of configs for each ADC channel that will be used, see below description. -- :cpp:member:`adc_continuous_config_t::sample_freq_hz`, expected ADC sampling frequency in Hz. -- :cpp:member:`adc_continuous_config_t::conv_mode`, continuous conversion mode. -- :cpp:member:`adc_continuous_config_t::format`, conversion output format. +- :cpp:member:`adc_continuous_config_t::pattern_num`: number of ADC channels that will be used. +- :cpp:member:`adc_continuous_config_t::adc_pattern`: list of configs for each ADC channel that will be used, see the description below. +- :cpp:member:`adc_continuous_config_t::sample_freq_hz`: expected ADC sampling frequency in Hz. +- :cpp:member:`adc_continuous_config_t::conv_mode`: continuous conversion mode. +- :cpp:member:`adc_continuous_config_t::format`: conversion output format. -For :cpp:type:`adc_digi_pattern_config_t`: +Set :cpp:type:`adc_digi_pattern_config_t` with the following process: -- :cpp:member:`adc_digi_pattern_config_t::atten`, ADC attenuation. Refer to the On-Chip Sensor chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__. -- :cpp:member:`adc_digi_pattern_config_t::channel`, the IO corresponding ADC channel number. See below note. -- :cpp:member:`adc_digi_pattern_config_t::unit`, the ADC that the IO is subordinate to. -- :cpp:member:`adc_digi_pattern_config_t::bit_width`, the bitwidth of the raw conversion result. +- :cpp:member:`adc_digi_pattern_config_t::atten`: ADC attenuation. Refer to the On-Chip Sensor and Analog Signal Processing chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__. +- :cpp:member:`adc_digi_pattern_config_t::channel`: the IO corresponding ADC channel number. See the note below. +- :cpp:member:`adc_digi_pattern_config_t::unit`: the ADC that the IO is subordinate to. +- :cpp:member:`adc_digi_pattern_config_t::bit_width`: the bitwidth of the raw conversion result. .. note:: - For the IO corresponding ADC channel number. Check `datasheet <{IDF_TARGET_TRM_EN_URL}>`__ to acquire the ADC IOs. - On the other hand, :cpp:func:`adc_continuous_io_to_channel` and :cpp:func:`adc_continuous_channel_to_io` can be used to acquire the ADC channels and ADC IOs. + For the IO corresponding ADC channel number, check `TRM <{IDF_TARGET_TRM_EN_URL}#sensor>`__ to acquire the ADC IOs. Besides, :cpp:func:`adc_continuous_io_to_channel` and :cpp:func:`adc_continuous_channel_to_io` can be used to acquire the ADC channels and ADC IOs. -To make these settings take effect, call :cpp:func:`adc_continuous_config` with the configuration structure above. -This API may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. When it returns :c:macro:`ESP_ERR_INVALID_STATE`, this means the ADC continuous mode driver is started, you shouldn't call this API at this moment. +To make these settings take effect, call :cpp:func:`adc_continuous_config` with the configuration structure above. This API may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. When it returns :c:macro:`ESP_ERR_INVALID_STATE`, this means the ADC continuous mode driver is started, you should not call this API at this moment. See ADC continuous mode example :example:`peripherals/adc/continuous_read` to see configuration codes. .. only:: SOC_ADC_DIG_IIR_FILTER_SUPPORTED - To enable / disable the ADC IIR filter, you should call :cpp:func:`adc_continuous_iir_filter_enable` / :cpp:func:`adc_continuous_iir_filter_disable`. + To enable/disable the ADC IIR filter, you should call :cpp:func:`adc_continuous_iir_filter_enable` / :cpp:func:`adc_continuous_iir_filter_disable`. + +.. only:: SOC_ADC_MONITOR_SUPPORTED + + To enable/disable the ADC monitor, you should call :cpp:func:`adc_continuous_monitor_enable` / :cpp:func:`adc_continuous_monitor_disable`. + +.. _adc-continuous-adc-control: ADC Control ^^^^^^^^^^^ @@ -181,8 +194,9 @@ ADC Control Start and Stop ~~~~~~~~~~~~~~ -Calling :cpp:func:`adc_continuous_start` will make the ADC start to measure analog signals from the configured ADC channels, and generate the conversion results. -On the contrary, calling :cpp:func:`adc_continuous_stop` will stop the ADC conversion. +Calling :cpp:func:`adc_continuous_start` makes the ADC start to measure analog signals from the configured ADC channels, and generate the conversion results. + +On the contrary, calling :cpp:func:`adc_continuous_stop` stops the ADC conversion. .. code::c @@ -193,24 +207,27 @@ On the contrary, calling :cpp:func:`adc_continuous_stop` will stop the ADC conve ESP_ERROR_CHECK(adc_continuous_stop()); +.. _adc-continuous-register-event-callbacks: + Register Event Callbacks ^^^^^^^^^^^^^^^^^^^^^^^^ -By calling :cpp:func:`adc_continuous_register_event_callbacks`, you can hook your own function to the driver ISR. Supported event callbacks are listed in :cpp:type:`adc_continuous_evt_cbs_t` -- :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done`, this is invoked when one conversion frame finishes. -- :cpp:member:`adc_continuous_evt_cbs_t::on_pool_ovf`, this is invoked when internal pool is full. Newer conversion results will be discarded. +By calling :cpp:func:`adc_continuous_register_event_callbacks`, you can hook your own function to the driver ISR. Supported event callbacks are listed in :cpp:type:`adc_continuous_evt_cbs_t`. + +- :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done`: this is invoked when one conversion frame finishes. +- :cpp:member:`adc_continuous_evt_cbs_t::on_pool_ovf`: this is invoked when the internal pool is full. Newer conversion results will be discarded. -As above callbacks are called in an ISR context, you should always ensure the callback function is suitable for an ISR context. Blocking logics should not appear in these callbacks. Callback function prototype is declared in :cpp:type:`adc_continuous_callback_t`. +As the above callbacks are called in an ISR context, you should always ensure the callback function is suitable for an ISR context. Blocking logic should not appear in these callbacks. The callback function prototype is declared in :cpp:type:`adc_continuous_callback_t`. -You can also register your own context when calling :cpp:func:`adc_continuous_register_event_callbacks`, by the parameter ``user_data``. This user data will be passed to the callback functions directly. +You can also register your own context when calling :cpp:func:`adc_continuous_register_event_callbacks` by the parameter ``user_data``. This user data will be passed to the callback functions directly. -This function may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. Specially, when :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` is enabled, this error may indicate that the callback functions aren't in internal RAM. Check error log to know this. Besides, when it fails due to :c:macro:`ESP_ERR_INVALID_STATE`, this means the ADC continuous mode driver is started, you shouldn't add callback at this moment. +This function may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. Especially, when :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` is enabled, this error may indicate that the callback functions are not in the internal RAM. Check the error log for more details. Besides, when it fails due to :c:macro:`ESP_ERR_INVALID_STATE`, it indicates that the ADC continuous mode driver is started, and you should not add a callback at this moment. Conversion Done Event ~~~~~~~~~~~~~~~~~~~~~ -The driver will fill in the event data of a :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done` event. Event data contains a buffer pointer to a conversion frame buffer, together with the size. Refer to :cpp:type:`adc_continuous_evt_data_t` to know the event data structure. +When the driver completes a conversion, it triggers the :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done` event and fills the event data. Event data contains a buffer pointer to a conversion frame buffer, together with the size. Refer to :cpp:type:`adc_continuous_evt_data_t` to know the event data structure. .. note:: @@ -223,23 +240,25 @@ The driver will fill in the event data of a :cpp:member:`adc_continuous_evt_cbs_ Pool Overflow Event ~~~~~~~~~~~~~~~~~~~ -The ADC continuous mode driver has an internal pool to save the conversion results. When the pool is full, a pool overflow event will emerge. Under this condition, the driver won't fill in the event data. This usually happens the speed to read data from the pool (by calling :cpp:func:`adc_continuous_read`) is much slower than the ADC conversion speed. +The ADC continuous mode driver has an internal pool to save the conversion results. When the pool is full, a pool overflow event will emerge. Under this condition, the driver will not fill in the event data. This usually happens because the speed to read data from the pool by calling :cpp:func:`adc_continuous_read` is much slower than the ADC conversion speed. + +.. _adc-continuous-read-conversion-result: Read Conversion Result ^^^^^^^^^^^^^^^^^^^^^^ After calling :cpp:func:`adc_continuous_start`, the ADC continuous conversion starts. Call :cpp:func:`adc_continuous_read` to get the conversion results of the ADC channels. You need to provide a buffer to get the raw results. -This function will try to read the expected length of conversion results each time. +Function :cpp:func:`adc_continuous_read` tries to read the expected length of conversion results each time. -- If the requested length isn't reached, the function will still move the data from the internal pool to the buffer you prepared. Therefore, check the `out_length` to know the actual size of conversion results. -- If there is no conversion result generated in the internal pool, the function will block for `timeout_ms` until the conversion results are generated. If there is still no generated results, the function will return :c:macro:`ESP_ERR_TIMEOUT`. -- If the generated results fill up the internal pool, new generated results will be lost. Next time when the :cpp:func:`adc_continuous_read` is called, this function will return :c:macro:`ESP_ERR_INVALID_STATE` indicating this situation. +- When calling :cpp:func:`adc_continuous_read`, you can request to read a conversion result of the specified length. Sometimes, however, the actual available conversion results may be less than the requested length, in which case the function still moves the data from the internal pool into the buffer you provided. Therefore, to learn the number of conversion results actually moved into the buffer, please check the value of ``out_length``. +- If there is no conversion result generated in the internal pool, the function will block for ``timeout_ms`` until the conversion results are generated. If there are still no generated results, the function will return :c:macro:`ESP_ERR_TIMEOUT`. +- If the generated results fill up the internal pool, newly generated results will be lost. Next time when :cpp:func:`adc_continuous_read` is called, this function will return :c:macro:`ESP_ERR_INVALID_STATE` to indicate this situation. This API aims to give you a chance to read all the ADC continuous conversion results. -The ADC conversion results read from above function are raw data. To calculate the voltage based on the ADC raw results, this formula can be used: +The ADC conversion results read from the above function are raw data. To calculate the voltage based on the ADC raw results, this formula can be used: .. parsed-literal:: @@ -247,67 +266,85 @@ The ADC conversion results read from above function are raw data. To calculate t where: -====== ============================================================= -Vout Digital output result, standing for the voltage. -Dout ADC raw digital reading result. -Vmax Maximum measurable input analog voltage, this is related to the ADC attenuation, please refer to the On-Chip Sensor chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__. -Dmax Maximum of the output ADC raw digital reading result, which is 2^bitwidth, where bitwidth is the :cpp:member::`adc_digi_pattern_config_t:bit_width` configured before. -====== ============================================================= +.. list-table:: + :header-rows: 1 + :widths: 20 80 + :align: center + + * - Vout + - Digital output result, standing for the voltage. + * - Dout + - ADC raw digital reading result. + * - Vmax + - Maximum measurable input analog voltage, this is related to the ADC attenuation, please refer to the On-Chip Sensor and Analog Signal Processing chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__. + * - Dmax + - Maximum of the output ADC raw digital reading result, which is 2^bitwidth, where the bitwidth is the :cpp:member:`adc_digi_pattern_config_t::bit_width` configured before. -To do further calbration to convert the ADC raw result to voltage in mV, please refer to calibration doc :doc:`adc_calibration`. +To do further calibration to convert the ADC raw result to voltage in mV, please refer to :doc:`adc_calibration`. + +.. _adc-continuous-hardware-limitations: .. _hardware_limitations_adc_continuous: Hardware Limitations ^^^^^^^^^^^^^^^^^^^^ -- A specific ADC unit can only work under one operating mode at any one time, either continuous mode or oneshot mode. :cpp:func:`adc_continuous_start` has provided the protection. +- A specific ADC unit can only work under one operating mode at any one time, either continuous mode or one-shot mode. :cpp:func:`adc_continuous_start` has provided the protection. -- Random Number Generator uses ADC as an input source. When ADC continuous mode driver works, the random number generated from RNG will be less random. +- Random Number Generator (RNG) uses ADC as an input source. When ADC continuous mode driver works, the random number generated from RNG will be less random. .. only:: esp32 or esp32s2 - - ADC2 is also used by the Wi-Fi. :cpp:func:`adc_continuous_start` has provided the protection between Wi-Fi driver and ADC continuous mode driver. + - ADC2 is also used by Wi-Fi. :cpp:func:`adc_continuous_start` has provided the protection between Wi-Fi driver and ADC continuous mode driver. .. only:: esp32 - - ADC continuous mode driver uses I2S0 peripheral as hardware DMA fifo. Therefore, if I2S0 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`. + - ADC continuous mode driver uses I2S0 peripheral as hardware DMA FIFO. Therefore, if I2S0 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`. - ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits. - - ESP-WROVER-KIT: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes. + - ESP-WROVER-KIT: GPIO 0, 2, 4, and 15 cannot be used due to external connections for different purposes. .. only:: esp32s2 - - ADC continuous mode driver uses SPI3 peripheral as hardware DMA fifo. Therefore, if SPI3 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`. + - ADC continuous mode driver uses SPI3 peripheral as hardware DMA FIFO. Therefore, if SPI3 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`. .. only:: esp32c3 - - ADC2 continuous mode is no longer supported, due to hardware limitation. The results are not stable. This issue can be found in `ESP32C3 Errata `_. For compatibility, you can enable :ref:`CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3` to force use ADC2. + - ADC2 DMA functionality is no longer supported to retrieve ADC conversion results due to hardware limitations, as unstable results have been observed. This issue can be found in `ESP32C3 Errata `_. For compatibility, you can enable :ref:`CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3` to force use ADC2. .. only:: esp32s3 - - ADC2 continuous mode is no longer supported, due to hardware limitation. The results are not stable. This issue can be found in `ESP32S3 Errata `_. For compatibility, you can enable :ref:`CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3` to force use ADC2. + - ADC2 DMA functionality is no longer supported to retrieve ADC conversion results due to hardware limitations, as unstable results have been observed. This issue can be found in `ESP32S3 Errata `_. For compatibility, you can enable :ref:`CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3` to force use ADC2. + + .. _adc-continuous-power-management: + +.. only:: not esp32s3 + .. _adc-continuous-power-management: Power Management ^^^^^^^^^^^^^^^^ -When power management is enabled (i.e. :ref:`CONFIG_PM_ENABLE` is on), the APB clock frequency may be adjusted when the system is in an idle state, thus potentially changing the behavior of ADC continuous conversion. +When power management is enabled, i.e., :ref:`CONFIG_PM_ENABLE` is on, the APB clock frequency may be adjusted when the system is in an idle state, thus potentially changing the behavior of ADC continuous conversion. -However, the continuous mode driver can prevent this change by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. The lock is acquired after the continuous conversion is started by :cpp:func:`adc_continuous_start`. Similarly, the lock will be released after :cpp:func:`adc_continuous_stop`. Therefore, :cpp:func:`adc_continuous_start` and :cpp:func:`adc_continuous_stop` should appear in pairs, otherwise the power management will be out of action. +However, the continuous mode driver can prevent this change by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. The lock is acquired after the continuous conversion is started by :cpp:func:`adc_continuous_start`. Similarly, the lock will be released after :cpp:func:`adc_continuous_stop`. Therefore, :cpp:func:`adc_continuous_start` and :cpp:func:`adc_continuous_stop` should appear in pairs, otherwise, the power management will be out of action. +.. _adc-continuous-iram-safe: + IRAM Safe ^^^^^^^^^ -All the ADC continuous mode driver APIs are not IRAM-safe. They are not supposed to be run when the Cache is disabled. By enabling the Kconfig option :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE`, driver internal ISR handler is IRAM-safe, which means even when the Cache is disabled, the driver will still save the conversion results into its internal pool. +All the ADC continuous mode driver APIs are not IRAM-safe. They are not supposed to be run when the Cache is disabled. By enabling the Kconfig option :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE`, the driver's internal ISR handler is IRAM-safe, which means even when the Cache is disabled, the driver will still save the conversion results into its internal pool. + +.. _adc-continuous-thread-safety: Thread Safety ^^^^^^^^^^^^^ -ADC continuous mode driver APIs are not guaranteed to be thread safe. However, the share hardware mutual exclusion is provided by the driver. See `Hardware Limitations <#hardware-limitations>`__ for more details. +ADC continuous mode driver APIs are not guaranteed to be thread-safe. However, the share hardware mutual exclusion is provided by the driver. See :ref:`adc-continuous-hardware-limitations` for more details. Application Examples diff --git a/docs/zh_CN/api-reference/peripherals/adc_continuous.rst b/docs/zh_CN/api-reference/peripherals/adc_continuous.rst index 890cb0cf7f1..3e3ccdcc714 100644 --- a/docs/zh_CN/api-reference/peripherals/adc_continuous.rst +++ b/docs/zh_CN/api-reference/peripherals/adc_continuous.rst @@ -1 +1,359 @@ -.. include:: ../../../en/api-reference/peripherals/adc_continuous.rst \ No newline at end of file +模数转换器 (ADC) 连续转换模式驱动 +======================================================== + +:link_to_translation:`en:[English]` + +{IDF_TARGET_ADC_NUM:default="两", esp32c2="一", esp32c6="一", esp32h2="一"} + +简介 +------------ + +{IDF_TARGET_NAME} 芯片集成了模数转换器 (ADC),支持测量特定模拟 IO 管脚的模拟信号。此外,ADC 还支持直接内存访问 (DMA) 功能,高效获取 ADC 转换结果。 + +{IDF_TARGET_NAME} 具有 {IDF_TARGET_ADC_NUM} 个 ADC 单元,可应用于以下场景: + +- 生成单次 ADC 转换结果 +- 生成连续 ADC 转换结果 + +本指南介绍了 ADC 连续转换模式。 + +ADC 连续转换模式驱动概念 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ADC 连续转换模式驱动由多个转换帧组成。 + +- 转换帧:一个转换帧包含多个转换结果。转换帧大小以字节为单位,在 :cpp:func:`adc_continuous_new_handle` 中配置。 +- 转换结果:一个转换结果包含多个字节,即 :c:macro:`SOC_ADC_DIGI_RESULT_BYTES`。转换结果的数据结构由 :cpp:type:`adc_digi_output_data_t` 定义,包括 ADC 单元、ADC 通道以及原始数据。 + +.. image:: /../_static/diagrams/adc/adc_conversion_frame.png + :scale: 100 % + :align: center + +功能概述 +------------------- + +下文将分节概述安装 ADC 连续转换模式驱动、并从一组 ADC 通道连续读取 ADC 转换结果的基本步骤: + +- :ref:`adc-continuous-resource-allocation`:介绍初始化 ADC 连续转换模式驱动所需设置的参数,以及如何将驱动去初始化。 +- :ref:`adc-continuous-adc-configurations`:介绍如何将 ADC 配置为在连续转换模式下工作。 +- :ref:`adc-continuous-adc-control`:介绍 ADC 控制函数。 +- :ref:`adc-continuous-register-event-callbacks`:介绍如何将特定用户代码链接到 ADC 连续转换模式事件回调函数。 +- :ref:`adc-continuous-read-conversion-result`:介绍如何获取 ADC 转换结果。 +- :ref:`adc-continuous-hardware-limitations`:介绍与 ADC 相关的硬件限制。 +- :ref:`adc-continuous-power-management`:介绍电源管理的相关内容。 +- :ref:`adc-continuous-iram-safe`:介绍与 IRAM 安全相关的函数。 +- :ref:`adc-continuous-thread-safety`:介绍由驱动程序认证为线程安全的 API。 + + +.. _adc-continuous-resource-allocation: + +资源分配 +^^^^^^^^^^^^^^^^^^^ + +ADC 连续转换模式驱动基于 {IDF_TARGET_NAME} SAR ADC 模块实现,不同的 ESP 目标芯片可能拥有不同数量的独立 ADC。 + +请按照以下步骤设置配置结构体 :cpp:type:`adc_continuous_handle_cfg_t`,创建 ADC 连续转换模式驱动的句柄: + +- :cpp:member:`adc_continuous_handle_cfg_t::max_store_buf_size`:以字节为单位设置最大缓冲池的大小,驱动程序将 ADC 转换结果保存到该缓冲池中。缓冲池已满时,新的转换将丢失。 +- :cpp:member:`adc_continuous_handle_cfg_t::conv_frame_size`:以字节为单位设置 ADC 转换帧大小。 +- :cpp:member:`adc_continuous_handle_cfg_t::flags`:设置可以改变驱动程序行为的标志。 + + - ``flush_pool``:缓冲池满时自动清空缓冲池。 + + +完成以上 ADC 配置后,使用已设置的配置结构体 :cpp:type:`adc_continuous_handle_cfg_t` 调用 :cpp:func:`adc_continuous_new_handle`。该函数可能将在特定情况下返回错误值,如无效参数、内存不足等。 + +.. only:: esp32 + + 函数返回 :c:macro:`ESP_ERR_NOT_FOUND` 时,表明 I2S0 外设正在使用中,详情请参阅 :ref:`adc-continuous-hardware-limitations`。 + +.. only:: esp32s2 + + 函数返回 :c:macro:`ESP_ERR_NOT_FOUND` 时,表明 SPI3 外设正在使用中,详情请参阅 :ref:`adc-continuous-hardware-limitations`。 + +.. only:: SOC_GDMA_SUPPORTED + + 函数返回 :c:macro:`ESP_ERR_NOT_FOUND` 时,表明 GDMA 空闲通道不足。 + +如果不再使用 ADC 连续转换模式驱动,请调用 :cpp:func:`adc_continuous_deinit` 将驱动去初始化。 + + +.. only:: SOC_ADC_DIG_IIR_FILTER_SUPPORTED + + IIR 滤波器 + ~~~~~~~~~~ + + ADC 连续转换模式下支持使用两个 IIR 滤波器。请设置 :cpp:type:`adc_continuous_iir_filter_config_t` 结构体并调用 :cpp:func:`adc_new_continuous_iir_filter`,以创建 ADC IIR 滤波器。 + + - :cpp:member:`adc_digi_filter_config_t::unit`:ADC 单元。 + - :cpp:member:`adc_digi_filter_config_t::channel`:将进行滤波的 ADC 通道。 + - :cpp:member:`adc_digi_filter_config_t::coeff`:滤波器系数。 + + .. only:: SOC_ADC_DIG_IIR_FILTER_UNIT_BINDED + + 在 {IDF_TARGET_NAME} 上,滤波器按 ADC 单元设置。一旦启用了滤波器,将对当前 ADC 单元中所有启用的 ADC 通道进行滤波。每个通道的滤波结果取决于前一次的滤波结果,因此为避免混淆滤波结果,建议在使用滤波器功能时,每个 ADC 单元只启用一条 ADC 通道,请勿同时启用多条 ADC 通道。 + + 调用 :cpp:func:`adc_del_continuous_iir_filter` 可以回收滤波器。 + + .. only:: not SOC_ADC_DIG_IIR_FILTER_UNIT_BINDED + + .. note:: + + 在一个 ADC 通道上同时使用两个滤波器时,只有第一个滤波器会生效。 + +.. only:: SOC_ADC_MONITOR_SUPPORTED + + 监视器 + ~~~~~~~ + + 当 ADC 在连续转换模式下运行时,支持使用 {IDF_TARGET_SOC_ADC_DIGI_MONITOR_NUM} 个监视器。你可以在运行中的 ADC 通道上设置一到两个监视器阈值,一旦转换结果超出阈值,监视器将在每个采样循环中触发中断。请设置 :cpp:type:`adc_monitor_config_t`,并调用 :cpp:func:`adc_new_continuous_monitor` 以创建 ADC 监视器。 + + - :cpp:member:`adc_monitor_config_t::adc_unit`:配置要监视的 ADC 通道所属的 ADC 单元。 + - :cpp:member:`adc_monitor_config_t::channel`:要监视的 ADC 通道。 + - :cpp:member:`adc_monitor_config_t::h_threshold`:高阈值,转换结果大于此值将触发中断,如果不使用此阈值,则将其设置为 -1。 + - :cpp:member:`adc_monitor_config_t::l_threshold`:低阈值,转换结果小于此值将触发中断,如果不使用此阈值,则将其设置为 -1。 + + 创建监视器后,可以使用以下 API 操作监视器,构建你的应用程序。 + + - :cpp:func:`adc_continuous_monitor_enable`:启用监视器。 + - :cpp:func:`adc_continuous_monitor_disable`:禁用监视器. + - :cpp:func:`adc_monitor_register_callbacks`:注册用户回调函数,在 ADC 转换结果超出阈值时,执行相应操作。 + - :cpp:func:`adc_del_continuous_monitor`:删除监视器,释放资源。 + + .. only:: esp32s2 + + .. NOTE:: + + {IDF_TARGET_NAME} 上存在以下硬件限制: + 1. 每个监视器仅支持一个阈值。 + 2. 每个 ADC 单元仅支持一个监视器。 + 3. ADC 连续转换模式驱动中,如果启用了监视器,无需使用参数 :cpp:member:`adc_monitor_config_t::channel` 指定,某个 ADC 单元中所有已启用的通道都会受监视。 + +初始化 ADC 连续转换模式驱动 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: c + + adc_continuous_handle_cfg_t adc_config = { + .max_store_buf_size = 1024, + .conv_frame_size = 100, + }; + ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config)); + + +回收 ADC 单元 +~~~~~~~~~~~~~~~~~~~~ + +.. code:: c + + ESP_ERROR_CHECK(adc_continuous_deinit()); + + +.. _adc-continuous-adc-configurations: + +配置 ADC +^^^^^^^^^^^^^^^^^^ + +初始化 ADC 连续转换模式驱动后,设置 :cpp:type:`adc_continuous_config_t` 配置 ADC IO,测量模拟信号: + +- :cpp:member:`adc_continuous_config_t::pattern_num`:要使用的 ADC 通道数量。 +- :cpp:member:`adc_continuous_config_t::adc_pattern`:每个要使用的 ADC 通道的配置列表,请参阅下文描述。 +- :cpp:member:`adc_continuous_config_t::sample_freq_hz`:期望的 ADC 采样频率,单位为 Hz。 +- :cpp:member:`adc_continuous_config_t::conv_mode`:连续转换模式。 +- :cpp:member:`adc_continuous_config_t::format`:转换模式结果的输出格式。 + +按照以下步骤设置 :cpp:type:`adc_digi_pattern_config_t`: + +- :cpp:member:`adc_digi_pattern_config_t::atten`:ADC 衰减。请参阅 `技术参考手册 <{IDF_TARGET_TRM_CN_URL}#sensor>`__ 中的片上传感器与模拟信号处理章节。 +- :cpp:member:`adc_digi_pattern_config_t::channel`:IO 对应的 ADC 通道号,请参阅下文注意事项。 +- :cpp:member:`adc_digi_pattern_config_t::unit`:IO 所属的 ADC 单元。 +- :cpp:member:`adc_digi_pattern_config_t::bit_width`:原始转换结果的位宽。 + +.. note:: + + 对于 IO 对应的 ADC 通道号,请参阅 `技术参考手册 <{IDF_TARGET_TRM_CN_URL}#sensor>`__ 获取 ADC IO 管脚的详细信息。另外,可以使用 :cpp:func:`adc_continuous_io_to_channel` 和 :cpp:func:`adc_continuous_channel_to_io` 获取 ADC 通道和 ADC IO 的对应关系。 + +为使这些设置生效,请使用上述配置结构体,调用 :cpp:func:`adc_continuous_config`。此 API 可能由于 :c:macro:`ESP_ERR_INVALID_ARG` 等原因返回错误。当它返回 :c:macro:`ESP_ERR_INVALID_STATE` 时,意味着 ADC 连续转换模式驱动已经启动,此时不应调用此 API。 + +请参考 ADC 连续转换模式示例 :example:`peripherals/adc/continuous_read`,查看相应配置代码。 + + +.. only:: SOC_ADC_DIG_IIR_FILTER_SUPPORTED + + 请调用 :cpp:func:`adc_continuous_iir_filter_enable` 或 :cpp:func:`adc_continuous_iir_filter_disable`,以启用或禁用 ADC IIR 滤波器。 + +.. only:: SOC_ADC_MONITOR_SUPPORTED + + 请调用 :cpp:func:`adc_continuous_monitor_enable` 或 :cpp:func:`adc_continuous_monitor_disable`,以启用或禁用 ADC 监视器。 + +.. _adc-continuous-adc-control: + +ADC 控制 +^^^^^^^^^^^ + +启动和停止 +~~~~~~~~~~~~~~ + +调用 :cpp:func:`adc_continuous_start`,将使 ADC 开始从配置好的 ADC 通道测量模拟信号,并生成转换结果。 + +相反,调用 :cpp:func:`adc_continuous_stop` 则会停止 ADC 转换。 + +.. code::c + + ESP_ERROR_CHECK(adc_continuous_start()); + +.. code:: c + + ESP_ERROR_CHECK(adc_continuous_stop()); + + +.. _adc-continuous-register-event-callbacks: + +注册事件回调 +^^^^^^^^^^^^^^^^^^^^^^^^ + +调用 :cpp:func:`adc_continuous_register_event_callbacks`,可以将自己的函数链接到驱动程序的 ISR 中。通过 :cpp:type:`adc_continuous_evt_cbs_t` 可查看所有支持的事件回调。 + +- :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done`:当一个转换帧完成时,触发此事件。 +- :cpp:member:`adc_continuous_evt_cbs_t::on_pool_ovf`:当内部缓冲池已满时,触发此事件,新的转换结果将丢失。 + +由于上述回调函数在 ISR 中调用,请确保回调函数适合在 ISR 上下文中运行,且这些回调不应涉及阻塞逻辑。回调函数的原型在 :cpp:type:`adc_continuous_callback_t` 中声明。 + +在调用 :cpp:func:`adc_continuous_register_event_callbacks` 时,还可以通过参数 ``user_data`` 注册自己的上下文,该用户数据将直接传递给回调函数。 + +此回调函数可能由于 :c:macro:`ESP_ERR_INVALID_ARG` 等原因返回错误。启用 :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` 时,如果回调函数失败并报错,可能是因为回调函数不在内部 RAM 中,请查看错误日志了解详情。此外,如果回调函数出现 :c:macro:`ESP_ERR_INVALID_STATE` 错误,表明 ADC 连续转换模式驱动已经启动,此时不应添加回调。 + + +转换完成事件 +~~~~~~~~~~~~~~~~~~~~~ + +当驱动程序完成一次转换后,会触发 :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done` 事件,并填充事件数据。事件数据包含一个指向转换帧缓冲区的指针,以及转换帧缓冲区大小。要了解事件数据结构,请参阅 :cpp:type:`adc_continuous_evt_data_t`。 + +.. note:: + + 注意,数据缓冲区 :cpp:member:`adc_continuous_evt_data_t::conv_frame_buffer` 由驱动程序本身维护,请勿释放此内存。 + +.. note:: + + 启用 Kconfig 选项 :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` 时,注册的回调函数以及回调函数中调用的函数应放置在 IRAM 中,涉及的变量也应放置在内部 RAM 中。 + +缓冲池溢出事件 +~~~~~~~~~~~~~~~~~~~ + +ADC 连续转换模式驱动使用内部缓冲池保存转换结果,缓冲池满时将发生缓冲池溢出事件。此时,驱动程序不会继续填充事件数据。缓冲池溢出通常是因为调用 :cpp:func:`adc_continuous_read` 从池中读取数据的速度远低于 ADC 转换的速度。 + + +.. _adc-continuous-read-conversion-result: + +读取转换结果 +^^^^^^^^^^^^^^^^^^^^^^ + +调用 :cpp:func:`adc_continuous_start` 启动 ADC 连续转换,调用 :cpp:func:`adc_continuous_read` 可以获取 ADC 通道的转换结果。注意提供缓冲区,获取原始结果。 + +函数 :cpp:func:`adc_continuous_read` 每次都会尝试以期望长度读取转换结果。 + +- 调用 :cpp:func:`adc_continuous_read` 可以请求读取指定长度的转换结果。但有时实际可用的转换结果可能少于请求长度,此时,函数仍会将数据从内部池移动到你提供的缓冲区中。因此,请查看 ``out_length`` 的值,了解实际移动到缓冲区中的转换结果数量。 +- 如果内部池中没有生成转换结果,函数将会阻塞一段时间,即 ``timeout_ms``,直到转换结果生成。如果始终没有转换结果生成,函数将返回 :c:macro:`ESP_ERR_TIMEOUT`。 +- 如果 ADC 连续转换生成的结果填满了内部池,新产生的结果将丢失。下次调用 :cpp:func:`adc_continuous_read` 时,将返回 :c:macro:`ESP_ERR_INVALID_STATE`,提示此情况发生。 + +此 API 提供了一个读取所有 ADC 连续转换结果的机会。 + +从上述函数读取的 ADC 转换结果为原始数据。要根据 ADC 原始结果计算电压,可以使用以下公式: + +.. parsed-literal:: + + Vout = Dout * Vmax / Dmax (1) + +其中: + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + :align: center + + * - Vout + - 数据输出结果,代表电压。 + * - Dout + - ADC 原始数据读取结果。 + * - Vmax + - 可测量的最大模拟输入电压,与 ADC 衰减相关,请参考 `技术参考手册 <{IDF_TARGET_TRM_CN_URL}#sensor>`__ 中的片上传感器与模拟信号处理章节。 + * - Dmax + - 输出 ADC 原始数据读取结果的最大值,即 2^位宽,位宽即之前配置的 :cpp:member:`adc_digi_pattern_config_t::bit_width`。 + +若需进一步校准,将 ADC 原始结果转换为以 mV 为单位的电压数据,请参考 :doc:`adc_calibration`。 + +.. _adc-continuous-hardware-limitations: + +.. _hardware_limitations_adc_continuous: + +硬件限制 +^^^^^^^^^^^^^^^^^^^^ + +- 一个 ADC 单元一次只能运行一种操作模式,即连续模式或单次模式。:cpp:func:`adc_continuous_start` 提供了保护措施。 + +- 随机数生成器 (RNG) 以 ADC 为输入源。使用 ADC 连续转换模式驱动从 RNG 生成随机数时,随机性会减弱。 + +.. only:: esp32 or esp32s2 + + - Wi-Fi 也使用 ADC2,:cpp:func:`adc_continuous_start` 提供了 Wi-Fi 驱动和 ADC 连续转换模式驱动之间的保护。 + +.. only:: esp32 + + - ADC 连续转换模式驱动使用 I2S0 外设作为硬件 DMA FIFO。因此,如果 I2S0 已在使用中,:cpp:func:`adc_continuous_new_handle` 将返回 :c:macro:`ESP_ERR_NOT_FOUND`。 + + - ESP32 DevKitC:由于存在外部自动烧录电路,GPIO 0 不能用于 ADC 连续转换模式。 + + - ESP-WROVER-KIT:由于部分 GPIO 管脚可能已经用于其他目的,GPIO 0、2、4 和 15 不能用于 ADC 连续转换模式。 + +.. only:: esp32s2 + + - ADC 连续转换模式驱动使用 SPI3 外设作为硬件 DMA FIFO。因此,如果 SPI3 已在使用中,:cpp:func:`adc_continuous_new_handle` 将返回 :c:macro:`ESP_ERR_NOT_FOUND`。 + +.. only:: esp32c3 + + - 由于硬件限制,现已不再支持使用 ADC2 DMA 功能获取 ADC 转换结果。使用 ADC2 连续转换的结果可能不稳定,具体可参考 `ESP32-C3 系列芯片勘误表 `__。出于兼容性考虑,可以启用 :ref:`CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3`,强制使用 ADC2。 + +.. only:: esp32s3 + + - 由于硬件限制,现已不再支持使用 ADC2 DMA 功能获取 ADC 转换结果。使用 ADC2 连续转换的结果可能不稳定,具体可参考 `ESP32-S3 系列芯片勘误表 `__。出于兼容性考虑,可以启用 :ref:`CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3`,强制使用 ADC2。 + + .. _adc-continuous-power-management: + +.. only:: not esp32s3 + + .. _adc-continuous-power-management: + +电源管理 +^^^^^^^^^^^^^^^^ + +启用电源管理,即启用 :ref:`CONFIG_PM_ENABLE` 时,系统在空闲状态下,可能会调整 APB 时钟频率,这可能会改变 ADC 连续转换的行为。 + +然而,通过获取类型为 :cpp:enumerator:`ESP_PM_APB_FREQ_MAX` 的电源管理锁,ADC 连续转换模式驱动可以阻止这种改变。调用 :cpp:func:`adc_continuous_start` 启动连续转换后即可获取该锁。同样,调用 :cpp:func:`adc_continuous_stop` 停止转换后将释放该锁。因此,必须确保 :cpp:func:`adc_continuous_start` 和 :cpp:func:`adc_continuous_stop` 成对出现,否则电源管理将失效。 + + +.. _adc-continuous-iram-safe: + +IRAM 安全 +^^^^^^^^^ + +ADC 连续转换模式驱动的所有 API 均非 IRAM 安全。禁用 cache 时,不应运行这类 API。启用 Kconfig 选项 :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` 可确保驱动的内部 ISR 处理程序为 IRAM 安全,此时即使禁用 cache,驱动仍然会将转换结果保存到其内部缓冲池中。 + + +.. _adc-continuous-thread-safety: + +线程安全 +^^^^^^^^^^^^^ + +ADC 连续转换模式驱动的 API 不一定线程安全,但驱动程序提供了共享硬件互斥,详情请参阅 :ref:`adc-continuous-hardware-limitations`。 + + +应用示例 +-------------------- + +* ADC 连续转换模式示例::example:`peripherals/adc/continuous_read`。 + + +API 参考 +------------- + +.. include-build-file:: inc/adc_continuous.inc From a831d40b52284f6fbc5009588ef32d9cfdbda36f Mon Sep 17 00:00:00 2001 From: xieqinan Date: Tue, 29 Aug 2023 15:58:44 +0800 Subject: [PATCH 40/71] feat(zigbee): optimize Zigbee example implementation --- .../main/esp_zigbee_gateway.c | 26 +++---- .../esp_zigbee_gateway/main/idf_component.yml | 4 +- .../esp_zigbee_rcp/main/esp_zigbee_rcp.c | 4 +- .../esp_zigbee_rcp/main/idf_component.yml | 4 +- .../HA_on_off_light/main/esp_zb_light.c | 74 ++++++++++++------- .../HA_on_off_light/main/idf_component.yml | 4 +- .../HA_on_off_light/partitions.csv | 6 +- .../HA_on_off_switch/main/esp_zb_switch.c | 70 ++++++++++-------- .../HA_on_off_switch/main/idf_component.yml | 4 +- .../HA_on_off_switch/partitions.csv | 6 +- 10 files changed, 114 insertions(+), 88 deletions(-) diff --git a/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.c b/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.c index a6777d90b75..52d61945b81 100644 --- a/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.c +++ b/examples/zigbee/esp_zigbee_gateway/main/esp_zigbee_gateway.c @@ -34,23 +34,23 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - #include -#include "esp_log.h" +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/usb_serial_jtag.h" +#include "esp_coexist_internal.h" +#include "esp_log.h" #include "esp_netif.h" +#include "esp_spiffs.h" #include "esp_vfs_eventfd.h" +#include "esp_vfs_dev.h" +#include "esp_vfs_usb_serial_jtag.h" #include "esp_wifi.h" #include "nvs_flash.h" #include "protocol_examples_common.h" -#include "esp_coexist_internal.h" #include "esp_zigbee_gateway.h" -#include "esp_vfs_dev.h" -#include "esp_vfs_usb_serial_jtag.h" -#include "driver/usb_serial_jtag.h" - #if (!defined ZB_MACSPLIT_HOST && defined ZB_MACSPLIT_DEVICE) #error Only Zigbee gateway host device should be defined #endif @@ -82,7 +82,6 @@ esp_err_t esp_zb_gateway_console_init(void) } #endif -/********************* Define functions **************************/ static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) { ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); @@ -103,8 +102,8 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) break; case ESP_ZB_MACSPLIT_DEVICE_BOOT: ESP_LOGI(TAG, "Zigbee rcp device booted"); - rcp_version = (esp_zb_zdo_signal_macsplit_dev_boot_params_t*)esp_zb_app_signal_get_params(p_sg_p); - ESP_LOGI(TAG, "Running RCP Version:%s", rcp_version->version_str); + rcp_version = (esp_zb_zdo_signal_macsplit_dev_boot_params_t *)esp_zb_app_signal_get_params(p_sg_p); + ESP_LOGI(TAG, "Running RCP Version: %s", rcp_version->version_str); break; case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: @@ -112,7 +111,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) ESP_LOGI(TAG, "Start network formation"); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); } else { - ESP_LOGE(TAG, "Failed to initialize Zigbee stack (status: %d)", err_status); + ESP_LOGE(TAG, "Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); } break; case ESP_ZB_BDB_SIGNAL_FORMATION: @@ -125,7 +124,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) esp_zb_get_pan_id(), esp_zb_get_current_channel()); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); } else { - ESP_LOGI(TAG, "Restart network formation (status: %d)", err_status); + ESP_LOGI(TAG, "Restart network formation (status: %s)", esp_err_to_name(err_status)); esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_FORMATION, 1000); } break; @@ -139,7 +138,8 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) ESP_LOGI(TAG, "New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr); break; default: - ESP_LOGI(TAG, "ZDO signal: %d, status: %d", sig_type, err_status); + ESP_LOGI(TAG, "ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, + esp_err_to_name(err_status)); break; } } diff --git a/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml b/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml index 1d60ab3792f..aa99452a45f 100644 --- a/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml +++ b/examples/zigbee/esp_zigbee_gateway/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp-zboss-lib: "~0.5.0" - espressif/esp-zigbee-lib: "~0.7.0" + espressif/esp-zboss-lib: "~0.7.0" + espressif/esp-zigbee-lib: "~0.9.0" ## Required IDF version idf: version: ">=5.0.0" diff --git a/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.c b/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.c index 966baf32df1..d264f25e438 100644 --- a/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.c +++ b/examples/zigbee/esp_zigbee_rcp/main/esp_zigbee_rcp.c @@ -35,12 +35,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_log.h" +#include "nvs_flash.h" #include "zb_scheduler.h" #include "esp_zigbee_rcp.h" -#include "nvs_flash.h" #if (defined ZB_MACSPLIT_HOST && !defined ZB_MACSPLIT_DEVICE) #error Only Zigbee rcp device should be defined diff --git a/examples/zigbee/esp_zigbee_rcp/main/idf_component.yml b/examples/zigbee/esp_zigbee_rcp/main/idf_component.yml index 1d60ab3792f..aa99452a45f 100644 --- a/examples/zigbee/esp_zigbee_rcp/main/idf_component.yml +++ b/examples/zigbee/esp_zigbee_rcp/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp-zboss-lib: "~0.5.0" - espressif/esp-zigbee-lib: "~0.7.0" + espressif/esp-zboss-lib: "~0.7.0" + espressif/esp-zigbee-lib: "~0.9.0" ## Required IDF version idf: version: ">=5.0.0" diff --git a/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.c b/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.c index 391d115b549..e2fef6a8faf 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.c +++ b/examples/zigbee/light_sample/HA_on_off_light/main/esp_zb_light.c @@ -35,16 +35,14 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_check.h" +#include "esp_log.h" +#include "nvs_flash.h" #include "ha/esp_zigbee_ha_standard.h" #include "esp_zb_light.h" -#include "nvs_flash.h" -/** - * @note Make sure set idf.py menuconfig in zigbee component as zigbee end device! -*/ #if !defined ZB_ED_ROLE #error Define ZB_ED_ROLE in idf.py menuconfig to compile light (End Device) source code. #endif @@ -56,21 +54,6 @@ static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); } -void attr_cb(uint8_t status, uint8_t endpoint, uint16_t cluster_id, uint16_t attr_id, void *new_value) -{ - if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) { - uint8_t value = *(uint8_t *)new_value; - if (attr_id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID) { - /* implemented light on/off control */ - ESP_LOGI(TAG, "on/off light set to %hd", value); - light_driver_set_power((bool)value); - } - } else { - /* Implement some actions if needed when other cluster changed */ - ESP_LOGI(TAG, "cluster:0x%x, attribute:0x%x changed ", cluster_id, attr_id); - } -} - void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) { uint32_t *p_sg_p = signal_struct->p_app_signal; @@ -88,7 +71,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); } else { /* commissioning failed */ - ESP_LOGW(TAG, "Failed to initialize Zigbee stack (status: %d)", err_status); + ESP_LOGW(TAG, "Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); } break; case ESP_ZB_BDB_SIGNAL_STEERING: @@ -100,26 +83,63 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0], esp_zb_get_pan_id(), esp_zb_get_current_channel()); } else { - ESP_LOGI(TAG, "Network steering was not successful (status: %d)", err_status); + ESP_LOGI(TAG, "Network steering was not successful (status: %s)", esp_err_to_name(err_status)); esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000); } break; default: - ESP_LOGI(TAG, "ZDO signal: %d, status: %d", sig_type, err_status); + ESP_LOGI(TAG, "ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, + esp_err_to_name(err_status)); + break; + } +} + +static esp_err_t zb_attribute_handler(const esp_zb_zcl_set_attr_value_message_t *message) +{ + esp_err_t ret = ESP_OK; + bool light_state = 0; + + ESP_RETURN_ON_FALSE(message, ESP_FAIL, TAG, "Empty message"); + ESP_RETURN_ON_FALSE(message->info.status == ESP_ZB_ZCL_STATUS_SUCCESS, ESP_ERR_INVALID_ARG, TAG, + "Received message: error status(%d)", message->info.status); + ESP_LOGI(TAG, "Received message: endpoint(%d), cluster(0x%x), attribute(0x%x), data size(%d)", + message->info.dst_endpoint, message->info.cluster, message->attribute.id, message->attribute.data.size); + if (message->info.dst_endpoint == HA_ESP_LIGHT_ENDPOINT) { + if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) { + if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && + message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) { + light_state = message->attribute.data.value ? *(bool *)message->attribute.data.value : light_state; + ESP_LOGI(TAG, "Light sets to %s", light_state ? "On" : "Off"); + light_driver_set_power(light_state); + } + } + } + return ret; +} + +static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message) +{ + esp_err_t ret = ESP_OK; + switch (callback_id) { + case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID: + ret = zb_attribute_handler((esp_zb_zcl_set_attr_value_message_t *)message); + break; + default: + ESP_LOGW(TAG, "Receive Zigbee action(0x%x) callback", callback_id); break; } + return ret; } static void esp_zb_task(void *pvParameters) { - /* initialize Zigbee stack with Zigbee end-device config */ + /* initialize Zigbee stack */ esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG(); esp_zb_init(&zb_nwk_cfg); - /* set the on-off light device config */ esp_zb_on_off_light_cfg_t light_cfg = ESP_ZB_DEFAULT_ON_OFF_LIGHT_CONFIG(); esp_zb_ep_list_t *esp_zb_on_off_light_ep = esp_zb_on_off_light_ep_create(HA_ESP_LIGHT_ENDPOINT, &light_cfg); esp_zb_device_register(esp_zb_on_off_light_ep); - esp_zb_device_add_set_attr_value_cb(attr_cb); + esp_zb_core_action_handler_register(zb_action_handler); esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK); ESP_ERROR_CHECK(esp_zb_start(false)); esp_zb_main_loop_iteration(); @@ -132,9 +152,7 @@ void app_main(void) .host_config = ESP_ZB_DEFAULT_HOST_CONFIG(), }; ESP_ERROR_CHECK(nvs_flash_init()); - /* load Zigbee light_bulb platform config to initialization */ ESP_ERROR_CHECK(esp_zb_platform_config(&config)); - /* hardware related and device init */ light_driver_init(LIGHT_DEFAULT_OFF); xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL); } diff --git a/examples/zigbee/light_sample/HA_on_off_light/main/idf_component.yml b/examples/zigbee/light_sample/HA_on_off_light/main/idf_component.yml index 0799daf7301..0fb287d6985 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/main/idf_component.yml +++ b/examples/zigbee/light_sample/HA_on_off_light/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp-zigbee-lib: "~0.7.0" - espressif/esp-zboss-lib: "~0.5.0" + espressif/esp-zigbee-lib: "~0.9.0" + espressif/esp-zboss-lib: "~0.7.0" espressif/led_strip: "~2.0.0" ## Required IDF version idf: diff --git a/examples/zigbee/light_sample/HA_on_off_light/partitions.csv b/examples/zigbee/light_sample/HA_on_off_light/partitions.csv index d8dcfcdf6b5..24bb3132a40 100644 --- a/examples/zigbee/light_sample/HA_on_off_light/partitions.csv +++ b/examples/zigbee/light_sample/HA_on_off_light/partitions.csv @@ -2,6 +2,6 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 550K, -zb_storage, data, fat, 0x9a000, 16K, -zb_fct, data, fat, 0x9e000, 1K, +factory, app, factory, 0x10000, 650K, +zb_storage, data, fat, 0xb3000, 16K, +zb_fct, data, fat, 0xb7000, 1K, diff --git a/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.c b/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.c index a2ee868e6ae..2fdaa821726 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.c +++ b/examples/zigbee/light_sample/HA_on_off_switch/main/esp_zb_switch.c @@ -35,53 +35,38 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "esp_log.h" +#include "string.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_log.h" +#include "nvs_flash.h" #include "ha/esp_zigbee_ha_standard.h" #include "esp_zb_switch.h" -#include "nvs_flash.h" -/** - * @note Make sure set idf.py menuconfig in zigbee component as zigbee coordinator device! -*/ #if defined ZB_ED_ROLE #error Define ZB_COORDINATOR_ROLE in idf.py menuconfig to compile light switch source code. #endif - -/* define a single remote device struct for managing */ typedef struct light_bulb_device_params_s { esp_zb_ieee_addr_t ieee_addr; uint8_t endpoint; uint16_t short_addr; } light_bulb_device_params_t; -/* define Button function currently only 1 switch define */ static switch_func_pair_t button_func_pair[] = { {GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL} }; static const char *TAG = "ESP_ZB_ON_OFF_SWITCH"; -/* remote device struct for recording and managing node info */ -light_bulb_device_params_t on_off_light; -/********************* Define functions **************************/ -/** - * @brief Callback for button events, currently only toggle event available - * - * @param button_func_pair Incoming event from the button_pair. - */ static void esp_zb_buttons_handler(switch_func_pair_t *button_func_pair) { if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) { /* implemented light switch toggle functionality */ esp_zb_zcl_on_off_cmd_t cmd_req; - cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = on_off_light.short_addr; - cmd_req.zcl_basic_cmd.dst_endpoint = on_off_light.endpoint; cmd_req.zcl_basic_cmd.src_endpoint = HA_ONOFF_SWITCH_ENDPOINT; - cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT; + cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT; cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID; - ESP_EARLY_LOGI(TAG, "send 'on_off toggle' command"); + ESP_EARLY_LOGI(TAG, "Send 'on_off toggle' command"); esp_zb_zcl_on_off_cmd_req(&cmd_req); } } @@ -91,12 +76,37 @@ static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask) ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask)); } -void user_find_cb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) +static void bind_cb(esp_zb_zdp_status_t zdo_status, void *user_ctx) +{ + if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { + ESP_LOGI(TAG, "Bound successfully!"); + if (user_ctx) { + light_bulb_device_params_t *light = (light_bulb_device_params_t *)user_ctx; + ESP_LOGI(TAG, "The light originating from address(0x%x) on endpoint(%d)", light->short_addr, + light->endpoint); + free(light); + } + } +} + +static void user_find_cb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) { - ESP_LOGI(TAG, "User find cb: response_status:%d, address:0x%x, endpoint:%d", zdo_status, addr, endpoint); if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) { - on_off_light.endpoint = endpoint; - on_off_light.short_addr = addr; + ESP_LOGI(TAG, "Found light"); + esp_zb_zdo_bind_req_param_t bind_req; + light_bulb_device_params_t *light = (light_bulb_device_params_t *)malloc(sizeof(light_bulb_device_params_t)); + light->endpoint = endpoint; + light->short_addr = addr; + esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr); + esp_zb_get_long_address(bind_req.src_address); + bind_req.src_endp = HA_ONOFF_SWITCH_ENDPOINT; + bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF; + bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED; + memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t)); + bind_req.dst_endp = endpoint; + bind_req.req_dst_addr = esp_zb_get_short_address(); + ESP_LOGI(TAG, "Try to bind On/Off"); + esp_zb_zdo_device_bind_req(&bind_req, bind_cb, (void *)light); } } @@ -117,7 +127,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) ESP_LOGI(TAG, "Start network formation"); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); } else { - ESP_LOGE(TAG, "Failed to initialize Zigbee stack (status: %d)", err_status); + ESP_LOGE(TAG, "Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); } break; case ESP_ZB_BDB_SIGNAL_FORMATION: @@ -130,7 +140,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) esp_zb_get_pan_id(), esp_zb_get_current_channel()); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); } else { - ESP_LOGI(TAG, "Restart network formation (status: %d)", err_status); + ESP_LOGI(TAG, "Restart network formation (status: %s)", esp_err_to_name(err_status)); esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_FORMATION, 1000); } break; @@ -148,17 +158,17 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) esp_zb_zdo_find_on_off_light(&cmd_req, user_find_cb, NULL); break; default: - ESP_LOGI(TAG, "ZDO signal: %d, status: %d", sig_type, err_status); + ESP_LOGI(TAG, "ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, + esp_err_to_name(err_status)); break; } } static void esp_zb_task(void *pvParameters) { - /* initialize Zigbee stack with Zigbee coordinator config */ + /* initialize Zigbee stack */ esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZC_CONFIG(); esp_zb_init(&zb_nwk_cfg); - /* set the on-off switch device config */ esp_zb_on_off_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_ON_OFF_SWITCH_CONFIG(); esp_zb_ep_list_t *esp_zb_on_off_switch_ep = esp_zb_on_off_switch_ep_create(HA_ONOFF_SWITCH_ENDPOINT, &switch_cfg); esp_zb_device_register(esp_zb_on_off_switch_ep); @@ -174,9 +184,7 @@ void app_main(void) .host_config = ESP_ZB_DEFAULT_HOST_CONFIG(), }; ESP_ERROR_CHECK(nvs_flash_init()); - /* load Zigbee switch platform config to initialization */ ESP_ERROR_CHECK(esp_zb_platform_config(&config)); - /* hardware related and device init */ switch_driver_init(button_func_pair, PAIR_SIZE(button_func_pair), esp_zb_buttons_handler); xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL); } diff --git a/examples/zigbee/light_sample/HA_on_off_switch/main/idf_component.yml b/examples/zigbee/light_sample/HA_on_off_switch/main/idf_component.yml index 0a205398428..479a89e4fc2 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/main/idf_component.yml +++ b/examples/zigbee/light_sample/HA_on_off_switch/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp-zigbee-lib: "~0.7.0" - espressif/esp-zboss-lib: "~0.5.0" + espressif/esp-zigbee-lib: "~0.9.0" + espressif/esp-zboss-lib: "~0.7.0" ## Required IDF version idf: version: ">=5.0.0" diff --git a/examples/zigbee/light_sample/HA_on_off_switch/partitions.csv b/examples/zigbee/light_sample/HA_on_off_switch/partitions.csv index d8dcfcdf6b5..24bb3132a40 100644 --- a/examples/zigbee/light_sample/HA_on_off_switch/partitions.csv +++ b/examples/zigbee/light_sample/HA_on_off_switch/partitions.csv @@ -2,6 +2,6 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 550K, -zb_storage, data, fat, 0x9a000, 16K, -zb_fct, data, fat, 0x9e000, 1K, +factory, app, factory, 0x10000, 650K, +zb_storage, data, fat, 0xb3000, 16K, +zb_fct, data, fat, 0xb7000, 1K, From 55323ed437a216fb641acfc1661c81a1f3c6e5ed Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Mon, 21 Aug 2023 13:06:34 +0530 Subject: [PATCH 41/71] fix(nimble): Add event for reattempt connection count information --- components/bt/host/nimble/nimble | 2 +- components/bt/host/nimble/port/include/esp_nimble_cfg.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index acdf522a215..da4bcac49f6 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit acdf522a21518a69b3582ff4a4e5b67512a13b32 +Subproject commit da4bcac49f6ee4d874bacb7bc6fd6f5e24155d2f diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h index 37d812ba1df..dff3469ba36 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -1751,4 +1751,12 @@ #endif #endif +#ifndef MYNEWT_VAL_BLE_ENABLE_CONN_REATTEMPT +#ifdef CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT +#define MYNEWT_VAL_BLE_ENABLE_CONN_REATTEMPT CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT +#else +#define MYNEWT_VAL_BLE_ENABLE_CONN_REATTEMPT (0) +#endif +#endif + #endif From 9811ff7be9d1c3bae940a5f070d6b35e04e36c4e Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 20 Sep 2023 11:35:25 +0800 Subject: [PATCH 42/71] ci(adc): increase all adc performance test threshold on c6 --- .../include/esp32c6/idf_performance_target.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/idf_test/include/esp32c6/idf_performance_target.h b/components/idf_test/include/esp32c6/idf_performance_target.h index dd0ffc1bb92..08c145126bf 100644 --- a/components/idf_test/include/esp32c6/idf_performance_target.h +++ b/components/idf_test/include/esp32c6/idf_performance_target.h @@ -23,10 +23,10 @@ #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 32 #define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 15 -#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_NO_FILTER 5 -#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_2 5 -#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_4 5 -#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_8 5 -#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_16 5 -#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_64 5 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_NO_FILTER 7 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_2 7 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_4 7 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_8 7 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_16 7 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_64 7 #define IDF_PERFORMANCE_MAX_ADC_ONESHOT_STD_ATTEN3 7 From af2f5dbd18db46aeefac3e79691a7789d85bfbb5 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Mon, 18 Sep 2023 12:02:04 +0700 Subject: [PATCH 43/71] ci(pre-commit): Add rules for branch namimg Limit slashes in branch names No uppercase letters in branch names --- .pre-commit-config.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a7c9d1f512a..94f4af81dae 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,6 +28,12 @@ repos: - id: mixed-line-ending args: ['-f=lf'] - id: double-quote-string-fixer + - id: no-commit-to-branch + name: Do not use more than one slash in the branch name + args: ['--pattern', '^[^/]*/[^/]*/'] + - id: no-commit-to-branch + name: Do not use uppercase letters in the branch name + args: ['--pattern', '^[^A-Z]*[A-Z]'] - repo: https://github.com/PyCQA/flake8 rev: 5.0.4 hooks: From a686c20ee599bea3260f2c817a6eb4fd6c283a88 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Wed, 20 Sep 2023 10:39:58 +0530 Subject: [PATCH 44/71] feat(bootloader): Update micro-ecc version to v1.1 This fix ensures that https://nvd.nist.gov/vuln/detail/CVE-2020-27209 is not reported by the ESP-IDF SBOM tool. Please note that, this CVE was anyways not applicable for ESP32 platform, as the bootloader (user of micro-ecc library) do not perform signing on the device, its only verification that happens in secure-boot-v1 case. --- .gitmodules | 4 ++-- .../bootloader/subproject/components/micro-ecc/micro-ecc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 1a9c145c62a..e944b5da373 100644 --- a/.gitmodules +++ b/.gitmodules @@ -30,12 +30,12 @@ [submodule "components/bootloader/subproject/components/micro-ecc/micro-ecc"] path = components/bootloader/subproject/components/micro-ecc/micro-ecc url = ../../kmackay/micro-ecc.git - sbom-version = 1.0 + sbom-version = 1.1 sbom-cpe = cpe:2.3:a:micro-ecc_project:micro-ecc:{}:*:*:*:*:*:*:* sbom-supplier = Person: Ken MacKay sbom-url = https://github.com/kmackay/micro-ecc sbom-description = A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors - sbom-hash = d037ec89546fad14b5c4d5456c2e23a71e554966 + sbom-hash = 24c60e243580c7868f4334a1ba3123481fe1aa48 [submodule "components/spiffs/spiffs"] path = components/spiffs/spiffs diff --git a/components/bootloader/subproject/components/micro-ecc/micro-ecc b/components/bootloader/subproject/components/micro-ecc/micro-ecc index d037ec89546..24c60e24358 160000 --- a/components/bootloader/subproject/components/micro-ecc/micro-ecc +++ b/components/bootloader/subproject/components/micro-ecc/micro-ecc @@ -1 +1 @@ -Subproject commit d037ec89546fad14b5c4d5456c2e23a71e554966 +Subproject commit 24c60e243580c7868f4334a1ba3123481fe1aa48 From 59f8008e22ee354e6f0dd9e0eb0b01ac6dc60f64 Mon Sep 17 00:00:00 2001 From: "Planck (Lu Zeyu)" Date: Tue, 12 Sep 2023 12:28:56 +0800 Subject: [PATCH 45/71] feat(pcnt): replace periph_module func with new ll func --- components/driver/deprecated/pcnt_legacy.c | 13 +++++-- components/driver/pcnt/pulse_cnt.c | 16 +++++++-- components/hal/esp32/include/hal/pcnt_ll.h | 35 +++++++++++++++++++ components/hal/esp32c6/include/hal/pcnt_ll.h | 22 ++++++++++++ components/hal/esp32h2/include/hal/pcnt_ll.h | 22 ++++++++++++ components/hal/esp32p4/include/hal/pcnt_ll.h | 30 ++++++++++++++++ components/hal/esp32s2/include/hal/pcnt_ll.h | 36 ++++++++++++++++++++ components/hal/esp32s3/include/hal/pcnt_ll.h | 30 ++++++++++++++++ 8 files changed, 199 insertions(+), 5 deletions(-) diff --git a/components/driver/deprecated/pcnt_legacy.c b/components/driver/deprecated/pcnt_legacy.c index b0ecdbf9bf9..630fced4f3b 100644 --- a/components/driver/deprecated/pcnt_legacy.c +++ b/components/driver/deprecated/pcnt_legacy.c @@ -31,6 +31,13 @@ #define PCNT_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux) #define PCNT_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux) +#if !SOC_RCC_IS_INDEPENDENT +#define PCNT_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define PCNT_RCC_ATOMIC() +#endif + + static const char *TAG = "pcnt(legacy)"; #define PCNT_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE(a, ret_val, TAG, "%s", str) @@ -365,10 +372,12 @@ static inline esp_err_t _pcnt_unit_config(pcnt_port_t pcnt_port, const pcnt_conf /*Enalbe hardware module*/ static bool pcnt_enable = false; if (pcnt_enable == false) { - periph_module_reset(pcnt_periph_signals.groups[pcnt_port].module); + PCNT_RCC_ATOMIC() { + pcnt_ll_reset_register(pcnt_port); + pcnt_ll_enable_bus_clock(pcnt_port, true); + } pcnt_enable = true; } - periph_module_enable(pcnt_periph_signals.groups[pcnt_port].module); /*Set counter range*/ _pcnt_set_event_value(pcnt_port, unit, PCNT_EVT_H_LIM, pcnt_config->counter_h_lim); _pcnt_set_event_value(pcnt_port, unit, PCNT_EVT_L_LIM, pcnt_config->counter_l_lim); diff --git a/components/driver/pcnt/pulse_cnt.c b/components/driver/pcnt/pulse_cnt.c index c8dee2346ed..fc2c0a709e8 100644 --- a/components/driver/pcnt/pulse_cnt.c +++ b/components/driver/pcnt/pulse_cnt.c @@ -50,6 +50,12 @@ #define PCNT_PM_LOCK_NAME_LEN_MAX 16 +#if !SOC_RCC_IS_INDEPENDENT +#define PCNT_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define PCNT_RCC_ATOMIC() +#endif + static const char *TAG = "pcnt"; typedef struct pcnt_platform_t pcnt_platform_t; @@ -763,8 +769,10 @@ static pcnt_group_t *pcnt_acquire_group_handle(int group_id) group->intr_priority = -1; group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; // enable APB access pcnt registers - periph_module_enable(pcnt_periph_signals.groups[group_id].module); - periph_module_reset(pcnt_periph_signals.groups[group_id].module); + PCNT_RCC_ATOMIC() { + pcnt_ll_enable_bus_clock(group_id, true); + pcnt_ll_reset_register(group_id); + } // initialize HAL context pcnt_hal_init(&group->hal, group_id); } @@ -795,7 +803,9 @@ static void pcnt_release_group_handle(pcnt_group_t *group) assert(s_platform.groups[group_id]); do_deinitialize = true; s_platform.groups[group_id] = NULL; // deregister from platform - periph_module_disable(pcnt_periph_signals.groups[group_id].module); + PCNT_RCC_ATOMIC() { + pcnt_ll_enable_bus_clock(group_id, false); + } } _lock_release(&s_platform.mutex); diff --git a/components/hal/esp32/include/hal/pcnt_ll.h b/components/hal/esp32/include/hal/pcnt_ll.h index 5e6a8b36606..e54e97b050f 100644 --- a/components/hal/esp32/include/hal/pcnt_ll.h +++ b/components/hal/esp32/include/hal/pcnt_ll.h @@ -21,6 +21,8 @@ #include "soc/pcnt_struct.h" #include "hal/pcnt_types.h" #include "hal/misc.h" +#include "soc/dport_access.h" +#include "soc/dport_reg.h" #ifdef __cplusplus extern "C" { @@ -437,6 +439,39 @@ static inline volatile void *pcnt_ll_get_intr_status_reg(pcnt_dev_t *hw) return &hw->int_st.val; } +/** + * @brief Enable or disable the bus clock for the PCNT module + * + * @param set_bit True to set bit, false to clear bit + */ +static inline void pcnt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + if (enable) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; pcnt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the PCNT module + */ +static inline void pcnt_ll_reset_register(int group_id) +{ + (void)group_id; + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; pcnt_ll_reset_register(__VA_ARGS__) + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/pcnt_ll.h b/components/hal/esp32c6/include/hal/pcnt_ll.h index b597087fb4f..ade48358ae9 100644 --- a/components/hal/esp32c6/include/hal/pcnt_ll.h +++ b/components/hal/esp32c6/include/hal/pcnt_ll.h @@ -19,6 +19,7 @@ #include #include "soc/pcnt_struct.h" #include "hal/pcnt_types.h" +#include "soc/pcr_struct.h" #ifdef __cplusplus extern "C" { @@ -435,6 +436,27 @@ static inline volatile void *pcnt_ll_get_intr_status_reg(pcnt_dev_t *hw) return &hw->int_st.val; } +/** + * @brief Enable or disable the bus clock for the PCNT module + * + * @param set_bit True to set bit, false to clear bit + */ +static inline void pcnt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.pcnt_conf.pcnt_clk_en = enable; +} + +/** + * @brief Reset the PCNT module + */ +static inline void pcnt_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.pcnt_conf.pcnt_rst_en = 1; + PCR.pcnt_conf.pcnt_rst_en = 0; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/pcnt_ll.h b/components/hal/esp32h2/include/hal/pcnt_ll.h index 0b393aee673..17c4b96212e 100644 --- a/components/hal/esp32h2/include/hal/pcnt_ll.h +++ b/components/hal/esp32h2/include/hal/pcnt_ll.h @@ -19,6 +19,7 @@ #include #include "soc/pcnt_struct.h" #include "hal/pcnt_types.h" +#include "soc/pcr_struct.h" #ifdef __cplusplus extern "C" { @@ -435,6 +436,27 @@ static inline volatile void *pcnt_ll_get_intr_status_reg(pcnt_dev_t *hw) return &hw->int_st.val; } +/** + * @brief Enable or disable the bus clock for the PCNT module + * + * @param set_bit True to set bit, false to clear bit + */ +static inline void pcnt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.pcnt_conf.pcnt_clk_en = enable; +} + +/** + * @brief Reset the PCNT module + */ +static inline void pcnt_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.pcnt_conf.pcnt_rst_en = 1; + PCR.pcnt_conf.pcnt_rst_en = 0; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/pcnt_ll.h b/components/hal/esp32p4/include/hal/pcnt_ll.h index bc62612308d..610dae51e58 100644 --- a/components/hal/esp32p4/include/hal/pcnt_ll.h +++ b/components/hal/esp32p4/include/hal/pcnt_ll.h @@ -20,6 +20,7 @@ #include "soc/pcnt_struct.h" #include "hal/pcnt_types.h" #include "hal/misc.h" +#include "soc/hp_sys_clkrst_struct.h" #ifdef __cplusplus extern "C" { @@ -476,6 +477,35 @@ static inline volatile void *pcnt_ll_get_intr_status_reg(pcnt_dev_t *hw) return &hw->int_st.val; } +/** + * @brief Enable or disable the bus clock for the PCNT module + * + * @param set_bit True to set bit, false to clear bit + */ +static inline void pcnt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + HP_SYS_CLKRST.soc_clk_ctrl2.reg_pcnt_apb_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; pcnt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the PCNT module + */ +static inline void pcnt_ll_reset_register(int group_id) +{ + (void)group_id; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_pcnt = 1; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_pcnt = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; pcnt_ll_reset_register(__VA_ARGS__) + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/pcnt_ll.h b/components/hal/esp32s2/include/hal/pcnt_ll.h index 4ba835fbb25..fecf8146522 100644 --- a/components/hal/esp32s2/include/hal/pcnt_ll.h +++ b/components/hal/esp32s2/include/hal/pcnt_ll.h @@ -19,6 +19,8 @@ #include #include "soc/pcnt_struct.h" #include "hal/pcnt_types.h" +#include "soc/dport_reg.h" +#include "soc/dport_access.h" #ifdef __cplusplus extern "C" { @@ -435,6 +437,40 @@ static inline volatile void *pcnt_ll_get_intr_status_reg(pcnt_dev_t *hw) return &hw->int_st.val; } +/** + * @brief Enable or disable the bus clock for the PCNT module + * + * @param set_bit True to set bit, false to clear bit + */ +static inline void pcnt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + if (enable) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; pcnt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the PCNT module + */ +static inline void pcnt_ll_reset_register(int group_id) +{ + (void)group_id; + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; pcnt_ll_reset_register(__VA_ARGS__) + + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/pcnt_ll.h b/components/hal/esp32s3/include/hal/pcnt_ll.h index 34b2f874130..e9ec7e1a1c0 100644 --- a/components/hal/esp32s3/include/hal/pcnt_ll.h +++ b/components/hal/esp32s3/include/hal/pcnt_ll.h @@ -19,6 +19,7 @@ #include #include "soc/pcnt_struct.h" #include "hal/pcnt_types.h" +#include "soc/system_struct.h" #ifdef __cplusplus extern "C" { @@ -435,6 +436,35 @@ static inline volatile void *pcnt_ll_get_intr_status_reg(pcnt_dev_t *hw) return &hw->int_st.val; } +/** + * @brief Enable or disable the bus clock for the PCNT module + * + * @param set_bit True to set bit, false to clear bit + */ +static inline void pcnt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + SYSTEM.perip_clk_en0.pcnt_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; pcnt_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the PCNT module + */ +static inline void pcnt_ll_reset_register(int group_id) +{ + (void)group_id; + SYSTEM.perip_rst_en0.pcnt_rst = 1; + SYSTEM.perip_rst_en0.pcnt_rst = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; pcnt_ll_reset_register(__VA_ARGS__) + #ifdef __cplusplus } #endif From 7ef91d4ec7f0b456d033c523fb4c9ff45c3f5c54 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Wed, 20 Sep 2023 11:32:47 +0700 Subject: [PATCH 46/71] ci(danger): Add rules for branch naming --- .gitlab/dangerjs/dangerfile.js | 3 +++ .gitlab/dangerjs/mrSourceBranchName.js | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 .gitlab/dangerjs/mrSourceBranchName.js diff --git a/.gitlab/dangerjs/dangerfile.js b/.gitlab/dangerjs/dangerfile.js index d6084cf45c1..80b51967257 100644 --- a/.gitlab/dangerjs/dangerfile.js +++ b/.gitlab/dangerjs/dangerfile.js @@ -25,6 +25,9 @@ async function runChecks() { // Checks for MR area labels await require("./mrAreaLabels.js")(); + // Checks for Source branch name + require("./mrSourceBranchName.js")(); + // Add success log if no issues if ( results.fails.length === 0 && diff --git a/.gitlab/dangerjs/mrSourceBranchName.js b/.gitlab/dangerjs/mrSourceBranchName.js new file mode 100644 index 00000000000..ae76ed8e569 --- /dev/null +++ b/.gitlab/dangerjs/mrSourceBranchName.js @@ -0,0 +1,23 @@ +/** + * Throw Danger WARN if branch name contains more than one slash or uppercase letters + * + * @dangerjs INFO + */ +module.exports = function () { + const sourceBranch = danger.gitlab.mr.source_branch; + + // Check if the source branch name contains more than one slash + const slashCount = (sourceBranch.match(/\//g) || []).length; + if (slashCount > 1) { + return message( + `The source branch name \`${sourceBranch}\` contains more than one slash. This can cause troubles with git sync. Please rename the branch.` + ); + } + + // Check if the source branch name contains any uppercase letters + if (sourceBranch !== sourceBranch.toLowerCase()) { + return message( + `The source branch name \`${sourceBranch}\` contains uppercase letters. This can cause troubles on case-insensitive file systems (macOS). Please use only lowercase letters.`, + ); + } +}; From a76a1465b6aec6bcd65d45a9e8199fd85c3589a0 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Fri, 8 Sep 2023 16:13:06 +0200 Subject: [PATCH 47/71] fix(freertos): Updated IDLE task names for each core to have the coreID as a suffix This commit updates the IDLE task names for each core by concatenating the respective coreIDs to the names. Closes https://github.com/espressif/esp-idf/issues/12204 --- components/freertos/FreeRTOS-Kernel/tasks.c | 162 ++++++++++++++++--- docs/en/api-reference/system/freertos.rst | 2 +- docs/zh_CN/api-reference/system/freertos.rst | 2 +- 3 files changed, 139 insertions(+), 27 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index 3459a572a79..ca99a75655f 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -506,6 +506,11 @@ PRIVILEGED_DATA static volatile BaseType_t xSwitchingContext[ configNUM_CORES ] /* File private functions. --------------------------------*/ +/* + * Creates the idle tasks during scheduler start. + */ +static BaseType_t prvCreateIdleTasks( void ); + /** * Utility task that simply returns pdTRUE if the task referenced by xTask is * currently in the Suspended state, or pdFALSE if the task referenced by xTask @@ -2125,16 +2130,14 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ /*-----------------------------------------------------------*/ -void vTaskStartScheduler( void ) +static BaseType_t prvCreateIdleTasks( void ) { - BaseType_t xReturn; + BaseType_t xReturn = pdPASS; - #ifdef ESP_PLATFORM - /* Create an IDLE task for each core */ - for( BaseType_t xCoreID = 0; xCoreID < configNUM_CORES; xCoreID++ ) - #endif //ESP_PLATFORM - /* Add the idle task at the lowest priority. */ - #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + #if ( configNUM_CORES == 1 ) + { + /* Add the idle task at the lowest priority. */ + #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) { StaticTask_t * pxIdleTaskTCBBuffer = NULL; StackType_t * pxIdleTaskStackBuffer = NULL; @@ -2143,16 +2146,16 @@ void vTaskStartScheduler( void ) /* The Idle task is created using user provided RAM - obtain the * address of the RAM then create the idle task. */ vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); - xIdleTaskHandle[ xCoreID ] = xTaskCreateStaticPinnedToCore( prvIdleTask, - configIDLE_TASK_NAME, - ulIdleTaskStackSize, - ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ - portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - pxIdleTaskStackBuffer, - pxIdleTaskTCBBuffer, - xCoreID ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + xIdleTaskHandle[ 0 ] = xTaskCreateStaticPinnedToCore( prvIdleTask, + configIDLE_TASK_NAME, + ulIdleTaskStackSize, + ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + pxIdleTaskStackBuffer, + pxIdleTaskTCBBuffer, + 0 ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ - if( xIdleTaskHandle[ xCoreID ] != NULL ) + if( xIdleTaskHandle[ 0 ] != NULL ) { xReturn = pdPASS; } @@ -2161,27 +2164,136 @@ void vTaskStartScheduler( void ) xReturn = pdFAIL; } } - #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ { /* The Idle task is being created using dynamically allocated RAM. */ xReturn = xTaskCreatePinnedToCore( prvIdleTask, configIDLE_TASK_NAME, configMINIMAL_STACK_SIZE, ( void * ) NULL, - portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - &xIdleTaskHandle[ xCoreID ], - xCoreID ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + &xIdleTaskHandle[ 0 ], + 0 ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + } + #else /* #if ( configNUM_CORES == 1 ) */ + { + BaseType_t xCoreID; + char cIdleName[ configMAX_TASK_NAME_LEN ]; + + /* Add each idle task at the lowest priority. */ + for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUM_CORES; xCoreID++ ) + { + BaseType_t x; - if( xIdleTaskHandle[ xCoreID ] != NULL ) + if( xReturn == pdFAIL ) { - xReturn = pdPASS; + /* TODO: IDF-8240 - Memory leaks occur if IDLE task creation fails on some core + * as we do not free memory for the successfully created IDLE tasks. + */ + break; } else { - xReturn = pdFAIL; + mtCOVERAGE_TEST_MARKER(); + } + + for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + cIdleName[ x ] = configIDLE_TASK_NAME[ x ]; + + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than + * configMAX_TASK_NAME_LEN characters just in case the memory after the + * string is not accessible (extremely unlikely). */ + if( cIdleName[ x ] == ( char ) 0x00 ) + { + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Append the idle task number to the end of the name if there is space. */ + if( x < ( BaseType_t ) configMAX_TASK_NAME_LEN ) + { + cIdleName[ x ] = ( char ) ( xCoreID + '0' ); + x++; + + /* And append a null character if there is space. */ + if( x < ( BaseType_t ) configMAX_TASK_NAME_LEN ) + { + cIdleName[ x ] = '\0'; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); } + + #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + StaticTask_t * pxIdleTaskTCBBuffer = NULL; + StackType_t * pxIdleTaskStackBuffer = NULL; + uint32_t ulIdleTaskStackSize; + + /* The Idle task is created using user provided RAM - obtain the + * address of the RAM then create the idle task. */ + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); + xIdleTaskHandle[ xCoreID ] = xTaskCreateStaticPinnedToCore( prvIdleTask, + cIdleName, + ulIdleTaskStackSize, + ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + pxIdleTaskStackBuffer, + pxIdleTaskTCBBuffer, + xCoreID ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + + if( xIdleTaskHandle[ xCoreID ] != NULL ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + } + #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + { + /* The Idle task is being created using dynamically allocated RAM. */ + xReturn = xTaskCreatePinnedToCore( prvIdleTask, + cIdleName, + configMINIMAL_STACK_SIZE, + ( void * ) NULL, + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + &xIdleTaskHandle[ xCoreID ], + xCoreID ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ } - #endif /* configSUPPORT_STATIC_ALLOCATION */ + } + #endif /* #if ( configNUM_CORES == 1 ) */ + + return xReturn; +} + +/*-----------------------------------------------------------*/ + +void vTaskStartScheduler( void ) +{ + BaseType_t xReturn; + + /* The code for prvCreateIdleTasks() has been backported from the upstream + * FreeRTOS-Kernel source. The reference for the same is on the mainline + * at the commit id# 2f94b181a2f049ec342deba0927bed51f7174ab0. + */ + xReturn = prvCreateIdleTasks(); #if ( configUSE_TIMERS == 1 ) { diff --git a/docs/en/api-reference/system/freertos.rst b/docs/en/api-reference/system/freertos.rst index bb8bbaf1d91..745f7e82972 100644 --- a/docs/en/api-reference/system/freertos.rst +++ b/docs/en/api-reference/system/freertos.rst @@ -95,7 +95,7 @@ During startup, ESP-IDF and the FreeRTOS kernel automatically create multiple ta - Affinity - Priority * - Idle Tasks (``IDLEx``) - - An idle task (``IDLEx``) is created for (and pinned to) each CPU core, where ``x`` is the CPU core's number + - An idle task (``IDLEx``) is created for (and pinned to) each CPU core, where ``x`` is the CPU core's number. The ``x`` is dropped when single-core configuration is enabled. - :ref:`CONFIG_FREERTOS_IDLE_TASK_STACKSIZE` - Core x - ``0`` diff --git a/docs/zh_CN/api-reference/system/freertos.rst b/docs/zh_CN/api-reference/system/freertos.rst index d32ac2ef978..7fbe7b967c7 100644 --- a/docs/zh_CN/api-reference/system/freertos.rst +++ b/docs/zh_CN/api-reference/system/freertos.rst @@ -95,7 +95,7 @@ ESP-IDF FreeRTOS - 亲和性 - 优先级 * - 空闲任务 (``IDLEx``) - - 为每个 CPU 核创建并固定一个空闲任务 (``IDLEx``),其中 ``x`` 是 CPU 核的编号 + - 为每个 CPU 核创建并固定一个空闲任务 (``IDLEx``),其中 ``x`` 是 CPU 核的编号。 当启用单核配置时,``x`` 将被删除。 - :ref:`CONFIG_FREERTOS_IDLE_TASK_STACKSIZE` - Core x - ``0`` From 2e11919f70e58b208775a7f9da75da409cfa23b8 Mon Sep 17 00:00:00 2001 From: Chen Yudong Date: Wed, 20 Sep 2023 19:09:47 +0800 Subject: [PATCH 48/71] fix(ci): change build-test-rules files folder --- components/app_update/{ => test_apps}/.build-test-rules.yml | 0 .../{ => test_apps}/.build-test-rules.yml | 0 components/cxx/{ => test_apps}/.build-test-rules.yml | 0 components/driver/{ => test_apps}/.build-test-rules.yml | 0 components/efuse/{ => test_apps}/.build-test-rules.yml | 0 components/esp_adc/{ => test_apps}/.build-test-rules.yml | 0 .../{ => test_apps}/.build-test-rules.yml | 0 components/esp_common/{ => test_apps}/.build-test-rules.yml | 0 components/esp_eth/{ => test_apps}/.build-test-rules.yml | 0 components/esp_event/{ => test_apps}/.build-test-rules.yml | 0 .../esp_hw_support/{ => test_apps}/.build-test-rules.yml | 0 components/esp_lcd/{ => test_apps}/.build-test-rules.yml | 0 components/esp_netif/{ => test_apps}/.build-test-rules.yml | 0 .../esp_partition/{ => host_test}/.build-test-rules.yml | 0 components/esp_psram/{ => test_apps}/.build-test-rules.yml | 0 .../esp_ringbuf/{ => test_apps}/.build-test-rules.yml | 0 components/esp_rom/{ => test_apps}/.build-test-rules.yml | 0 components/esp_system/{ => test_apps}/.build-test-rules.yml | 0 components/esp_timer/{ => test_apps}/.build-test-rules.yml | 0 components/esp_wifi/{ => test_apps}/.build-test-rules.yml | 0 components/fatfs/{ => test_apps}/.build-test-rules.yml | 0 components/heap/{ => test_apps}/.build-test-rules.yml | 0 components/ieee802154/{ => test_apps}/.build-test-rules.yml | 0 components/log/{ => host_test}/.build-test-rules.yml | 5 ----- components/log/test_apps/.build-test-rules.yml | 6 ++++++ components/mqtt/{ => test_apps}/.build-test-rules.yml | 0 components/newlib/{ => test_apps}/.build-test-rules.yml | 0 components/sdmmc/{ => test_apps}/.build-test-rules.yml | 0 components/spi_flash/{ => test_apps}/.build-test-rules.yml | 0 components/spiffs/host_test/.build-test-rules.yml | 4 ++++ components/spiffs/{ => test_apps}/.build-test-rules.yml | 5 ----- .../tcp_transport/{ => test_apps}/.build-test-rules.yml | 0 .../touch_element/{ => test_apps}/.build-test-rules.yml | 0 components/ulp/{ => test_apps}/.build-test-rules.yml | 0 components/usb/{ => test_apps}/.build-test-rules.yml | 0 components/wear_levelling/host_test/.build-test-rules.yml | 6 ++++++ .../wear_levelling/{ => test_apps}/.build-test-rules.yml | 4 ---- 37 files changed, 16 insertions(+), 14 deletions(-) rename components/app_update/{ => test_apps}/.build-test-rules.yml (100%) rename components/bootloader_support/{ => test_apps}/.build-test-rules.yml (100%) rename components/cxx/{ => test_apps}/.build-test-rules.yml (100%) rename components/driver/{ => test_apps}/.build-test-rules.yml (100%) rename components/efuse/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_adc/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_bootloader_format/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_common/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_eth/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_event/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_hw_support/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_lcd/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_netif/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_partition/{ => host_test}/.build-test-rules.yml (100%) rename components/esp_psram/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_ringbuf/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_rom/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_system/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_timer/{ => test_apps}/.build-test-rules.yml (100%) rename components/esp_wifi/{ => test_apps}/.build-test-rules.yml (100%) rename components/fatfs/{ => test_apps}/.build-test-rules.yml (100%) rename components/heap/{ => test_apps}/.build-test-rules.yml (100%) rename components/ieee802154/{ => test_apps}/.build-test-rules.yml (100%) rename components/log/{ => host_test}/.build-test-rules.yml (65%) create mode 100644 components/log/test_apps/.build-test-rules.yml rename components/mqtt/{ => test_apps}/.build-test-rules.yml (100%) rename components/newlib/{ => test_apps}/.build-test-rules.yml (100%) rename components/sdmmc/{ => test_apps}/.build-test-rules.yml (100%) rename components/spi_flash/{ => test_apps}/.build-test-rules.yml (100%) create mode 100644 components/spiffs/host_test/.build-test-rules.yml rename components/spiffs/{ => test_apps}/.build-test-rules.yml (66%) rename components/tcp_transport/{ => test_apps}/.build-test-rules.yml (100%) rename components/touch_element/{ => test_apps}/.build-test-rules.yml (100%) rename components/ulp/{ => test_apps}/.build-test-rules.yml (100%) rename components/usb/{ => test_apps}/.build-test-rules.yml (100%) create mode 100644 components/wear_levelling/host_test/.build-test-rules.yml rename components/wear_levelling/{ => test_apps}/.build-test-rules.yml (68%) diff --git a/components/app_update/.build-test-rules.yml b/components/app_update/test_apps/.build-test-rules.yml similarity index 100% rename from components/app_update/.build-test-rules.yml rename to components/app_update/test_apps/.build-test-rules.yml diff --git a/components/bootloader_support/.build-test-rules.yml b/components/bootloader_support/test_apps/.build-test-rules.yml similarity index 100% rename from components/bootloader_support/.build-test-rules.yml rename to components/bootloader_support/test_apps/.build-test-rules.yml diff --git a/components/cxx/.build-test-rules.yml b/components/cxx/test_apps/.build-test-rules.yml similarity index 100% rename from components/cxx/.build-test-rules.yml rename to components/cxx/test_apps/.build-test-rules.yml diff --git a/components/driver/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml similarity index 100% rename from components/driver/.build-test-rules.yml rename to components/driver/test_apps/.build-test-rules.yml diff --git a/components/efuse/.build-test-rules.yml b/components/efuse/test_apps/.build-test-rules.yml similarity index 100% rename from components/efuse/.build-test-rules.yml rename to components/efuse/test_apps/.build-test-rules.yml diff --git a/components/esp_adc/.build-test-rules.yml b/components/esp_adc/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_adc/.build-test-rules.yml rename to components/esp_adc/test_apps/.build-test-rules.yml diff --git a/components/esp_bootloader_format/.build-test-rules.yml b/components/esp_bootloader_format/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_bootloader_format/.build-test-rules.yml rename to components/esp_bootloader_format/test_apps/.build-test-rules.yml diff --git a/components/esp_common/.build-test-rules.yml b/components/esp_common/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_common/.build-test-rules.yml rename to components/esp_common/test_apps/.build-test-rules.yml diff --git a/components/esp_eth/.build-test-rules.yml b/components/esp_eth/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_eth/.build-test-rules.yml rename to components/esp_eth/test_apps/.build-test-rules.yml diff --git a/components/esp_event/.build-test-rules.yml b/components/esp_event/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_event/.build-test-rules.yml rename to components/esp_event/test_apps/.build-test-rules.yml diff --git a/components/esp_hw_support/.build-test-rules.yml b/components/esp_hw_support/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_hw_support/.build-test-rules.yml rename to components/esp_hw_support/test_apps/.build-test-rules.yml diff --git a/components/esp_lcd/.build-test-rules.yml b/components/esp_lcd/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_lcd/.build-test-rules.yml rename to components/esp_lcd/test_apps/.build-test-rules.yml diff --git a/components/esp_netif/.build-test-rules.yml b/components/esp_netif/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_netif/.build-test-rules.yml rename to components/esp_netif/test_apps/.build-test-rules.yml diff --git a/components/esp_partition/.build-test-rules.yml b/components/esp_partition/host_test/.build-test-rules.yml similarity index 100% rename from components/esp_partition/.build-test-rules.yml rename to components/esp_partition/host_test/.build-test-rules.yml diff --git a/components/esp_psram/.build-test-rules.yml b/components/esp_psram/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_psram/.build-test-rules.yml rename to components/esp_psram/test_apps/.build-test-rules.yml diff --git a/components/esp_ringbuf/.build-test-rules.yml b/components/esp_ringbuf/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_ringbuf/.build-test-rules.yml rename to components/esp_ringbuf/test_apps/.build-test-rules.yml diff --git a/components/esp_rom/.build-test-rules.yml b/components/esp_rom/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_rom/.build-test-rules.yml rename to components/esp_rom/test_apps/.build-test-rules.yml diff --git a/components/esp_system/.build-test-rules.yml b/components/esp_system/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_system/.build-test-rules.yml rename to components/esp_system/test_apps/.build-test-rules.yml diff --git a/components/esp_timer/.build-test-rules.yml b/components/esp_timer/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_timer/.build-test-rules.yml rename to components/esp_timer/test_apps/.build-test-rules.yml diff --git a/components/esp_wifi/.build-test-rules.yml b/components/esp_wifi/test_apps/.build-test-rules.yml similarity index 100% rename from components/esp_wifi/.build-test-rules.yml rename to components/esp_wifi/test_apps/.build-test-rules.yml diff --git a/components/fatfs/.build-test-rules.yml b/components/fatfs/test_apps/.build-test-rules.yml similarity index 100% rename from components/fatfs/.build-test-rules.yml rename to components/fatfs/test_apps/.build-test-rules.yml diff --git a/components/heap/.build-test-rules.yml b/components/heap/test_apps/.build-test-rules.yml similarity index 100% rename from components/heap/.build-test-rules.yml rename to components/heap/test_apps/.build-test-rules.yml diff --git a/components/ieee802154/.build-test-rules.yml b/components/ieee802154/test_apps/.build-test-rules.yml similarity index 100% rename from components/ieee802154/.build-test-rules.yml rename to components/ieee802154/test_apps/.build-test-rules.yml diff --git a/components/log/.build-test-rules.yml b/components/log/host_test/.build-test-rules.yml similarity index 65% rename from components/log/.build-test-rules.yml rename to components/log/host_test/.build-test-rules.yml index 4b3b0adbf4e..4385b9916b6 100644 --- a/components/log/.build-test-rules.yml +++ b/components/log/host_test/.build-test-rules.yml @@ -4,8 +4,3 @@ components/log/host_test/log_test: enable: - if: IDF_TARGET == "linux" reason: only test on linux - -components/log/test_apps: - enable: - - if: IDF_TARGET == "esp32" - reason: only test on esp32 diff --git a/components/log/test_apps/.build-test-rules.yml b/components/log/test_apps/.build-test-rules.yml new file mode 100644 index 00000000000..932fbe83853 --- /dev/null +++ b/components/log/test_apps/.build-test-rules.yml @@ -0,0 +1,6 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/log/test_apps: + enable: + - if: IDF_TARGET == "esp32" + reason: only test on esp32 diff --git a/components/mqtt/.build-test-rules.yml b/components/mqtt/test_apps/.build-test-rules.yml similarity index 100% rename from components/mqtt/.build-test-rules.yml rename to components/mqtt/test_apps/.build-test-rules.yml diff --git a/components/newlib/.build-test-rules.yml b/components/newlib/test_apps/.build-test-rules.yml similarity index 100% rename from components/newlib/.build-test-rules.yml rename to components/newlib/test_apps/.build-test-rules.yml diff --git a/components/sdmmc/.build-test-rules.yml b/components/sdmmc/test_apps/.build-test-rules.yml similarity index 100% rename from components/sdmmc/.build-test-rules.yml rename to components/sdmmc/test_apps/.build-test-rules.yml diff --git a/components/spi_flash/.build-test-rules.yml b/components/spi_flash/test_apps/.build-test-rules.yml similarity index 100% rename from components/spi_flash/.build-test-rules.yml rename to components/spi_flash/test_apps/.build-test-rules.yml diff --git a/components/spiffs/host_test/.build-test-rules.yml b/components/spiffs/host_test/.build-test-rules.yml new file mode 100644 index 00000000000..eec002ed8a4 --- /dev/null +++ b/components/spiffs/host_test/.build-test-rules.yml @@ -0,0 +1,4 @@ +components/spiffs/host_test: + enable: + - if: IDF_TARGET == "linux" + reason: only test on linux diff --git a/components/spiffs/.build-test-rules.yml b/components/spiffs/test_apps/.build-test-rules.yml similarity index 66% rename from components/spiffs/.build-test-rules.yml rename to components/spiffs/test_apps/.build-test-rules.yml index c6d7af71602..7ae25a037ae 100644 --- a/components/spiffs/.build-test-rules.yml +++ b/components/spiffs/test_apps/.build-test-rules.yml @@ -1,8 +1,3 @@ -components/spiffs/host_test: - enable: - - if: IDF_TARGET == "linux" - reason: only test on linux - components/spiffs/test_apps: disable_test: - if: IDF_TARGET not in ["esp32", "esp32c3", "esp32s3"] diff --git a/components/tcp_transport/.build-test-rules.yml b/components/tcp_transport/test_apps/.build-test-rules.yml similarity index 100% rename from components/tcp_transport/.build-test-rules.yml rename to components/tcp_transport/test_apps/.build-test-rules.yml diff --git a/components/touch_element/.build-test-rules.yml b/components/touch_element/test_apps/.build-test-rules.yml similarity index 100% rename from components/touch_element/.build-test-rules.yml rename to components/touch_element/test_apps/.build-test-rules.yml diff --git a/components/ulp/.build-test-rules.yml b/components/ulp/test_apps/.build-test-rules.yml similarity index 100% rename from components/ulp/.build-test-rules.yml rename to components/ulp/test_apps/.build-test-rules.yml diff --git a/components/usb/.build-test-rules.yml b/components/usb/test_apps/.build-test-rules.yml similarity index 100% rename from components/usb/.build-test-rules.yml rename to components/usb/test_apps/.build-test-rules.yml diff --git a/components/wear_levelling/host_test/.build-test-rules.yml b/components/wear_levelling/host_test/.build-test-rules.yml new file mode 100644 index 00000000000..6a71b6a08d2 --- /dev/null +++ b/components/wear_levelling/host_test/.build-test-rules.yml @@ -0,0 +1,6 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/wear_levelling/host_test: + enable: + - if: IDF_TARGET == "linux" + reason: only test on linux diff --git a/components/wear_levelling/.build-test-rules.yml b/components/wear_levelling/test_apps/.build-test-rules.yml similarity index 68% rename from components/wear_levelling/.build-test-rules.yml rename to components/wear_levelling/test_apps/.build-test-rules.yml index d0aadb1bfa3..f596e6c08a5 100644 --- a/components/wear_levelling/.build-test-rules.yml +++ b/components/wear_levelling/test_apps/.build-test-rules.yml @@ -1,9 +1,5 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps -components/wear_levelling/host_test: - enable: - - if: IDF_TARGET == "linux" - reason: only test on linux components/wear_levelling/test_apps: enable: - if: IDF_TARGET in ["esp32", "esp32c3"] From e74193f405a8ecd2f25d47a319df29f6bc6bf7c8 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 20 Sep 2023 15:27:30 +0400 Subject: [PATCH 49/71] fix(gdbstub): fix getting FreeRTOS TCB pointer --- components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c b/components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c index 9e2d1b7846a..1fd13ba3e4e 100644 --- a/components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c +++ b/components/esp_gdbstub/src/port/riscv/gdbstub_riscv.c @@ -89,10 +89,10 @@ void esp_gdbstub_int(__attribute__((unused)) void *frame) int core_id = esp_cpu_get_core_id(); #if CONFIG_FREERTOS_USE_KERNEL_10_5_1 extern void **pxCurrentTCBs; - dummy_tcb_t *tcb = pxCurrentTCBs[core_id]; + dummy_tcb_t *tcb = (dummy_tcb_t *) &pxCurrentTCBs[core_id]; #else extern void **pxCurrentTCB; - dummy_tcb_t *tcb = pxCurrentTCB[core_id]; + dummy_tcb_t *tcb = (dummy_tcb_t *) &pxCurrentTCB[core_id]; #endif /* CONFIG_FREERTOS_USE_KERNEL_10_5_1 */ gdbstub_handle_uart_int((esp_gdbstub_frame_t *)tcb->top_of_stack); } From 2d458a3f938ef0b67dc1068ddd61e98b6240b14e Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Fri, 15 Sep 2023 12:56:13 +0800 Subject: [PATCH 50/71] feat(lp_io): Add support for ESP32P4 --- components/driver/gpio/include/driver/lp_io.h | 51 + .../driver/gpio/include/driver/rtc_io.h | 4 +- components/driver/gpio/rtc_io.c | 21 +- .../driver/test_apps/gpio/main/test_rtcio.c | 112 +- .../driver/test_apps/gpio/main/test_rtcio.h | 148 ++ .../driver/test_apps/gpio/pytest_gpio.py | 1 + components/esp_hw_support/sleep_modes.c | 6 +- components/hal/esp32/include/hal/rtc_io_ll.h | 53 +- .../hal/esp32c6/include/hal/rtc_io_ll.h | 64 +- .../hal/esp32h2/include/hal/rtc_io_ll.h | 8 +- components/hal/esp32p4/include/hal/gpio_ll.h | 43 +- .../hal/esp32p4/include/hal/rtc_io_ll.h | 436 ++++++ .../hal/esp32s2/include/hal/rtc_io_ll.h | 53 +- .../hal/esp32s3/include/hal/rtc_io_ll.h | 51 +- components/hal/include/hal/rtc_io_hal.h | 34 +- components/hal/rtc_io_hal.c | 12 +- components/soc/esp32/rtc_io_periph.c | 1 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 28 + .../soc/esp32p4/include/soc/lp_gpio_pins.h | 21 + .../soc/esp32p4/include/soc/lp_gpio_sig_map.h | 3 + .../soc/esp32p4/include/soc/lp_gpio_struct.h | 1267 +---------------- .../soc/esp32p4/include/soc/lp_iomux_struct.h | 845 +---------- .../soc/esp32p4/include/soc/rtc_io_channel.h | 56 + components/soc/esp32p4/include/soc/soc_caps.h | 15 +- components/soc/esp32p4/rtc_io_periph.c | 67 + components/soc/esp32s2/rtc_io_periph.c | 1 + components/soc/esp32s3/rtc_io_periph.c | 1 + components/soc/include/soc/rtc_io_periph.h | 4 - .../lp_core/include/ulp_lp_core_gpio.h | 7 +- docs/en/api-reference/peripherals/gpio.rst | 11 +- .../peripherals/gpio/esp32p4.inc | 2 +- docs/zh_CN/api-reference/peripherals/gpio.rst | 9 +- 32 files changed, 1105 insertions(+), 2330 deletions(-) create mode 100644 components/driver/gpio/include/driver/lp_io.h create mode 100644 components/driver/test_apps/gpio/main/test_rtcio.h create mode 100644 components/hal/esp32p4/include/hal/rtc_io_ll.h create mode 100644 components/soc/esp32p4/include/soc/lp_gpio_pins.h create mode 100644 components/soc/esp32p4/include/soc/rtc_io_channel.h create mode 100644 components/soc/esp32p4/rtc_io_periph.c diff --git a/components/driver/gpio/include/driver/lp_io.h b/components/driver/gpio/include/driver/lp_io.h new file mode 100644 index 00000000000..a19c2fff4e5 --- /dev/null +++ b/components/driver/gpio/include/driver/lp_io.h @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" +#include "esp_err.h" +#include "driver/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_LP_GPIO_MATRIX_SUPPORTED +/** + * @brief Connect a RTC(LP) GPIO input with a peripheral signal, which tagged as input attribute + * + * @note There's no limitation on the number of signals that a RTC(LP) GPIO can connect with + * + * @param gpio_num GPIO number, especially, `LP_GPIO_MATRIX_CONST_ZERO_INPUT` means connect logic 0 to signal + * `LP_GPIO_MATRIX_CONST_ONE_INPUT` means connect logic 1 to signal + * @param signal_idx LP peripheral signal index (tagged as input attribute) + * @param inv Whether the RTC(LP) GPIO input to be inverted or not + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t lp_gpio_connect_in_signal(gpio_num_t gpio_num, uint32_t signal_idx, bool inv); + +/** + * @brief Connect a peripheral signal which tagged as output attribute with a RTC(LP) GPIO + * + * @note There's no limitation on the number of RTC(LP) GPIOs that a signal can connect with + * + * @param gpio_num GPIO number + * @param signal_idx LP peripheral signal index (tagged as input attribute), especially, `SIG_LP_GPIO_OUT_IDX` means disconnect RTC(LP) GPIO and other peripherals. Only the RTC GPIO driver can control the output level + * @param out_inv Whether to signal to be inverted or not + * @param oen_inv Whether the output enable control is inverted or not + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t lp_gpio_connect_out_signal(gpio_num_t gpio_num, uint32_t signal_idx, bool out_inv, bool oen_inv); +#endif // SOC_LP_GPIO_MATRIX_SUPPORTED + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/gpio/include/driver/rtc_io.h b/components/driver/gpio/include/driver/rtc_io.h index 381ed0e24e4..4e9c2d0e3c2 100644 --- a/components/driver/gpio/include/driver/rtc_io.h +++ b/components/driver/gpio/include/driver/rtc_io.h @@ -107,8 +107,8 @@ esp_err_t rtc_gpio_set_direction(gpio_num_t gpio_num, rtc_gpio_mode_t mode); * @brief RTC GPIO set direction in deep sleep mode or disable sleep status (default). * In some application scenarios, IO needs to have another states during deep sleep. * - * NOTE: ESP32 support INPUT_ONLY mode. - * ESP32S2 support INPUT_ONLY, OUTPUT_ONLY, INPUT_OUTPUT mode. + * NOTE: ESP32 supports INPUT_ONLY mode. + * The rest targets support INPUT_ONLY, OUTPUT_ONLY, INPUT_OUTPUT mode. * * @param gpio_num GPIO number (e.g. GPIO_NUM_12) * @param mode GPIO direction diff --git a/components/driver/gpio/rtc_io.c b/components/driver/gpio/rtc_io.c index ce25da71404..29ee26d299d 100644 --- a/components/driver/gpio/rtc_io.c +++ b/components/driver/gpio/rtc_io.c @@ -12,6 +12,7 @@ #include "freertos/semphr.h" #include "freertos/timers.h" #include "driver/rtc_io.h" +#include "driver/lp_io.h" #include "hal/rtc_io_hal.h" #include "soc/rtc_io_periph.h" #include "soc/soc_caps.h" @@ -44,7 +45,7 @@ esp_err_t rtc_gpio_init(gpio_num_t gpio_num) { ESP_RETURN_ON_FALSE(rtc_gpio_is_valid_gpio(gpio_num), ESP_ERR_INVALID_ARG, RTCIO_TAG, "RTCIO number error"); RTCIO_ENTER_CRITICAL(); - rtcio_hal_function_select(rtc_io_number_get(gpio_num), RTCIO_FUNC_RTC); + rtcio_hal_function_select(rtc_io_number_get(gpio_num), RTCIO_LL_FUNC_RTC); RTCIO_EXIT_CRITICAL(); return ESP_OK; @@ -55,7 +56,7 @@ esp_err_t rtc_gpio_deinit(gpio_num_t gpio_num) ESP_RETURN_ON_FALSE(rtc_gpio_is_valid_gpio(gpio_num), ESP_ERR_INVALID_ARG, RTCIO_TAG, "RTCIO number error"); RTCIO_ENTER_CRITICAL(); // Select Gpio as Digital Gpio - rtcio_hal_function_select(rtc_io_number_get(gpio_num), RTCIO_FUNC_DIGITAL); + rtcio_hal_function_select(rtc_io_number_get(gpio_num), RTCIO_LL_FUNC_DIGITAL); RTCIO_EXIT_CRITICAL(); return ESP_OK; @@ -170,6 +171,22 @@ esp_err_t rtc_gpio_iomux_func_sel(gpio_num_t gpio_num, int func) return ESP_OK; } +#if SOC_LP_GPIO_MATRIX_SUPPORTED +esp_err_t lp_gpio_connect_in_signal(gpio_num_t gpio_num, uint32_t signal_idx, bool inv) +{ + ESP_RETURN_ON_FALSE(rtc_gpio_is_valid_gpio(gpio_num), ESP_ERR_INVALID_ARG, RTCIO_TAG, "LP_IO number error"); + rtcio_hal_matrix_in(rtc_io_number_get(gpio_num), signal_idx, inv); + return ESP_OK; +} + +esp_err_t lp_gpio_connect_out_signal(gpio_num_t gpio_num, uint32_t signal_idx, bool out_inv, bool oen_inv) +{ + ESP_RETURN_ON_FALSE(rtc_gpio_is_valid_gpio(gpio_num), ESP_ERR_INVALID_ARG, RTCIO_TAG, "LP_IO number error"); + rtcio_hal_matrix_out(rtc_io_number_get(gpio_num), signal_idx, out_inv, oen_inv); + return ESP_OK; +} +#endif // SOC_LP_GPIO_MATRIX_SUPPORTED + #endif // SOC_RTCIO_INPUT_OUTPUT_SUPPORTED #if SOC_RTCIO_HOLD_SUPPORTED diff --git a/components/driver/test_apps/gpio/main/test_rtcio.c b/components/driver/test_apps/gpio/main/test_rtcio.c index c6bd60d815d..346d774b13c 100644 --- a/components/driver/test_apps/gpio/main/test_rtcio.c +++ b/components/driver/test_apps/gpio/main/test_rtcio.c @@ -5,6 +5,7 @@ */ #include #include +#include "test_rtcio.h" #include "esp_system.h" #include "esp_sleep.h" #include "unity.h" @@ -16,114 +17,7 @@ #include "esp_err.h" #include "esp_log.h" #include "soc/rtc_io_periph.h" - -#ifdef CONFIG_IDF_TARGET_ESP32 -// The input-only rtcio pins do not have pull-up/down resistors (not support pull-up/down) -#define RTCIO_SUPPORT_PU_PD(num) (rtc_io_desc[num].pullup != 0) -#define TEST_GPIO_PIN_COUNT 16 -const int s_test_map[TEST_GPIO_PIN_COUNT] = { - // GPIO_NUM_0, //GPIO0 // Workaround: GPIO0 is strap pin, can not be used pullup/pulldown test. - GPIO_NUM_2, //GPIO2 - GPIO_NUM_4, //GPIO4 - // GPIO_NUM_12, //GPIO12 // Workaround: GPIO12 is strap pin, can not be used pullup/pulldown test. - GPIO_NUM_13, //GPIO13 - GPIO_NUM_14, //GPIO14 - GPIO_NUM_15, //GPIO15 - GPIO_NUM_25, //GPIO25 - GPIO_NUM_26, //GPIO26 - GPIO_NUM_27, //GPIO27 - GPIO_NUM_32, //GPIO32 - GPIO_NUM_33, //GPIO33 - GPIO_NUM_34, //GPIO34 - GPIO_NUM_35, //GPIO35 - GPIO_NUM_36, //GPIO36 - GPIO_NUM_37, //GPIO37 - GPIO_NUM_38, //GPIO38 - GPIO_NUM_39, //GPIO39 -}; -#elif defined CONFIG_IDF_TARGET_ESP32S2 -// Has no input-only rtcio pins, all pins support pull-up/down -#define RTCIO_SUPPORT_PU_PD(num) 1 -#define TEST_GPIO_PIN_COUNT 20 -const int s_test_map[TEST_GPIO_PIN_COUNT] = { - // GPIO_NUM_0, //GPIO0 // Workaround: GPIO0 is strap pin, can not be used pullup/pulldown test. - GPIO_NUM_1, //GPIO1 - GPIO_NUM_2, //GPIO2 - GPIO_NUM_3, //GPIO3 - GPIO_NUM_4, //GPIO4 - GPIO_NUM_5, //GPIO5 - GPIO_NUM_6, //GPIO6 - GPIO_NUM_7, //GPIO7 - GPIO_NUM_8, //GPIO8 - GPIO_NUM_9, //GPIO9 - GPIO_NUM_10, //GPIO10 - GPIO_NUM_11, //GPIO11 - GPIO_NUM_12, //GPIO12 - GPIO_NUM_13, //GPIO13 - GPIO_NUM_14, //GPIO14 - GPIO_NUM_15, //GPIO15 - GPIO_NUM_16, //GPIO16 - GPIO_NUM_17, //GPIO17 - // GPIO_NUM_18, //GPIO18 // Workaround: IO18 is pullup outside in ESP32S2-Saola Runner. - GPIO_NUM_19, //GPIO19 - GPIO_NUM_20, //GPIO20 - GPIO_NUM_21, //GPIO21 -}; -#elif defined CONFIG_IDF_TARGET_ESP32S3 -// Has no input-only rtcio pins, all pins support pull-up/down -#define RTCIO_SUPPORT_PU_PD(num) 1 -#define TEST_GPIO_PIN_COUNT 21 -const int s_test_map[TEST_GPIO_PIN_COUNT] = { - // GPIO_NUM_0, //GPIO0 // Workaround: GPIO0 is strap pin, can not be used pullup/pulldown test. - GPIO_NUM_1, //GPIO1 - GPIO_NUM_2, //GPIO2 - GPIO_NUM_3, //GPIO3 - GPIO_NUM_4, //GPIO4 - GPIO_NUM_5, //GPIO5 - GPIO_NUM_6, //GPIO6 - GPIO_NUM_7, //GPIO7 - GPIO_NUM_8, //GPIO8 - GPIO_NUM_9, //GPIO9 - GPIO_NUM_10, //GPIO10 - GPIO_NUM_11, //GPIO11 - GPIO_NUM_12, //GPIO12 - GPIO_NUM_13, //GPIO13 - GPIO_NUM_14, //GPIO14 - GPIO_NUM_15, //GPIO15 - GPIO_NUM_16, //GPIO16 - GPIO_NUM_17, //GPIO17 - GPIO_NUM_18, //GPIO18 - GPIO_NUM_19, //GPIO19 - GPIO_NUM_20, //GPIO20 - GPIO_NUM_21, //GPIO21 -}; -#elif CONFIG_IDF_TARGET_ESP32C6 -// Has no input-only rtcio pins, all pins support pull-up/down -#define RTCIO_SUPPORT_PU_PD(num) 1 -#define TEST_GPIO_PIN_COUNT 8 -const int s_test_map[TEST_GPIO_PIN_COUNT] = { - GPIO_NUM_0, //GPIO0 - GPIO_NUM_1, //GPIO1 - GPIO_NUM_2, //GPIO2 - GPIO_NUM_3, //GPIO3 - GPIO_NUM_4, //GPIO4 - GPIO_NUM_5, //GPIO5 - GPIO_NUM_6, //GPIO6 - GPIO_NUM_7, //GPIO7 -}; -#elif CONFIG_IDF_TARGET_ESP32H2 -#define TEST_GPIO_PIN_COUNT 8 -const int s_test_map[TEST_GPIO_PIN_COUNT] = { - GPIO_NUM_7, //GPIO7 - GPIO_NUM_8, //GPIO8 - GPIO_NUM_9, //GPIO9 - GPIO_NUM_10, //GPIO10 - GPIO_NUM_11, //GPIO11 - GPIO_NUM_12, //GPIO12 - GPIO_NUM_13, //GPIO13 - GPIO_NUM_14, //GPIO14 -}; -#endif +#include "soc/soc_caps.h" #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED static const char *TAG = "rtcio_test"; @@ -341,6 +235,7 @@ TEST_CASE("RTCIO_output_hold_test", "[rtcio]") #endif //SOC_RTCIO_HOLD_SUPPORTED #endif //SOC_RTCIO_INPUT_OUTPUT_SUPPORTED +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) // TODO: IDF-7529 // It is not necessary to test every rtcio pin, it will take too much ci testing time for deep sleep // Only tests on s_test_map[TEST_RTCIO_DEEP_SLEEP_PIN_INDEX] pin // (ESP32: IO25, ESP32S2, S3: IO6, C6: IO5, H2: IO12) these pads' default configuration is low level @@ -389,3 +284,4 @@ static void rtcio_deep_sleep_hold_test_second_stage(void) TEST_CASE_MULTIPLE_STAGES("RTCIO_deep_sleep_output_hold_test", "[rtcio]", rtcio_deep_sleep_hold_test_first_stage, rtcio_deep_sleep_hold_test_second_stage) +#endif // !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) diff --git a/components/driver/test_apps/gpio/main/test_rtcio.h b/components/driver/test_apps/gpio/main/test_rtcio.h new file mode 100644 index 00000000000..e2eb1f00d34 --- /dev/null +++ b/components/driver/test_apps/gpio/main/test_rtcio.h @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" +#include "soc/gpio_num.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_IDF_TARGET_ESP32 +// The input-only rtcio pins do not have pull-up/down resistors (not support pull-up/down) +#define RTCIO_SUPPORT_PU_PD(num) (rtc_io_desc[num].pullup != 0) +#define TEST_GPIO_PIN_COUNT 16 +const int s_test_map[TEST_GPIO_PIN_COUNT] = { + // GPIO_NUM_0, //GPIO0 // Workaround: GPIO0 is strap pin, can not be used pullup/pulldown test. + GPIO_NUM_2, //GPIO2 + GPIO_NUM_4, //GPIO4 + // GPIO_NUM_12, //GPIO12 // Workaround: GPIO12 is strap pin, can not be used pullup/pulldown test. + GPIO_NUM_13, //GPIO13 + GPIO_NUM_14, //GPIO14 + GPIO_NUM_15, //GPIO15 + GPIO_NUM_25, //GPIO25 + GPIO_NUM_26, //GPIO26 + GPIO_NUM_27, //GPIO27 + GPIO_NUM_32, //GPIO32 + GPIO_NUM_33, //GPIO33 + GPIO_NUM_34, //GPIO34 + GPIO_NUM_35, //GPIO35 + GPIO_NUM_36, //GPIO36 + GPIO_NUM_37, //GPIO37 + GPIO_NUM_38, //GPIO38 + GPIO_NUM_39, //GPIO39 +}; +#elif defined CONFIG_IDF_TARGET_ESP32S2 +// Has no input-only rtcio pins, all pins support pull-up/down +#define RTCIO_SUPPORT_PU_PD(num) 1 +#define TEST_GPIO_PIN_COUNT 20 +const int s_test_map[TEST_GPIO_PIN_COUNT] = { + // GPIO_NUM_0, //GPIO0 // Workaround: GPIO0 is strap pin, can not be used pullup/pulldown test. + GPIO_NUM_1, //GPIO1 + GPIO_NUM_2, //GPIO2 + GPIO_NUM_3, //GPIO3 + GPIO_NUM_4, //GPIO4 + GPIO_NUM_5, //GPIO5 + GPIO_NUM_6, //GPIO6 + GPIO_NUM_7, //GPIO7 + GPIO_NUM_8, //GPIO8 + GPIO_NUM_9, //GPIO9 + GPIO_NUM_10, //GPIO10 + GPIO_NUM_11, //GPIO11 + GPIO_NUM_12, //GPIO12 + GPIO_NUM_13, //GPIO13 + GPIO_NUM_14, //GPIO14 + GPIO_NUM_15, //GPIO15 + GPIO_NUM_16, //GPIO16 + GPIO_NUM_17, //GPIO17 + // GPIO_NUM_18, //GPIO18 // Workaround: IO18 is pullup outside in ESP32S2-Saola Runner. + GPIO_NUM_19, //GPIO19 + GPIO_NUM_20, //GPIO20 + GPIO_NUM_21, //GPIO21 +}; +#elif defined CONFIG_IDF_TARGET_ESP32S3 +// Has no input-only rtcio pins, all pins support pull-up/down +#define RTCIO_SUPPORT_PU_PD(num) 1 +#define TEST_GPIO_PIN_COUNT 21 +const int s_test_map[TEST_GPIO_PIN_COUNT] = { + // GPIO_NUM_0, //GPIO0 // Workaround: GPIO0 is strap pin, can not be used pullup/pulldown test. + GPIO_NUM_1, //GPIO1 + GPIO_NUM_2, //GPIO2 + GPIO_NUM_3, //GPIO3 + GPIO_NUM_4, //GPIO4 + GPIO_NUM_5, //GPIO5 + GPIO_NUM_6, //GPIO6 + GPIO_NUM_7, //GPIO7 + GPIO_NUM_8, //GPIO8 + GPIO_NUM_9, //GPIO9 + GPIO_NUM_10, //GPIO10 + GPIO_NUM_11, //GPIO11 + GPIO_NUM_12, //GPIO12 + GPIO_NUM_13, //GPIO13 + GPIO_NUM_14, //GPIO14 + GPIO_NUM_15, //GPIO15 + GPIO_NUM_16, //GPIO16 + GPIO_NUM_17, //GPIO17 + GPIO_NUM_18, //GPIO18 + GPIO_NUM_19, //GPIO19 + GPIO_NUM_20, //GPIO20 + GPIO_NUM_21, //GPIO21 +}; +#elif CONFIG_IDF_TARGET_ESP32C6 +// Has no input-only rtcio pins, all pins support pull-up/down +#define RTCIO_SUPPORT_PU_PD(num) 1 +#define TEST_GPIO_PIN_COUNT 8 +const int s_test_map[TEST_GPIO_PIN_COUNT] = { + GPIO_NUM_0, //GPIO0 + GPIO_NUM_1, //GPIO1 + GPIO_NUM_2, //GPIO2 + GPIO_NUM_3, //GPIO3 + GPIO_NUM_4, //GPIO4 + GPIO_NUM_5, //GPIO5 + GPIO_NUM_6, //GPIO6 + GPIO_NUM_7, //GPIO7 +}; +#elif CONFIG_IDF_TARGET_ESP32H2 +#define TEST_GPIO_PIN_COUNT 8 +const int s_test_map[TEST_GPIO_PIN_COUNT] = { + GPIO_NUM_7, //GPIO7 + GPIO_NUM_8, //GPIO8 + GPIO_NUM_9, //GPIO9 + GPIO_NUM_10, //GPIO10 + GPIO_NUM_11, //GPIO11 + GPIO_NUM_12, //GPIO12 + GPIO_NUM_13, //GPIO13 + GPIO_NUM_14, //GPIO14 +}; +#elif CONFIG_IDF_TARGET_ESP32P4 +// Has no input-only rtcio pins, all pins support pull-up/down +#define RTCIO_SUPPORT_PU_PD(num) 1 +#define TEST_GPIO_PIN_COUNT 16 +const int s_test_map[TEST_GPIO_PIN_COUNT] = { + GPIO_NUM_0, //GPIO0 + GPIO_NUM_1, //GPIO1 + GPIO_NUM_2, //GPIO2 + GPIO_NUM_3, //GPIO3 + GPIO_NUM_4, //GPIO4 + GPIO_NUM_5, //GPIO5 + GPIO_NUM_6, //GPIO6 + GPIO_NUM_7, //GPIO7 + GPIO_NUM_8, //GPIO8 + GPIO_NUM_9, //GPIO9 + GPIO_NUM_10, //GPIO10 + GPIO_NUM_11, //GPIO11 + GPIO_NUM_12, //GPIO12 + GPIO_NUM_13, //GPIO13 + GPIO_NUM_14, //GPIO14 + GPIO_NUM_15, //GPIO15 +}; +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/test_apps/gpio/pytest_gpio.py b/components/driver/test_apps/gpio/pytest_gpio.py index 1ab39405f9f..f0682a007d2 100644 --- a/components/driver/test_apps/gpio/pytest_gpio.py +++ b/components/driver/test_apps/gpio/pytest_gpio.py @@ -34,6 +34,7 @@ def test_legacy_sigma_delta(dut: IdfDut) -> None: @pytest.mark.esp32s3 @pytest.mark.esp32c6 @pytest.mark.esp32h2 +@pytest.mark.esp32p4 @pytest.mark.generic @pytest.mark.parametrize('config', CONFIGS, indirect=True) def test_rtc_io(dut: IdfDut) -> None: diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index a4f920890b4..6a7a12bb134 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1389,7 +1389,7 @@ static void ext0_wakeup_prepare(void) { int rtc_gpio_num = s_config.ext0_rtc_gpio_num; rtcio_hal_ext0_set_wakeup_pin(rtc_gpio_num, s_config.ext0_trigger_level); - rtcio_hal_function_select(rtc_gpio_num, RTCIO_FUNC_RTC); + rtcio_hal_function_select(rtc_gpio_num, RTCIO_LL_FUNC_RTC); rtcio_hal_input_enable(rtc_gpio_num); } #endif // SOC_PM_SUPPORT_EXT0_WAKEUP @@ -1462,7 +1462,7 @@ static void ext1_wakeup_prepare(void) } #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED // Route pad to RTC - rtcio_hal_function_select(rtc_pin, RTCIO_FUNC_RTC); + rtcio_hal_function_select(rtc_pin, RTCIO_LL_FUNC_RTC); // set input enable in sleep mode rtcio_hal_input_enable(rtc_pin); #if SOC_PM_SUPPORT_RTC_PERIPH_PD @@ -1477,7 +1477,7 @@ static void ext1_wakeup_prepare(void) * a pathway to EXT1. */ // Route pad to DIGITAL - rtcio_hal_function_select(rtc_pin, RTCIO_FUNC_DIGITAL); + rtcio_hal_function_select(rtc_pin, RTCIO_LL_FUNC_DIGITAL); // set input enable gpio_ll_input_enable(&GPIO, gpio); // hold rtc_pin to use it during sleep state diff --git a/components/hal/esp32/include/hal/rtc_io_ll.h b/components/hal/esp32/include/hal/rtc_io_ll.h index c47f2cf22fe..d92ab124fde 100644 --- a/components/hal/esp32/include/hal/rtc_io_ll.h +++ b/components/hal/esp32/include/hal/rtc_io_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,8 +13,9 @@ #pragma once #include +#include "soc/rtc_io_struct.h" +#include "soc/rtc_io_reg.h" #include "soc/rtc_periph.h" -#include "hal/gpio_types.h" #define RTCIO_LL_PIN_FUNC 0 @@ -23,19 +24,19 @@ extern "C" { #endif typedef enum { - RTCIO_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */ - RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ + RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */ + RTCIO_LL_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ } rtcio_ll_func_t; typedef enum { - RTCIO_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ - RTCIO_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ - RTCIO_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ + RTCIO_LL_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ + RTCIO_LL_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ + RTCIO_LL_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ } rtcio_ll_wake_type_t; typedef enum { - RTCIO_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ - RTCIO_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ + RTCIO_LL_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ + RTCIO_LL_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ } rtcio_ll_out_mode_t; /** @@ -58,12 +59,12 @@ static inline void rtcio_ll_iomux_func_sel(int rtcio_num, int func) */ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) { - if (func == RTCIO_FUNC_RTC) { + if (func == RTCIO_LL_FUNC_RTC) { // 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module. SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux)); //0:RTC FUNCTION 1,2,3:Reserved rtcio_ll_iomux_func_sel(rtcio_num, RTCIO_LL_PIN_FUNC); - } else if (func == RTCIO_FUNC_DIGITAL) { + } else if (func == RTCIO_LL_FUNC_DIGITAL) { CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux)); } } @@ -291,7 +292,7 @@ static inline void rtcio_ll_wakeup_enable(int rtcio_num, rtcio_ll_wake_type_t ty static inline void rtcio_ll_wakeup_disable(int rtcio_num) { RTCIO.pin[rtcio_num].wakeup_enable = 0; - RTCIO.pin[rtcio_num].int_type = RTCIO_WAKEUP_DISABLE; + RTCIO.pin[rtcio_num].int_type = RTCIO_LL_WAKEUP_DISABLE; } /** @@ -299,10 +300,10 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_output_in_sleep(int rtcio_num) { - if (rtc_io_desc[gpio_num].slpoe) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe); + if (rtc_io_desc[rtcio_num].slpoe) { + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpoe); } } @@ -311,10 +312,10 @@ static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_output_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_output_in_sleep(int rtcio_num) { - if (rtc_io_desc[gpio_num].slpoe) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe); + if (rtc_io_desc[rtcio_num].slpoe) { + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpoe); } } @@ -323,9 +324,9 @@ static inline void rtcio_ll_disable_output_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_input_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_input_in_sleep(int rtcio_num) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie); + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpie); } /** @@ -333,9 +334,9 @@ static inline void rtcio_ll_enable_input_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_input_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_input_in_sleep(int rtcio_num) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie); + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpie); } /** @@ -343,9 +344,9 @@ static inline void rtcio_ll_disable_input_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_sleep_setting(int rtcio_num) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel); + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpsel); } /** @@ -353,9 +354,9 @@ static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_sleep_setting(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_sleep_setting(int rtcio_num) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel); + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpsel); } /** diff --git a/components/hal/esp32c6/include/hal/rtc_io_ll.h b/components/hal/esp32c6/include/hal/rtc_io_ll.h index ab374e2f6ae..28d3276ed04 100644 --- a/components/hal/esp32c6/include/hal/rtc_io_ll.h +++ b/components/hal/esp32c6/include/hal/rtc_io_ll.h @@ -14,15 +14,13 @@ #include #include -#include "soc/rtc_periph.h" +#include "soc/soc_caps.h" #include "soc/pcr_struct.h" -#include "soc/rtc_io_struct.h" +#include "soc/lp_io_struct.h" #include "soc/lp_aon_struct.h" #include "soc/pmu_struct.h" #include "hal/misc.h" #include "hal/assert.h" -#include "hal/gpio_types.h" -#include "soc/io_mux_reg.h" #ifdef __cplusplus extern "C" { @@ -31,19 +29,19 @@ extern "C" { #define RTCIO_LL_PIN_FUNC 0 typedef enum { - RTCIO_FUNC_RTC = 0x0, /*!< The pin controlled by RTC module. */ - RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ + RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controlled by RTC module. */ + RTCIO_LL_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ } rtcio_ll_func_t; typedef enum { - RTCIO_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ - RTCIO_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ - RTCIO_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ + RTCIO_LL_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ + RTCIO_LL_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ + RTCIO_LL_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ } rtcio_ll_wake_type_t; typedef enum { - RTCIO_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ - RTCIO_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ + RTCIO_LL_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ + RTCIO_LL_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ } rtcio_ll_out_mode_t; /** @@ -69,14 +67,14 @@ static inline void rtcio_ll_iomux_func_sel(int rtcio_num, int func) */ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) { - if (func == RTCIO_FUNC_RTC) { + if (func == RTCIO_LL_FUNC_RTC) { // 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module. uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel); sel_mask |= BIT(rtcio_num); HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel, sel_mask); //0:RTC FUNCTION 1,2,3:Reserved rtcio_ll_iomux_func_sel(rtcio_num, RTCIO_LL_PIN_FUNC); - } else if (func == RTCIO_FUNC_DIGITAL) { + } else if (func == RTCIO_LL_FUNC_DIGITAL) { // Clear the bit to use digital GPIO module uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel); sel_mask &= ~BIT(rtcio_num); @@ -147,7 +145,7 @@ static inline void rtcio_ll_input_disable(int rtcio_num) */ static inline uint32_t rtcio_ll_get_level(int rtcio_num) { - return (uint32_t)(LP_IO.in.in_data_next >> rtcio_num) & 0x1; + return (uint32_t)(HAL_FORCE_READ_U32_REG_FIELD(LP_IO.in, in_data_next) >> rtcio_num) & 0x1; } /** @@ -296,7 +294,7 @@ static inline void rtcio_ll_wakeup_enable(int rtcio_num, rtcio_ll_wake_type_t ty static inline void rtcio_ll_wakeup_disable(int rtcio_num) { LP_IO.pin[rtcio_num].wakeup_enable = 0; - LP_IO.pin[rtcio_num].int_type = RTCIO_WAKEUP_DISABLE; + LP_IO.pin[rtcio_num].int_type = RTCIO_LL_WAKEUP_DISABLE; } /** @@ -304,9 +302,9 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_output_in_sleep(int rtcio_num) { - LP_IO.gpio[gpio_num].mcu_oe = 1; + LP_IO.gpio[rtcio_num].mcu_oe = 1; } /** @@ -314,9 +312,9 @@ static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_output_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_output_in_sleep(int rtcio_num) { - LP_IO.gpio[gpio_num].mcu_oe = 0; + LP_IO.gpio[rtcio_num].mcu_oe = 0; } /** @@ -324,9 +322,9 @@ static inline void rtcio_ll_disable_output_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_input_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_input_in_sleep(int rtcio_num) { - LP_IO.gpio[gpio_num].mcu_ie = 1; + LP_IO.gpio[rtcio_num].mcu_ie = 1; } /** @@ -334,9 +332,9 @@ static inline void rtcio_ll_enable_input_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_input_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_input_in_sleep(int rtcio_num) { - LP_IO.gpio[gpio_num].mcu_ie = 0; + LP_IO.gpio[rtcio_num].mcu_ie = 0; } /** @@ -344,9 +342,9 @@ static inline void rtcio_ll_disable_input_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_sleep_setting(int rtcio_num) { - LP_IO.gpio[gpio_num].slp_sel = 1; + LP_IO.gpio[rtcio_num].slp_sel = 1; } /** @@ -354,23 +352,21 @@ static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_sleep_setting(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_sleep_setting(int rtcio_num) { - LP_IO.gpio[gpio_num].slp_sel = 0; + LP_IO.gpio[rtcio_num].slp_sel = 0; } /** * @brief Get the status of whether an IO is used for sleep wake-up. * - * @param hw Peripheral GPIO hardware instance address. - * @param gpio_num GPIO number + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). * @return True if the pin is enabled to wake up from deep-sleep */ -static inline bool rtcio_ll_wakeup_is_enabled(gpio_num_t gpio_num) +static inline bool rtcio_ll_wakeup_is_enabled(int rtcio_num) { - HAL_ASSERT(gpio_num <= GPIO_NUM_7 && "gpio larger than 7 does not support deep sleep wake-up function"); - // On ESP32-C6, (lp_io pin number) == (gpio pin number) - return LP_IO.pin[gpio_num].wakeup_enable; + HAL_ASSERT(rtcio_num >= 0 && rtcio_num < SOC_RTCIO_PIN_COUNT && "io does not support deep sleep wake-up function"); + return LP_IO.pin[rtcio_num].wakeup_enable; } /** @@ -380,7 +376,7 @@ static inline bool rtcio_ll_wakeup_is_enabled(gpio_num_t gpio_num) */ static inline uint32_t rtcio_ll_get_interrupt_status(void) { - return (uint32_t)(LP_IO.status.status_interrupt); + return (uint32_t)HAL_FORCE_READ_U32_REG_FIELD(LP_IO.status, status_interrupt); } /** diff --git a/components/hal/esp32h2/include/hal/rtc_io_ll.h b/components/hal/esp32h2/include/hal/rtc_io_ll.h index 1205098a85a..dcd32b22394 100644 --- a/components/hal/esp32h2/include/hal/rtc_io_ll.h +++ b/components/hal/esp32h2/include/hal/rtc_io_ll.h @@ -23,8 +23,8 @@ extern "C" { #define RTCIO_LL_GPIO_NUM_OFFSET 7 // rtcio 0-7 correspond to gpio 7-14 typedef enum { - RTCIO_FUNC_RTC = 0x0, /*!< The pin controlled by RTC module. */ - RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ + RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controlled by RTC module. */ + RTCIO_LL_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ } rtcio_ll_func_t; /** @@ -37,12 +37,12 @@ typedef enum { */ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) { - if (func == RTCIO_FUNC_RTC) { + if (func == RTCIO_LL_FUNC_RTC) { // 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module. uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel); sel_mask |= BIT(rtcio_num); HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel, sel_mask); - } else if (func == RTCIO_FUNC_DIGITAL) { + } else if (func == RTCIO_LL_FUNC_DIGITAL) { // Clear the bit to use digital GPIO module uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel); sel_mask &= ~BIT(rtcio_num); diff --git a/components/hal/esp32p4/include/hal/gpio_ll.h b/components/hal/esp32p4/include/hal/gpio_ll.h index 7a9117d00fb..274d5e68102 100644 --- a/components/hal/esp32p4/include/hal/gpio_ll.h +++ b/components/hal/esp32p4/include/hal/gpio_ll.h @@ -247,18 +247,17 @@ static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_pin_input_hysteresis_enable(gpio_dev_t *hw, uint32_t gpio_num) { - // TODO: IDF-7480 Fix magic number 16 with proper macro uint64_t bit_mask = 1ULL << gpio_num; if (!(bit_mask & SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK)) { // GPIO0-15 LP_IOMUX.lp_pad_hys.reg_lp_gpio_hys |= bit_mask; } else { - if (gpio_num < 32 + 16) { + if (gpio_num < 32 + SOC_RTCIO_PIN_COUNT) { // GPIO 16-47 - HP_SYSTEM.gpio_o_hys_ctrl0.reg_gpio_0_hys_low |= (bit_mask >> 16); + HP_SYSTEM.gpio_o_hys_ctrl0.reg_gpio_0_hys_low |= (bit_mask >> SOC_RTCIO_PIN_COUNT); } else { // GPIO 48-56 - HP_SYSTEM.gpio_o_hys_ctrl1.reg_gpio_0_hys_high |= (bit_mask >> (32 + 16)); + HP_SYSTEM.gpio_o_hys_ctrl1.reg_gpio_0_hys_high |= (bit_mask >> (32 + SOC_RTCIO_PIN_COUNT)); } } } @@ -271,18 +270,17 @@ static inline void gpio_ll_pin_input_hysteresis_enable(gpio_dev_t *hw, uint32_t */ static inline void gpio_ll_pin_input_hysteresis_disable(gpio_dev_t *hw, uint32_t gpio_num) { - // TODO: IDF-7480 Fix magic number 16 with proper macro uint64_t bit_mask = 1ULL << gpio_num; if (!(bit_mask & SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK)) { // GPIO0-15 LP_IOMUX.lp_pad_hys.reg_lp_gpio_hys &= ~bit_mask; } else { - if (gpio_num < 32 + 16) { + if (gpio_num < 32 + SOC_RTCIO_PIN_COUNT) { // GPIO 16-47 - HP_SYSTEM.gpio_o_hys_ctrl0.reg_gpio_0_hys_low &= ~(bit_mask >> 16); + HP_SYSTEM.gpio_o_hys_ctrl0.reg_gpio_0_hys_low &= ~(bit_mask >> SOC_RTCIO_PIN_COUNT); } else { // GPIO 48-56 - HP_SYSTEM.gpio_o_hys_ctrl1.reg_gpio_0_hys_high &= ~(bit_mask >> (32 + 16)); + HP_SYSTEM.gpio_o_hys_ctrl1.reg_gpio_0_hys_high &= ~(bit_mask >> (32 + SOC_RTCIO_PIN_COUNT)); } } } @@ -443,18 +441,19 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu */ static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) { - // TODO: IDF-7480 Fix magic number 16 with proper macro uint64_t bit_mask = 1ULL << gpio_num; if (!(bit_mask & SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK)) { // GPIO 0-15 - LP_IOMUX.lp_pad_hold.reg_lp_gpio_hold |= bit_mask; + uint32_t hold_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_IOMUX.lp_pad_hold, reg_lp_gpio_hold); + hold_mask |= bit_mask; + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_IOMUX.lp_pad_hold, reg_lp_gpio_hold, hold_mask); } else { - if (gpio_num < 32 + 16) { + if (gpio_num < 32 + SOC_RTCIO_PIN_COUNT) { // GPIO 16-47 - HP_SYSTEM.gpio_o_hold_ctrl0.reg_gpio_0_hold_low |= (bit_mask >> 16); + HP_SYSTEM.gpio_o_hold_ctrl0.reg_gpio_0_hold_low |= (bit_mask >> SOC_RTCIO_PIN_COUNT); } else { // GPIO 48-56 - HP_SYSTEM.gpio_o_hold_ctrl1.reg_gpio_0_hold_high |= (bit_mask >> (32 + 16)); + HP_SYSTEM.gpio_o_hold_ctrl1.reg_gpio_0_hold_high |= (bit_mask >> (32 + SOC_RTCIO_PIN_COUNT)); } } } @@ -467,18 +466,19 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num) { - // TODO: IDF-7480 Fix magic number 16 with proper macro uint64_t bit_mask = 1ULL << gpio_num; if (!(bit_mask & SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK)) { // GPIO 0-15 - LP_IOMUX.lp_pad_hold.reg_lp_gpio_hold &= ~bit_mask; + uint32_t hold_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_IOMUX.lp_pad_hold, reg_lp_gpio_hold); + hold_mask &= ~bit_mask; + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_IOMUX.lp_pad_hold, reg_lp_gpio_hold, hold_mask); } else { - if (gpio_num < 32 + 16) { + if (gpio_num < 32 + SOC_RTCIO_PIN_COUNT) { // GPIO 16-47 - HP_SYSTEM.gpio_o_hold_ctrl0.reg_gpio_0_hold_low &= ~(bit_mask >> 16); + HP_SYSTEM.gpio_o_hold_ctrl0.reg_gpio_0_hold_low &= ~(bit_mask >> SOC_RTCIO_PIN_COUNT); } else { // GPIO 48-56 - HP_SYSTEM.gpio_o_hold_ctrl1.reg_gpio_0_hold_high &= ~(bit_mask >> (32 + 16)); + HP_SYSTEM.gpio_o_hold_ctrl1.reg_gpio_0_hold_high &= ~(bit_mask >> (32 + SOC_RTCIO_PIN_COUNT)); } } } @@ -498,18 +498,17 @@ static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num) { - // TODO: IDF-7480 Fix magic number 16 with proper macro uint64_t bit_mask = 1ULL << gpio_num; if (!(bit_mask & SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK)) { // GPIO 0-15 abort(); } else { - if (gpio_num < 32 + 16) { + if (gpio_num < 32 + SOC_RTCIO_PIN_COUNT) { // GPIO 16-47 - return !!(HP_SYSTEM.gpio_o_hold_ctrl0.reg_gpio_0_hold_low & (bit_mask >> 16)); + return !!(HP_SYSTEM.gpio_o_hold_ctrl0.reg_gpio_0_hold_low & (bit_mask >> SOC_RTCIO_PIN_COUNT)); } else { // GPIO 48-56 - return !!(HP_SYSTEM.gpio_o_hold_ctrl1.reg_gpio_0_hold_high & (bit_mask >> (32 + 16))); + return !!(HP_SYSTEM.gpio_o_hold_ctrl1.reg_gpio_0_hold_high & (bit_mask >> (32 + SOC_RTCIO_PIN_COUNT))); } } } diff --git a/components/hal/esp32p4/include/hal/rtc_io_ll.h b/components/hal/esp32p4/include/hal/rtc_io_ll.h new file mode 100644 index 00000000000..5d448c145bb --- /dev/null +++ b/components/hal/esp32p4/include/hal/rtc_io_ll.h @@ -0,0 +1,436 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + +#pragma once + +#include +#include "esp_bit_defs.h" +#include "soc/soc_caps.h" +#include "soc/lp_gpio_struct.h" +#include "soc/lp_iomux_struct.h" +#include "soc/lp_gpio_sig_map.h" +#include "soc/pmu_struct.h" +#include "hal/misc.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTCIO_LL_PIN_FUNC 1 // LP_GPIO function + +typedef enum { + RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controlled by RTC module. */ + RTCIO_LL_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ +} rtcio_ll_func_t; + +typedef enum { + RTCIO_LL_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ + RTCIO_LL_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ + RTCIO_LL_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ +} rtcio_ll_wake_type_t; + +typedef enum { + RTCIO_LL_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ + RTCIO_LL_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ +} rtcio_ll_out_mode_t; + +/** + * @brief Select RTC GPIO input to a signal. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param signal_idx LP peripheral signal index. + * @param inv True to invert input signal; False then no invert. + */ +static inline void rtcio_ll_matrix_in(int rtcio_num, uint32_t signal_idx, bool inv) +{ + lp_gpio_func_in_sel_cfg_reg_t reg; + reg.func_in_sel = rtcio_num; + reg.in_inv_sel = inv; + reg.sig_in_sel = 1; // Bypass LP_GPIO + LP_GPIO.func_in_sel_cfg[signal_idx].val = reg.val; +} + +/** + * @brief Select signal output to a RTC GPIO. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param signal_idx LP peripheral signal index. + * @param out_inv True to invert output signal; False then no invert. + * @param oen_inv True to invert output enable signal; False then no invert. + */ +static inline void rtcio_ll_matrix_out(int rtcio_num, uint32_t signal_idx, bool out_inv, bool oen_inv) +{ + lp_gpio_func_out_sel_cfg_reg_t reg; + reg.func_out_sel = signal_idx; + reg.out_inv_sel = out_inv; + reg.oe_inv_sel = oen_inv; + LP_GPIO.func_out_sel_cfg[rtcio_num].val = reg.val; + + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_GPIO.enable_w1ts, reg_gpio_enable_data_w1ts, BIT(rtcio_num)); +} + +/** + * @brief Select a RTC IOMUX function for the RTC IO + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param func Function to assign to the pin + */ +static inline void rtcio_ll_iomux_func_sel(int rtcio_num, int func) +{ + LP_IOMUX.pad[rtcio_num].fun_sel = func; + // When using as normal (output) LP_GPIO, it is reasonable to ensure that no peripheral signal is routed to the pin + if (func == RTCIO_LL_PIN_FUNC) { + LP_GPIO.func_out_sel_cfg[rtcio_num].func_out_sel = SIG_LP_GPIO_OUT_IDX; + } +} + +/** + * @brief Select the lp_gpio/hp_gpio function to control the pad. + * + * @note The RTC function must be selected before the pad analog function is enabled. + * @note The clock gating 'HP_SYS_CLKRST.soc_clk_ctrl3.reg_iomux_apb_clk_en' is the gate of 'lp_io', 'ana_cmpr', 'sdm', 'glitch_fliter', and 'etm_gpio' + * And it's default to be turned on, so we don't need to operate this clock gate here additionally + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param func Select pin function. + */ +static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) +{ + if (func == RTCIO_LL_FUNC_RTC) { + // 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module. + LP_IOMUX.pad[rtcio_num].mux_sel = 1; + // LP_GPIO is FUNC 1 + rtcio_ll_iomux_func_sel(rtcio_num, RTCIO_LL_PIN_FUNC); + } else if (func == RTCIO_LL_FUNC_DIGITAL) { + // Clear the bit to use digital GPIO module + LP_IOMUX.pad[rtcio_num].mux_sel = 0; + } +} + +/** + * @brief Enable RTCIO output. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_output_enable(int rtcio_num) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_GPIO.enable_w1ts, reg_gpio_enable_data_w1ts, BIT(rtcio_num)); +} + +/** + * @brief Disable RTCIO output. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_output_disable(int rtcio_num) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_GPIO.enable_w1tc, reg_gpio_enable_data_w1tc, BIT(rtcio_num)); + // Ensure no other output signal is routed via LP_GPIO matrix to this pin + LP_GPIO.func_out_sel_cfg[rtcio_num].func_out_sel = SIG_LP_GPIO_OUT_IDX; +} + +/** + * @brief Set RTCIO output level. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param level 0: output low; 1: output high. + */ +static inline void rtcio_ll_set_level(int rtcio_num, uint32_t level) +{ + if (level) { + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_GPIO.out_w1ts, reg_gpio_out_data_w1ts, BIT(rtcio_num)); + } else { + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_GPIO.out_w1tc, reg_gpio_out_data_w1tc, BIT(rtcio_num)); + } +} + +/** + * @brief Enable RTCIO input. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_input_enable(int rtcio_num) +{ + LP_IOMUX.pad[rtcio_num].fun_ie = 1; +} + +/** + * @brief Disable RTCIO input. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_input_disable(int rtcio_num) +{ + LP_IOMUX.pad[rtcio_num].fun_ie = 0; +} + +/** + * @brief Get RTCIO input level. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * + * @return 0: input low; 1: input high. + */ +static inline uint32_t rtcio_ll_get_level(int rtcio_num) +{ + return (uint32_t)(HAL_FORCE_READ_U32_REG_FIELD(LP_GPIO.in, reg_gpio_in_data_next) >> rtcio_num) & 0x1; +} + +/** + * @brief Set RTC GPIO pad drive capability + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param strength Drive capability of the pad. Range: 0 ~ 3. + */ +static inline void rtcio_ll_set_drive_capability(int rtcio_num, uint32_t strength) +{ + LP_IOMUX.pad[rtcio_num].drv = strength; +} + +/** + * @brief Get RTC GPIO pad drive capability. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * + * @return Drive capability of the pad. Range: 0 ~ 3. + */ +static inline uint32_t rtcio_ll_get_drive_capability(int rtcio_num) +{ + return LP_IOMUX.pad[rtcio_num].drv; +} + +/** + * @brief Set RTC GPIO pad output mode. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * + * @return mode Output mode. + */ +static inline void rtcio_ll_output_mode_set(int rtcio_num, rtcio_ll_out_mode_t mode) +{ + LP_GPIO.pin[rtcio_num].pad_driver = mode; +} + +/** + * @brief RTC GPIO pullup enable. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_pullup_enable(int rtcio_num) +{ + /* Enable internal weak pull-up */ + LP_IOMUX.pad[rtcio_num].rue = 1; +} + +/** + * @brief RTC GPIO pullup disable. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_pullup_disable(int rtcio_num) +{ + /* Disable internal weak pull-up */ + LP_IOMUX.pad[rtcio_num].rue = 0; +} + +/** + * @brief RTC GPIO pulldown enable. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_pulldown_enable(int rtcio_num) +{ + /* Enable internal weak pull-down */ + LP_IOMUX.pad[rtcio_num].rde = 1; +} + +/** + * @brief RTC GPIO pulldown disable. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_pulldown_disable(int rtcio_num) +{ + /* Enable internal weak pull-down */ + LP_IOMUX.pad[rtcio_num].rde = 0; +} + +/** + * @brief Enable force hold function for an RTC IO pad. + * + * Enabling HOLD function will cause the pad to lock current status, such as, + * input/output enable, input/output value, function, drive strength values. + * This function is useful when going into light or deep sleep mode to prevent + * the pin configuration from changing. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_force_hold_enable(int rtcio_num) +{ + uint32_t hold_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_IOMUX.lp_pad_hold, reg_lp_gpio_hold); + hold_mask |= BIT(rtcio_num); + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_IOMUX.lp_pad_hold, reg_lp_gpio_hold, hold_mask); +} + +/** + * @brief Disable hold function on an RTC IO pad + * + * @note If disable the pad hold, the status of pad maybe changed in sleep mode. + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_force_hold_disable(int rtcio_num) +{ + uint32_t hold_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_IOMUX.lp_pad_hold, reg_lp_gpio_hold); + hold_mask &= ~BIT(rtcio_num); + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_IOMUX.lp_pad_hold, reg_lp_gpio_hold, hold_mask); +} + +/** + * @brief Enable force hold function for all RTC IO pads + * + * Enabling HOLD function will cause the pad to lock current status, such as, + * input/output enable, input/output value, function, drive strength values. + * This function is useful when going into light or deep sleep mode to prevent + * the pin configuration from changing. + */ +static inline void rtcio_ll_force_hold_all(void) +{ + PMU.imm_pad_hold_all.tie_high_lp_pad_hold_all = 1; +} + +/** + * @brief Disable hold function fon all RTC IO pads + * + * @note If disable the pad hold, the status of pad maybe changed in sleep mode. + */ +static inline void rtcio_ll_force_unhold_all(void) +{ + PMU.imm_pad_hold_all.tie_low_lp_pad_hold_all = 1; +} + +/** + * @brief Enable wakeup function and set wakeup type from light sleep or deep sleep for RTCIO. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param type Wakeup on high level or low level. + */ +static inline void rtcio_ll_wakeup_enable(int rtcio_num, rtcio_ll_wake_type_t type) +{ + LP_GPIO.pin[rtcio_num].wakeup_enable = 1; + LP_GPIO.pin[rtcio_num].int_type = type; +} + +/** + * @brief Disable wakeup function from light sleep or deep sleep for RTCIO. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_wakeup_disable(int rtcio_num) +{ + LP_GPIO.pin[rtcio_num].wakeup_enable = 0; + LP_GPIO.pin[rtcio_num].int_type = RTCIO_LL_WAKEUP_DISABLE; +} + +/** + * @brief Enable RTCIO output in deep sleep. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_enable_output_in_sleep(int rtcio_num) +{ + LP_IOMUX.pad[rtcio_num].slp_oe = 1; +} + +/** + * @brief Disable RTCIO output in deep sleep. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_disable_output_in_sleep(int rtcio_num) +{ + LP_IOMUX.pad[rtcio_num].slp_oe = 0; +} + +/** + * @brief Enable RTCIO input in deep sleep. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_enable_input_in_sleep(int rtcio_num) +{ + LP_IOMUX.pad[rtcio_num].slp_ie = 1; +} + +/** + * @brief Disable RTCIO input in deep sleep. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_disable_input_in_sleep(int rtcio_num) +{ + LP_IOMUX.pad[rtcio_num].slp_ie = 0; +} + +/** + * @brief Enable RTCIO keep another setting in deep sleep. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_enable_sleep_setting(int rtcio_num) +{ + LP_IOMUX.pad[rtcio_num].slp_sel = 1; +} + +/** + * @brief Disable RTCIO keep another setting in deep sleep. (Default) + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + */ +static inline void rtcio_ll_disable_sleep_setting(int rtcio_num) +{ + LP_IOMUX.pad[rtcio_num].slp_sel = 0; +} + +/** + * @brief Get the status of whether an IO is used for sleep wake-up. + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @return True if the pin is enabled to wake up from deep-sleep + */ +static inline bool rtcio_ll_wakeup_is_enabled(int rtcio_num) +{ + HAL_ASSERT(rtcio_num >= 0 && rtcio_num < SOC_RTCIO_PIN_COUNT && "io does not support deep sleep wake-up function"); + return LP_GPIO.pin[rtcio_num].wakeup_enable; +} + +/** + * @brief Get the LP IO interrupt status + * + * @return Bit 0~15 corresponding to 0 ~ SOC_RTCIO_PIN_COUNT. + */ +static inline uint32_t rtcio_ll_get_interrupt_status(void) +{ + return (uint32_t)HAL_FORCE_READ_U32_REG_FIELD(LP_GPIO.status, reg_gpio_status_data); +} + +/** + * @brief Clear all LP IO pads status + */ +static inline void rtcio_ll_clear_interrupt_status(void) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_GPIO.status_w1tc, reg_gpio_status_data_w1tc, 0xFFFF); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s2/include/hal/rtc_io_ll.h b/components/hal/esp32s2/include/hal/rtc_io_ll.h index 27a884a3326..ad05ea95dd7 100644 --- a/components/hal/esp32s2/include/hal/rtc_io_ll.h +++ b/components/hal/esp32s2/include/hal/rtc_io_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,9 +13,10 @@ #pragma once #include +#include "soc/rtc_io_struct.h" +#include "soc/rtc_io_reg.h" #include "soc/rtc_periph.h" #include "soc/sens_struct.h" -#include "hal/gpio_types.h" #define RTCIO_LL_PIN_FUNC 0 @@ -24,19 +25,19 @@ extern "C" { #endif typedef enum { - RTCIO_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */ - RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ + RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */ + RTCIO_LL_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ } rtcio_ll_func_t; typedef enum { - RTCIO_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ - RTCIO_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ - RTCIO_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ + RTCIO_LL_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ + RTCIO_LL_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ + RTCIO_LL_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ } rtcio_ll_wake_type_t; typedef enum { - RTCIO_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ - RTCIO_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ + RTCIO_LL_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ + RTCIO_LL_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ } rtcio_ll_out_mode_t; /** @@ -59,13 +60,13 @@ static inline void rtcio_ll_iomux_func_sel(int rtcio_num, int func) */ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) { - if (func == RTCIO_FUNC_RTC) { + if (func == RTCIO_LL_FUNC_RTC) { SENS.sar_io_mux_conf.iomux_clk_gate_en = 1; // 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module. SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux)); //0:RTC FUNCTION 1,2,3:Reserved rtcio_ll_iomux_func_sel(rtcio_num, RTCIO_LL_PIN_FUNC); - } else if (func == RTCIO_FUNC_DIGITAL) { + } else if (func == RTCIO_LL_FUNC_DIGITAL) { CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux)); SENS.sar_io_mux_conf.iomux_clk_gate_en = 0; } @@ -294,7 +295,7 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) { SENS.sar_io_mux_conf.iomux_clk_gate_en = 0; RTCIO.pin[rtcio_num].wakeup_enable = 0; - RTCIO.pin[rtcio_num].int_type = RTCIO_WAKEUP_DISABLE; + RTCIO.pin[rtcio_num].int_type = RTCIO_LL_WAKEUP_DISABLE; } /** @@ -302,10 +303,10 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_output_in_sleep(int rtcio_num) { - if (rtc_io_desc[gpio_num].slpoe) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe); + if (rtc_io_desc[rtcio_num].slpoe) { + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpoe); } } @@ -314,10 +315,10 @@ static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_output_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_output_in_sleep(int rtcio_num) { - if (rtc_io_desc[gpio_num].slpoe) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe); + if (rtc_io_desc[rtcio_num].slpoe) { + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpoe); } } @@ -326,9 +327,9 @@ static inline void rtcio_ll_disable_output_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_input_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_input_in_sleep(int rtcio_num) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie); + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpie); } /** @@ -336,9 +337,9 @@ static inline void rtcio_ll_enable_input_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_input_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_input_in_sleep(int rtcio_num) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie); + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpie); } /** @@ -346,9 +347,9 @@ static inline void rtcio_ll_disable_input_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_sleep_setting(int rtcio_num) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel); + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpsel); } /** @@ -356,9 +357,9 @@ static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_sleep_setting(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_sleep_setting(int rtcio_num) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel); + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpsel); } /** diff --git a/components/hal/esp32s3/include/hal/rtc_io_ll.h b/components/hal/esp32s3/include/hal/rtc_io_ll.h index 9d1aa0aee6e..323e126c11b 100644 --- a/components/hal/esp32s3/include/hal/rtc_io_ll.h +++ b/components/hal/esp32s3/include/hal/rtc_io_ll.h @@ -13,8 +13,9 @@ #pragma once #include +#include "soc/rtc_io_struct.h" +#include "soc/rtc_io_reg.h" #include "soc/rtc_periph.h" -#include "hal/gpio_types.h" #include "soc/io_mux_reg.h" #include "soc/usb_serial_jtag_reg.h" #include "soc/usb_serial_jtag_struct.h" @@ -26,19 +27,19 @@ extern "C" { #define RTCIO_LL_PIN_FUNC 0 typedef enum { - RTCIO_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */ - RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ + RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */ + RTCIO_LL_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ } rtcio_ll_func_t; typedef enum { - RTCIO_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ - RTCIO_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ - RTCIO_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ + RTCIO_LL_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */ + RTCIO_LL_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */ + RTCIO_LL_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ } rtcio_ll_wake_type_t; typedef enum { - RTCIO_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ - RTCIO_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ + RTCIO_LL_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ + RTCIO_LL_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ } rtcio_ll_out_mode_t; /** @@ -61,7 +62,7 @@ static inline void rtcio_ll_iomux_func_sel(int rtcio_num, int func) */ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) { - if (func == RTCIO_FUNC_RTC) { + if (func == RTCIO_LL_FUNC_RTC) { // Disable USB Serial JTAG if pin 19 or pin 20 needs to select the rtc function if (rtcio_num == rtc_io_num_map[USB_INT_PHY0_DM_GPIO_NUM] || rtcio_num == rtc_io_num_map[USB_INT_PHY0_DP_GPIO_NUM]) { USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; @@ -71,7 +72,7 @@ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux)); //0:RTC FUNCTION 1,2,3:Reserved rtcio_ll_iomux_func_sel(rtcio_num, RTCIO_LL_PIN_FUNC); - } else if (func == RTCIO_FUNC_DIGITAL) { + } else if (func == RTCIO_LL_FUNC_DIGITAL) { CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux)); SENS.sar_peri_clk_gate_conf.iomux_clk_en = 0; // USB Serial JTAG pad re-enable won't be done here (it requires both DM and DP pins not in rtc function) @@ -309,7 +310,7 @@ static inline void rtcio_ll_wakeup_enable(int rtcio_num, rtcio_ll_wake_type_t ty static inline void rtcio_ll_wakeup_disable(int rtcio_num) { RTCIO.pin[rtcio_num].wakeup_enable = 0; - RTCIO.pin[rtcio_num].int_type = RTCIO_WAKEUP_DISABLE; + RTCIO.pin[rtcio_num].int_type = RTCIO_LL_WAKEUP_DISABLE; } /** @@ -317,10 +318,10 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_output_in_sleep(int rtcio_num) { - if (rtc_io_desc[gpio_num].slpoe) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe); + if (rtc_io_desc[rtcio_num].slpoe) { + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpoe); } } @@ -329,10 +330,10 @@ static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_output_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_output_in_sleep(int rtcio_num) { - if (rtc_io_desc[gpio_num].slpoe) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe); + if (rtc_io_desc[rtcio_num].slpoe) { + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpoe); } } @@ -341,9 +342,9 @@ static inline void rtcio_ll_disable_output_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_input_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_input_in_sleep(int rtcio_num) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie); + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpie); } /** @@ -351,9 +352,9 @@ static inline void rtcio_ll_enable_input_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_input_in_sleep(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_input_in_sleep(int rtcio_num) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie); + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpie); } /** @@ -361,9 +362,9 @@ static inline void rtcio_ll_disable_input_in_sleep(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num) +static inline void rtcio_ll_enable_sleep_setting(int rtcio_num) { - SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel); + SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpsel); } /** @@ -371,9 +372,9 @@ static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num) * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ -static inline void rtcio_ll_disable_sleep_setting(gpio_num_t gpio_num) +static inline void rtcio_ll_disable_sleep_setting(int rtcio_num) { - CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel); + CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].slpsel); } /** diff --git a/components/hal/include/hal/rtc_io_hal.h b/components/hal/include/hal/rtc_io_hal.h index 6f186e520cf..2e6d50ca81a 100644 --- a/components/hal/include/hal/rtc_io_hal.h +++ b/components/hal/include/hal/rtc_io_hal.h @@ -19,6 +19,7 @@ #include "soc/soc_caps.h" #if SOC_RTCIO_PIN_COUNT > 0 +#include "soc/rtc_io_periph.h" #include "hal/rtc_io_ll.h" #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED #include "hal/rtc_io_types.h" @@ -130,8 +131,8 @@ void rtcio_hal_set_direction(int rtcio_num, rtc_gpio_mode_t mode); /** * Set RTC IO direction in deep sleep or disable sleep status. * - * NOTE: ESP32 support INPUT_ONLY mode. - * ESP32S2 support INPUT_ONLY, OUTPUT_ONLY, INPUT_OUTPUT mode. + * NOTE: ESP32 supports INPUT_ONLY mode. + * The rest targets support INPUT_ONLY, OUTPUT_ONLY, INPUT_OUTPUT mode. * * @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT. * @param mode IO direction. @@ -174,6 +175,27 @@ void rtcio_hal_set_direction_in_sleep(int rtcio_num, rtc_gpio_mode_t mode); */ #define rtcio_hal_iomux_func_sel(rtcio_num, func) rtcio_ll_iomux_func_sel(rtcio_num, func) +#if SOC_LP_GPIO_MATRIX_SUPPORTED +/** + * Select RTC GPIO input to a signal + * + * @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT. + * @param signal_idx LP peripheral signal index. + * @param inv inv True to invert input signal; False then no invert. + */ +#define rtcio_hal_matrix_in(rtcio_num, signal_idx, inv) rtcio_ll_matrix_in(rtcio_num, signal_idx, inv) + +/** + * Select signal output to a RTC GPIO + * + * @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT. + * @param signal_idx LP peripheral signal index. + * @param out_inv True to invert output signal; False then no invert. + * @param oen_inv True to invert output enable signal; False then no invert. + */ +#define rtcio_hal_matrix_out(rtcio_num, signal_idx, out_inv, oen_inv) rtcio_ll_matrix_out(rtcio_num, signal_idx, out_inv, oen_inv) +#endif // SOC_LP_GPIO_MATRIX_SUPPORTED + #endif // SOC_RTCIO_INPUT_OUTPUT_SUPPORTED #if SOC_RTCIO_HOLD_SUPPORTED @@ -269,9 +291,9 @@ void rtcio_hal_isolate(int rtc_num); #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP && (SOC_RTCIO_PIN_COUNT > 0) -#define gpio_hal_deepsleep_wakeup_enable(hal, gpio_num, intr_type) rtcio_hal_wakeup_enable(gpio_num, intr_type) -#define gpio_hal_deepsleep_wakeup_disable(hal, gpio_num) rtcio_hal_wakeup_disable(gpio_num) -#define gpio_hal_deepsleep_wakeup_is_enabled(hal, gpio_num) rtcio_hal_wakeup_is_enabled(gpio_num) +#define gpio_hal_deepsleep_wakeup_enable(hal, gpio_num, intr_type) rtcio_hal_wakeup_enable(rtc_io_num_map[gpio_num], intr_type) +#define gpio_hal_deepsleep_wakeup_disable(hal, gpio_num) rtcio_hal_wakeup_disable(rtc_io_num_map[gpio_num]) +#define gpio_hal_deepsleep_wakeup_is_enabled(hal, gpio_num) rtcio_hal_wakeup_is_enabled(rtc_io_num_map[gpio_num]) #define rtc_hal_gpio_get_wakeup_status() rtcio_hal_get_interrupt_status() #define rtc_hal_gpio_clear_wakeup_status() rtcio_hal_clear_interrupt_status() @@ -279,7 +301,7 @@ void rtcio_hal_isolate(int rtc_num); * @brief Get the status of whether an IO is used for sleep wake-up. * * @param hw Peripheral GPIO hardware instance address. - * @param rtcio_num GPIO number + * @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT. * @return True if the pin is enabled to wake up from deep-sleep */ #define rtcio_hal_wakeup_is_enabled(rtcio_num) rtcio_ll_wakeup_is_enabled(rtcio_num) diff --git a/components/hal/rtc_io_hal.c b/components/hal/rtc_io_hal.c index 586a3c8f51a..ce88795642d 100644 --- a/components/hal/rtc_io_hal.c +++ b/components/hal/rtc_io_hal.c @@ -15,32 +15,32 @@ void rtcio_hal_set_direction(int rtcio_num, rtc_gpio_mode_t mode) { switch (mode) { case RTC_GPIO_MODE_INPUT_ONLY: - rtcio_ll_output_mode_set(rtcio_num, RTCIO_OUTPUT_NORMAL); + rtcio_ll_output_mode_set(rtcio_num, RTCIO_LL_OUTPUT_NORMAL); rtcio_ll_output_disable(rtcio_num); rtcio_ll_input_enable(rtcio_num); break; case RTC_GPIO_MODE_OUTPUT_ONLY: - rtcio_ll_output_mode_set(rtcio_num, RTCIO_OUTPUT_NORMAL); + rtcio_ll_output_mode_set(rtcio_num, RTCIO_LL_OUTPUT_NORMAL); rtcio_ll_output_enable(rtcio_num); rtcio_ll_input_disable(rtcio_num); break; case RTC_GPIO_MODE_INPUT_OUTPUT: - rtcio_ll_output_mode_set(rtcio_num, RTCIO_OUTPUT_NORMAL); + rtcio_ll_output_mode_set(rtcio_num, RTCIO_LL_OUTPUT_NORMAL); rtcio_ll_output_enable(rtcio_num); rtcio_ll_input_enable(rtcio_num); break; case RTC_GPIO_MODE_DISABLED: - rtcio_ll_output_mode_set(rtcio_num, RTCIO_OUTPUT_NORMAL); + rtcio_ll_output_mode_set(rtcio_num, RTCIO_LL_OUTPUT_NORMAL); rtcio_ll_output_disable(rtcio_num); rtcio_ll_input_disable(rtcio_num); break; case RTC_GPIO_MODE_OUTPUT_OD: - rtcio_ll_output_mode_set(rtcio_num, RTCIO_OUTPUT_OD); + rtcio_ll_output_mode_set(rtcio_num, RTCIO_LL_OUTPUT_OD); rtcio_ll_output_enable(rtcio_num); rtcio_ll_input_disable(rtcio_num); break; case RTC_GPIO_MODE_INPUT_OUTPUT_OD: - rtcio_ll_output_mode_set(rtcio_num, RTCIO_OUTPUT_OD); + rtcio_ll_output_mode_set(rtcio_num, RTCIO_LL_OUTPUT_OD); rtcio_ll_output_enable(rtcio_num); rtcio_ll_input_enable(rtcio_num); break; diff --git a/components/soc/esp32/rtc_io_periph.c b/components/soc/esp32/rtc_io_periph.c index 133fb738f27..899dabda751 100644 --- a/components/soc/esp32/rtc_io_periph.c +++ b/components/soc/esp32/rtc_io_periph.c @@ -5,6 +5,7 @@ */ #include "soc/rtc_periph.h" +#include "soc/rtc_io_reg.h" const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { RTCIO_GPIO0_CHANNEL, //GPIO0 diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index f31edf192f3..5f5e72c2245 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -91,6 +91,14 @@ config SOC_FLASH_ENC_SUPPORTED bool default y +config SOC_LP_GPIO_MATRIX_SUPPORTED + bool + default y + +config SOC_LP_PERIPHERALS_SUPPORTED + bool + default y + config SOC_SPIRAM_SUPPORTED bool default y @@ -315,6 +323,10 @@ config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y +config SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP + bool + default y + config SOC_GPIO_VALID_GPIO_MASK hex default 0x01FFFFFFFFFFFFFF @@ -335,6 +347,22 @@ config SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP bool default y +config SOC_RTCIO_PIN_COUNT + int + default 16 + +config SOC_RTCIO_INPUT_OUTPUT_SUPPORTED + bool + default y + +config SOC_RTCIO_HOLD_SUPPORTED + bool + default y + +config SOC_RTCIO_WAKE_SUPPORTED + bool + default y + config SOC_DEDIC_GPIO_OUT_CHANNELS_NUM int default 8 diff --git a/components/soc/esp32p4/include/soc/lp_gpio_pins.h b/components/soc/esp32p4/include/soc/lp_gpio_pins.h new file mode 100644 index 00000000000..3c9d05556d0 --- /dev/null +++ b/components/soc/esp32p4/include/soc/lp_gpio_pins.h @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// `LP_GPIO_MATRIX_CONST_ONE_INPUT` means connect logic 1 to the LP peripheral signal +#define LP_GPIO_MATRIX_CONST_ONE_INPUT (0x30) +// `LP_GPIO_MATRIX_CONST_ZERO_INPUT` means connect logic 0 to the LP peripheral signal +#define LP_GPIO_MATRIX_CONST_ZERO_INPUT (0x20) + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32p4/include/soc/lp_gpio_sig_map.h b/components/soc/esp32p4/include/soc/lp_gpio_sig_map.h index d9649fa9a29..98001a91fa0 100644 --- a/components/soc/esp32p4/include/soc/lp_gpio_sig_map.h +++ b/components/soc/esp32p4/include/soc/lp_gpio_sig_map.h @@ -50,4 +50,7 @@ #define LP_PROBE_TOP_OUT14_IDX 28 #define LP_PROBE_TOP_OUT15_IDX 29 #define PROBE_CHAIN_CLK_PAD_OUT_IDX 30 + +#define SIG_LP_GPIO_OUT_IDX 32 + #define LP_GPIO_MAP_DATE_IDX 0x230323 diff --git a/components/soc/esp32p4/include/soc/lp_gpio_struct.h b/components/soc/esp32p4/include/soc/lp_gpio_struct.h index 507cf47a8fb..6323bdceffa 100644 --- a/components/soc/esp32p4/include/soc/lp_gpio_struct.h +++ b/components/soc/esp32p4/include/soc/lp_gpio_struct.h @@ -216,1237 +216,85 @@ typedef union { } lp_gpio_in_reg_t; -/** Group: pin0 */ -/** Type of pin0 register +/** Group: pin */ +/** Type of pin register * Reserved */ typedef union { struct { - /** reg_gpio_pin0_wakeup_enable : R/W; bitpos: [0]; default: 0; + /** wakeup_enable : R/W; bitpos: [0]; default: 0; * Reserved */ - uint32_t reg_gpio_pin0_wakeup_enable:1; - /** reg_gpio_pin0_int_type : R/W; bitpos: [3:1]; default: 0; + uint32_t wakeup_enable:1; + /** int_type : R/W; bitpos: [3:1]; default: 0; * Reserved */ - uint32_t reg_gpio_pin0_int_type:3; - /** reg_gpio_pin0_pad_driver : R/W; bitpos: [4]; default: 0; + uint32_t int_type:3; + /** pad_driver : R/W; bitpos: [4]; default: 0; * Reserved */ - uint32_t reg_gpio_pin0_pad_driver:1; - /** reg_gpio_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; + uint32_t pad_driver:1; + /** edge_wakeup_clr : WT; bitpos: [5]; default: 0; * need des */ - uint32_t reg_gpio_pin0_edge_wakeup_clr:1; + uint32_t edge_wakeup_clr:1; uint32_t reserved_6:26; }; uint32_t val; -} lp_gpio_pin0_reg_t; +} lp_gpio_pin_reg_t; -/** Group: pin1 */ -/** Type of pin1 register +/** Group: func_in_sel_cfg */ +/** Type of func_in_sel_cfg register * Reserved */ typedef union { struct { - /** reg_gpio_pin1_wakeup_enable : R/W; bitpos: [0]; default: 0; + /** in_inv_sel : R/W; bitpos: [0]; default: 0; * Reserved */ - uint32_t reg_gpio_pin1_wakeup_enable:1; - /** reg_gpio_pin1_int_type : R/W; bitpos: [3:1]; default: 0; + uint32_t in_inv_sel:1; + /** sig_in_sel : R/W; bitpos: [1]; default: 0; * Reserved */ - uint32_t reg_gpio_pin1_int_type:3; - /** reg_gpio_pin1_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin1_pad_driver:1; - /** reg_gpi1_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi1_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin1_reg_t; - - -/** Group: pin2 */ -/** Type of pin2 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin2_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin2_wakeup_enable:1; - /** reg_gpio_pin2_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin2_int_type:3; - /** reg_gpio_pin2_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin2_pad_driver:1; - /** reg_gpi2_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi2_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin2_reg_t; - - -/** Group: pin3 */ -/** Type of pin3 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin3_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin3_wakeup_enable:1; - /** reg_gpio_pin3_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin3_int_type:3; - /** reg_gpio_pin3_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin3_pad_driver:1; - /** reg_gpi3_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi3_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin3_reg_t; - - -/** Group: pin4 */ -/** Type of pin4 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin4_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin4_wakeup_enable:1; - /** reg_gpio_pin4_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin4_int_type:3; - /** reg_gpio_pin4_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin4_pad_driver:1; - /** reg_gpi4_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi4_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin4_reg_t; - - -/** Group: pin5 */ -/** Type of pin5 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin5_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin5_wakeup_enable:1; - /** reg_gpio_pin5_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin5_int_type:3; - /** reg_gpio_pin5_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin5_pad_driver:1; - /** reg_gpi5_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi5_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin5_reg_t; - - -/** Group: pin6 */ -/** Type of pin6 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin6_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin6_wakeup_enable:1; - /** reg_gpio_pin6_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin6_int_type:3; - /** reg_gpio_pin6_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin6_pad_driver:1; - /** reg_gpi6_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi6_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin6_reg_t; - - -/** Group: pin7 */ -/** Type of pin7 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin7_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin7_wakeup_enable:1; - /** reg_gpio_pin7_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin7_int_type:3; - /** reg_gpio_pin7_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin7_pad_driver:1; - /** reg_gpi7_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi7_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin7_reg_t; - - -/** Group: pin8 */ -/** Type of pin8 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin8_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin8_wakeup_enable:1; - /** reg_gpio_pin8_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin8_int_type:3; - /** reg_gpio_pin8_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin8_pad_driver:1; - /** reg_gpi8_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi8_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin8_reg_t; - - -/** Group: pin9 */ -/** Type of pin9 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin9_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin9_wakeup_enable:1; - /** reg_gpio_pin9_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin9_int_type:3; - /** reg_gpio_pin9_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin9_pad_driver:1; - /** reg_gpi9_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi9_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin9_reg_t; - - -/** Group: pin10 */ -/** Type of pin10 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin10_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin10_wakeup_enable:1; - /** reg_gpio_pin10_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin10_int_type:3; - /** reg_gpio_pin10_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin10_pad_driver:1; - /** reg_gpi10_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi10_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin10_reg_t; - - -/** Group: pin11 */ -/** Type of pin11 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin11_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin11_wakeup_enable:1; - /** reg_gpio_pin11_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin11_int_type:3; - /** reg_gpio_pin11_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin11_pad_driver:1; - /** reg_gpi11_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi11_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin11_reg_t; - - -/** Group: pin12 */ -/** Type of pin12 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin12_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin12_wakeup_enable:1; - /** reg_gpio_pin12_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin12_int_type:3; - /** reg_gpio_pin12_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin12_pad_driver:1; - /** reg_gpi12_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi12_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin12_reg_t; - - -/** Group: pin13 */ -/** Type of pin13 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin13_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin13_wakeup_enable:1; - /** reg_gpio_pin13_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin13_int_type:3; - /** reg_gpio_pin13_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin13_pad_driver:1; - /** reg_gpi13_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi13_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin13_reg_t; - - -/** Group: pin14 */ -/** Type of pin14 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin14_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin14_wakeup_enable:1; - /** reg_gpio_pin14_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin14_int_type:3; - /** reg_gpio_pin14_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin14_pad_driver:1; - /** reg_gpi14_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi14_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin14_reg_t; - - -/** Group: pin15 */ -/** Type of pin15 register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_pin15_wakeup_enable : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin15_wakeup_enable:1; - /** reg_gpio_pin15_int_type : R/W; bitpos: [3:1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin15_int_type:3; - /** reg_gpio_pin15_pad_driver : R/W; bitpos: [4]; default: 0; - * Reserved - */ - uint32_t reg_gpio_pin15_pad_driver:1; - /** reg_gpi15_pin0_edge_wakeup_clr : WT; bitpos: [5]; default: 0; - * need des - */ - uint32_t reg_gpi15_pin0_edge_wakeup_clr:1; - uint32_t reserved_6:26; - }; - uint32_t val; -} lp_gpio_pin15_reg_t; - - -/** Group: func0_in_sel_cfg */ -/** Type of func0_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func0_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func0_in_inv_sel:1; - /** reg_gpio_sig0_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig0_in_sel:1; - /** reg_gpio_func0_in_sel : R/W; bitpos: [7:2]; default: 48; - * reg_gpio_func0_in_sel[5:4]==2'b11->constant - * 1,reg_gpio_func0_in_sel[5:4]==2'b10->constant 0 - */ - uint32_t reg_gpio_func0_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func0_in_sel_cfg_reg_t; - - -/** Group: func1_in_sel_cfg */ -/** Type of func1_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func1_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func1_in_inv_sel:1; - /** reg_gpio_sig1_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig1_in_sel:1; - /** reg_gpio_func1_in_sel : R/W; bitpos: [7:2]; default: 48; - * Reserved - */ - uint32_t reg_gpio_func1_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func1_in_sel_cfg_reg_t; - - -/** Group: func2_in_sel_cfg */ -/** Type of func2_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func2_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func2_in_inv_sel:1; - /** reg_gpio_sig2_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig2_in_sel:1; - /** reg_gpio_func2_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func2_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func2_in_sel_cfg_reg_t; - - -/** Group: func3_in_sel_cfg */ -/** Type of func3_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func3_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func3_in_inv_sel:1; - /** reg_gpio_sig3_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig3_in_sel:1; - /** reg_gpio_func3_in_sel : R/W; bitpos: [7:2]; default: 48; - * Reserved - */ - uint32_t reg_gpio_func3_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func3_in_sel_cfg_reg_t; - - -/** Group: func4_in_sel_cfg */ -/** Type of func4_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func4_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func4_in_inv_sel:1; - /** reg_gpio_sig4_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig4_in_sel:1; - /** reg_gpio_func4_in_sel : R/W; bitpos: [7:2]; default: 48; - * Reserved - */ - uint32_t reg_gpio_func4_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func4_in_sel_cfg_reg_t; - - -/** Group: func5_in_sel_cfg */ -/** Type of func5_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func5_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func5_in_inv_sel:1; - /** reg_gpio_sig5_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig5_in_sel:1; - /** reg_gpio_func5_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func5_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func5_in_sel_cfg_reg_t; - - -/** Group: func6_in_sel_cfg */ -/** Type of func6_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func6_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func6_in_inv_sel:1; - /** reg_gpio_sig6_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig6_in_sel:1; - /** reg_gpio_func6_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func6_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func6_in_sel_cfg_reg_t; - - -/** Group: func7_in_sel_cfg */ -/** Type of func7_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func7_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func7_in_inv_sel:1; - /** reg_gpio_sig7_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig7_in_sel:1; - /** reg_gpio_func7_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func7_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func7_in_sel_cfg_reg_t; - - -/** Group: func8_in_sel_cfg */ -/** Type of func8_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func8_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func8_in_inv_sel:1; - /** reg_gpio_sig8_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig8_in_sel:1; - /** reg_gpio_func8_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func8_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func8_in_sel_cfg_reg_t; - - -/** Group: func9_in_sel_cfg */ -/** Type of func9_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func9_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func9_in_inv_sel:1; - /** reg_gpio_sig9_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig9_in_sel:1; - /** reg_gpio_func9_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func9_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func9_in_sel_cfg_reg_t; - - -/** Group: func10_in_sel_cfg */ -/** Type of func10_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func10_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func10_in_inv_sel:1; - /** reg_gpio_sig10_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig10_in_sel:1; - /** reg_gpio_func10_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func10_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func10_in_sel_cfg_reg_t; - - -/** Group: func11_in_sel_cfg */ -/** Type of func11_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func11_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func11_in_inv_sel:1; - /** reg_gpio_sig11_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig11_in_sel:1; - /** reg_gpio_func11_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func11_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func11_in_sel_cfg_reg_t; - - -/** Group: func12_in_sel_cfg */ -/** Type of func12_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func12_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func12_in_inv_sel:1; - /** reg_gpio_sig12_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig12_in_sel:1; - /** reg_gpio_func12_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func12_in_sel:6; - uint32_t reserved_8:24; - }; - uint32_t val; -} lp_gpio_func12_in_sel_cfg_reg_t; - - -/** Group: func13_in_sel_cfg */ -/** Type of func13_in_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func13_in_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func13_in_inv_sel:1; - /** reg_gpio_sig13_in_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_sig13_in_sel:1; - /** reg_gpio_func13_in_sel : R/W; bitpos: [7:2]; default: 32; - * Reserved + uint32_t sig_in_sel:1; + /** func_in_sel : R/W; bitpos: [7:2]; default: 48 (for func0/1/3/4) 32 (for the rest); + * func_in_sel[5:4]==2'b11 (s=0x30) -> constant 1 + * func_in_sel[5:4]==2'b10 (s=0x20) -> constant 0 */ - uint32_t reg_gpio_func13_in_sel:6; + uint32_t func_in_sel:6; uint32_t reserved_8:24; }; uint32_t val; -} lp_gpio_func13_in_sel_cfg_reg_t; +} lp_gpio_func_in_sel_cfg_reg_t; -/** Group: func0_out_sel_cfg */ +/** Group: func_out_sel_cfg */ /** Type of func0_out_sel_cfg register * Reserved */ typedef union { struct { - /** reg_gpio_func0_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func0_oe_inv_sel:1; - /** reg_gpio_func0_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func0_oe_sel:1; - /** reg_gpio_func0_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func0_out_inv_sel:1; - /** reg_gpio_func0_out_sel : R/W; bitpos: [8:3]; default: 32; - * reg_gpio_func0_out_sel[5:1]==16 -> output gpio register value to pad - */ - uint32_t reg_gpio_func0_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func0_out_sel_cfg_reg_t; - - -/** Group: func1_out_sel_cfg */ -/** Type of func1_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func1_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func1_oe_inv_sel:1; - /** reg_gpio_func1_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func1_oe_sel:1; - /** reg_gpio_func1_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func1_out_inv_sel:1; - /** reg_gpio_func1_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func1_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func1_out_sel_cfg_reg_t; - - -/** Group: func2_out_sel_cfg */ -/** Type of func2_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func2_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func2_oe_inv_sel:1; - /** reg_gpio_func2_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func2_oe_sel:1; - /** reg_gpio_func2_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func2_out_inv_sel:1; - /** reg_gpio_func2_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func2_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func2_out_sel_cfg_reg_t; - - -/** Group: func3_out_sel_cfg */ -/** Type of func3_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func3_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func3_oe_inv_sel:1; - /** reg_gpio_func3_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func3_oe_sel:1; - /** reg_gpio_func3_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func3_out_inv_sel:1; - /** reg_gpio_func3_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func3_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func3_out_sel_cfg_reg_t; - - -/** Group: func4_out_sel_cfg */ -/** Type of func4_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func4_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func4_oe_inv_sel:1; - /** reg_gpio_func4_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func4_oe_sel:1; - /** reg_gpio_func4_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func4_out_inv_sel:1; - /** reg_gpio_func4_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func4_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func4_out_sel_cfg_reg_t; - - -/** Group: func5_out_sel_cfg */ -/** Type of func5_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func5_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func5_oe_inv_sel:1; - /** reg_gpio_func5_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func5_oe_sel:1; - /** reg_gpio_func5_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func5_out_inv_sel:1; - /** reg_gpio_func5_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func5_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func5_out_sel_cfg_reg_t; - - -/** Group: func6_out_sel_cfg */ -/** Type of func6_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func6_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func6_oe_inv_sel:1; - /** reg_gpio_func6_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func6_oe_sel:1; - /** reg_gpio_func6_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func6_out_inv_sel:1; - /** reg_gpio_func6_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func6_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func6_out_sel_cfg_reg_t; - - -/** Group: func7_out_sel_cfg */ -/** Type of func7_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func7_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func7_oe_inv_sel:1; - /** reg_gpio_func7_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func7_oe_sel:1; - /** reg_gpio_func7_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func7_out_inv_sel:1; - /** reg_gpio_func7_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func7_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func7_out_sel_cfg_reg_t; - - -/** Group: func8_out_sel_cfg */ -/** Type of func8_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func8_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func8_oe_inv_sel:1; - /** reg_gpio_func8_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func8_oe_sel:1; - /** reg_gpio_func8_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func8_out_inv_sel:1; - /** reg_gpio_func8_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func8_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func8_out_sel_cfg_reg_t; - - -/** Group: func9_out_sel_cfg */ -/** Type of func9_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func9_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func9_oe_inv_sel:1; - /** reg_gpio_func9_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func9_oe_sel:1; - /** reg_gpio_func9_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func9_out_inv_sel:1; - /** reg_gpio_func9_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func9_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func9_out_sel_cfg_reg_t; - - -/** Group: func10_out_sel_cfg */ -/** Type of func10_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func10_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func10_oe_inv_sel:1; - /** reg_gpio_func10_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func10_oe_sel:1; - /** reg_gpio_func10_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func10_out_inv_sel:1; - /** reg_gpio_func10_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func10_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func10_out_sel_cfg_reg_t; - - -/** Group: func11_out_sel_cfg */ -/** Type of func11_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func11_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func11_oe_inv_sel:1; - /** reg_gpio_func11_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func11_oe_sel:1; - /** reg_gpio_func11_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func11_out_inv_sel:1; - /** reg_gpio_func11_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func11_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func11_out_sel_cfg_reg_t; - - -/** Group: func12_out_sel_cfg */ -/** Type of func12_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func12_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func12_oe_inv_sel:1; - /** reg_gpio_func12_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func12_oe_sel:1; - /** reg_gpio_func12_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func12_out_inv_sel:1; - /** reg_gpio_func12_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func12_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func12_out_sel_cfg_reg_t; - - -/** Group: func13_out_sel_cfg */ -/** Type of func13_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func13_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func13_oe_inv_sel:1; - /** reg_gpio_func13_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func13_oe_sel:1; - /** reg_gpio_func13_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func13_out_inv_sel:1; - /** reg_gpio_func13_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func13_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func13_out_sel_cfg_reg_t; - - -/** Group: func14_out_sel_cfg */ -/** Type of func14_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func14_oe_inv_sel : R/W; bitpos: [0]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func14_oe_inv_sel:1; - /** reg_gpio_func14_oe_sel : R/W; bitpos: [1]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func14_oe_sel:1; - /** reg_gpio_func14_out_inv_sel : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_gpio_func14_out_inv_sel:1; - /** reg_gpio_func14_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved - */ - uint32_t reg_gpio_func14_out_sel:6; - uint32_t reserved_9:23; - }; - uint32_t val; -} lp_gpio_func14_out_sel_cfg_reg_t; - - -/** Group: func15_out_sel_cfg */ -/** Type of func15_out_sel_cfg register - * Reserved - */ -typedef union { - struct { - /** reg_gpio_func15_oe_inv_sel : R/W; bitpos: [0]; default: 0; + /** oe_inv_sel : R/W; bitpos: [0]; default: 0; * Reserved */ - uint32_t reg_gpio_func15_oe_inv_sel:1; - /** reg_gpio_func15_oe_sel : R/W; bitpos: [1]; default: 0; + uint32_t oe_inv_sel:1; + /** oe_sel : R/W; bitpos: [1]; default: 0; * Reserved */ - uint32_t reg_gpio_func15_oe_sel:1; - /** reg_gpio_func15_out_inv_sel : R/W; bitpos: [2]; default: 0; + uint32_t oe_sel:1; + /** out_inv_sel : R/W; bitpos: [2]; default: 0; * Reserved */ - uint32_t reg_gpio_func15_out_inv_sel:1; - /** reg_gpio_func15_out_sel : R/W; bitpos: [8:3]; default: 32; - * Reserved + uint32_t out_inv_sel:1; + /** func_out_sel : R/W; bitpos: [8:3]; default: 32; + * func_out_sel[5:1]==16 (s=32) -> output gpio register value to pad */ - uint32_t reg_gpio_func15_out_sel:6; + uint32_t func_out_sel:6; uint32_t reserved_9:23; }; uint32_t val; -} lp_gpio_func15_out_sel_cfg_reg_t; +} lp_gpio_func_out_sel_cfg_reg_t; typedef struct lp_gpio_dev_t { @@ -1463,53 +311,10 @@ typedef struct lp_gpio_dev_t { volatile lp_gpio_status_w1tc_reg_t status_w1tc; volatile lp_gpio_status_next_reg_t status_next; volatile lp_gpio_in_reg_t in; - volatile lp_gpio_pin0_reg_t pin0; - volatile lp_gpio_pin1_reg_t pin1; - volatile lp_gpio_pin2_reg_t pin2; - volatile lp_gpio_pin3_reg_t pin3; - volatile lp_gpio_pin4_reg_t pin4; - volatile lp_gpio_pin5_reg_t pin5; - volatile lp_gpio_pin6_reg_t pin6; - volatile lp_gpio_pin7_reg_t pin7; - volatile lp_gpio_pin8_reg_t pin8; - volatile lp_gpio_pin9_reg_t pin9; - volatile lp_gpio_pin10_reg_t pin10; - volatile lp_gpio_pin11_reg_t pin11; - volatile lp_gpio_pin12_reg_t pin12; - volatile lp_gpio_pin13_reg_t pin13; - volatile lp_gpio_pin14_reg_t pin14; - volatile lp_gpio_pin15_reg_t pin15; - volatile lp_gpio_func0_in_sel_cfg_reg_t func0_in_sel_cfg; - volatile lp_gpio_func1_in_sel_cfg_reg_t func1_in_sel_cfg; - volatile lp_gpio_func2_in_sel_cfg_reg_t func2_in_sel_cfg; - volatile lp_gpio_func3_in_sel_cfg_reg_t func3_in_sel_cfg; - volatile lp_gpio_func4_in_sel_cfg_reg_t func4_in_sel_cfg; - volatile lp_gpio_func5_in_sel_cfg_reg_t func5_in_sel_cfg; - volatile lp_gpio_func6_in_sel_cfg_reg_t func6_in_sel_cfg; - volatile lp_gpio_func7_in_sel_cfg_reg_t func7_in_sel_cfg; - volatile lp_gpio_func8_in_sel_cfg_reg_t func8_in_sel_cfg; - volatile lp_gpio_func9_in_sel_cfg_reg_t func9_in_sel_cfg; - volatile lp_gpio_func10_in_sel_cfg_reg_t func10_in_sel_cfg; - volatile lp_gpio_func11_in_sel_cfg_reg_t func11_in_sel_cfg; - volatile lp_gpio_func12_in_sel_cfg_reg_t func12_in_sel_cfg; - volatile lp_gpio_func13_in_sel_cfg_reg_t func13_in_sel_cfg; + volatile lp_gpio_pin_reg_t pin[16]; + volatile lp_gpio_func_in_sel_cfg_reg_t func_in_sel_cfg[14]; uint32_t reserved_0ac[18]; - volatile lp_gpio_func0_out_sel_cfg_reg_t func0_out_sel_cfg; - volatile lp_gpio_func1_out_sel_cfg_reg_t func1_out_sel_cfg; - volatile lp_gpio_func2_out_sel_cfg_reg_t func2_out_sel_cfg; - volatile lp_gpio_func3_out_sel_cfg_reg_t func3_out_sel_cfg; - volatile lp_gpio_func4_out_sel_cfg_reg_t func4_out_sel_cfg; - volatile lp_gpio_func5_out_sel_cfg_reg_t func5_out_sel_cfg; - volatile lp_gpio_func6_out_sel_cfg_reg_t func6_out_sel_cfg; - volatile lp_gpio_func7_out_sel_cfg_reg_t func7_out_sel_cfg; - volatile lp_gpio_func8_out_sel_cfg_reg_t func8_out_sel_cfg; - volatile lp_gpio_func9_out_sel_cfg_reg_t func9_out_sel_cfg; - volatile lp_gpio_func10_out_sel_cfg_reg_t func10_out_sel_cfg; - volatile lp_gpio_func11_out_sel_cfg_reg_t func11_out_sel_cfg; - volatile lp_gpio_func12_out_sel_cfg_reg_t func12_out_sel_cfg; - volatile lp_gpio_func13_out_sel_cfg_reg_t func13_out_sel_cfg; - volatile lp_gpio_func14_out_sel_cfg_reg_t func14_out_sel_cfg; - volatile lp_gpio_func15_out_sel_cfg_reg_t func15_out_sel_cfg; + volatile lp_gpio_func_out_sel_cfg_reg_t func_out_sel_cfg[16]; } lp_gpio_dev_t; extern lp_gpio_dev_t LP_GPIO; diff --git a/components/soc/esp32p4/include/soc/lp_iomux_struct.h b/components/soc/esp32p4/include/soc/lp_iomux_struct.h index 1a7e96dda43..d689b6c4293 100644 --- a/components/soc/esp32p4/include/soc/lp_iomux_struct.h +++ b/components/soc/esp32p4/include/soc/lp_iomux_struct.h @@ -42,836 +42,56 @@ typedef union { } lp_iomux_ver_date_reg_t; -/** Group: pad0 */ -/** Type of pad0 register +/** Group: pad */ +/** Type of pad register * Reserved */ typedef union { struct { - /** reg_pad0_drv : R/W; bitpos: [1:0]; default: 2; + /** drv : R/W; bitpos: [1:0]; default: 2; * Reserved */ - uint32_t reg_pad0_drv:2; - /** reg_pad0_rde : R/W; bitpos: [2]; default: 0; + uint32_t drv:2; + /** rde : R/W; bitpos: [2]; default: 0; * Reserved */ - uint32_t reg_pad0_rde:1; - /** reg_pad0_rue : R/W; bitpos: [3]; default: 0; + uint32_t rde:1; + /** rue : R/W; bitpos: [3]; default: 0; * Reserved */ - uint32_t reg_pad0_rue:1; - /** reg_pad0_mux_sel : R/W; bitpos: [4]; default: 0; + uint32_t rue:1; + /** mux_sel : R/W; bitpos: [4]; default: 0; * 1:use LP GPIO,0: use digital GPIO */ - uint32_t reg_pad0_mux_sel:1; - /** reg_pad0_fun_sel : R/W; bitpos: [6:5]; default: 0; + uint32_t mux_sel:1; + /** fun_sel : R/W; bitpos: [6:5]; default: 0; * function sel */ - uint32_t reg_pad0_fun_sel:2; - /** reg_pad0_slp_sel : R/W; bitpos: [7]; default: 0; + uint32_t fun_sel:2; + /** slp_sel : R/W; bitpos: [7]; default: 0; * 1: enable sleep mode during sleep,0: no sleep mode */ - uint32_t reg_pad0_slp_sel:1; - /** reg_pad0_slp_ie : R/W; bitpos: [8]; default: 0; + uint32_t slp_sel:1; + /** slp_ie : R/W; bitpos: [8]; default: 0; * input enable in sleep mode */ - uint32_t reg_pad0_slp_ie:1; - /** reg_pad0_slp_oe : R/W; bitpos: [9]; default: 0; + uint32_t slp_ie:1; + /** slp_oe : R/W; bitpos: [9]; default: 0; * output enable in sleep mode */ - uint32_t reg_pad0_slp_oe:1; - /** reg_pad0_fun_ie : R/W; bitpos: [10]; default: 0; + uint32_t slp_oe:1; + /** fun_ie : R/W; bitpos: [10]; default: 0; * input enable in work mode - */ - uint32_t reg_pad0_fun_ie:1; - /** reg_pad0_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad0_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad0_reg_t; - - -/** Group: pad1 */ -/** Type of pad1 register - * Reserved - */ -typedef union { - struct { - /** reg_pad1_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad1_drv:2; - /** reg_pad1_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad1_rde:1; - /** reg_pad1_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad1_rue:1; - /** reg_pad1_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad1_mux_sel:1; - /** reg_pad1_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad1_fun_sel:2; - /** reg_pad1_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad1_slp_sel:1; - /** reg_pad1_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad1_slp_ie:1; - /** reg_pad1_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad1_slp_oe:1; - /** reg_pad1_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad1_fun_ie:1; - /** reg_pad1_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad1_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad1_reg_t; - - -/** Group: pad2 */ -/** Type of pad2 register - * Reserved - */ -typedef union { - struct { - /** reg_pad2_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad2_drv:2; - /** reg_pad2_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad2_rde:1; - /** reg_pad2_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad2_rue:1; - /** reg_pad2_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad2_mux_sel:1; - /** reg_pad2_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad2_fun_sel:2; - /** reg_pad2_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad2_slp_sel:1; - /** reg_pad2_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad2_slp_ie:1; - /** reg_pad2_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad2_slp_oe:1; - /** reg_pad2_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad2_fun_ie:1; - /** reg_pad2_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad2_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad2_reg_t; - - -/** Group: pad3 */ -/** Type of pad3 register - * Reserved - */ -typedef union { - struct { - /** reg_pad3_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad3_drv:2; - /** reg_pad3_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad3_rde:1; - /** reg_pad3_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad3_rue:1; - /** reg_pad3_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad3_mux_sel:1; - /** reg_pad3_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad3_fun_sel:2; - /** reg_pad3_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad3_slp_sel:1; - /** reg_pad3_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad3_slp_ie:1; - /** reg_pad3_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad3_slp_oe:1; - /** reg_pad3_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad3_fun_ie:1; - /** reg_pad3_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad3_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad3_reg_t; - - -/** Group: pad4 */ -/** Type of pad4 register - * Reserved - */ -typedef union { - struct { - /** reg_pad4_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad4_drv:2; - /** reg_pad4_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad4_rde:1; - /** reg_pad4_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad4_rue:1; - /** reg_pad4_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad4_mux_sel:1; - /** reg_pad4_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad4_fun_sel:2; - /** reg_pad4_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad4_slp_sel:1; - /** reg_pad4_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad4_slp_ie:1; - /** reg_pad4_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad4_slp_oe:1; - /** reg_pad4_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad4_fun_ie:1; - /** reg_pad4_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad4_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad4_reg_t; - - -/** Group: pad5 */ -/** Type of pad5 register - * Reserved - */ -typedef union { - struct { - /** reg_pad5_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad5_drv:2; - /** reg_pad5_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad5_rde:1; - /** reg_pad5_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad5_rue:1; - /** reg_pad5_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad5_mux_sel:1; - /** reg_pad5_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad5_fun_sel:2; - /** reg_pad5_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad5_slp_sel:1; - /** reg_pad5_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad5_slp_ie:1; - /** reg_pad5_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad5_slp_oe:1; - /** reg_pad5_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad5_fun_ie:1; - /** reg_pad5_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad5_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad5_reg_t; - - -/** Group: pad6 */ -/** Type of pad6 register - * Reserved - */ -typedef union { - struct { - /** reg_pad6_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad6_drv:2; - /** reg_pad6_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad6_rde:1; - /** reg_pad6_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad6_rue:1; - /** reg_pad6_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad6_mux_sel:1; - /** reg_pad6_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad6_fun_sel:2; - /** reg_pad6_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad6_slp_sel:1; - /** reg_pad6_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad6_slp_ie:1; - /** reg_pad6_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad6_slp_oe:1; - /** reg_pad6_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad6_fun_ie:1; - /** reg_pad6_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad6_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad6_reg_t; - - -/** Group: pad7 */ -/** Type of pad7 register - * Reserved - */ -typedef union { - struct { - /** reg_pad7_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad7_drv:2; - /** reg_pad7_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad7_rde:1; - /** reg_pad7_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad7_rue:1; - /** reg_pad7_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad7_mux_sel:1; - /** reg_pad7_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad7_fun_sel:2; - /** reg_pad7_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad7_slp_sel:1; - /** reg_pad7_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad7_slp_ie:1; - /** reg_pad7_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad7_slp_oe:1; - /** reg_pad7_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad7_fun_ie:1; - /** reg_pad7_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad7_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad7_reg_t; - - -/** Group: pad8 */ -/** Type of pad8 register - * Reserved - */ -typedef union { - struct { - /** reg_pad8_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad8_drv:2; - /** reg_pad8_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad8_rde:1; - /** reg_pad8_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad8_rue:1; - /** reg_pad8_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad8_mux_sel:1; - /** reg_pad8_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad8_fun_sel:2; - /** reg_pad8_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad8_slp_sel:1; - /** reg_pad8_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad8_slp_ie:1; - /** reg_pad8_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad8_slp_oe:1; - /** reg_pad8_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad8_fun_ie:1; - /** reg_pad8_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad8_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad8_reg_t; - - -/** Group: pad9 */ -/** Type of pad9 register - * Reserved - */ -typedef union { - struct { - /** reg_pad9_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad9_drv:2; - /** reg_pad9_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad9_rde:1; - /** reg_pad9_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad9_rue:1; - /** reg_pad9_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad9_mux_sel:1; - /** reg_pad9_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad9_fun_sel:2; - /** reg_pad9_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad9_slp_sel:1; - /** reg_pad9_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad9_slp_ie:1; - /** reg_pad9_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad9_slp_oe:1; - /** reg_pad9_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad9_fun_ie:1; - /** reg_pad9_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad9_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad9_reg_t; - - -/** Group: pad10 */ -/** Type of pad10 register - * Reserved - */ -typedef union { - struct { - /** reg_pad10_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad10_drv:2; - /** reg_pad10_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad10_rde:1; - /** reg_pad10_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad10_rue:1; - /** reg_pad10_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad10_mux_sel:1; - /** reg_pad10_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad10_fun_sel:2; - /** reg_pad10_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad10_slp_sel:1; - /** reg_pad10_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad10_slp_ie:1; - /** reg_pad10_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad10_slp_oe:1; - /** reg_pad10_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad10_fun_ie:1; - /** reg_pad10_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad10_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad10_reg_t; - - -/** Group: pad11 */ -/** Type of pad11 register - * Reserved - */ -typedef union { - struct { - /** reg_pad11_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad11_drv:2; - /** reg_pad11_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad11_rde:1; - /** reg_pad11_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad11_rue:1; - /** reg_pad11_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad11_mux_sel:1; - /** reg_pad11_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad11_fun_sel:2; - /** reg_pad11_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad11_slp_sel:1; - /** reg_pad11_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad11_slp_ie:1; - /** reg_pad11_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad11_slp_oe:1; - /** reg_pad11_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad11_fun_ie:1; - /** reg_pad11_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad11_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad11_reg_t; - - -/** Group: pad12 */ -/** Type of pad120 register - * Reserved - */ -typedef union { - struct { - /** reg_pad12_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad12_drv:2; - /** reg_pad12_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad12_rde:1; - /** reg_pad12_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad12_rue:1; - /** reg_pad12_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad12_mux_sel:1; - /** reg_pad12_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad12_fun_sel:2; - /** reg_pad12_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad12_slp_sel:1; - /** reg_pad12_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad12_slp_ie:1; - /** reg_pad12_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad12_slp_oe:1; - /** reg_pad12_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad12_fun_ie:1; - /** reg_pad12_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad12_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad120_reg_t; - - -/** Group: pad13 */ -/** Type of pad13 register - * Reserved - */ -typedef union { - struct { - /** reg_pad13_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad13_drv:2; - /** reg_pad13_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad13_rde:1; - /** reg_pad13_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad13_rue:1; - /** reg_pad13_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad13_mux_sel:1; - /** reg_pad13_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad13_fun_sel:2; - /** reg_pad13_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad13_slp_sel:1; - /** reg_pad13_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad13_slp_ie:1; - /** reg_pad13_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad13_slp_oe:1; - /** reg_pad13_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad13_fun_ie:1; - /** reg_pad13_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad13_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad13_reg_t; - - -/** Group: pad14 */ -/** Type of pad14 register - * Reserved - */ -typedef union { - struct { - /** reg_pad14_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad14_drv:2; - /** reg_pad14_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad14_rde:1; - /** reg_pad14_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad14_rue:1; - /** reg_pad14_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad14_mux_sel:1; - /** reg_pad14_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad14_fun_sel:2; - /** reg_pad14_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad14_slp_sel:1; - /** reg_pad14_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad14_slp_ie:1; - /** reg_pad14_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad14_slp_oe:1; - /** reg_pad14_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad14_fun_ie:1; - /** reg_pad14_filter_en : R/W; bitpos: [11]; default: 0; - * need des - */ - uint32_t reg_pad14_filter_en:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} lp_iomux_pad14_reg_t; - - -/** Group: pad15 */ -/** Type of pad15 register - * Reserved - */ -typedef union { - struct { - /** reg_pad15_drv : R/W; bitpos: [1:0]; default: 2; - * Reserved - */ - uint32_t reg_pad15_drv:2; - /** reg_pad15_rde : R/W; bitpos: [2]; default: 0; - * Reserved - */ - uint32_t reg_pad15_rde:1; - /** reg_pad15_rue : R/W; bitpos: [3]; default: 0; - * Reserved - */ - uint32_t reg_pad15_rue:1; - /** reg_pad15_mux_sel : R/W; bitpos: [4]; default: 0; - * 1:use LP GPIO,0: use digital GPIO - */ - uint32_t reg_pad15_mux_sel:1; - /** reg_pad15_fun_sel : R/W; bitpos: [6:5]; default: 0; - * function sel - */ - uint32_t reg_pad15_fun_sel:2; - /** reg_pad15_slp_sel : R/W; bitpos: [7]; default: 0; - * 1: enable sleep mode during sleep,0: no sleep mode - */ - uint32_t reg_pad15_slp_sel:1; - /** reg_pad15_slp_ie : R/W; bitpos: [8]; default: 0; - * input enable in sleep mode - */ - uint32_t reg_pad15_slp_ie:1; - /** reg_pad15_slp_oe : R/W; bitpos: [9]; default: 0; - * output enable in sleep mode - */ - uint32_t reg_pad15_slp_oe:1; - /** reg_pad15_fun_ie : R/W; bitpos: [10]; default: 0; - * input enable in work mode - */ - uint32_t reg_pad15_fun_ie:1; - /** reg_pad15_filter_en : R/W; bitpos: [11]; default: 0; + */ + uint32_t fun_ie:1; + /** filter_en : R/W; bitpos: [11]; default: 0; * need des */ - uint32_t reg_pad15_filter_en:1; + uint32_t filter_en:1; uint32_t reserved_12:20; }; uint32_t val; -} lp_iomux_pad15_reg_t; +} lp_iomux_pad_reg_t; /** Group: ext_wakeup0_sel */ @@ -929,22 +149,7 @@ typedef union { typedef struct lp_iomux_dev_t { volatile lp_iomux_clk_en_reg_t clk_en; volatile lp_iomux_ver_date_reg_t ver_date; - volatile lp_iomux_pad0_reg_t pad0; - volatile lp_iomux_pad1_reg_t pad1; - volatile lp_iomux_pad2_reg_t pad2; - volatile lp_iomux_pad3_reg_t pad3; - volatile lp_iomux_pad4_reg_t pad4; - volatile lp_iomux_pad5_reg_t pad5; - volatile lp_iomux_pad6_reg_t pad6; - volatile lp_iomux_pad7_reg_t pad7; - volatile lp_iomux_pad8_reg_t pad8; - volatile lp_iomux_pad9_reg_t pad9; - volatile lp_iomux_pad10_reg_t pad10; - volatile lp_iomux_pad11_reg_t pad11; - volatile lp_iomux_pad120_reg_t pad120; - volatile lp_iomux_pad13_reg_t pad13; - volatile lp_iomux_pad14_reg_t pad14; - volatile lp_iomux_pad15_reg_t pad15; + volatile lp_iomux_pad_reg_t pad[16]; volatile lp_iomux_ext_wakeup0_sel_reg_t ext_wakeup0_sel; volatile lp_iomux_lp_pad_hold_reg_t lp_pad_hold; volatile lp_iomux_lp_pad_hys_reg_t lp_pad_hys; diff --git a/components/soc/esp32p4/include/soc/rtc_io_channel.h b/components/soc/esp32p4/include/soc/rtc_io_channel.h new file mode 100644 index 00000000000..7aafca559d6 --- /dev/null +++ b/components/soc/esp32p4/include/soc/rtc_io_channel.h @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +//RTC GPIO channels +#define RTCIO_GPIO0_CHANNEL 0 //RTCIO_CHANNEL_0 +#define RTCIO_CHANNEL_0_GPIO_NUM 0 + +#define RTCIO_GPIO1_CHANNEL 1 //RTCIO_CHANNEL_1 +#define RTCIO_CHANNEL_1_GPIO_NUM 1 + +#define RTCIO_GPIO2_CHANNEL 2 //RTCIO_CHANNEL_2 +#define RTCIO_CHANNEL_2_GPIO_NUM 2 + +#define RTCIO_GPIO3_CHANNEL 3 //RTCIO_CHANNEL_3 +#define RTCIO_CHANNEL_3_GPIO_NUM 3 + +#define RTCIO_GPIO4_CHANNEL 4 //RTCIO_CHANNEL_4 +#define RTCIO_CHANNEL_4_GPIO_NUM 4 + +#define RTCIO_GPIO5_CHANNEL 5 //RTCIO_CHANNEL_5 +#define RTCIO_CHANNEL_5_GPIO_NUM 5 + +#define RTCIO_GPIO6_CHANNEL 6 //RTCIO_CHANNEL_6 +#define RTCIO_CHANNEL_6_GPIO_NUM 6 + +#define RTCIO_GPIO7_CHANNEL 7 //RTCIO_CHANNEL_7 +#define RTCIO_CHANNEL_7_GPIO_NUM 7 + +#define RTCIO_GPIO8_CHANNEL 8 //RTCIO_CHANNEL_8 +#define RTCIO_CHANNEL_8_GPIO_NUM 8 + +#define RTCIO_GPIO9_CHANNEL 9 //RTCIO_CHANNEL_9 +#define RTCIO_CHANNEL_9_GPIO_NUM 9 + +#define RTCIO_GPIO10_CHANNEL 10 //RTCIO_CHANNEL_10 +#define RTCIO_CHANNEL_10_GPIO_NUM 10 + +#define RTCIO_GPIO11_CHANNEL 11 //RTCIO_CHANNEL_11 +#define RTCIO_CHANNEL_11_GPIO_NUM 11 + +#define RTCIO_GPIO12_CHANNEL 12 //RTCIO_CHANNEL_12 +#define RTCIO_CHANNEL_12_GPIO_NUM 12 + +#define RTCIO_GPIO13_CHANNEL 13 //RTCIO_CHANNEL_13 +#define RTCIO_CHANNEL_13_GPIO_NUM 13 + +#define RTCIO_GPIO14_CHANNEL 14 //RTCIO_CHANNEL_14 +#define RTCIO_CHANNEL_14_GPIO_NUM 14 + +#define RTCIO_GPIO15_CHANNEL 15 //RTCIO_CHANNEL_15 +#define RTCIO_CHANNEL_15_GPIO_NUM 15 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8c2ef769b84..96b5a93e297 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -71,6 +71,8 @@ // #define SOC_PMU_SUPPORTED 1 //TODO: IDF-7531 // #define SOC_PAU_SUPPORTED 1 //TODO: IDF-7531 // #define SOC_LP_TIMER_SUPPORTED 1 //TODO: IDF-7532 +#define SOC_LP_GPIO_MATRIX_SUPPORTED 1 +#define SOC_LP_PERIPHERALS_SUPPORTED 1 #define SOC_SPIRAM_SUPPORTED 1 // #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534 // #define SOC_SDMMC_HOST_SUPPORTED 1 //TODO: IDF-6502 @@ -189,7 +191,7 @@ // On ESP32-P4, Digital IOs have their own registers to control pullup/down capability, independent of LP registers. #define SOC_GPIO_SUPPORT_RTC_INDEPENDENT (1) // GPIO0~15 on ESP32P4 can support chip deep sleep wakeup -// #define SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP (1) // TODO: IDF-7480 +#define SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP (1) #define SOC_GPIO_VALID_GPIO_MASK (0x01FFFFFFFFFFFFFF) #define SOC_GPIO_VALID_OUTPUT_GPIO_MASK SOC_GPIO_VALID_GPIO_MASK @@ -204,10 +206,13 @@ #define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1) /*-------------------------- RTCIO CAPS --------------------------------------*/ -// #define SOC_RTCIO_PIN_COUNT 16 //TODO: IDF-7480 -// #define SOC_RTCIO_INPUT_OUTPUT_SUPPORTED 1 //TODO: IDF-7480 -// #define SOC_RTCIO_HOLD_SUPPORTED 1 //TODO: IDF-7480 -// #define SOC_RTCIO_WAKE_SUPPORTED 1 //TODO: IDF-7480 +#define SOC_RTCIO_PIN_COUNT 16 +#define SOC_RTCIO_INPUT_OUTPUT_SUPPORTED 1 /* This macro indicates that the target has separate RTC IOMUX hardware feature, + * so it supports unique IOMUX configuration (including IE, OE, PU, PD, DRV etc.) + * when the pins are switched to RTC function. + */ +#define SOC_RTCIO_HOLD_SUPPORTED 1 +#define SOC_RTCIO_WAKE_SUPPORTED 1 /*-------------------------- Dedicated GPIO CAPS -----------------------------*/ #define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */ diff --git a/components/soc/esp32p4/rtc_io_periph.c b/components/soc/esp32p4/rtc_io_periph.c new file mode 100644 index 00000000000..2e1bd96cd33 --- /dev/null +++ b/components/soc/esp32p4/rtc_io_periph.c @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/rtc_periph.h" + +const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { + RTCIO_GPIO0_CHANNEL, //GPIO0 + RTCIO_GPIO1_CHANNEL, //GPIO1 + RTCIO_GPIO2_CHANNEL, //GPIO2 + RTCIO_GPIO3_CHANNEL, //GPIO3 + RTCIO_GPIO4_CHANNEL, //GPIO4 + RTCIO_GPIO5_CHANNEL, //GPIO5 + RTCIO_GPIO6_CHANNEL, //GPIO6 + RTCIO_GPIO7_CHANNEL, //GPIO7 + RTCIO_GPIO8_CHANNEL, //GPIO8 + RTCIO_GPIO9_CHANNEL, //GPIO9 + RTCIO_GPIO10_CHANNEL, //GPIO10 + RTCIO_GPIO11_CHANNEL, //GPIO11 + RTCIO_GPIO12_CHANNEL, //GPIO12 + RTCIO_GPIO13_CHANNEL, //GPIO13 + RTCIO_GPIO14_CHANNEL, //GPIO14 + RTCIO_GPIO15_CHANNEL, //GPIO15 + -1,//GPIO16 + -1,//GPIO17 + -1,//GPIO18 + -1,//GPIO19 + -1,//GPIO20 + -1,//GPIO21 + -1,//GPIO22 + -1,//GPIO23 + -1,//GPIO24 + -1,//GPIO25 + -1,//GPIO26 + -1,//GPIO27 + -1,//GPIO28 + -1,//GPIO29 + -1,//GPIO30 + -1,//GPIO31 + -1,//GPIO32 + -1,//GPIO33 + -1,//GPIO34 + -1,//GPIO35 + -1,//GPIO36 + -1,//GPIO37 + -1,//GPIO38 + -1,//GPIO39 + -1,//GPIO40 + -1,//GPIO41 + -1,//GPIO42 + -1,//GPIO43 + -1,//GPIO44 + -1,//GPIO45 + -1,//GPIO46 + -1,//GPIO47 + -1,//GPIO48 + -1,//GPIO49 + -1,//GPIO50 + -1,//GPIO51 + -1,//GPIO52 + -1,//GPIO53 + -1,//GPIO54 + -1,//GPIO55 + -1,//GPIO56 +}; diff --git a/components/soc/esp32s2/rtc_io_periph.c b/components/soc/esp32s2/rtc_io_periph.c index 9130571328d..e19d22a691e 100644 --- a/components/soc/esp32s2/rtc_io_periph.c +++ b/components/soc/esp32s2/rtc_io_periph.c @@ -5,6 +5,7 @@ */ #include "soc/rtc_periph.h" +#include "soc/rtc_io_reg.h" const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { RTCIO_GPIO0_CHANNEL, //GPIO0 diff --git a/components/soc/esp32s3/rtc_io_periph.c b/components/soc/esp32s3/rtc_io_periph.c index 029847e1166..cf2484a911a 100644 --- a/components/soc/esp32s3/rtc_io_periph.c +++ b/components/soc/esp32s3/rtc_io_periph.c @@ -5,6 +5,7 @@ */ #include "soc/rtc_periph.h" +#include "soc/rtc_io_reg.h" const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { RTCIO_GPIO0_CHANNEL, //GPIO0 diff --git a/components/soc/include/soc/rtc_io_periph.h b/components/soc/include/soc/rtc_io_periph.h index eaba50077fd..95315e064b4 100644 --- a/components/soc/include/soc/rtc_io_periph.h +++ b/components/soc/include/soc/rtc_io_periph.h @@ -13,10 +13,6 @@ #if SOC_RTCIO_PIN_COUNT > 0 #include "soc/rtc_io_channel.h" -#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED -#include "soc/rtc_io_reg.h" -#include "soc/rtc_io_struct.h" -#endif #endif #if SOC_ADC_RTC_CTRL_SUPPORTED diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h index 910d592d7fd..85ac81cf001 100644 --- a/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h @@ -13,6 +13,9 @@ extern "C" { #include "hal/gpio_types.h" #include "hal/rtc_io_ll.h" +#define RTCIO_OUTPUT_NORMAL _Pragma ("GCC warning \"'RTCIO_OUTPUT_NORMAL' macro is deprecated\"") RTCIO_LL_OUTPUT_NORMAL +#define RTCIO_OUTPUT_OD _Pragma ("GCC warning \"'RTCIO_OUTPUT_OD' macro is deprecated\"") RTCIO_LL_OUTPUT_OD + typedef enum { LP_IO_NUM_0 = 0, /*!< GPIO0, input and output */ LP_IO_NUM_1 = 1, /*!< GPIO1, input and output */ @@ -31,7 +34,7 @@ typedef enum { */ static inline void ulp_lp_core_gpio_init(lp_io_num_t lp_io_num) { - rtcio_ll_function_select(lp_io_num, RTCIO_FUNC_RTC); + rtcio_ll_function_select(lp_io_num, RTCIO_LL_FUNC_RTC); } /** @@ -99,7 +102,7 @@ static inline uint32_t ulp_lp_core_gpio_get_level(lp_io_num_t lp_io_num) * @brief Set rtcio output mode * * @param lp_io_num The rtc io pin to set the output mode for - * @param mode RTCIO_OUTPUT_NORMAL: normal, RTCIO_OUTPUT_OD: open drain + * @param mode RTCIO_LL_OUTPUT_NORMAL: normal, RTCIO_LL_OUTPUT_OD: open drain */ static inline void ulp_lp_core_gpio_set_output_mode(lp_io_num_t lp_io_num, rtcio_ll_out_mode_t mode) { diff --git a/docs/en/api-reference/peripherals/gpio.rst b/docs/en/api-reference/peripherals/gpio.rst index e642818a2a0..78e52ebc10a 100644 --- a/docs/en/api-reference/peripherals/gpio.rst +++ b/docs/en/api-reference/peripherals/gpio.rst @@ -13,13 +13,20 @@ GPIO Summary .. only:: SOC_RTCIO_INPUT_OUTPUT_SUPPORTED - There is also separate "RTC GPIO" support, which functions when GPIOs are routed to the "RTC" low-power and analog subsystem. These pin functions can be used when: + .. only:: not SOC_LP_PERIPHERALS_SUPPORTED + + There is also separate "RTC GPIO" support, which functions when GPIOs are routed to the "RTC" low-power and analog subsystem. These pin functions can be used when: + + .. only:: SOC_LP_PERIPHERALS_SUPPORTED + + There is also separate "RTC GPIO" support, which functions when GPIOs are routed to the "RTC" low-power, analog subsystem, and Low-Power(LP) peripherals. These pin functions can be used when: .. list:: - In Deep-sleep mode :SOC_ULP_SUPPORTED and not esp32c6: - The :doc:`Ultra Low Power co-processor <../../api-reference/system/ulp>` is running - - Analog functions such as ADC/DAC/etc are in use. + - Analog functions such as ADC/DAC/etc are in use + :SOC_LP_PERIPHERALS_SUPPORTED: - LP peripherals, such as LP_UART, LP_I2C, are in use .. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER or SOC_GPIO_FLEX_GLITCH_FILTER_NUM diff --git a/docs/en/api-reference/peripherals/gpio/esp32p4.inc b/docs/en/api-reference/peripherals/gpio/esp32p4.inc index 027104fe3c0..47335f01694 100644 --- a/docs/en/api-reference/peripherals/gpio/esp32p4.inc +++ b/docs/en/api-reference/peripherals/gpio/esp32p4.inc @@ -310,6 +310,6 @@ The table below provides more information on pin usage, and please note the comm .. note:: - Strapping pin: GPIO34, GPIO35, GPIO36, GPIO37, and GPIO38 are strapping pins. For more infomation, please refer to `datasheet <{IDF_TARGET_DATASHEET_EN_URL}>`__. - - USB-JTAG: GPIO 24 and 25 are used by USB-JTAG by default. In order to use them as GPIOs, USB-JTAG will be disabled by the drivers. + - USB-JTAG: GPIO 24 and 25 are used by USB-JTAG by default. In order to use them as GPIOs, USB-JTAG will be disabled by the drivers. --- diff --git a/docs/zh_CN/api-reference/peripherals/gpio.rst b/docs/zh_CN/api-reference/peripherals/gpio.rst index d371f5b9cab..a30c91625ee 100644 --- a/docs/zh_CN/api-reference/peripherals/gpio.rst +++ b/docs/zh_CN/api-reference/peripherals/gpio.rst @@ -13,13 +13,20 @@ GPIO 汇总 .. only:: SOC_RTCIO_INPUT_OUTPUT_SUPPORTED - 当 GPIO 连接到 RTC 低功耗和模拟子系统时,{IDF_TARGET_NAME} 芯片还单独支持 RTC GPIO。可在以下情况时使用这些管脚功能: + .. only:: not SOC_LP_PERIPHERALS_SUPPORTED + + 当 GPIO 连接到 RTC 低功耗和模拟子系统时,{IDF_TARGET_NAME} 芯片还单独支持 RTC GPIO。可在以下情况时使用这些管脚功能: + + .. only:: SOC_LP_PERIPHERALS_SUPPORTED + + 当 GPIO 连接到 RTC 低功耗、模拟子系统、低功耗外设时,{IDF_TARGET_NAME} 芯片还单独支持 RTC GPIO。可在以下情况时使用这些管脚功能: .. list:: - 处于 Deep-sleep 模式时 :SOC_ULP_SUPPORTED and not esp32c6: - :doc:`超低功耗协处理器 (ULP) <../../api-reference/system/ulp>` 运行时 - 使用 ADC/DAC 等模拟功能时 + :SOC_LP_PERIPHERALS_SUPPORTED: - 使用低功耗外设时,例如: LP_UART , LP_I2C 等 .. only:: SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER or SOC_GPIO_FLEX_GLITCH_FILTER_NUM From 0798691bf07a0fd746a0ade95de35a7e8ccb5a15 Mon Sep 17 00:00:00 2001 From: Harshit Malpani Date: Wed, 20 Sep 2023 14:05:10 +0530 Subject: [PATCH 51/71] fix: Fix protocols example to build without setting target Protocol examples used to raise an error if the target was not set and `idf.py build` command was used. This commit fix this error and when IDF_TARGET is not set, ESP32 is selected as default target --- examples/protocols/esp_http_client/CMakeLists.txt | 2 +- examples/protocols/esp_http_client/main/CMakeLists.txt | 4 +++- examples/protocols/http_server/simple/CMakeLists.txt | 2 +- examples/protocols/http_server/simple/main/CMakeLists.txt | 4 +++- examples/protocols/sockets/tcp_client/main/CMakeLists.txt | 4 +++- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/examples/protocols/esp_http_client/CMakeLists.txt b/examples/protocols/esp_http_client/CMakeLists.txt index e012d1a3fd0..0715448e56b 100644 --- a/examples/protocols/esp_http_client/CMakeLists.txt +++ b/examples/protocols/esp_http_client/CMakeLists.txt @@ -2,7 +2,7 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -if(${IDF_TARGET} STREQUAL "linux") +if("${IDF_TARGET}" STREQUAL "linux") set(COMPONENTS main) endif() diff --git a/examples/protocols/esp_http_client/main/CMakeLists.txt b/examples/protocols/esp_http_client/main/CMakeLists.txt index 23ba7fa726c..bfee9f9c9e5 100644 --- a/examples/protocols/esp_http_client/main/CMakeLists.txt +++ b/examples/protocols/esp_http_client/main/CMakeLists.txt @@ -2,7 +2,9 @@ # # (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.) set(requires "") -if(${IDF_TARGET} STREQUAL "linux") +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") list(APPEND requires esp_stubs esp_event esp-tls esp_http_client protocol_examples_common nvs_flash) endif() idf_component_register(SRCS "esp_http_client_example.c" diff --git a/examples/protocols/http_server/simple/CMakeLists.txt b/examples/protocols/http_server/simple/CMakeLists.txt index 42acdd7cc75..9bed06a0791 100644 --- a/examples/protocols/http_server/simple/CMakeLists.txt +++ b/examples/protocols/http_server/simple/CMakeLists.txt @@ -2,7 +2,7 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -if(${IDF_TARGET} STREQUAL "linux") +if("${IDF_TARGET}" STREQUAL "linux") set(COMPONENTS main) endif() diff --git a/examples/protocols/http_server/simple/main/CMakeLists.txt b/examples/protocols/http_server/simple/main/CMakeLists.txt index 28894fd56e4..564c3f54f60 100644 --- a/examples/protocols/http_server/simple/main/CMakeLists.txt +++ b/examples/protocols/http_server/simple/main/CMakeLists.txt @@ -1,5 +1,7 @@ set(requires "") -if(${IDF_TARGET} STREQUAL "linux") +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") list(APPEND requires esp_stubs esp-tls esp_http_server protocol_examples_common nvs_flash) endif() idf_component_register(SRCS "main.c" diff --git a/examples/protocols/sockets/tcp_client/main/CMakeLists.txt b/examples/protocols/sockets/tcp_client/main/CMakeLists.txt index 0ac00ed4029..5862a63d4a4 100644 --- a/examples/protocols/sockets/tcp_client/main/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_client/main/CMakeLists.txt @@ -1,4 +1,6 @@ -if(${IDF_TARGET} STREQUAL "linux") +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") set(requires esp_event esp_stubs protocol_examples_common nvs_flash) endif() From a71208f96d97ec9676c227a4ae0fee08bc56ca84 Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 20 Sep 2023 11:31:21 +0800 Subject: [PATCH 52/71] refactor(etm): systimer etm test case previously we use the systimer event to toggling a GPIO and assert the GPIO level, which is not stable in CI. Now we swicth to clear the GPIO at the systimer event. --- .../test_apps/etm/main/test_systimer_etm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/esp_hw_support/test_apps/etm/main/test_systimer_etm.c b/components/esp_hw_support/test_apps/etm/main/test_systimer_etm.c index 6d2ce1e02ec..23b0cba9606 100644 --- a/components/esp_hw_support/test_apps/etm/main/test_systimer_etm.c +++ b/components/esp_hw_support/test_apps/etm/main/test_systimer_etm.c @@ -79,7 +79,7 @@ TEST_CASE("esp_timer_etm_event", "[etm]") printf("allocate GPIO etm task\r\n"); esp_etm_task_handle_t gpio_task = NULL; gpio_etm_task_config_t gpio_task_config = { - .action = GPIO_ETM_TASK_ACTION_TOG, + .action = GPIO_ETM_TASK_ACTION_CLR, }; TEST_ESP_OK(gpio_new_etm_task(&gpio_task_config, &gpio_task)); @@ -114,12 +114,14 @@ TEST_CASE("esp_timer_etm_event", "[etm]") TEST_ESP_OK(esp_timer_create(&periodic_timer_args, &periodic_timer)); TEST_ESP_OK(esp_timer_start_periodic(periodic_timer, 500000)); - // should see a 1Hz square wave on the GPIO - esp_rom_delay_us(1200000); - - // check the final GPIO level + vTaskDelay(pdMS_TO_TICKS(100)); + // etm event not active yet, so the GPIO level should still be the initial state TEST_ASSERT_EQUAL(1, gpio_get_level(output_gpio)); + vTaskDelay(pdMS_TO_TICKS(1000)); + // etm event should have cleared the GPIO level + TEST_ASSERT_EQUAL(0, gpio_get_level(output_gpio)); + TEST_ESP_OK(esp_timer_stop(periodic_timer)); TEST_ESP_OK(esp_timer_delete(periodic_timer)); From 9bec9ccade797c3cd5ea318eddcfc740a7f8e0be Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 8 Sep 2023 18:23:10 +0800 Subject: [PATCH 53/71] feat(hal): add hal utils for clock divider calculation --- components/hal/CMakeLists.txt | 1 + components/hal/hal_utils.c | 118 +++++++++++++++++++++++++ components/hal/include/hal/hal_utils.h | 65 ++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 components/hal/hal_utils.c create mode 100644 components/hal/include/hal/hal_utils.h diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index e0bab96d2b5..7019d228041 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -9,6 +9,7 @@ endif() set(srcs "mpu_hal.c" "efuse_hal.c" + "hal_utils.c" "${target}/efuse_hal.c") diff --git a/components/hal/hal_utils.c b/components/hal/hal_utils.c new file mode 100644 index 00000000000..1d9847c9ae6 --- /dev/null +++ b/components/hal/hal_utils.c @@ -0,0 +1,118 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/hal_utils.h" + +/** + * @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; +} + +__attribute__((always_inline)) +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 div_denom = 1; + 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) { + // 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 + clk_div->integ = div_integ; + clk_div->denom = div_denom; + clk_div->numer = div_numer; + + // Return the actual frequency + if (div_numer) { + uint32_t temp = div_integ * div_denom + div_numer; + return (uint32_t)(((uint64_t)clk_info->src_freq_hz * div_denom + temp / 2) / temp); + } + 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 div_denom = 1; + 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)) { + // 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++) { + 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) { + div_denom = a; + div_numer = b; + min = sub; + } + } + } else { + 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) { + return 0; + } + + // Assign result + clk_div->integ = div_integ; + clk_div->denom = div_denom; + clk_div->numer = div_numer; + + // Return the actual frequency + if (div_numer) { + uint32_t temp = div_integ * div_denom + div_numer; + return (uint32_t)(((uint64_t)clk_info->src_freq_hz * div_denom + temp / 2) / temp); + } + return clk_info->src_freq_hz / div_integ; +} diff --git a/components/hal/include/hal/hal_utils.h b/components/hal/include/hal/hal_utils.h new file mode 100644 index 00000000000..36ead6fbf42 --- /dev/null +++ b/components/hal/include/hal/hal_utils.h @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Clock infomation + * + */ +typedef struct { + uint32_t src_freq_hz; /*!< Source 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 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) */ +} hal_utils_clk_info_t; + +/** + * @brief Members of clock division + * + */ +typedef struct { + uint32_t integ; /*!< Integer part of division */ + uint32_t denom; /*!< Denominator part of division */ + uint32_t numer; /*!< Numerator part of division */ +} hal_utils_clk_div_t; + +/** + * @brief Calculate the clock division + * @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 + * @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); + +/** + * @brief Calculate the clock division + * @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 + * @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); + +#ifdef __cplusplus +} +#endif From dd4072a80cc9da88ccebab8c0de81004e2d3b845 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 11 Sep 2023 12:58:38 +0800 Subject: [PATCH 54/71] refactor(hal): use hal utils to calculate clock division --- components/driver/dac/esp32/dac_dma.c | 2 +- components/driver/dac/esp32s2/dac_dma.c | 40 ++--- components/esp_lcd/linker.lf | 1 + components/hal/.build-test-rules.yml | 7 + components/hal/adc_hal.c | 2 +- components/hal/esp32/include/hal/i2s_ll.h | 22 +-- components/hal/esp32c3/include/hal/i2s_ll.h | 43 ++--- components/hal/esp32c6/include/hal/i2s_ll.h | 43 ++--- components/hal/esp32h2/include/hal/i2s_ll.h | 43 ++--- components/hal/esp32s2/include/hal/i2s_ll.h | 22 +-- components/hal/esp32s3/include/hal/i2s_ll.h | 43 ++--- components/hal/hal_utils.c | 93 +++++++---- components/hal/i2s_hal.c | 52 ++---- components/hal/include/hal/hal_utils.h | 45 ++++-- components/hal/include/hal/i2s_hal.h | 2 +- components/hal/lcd_hal.c | 57 ++----- .../hal/test_apps/hal_utils/CMakeLists.txt | 10 ++ components/hal/test_apps/hal_utils/README.md | 2 + .../test_apps/hal_utils/main/CMakeLists.txt | 5 + .../test_apps/hal_utils/main/test_app_main.c | 27 ++++ .../hal_utils/main/test_calc_clk_div.c | 150 ++++++++++++++++++ .../test_apps/hal_utils/pytest_hal_utils.py | 11 ++ .../test_apps/hal_utils/sdkconfig.defaults | 2 + 23 files changed, 432 insertions(+), 292 deletions(-) create mode 100644 components/hal/.build-test-rules.yml create mode 100644 components/hal/test_apps/hal_utils/CMakeLists.txt create mode 100644 components/hal/test_apps/hal_utils/README.md create mode 100644 components/hal/test_apps/hal_utils/main/CMakeLists.txt create mode 100644 components/hal/test_apps/hal_utils/main/test_app_main.c create mode 100644 components/hal/test_apps/hal_utils/main/test_calc_clk_div.c create mode 100644 components/hal/test_apps/hal_utils/pytest_hal_utils.py create mode 100644 components/hal/test_apps/hal_utils/sdkconfig.defaults diff --git a/components/driver/dac/esp32/dac_dma.c b/components/driver/dac/esp32/dac_dma.c index cc2b5706a2b..c5f8223a909 100644 --- a/components/driver/dac/esp32/dac_dma.c +++ b/components/driver/dac/esp32/dac_dma.c @@ -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); diff --git a/components/driver/dac/esp32s2/dac_dma.c b/components/driver/dac/esp32s2/dac_dma.c index 25d9ceaf408..af9dfb11c69 100644 --- a/components/driver/dac/esp32s2/dac_dma.c +++ b/components/driver/dac/esp32s2/dac_dma.c @@ -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; } diff --git a/components/esp_lcd/linker.lf b/components/esp_lcd/linker.lf index e46cfad3d9d..6e3aa0d3cda 100644 --- a/components/esp_lcd/linker.lf +++ b/components/esp_lcd/linker.lf @@ -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) diff --git a/components/hal/.build-test-rules.yml b/components/hal/.build-test-rules.yml new file mode 100644 index 00000000000..af13d55d6cb --- /dev/null +++ b/components/hal/.build-test-rules.yml @@ -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 diff --git a/components/hal/adc_hal.c b/components/hal/adc_hal.c index 3e4f74da55a..77b4809a75c 100644 --- a/components/hal/adc_hal.c +++ b/components/hal/adc_hal.c @@ -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); diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 5f33bf42778..8f621d92e21 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -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); diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index cf492a72db7..6f8dac94ee9 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -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); } /** diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 347767cecc0..687ef3162fb 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -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); } /** diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index d8a0b7ad049..8ebfa8518bb 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -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); } /** diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index aaed7ac5056..4b419047e5a 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -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); diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 4ae55469c46..1beb845b2db 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -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); } diff --git a/components/hal/hal_utils.c b/components/hal/hal_utils.c index 1d9847c9ae6..1213aa49cf2 100644 --- a/components/hal/hal_utils.c +++ b/components/hal/hal_utils.c @@ -5,6 +5,7 @@ */ #include "hal/hal_utils.h" +#include "hal/assert.h" /** * @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; } -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) { - // 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; + // 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 (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; +} diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 2883b4084cc..ee3c94c29c2 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -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); diff --git a/components/hal/include/hal/hal_utils.h b/components/hal/include/hal/hal_utils.h index 36ead6fbf42..7f5961ceca5 100644 --- a/components/hal/include/hal/hal_utils.h +++ b/components/hal/include/hal/hal_utils.h @@ -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_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_accurate(const hal_utils_clk_info_t *clk_info, hal_utils_clk_div_t *clk_div); +uint32_t hal_utils_calc_clk_div_integer(const hal_utils_clk_info_t *clk_info, uint32_t *int_div); #ifdef __cplusplus } diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index d6ca077e368..e1286b876fe 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -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 diff --git a/components/hal/lcd_hal.c b/components/hal/lcd_hal.c index 8dbe8d48513..706f5787dce 100644 --- a/components/hal/lcd_hal.c +++ b/components/hal/lcd_hal.c @@ -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; } diff --git a/components/hal/test_apps/hal_utils/CMakeLists.txt b/components/hal/test_apps/hal_utils/CMakeLists.txt new file mode 100644 index 00000000000..8a655695762 --- /dev/null +++ b/components/hal/test_apps/hal_utils/CMakeLists.txt @@ -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) diff --git a/components/hal/test_apps/hal_utils/README.md b/components/hal/test_apps/hal_utils/README.md new file mode 100644 index 00000000000..37c142df16d --- /dev/null +++ b/components/hal/test_apps/hal_utils/README.md @@ -0,0 +1,2 @@ +| Supported Targets | Linux | +| ----------------- | ----- | diff --git a/components/hal/test_apps/hal_utils/main/CMakeLists.txt b/components/hal/test_apps/hal_utils/main/CMakeLists.txt new file mode 100644 index 00000000000..86a4981deda --- /dev/null +++ b/components/hal/test_apps/hal_utils/main/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register(SRCS "test_app_main.c" + "test_calc_clk_div.c" + INCLUDE_DIRS "." + REQUIRES unity hal + WHOLE_ARCHIVE) diff --git a/components/hal/test_apps/hal_utils/main/test_app_main.c b/components/hal/test_apps/hal_utils/main/test_app_main.c new file mode 100644 index 00000000000..be6b1a087c6 --- /dev/null +++ b/components/hal/test_apps/hal_utils/main/test_app_main.c @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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(); +} diff --git a/components/hal/test_apps/hal_utils/main/test_calc_clk_div.c b/components/hal/test_apps/hal_utils/main/test_calc_clk_div.c new file mode 100644 index 00000000000..f332cb22697 --- /dev/null +++ b/components/hal/test_apps/hal_utils/main/test_calc_clk_div.c @@ -0,0 +1,150 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#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); +} diff --git a/components/hal/test_apps/hal_utils/pytest_hal_utils.py b/components/hal/test_apps/hal_utils/pytest_hal_utils.py new file mode 100644 index 00000000000..425909be330 --- /dev/null +++ b/components/hal/test_apps/hal_utils/pytest_hal_utils.py @@ -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() diff --git a/components/hal/test_apps/hal_utils/sdkconfig.defaults b/components/hal/test_apps/hal_utils/sdkconfig.defaults new file mode 100644 index 00000000000..d30b539092c --- /dev/null +++ b/components/hal/test_apps/hal_utils/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_IDF_TARGET="linux" +CONFIG_ESP_TASK_WDT_EN=n From f8517949ee67452d8f520b3465a764e9e51eb71a Mon Sep 17 00:00:00 2001 From: caixinying-git Date: Fri, 25 Aug 2023 14:19:42 +0800 Subject: [PATCH 55/71] docs: provide CN translation for api-reference/peripherals/sdmmc_host.rst --- .../api-reference/peripherals/sdmmc_host.rst | 134 ++++++++----- .../api-reference/peripherals/sdmmc_host.rst | 188 +++++++++++++++++- 2 files changed, 269 insertions(+), 53 deletions(-) diff --git a/docs/en/api-reference/peripherals/sdmmc_host.rst b/docs/en/api-reference/peripherals/sdmmc_host.rst index 95273e94a2b..58bd62d669e 100644 --- a/docs/en/api-reference/peripherals/sdmmc_host.rst +++ b/docs/en/api-reference/peripherals/sdmmc_host.rst @@ -1,10 +1,12 @@ SDMMC Host Driver ================= +:link_to_translation:`zh_CN:[中文]` + Overview -------- -{IDF_TARGET_NAME}'s SDMMC host peripheral has two slots. Each slot can be used independently to connect to an SD card, SDIO device or eMMC chip. +{IDF_TARGET_NAME}'s SDMMC host peripheral has two slots. Each slot can be used independently to connect to an SD card, SDIO device, or eMMC chip. .. only:: esp32 @@ -13,44 +15,61 @@ Overview The slots are connected to {IDF_TARGET_NAME} GPIOs using IO MUX. Pin mappings of these slots are given in the table below. - +--------+-------------+-------------+ - | Signal | Slot 0 | Slot 1 | - +========+=============+=============+ - | CMD | GPIO11 | GPIO15 | - +--------+-------------+-------------+ - | CLK | GPIO6 | GPIO14 | - +--------+-------------+-------------+ - | D0 | GPIO7 | GPIO2 | - +--------+-------------+-------------+ - | D1 | GPIO8 | GPIO4 | - +--------+-------------+-------------+ - | D2 | GPIO9 | GPIO12 | - +--------+-------------+-------------+ - | D3 | GPIO10 | GPIO13 | - +--------+-------------+-------------+ - | D4 | GPIO16 | | - +--------+-------------+-------------+ - | D5 | GPIO17 | | - +--------+-------------+-------------+ - | D6 | GPIO5 | | - +--------+-------------+-------------+ - | D7 | GPIO18 | | - +--------+-------------+-------------+ - | CD | any input via GPIO matrix | - +--------+---------------------------+ - | WP | any input via GPIO matrix | - +--------+---------------------------+ - - The Card Detect and Write Protect signals can be routed to arbitrary pins using the GPIO matrix. To reserve the pins, set the ``cd`` and ``wp`` members of the :cpp:class:`sdmmc_slot_config_t` structure before calling :cpp:func:`sdmmc_host_init_slot`. Please note that it is not advised to specify a Card Detect pin when working with SDIO cards, because the card detect signal in ESP32 can also trigger SDIO slave interrupt. + .. list-table:: + :header-rows: 1 + :widths: 20 40 40 + :align: center + + * - Signal + - Slot 0 + - Slot 1 + * - CMD + - GPIO11 + - GPIO15 + * - CLK + - GPIO6 + - GPIO14 + * - D0 + - GPIO7 + - GPIO2 + * - D1 + - GPIO8 + - GPIO4 + * - D2 + - GPIO9 + - GPIO12 + * - D3 + - GPIO10 + - GPIO13 + * - D4 + - GPIO16 + - + * - D5 + - GPIO17 + - + * - D6 + - GPIO5 + - + * - D7 + - GPIO18 + - + * - CD + - any input via GPIO matrix + - any input via GPIO matrix + * - WP + - any input via GPIO matrix + - any input via GPIO matrix + + The Card Detect (CD) and Write Protect (WP) signals can be routed to arbitrary pins using the GPIO matrix. To reserve the pins, set the ``cd`` and ``wp`` members of the :cpp:class:`sdmmc_slot_config_t` structure before calling :cpp:func:`sdmmc_host_init_slot`. Please note that it is not advised to specify a CD pin when working with SDIO cards, because the CD signal in ESP32 can also trigger SDIO slave interrupt. .. warning:: - Pins used by Slot 0 (``HS1_*``) are also used to connect the SPI flash chip in ESP32-WROOM and ESP32-WROVER modules. These pins cannot be shared between an SD card and SPI flash. If you need to use Slot 0, connect SPI flash to different pins and set eFuses accordingly. + Pins used by Slot 0 (``HS1_*``) are also used to connect the SPI flash chip in ESP32-WROOM and ESP32-WROVER modules. These pins cannot be concurrently shared between an SD card and an SPI flash. If you need to use Slot 0, establish an alternative connection for the SPI flash using different pins and configure the necessary eFuses accordingly. .. only:: SOC_SDMMC_USE_GPIO_MATRIX - Both slots (:c:macro:`SDMMC_HOST_SLOT_0`, :c:macro:`SDMMC_HOST_SLOT_1`) support 1-, 4- and 8-line SD interface. The slots are connected to {IDF_TARGET_NAME} GPIOs using GPIO matrix. This means that any GPIO may be used for each of the SD card signals. + Both slots :c:macro:`SDMMC_HOST_SLOT_0` and :c:macro:`SDMMC_HOST_SLOT_1` support 1-, 4- and 8-line SD interfaces. The slots are connected to {IDF_TARGET_NAME} GPIOs using the GPIO matrix. This means that any GPIO may be used for each of the SD card signals. Supported Speed Modes @@ -58,14 +77,14 @@ Supported Speed Modes SDMMC Host driver supports the following speed modes: -- Default Speed (20 MHz), 1-line or 4-line (with SD cards), and 1-line, 4-line or 8-line (with 3.3 V eMMC) -- High Speed (40 MHz), 1-line or 4-line (with SD cards), and 1-line, 4-line or 8-line (with 3.3 V eMMC) -- High Speed DDR (40 MHz), 4-line (with 3.3 V eMMC) +- Default Speed (20 MHz): 1-line or 4-line with SD cards, and 1-line, 4-line, or 8-line with 3.3 V eMMC +- High Speed (40 MHz): 1-line or 4-line with SD cards, and 1-line, 4-line, or 8-line with 3.3 V eMMC +- High Speed DDR (40 MHz): 4-line with 3.3 V eMMC Speed modes not supported at present: -- High Speed DDR mode, 8-line eMMC -- UHS-I 1.8 V modes, 4-line SD cards +- High Speed DDR mode: 8-line eMMC +- UHS-I 1.8 V modes: 4-line SD cards Using the SDMMC Host Driver @@ -87,17 +106,22 @@ Other functions, such as the ones given below, will be called by the SD/MMC prot Configuring Bus Width and Frequency ----------------------------------- -With the default initializers for :cpp:class:`sdmmc_host_t` and :cpp:class:`sdmmc_slot_config_t` (:c:macro:`SDMMC_HOST_DEFAULT` and :c:macro:`SDMMC_SLOT_CONFIG_DEFAULT`), SDMMC Host driver will attempt to use the widest bus supported by the card (4 lines for SD, 8 lines for eMMC) and the frequency of 20 MHz. +With the default initializers for :cpp:class:`sdmmc_host_t` and :cpp:class:`sdmmc_slot_config_t`, i.e., :c:macro:`SDMMC_HOST_DEFAULT` and :c:macro:`SDMMC_SLOT_CONFIG_DEFAULT`, SDMMC Host driver will attempt to use the widest bus supported by the card (4 lines for SD, 8 lines for eMMC) and the frequency of 20 MHz. + +In the designs where communication at 40 MHz frequency can be achieved, it is possible to increase the bus frequency by changing the ``max_freq_khz`` field of :cpp:class:`sdmmc_host_t`: -In the designs where communication at 40 MHz frequency can be achieved, it is possible to increase the bus frequency by changing the ``max_freq_khz`` field of :cpp:class:`sdmmc_host_t`:: +.. code-block:: sdmmc_host_t host = SDMMC_HOST_DEFAULT(); host.max_freq_khz = SDMMC_FREQ_HIGHSPEED; -If you need a specific frequency other than standard speeds, you are free to use any value from within appropriate range of the SD interface given (SDMMC or SDSPI). However, the real clock frequency shall be calculated by the underlying driver and the value can be different from the one required. -For the SDMMC, ``max_freq_khz`` works as the upper limit so the final frequency value shall be always lower or equal. For the SDSPI, the nearest fitting frequency is supplied and thus the value can be greater than / equal to / lower than ``max_freq_khz``. +If you need a specific frequency other than standard speeds, you are free to use any value from within an appropriate range of the SD interface given (SDMMC or SDSPI). However, the real clock frequency shall be calculated by the underlying driver and the value can be different from the one required. + +For the SDMMC, ``max_freq_khz`` works as the upper limit so the final frequency value shall be always lower or equal. For the SDSPI, the nearest fitting frequency is supplied and thus the value can be greater than/equal to/lower than ``max_freq_khz``. -To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_config_t`. For example, to set 1-line mode:: +To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_config_t`. For example, to set 1-line mode: + +.. code-block:: sdmmc_slot_config_t slot = SDMMC_SLOT_CONFIG_DEFAULT(); slot.width = 1; @@ -107,7 +131,11 @@ To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_co Configuring GPIOs ----------------- - {IDF_TARGET_NAME} SDMMC Host can be configured to use arbitrary GPIOs for each of the signals. Configuration is performed by setting members of :cpp:class:`sdmmc_slot_config_t` structure. For example, to use GPIOs 1-6 for CLK, CMD, D0 - D3 signals, respectively:: + {IDF_TARGET_NAME} SDMMC Host can be configured to use arbitrary GPIOs for each of the signals. Configuration is performed by setting members of :cpp:class:`sdmmc_slot_config_t` structure. + + For example, to use GPIOs 1-6 for CLK, CMD, and D0-D3 signals respectively: + + .. code-block:: sdmmc_slot_config_t slot = SDMMC_SLOT_CONFIG_DEFAULT(); slot.clk = GPIO_NUM_1; @@ -117,16 +145,18 @@ To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_co slot.d2 = GPIO_NUM_5; slot.d3 = GPIO_NUM_6; - It is also possible to configure Card Detect and Write Protect pins. Similar to other signals, set ``cd`` and ``wp`` members of the same structure:: + It is also possible to configure Card Detect and Write Protect pins. Similar to other signals, set ``cd`` and ``wp`` members of the same structure: + + .. code-block:: slot.cd = GPIO_NUM_7; slot.wp = GPIO_NUM_8; ``SDMMC_SLOT_CONFIG_DEFAULT`` sets both to ``GPIO_NUM_NC``, meaning that by default the signals are not used. - Once :cpp:class:`sdmmc_slot_config_t` structure is initialized this way, you can use it when calling :cpp:func:`sdmmc_host_init_slot` or one of the higher level functions, such as :cpp:func:`esp_vfs_fat_sdmmc_mount`. + Once :cpp:class:`sdmmc_slot_config_t` structure is initialized this way, you can use it when calling :cpp:func:`sdmmc_host_init_slot` or one of the higher level functions (such as :cpp:func:`esp_vfs_fat_sdmmc_mount`). -DDR Mode for eMMC chips +DDR Mode for eMMC Chips ----------------------- By default, DDR mode will be used if: @@ -134,7 +164,9 @@ By default, DDR mode will be used if: - SDMMC host frequency is set to :c:macro:`SDMMC_FREQ_HIGHSPEED` in :cpp:class:`sdmmc_host_t` structure, and - eMMC chip reports DDR mode support in its CSD register -DDR mode places higher requirements for signal integrity. To disable DDR mode while keeping :c:macro:`SDMMC_FREQ_HIGHSPEED` frequency, clear :c:macro:`SDMMC_HOST_FLAG_DDR` bit in ``flags`` field of :cpp:class:`sdmmc_host_t`:: +DDR mode places higher requirements for signal integrity. To disable DDR mode while keeping the :c:macro:`SDMMC_FREQ_HIGHSPEED` frequency, clear the :c:macro:`SDMMC_HOST_FLAG_DDR` bit in :cpp:member:`sdmmc_host_t::flags` field of the :cpp:class:`sdmmc_host_t`: + +.. code-block:: sdmmc_host_t host = SDMMC_HOST_DEFAULT(); host.max_freq_khz = SDMMC_FREQ_HIGHSPEED; @@ -144,11 +176,9 @@ DDR mode places higher requirements for signal integrity. To disable DDR mode wh See also -------- -See :doc:`SD/SDIO/MMC Driver <../storage/sdmmc>` for the higher level driver which implements the protocol layer. - -See :doc:`SD SPI Host Driver ` for a similar driver which uses the SPI controller and is limited to SD protocol's SPI mode. - -See :doc:`sd_pullup_requirements` for pullup support and compatibilities of modules and development kits. +- :doc:`../storage/sdmmc`: introduces the higher-level driver which implements the protocol layer. +- :doc:`sdspi_host`: introduces a similar driver that uses the SPI controller and is limited to SD protocol's SPI mode. +- :doc:`sd_pullup_requirements`: introduces pull-up support and compatibilities of modules and development kits. API Reference diff --git a/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst b/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst index 888f8c32077..e66b8bb9baa 100644 --- a/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst +++ b/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst @@ -1 +1,187 @@ -.. include:: ../../../en/api-reference/peripherals/sdmmc_host.rst \ No newline at end of file +SDMMC 主机驱动 +================= + +:link_to_translation:`en:[English]` + +概述 +-------- + +{IDF_TARGET_NAME} 的 SDMMC 主机外设共有两个卡槽,用于插入 SD 卡、连接 SDIO 设备或连接 eMMC 芯片,每个卡槽均可单独使用。 + +.. only:: esp32 + + - 卡槽 0 (:c:macro:`SDMMC_HOST_SLOT_0`) 为 8 位卡槽,使用 PIN MUX 中的 ``HS1_*`` 信号。 + - 卡槽 1 (:c:macro:`SDMMC_HOST_SLOT_1`) 为 4 位卡槽,使用 PIN MUX 中的 ``HS2_*`` 信号。 + + 这些卡槽通过 IO MUX 连接到 {IDF_TARGET_NAME} 的 GPIO,其管脚映射如下表所示。 + + .. list-table:: + :header-rows: 1 + :widths: 20 40 40 + :align: center + + * - 信号 + - 卡槽 0 + - 卡槽 1 + * - CMD + - GPIO11 + - GPIO15 + * - CLK + - GPIO6 + - GPIO14 + * - D0 + - GPIO7 + - GPIO2 + * - D1 + - GPIO8 + - GPIO4 + * - D2 + - GPIO9 + - GPIO12 + * - D3 + - GPIO10 + - GPIO13 + * - D4 + - GPIO16 + - + * - D5 + - GPIO17 + - + * - D6 + - GPIO5 + - + * - D7 + - GPIO18 + - + * - CD + - 来自 GPIO 交换矩阵的任意输入 + - 来自 GPIO 交换矩阵的任意输入 + * - WP + - 来自 GPIO 交换矩阵的任意输入 + - 来自 GPIO 交换矩阵的任意输入 + + 可以通过 GPIO 交换矩阵将卡检测 (CD) 和写保护 (WP) 信号路由到任意管脚。为了保留这些管脚,需要先配置 :cpp:class:`sdmmc_slot_config_t` 结构体的 ``cd`` 和 ``wp``,再调用 :cpp:func:`sdmmc_host_init_slot`。注意,使用 SDIO 卡时,不建议指定 CD 管脚,因为 ESP32 中的 CD 信号也可能触发 SDIO 从机设备中断。 + + .. warning:: + + 卡槽 0 使用的管脚 (``HS1_*``) 既用于连接主机上的 SD 卡插槽,也用于连接 ESP32-WROOM 和 ESP32-WROVER 模组中的 SPI flash 芯片,但这些管脚不能同时用于 SD 卡与 SPI flash。如需使用卡槽 0,请将 SPI flash 连接到其他管脚,并根据需要配置 eFuse。 + + +.. only:: SOC_SDMMC_USE_GPIO_MATRIX + + 卡槽 :c:macro:`SDMMC_HOST_SLOT_0` 和 :c:macro:`SDMMC_HOST_SLOT_1` 都支持 1、4、8 线的 SD 接口,这些卡槽通过 GPIO 交换矩阵连接到 {IDF_TARGET_NAME} 的 GPIO,即每个 SD 卡信号都可以使用任意 GPIO 连接。 + + +支持的速率模式 +--------------------- + +SDMMC 主机驱动支持以下速率模式: + +- 默认速率 (20 MHz):对于 SD 卡,支持 1 线或 4 线传输;对于 3.3 V eMMC,支持 1 线、4 线或 8 线传输。 +- 高速模式 (40 MHz):对于 SD 卡,支持 1 线或 4 线传输;对于 3.3 V eMMC,支持 1 线、4 线或 8 线传输。 +- 高速 DDR 模式 (40 MHz):对于 3.3 V eMMC,支持 4 线传输。 + +当前尚不支持的速率模式: + +- 高速 DDR 模式:不支持 8 线 eMMC 传输 +- UHS-I 1.8 V 模式:不支持 4 线 SD 卡传输 + + +使用 SDMMC 主机驱动 +--------------------------- + +在大多数应用程序中,只有下列函数会被直接调用: + +- :cpp:func:`sdmmc_host_init` +- :cpp:func:`sdmmc_host_init_slot` +- :cpp:func:`sdmmc_host_deinit` + +其他函数将通过 :cpp:class:`sdmmc_host_t` 结构体中的函数指针由 SD/MMC 协议层调用,例如: + +- :cpp:func:`sdmmc_host_set_bus_width` +- :cpp:func:`sdmmc_host_set_card_clk` +- :cpp:func:`sdmmc_host_do_transaction` + + +配置总线宽度和频率 +----------------------------------- + +使用 :cpp:class:`sdmmc_host_t` 和 :cpp:class:`sdmmc_slot_config_t` 的默认初始化配置,即 :c:macro:`SDMMC_HOST_DEFAULT` 和 :c:macro:`SDMMC_SLOT_CONFIG_DEFAULT` 时,SDMMC 主机驱动会尝试以当前卡所支持的最大总线宽度进行通信(SD 卡为 4 线,eMMC 为 8 线),并使用 20 MHz 的通信频率。 + +在支持 40 MHz 频率通信的设计中,可以调整 :cpp:class:`sdmmc_host_t` 结构体中的 ``max_freq_khz`` 字段,提升总线频率: + +.. code-block:: + + sdmmc_host_t host = SDMMC_HOST_DEFAULT(); + host.max_freq_khz = SDMMC_FREQ_HIGHSPEED; + +如需选择标准速率以外的特定频率,请根据所使用的 SD 接口(SDMMC 或 SDSPI)确定适当频率范围,并选择其中的任意值。然而,实际的时钟频率会由底层驱动程序计算,可能与你所需的值不同。 + +使用 SDMMC 接口时,``max_freq_khz`` 即频率上限,因此最终的频率值应始终低于该上限。而使用 SDSPI 接口时,驱动程序会提供最接近的适配频率,因此该值可以大于、等于或小于 ``max_freq_khz``。 + +请配置 :cpp:class:`sdmmc_slot_config_t` 的 ``width`` 字段,配置总线宽度。例如,配置 1 线模式的代码如下: + +.. code-block:: + + sdmmc_slot_config_t slot = SDMMC_SLOT_CONFIG_DEFAULT(); + slot.width = 1; + +.. only:: SOC_SDMMC_USE_GPIO_MATRIX + + 配置 GPIO + ----------------- + + 通过配置结构体 :cpp:class:`sdmmc_slot_config_t`,{IDF_TARGET_NAME} 的 SDMMC 主机可以根据需要,为每个信号配置任意的 GPIO 管脚。 + + 例如,使用以下代码,可以将 GPIO 1-6 分别用于 CLK、CMD、D0-D3 信号: + + .. code-block:: + + sdmmc_slot_config_t slot = SDMMC_SLOT_CONFIG_DEFAULT(); + slot.clk = GPIO_NUM_1; + slot.cmd = GPIO_NUM_2; + slot.d0 = GPIO_NUM_3; + slot.d1 = GPIO_NUM_4; + slot.d2 = GPIO_NUM_5; + slot.d3 = GPIO_NUM_6; + + 也可以配置 CD 和 WP 管脚。与配置其他信号的方法类似,你只需配置相同结构体的 ``cd`` 和 ``wp`` 参数: + + .. code-block:: + + slot.cd = GPIO_NUM_7; + slot.wp = GPIO_NUM_8; + + ``SDMMC_SLOT_CONFIG_DEFAULT`` 将 CD 和 WP 管脚都配置为 ``GPIO_NUM_NC``,表明默认情况下不会使用这两个管脚。 + + 通过上述方式初始化 :cpp:class:`sdmmc_slot_config_t` 结构体后,即可在调用 :cpp:func:`sdmmc_host_init_slot` 或其他任意高层函数(如 :cpp:func:`esp_vfs_fat_sdmmc_mount`)时使用该结构体。 + +eMMC 芯片的 DDR 模式 +----------------------- + +默认情况下,如果满足以下条件,将使用 DDR 模式: + +- 在 :cpp:class:`sdmmc_host_t` 结构体中将 SDMMC 主机频率配置为 :c:macro:`SDMMC_FREQ_HIGHSPEED`,且 +- eMMC 芯片在其 CSD 寄存器中报告支持 DDR 模式 + +DDR 模式对信号完整性要求更高。如果要在保持 :c:macro:`SDMMC_FREQ_HIGHSPEED` 频率的同时禁用 DDR 模式,请在 :cpp:class:`sdmmc_host_t` 结构体的 :cpp:member:`sdmmc_host_t::flags` 字段中清除 :c:macro:`SDMMC_HOST_FLAG_DDR` 位: + +.. code-block:: + + sdmmc_host_t host = SDMMC_HOST_DEFAULT(); + host.max_freq_khz = SDMMC_FREQ_HIGHSPEED; + host.flags &= ~SDMMC_HOST_FLAG_DDR; + + +相关文档 +-------- + +- :doc:`../storage/sdmmc`:介绍了实现协议层的高层驱动程序。 +- :doc:`sdspi_host`:介绍了一种类似驱动,该驱动使用 SPI 控制器且受限于 SD 协议的 SPI 模式。 +- :doc:`sd_pullup_requirements` 介绍了模组和开发套件上的上拉支持和兼容信息。 + + +API 参考 +------------- + +.. include-build-file:: inc/sdmmc_host.inc From 3265bab95f4d358b5393b22f10200911654a2666 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Fri, 15 Sep 2023 19:49:24 +0800 Subject: [PATCH 56/71] fix(temperature_snesor): Put clock gate enable/disable in to sar_periph_ctrl together --- components/driver/deprecated/rtc_temperature_legacy.c | 4 ---- .../driver/temperature_sensor/temperature_sensor.c | 6 ------ components/esp_hw_support/sar_periph_ctrl_common.c | 9 +++++++++ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/components/driver/deprecated/rtc_temperature_legacy.c b/components/driver/deprecated/rtc_temperature_legacy.c index 1e162c127e9..97e700fa804 100644 --- a/components/driver/deprecated/rtc_temperature_legacy.c +++ b/components/driver/deprecated/rtc_temperature_legacy.c @@ -94,10 +94,7 @@ esp_err_t temp_sensor_start(void) ESP_LOGE(TAG, "Is already running or not be configured"); err = ESP_ERR_INVALID_STATE; } - regi2c_saradc_enable(); - periph_module_enable(PERIPH_TEMPSENSOR_MODULE); temperature_sensor_power_acquire(); - temperature_sensor_ll_clk_enable(true); temperature_sensor_ll_clk_sel(TEMPERATURE_SENSOR_CLK_SRC_DEFAULT); tsens_hw_state = TSENS_HW_STATE_STARTED; return err; @@ -105,7 +102,6 @@ esp_err_t temp_sensor_start(void) esp_err_t temp_sensor_stop(void) { - regi2c_saradc_disable(); temperature_sensor_power_release(); tsens_hw_state = TSENS_HW_STATE_CONFIGURED; return ESP_OK; diff --git a/components/driver/temperature_sensor/temperature_sensor.c b/components/driver/temperature_sensor/temperature_sensor.c index 1720b9b92cf..51d5e59e1d8 100644 --- a/components/driver/temperature_sensor/temperature_sensor.c +++ b/components/driver/temperature_sensor/temperature_sensor.c @@ -104,8 +104,6 @@ esp_err_t temperature_sensor_install(const temperature_sensor_config_t *tsens_co ESP_GOTO_ON_FALSE(tsens != NULL, ESP_ERR_NO_MEM, err, TAG, "no mem for temp sensor"); tsens->clk_src = tsens_config->clk_src; - periph_module_enable(PERIPH_TEMPSENSOR_MODULE); - periph_module_reset(PERIPH_TEMPSENSOR_MODULE); ESP_GOTO_ON_ERROR(temperature_sensor_attribute_table_sort(), err, TAG, "Table sort failed"); ESP_GOTO_ON_ERROR(temperature_sensor_choose_best_range(tsens, tsens_config), err, TAG, "Cannot select the correct range"); @@ -114,7 +112,6 @@ esp_err_t temperature_sensor_install(const temperature_sensor_config_t *tsens_co tsens->tsens_attribute->range_max, tsens->tsens_attribute->error_max); - regi2c_saradc_enable(); temperature_sensor_ll_set_range(tsens->tsens_attribute->reg_val); tsens->fsm = TEMP_SENSOR_FSM_INIT; @@ -134,7 +131,6 @@ esp_err_t temperature_sensor_uninstall(temperature_sensor_handle_t tsens) free(s_tsens_attribute_copy); } s_tsens_attribute_copy = NULL; - regi2c_saradc_disable(); #if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT temperature_sensor_ll_enable_intr(false); @@ -143,7 +139,6 @@ esp_err_t temperature_sensor_uninstall(temperature_sensor_handle_t tsens) } #endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT - periph_module_disable(PERIPH_TEMPSENSOR_MODULE); free(tsens); return ESP_OK; } @@ -178,7 +173,6 @@ esp_err_t temperature_sensor_enable(temperature_sensor_handle_t tsens) temperature_sensor_ll_sample_enable(true); #endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT - temperature_sensor_ll_clk_enable(true); temperature_sensor_ll_clk_sel(tsens->clk_src); temperature_sensor_power_acquire(); tsens->fsm = TEMP_SENSOR_FSM_ENABLE; diff --git a/components/esp_hw_support/sar_periph_ctrl_common.c b/components/esp_hw_support/sar_periph_ctrl_common.c index b8776b39e60..1173a82cefd 100644 --- a/components/esp_hw_support/sar_periph_ctrl_common.c +++ b/components/esp_hw_support/sar_periph_ctrl_common.c @@ -13,6 +13,8 @@ #if SOC_TEMP_SENSOR_SUPPORTED #include "hal/temperature_sensor_ll.h" #include "soc/temperature_sensor_periph.h" +#include "soc/periph_defs.h" +#include "esp_private/periph_ctrl.h" extern __attribute__((unused)) portMUX_TYPE rtc_spinlock; @@ -35,6 +37,10 @@ void temperature_sensor_power_acquire(void) portENTER_CRITICAL(&rtc_spinlock); s_temperature_sensor_power_cnt++; if (s_temperature_sensor_power_cnt == 1) { + periph_module_enable(PERIPH_TEMPSENSOR_MODULE); + periph_module_reset(PERIPH_TEMPSENSOR_MODULE); + regi2c_saradc_enable(); + temperature_sensor_ll_clk_enable(true); temperature_sensor_ll_enable(true); } portEXIT_CRITICAL(&rtc_spinlock); @@ -50,7 +56,10 @@ void temperature_sensor_power_release(void) ESP_LOGE(TAG_TSENS, "%s called, but s_temperature_sensor_power_cnt == 0", __func__); abort(); } else if (s_temperature_sensor_power_cnt == 0) { + temperature_sensor_ll_clk_enable(false); temperature_sensor_ll_enable(false); + regi2c_saradc_disable(); + periph_module_disable(PERIPH_TEMPSENSOR_MODULE); } portEXIT_CRITICAL(&rtc_spinlock); } From 4705995b69a20d3601ee71ecee312b39ae4e6327 Mon Sep 17 00:00:00 2001 From: chenqingqing Date: Mon, 18 Sep 2023 17:00:28 +0800 Subject: [PATCH 57/71] fix(bt/bluedroid): Fix the judgment condition for packet transmission status statistics --- components/bt/host/bluedroid/stack/btm/btm_sco.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_sco.c b/components/bt/host/bluedroid/stack/btm/btm_sco.c index 8431a7d77b6..6496560b33c 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sco.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sco.c @@ -379,7 +379,7 @@ static void btm_pkt_stat_send_nums_update(uint16_t sco_inx, uint8_t pkt_status) { tSCO_CONN *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx]; p_ccb->pkt_stat_nums.tx_total++; - if (pkt_status != BTM_SUCCESS) { + if (pkt_status != BTM_SUCCESS && pkt_status != BTM_NO_RESOURCES && pkt_status != BTM_SCO_BAD_LENGTH) { p_ccb->pkt_stat_nums.tx_discarded++; } } @@ -534,7 +534,7 @@ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf) status = BTM_UNKNOWN_ADDR; } - if (status != BTM_SUCCESS && status!= BTM_NO_RESOURCES) { + if (status != BTM_SUCCESS && status!= BTM_NO_RESOURCES && status != BTM_SCO_BAD_LENGTH) { BTM_TRACE_WARNING ("stat %d", status); osi_free(p_buf); } From dcb714e7967468219c75899c9a9898bf42c6cf87 Mon Sep 17 00:00:00 2001 From: shangke Date: Mon, 18 Sep 2023 12:06:19 +0800 Subject: [PATCH 58/71] fix(bt/controller): Fixed some HCI commands parameter 1: add param check for HCI_Recevie_Synchronization_Train. 2: add param check for HCI_Set_Connectionless_Peripheral_Broadcast. 3: fix slave cannot take a secure authentication. --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index ffa102a7565..19fa60b819d 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit ffa102a7565dde12510b03d36b616ff9749fe1ad +Subproject commit 19fa60b819db1e3bb8a07790f819b69657e4ae3f From 55767ea855c2f5ffcb130a8fea47fafde4835506 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Wed, 20 Sep 2023 08:47:53 +0530 Subject: [PATCH 59/71] remove(nimble): Removed unused coex header inclusion --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index da4bcac49f6..48bb80dab7f 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit da4bcac49f6ee4d874bacb7bc6fd6f5e24155d2f +Subproject commit 48bb80dab7f0e5c6e5a2da09357896edd260b6e4 From c79c16a73e5a879d6c91055c815504676aed4699 Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Thu, 21 Sep 2023 12:59:09 +0200 Subject: [PATCH 60/71] ci: fix cleanup_ignore_lists.py on windows --- tools/ci/cleanup_ignore_lists.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/ci/cleanup_ignore_lists.py b/tools/ci/cleanup_ignore_lists.py index 94aebd13862..68f718f40dd 100755 --- a/tools/ci/cleanup_ignore_lists.py +++ b/tools/ci/cleanup_ignore_lists.py @@ -6,11 +6,12 @@ import glob import os import typing as t +from pathlib import Path from idf_ci_utils import IDF_PATH -def print_list(_list: t.Iterable[str], title: t.Optional[str] = None) -> None: +def print_list(_list: t.Iterable[t.Any], title: t.Optional[str] = None) -> None: if not _list: return @@ -18,15 +19,16 @@ def print_list(_list: t.Iterable[str], title: t.Optional[str] = None) -> None: print(title) for i in _list: - print('- ', i) + print('- ', str(i)) if __name__ == '__main__': os.chdir(IDF_PATH) - ignore_lists = set() - ignore_lists.update(glob.glob('tools/ci/*.txt', recursive=True)) - ignore_lists.remove('tools/ci/ignore_build_warnings.txt') - ignore_lists.remove('tools/ci/check_ldgen_mapping_exceptions.txt') + ignore_lists: t.Set[Path] = set() + ignore_lists.update(Path('tools', 'ci').glob('**/*.txt')) + ignore_lists.remove(Path('tools', 'ci', 'ignore_build_warnings.txt')) + ignore_lists.remove(Path('tools', 'ci', 'check_ldgen_mapping_exceptions.txt')) + print_list(ignore_lists, 'Ignore lists:') updated_files = [] From 9acd3b785664552e87b48ae5b0160cf5693c3809 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 19 Sep 2023 17:18:39 +0200 Subject: [PATCH 61/71] feat(perfmon): migrate the tests from unit-test-app --- components/perfmon/test/CMakeLists.txt | 10 - components/perfmon/test/test_perfmon_ansi.c | 184 ------------------ .../perfmon/test_apps/.build-test-rules.yml | 6 + components/perfmon/test_apps/CMakeLists.txt | 9 + components/perfmon/test_apps/README.md | 19 ++ .../perfmon/test_apps/main/CMakeLists.txt | 4 + .../perfmon/test_apps/main/test_perfmon.c | 178 +++++++++++++++++ .../test_apps/main/test_perfmon_main.c | 48 +++++ .../perfmon/test_apps/pytest_perfmon_ut.py | 13 ++ .../perfmon/test_apps/sdkconfig.defaults | 1 + 10 files changed, 278 insertions(+), 194 deletions(-) delete mode 100644 components/perfmon/test/CMakeLists.txt delete mode 100644 components/perfmon/test/test_perfmon_ansi.c create mode 100644 components/perfmon/test_apps/.build-test-rules.yml create mode 100644 components/perfmon/test_apps/CMakeLists.txt create mode 100644 components/perfmon/test_apps/README.md create mode 100644 components/perfmon/test_apps/main/CMakeLists.txt create mode 100644 components/perfmon/test_apps/main/test_perfmon.c create mode 100644 components/perfmon/test_apps/main/test_perfmon_main.c create mode 100644 components/perfmon/test_apps/pytest_perfmon_ut.py create mode 100644 components/perfmon/test_apps/sdkconfig.defaults diff --git a/components/perfmon/test/CMakeLists.txt b/components/perfmon/test/CMakeLists.txt deleted file mode 100644 index c4a984da44f..00000000000 --- a/components/perfmon/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -if(CONFIG_IDF_TARGET_ARCH_XTENSA) - list(APPEND src_dirs .) -endif() - -idf_component_register(SRC_DIRS ${src_dirs} - PRIV_INCLUDE_DIRS "." - PRIV_REQUIRES cmock xtensa perfmon) -if(CONFIG_IDF_TARGET_ARCH_XTENSA) - target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") -endif() diff --git a/components/perfmon/test/test_perfmon_ansi.c b/components/perfmon/test/test_perfmon_ansi.c deleted file mode 100644 index f8f09022b89..00000000000 --- a/components/perfmon/test/test_perfmon_ansi.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "unity.h" -#include "esp_log.h" -#include - -#include "perfmon.h" - -// These includes required only for the tests -#include "xtensa-debug-module.h" -#include "eri.h" - -static const char *TAG = "perfmon"; - - -TEST_CASE("Perfomance counter dump", "[perfmon]") -{ - - xtensa_perfmon_dump(); - xtensa_perfmon_stop(); - xtensa_perfmon_dump(); - xtensa_perfmon_init(0, 0, 0xffff, 0, 6); - xtensa_perfmon_dump(); - xtensa_perfmon_reset(0); - xtensa_perfmon_start(); - int pm_data[10]; - for (int i = 0 ; i < 10 ; i++) { - if (i == 4) { - xtensa_perfmon_reset(0); - xtensa_perfmon_start(); - } - if (i == 6) { - xtensa_perfmon_stop(); - } - if (i == 8) { - xtensa_perfmon_start(); - } - pm_data[i] = eri_read(ERI_PERFMON_PM0); - } - for (int i = 0 ; i < 10 ; i++) { - ESP_LOGI(TAG, "pm_data[%i]= %08x", i, pm_data[i]); - } - if (pm_data[4] > pm_data[3]) { - ESP_LOGE(TAG, "The functions xtensa_perfmon_reset and xtensa_perfmon_start are not working correct."); - ESP_LOGW(TAG, "pm_data[3]= %i, must be > pm_data[4]= %i", pm_data[3], pm_data[4]); - TEST_ESP_OK(ESP_FAIL); - } - if ( pm_data[6] != pm_data[7]) { - ESP_LOGE(TAG, "The xtensa_perfmon_stop functions is not working correct."); - ESP_LOGW(TAG, "pm_data[6]= %i, must be == pm_data[7]= %i", pm_data[6], pm_data[7]); - TEST_ESP_OK(ESP_FAIL); - } - if ( pm_data[7] == pm_data[8]) { - ESP_LOGE(TAG, "The xtensa_perfmon_start functions is not working correct."); - ESP_LOGW(TAG, "pm_data[7]= %i, must be < pm_data[8]= %i", pm_data[7], pm_data[8]); - TEST_ESP_OK(ESP_FAIL); - } - - xtensa_perfmon_stop(); -} - -static void test_call(void* params) -{ - for (int i = 0 ; i < 1000 ; i++) { - __asm__ __volatile__(" nop"); - } -} - -static bool callback_called = false; -static int callback_call_count = 0; -static void test_callback(void *params, uint32_t select, uint32_t mask, uint32_t value) -{ - ESP_LOGI("test", "test_callback select = %i, mask = %i, value = %i", select, mask, value); - callback_called = true; - callback_call_count++; -} - -TEST_CASE("Performacnce test callback", "[perfmon]") -{ - ESP_LOGI(TAG, "Initialize performance structure"); - xtensa_perfmon_config_t pm_config = {}; - pm_config.counters_size = sizeof(xtensa_perfmon_select_mask_all) / sizeof(uint32_t) / 2; - pm_config.select_mask = xtensa_perfmon_select_mask_all; - pm_config.repeat_count = 200; - pm_config.max_deviation = 1; - pm_config.call_function = test_call; - pm_config.callback = test_callback; - pm_config.callback_params = stdout; - pm_config.tracelevel = -1; // Trace all events - callback_called = false; - callback_call_count = 0; - xtensa_perfmon_exec(&pm_config); - - ESP_LOGI(TAG, "Callback count = %i", callback_call_count); - if (callback_call_count != pm_config.counters_size) { - ESP_LOGE(TAG, "The callback count is not correct."); - ESP_LOGW(TAG, "callback_call_count= %i, must be == pm_config.counters_size= %i", callback_call_count, pm_config.counters_size); - TEST_ESP_OK(ESP_FAIL); - } - if (ESP_OK != xtensa_perfmon_overflow(0)) - { - ESP_LOGE(TAG, "Perfmon 0 overflow detected!"); - TEST_ESP_OK(ESP_FAIL); - } - if (ESP_OK != xtensa_perfmon_overflow(1)) - { - ESP_LOGE(TAG, "Perfmon 1 overflow detected!"); - TEST_ESP_OK(ESP_FAIL); - } - if (false == callback_called) { - TEST_ESP_OK(ESP_FAIL); - } -} - -static void exec_callback(void *params) -{ - for (int i = 0 ; i < 100 ; i++) { - __asm__ __volatile__(" nop"); - } -} - -static const uint32_t test_dsp_table[] = { - XTPERF_CNT_CYCLES, XTPERF_MASK_CYCLES, // total cycles - XTPERF_CNT_INSN, XTPERF_MASK_INSN_ALL, // total instructions - XTPERF_CNT_D_LOAD_U1, XTPERF_MASK_D_LOAD_LOCAL_MEM, // Mem read - XTPERF_CNT_D_STORE_U1, XTPERF_MASK_D_STORE_LOCAL_MEM, // Mem write - XTPERF_CNT_BUBBLES, XTPERF_MASK_BUBBLES_ALL &(~XTPERF_MASK_BUBBLES_R_HOLD_REG_DEP), // wait for other reasons - XTPERF_CNT_BUBBLES, XTPERF_MASK_BUBBLES_R_HOLD_REG_DEP, // Wait for register dependency - XTPERF_CNT_OVERFLOW, XTPERF_MASK_OVERFLOW, // Last test cycle -}; - -TEST_CASE("Performance test for Empty callback", "[perfmon]") -{ - for (int i = 5 ; i < 10 ; i++) { - exec_callback(NULL); - ESP_LOGD(TAG, "Empty call passed."); - } - - ESP_LOGI(TAG, "Start first test"); - xtensa_perfmon_config_t pm_config = {}; - pm_config.counters_size = sizeof(xtensa_perfmon_select_mask_all) / sizeof(uint32_t) / 2; - pm_config.select_mask = xtensa_perfmon_select_mask_all; - pm_config.repeat_count = 200; - pm_config.max_deviation = 1; - pm_config.call_function = exec_callback; - pm_config.callback = xtensa_perfmon_view_cb; - pm_config.callback_params = stdout; - pm_config.tracelevel = -1; - - xtensa_perfmon_exec(&pm_config); - callback_call_count = 0; - ESP_LOGI(TAG, "Start second test"); - pm_config.counters_size = sizeof(test_dsp_table) / sizeof(uint32_t) / 2; - pm_config.select_mask = test_dsp_table; - pm_config.repeat_count = 200; - pm_config.max_deviation = 1; - pm_config.call_function = exec_callback; - pm_config.callback = xtensa_perfmon_view_cb; - pm_config.callback_params = stdout; - pm_config.tracelevel = -1; - - xtensa_perfmon_exec(&pm_config); - callback_call_count = 0; - ESP_LOGI(TAG, "Start third test"); - pm_config.counters_size = sizeof(test_dsp_table) / sizeof(uint32_t) / 2; - pm_config.select_mask = test_dsp_table; - pm_config.repeat_count = 200; - pm_config.max_deviation = 1; - pm_config.call_function = exec_callback; - pm_config.callback = test_callback; - pm_config.callback_params = stdout; - pm_config.tracelevel = -1; - - xtensa_perfmon_exec(&pm_config); - if (callback_call_count != pm_config.counters_size) { - TEST_ESP_OK(ESP_FAIL); - } - ESP_LOGI(TAG, "All tests passed."); -} diff --git a/components/perfmon/test_apps/.build-test-rules.yml b/components/perfmon/test_apps/.build-test-rules.yml new file mode 100644 index 00000000000..f89ac8c2692 --- /dev/null +++ b/components/perfmon/test_apps/.build-test-rules.yml @@ -0,0 +1,6 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/perfmon/test_apps: + enable: + - if: IDF_TARGET in ["esp32", "esp32s2", "esp32s3"] + reason: Perfmon is only supported on Xtensa diff --git a/components/perfmon/test_apps/CMakeLists.txt b/components/perfmon/test_apps/CMakeLists.txt new file mode 100644 index 00000000000..b9d294924a3 --- /dev/null +++ b/components/perfmon/test_apps/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) +list(PREPEND SDKCONFIG_DEFAULTS + "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" + "sdkconfig.defaults") + +project(perfmon_test) diff --git a/components/perfmon/test_apps/README.md b/components/perfmon/test_apps/README.md new file mode 100644 index 00000000000..b6a2613b40e --- /dev/null +++ b/components/perfmon/test_apps/README.md @@ -0,0 +1,19 @@ +| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | + +# Perfmon test + +To build and run this test app, using esp32s3 target for example: + +```bash +idf.py set-target esp32s3 +idf.py build flash monitor +``` + +To run tests using pytest: + +```bash +idf.py set-target esp32s3 +idf.py build +pytest --target=esp32s3 +``` diff --git a/components/perfmon/test_apps/main/CMakeLists.txt b/components/perfmon/test_apps/main/CMakeLists.txt new file mode 100644 index 00000000000..eb7cda692da --- /dev/null +++ b/components/perfmon/test_apps/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "test_perfmon_main.c" "test_perfmon.c" + INCLUDE_DIRS "." + PRIV_REQUIRES perfmon xtensa unity + WHOLE_ARCHIVE) diff --git a/components/perfmon/test_apps/main/test_perfmon.c b/components/perfmon/test_apps/main/test_perfmon.c new file mode 100644 index 00000000000..f061365c100 --- /dev/null +++ b/components/perfmon/test_apps/main/test_perfmon.c @@ -0,0 +1,178 @@ +/* + * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "esp_log.h" +#include "perfmon.h" +#include "unity.h" + +#include "xtensa-debug-module.h" +#include "eri.h" +#include "xtensa_perfmon_access.h" + +static const char *TAG = "perfmon"; + +static void delay(void) +{ + for (int i = 0 ; i < 1000 ; i++) { + __asm__ __volatile__("nop"); + } +} + +TEST_CASE("Start/stop/reset sanity check", "[perfmon]") +{ + xtensa_perfmon_stop(); + xtensa_perfmon_init(0, 0, 0xffff, 0, 6); + + xtensa_perfmon_reset(0); + delay(); + uint32_t count_0 = eri_read(ERI_PERFMON_PM0); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(0, count_0, "Counter should be 0 after reset"); + + xtensa_perfmon_start(); + delay(); + uint32_t count_1 = eri_read(ERI_PERFMON_PM0); + TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(0, count_1, "Counter should not be 0 after start"); + + xtensa_perfmon_stop(); + uint32_t count_2 = eri_read(ERI_PERFMON_PM0); + delay(); + uint32_t count_3 = eri_read(ERI_PERFMON_PM0); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(count_2, count_3, "Counter should not change after stop"); + + xtensa_perfmon_reset(0); + xtensa_perfmon_start(); + delay(); + delay(); + uint32_t count_4 = eri_read(ERI_PERFMON_PM0); + TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(count_1, count_4, "Counter should be greater when delay is longer"); + + xtensa_perfmon_stop(); +} + +static void test_call(void *params) +{ + delay(); +} + +static void test_callback(void *params, uint32_t select, uint32_t mask, uint32_t value) +{ + int *call_count = (int *)params; + ESP_LOGI(TAG, "%s: select=%" PRIu32 ", mask=%" PRIx32 ", value=%" PRIu32, + __func__, select, mask, value); + (*call_count)++; +} + +TEST_CASE("xtensa_perfmon_exec custom callback", "[perfmon]") +{ + int num_counters = sizeof(xtensa_perfmon_select_mask_all) / sizeof(xtensa_perfmon_select_mask_all[0]) / 2; + int callback_call_count = 0; + xtensa_perfmon_config_t pm_config = { + .counters_size = num_counters, + .select_mask = xtensa_perfmon_select_mask_all, + .repeat_count = 200, + .max_deviation = 1, + .call_function = test_call, + .call_params = NULL, + .callback = test_callback, + .callback_params = &callback_call_count, + .tracelevel = -1 + }; + TEST_ESP_OK(xtensa_perfmon_exec(&pm_config)); + + TEST_ASSERT_NOT_EQUAL_MESSAGE(0, callback_call_count, "Callback should be called at least once"); + // Performance counters should not have overflow status set + TEST_ESP_OK(xtensa_perfmon_overflow(0)); + TEST_ESP_OK(xtensa_perfmon_overflow(1)); + TEST_ASSERT_EQUAL_MESSAGE(num_counters, callback_call_count, + "Callback should be called once for every counter"); +} + +TEST_CASE("xtensa_perfmon_view_cb test", "[perfmon]") +{ + const uint32_t test_table[] = { + XTPERF_CNT_CYCLES, XTPERF_MASK_CYCLES, // total cycles + XTPERF_CNT_INSN, XTPERF_MASK_INSN_ALL, // total instructions + XTPERF_CNT_D_LOAD_U1, XTPERF_MASK_D_LOAD_LOCAL_MEM, // Mem read + XTPERF_CNT_D_STORE_U1, XTPERF_MASK_D_STORE_LOCAL_MEM, // Mem write + XTPERF_CNT_BUBBLES, XTPERF_MASK_BUBBLES_ALL &(~XTPERF_MASK_BUBBLES_R_HOLD_REG_DEP), // wait for other reasons + XTPERF_CNT_BUBBLES, XTPERF_MASK_BUBBLES_R_HOLD_REG_DEP, // Wait for register dependency + XTPERF_CNT_OVERFLOW, XTPERF_MASK_OVERFLOW, // Last test cycle + }; + int num_counters = sizeof(test_table) / sizeof(test_table[0]) / 2; + + // We will collect the output of xtensa_perfmon_view_cb in a string + // and check that the output matches the counters table above. + char *out_str = NULL; + size_t out_len = 0; + FILE *out_stream = open_memstream(&out_str, &out_len); + + xtensa_perfmon_config_t pm_config = { + .counters_size = num_counters, + .select_mask = test_table, + .repeat_count = 200, + .max_deviation = 1, + .call_function = test_call, + .call_params = NULL, + .callback = xtensa_perfmon_view_cb, + .callback_params = out_stream, + .tracelevel = -1, + }; + + TEST_ESP_OK(xtensa_perfmon_exec(&pm_config)); + fclose(out_stream); + + TEST_ASSERT_MESSAGE(strlen(out_str) > 0, "xtensa_perfmon_view_cb should print something"); + // Check that performance counters defined in test_table are present in the output: + const char *p = out_str; + + // 1. XTPERF_CNT_CYCLES + p = strstr(p, "Value ="); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "Counts cycles."); + TEST_ASSERT_NOT_NULL(p); + + // 2. XTPERF_CNT_INSN + p = strstr(p, "Value ="); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "Successfully Retired Instructions."); + + // 3. XTPERF_CNT_D_LOAD_U1 + p = strstr(p, "Value ="); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "Load Instruction (Data Memory)."); + + // 4. XTPERF_CNT_D_STORE_U1 + p = strstr(p, "Value ="); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "Store Instruction (Data Memory)."); + TEST_ASSERT_NOT_NULL(p); + + // 5. XTPERF_CNT_BUBBLES + p = strstr(p, "Value ="); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "Hold and Other Bubble cycles."); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "CTI bubble (e.g. branch delay slot)"); + + // 6. XTPERF_CNT_BUBBLES (with a different mask) + p = strstr(p, "Value ="); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "Hold and Other Bubble cycles."); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "R hold caused by register dependency"); + + // 7. XTPERF_CNT_OVERFLOW + p = strstr(p, "Value ="); + TEST_ASSERT_NOT_NULL(p); + p = strstr(p, "Overflow counter"); + TEST_ASSERT_NOT_NULL(p); + + free(out_str); +} diff --git a/components/perfmon/test_apps/main/test_perfmon_main.c b/components/perfmon/test_apps/main/test_perfmon_main.c new file mode 100644 index 00000000000..656bf5596c7 --- /dev/null +++ b/components/perfmon/test_apps/main/test_perfmon_main.c @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT 0 +static int leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +void set_leak_threshold(int threshold) +{ + leak_threshold = threshold; +} + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= leak_threshold, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); + + leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +} + +void app_main(void) +{ + printf("Running perfmon component tests\n"); + unity_run_menu(); +} diff --git a/components/perfmon/test_apps/pytest_perfmon_ut.py b/components/perfmon/test_apps/pytest_perfmon_ut.py new file mode 100644 index 00000000000..32adeee597e --- /dev/null +++ b/components/perfmon/test_apps/pytest_perfmon_ut.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.generic +@pytest.mark.esp32 +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +def test_perfmon_ut(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/perfmon/test_apps/sdkconfig.defaults b/components/perfmon/test_apps/sdkconfig.defaults new file mode 100644 index 00000000000..7b569fa0755 --- /dev/null +++ b/components/perfmon/test_apps/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n From 9e20bf4f069d349fc12e0f241cda9cbf2013e03e Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 20 Sep 2023 13:23:47 +0200 Subject: [PATCH 62/71] feat(esp_hid): migrate the tests from unit-test-app --- components/esp_hid/test/CMakeLists.txt | 4 -- .../esp_hid/test_apps/.build-test-rules.yml | 8 ++++ components/esp_hid/test_apps/CMakeLists.txt | 9 ++++ .../esp_hid/{test => test_apps}/README.md | 26 +++++++++- .../esp_hid/test_apps/main/CMakeLists.txt | 4 ++ .../{test => test_apps/main}/hid_descriptor.h | 19 +++----- .../{test => test_apps/main}/test_esp_hid.c | 19 ++------ .../test_apps/main/test_esp_hid_main.c | 48 +++++++++++++++++++ .../esp_hid/test_apps/pytest_esp_hid.py | 12 +++++ .../esp_hid/test_apps/sdkconfig.defaults | 1 + tools/ci/check_copyright_ignore.txt | 2 - 11 files changed, 118 insertions(+), 34 deletions(-) delete mode 100644 components/esp_hid/test/CMakeLists.txt create mode 100644 components/esp_hid/test_apps/.build-test-rules.yml create mode 100644 components/esp_hid/test_apps/CMakeLists.txt rename components/esp_hid/{test => test_apps}/README.md (69%) create mode 100644 components/esp_hid/test_apps/main/CMakeLists.txt rename components/esp_hid/{test => test_apps/main}/hid_descriptor.h (96%) rename components/esp_hid/{test => test_apps/main}/test_esp_hid.c (94%) create mode 100644 components/esp_hid/test_apps/main/test_esp_hid_main.c create mode 100644 components/esp_hid/test_apps/pytest_esp_hid.py create mode 100644 components/esp_hid/test_apps/sdkconfig.defaults diff --git a/components/esp_hid/test/CMakeLists.txt b/components/esp_hid/test/CMakeLists.txt deleted file mode 100644 index fa7a4e5216f..00000000000 --- a/components/esp_hid/test/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -idf_component_register(SRC_DIRS "." - INCLUDE_DIRS "." - REQUIRES cmock test_utils esp_hid) -target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/esp_hid/test_apps/.build-test-rules.yml b/components/esp_hid/test_apps/.build-test-rules.yml new file mode 100644 index 00000000000..452d163e2db --- /dev/null +++ b/components/esp_hid/test_apps/.build-test-rules.yml @@ -0,0 +1,8 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/esp_hid/test_apps: + enable: + - if: IDF_TARGET in ["esp32", "esp32c3"] + reason: Testing on one chip per architecture is currently enough + depends_components: + - esp_hid diff --git a/components/esp_hid/test_apps/CMakeLists.txt b/components/esp_hid/test_apps/CMakeLists.txt new file mode 100644 index 00000000000..48539b92f26 --- /dev/null +++ b/components/esp_hid/test_apps/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) +list(PREPEND SDKCONFIG_DEFAULTS + "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" + "sdkconfig.defaults") + +project(esp_hid_test) diff --git a/components/esp_hid/test/README.md b/components/esp_hid/test_apps/README.md similarity index 69% rename from components/esp_hid/test/README.md rename to components/esp_hid/test_apps/README.md index 1a3fb7d9091..f9ee4bcefb6 100644 --- a/components/esp_hid/test/README.md +++ b/components/esp_hid/test_apps/README.md @@ -1,4 +1,28 @@ -### Tests have been generated with the following code +| Supported Targets | ESP32 | ESP32-C3 | +| ----------------- | ----- | -------- | + +# esp_hid unit tests + +The unit tests are currently run only on the chips listed above just to save CI resources. If you are adding some tests which need to run on a different chip, update [.build-test-rules.yml](../.build-test-rules.yml), adding the chip you need. + +When adding new test cases, check if the `depends_components` list in `.build-test-rules.yml` needs to be updated to include additional components. The test app will only be built and tested when these components are modified. + +To build and run this test app, using esp32c3 target for example: + +```bash +idf.py set-target esp32c3 +idf.py build flash monitor +``` + +To run tests using pytest: + +```bash +idf.py set-target esp32c3 +idf.py build +pytest --target=esp32c3 +``` + +### Code used to generate tests ```c diff --git a/components/esp_hid/test_apps/main/CMakeLists.txt b/components/esp_hid/test_apps/main/CMakeLists.txt new file mode 100644 index 00000000000..90b84e9d667 --- /dev/null +++ b/components/esp_hid/test_apps/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "test_esp_hid_main.c" + "test_esp_hid.c" + PRIV_REQUIRES unity esp_hid + WHOLE_ARCHIVE) diff --git a/components/esp_hid/test/hid_descriptor.h b/components/esp_hid/test_apps/main/hid_descriptor.h similarity index 96% rename from components/esp_hid/test/hid_descriptor.h rename to components/esp_hid/test_apps/main/hid_descriptor.h index 56142d001a8..2b7172ed291 100644 --- a/components/esp_hid/test/hid_descriptor.h +++ b/components/esp_hid/test_apps/main/hid_descriptor.h @@ -1,16 +1,9 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + #pragma once const unsigned char hidReportMap[] = { diff --git a/components/esp_hid/test/test_esp_hid.c b/components/esp_hid/test_apps/main/test_esp_hid.c similarity index 94% rename from components/esp_hid/test/test_esp_hid.c rename to components/esp_hid/test_apps/main/test_esp_hid.c index db9b0d10af2..4f9eb213eb2 100644 --- a/components/esp_hid/test/test_esp_hid.c +++ b/components/esp_hid/test_apps/main/test_esp_hid.c @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include @@ -18,7 +10,6 @@ #include #include "unity.h" #include "unity_test_runner.h" -#include "test_utils.h" #include "esp_log.h" #include "esp_hid_common.h" #include "hid_descriptor.h" diff --git a/components/esp_hid/test_apps/main/test_esp_hid_main.c b/components/esp_hid/test_apps/main/test_esp_hid_main.c new file mode 100644 index 00000000000..62fdec99476 --- /dev/null +++ b/components/esp_hid/test_apps/main/test_esp_hid_main.c @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT 0 +static int leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +void set_leak_threshold(int threshold) +{ + leak_threshold = threshold; +} + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= leak_threshold, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); + + leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +} + +void app_main(void) +{ + printf("Running esp_hid component tests\n"); + unity_run_menu(); +} diff --git a/components/esp_hid/test_apps/pytest_esp_hid.py b/components/esp_hid/test_apps/pytest_esp_hid.py new file mode 100644 index 00000000000..664e29bf6fa --- /dev/null +++ b/components/esp_hid/test_apps/pytest_esp_hid.py @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.generic +@pytest.mark.esp32 +@pytest.mark.esp32c3 +def test_esp_hid(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_hid/test_apps/sdkconfig.defaults b/components/esp_hid/test_apps/sdkconfig.defaults new file mode 100644 index 00000000000..7b569fa0755 --- /dev/null +++ b/components/esp_hid/test_apps/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 9b77f5ab634..9405c40e159 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -419,8 +419,6 @@ components/esp_hid/private/bt_hidd.h components/esp_hid/private/bt_hidh.h components/esp_hid/private/esp_hidd_private.h components/esp_hid/src/esp_hid_common.c -components/esp_hid/test/hid_descriptor.h -components/esp_hid/test/test_esp_hid.c components/esp_local_ctrl/src/esp_local_ctrl_handler.c components/esp_local_ctrl/src/esp_local_ctrl_priv.h components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c From 3f07dc5a615af1d9d216a9baaf3fc25700f5b113 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 20 Sep 2023 13:01:38 +0200 Subject: [PATCH 63/71] feat(espcoredump): migrate the tests from unit-test-app --- components/espcoredump/test/CMakeLists.txt | 8 ---- .../test_apps/.build-test-rules.yml | 9 ++++ .../espcoredump/test_apps/CMakeLists.txt | 9 ++++ components/espcoredump/test_apps/README.md | 25 ++++++++++ .../espcoredump/test_apps/main/CMakeLists.txt | 5 ++ .../test_apps/main/test_coredump_main.c | 48 +++++++++++++++++++ .../{test => test_apps/main}/test_sections.c | 15 +++--- .../espcoredump/test_apps/pytest_coredump.py | 13 +++++ .../espcoredump/test_apps/sdkconfig.defaults | 1 + 9 files changed, 117 insertions(+), 16 deletions(-) delete mode 100644 components/espcoredump/test/CMakeLists.txt create mode 100644 components/espcoredump/test_apps/.build-test-rules.yml create mode 100644 components/espcoredump/test_apps/CMakeLists.txt create mode 100644 components/espcoredump/test_apps/README.md create mode 100644 components/espcoredump/test_apps/main/CMakeLists.txt create mode 100644 components/espcoredump/test_apps/main/test_coredump_main.c rename components/espcoredump/{test => test_apps/main}/test_sections.c (80%) create mode 100644 components/espcoredump/test_apps/pytest_coredump.py create mode 100644 components/espcoredump/test_apps/sdkconfig.defaults diff --git a/components/espcoredump/test/CMakeLists.txt b/components/espcoredump/test/CMakeLists.txt deleted file mode 100644 index 08873b6a8e4..00000000000 --- a/components/espcoredump/test/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -if(TESTS_ALL EQUAL 1) - message("not linking coredump test from CI.") -else() - idf_component_register(SRC_DIRS "." - PRIV_INCLUDE_DIRS "." - PRIV_REQUIRES cmock nvs_flash test_utils) - target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") -endif() diff --git a/components/espcoredump/test_apps/.build-test-rules.yml b/components/espcoredump/test_apps/.build-test-rules.yml new file mode 100644 index 00000000000..3f3d8745926 --- /dev/null +++ b/components/espcoredump/test_apps/.build-test-rules.yml @@ -0,0 +1,9 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/espcoredump/test_apps: + enable: + - if: IDF_TARGET in ["esp32", "esp32c3", "esp32c2"] + reason: Can test one chip per architecture, plus C2 which doesn't have RTC RAM + depends_components: + - espcoredump + - esp_system # for linker scripts diff --git a/components/espcoredump/test_apps/CMakeLists.txt b/components/espcoredump/test_apps/CMakeLists.txt new file mode 100644 index 00000000000..625d365f940 --- /dev/null +++ b/components/espcoredump/test_apps/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) +list(PREPEND SDKCONFIG_DEFAULTS + "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" + "sdkconfig.defaults") + +project(coredump_test) diff --git a/components/espcoredump/test_apps/README.md b/components/espcoredump/test_apps/README.md new file mode 100644 index 00000000000..b4c0aa7c509 --- /dev/null +++ b/components/espcoredump/test_apps/README.md @@ -0,0 +1,25 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | +| ----------------- | ----- | -------- | -------- | + +# Coredump unit tests + +The unit tests are currently run only on the chips listed above just to save CI resources. If you are adding some tests which need to run on a different chip, update [.build-test-rules.yml](../.build-test-rules.yml), adding the chip you need. + +When adding new test cases, check if the `depends_components` list in `.build-test-rules.yml` needs to be updated to include additional components. The test app will only be built and tested when these components are modified. + +See also the [panic test app](../../../tools/test_apps/system/panic) which serves as an integration test for espcoredump and is run on all supported chips. + +To build and run this test app, using esp32c3 target for example: + +```bash +idf.py set-target esp32c3 +idf.py build flash monitor +``` + +To run tests using pytest: + +```bash +idf.py set-target esp32c3 +idf.py build +pytest --target=esp32c3 +``` diff --git a/components/espcoredump/test_apps/main/CMakeLists.txt b/components/espcoredump/test_apps/main/CMakeLists.txt new file mode 100644 index 00000000000..565a14b80d8 --- /dev/null +++ b/components/espcoredump/test_apps/main/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register(SRCS "test_coredump_main.c" + "test_sections.c" + INCLUDE_DIRS "." + PRIV_REQUIRES unity espcoredump + WHOLE_ARCHIVE) diff --git a/components/espcoredump/test_apps/main/test_coredump_main.c b/components/espcoredump/test_apps/main/test_coredump_main.c new file mode 100644 index 00000000000..a46242e95f8 --- /dev/null +++ b/components/espcoredump/test_apps/main/test_coredump_main.c @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT 0 +static int leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +void set_leak_threshold(int threshold) +{ + leak_threshold = threshold; +} + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= leak_threshold, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); + + leak_threshold = TEST_MEMORY_LEAK_THRESHOLD_DEFAULT; +} + +void app_main(void) +{ + printf("Running espcoredump component tests\n"); + unity_run_menu(); +} diff --git a/components/espcoredump/test/test_sections.c b/components/espcoredump/test_apps/main/test_sections.c similarity index 80% rename from components/espcoredump/test/test_sections.c rename to components/espcoredump/test_apps/main/test_sections.c index 0ec31b9dbae..32db8aa8d00 100644 --- a/components/espcoredump/test/test_sections.c +++ b/components/espcoredump/test_apps/main/test_sections.c @@ -6,7 +6,6 @@ #include #include "unity.h" #include "esp_attr.h" -#include "test_utils.h" /* Global variables that should be part of the coredump */ COREDUMP_IRAM_DATA_ATTR uint32_t var_iram = 0x42; @@ -28,10 +27,10 @@ extern int _coredump_rtc_fast_start; extern int _coredump_rtc_fast_end; #endif // SOC_RTC_MEM_SUPPORTED -static inline bool is_addr_in_region(void* addr, uint8_t* region, int region_size) +static inline bool is_addr_in_region(void *addr, uint8_t *region, int region_size) { - const void* start = (void*) region; - const void* end = (void*) (region + region_size); + const void *start = (void *) region; + const void *end = (void *) (region + region_size); return addr >= start && addr < end; } @@ -44,24 +43,24 @@ TEST_CASE("test variables presence in core dump sections", "[espcoredump]") section_start = (uint32_t)&_coredump_dram_start; section_size = (uint8_t *)&_coredump_dram_end - (uint8_t *)&_coredump_dram_start; TEST_ASSERT(section_size > 0); - TEST_ASSERT(is_addr_in_region(&var_dram, (uint8_t*) section_start, section_size)); + TEST_ASSERT(is_addr_in_region(&var_dram, (uint8_t *) section_start, section_size)); #if IRAM_8BIT_ACCESSIBLE /* Check IRAM coredump section */ section_start = (uint32_t)&_coredump_iram_start; section_size = (uint8_t *)&_coredump_iram_end - (uint8_t *)&_coredump_iram_start; TEST_ASSERT(section_size > 0); - TEST_ASSERT(is_addr_in_region(&var_iram, (uint8_t*) section_start, section_size)); + TEST_ASSERT(is_addr_in_region(&var_iram, (uint8_t *) section_start, section_size)); #endif #if SOC_RTC_MEM_SUPPORTED /* Check RTC coredump section */ section_start = (uint32_t)&_coredump_rtc_start; section_size = (uint8_t *)&_coredump_rtc_end - (uint8_t *)&_coredump_rtc_start; TEST_ASSERT(section_size > 0); - TEST_ASSERT(is_addr_in_region(&var_rtc, (uint8_t*) section_start, section_size)); + TEST_ASSERT(is_addr_in_region(&var_rtc, (uint8_t *) section_start, section_size)); /* Check RTC Fast coredump section */ section_start = (uint32_t)&_coredump_rtc_fast_start; section_size = (uint8_t *)&_coredump_rtc_fast_end - (uint8_t *)&_coredump_rtc_fast_start; TEST_ASSERT(section_size > 0); - TEST_ASSERT(is_addr_in_region(&var_rtcfast, (uint8_t*) section_start, section_size)); + TEST_ASSERT(is_addr_in_region(&var_rtcfast, (uint8_t *) section_start, section_size)); #endif // SOC_RTC_MEM_SUPPORTED } diff --git a/components/espcoredump/test_apps/pytest_coredump.py b/components/espcoredump/test_apps/pytest_coredump.py new file mode 100644 index 00000000000..c3e241a9913 --- /dev/null +++ b/components/espcoredump/test_apps/pytest_coredump.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.generic +@pytest.mark.esp32 +@pytest.mark.esp32c3 +@pytest.mark.esp32c2 +def test_coredump(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/espcoredump/test_apps/sdkconfig.defaults b/components/espcoredump/test_apps/sdkconfig.defaults new file mode 100644 index 00000000000..7b569fa0755 --- /dev/null +++ b/components/espcoredump/test_apps/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n From ac2515e19979aebb9b37db52c10aca8fa39a6227 Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Thu, 7 Sep 2023 13:17:02 +0800 Subject: [PATCH 64/71] refactor(lwip): Added on/off switch for LwIP stack * This switch allows applications to replace lwip with a different IP stack or just make it build if it is a dependency but not actually needed. --- components/esp-tls/CMakeLists.txt | 2 +- components/lwip/CMakeLists.txt | 354 +++++++++--------- components/lwip/Kconfig | 11 + components/mbedtls/CMakeLists.txt | 3 +- .../sockets/udp_client/sdkconfig.ci.linux | 1 + .../sockets/udp_client/sdkconfig.defaults | 0 .../udp_client/sdkconfig.defaults.linux | 1 + 7 files changed, 196 insertions(+), 176 deletions(-) create mode 100644 examples/protocols/sockets/udp_client/sdkconfig.defaults create mode 100644 examples/protocols/sockets/udp_client/sdkconfig.defaults.linux diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index b40b249c4c7..c8fe0d5a65d 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -35,7 +35,7 @@ set_property(TARGET ${lwip} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 5) else() # Check if LWIP in the build for linux target to adapt esp-tls compatibility layer idf_build_get_property(build_components BUILD_COMPONENTS) - if("lwip" IN_LIST build_components) + if(CONFIG_LWIP_ENABLE) target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_TLS_WITH_LWIP=1) endif() endif() diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index ca1e8e71bbf..d0526fd4bad 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -1,107 +1,76 @@ idf_build_get_property(target IDF_TARGET) -if(NOT ${target} STREQUAL "linux") - # ESP platform targets share the same port folder - set(target esp32xx) -endif() -set(include_dirs - include - include/apps - include/apps/sntp - lwip/src/include - port/include - port/freertos/include/ - port/${target}/include - port/${target}/include/arch - port/${target}/include/sys - ) +if(CONFIG_LWIP_ENABLE) + if(NOT ${target} STREQUAL "linux") + # ESP platform targets share the same port folder + set(target esp32xx) + endif() -set(srcs - "apps/sntp/sntp.c" - "lwip/src/api/api_lib.c" - "lwip/src/api/api_msg.c" - "lwip/src/api/err.c" - "lwip/src/api/if_api.c" - "lwip/src/api/netbuf.c" - "lwip/src/api/netdb.c" - "lwip/src/api/netifapi.c" - "lwip/src/api/sockets.c" - "lwip/src/api/tcpip.c" - "lwip/src/apps/sntp/sntp.c" - "lwip/src/apps/netbiosns/netbiosns.c" - "lwip/src/core/def.c" - "lwip/src/core/dns.c" - "lwip/src/core/inet_chksum.c" - "lwip/src/core/init.c" - "lwip/src/core/ip.c" - "lwip/src/core/mem.c" - "lwip/src/core/memp.c" - "lwip/src/core/netif.c" - "lwip/src/core/pbuf.c" - "lwip/src/core/raw.c" - "lwip/src/core/stats.c" - "lwip/src/core/sys.c" - "lwip/src/core/tcp.c" - "lwip/src/core/tcp_in.c" - "lwip/src/core/tcp_out.c" - "lwip/src/core/timeouts.c" - "lwip/src/core/udp.c" - "lwip/src/core/ipv4/autoip.c" - "lwip/src/core/ipv4/dhcp.c" - "lwip/src/core/ipv4/etharp.c" - "lwip/src/core/ipv4/icmp.c" - "lwip/src/core/ipv4/igmp.c" - "lwip/src/core/ipv4/ip4.c" - "lwip/src/core/ipv4/ip4_napt.c" - "lwip/src/core/ipv4/ip4_addr.c" - "lwip/src/core/ipv4/ip4_frag.c" - "lwip/src/core/ipv6/dhcp6.c" - "lwip/src/core/ipv6/ethip6.c" - "lwip/src/core/ipv6/icmp6.c" - "lwip/src/core/ipv6/inet6.c" - "lwip/src/core/ipv6/ip6.c" - "lwip/src/core/ipv6/ip6_addr.c" - "lwip/src/core/ipv6/ip6_frag.c" - "lwip/src/core/ipv6/mld6.c" - "lwip/src/core/ipv6/nd6.c" - "lwip/src/netif/ethernet.c" - "lwip/src/netif/bridgeif.c" - "lwip/src/netif/bridgeif_fdb.c" - "lwip/src/netif/slipif.c" - "lwip/src/netif/slipif.c" - "lwip/src/netif/ppp/auth.c" - "lwip/src/netif/ppp/ccp.c" - "lwip/src/netif/ppp/chap-md5.c" - "lwip/src/netif/ppp/chap-new.c" - "lwip/src/netif/ppp/chap_ms.c" - "lwip/src/netif/ppp/demand.c" - "lwip/src/netif/ppp/eap.c" - "lwip/src/netif/ppp/ecp.c" - "lwip/src/netif/ppp/eui64.c" - "lwip/src/netif/ppp/fsm.c" - "lwip/src/netif/ppp/ipcp.c" - "lwip/src/netif/ppp/ipv6cp.c" - "lwip/src/netif/ppp/lcp.c" - "lwip/src/netif/ppp/magic.c" - "lwip/src/netif/ppp/mppe.c" - "lwip/src/netif/ppp/multilink.c" - "lwip/src/netif/ppp/ppp.c" - "lwip/src/netif/ppp/pppapi.c" - "lwip/src/netif/ppp/pppcrypt.c" - "lwip/src/netif/ppp/pppoe.c" - "lwip/src/netif/ppp/pppol2tp.c" - "lwip/src/netif/ppp/pppos.c" - "lwip/src/netif/ppp/upap.c" - "lwip/src/netif/ppp/utils.c" - "lwip/src/netif/ppp/vj.c" - "port/hooks/tcp_isn_default.c" - "port/hooks/lwip_default_hooks.c" - "port/debug/lwip_debug.c" - "port/sockets_ext.c" - "port/freertos/sys_arch.c") - -if(CONFIG_LWIP_PPP_SUPPORT) - list(APPEND srcs + set(include_dirs + include + include/apps + include/apps/sntp + lwip/src/include + port/include + port/freertos/include/ + port/${target}/include + port/${target}/include/arch + port/${target}/include/sys + ) + + set(srcs + "apps/sntp/sntp.c" + "lwip/src/api/api_lib.c" + "lwip/src/api/api_msg.c" + "lwip/src/api/err.c" + "lwip/src/api/if_api.c" + "lwip/src/api/netbuf.c" + "lwip/src/api/netdb.c" + "lwip/src/api/netifapi.c" + "lwip/src/api/sockets.c" + "lwip/src/api/tcpip.c" + "lwip/src/apps/sntp/sntp.c" + "lwip/src/apps/netbiosns/netbiosns.c" + "lwip/src/core/def.c" + "lwip/src/core/dns.c" + "lwip/src/core/inet_chksum.c" + "lwip/src/core/init.c" + "lwip/src/core/ip.c" + "lwip/src/core/mem.c" + "lwip/src/core/memp.c" + "lwip/src/core/netif.c" + "lwip/src/core/pbuf.c" + "lwip/src/core/raw.c" + "lwip/src/core/stats.c" + "lwip/src/core/sys.c" + "lwip/src/core/tcp.c" + "lwip/src/core/tcp_in.c" + "lwip/src/core/tcp_out.c" + "lwip/src/core/timeouts.c" + "lwip/src/core/udp.c" + "lwip/src/core/ipv4/autoip.c" + "lwip/src/core/ipv4/dhcp.c" + "lwip/src/core/ipv4/etharp.c" + "lwip/src/core/ipv4/icmp.c" + "lwip/src/core/ipv4/igmp.c" + "lwip/src/core/ipv4/ip4.c" + "lwip/src/core/ipv4/ip4_napt.c" + "lwip/src/core/ipv4/ip4_addr.c" + "lwip/src/core/ipv4/ip4_frag.c" + "lwip/src/core/ipv6/dhcp6.c" + "lwip/src/core/ipv6/ethip6.c" + "lwip/src/core/ipv6/icmp6.c" + "lwip/src/core/ipv6/inet6.c" + "lwip/src/core/ipv6/ip6.c" + "lwip/src/core/ipv6/ip6_addr.c" + "lwip/src/core/ipv6/ip6_frag.c" + "lwip/src/core/ipv6/mld6.c" + "lwip/src/core/ipv6/nd6.c" + "lwip/src/netif/ethernet.c" + "lwip/src/netif/bridgeif.c" + "lwip/src/netif/bridgeif_fdb.c" + "lwip/src/netif/slipif.c" + "lwip/src/netif/slipif.c" "lwip/src/netif/ppp/auth.c" "lwip/src/netif/ppp/ccp.c" "lwip/src/netif/ppp/chap-md5.c" @@ -127,40 +96,77 @@ if(CONFIG_LWIP_PPP_SUPPORT) "lwip/src/netif/ppp/upap.c" "lwip/src/netif/ppp/utils.c" "lwip/src/netif/ppp/vj.c" - "lwip/src/netif/ppp/polarssl/arc4.c" - "lwip/src/netif/ppp/polarssl/des.c" - "lwip/src/netif/ppp/polarssl/md4.c" - "lwip/src/netif/ppp/polarssl/md5.c" - "lwip/src/netif/ppp/polarssl/sha1.c") -endif() + "port/hooks/tcp_isn_default.c" + "port/hooks/lwip_default_hooks.c" + "port/debug/lwip_debug.c" + "port/sockets_ext.c" + "port/freertos/sys_arch.c") -if(NOT ${target} STREQUAL "linux") - # Support for vfs and linker fragments only for target builds - set(priv_requires vfs) - set(linker_fragments linker.lf) - if(CONFIG_VFS_SUPPORT_IO) - list(APPEND srcs "port/${target}/vfs_lwip.c") + if(CONFIG_LWIP_PPP_SUPPORT) + list(APPEND srcs + "lwip/src/netif/ppp/auth.c" + "lwip/src/netif/ppp/ccp.c" + "lwip/src/netif/ppp/chap-md5.c" + "lwip/src/netif/ppp/chap-new.c" + "lwip/src/netif/ppp/chap_ms.c" + "lwip/src/netif/ppp/demand.c" + "lwip/src/netif/ppp/eap.c" + "lwip/src/netif/ppp/ecp.c" + "lwip/src/netif/ppp/eui64.c" + "lwip/src/netif/ppp/fsm.c" + "lwip/src/netif/ppp/ipcp.c" + "lwip/src/netif/ppp/ipv6cp.c" + "lwip/src/netif/ppp/lcp.c" + "lwip/src/netif/ppp/magic.c" + "lwip/src/netif/ppp/mppe.c" + "lwip/src/netif/ppp/multilink.c" + "lwip/src/netif/ppp/ppp.c" + "lwip/src/netif/ppp/pppapi.c" + "lwip/src/netif/ppp/pppcrypt.c" + "lwip/src/netif/ppp/pppoe.c" + "lwip/src/netif/ppp/pppol2tp.c" + "lwip/src/netif/ppp/pppos.c" + "lwip/src/netif/ppp/upap.c" + "lwip/src/netif/ppp/utils.c" + "lwip/src/netif/ppp/vj.c" + "lwip/src/netif/ppp/polarssl/arc4.c" + "lwip/src/netif/ppp/polarssl/des.c" + "lwip/src/netif/ppp/polarssl/md4.c" + "lwip/src/netif/ppp/polarssl/md5.c" + "lwip/src/netif/ppp/polarssl/sha1.c") + endif() + + if(NOT ${target} STREQUAL "linux") + # Support for vfs and linker fragments only for target builds + set(linker_fragments linker.lf) + if(CONFIG_VFS_SUPPORT_IO) + list(APPEND srcs "port/${target}/vfs_lwip.c") + else() + list(APPEND srcs "port/${target}/no_vfs_syscalls.c") + endif() else() - list(APPEND srcs "port/${target}/no_vfs_syscalls.c") + # This wraps some posix IO functions to conditionally pass control to lwip + list(APPEND srcs "port/${target}/vfs_lwip.c") endif() -else() - # This wraps some posix IO functions to conditionally pass control to lwip - list(APPEND srcs "port/${target}/vfs_lwip.c") -endif() -if(CONFIG_LWIP_ICMP) - list(APPEND srcs - "apps/ping/esp_ping.c" - "apps/ping/ping.c" - "apps/ping/ping_sock.c") -endif() + if(CONFIG_LWIP_ICMP) + list(APPEND srcs + "apps/ping/esp_ping.c" + "apps/ping/ping.c" + "apps/ping/ping_sock.c") + endif() -if(CONFIG_LWIP_DHCPS) - list(APPEND srcs "apps/dhcpserver/dhcpserver.c") -endif() + if(CONFIG_LWIP_DHCPS) + list(APPEND srcs "apps/dhcpserver/dhcpserver.c") + endif() + + if(CONFIG_LWIP_DHCP_RESTORE_LAST_IP) + list(APPEND srcs "port/esp32xx/netif/dhcp_state.c") + endif() +endif() # CONFIG_LWIP_ENABLE -if(CONFIG_LWIP_DHCP_RESTORE_LAST_IP) - list(APPEND srcs "port/esp32xx/netif/dhcp_state.c") +if(NOT ${target} STREQUAL "linux") + set(priv_requires vfs) endif() idf_component_register(SRCS "${srcs}" @@ -168,53 +174,55 @@ idf_component_register(SRCS "${srcs}" LDFRAGMENTS ${linker_fragments} PRIV_REQUIRES ${priv_requires}) -# lots of LWIP source files evaluate macros that check address of stack variables -target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address) -target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_LWIP_COMPONENT_BUILD) +if(CONFIG_LWIP_ENABLE) + # lots of LWIP source files evaluate macros that check address of stack variables + target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address) + target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_LWIP_COMPONENT_BUILD) -set_source_files_properties( - lwip/src/netif/ppp/pppos.c - PROPERTIES COMPILE_FLAGS - -Wno-type-limits + set_source_files_properties( + lwip/src/netif/ppp/pppos.c + PROPERTIES COMPILE_FLAGS + -Wno-type-limits + ) + # "comparison is always false due to limited range of data type" warning + # when setting CONFIG_LWIP_TCP_WND_DEFAULT to 65535 + set_source_files_properties( + lwip/src/core/tcp.c + PROPERTIES COMPILE_FLAGS + -Wno-type-limits ) -# "comparison is always false due to limited range of data type" warning -# when setting CONFIG_LWIP_TCP_WND_DEFAULT to 65535 -set_source_files_properties( - lwip/src/core/tcp.c - PROPERTIES COMPILE_FLAGS - -Wno-type-limits -) - -# ignore some declaration mismatches -set_source_files_properties( - lwip/src/netif/ppp/chap_ms.c - PROPERTIES COMPILE_FLAGS - -Wno-array-parameter -) - -if(CONFIG_OPENTHREAD_ENABLED) - idf_component_optional_requires(PRIVATE openthread) -endif() -if(CONFIG_ETH_ENABLED) - idf_component_optional_requires(PRIVATE esp_eth) -endif() + # ignore some declaration mismatches + set_source_files_properties( + lwip/src/netif/ppp/chap_ms.c + PROPERTIES COMPILE_FLAGS + -Wno-array-parameter + ) -if(CONFIG_LWIP_DHCP_RESTORE_LAST_IP) - idf_component_optional_requires(PRIVATE nvs_flash) -endif() + if(CONFIG_OPENTHREAD_ENABLED) + idf_component_optional_requires(PRIVATE openthread) + endif() + + if(CONFIG_ETH_ENABLED) + idf_component_optional_requires(PRIVATE esp_eth) + endif() -if(${target} STREQUAL "linux") - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads REQUIRED) - target_link_libraries(${COMPONENT_LIB} PRIVATE Threads::Threads) - set(WRAP_FUNCTIONS select - read - fcntl - write - close) - foreach(wrap ${WRAP_FUNCTIONS}) - target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}") - target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __wrap_${wrap}") - endforeach() + if(CONFIG_LWIP_DHCP_RESTORE_LAST_IP) + idf_component_optional_requires(PRIVATE nvs_flash) + endif() + + if(${target} STREQUAL "linux") + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + target_link_libraries(${COMPONENT_LIB} PRIVATE Threads::Threads) + set(WRAP_FUNCTIONS select + read + fcntl + write + close) + foreach(wrap ${WRAP_FUNCTIONS}) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __wrap_${wrap}") + endforeach() + endif() endif() diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index d3be4246d01..cb8f86bd4b4 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -1,4 +1,15 @@ menu "LWIP" + config LWIP_ENABLE + bool "Enable LwIP stack" + default y if !IDF_TARGET_LINUX + default n if IDF_TARGET_LINUX + help + Builds normally if selected. Excludes LwIP from build if unselected, even if it is a + dependency of a component or application. + Some applications can switch their IP stacks, e.g., when switching between chip + and Linux targets (LwIP stack vs. Linux IP stack). Since the LwIP dependency cannot + easily be excluded based on a Kconfig option, it has to be a dependency in all cases. + This switch allows the LwIP stack to be built selectively, even if it is a dependency. config LWIP_LOCAL_HOSTNAME string "Local netif hostname" diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index 1fe4dda01b1..b183388cd78 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -134,8 +134,7 @@ endif() # net_sockets.c should only be compiled if BSD socket functions are available. # Do this by checking if lwip component is included into the build. -idf_build_get_property(build_components BUILD_COMPONENTS) -if(lwip IN_LIST build_components) +if(CONFIG_LWIP_ENABLE) list(APPEND mbedtls_target_sources "${COMPONENT_DIR}/port/net_sockets.c") idf_component_get_property(lwip_lib lwip COMPONENT_LIB) target_link_libraries(${COMPONENT_LIB} ${linkage_type} ${lwip_lib}) diff --git a/examples/protocols/sockets/udp_client/sdkconfig.ci.linux b/examples/protocols/sockets/udp_client/sdkconfig.ci.linux index 6f95c918247..bcf15875e64 100644 --- a/examples/protocols/sockets/udp_client/sdkconfig.ci.linux +++ b/examples/protocols/sockets/udp_client/sdkconfig.ci.linux @@ -1,3 +1,4 @@ CONFIG_IDF_TARGET="linux" CONFIG_EXAMPLE_IPV4_ADDR="127.0.0.1" CONFIG_EXAMPLE_CONNECT_LWIP_TAPIF=n +CONFIG_LWIP_ENABLE=y diff --git a/examples/protocols/sockets/udp_client/sdkconfig.defaults b/examples/protocols/sockets/udp_client/sdkconfig.defaults new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/protocols/sockets/udp_client/sdkconfig.defaults.linux b/examples/protocols/sockets/udp_client/sdkconfig.defaults.linux new file mode 100644 index 00000000000..242f3ccd8c5 --- /dev/null +++ b/examples/protocols/sockets/udp_client/sdkconfig.defaults.linux @@ -0,0 +1 @@ +CONFIG_LWIP_ENABLE=y From ec9e9ff37634bd2ac92d86339cddad2f5b5274cf Mon Sep 17 00:00:00 2001 From: Liu Linyan Date: Thu, 21 Sep 2023 13:23:59 +0800 Subject: [PATCH 65/71] fix(ble_mesh): Check if role needed to be set based on idf version --- .../ble_mesh_fast_prov_client_model.c | 21 +++++++++++++++++++ .../fast_prov/ble_mesh_fast_prov_operation.c | 9 ++++++++ .../fast_prov_client/main/main.c | 9 ++++++++ .../fast_prov_server/main/main.c | 9 ++++++++ .../onoff_models/onoff_client/main/main.c | 3 +++ .../esp_ble_mesh/provisioner/main/main.c | 3 +++ .../sensor_models/sensor_client/main/main.c | 3 +++ .../vendor_models/vendor_client/main/main.c | 3 +++ .../esp_ble_mesh/wifi_coexist/main/main.c | 9 ++++++++ 9 files changed, 69 insertions(+) diff --git a/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_client_model.c b/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_client_model.c index a4b2427ecdf..c69a660c81f 100644 --- a/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_client_model.c +++ b/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_client_model.c @@ -129,6 +129,9 @@ void example_send_self_prov_node_addr(struct k_work *work) .app_idx = fast_prov_srv->app_idx, .dst = fast_prov_srv->prim_prov_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_FAST_PROV, +#endif }; err = example_send_fast_prov_self_prov_node_addr(model, &info, node_addr_send.addr); if (err != ESP_OK) { @@ -178,6 +181,9 @@ static void example_get_all_node_addr(struct k_work *work) .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 10000, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_PROVISIONER, +#endif }; err = example_send_fast_prov_all_node_addr_get(model, &info); if (err != ESP_OK) { @@ -232,10 +238,16 @@ esp_err_t example_fast_prov_client_recv_timeout(uint32_t opcode, esp_ble_mesh_mo set.ctx_flags = BIT(6); set.group_addr = fast_prov_srv->group_addr; } +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + info.role = ROLE_FAST_PROV; +#endif #else set.ctx_flags = 0x037F; memcpy(&set.node_addr_cnt, &node->node_addr_cnt, sizeof(example_node_info_t) - offsetof(example_node_info_t, node_addr_cnt)); +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + info.role = ROLE_PROVISIONER; +#endif #endif err = example_send_fast_prov_info_set(model, &info, &set); if (err != ESP_OK) { @@ -254,6 +266,9 @@ esp_err_t example_fast_prov_client_recv_timeout(uint32_t opcode, esp_ble_mesh_mo .app_idx = fast_prov_srv->app_idx, .dst = fast_prov_srv->prim_prov_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_FAST_PROV, +#endif }; err = example_send_fast_prov_self_prov_node_addr(model, &info, node_addr_send.addr); if (err != ESP_OK) { @@ -281,6 +296,9 @@ esp_err_t example_fast_prov_client_recv_timeout(uint32_t opcode, esp_ble_mesh_mo .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 10000, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_PROVISIONER, +#endif }; err = example_send_fast_prov_all_node_addr_get(model, &info); if (err != ESP_OK) { @@ -378,6 +396,9 @@ esp_err_t example_fast_prov_client_recv_status(esp_ble_mesh_model_t *model, .app_idx = node->app_idx, .dst = node->group_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_PROVISIONER, +#endif }; err = example_send_generic_onoff_set(cli_model, &info, LED_ON, 0x00, false); if (err != ESP_OK) { diff --git a/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_operation.c b/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_operation.c index c2e9251618b..86320bd53be 100644 --- a/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_operation.c +++ b/examples/bluetooth/esp_ble_mesh/common_components/fast_prov/ble_mesh_fast_prov_operation.c @@ -351,6 +351,9 @@ esp_err_t example_send_config_appkey_add(esp_ble_mesh_model_t *model, common.ctx.addr = info->dst; common.ctx.send_ttl = 0; common.msg_timeout = info->timeout; +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + common.msg_role = info->role; +#endif return esp_ble_mesh_config_client_set_state(&common, &set); } @@ -372,6 +375,9 @@ esp_err_t example_send_generic_onoff_get(esp_ble_mesh_model_t *model, common.ctx.addr = info->dst; common.ctx.send_ttl = 0; common.msg_timeout = info->timeout; +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + common.msg_role = info->role; +#endif return esp_ble_mesh_generic_client_get_state(&common, &get); } @@ -403,6 +409,9 @@ esp_err_t example_send_generic_onoff_set(esp_ble_mesh_model_t *model, common.ctx.addr = info->dst; common.ctx.send_ttl = 0; common.msg_timeout = info->timeout; +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + common.msg_role = info->role; +#endif return esp_ble_mesh_generic_client_set_state(&common, &set); } diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/main.c b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/main.c index 9ac4601074a..b799b17f5ab 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_client/main/main.c @@ -168,6 +168,9 @@ static void provisioner_prov_complete(int node_index, const uint8_t uuid[16], ui .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_PROVISIONER, +#endif }; esp_ble_mesh_cfg_app_key_add_t add_key = { .net_idx = prov_info.net_idx, @@ -424,6 +427,9 @@ static void example_config_client_callback(esp_ble_mesh_cfg_client_cb_event_t ev .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_PROVISIONER, +#endif }; err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); if (err != ESP_OK) { @@ -446,6 +452,9 @@ static void example_config_client_callback(esp_ble_mesh_cfg_client_cb_event_t ev .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_PROVISIONER, +#endif }; esp_ble_mesh_cfg_app_key_add_t add_key = { .net_idx = prov_info.net_idx, diff --git a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/main.c b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/main.c index 6fd267b9bf6..19a4806de9b 100644 --- a/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/fast_provisioning/fast_prov_server/main/main.c @@ -282,6 +282,9 @@ static void provisioner_prov_complete(int node_idx, const uint8_t uuid[16], uint .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_FAST_PROV, +#endif }; err = example_send_config_appkey_add(config_client.model, &info, NULL); if (err != ESP_OK) { @@ -605,6 +608,9 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_FAST_PROV, +#endif }; err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); if (err != ESP_OK) { @@ -627,6 +633,9 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_FAST_PROV, +#endif }; err = example_send_config_appkey_add(config_client.model, &info, NULL); if (err != ESP_OK) { diff --git a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/main.c b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/main.c index 1cc61e11562..2f037abf79b 100644 --- a/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/onoff_models/onoff_client/main/main.c @@ -182,6 +182,9 @@ void example_ble_mesh_send_gen_onoff_set(void) common.ctx.addr = 0xFFFF; /* to all nodes */ common.ctx.send_ttl = 3; common.msg_timeout = 0; /* 0 indicates that timeout value from menuconfig will be used */ +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + common.msg_role = ROLE_NODE; +#endif set.onoff_set.op_en = false; set.onoff_set.onoff = store.onoff; diff --git a/examples/bluetooth/esp_ble_mesh/provisioner/main/main.c b/examples/bluetooth/esp_ble_mesh/provisioner/main/main.c index 9eb27a655fb..4b7bf8ce9e5 100644 --- a/examples/bluetooth/esp_ble_mesh/provisioner/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/provisioner/main/main.c @@ -181,6 +181,9 @@ static esp_err_t example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_para common->ctx.addr = node->unicast; common->ctx.send_ttl = MSG_SEND_TTL; common->msg_timeout = MSG_TIMEOUT; +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + common->msg_role = MSG_ROLE; +#endif return ESP_OK; } diff --git a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/main.c b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/main.c index fd319b53e04..84a5af98a36 100644 --- a/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/sensor_models/sensor_client/main/main.c @@ -101,6 +101,9 @@ static void example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t * common->ctx.addr = node->unicast_addr; common->ctx.send_ttl = MSG_SEND_TTL; common->msg_timeout = MSG_TIMEOUT; +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + common->msg_role = MSG_ROLE; +#endif } static esp_err_t prov_complete(uint16_t node_index, const esp_ble_mesh_octet16_t uuid, diff --git a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/main.c b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/main.c index 461177a379d..c93e6d811ef 100644 --- a/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/vendor_models/vendor_client/main/main.c @@ -155,6 +155,9 @@ static void example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t * common->ctx.addr = node->unicast_addr; common->ctx.send_ttl = MSG_SEND_TTL; common->msg_timeout = MSG_TIMEOUT; +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + common->msg_role = MSG_ROLE; +#endif } static esp_err_t prov_complete(uint16_t node_index, const esp_ble_mesh_octet16_t uuid, diff --git a/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/main.c b/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/main.c index 1c8f6d45cf1..e95518c33f6 100644 --- a/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/wifi_coexist/main/main.c @@ -294,6 +294,9 @@ static void provisioner_prov_complete(int node_idx, const uint8_t uuid[16], uint .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_FAST_PROV, +#endif }; err = example_send_config_appkey_add(config_client.model, &info, NULL); if (err != ESP_OK) { @@ -617,6 +620,9 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_FAST_PROV, +#endif }; err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set); if (err != ESP_OK) { @@ -639,6 +645,9 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t .app_idx = node->app_idx, .dst = node->unicast_addr, .timeout = 0, +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) + .role = ROLE_FAST_PROV, +#endif }; err = example_send_config_appkey_add(config_client.model, &info, NULL); if (err != ESP_OK) { From 6e2cb4bcc00a55b39a219361086ceb95eb7d8825 Mon Sep 17 00:00:00 2001 From: renpeiying Date: Fri, 25 Aug 2023 14:49:29 +0800 Subject: [PATCH 66/71] docs: Provide Chinese translation for api-reference/storage/fatfsgen.rst --- docs/en/api-reference/storage/fatfsgen.rst | 135 ++++++----- docs/zh_CN/api-reference/storage/fatfsgen.rst | 226 +++++++++++++++++- 2 files changed, 298 insertions(+), 63 deletions(-) diff --git a/docs/en/api-reference/storage/fatfsgen.rst b/docs/en/api-reference/storage/fatfsgen.rst index 84734b091d9..051d2fc0d93 100644 --- a/docs/en/api-reference/storage/fatfsgen.rst +++ b/docs/en/api-reference/storage/fatfsgen.rst @@ -5,58 +5,64 @@ Generating and Parsing FATFS on Host ==================================== -This chapter is intended mainly for developers of Python tools :component_file:`fatfsgen.py ` and :component_file:`fatfsparse.py `, and people with special interest in these tools and implementation of the FAT file system in ESP-IDF. If you are interested in using these tools, please refer to the user guide at :ref:`fatfs-partition-generator`. +:link_to_translation:`zh_CN:[中文]` -The FAT file system is composed of various logical units. The units are used to store general information about the filesystem, allocations, content of files and directories, and file's metadata. The tools ``fatfsgen.py`` and ``fatfsparse.py`` implement the FAT filesystem considering all these logical units and they can also support wear levelling. +This document is intended mainly for developers of Python tools :component_file:`fatfsgen.py ` and :component_file:`fatfsparse.py `, and people with special interest in these tools and implementation of the FAT file system in ESP-IDF. If you are interested in using these tools, please refer to the user guide at :ref:`fatfs-partition-generator`. +The FAT file system is composed of various logical units. The units are used to store general information about the file system, allocations, content of files and directories, and file's metadata. The tools ``fatfsgen.py`` and ``fatfsparse.py`` are used to implement the FAT file system while considering all these logical units, and they also provide support for wear levelling. -FAT Filesystem Generator/Parser Design --------------------------------------- + +FAT File System Generator and Parser Design +------------------------------------------- This section describes particular units of the FAT file system generator and parser design. The implementation aims to create a valid model of the FAT structure with a focus on macro operations, generating and parsing the whole partition without modifying it in the run (mounting). .. figure:: ../../../_static/classes_fatfsgen.svg - :align: center - :alt: Class diagram + :align: center + :alt: Class diagram + + FAT File System Generator and Parser Design Architecture + Class FATFS ^^^^^^^^^^^ -This is the most general entity responsible for modeling the FAT file system. It is composed of **FATFSState** (holding metadata and boot sector), **FAT** (holding file allocation table), and **Directory** (representing the root directory required by FAT12 and FAT16). The class processes all the requirements for the partition, analyses the local folder dedicated to transforming it into a binary image, and generates an internal representation of the local folder. Then, the class can generate a binary image from the internal FAT filesystem model. +This is the most general entity responsible for modeling the FAT file system. It is composed of **FATFSState** (holding metadata and boot sector), **FAT** (holding file allocation table), and **Directory** (representing the root directory required by FAT12 and FAT16). The class processes all the requirements for the partition, analyses the local folder dedicated to transforming it into a binary image, and generates an internal representation of the local folder. Then, the class can generate a binary image from the internal FAT file system model. Class WLFATFS ^^^^^^^^^^^^^ -The class extends the functionality of the class **FATFS**. It implements an encapsulation of the filesystem into the wear levelling, by adding the "dummy" sector for balancing the load (a redundant sector, see the section :ref:`fafsgen-wear-levelling`), configuration sector and state sector. This class generates a binary FATFS partition with initialized wear levelling layer. For further analysis, it also provides an option to remove the wear levelling completely. The class is instantiated and invoked by the ``wl_fatfsgen.py`` script. +The class extends the functionality of the class **FATFS**. It implements an encapsulation of the file system into the wear levelling, by adding the "dummy" sector for balancing the load (a redundant sector, see the section :ref:`fafsgen-wear-levelling`), configuration sector and state sector. This class generates a binary FATFS partition with initialized wear levelling layer. For further analysis, it also provides an option to remove the wear levelling completely. The class is instantiated and invoked by the ``wl_fatfsgen.py`` script. Class BootSectorState ^^^^^^^^^^^^^^^^^^^^^ -The instance of this class contains the metadata required for building a boot sector and BPB (BIOS Parameter Block). Boot sector is basically implemented for the cross-platform compatibility, i.e., when ESP chipsets are connected with other platforms, it will always follow all the FAT filesystem standards. However, during partition generation, chip does not consume the data in this boot sector and all the other data needed, as the data is constant. In other words, changing the fields with the prefix "BS" is usually unnecessary and often does not work. If you want to add new features, please focus on fields with the prefix "BPB". Another critical role of this class is to share access to the metadata and binary image over the whole class system. Because of this, every class in the system can access this singleton. +The instance of this class contains the metadata required for building a boot sector and BPB (BIOS Parameter Block). Boot sector is basically implemented for the cross-platform compatibility, i.e., when ESP chipsets are connected with other platforms, it will always follow all the FAT file system standards. However, during partition generation, chip does not consume the data in this boot sector and all the other data needed, as the data is constant. In other words, changing the fields with the prefix "BS" is usually unnecessary and often does not work. If you want to add new features, please focus on fields with the prefix "BPB". Another critical role of this class is to share access to the metadata and binary image over the whole class system. Because of this, every class in the system can access this singleton. Class FATFSState ^^^^^^^^^^^^^^^^ -The class **FATFSState** might be obsolete in the future, so developers could transfer its functionality into the **BootSectorState**. The class contains a reference to the **BootSectorState** and extends the data with some unknown information when creating a boot sector or unnecessary for the boot sector, such as the information generated when the filesystem supports long file names. +The class **FATFSState** might be obsolete in the future, so developers could transfer its functionality into the **BootSectorState**. The class contains a reference to the **BootSectorState** and extends the data with some unknown information when creating a boot sector or unnecessary for the boot sector, such as the information generated when the file system supports long file names. Class FAT ^^^^^^^^^ -FAT represents the File Allocation Table. FAT is a sequence of bytes spread over one or more sectors. The number of sectors is determined by the number of clusters and is calculated by the function ``get_fat_sectors_count`` in ``utils.py``. The aim is to have as few sectors for one FAT as possible when you refer to every physical cluster in the file system. The FAT works as follows: For every physical cluster at ``i * some_constant`` address, FAT contains an entry at the ``i``-th location which represents next address of the clusters in the file chain. Each version of the FAT file system uses a different size for FAT entries. FAT12 uses 12 bits per entry, thus two entries span 3 bytes. FAT16 uses 16 bits per entry, thus one entry spans 2 bytes. FAT32 uses 32 bits per FAT entry, thus one entry spans 4 bytes. All entries are in little-endian byte order. +FAT represents the File Allocation Table. FAT is a sequence of bytes spread over one or more sectors. The number of sectors is determined by the number of clusters and is calculated by the function ``get_fat_sectors_count`` in ``utils.py``. The aim is to have as few sectors for one FAT as possible when you refer to every physical cluster in the file system. The FAT works as follows: For every physical cluster at ``i * some_constant`` address, FAT contains an entry at the ``i``-th location which represents next address of the clusters in the file chain. Each version of the FAT file system uses a different size for FAT entries. FAT12 uses 12 bits per entry, thus 2 entries span 3 bytes. FAT16 uses 16 bits per entry, thus 1 entry spans 2 bytes. FAT32 uses 32 bits per FAT entry, thus one entry spans 4 bytes. All entries are in little-endian byte order. All zeros at the ``i``-th entry indicates that corresponding cluster is free, while all ones at the ``i``-th entry indicates that corresponding cluster is occupied and is the last cluster in the file chain. The other number at ``ith``-th entry determines the next cluster's address in the file chain. These clusters are not necessarily stored adjacent to one another in the memory but instead are often fragmented throughout the data region. -For partition generation, the file is divided into several parts to fit the cluster, and the allocated chain is usually conquest. Notice that the structure allocation of the files is a linked list. Every cluster in the file allocation chain has entry in the FAT which refers to the next cluster or the information about the last cluster in the file chain. As mentioned, FAT12 uses 12 bits per FAT entry, thus it can sets a maximum number of 4096 clusters, as with 12 bits (one and a half bytes), it can enumerate 4096 clusters at most. However, because of other overhead, FAT12 can have 4085 clusters at most. Similarly, FAT16 can have 65525 clusters at most and for FAT32 can have 268435445 clusters at most (as practically only 28 bits out of 32 bits are used to denote each FAT entry). The current implementation doesn't allow forcibly redefining the FAT filesystem with less than 4085 clusters to FAT16, even though the documentation claims it is possible. Notice that it would be meaningless to define it vice versa, i.e., to FAT12 with more than 4085 clusters (which implies clusters on higher addresses being inaccessible). +For partition generation, the file is divided into several parts to fit the cluster. Notice that the structure allocation of the files is a linked list. Every cluster in the file allocation chain has entry in the FAT which refers to the next cluster or the information about the last cluster in the file chain. As mentioned, FAT12 uses 12 bits per FAT entry, thus it can sets a maximum number of 4096 clusters, as with 12 bits (one and a half bytes), it can enumerate 4096 clusters at most. However, because of other overhead, FAT12 can have 4085 clusters at most. Similarly, FAT16 can have 65525 clusters at most and for FAT32 can have 268435445 clusters at most (as practically only 28 bits out of 32 bits are used to denote each FAT entry). The current implementation doesn't allow forcibly redefining the FAT file system with less than 4085 clusters to FAT16, even though the documentation claims it is possible. Notice that it would be meaningless to define it vice versa, i.e., to FAT12 with more than 4085 clusters (which implies clusters on higher addresses being inaccessible). Class Cluster ^^^^^^^^^^^^^ -The **Cluster** class is responsible for accessing the FAT entries and the corresponding physical cluster. The class **FAT** is an aggregation of a particular number of **Cluster** instances. -Every cluster is uniquely defined by the ID, which also determines its position in FAT and corresponding sectors in the data region. When the cluster is allocated, it includes a reference to a file or directory. It happens only if the cluster is the first in the allocation chain. The cluster contains information if it is empty and the last in the file allocation linked list. Otherwise, it includes a reference to the next cluster in the linked list. In practical usage, the cluster doesn't need to access its file, but the other way around. The **File** or **Directory** accesses its cluster, to retrieve the entire content that might be chained. + +The **Cluster** class is responsible for accessing the FAT entries and the corresponding physical cluster. The class **FAT** is an aggregation of a particular number of **Cluster** instances. Every cluster is uniquely defined by the ID, which also determines its position in FAT and corresponding sectors in the data region. When the cluster is allocated, it includes a reference to a file or directory. It happens only if the cluster is the first in the allocation chain. The cluster contains information about whether it is empty and the last in the file allocation linked list. If not, it includes a reference to the next cluster in the linked list. In practical usage, the cluster doesn't need to access its file, but the other way around. The **File** or **Directory** accesses its cluster, to retrieve the entire content that might be chained. .. figure:: ../../../_static/fat_table.svg :align: center :alt: Table diagram + Class Directory ^^^^^^^^^^^^^^^ @@ -74,7 +80,8 @@ Class Entry .. figure:: ../../../_static/tree_fatfs.svg :align: center - :alt: Tree diagram + :alt: Tree diagram + ``fatfsgen.py`` --------------- @@ -91,12 +98,12 @@ The script command line arguments are as follows:: fatfsgen.py [-h] [--output_file OUTPUT_FILE] [--partition_size PARTITION_SIZE] [--sector_size {4096}] [--long_name_support] [--use_default_datetime] input_directory - --output_file - path to the generated binary partition - --partition_size - defines the size of the binary partition (decimal, hexa or binary number) - --sector_size - the size of the sector - --long_name_support - flag for supporting long file names - --use_default_datetime - this flag forces using default dates and times (date == 0x2100, time == 0x0000), not using argument preserves the original filesystem metadata - input_directory - required argument - name of the directory being encoded to the binary fat-compatibile partition + --output_file: path to the generated binary partition + --partition_size: defines the size of the binary partition (decimal, hexa or binary number) + --sector_size: the size of the sector + --long_name_support: flag for supporting long file names + --use_default_datetime: this flag forces using default dates and times (date == 0x2100, time == 0x0000), not using argument to preserve the original file system metadata + input_directory: required argument, name of the directory being encoded to the binary fat-compatibile partition ``fatfsparse.py`` ----------------- @@ -108,67 +115,71 @@ The script command line arguments are as follows:: The script command line arguments are as follows:: fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] input_image - --wl-layer - indicates if wl is enabled, disabled or should be detected (detection is ambiguous) - input_image - path to binary image -The long file names can be detected automatically. However, the wear leveling cannot be 100\% detected, because one partition can be valid either with or without wear leveling, according to the user's context. When the script finds WL sectors (cfg and state), it assumes WL is enabled, however it might be a false positive. + --wl-layer: indicates if wear leveling is enabled, disabled or should be detected (detection is ambiguous) + input_image: path to binary image + +The long file names can be detected automatically. However, the wear leveling cannot be 100\% detected, because one partition can be valid either with or without wear leveling, according to the user's context. When the script finds wear leveling sectors (cfg and state), it assumes wear leveling is enabled, however it might be a false positive. Features -------- -FAT12/16 -^^^^^^^^ +FAT12/FAT16 +^^^^^^^^^^^ -The supported FAT types are FAT12 and FAT16. For smaller partitions, FAT12 is sufficient. The type is detected according to the count of clusters, and cannot be changed by the user. If there are less than 4085 clusters, the selected type is FAT12 (FAT's entries have 12 bits). For partitions with 4085 to 65526 clusters (with 4085 and 65526 excluded), the type is FAT16. Currently ``fatfsgen.py`` or ``fatfsparse.py`` cannot process filesystems with more than 65525 clusters. +The supported FAT types are FAT12 and FAT16. For smaller partitions, FAT12 is sufficient. The type is detected according to the count of clusters, and cannot be changed by the user. If there are less than 4085 clusters, the selected type is FAT12 (FAT's entries have 12 bits). For partitions with 4085 to 65526 clusters (with 4085 and 65526 excluded), the type is FAT16. Currently ``fatfsgen.py`` or ``fatfsparse.py`` cannot process file systems with more than 65525 clusters. .. _fafsgen-wear-levelling: Wear Levelling ^^^^^^^^^^^^^^ -There are two types of operations related to the Wear Levelling (WL) layer, initialising WL records and removing WL records during generation and parsing of the FAT filesystem image. +There are two types of operations related to the wear levelling layer, initializing wear leveling records and removing wear leveling records during generation and parsing of the FAT file system image. -1. Initialising Wear Levelling: -When a new image with WL support is generated, the script initialises few extra sectors necessary for the WL function. +1. Initializing Wear Levelling - - The dummy sector: This is an empty sector placed at the begining of the partition and it will be ignored when filesystem is being mounted. The dummy sector copies the content of the next sector and then swaps its position with the next sector (or the first sector in case dummy sector was the last) after particular number of erase cycles. In this way, each FAT filesystem sector traverses across the whole range of flash partition, and thus the erase cycles corresponding to this sector gets distributed across the entire flash. +When a new image with wear leveling support is generated, the script initializes few extra sectors necessary for the wear leveling function. - - The state sector: State sector has 64 byte data stored. - - pos — position of the dummy sector - - max_pos — number of sectors in the partition (excluding config and state sectors). - - move_count — indicates how many times dummy sector traversed through the entire flash - - access_count — count of sector erase cycles after which dummy sector will swap its position - - max_count — equal to wl_config_t::updaterate - - block_size — equal to wl_config_t::page_size - - version — equal to wl_config_t::version - - device_id — generated randomly when the state is first initialized - - reserved — 7x 32-bit words, set to 0 - - crc32 — crc32 of all the previous fields, including reserved + - The dummy sector: This is an empty sector placed at the beginning of the partition and it will be ignored when file system is being mounted. The dummy sector copies the content of the next sector and then swaps its position with the next sector (or the first sector in case dummy sector was the last) after particular number of erase cycles. In this way, each FAT file system sector traverses across the whole range of flash partition, and thus the erase cycles corresponding to this sector gets distributed across the entire flash. + + - The state sector: State sector has 64 byte data stored. + - pos: position of the dummy sector + - max_pos: number of sectors in the partition (excluding config and state sectors) + - move_count: indicates how many times dummy sector traversed through the entire flash + - access_count: count of sector erase cycles after which dummy sector will swap its position + - max_count: equal to wl_config_t::updaterate + - block_size: equal to wl_config_t::page_size + - version: equal to wl_config_t::version + - device_id: generated randomly when the state is first initialized + - reserved: 7 x 32-bit words, set to 0 + - crc32: crc32 of all the previous fields, including reserved Also, the state sector will be appended by 16-byte ``pos update record`` for every value of ``pos``. Thus, this record will help us to determine the position of the dummy sector. + Since ``erase + write`` operation of the state sector is not atomic, we may lose the data if the power is cut off between "erase" and "write". However, two copies of the state are maintained to recover the state after the power outage. On each update, both copies are updated. Thus, after power outage, we can revert the original valid state. - - The config sector: This sector contains the information about the partition used by the WL layer. - - start_addr — start address of partition (always zero) - - full_mem_size — size of the partition, including data, dummy, state x 2, config sectors. Value is in bytes. - - page_size — equal to sector size (generally 4096) - - sector_size — always 4096 for the types of NOR flash supported by ESP-IDF - - updaterate — ESP-IDF always sets this to 16. Could be made a Kconfig option at some point. - - wr_size — always set to 16 - - version — current version is 2 - - temp_buff_size — always set to 32. (This shouldn't actually have been stored in flash) - - crc — crc32 of all the previous values. + - The config sector: This sector contains the information about the partition used by the wear leveling layer. + - start_addr: start address of partition (always 0) + - full_mem_size: size of the partition, including data, dummy, state x 2, config sectors. Value is in bytes + - page_size: equal to sector size (generally 4096) + - sector_size: always 4096 for the types of NOR flash supported by ESP-IDF + - updaterate: ESP-IDF always sets this to 16. Could be made a config option at some point + - wr_size: always set to 16 + - version: current version is 2 + - temp_buff_size: always set to 32 (This shouldn't actually have been stored in flash) + - crc: crc32 of all the previous values -2. Removing Wear Levelling: -While removing WL records, we have to find the position of the dummy sector, and the original and valid orders of the partition (because traversing the dummy sector shuffles the partition). The script can remove other WL sectors from the partition. Steps to remove WL records are given below. +2. Removing Wear Levelling +While removing wear leveling records, we have to find the position of the dummy sector, and the original and valid orders of the partition (because traversing the dummy sector shuffles the partition). The script can remove other wear leveling sectors from the partition. Steps to remove wear leveling records are given below: - Find the ``pos``, position of the dummy sector, which will be determined by the number of ``pos update records`` in the state sector. - Create the new image by removing dummy sector and merging remaining sectors before and after dummy sector. - - Then remove the WL state sectors and config sector which are placed at the end of the partition. - - Reorder the new image to get its original order. ``move_count`` helps us to find the beginning of the partition. The partition will start at the position ``end_of_partition - move_count``. Thus the beginning of the partition after removing WL sectors will be ``partition[end_of_partition - (move_count*page_size)]``. + - Then remove the wear leveling state sectors and config sector which are placed at the end of the partition. + - Reorder the new image to get its original order. ``move_count`` helps us to find the beginning of the partition. The partition will start at the position ``end_of_partition - move_count``. Thus the beginning of the partition after removing wear leveling sectors will be ``partition[end_of_partition - (move_count*page_size)]``. File Names Encoding ^^^^^^^^^^^^^^^^^^^ + The protocol FAT supports two types of file names. Short File Names (SFN) @@ -185,7 +196,7 @@ The entry denotes the file with 8.3 file name ("FILENAME.EXT") __(0x00/00-0A)__ Long File Names (LFN) ^^^^^^^^^^^^^^^^^^^^^ -The LFN supports 255 characters excluding the trailing ``NULL``. The LFN supports any character as short file names with an additional period (``.``) and the following special characters: ``+ , ; = [ ]``. LFN uses UNICODE, so the character is encoded using 2 bytes. +The LFN supports 255 characters excluding the trailing ``NULL``. The LFN supports any character as short file names with an additional period ``.`` and the following special characters: ``+ , ; = [ ]``. LFN uses UNICODE, so the character is encoded using 2 bytes. The structure of one name encoded using LFN is as follows:: @@ -198,17 +209,17 @@ The structure of one name encoded using LFN is as follows:: The above example encodes a file name ``thisislongfile.txt``. The record is composed of multiple entries. The first entry contains metadata and is equivalent to the SFN entry. This entry might be final if the file name conforms to the 8.3 file name convention. In such scenarios, the SFN pattern is used. Otherwise, the generator adds various entries with the LFN structure above the SFN entry. These entries hold information about the file name and its checksum for consistency. Every LFN record can hold 13 characters (26 bytes). The file name is firstly cut into some amount of 13-character substrings and these are added above the SFN entry. -We add LFN entries in reversed order, so the first entry in the directory is the last part of the file name and the last is SFN entry. In the above example, we can see that the first entry contains text ``e.txt``, while another one contains the beginning of the name ``thisislongfil``. The first byte in LFN entries denotes an order or the sequence number (numbered from 1). To determine the first entry of the LFN, the first byte is masked with 0x40 (``first_byte =| 0x40``). The specification says that the last entry value will be ORed with 0x40 and it is the mark for the last entry. For example, when the record is the second and also the last in the LFN entry, its first byte is ``0x42``. +We add LFN entries in reversed order, so the first entry in the directory is the last part of the file name and the last is SFN entry. In the above example, we can see that the first entry contains text ``e.txt``, while the others contain the beginning of the name ``thisislongfil``. The first byte in LFN entries denotes an order or the sequence number (numbered from 1). To determine the first entry of the LFN, the first byte is masked with 0x40 (``first_byte =| 0x40``). The specification says that the last entry value will be ORed with 0x40 and it is the mark for the last entry. For example, when the record is the second and also the last in the LFN entry, its first byte is ``0x42``. -The LFN entry is signed at field **DIR_Attr** with value ``ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID`` (see the file long_filename_utils.py). The SFN entry (possibly also within LFN) contains either ``ATTR_DIRECTORY`` or ``ATTR_ARCHIVE`` in this field for directory or file respectively. +The LFN entry is signed at field **DIR_Attr** with value ``ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID`` (see the file ``long_filename_utils.py``). The SFN entry (possibly also within LFN) contains either ``ATTR_DIRECTORY`` or ``ATTR_ARCHIVE`` in this field for directory or file respectively. The LFN entry is tagged at the field **DIR_NTRes** with the value ``0x00``. This is a sign of the SFN entry in the LFN record, if the entry is a whole SFN record, the value is ``0x18``. As you can see in the first example, the value at this field is ``0x18``, because the name **"FILENAME.EXT"** fits the SFN. However, the recent example showing **"thisislongfile.txt"** has value ``0x00`` at field **DIR_NTRes** in the last entry, since it is a LFN. The SFN needs to be unique. For that purpose, the ``fatfsgen.py`` uses the first 6 characters from the file name, concatenating with ``~`` and with ID denoting the order of the name with the same prefix. The ID is between 0 to 127, which is the maximal amount of files with the same prefix. Calculation of the checksum is described and implemented in the ``utils.py`` by function ``lfn_checksum``. The ``fatfsparse.py`` assumes that the LFN entries might not be right next to each other, but it assumes the relative order is preserved. The approach is first to find the SFN belonging to some LFN record (using **DIR_NTRes** field). From then, the script starts to search by moving upwards to the beginning of the respective sector, until it finds the last entry in the LFN record (the one with the first half byte equal to 4). The entries are distinguished by their checksums. When finished, the file name can be composed. -Date and Time in FAT Filesystem -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Date and Time in FAT File System +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The FAT filesystem protocol used by ESP-IDF does not preserve the date/time on the chips' media, so all the images extracted from the device have the same default timestamp for all the FAT-specified date-time fields (creation and the last modification timestamp as well as creation, last modification and last access dates). +The FAT file system protocol used by ESP-IDF does not preserve the date or time on the chips' media, so all the images extracted from the device have the same default timestamp for all the FAT-specified date-time fields (creation and the last modification timestamp as well as creation, last modification and last access dates). There are a couple of fields in the SFN entry describing time, such as **DIR_CrtTime** and **DIR_WrtTime**. Some fields are ignored by the FAT implementation used by ESP-IDF (see the file ``entry.py``). However, changes in the fields **DIR_WrtTime** and **DIR_WrtDate** are preserved in the chip. Both time and data entry are 16-bit, where the granularity of the time is 2 seconds. diff --git a/docs/zh_CN/api-reference/storage/fatfsgen.rst b/docs/zh_CN/api-reference/storage/fatfsgen.rst index f1b50ed530a..12c409ae009 100644 --- a/docs/zh_CN/api-reference/storage/fatfsgen.rst +++ b/docs/zh_CN/api-reference/storage/fatfsgen.rst @@ -1 +1,225 @@ -.. include:: ../../../en/api-reference/storage/fatfsgen.rst +.. linked from fatfs.rst + +:orphan: + +在主机上生成和解析 FATFS +===================================== + +:link_to_translation:`en:[English]` + +本章主要面向 Python 工具 :component_file:`fatfsgen.py ` 和 :component_file:`fatfsparse.py ` 的开发人员、对这些工具感兴趣的用户、和对在 ESP-IDF 中实现 FAT 文件系统感兴趣的用户。如果你对这些工具感兴趣,请参考 :ref:`fatfs-partition-generator`。 + +FAT 文件系统由多个逻辑单元组成。这些单元用于存储有关文件系统、分配、文件内容、目录以及文件元数据的一般信息。 ``fatfsgen.py`` 和 ``fatfsparse.py`` 工具用于实现 FAT 文件系统,该工具会考虑上述所有逻辑单元,并且支持磨损均衡。 + + +FAT 文件系统生成器及解析器的设计 +---------------------------------------- + +本节介绍了 FAT 文件系统生成器和解析器设计的特定单元,设计这些单元是为了创建一个专注于宏操作的有效 FAT 结构模型,用于生成和解析整个分区,而无需在运行(挂载)过程中进行修改。 + +.. figure:: ../../../_static/classes_fatfsgen.svg + :align: center + :alt: 图表 + + FAT 文件系统生成器及解析器设计架构 + + +FATFS 类 +^^^^^^^^^^^^^ + +FATFS 类是建立 FAT 文件系统模型最常用的实体,由 **FATFSState** (保存元数据和引导扇区)、 **FAT** (保存文件分配表)和 **Directory** (表示 FAT12 和 FAT16 所需的根目录)组成。该类可以处理分区的所有要求,分析用于将其转换为二进制映像的本地文件夹,并生成本地文件夹的内部表示。然后,该类就能从内部 FAT 文件系统模型中生成二进制映像。 + +WLFATFS 类 +^^^^^^^^^^^^^ + +WLFATFS 类扩展了 **FATFS** 类的功能,可在磨损均衡中添加虚拟扇区(用于平衡负载的冗余扇区,参见 :ref:`fafsgen-wear-levelling`)、配置扇区和状态扇区,从而对文件系统进行封装。WLFATFS 类还能生成带有初始化的磨损均衡层的二进制 FATFS 分区,并提供了完全删除磨损均衡的选项,用于进一步分析。该类可由 ``wl_fatfsgen.py`` 脚本进行实例化并调用。 + +BootSectorState 类 +^^^^^^^^^^^^^^^^^^^^^ + +**BootSectorState** 实例包含了构建引导扇区和 BPB(BIOS 参数块)所需的元数据。构件引导扇区主要是为了实现跨平台兼容,即当 ESP 芯片组连接到其他平台时,会始终遵守所有的 FAT 文件系统标准。但是,在分区生成期间,芯片并不消耗此引导扇区的数据和其他所需数据,因为这些数据是不变的常量。换句话说,一般无需更改前缀为 "BS" 的字段,且更改通常没有作用。如需添加新功能,应关注前缀为 "BPB" 的字段。 **BootSectorState** 类还有一个重要作用,即在整个类系统中共享对元数据和二进制镜像的访问。因此,系统中的每个类都可以访问这一单例。 + +FATFSState 类 +^^^^^^^^^^^^^^^^ + +**FATFSState** 类未来可能会被弃用,开发人员可以将其功能转移到 **BootSectorState** 中。该类包含对 **BootSectorState** 的引用,并且在创建引导扇区时,会用一些未知或不必要的信息(例如在文件系统支持长文件名时生成的信息)扩展引导扇区数据。 + +FAT 类 +^^^^^^^^^ + +**FAT** (File Allocation Table) 代表文件分配表,是分布在一个或多个扇区上的字节序列。扇区数由簇数决定,并由 ``utils.py`` 中的函数 ``get_fat_sectors_count`` 计算得出,因为在引用文件系统中的物理簇时,每个 FAT 的扇区数应越少越好。FAT 的工作方式如下:对于每个位于 ``i * some_constant`` 地址的物理簇,FAT 在第 ``i`` 个位置有一个条目,表示文件链中下一个簇的地址。每个 FAT 文件系统版本使用的 FAT 条目大小不同。FAT12 每个条目大小为 12 位,因此每 2 个条目占据 3 个字节。FAT16 的每个条目为 16 位,因此每 1 个条目占据 2 个字节。FAT32 的 每个 FAT 条目为 32 位,因此每 1 个条目占据 4 个字节。所有条目都按小字节顺序排列。 + +第 ``i`` 个条目处的所有 0 表示相应的簇为空闲状态,第 ``i`` 个条目处的所有 1 表示相应簇已占用,并且是文件链中的最后一个簇。 第 ``i`` 个条目处的其他数字表示下一个簇在文件链中的地址。这些簇并不一定存储在内存中的相邻位置,而通常会分散在整个数据区域中。 + +在生成分区时,文件会被分为几个部分以适应簇的大小。注意,文件的结构分配是一个链表。文件分配链中的每个簇在 FAT 中都有一个条目指向下一个簇,或文件链中最后一个簇的信息。如前所述,FAT12 的每个 FAT 条目有 12 位,因此最多可以枚举 4096 个簇,因为在 12 位(一个半字节)条件下最多可以列出 4096 个簇。但实际上由于其他开销,FAT12 最多可以有 4085 个簇。同样,FAT16 最多可以有 65525 个簇,而 FAT32 最多可以有 268435445 个簇,因为实际上每个条目只用了 32 位中的 28 位。即便文档中声称可行,但实际上目前的实现方式不允许将簇数少于 4085 的 FAT 文件系统强制重新定义为 FAT16。反之亦然,将具有 4085 个以上簇的 FAT 文件系统强制重新定义为 FAT12 也是没有意义的,否则将无法访问某些地址超出范围的簇。 + +Cluster 类 +^^^^^^^^^^^^^^^ + +**Cluster** 类用于访问 FAT 条目和相应的物理簇。 **FAT** 类是特定数量 **Cluster** 实例的集合。每个簇具有一个唯一 ID,用于确定其在 FAT 中的位置和在数据区中的相应扇区。分配簇时,分配链中的第一个簇会指向一个文件或目录。每个簇中包含该簇是否为空的信息,以及该簇是否为文件分配链中的最后一个簇。如果不是最后一个簇,则指向链表中下一个簇。在实际应用中,簇不需要访问其中的文件,而是反过来由 **文件** 或 **目录** 访问对应的簇,以检索链上可能的全部内容。 + +.. figure:: ../../../_static/fat_table.svg + :align: center + :alt: 图表 + + +Directory 类 +^^^^^^^^^^^^^^^ + +**Directory** 类表示文件系统目录。 **Directory** 的实例包含对相应 **Cluster** 实例的引用,该实例中有给定目录的分配链中的第一个簇。根目录较为特殊,其扇区数量不同,实例化过程也有所不同。不过,根目录仍然是此类的实例,也是分别与 **FATFS** 类和 **WLFATFS** 类相关联的唯一 **Directory** 实例。 **Directory** 类(除根目录外)与在父目录中定义其条目的 **Entry** 类一对一的关联。此外,由于每个目录都包含由实际目录内容组成(如别名、文件和目录)的多个条目,因此,它还有一个与 **Entry** 类关联的聚合。 + +File 类 +^^^^^^^^^^ + +与 **Directory** 类似, **File** 代表文件系统中的单个文件。此类与其分配链中的第一个簇一对一关联。通过这个簇, **File** 类可以访问相应的物理地址,从而修改其内容。每个文件还与属于其父目录的 **Entry** 实例具有一对一关联。 + +Entry 类 +^^^^^^^^^^^ + +**Entry** 类封装了在相应父目录数据区中的文件名或目录名信息。每个文件系统实体(文件/目录)都有一个条目。如果使用符号进行连接,可以让实体具有多个条目。目录使用条目来访问其后代文件和子目录,并实现对树状结构的遍历。此外, **Entry** 还保存了所用文件名(长文件名或 8.3 文件名)相关的名称、扩展名、大小等信息。 + +.. figure:: ../../../_static/tree_fatfs.svg + :align: center + :alt: 树状图 + + +``fatfsgen.py`` +--------------- + +组件 :component_file:`fatfsgen.py ` 在主机上生成 FAT 文件系统。 + +``fatfsgen.py`` 递归式地遍历给定文件夹的目录结构,将文件和(或)目录添加到二进制分区中。用户可以设置脚本生成的分区是否支持磨损均衡和长文件名,以及是否保留原始文件夹在主机上的修改日期和时间。 + +``./fatfsgen.py Espressif`` 命令默认生成一个简单的二进制分区。这里 ``Espressif`` 是生成二进制映像的本地文件夹(包含文件和/或子目录)。 + +:component_file:`fatfsgen.py ` 和 :component_file:`wl_fatfsgen.py ` 脚本都可以用于此目的,二者的区别在于, ``wl_fatfsgen.py`` 首先用 ``fatfsgen.py`` 生成分区,然后再初始化磨损均衡。 + +脚本命令行参数如下:: + + fatfsgen.py [-h] [--output_file OUTPUT_FILE] [--partition_size PARTITION_SIZE] [--sector_size {4096}] [--long_name_support] [--use_default_datetime] input_directory + + --output_file:生成的二进制分区的路径 + --partition_size:定义二进制分区大小(十进制、十六进制或二进制) + --sector_size:扇区大小 + --long_name_support:flag,表示支持长文件名 + --use_default_datetime:flag,强制使用默认的日期和时间 (date == 0x2100, time == 0x0000),不使用参数保留原始文件系统元数据 + input_directory:必填参数,编码到二进制分区 fat-compatibile 的目录名称 + +``fatfsparse.py`` +----------------- + +:component_file:`fatfsparse.py ` 将二进制映像转换成内部表示,并在主机上生成具有等效内容的文件夹。如果要求解析分区具有初始化磨损均衡, ``fatfsparse.py`` 会使用 ``wl_fatfsgen.py`` 提供的 ``remove_wl`` 函数删除磨损均衡扇区。删除扇区后,对分区的解析和没有初始磨损均衡的情况相同。 + +``./fatfsparse.py fatfs_image.img`` 命令会生成与二进制数据映像 ``fatfs_image.img`` 具有等效内容的目录。 + +脚本命令行参数如下:: + + fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] input_image + + --wl-layer:表示是否启用、禁用或应检测磨损均衡(模糊检测) + input_image:二进制映像的路径 + +长文件名可以自动检测,但无法 100\% 检测出磨损均衡,因为根据用户的上下文,一个分区在有或没有磨损均衡的情况下都是有效的。脚本找到磨损均衡扇区(cfg 和 state)时,会假设磨损均衡已启用,但实际不一定启用。 + + +支持功能 +------------ + +FAT12/FAT16 +^^^^^^^^^^^^ + +支持 FAT12 和 FAT16。对于较小的分区,使用 FAT12 即可。具体选择根据检测簇数决定,用户无法进行更改。如果分区簇数小于 4085,会选择 FAT12(FAT 的条目为 12 位)。如果分区簇数在 4085 到 65526 之间(不包括 4085 和 65526),会选择 FAT16。目前 ``fatfsgen.py`` 或 ``fatfsparse.py`` 不能处理簇数超过 65525 的文件系统。 + +.. _fafsgen-wear-levelling: + +磨损均衡 +^^^^^^^^^^^^^^ +与磨损均衡层相关的操作有两个,即初始化磨损均衡记录,和在生成及解析 FAT 文件系统映像时删除磨损均衡记录。 + +1. 初始化磨损均衡 + +生成支持磨损均衡的新映像时,脚本会初始化磨损均衡功能所需的几个额外扇区。 + + - 虚拟扇区:位于分区起始位置的空扇区,文件系统挂载时会被忽略。虚拟扇区复制下一个扇区的内容,在特定数量的擦除周期后,与下一个扇区交换位置(如果虚拟扇区已是最后一个扇区,则与第一个扇区交换位置)。这样,每个 FAT 文件系统扇区会遍历整个 flash 分区,而与此扇区对应的擦除周期也会分布在整个 flash 上。 + + - 状态扇区:状态扇区存储了 64 字节的数据。 + - pos:虚拟扇区的位置 + - max_pos:分区中的扇区数(不包括配置扇区和状态扇区) + - move_count:表示虚拟扇区遍历整个 flash 的次数 + - access_count:虚拟扇区交换位置前的扇区擦除周期数 + - max_count:等于 wl_config_t::updaterate + - block_size:等于 wl_config_t::page_size + - version:等于 wl_config_t::version + - device_id:在状态扇区次初始化时随机生成 + - reserved:7 x 32 位,设置为 0 + - crc32:前面所有字段的 crc32,包括保留字段 + + 此外,状态扇区会对每个 ``pos`` 值增加 16 字节的 ``pos update record``。该记录会帮助确定虚拟扇区的位置。 + + 由于状态扇区的 ``erase + write`` 不是原子操作,在 “erase” 和 “write” 之间断电可能会导致数据丢失。不过状态扇区保留了两份副本,可以在断电后帮助复原。每次更新时两份副本都会更新,因此,断电后可以恢复原来的有效状态扇区。 + + - 配置扇区:此扇区包含磨损均衡层使用的分区信息。 + - start_addr:分区的起始地址(始终为 0) + - full_mem_size:分区大小,包括数据、虚拟、状态 x 2 和配置扇区,单位为字节 + - page_size:等于扇区大小(通常为 4096) + - sector_size:对于 ESP-IDF 支持的 NOR flash 类型,始终为 4096 + - updaterate:ESP-IDF 始终将此值设置为 16。需要时可将其用作配置选项 + - wr_size:始终设置为 16 + - version:当前版本为 2 + - temp_buff_size:始终设置为 32(实际不应该存储在 flash 中) + - crc:之前所有值的 crc32 + +2. 删除磨损均衡 +删除磨损均衡记录时,须找到虚拟扇区的位置以及分区的原始有效顺序(因为遍历虚拟扇区会打乱分区)。脚本可以从分区中删除其他磨损均衡扇区。删除磨损均衡记录的步骤如下: + + - 找到虚拟扇区位置 ``pos``。该位置由状态扇区中 ``pos update records`` 的数量决定。 + - 删除虚拟扇区并合并虚拟扇区前后的剩余扇区,从而创建新映像。 + - 删除分区末尾的磨损均衡状态扇区和配置扇区。 + - 对新映像重新排序以获得其原始顺序。 ``move_count`` 可以找到分区的起点。分区会从 ``end_of_partition - move_count`` 位置开始,因此删除磨损均衡扇区后,分区的起始位置是 ``partition[end_of_partition - (move_count*page_size)]``。 + +文件名编码 +^^^^^^^^^^^^^^^^^^^ + +FAT 协议支持两种类型的文件名。 + +短文件名 (SFN) +^^^^^^^^^^^^^^^^^^^^^^ + +文件名必须遵循 SFN 规范。SFN 指 8.3 文件名规范,即文件名为 8 个字符,扩展名为 3 个字符。这种模式不区分大小写,但在生成器的内部表示中,所有文件名都会改为大写。描述短文件名的条目长 32 字节,其结构如下:: + + Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 0x000000: 46 49 4C 45 4E 41 4D 45 45 58 54 20 18 00 00 00 FILENAMEEXT..... + 0x000010: 21 00 21 00 00 00 00 00 21 00 02 00 1E 00 00 00 !.!.....!....... + +该条目表示当前文件名遵循 8.3 文件名规范 ("FILENAME.EXT") __(0x00/00-0A)__,文件名大小为 0x1E = 30 字节 __(0x10/0x0C)__,默认修改和创建时间为 (0x0021) __(0x10/00,02 和 08)__。文件相关的簇位于 __0x02 (0x10/0A)__。注意,每个字符用 1 个字节编码(例如,__0x46 == 'F'__)。 + +长文件名 (LFN) +^^^^^^^^^^^^^^^^^^^^^ + +长文件名 LFN 支持 255 个字符,不包括末尾的 ``NULL``。LFN 支持短文件名中的任何字符,以及句点 ``.`` 和特殊字符 ``+ , ; = [ ]``。LFN 使用 UNICODE,因此每个字符用 2 个字节编码。 + +使用 LFN 编码的文件名称结构如下:: + + 00003000: 42 65 00 2E 00 74 00 78 00 74 00 0F 00 43 FF FF Be...t.x.t...C.. + 00003010: FF FF FF FF FF FF FF FF FF FF 00 00 FF FF FF FF ................ + 00003020: 01 74 00 68 00 69 00 73 00 69 00 0F 00 43 73 00 .t.h.i.s.i...Cs. + 00003030: 6C 00 6F 00 6E 00 67 00 66 00 00 00 69 00 6C 00 l.o.n.g.f...i.l. + 00003040: 54 48 49 53 49 53 7E 31 54 58 54 20 00 00 D6 45 THISIS~1TXT...VE + 00003050: 26 55 26 55 00 00 D6 45 26 55 02 00 1C 00 00 00 &U&U..VE&U...... + +上述示例展示了文件名 ``thisislongfile.txt`` 的编码。该记录由多个条目组成,第一个条目包含元数据,相当于 SFN 条目。如果文件名符合 8.3 文件名规范,该条目可能就是最后的条目,使用 SFN 文件名编码结构。否则,生成器会在 SFN 条目上方添加具有上述 LFN 结构的多个条目,其中包含有关文件名及其一致性校验和的信息。每个 LFN 可以容纳 13 个字符(26 字节)。文件名首先会被切分成一定数量的 13 个字符的子串,这些子串会被添加到 SFN 条目上方。 + +LFN 条目以逆序添加,因此,目录中的第一个条目是文件名的最后一部分,即 SFN 条目。在上述示例中,第一个条目包含文本 ``e.txt``,而另外的条目包含文件名开头部分 ``thisislongfil``。LFN 条目的第一个字节表示顺序或序列号(从 1 开始编号)。要确定 LFN 的第一个条目,第一个字节会被掩码为 0x40 (``first_byte =| 0x40``)。最后一个条目的值会与 0x40 进行 OR 运算,作为最后一个条目的标记。例如,当记录是 LFN 条目中的第二条也是最后一条时,其第一个字节是 ``0x42``。 + +LFN 条目在 **DIR_Attr** 字段的值为 ``ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID`` (参见文件 ``long_filename_utils.py`` )。SFN 条目在此字段中包含 ``ATTR_DIRECTORY`` 或 ``ATTR_ARCHIVE`` (LFN 中可能也包含这两个值),分别表示目录或文件。 + +LFN 条目在 **DIR_NTRes** 字段上标记为 ``0x00``。这是 SFN 条目在 LFN 记录中的标志,如果条目是一个完整 SFN 记录,值为 ``0x18``。在第一个示例中,该字段中此值为 ``0x18``,因为名称 **"FILENAME.EXT"** 同样符合 SFN 规范。然而,上一个示例 **"thisislongfile.txt"** 在最后一个条目的 **DIR_NTRes** 字段中值为 ``0x00``,这是因为它仅符合 LFN 规范。SFN 须唯一。为此, ``fatfsgen.py`` 使用文件名的前 6 个字符,将其与 ``~`` 和一个 ID 相连接。这一 ID 表示该文件名在相同前缀的文件名中的顺序,范围 在 0 到 127 之间,127 是具有相同前缀的文件的最大数量。 + +校验和的计算在 ``utils.py`` 中由函数 ``lfn_checksum`` 描述并实现。 ``fatfsparse.py`` 假设 LFN 条目可能不会紧挨彼此,但保留了彼此的相对顺序。这一脚本首先用 **DIR_NTRes** 字段找到属于某个 LFN 记录的 SFN,然后开始在相应扇区自下而上进行搜索,直至找到 LFN 记录中的最后一个条目(前半字节等于 4 的条目)。脚本通过校验和来区分条目。这一过程结束后,即可组成文件名。 + +FAT 文件系统中的日期和时间 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ESP-IDF 使用的 FAT 文件系统协议不保留芯片介质上的日期或时间,因此,从设备中提取的所有映像都具有相同的默认时间戳,这个时间戳会应用到所有 FAT 相关的日期和时间字段上,包括创建、最后修改时间戳,以及创建、最后修改和最后访问日期。 + +SFN 条目中有几个描述时间的字段,如 **DIR_CrtTime** 和 **DIR_WrtTime**。ESP-IDF 的 FAT 实现过程会忽略一些字段(参见文件 ``entry.py``),然而 **DIR_WrtTime** 和 **DIR_WrtDate** 字段的更改会保留在芯片中。时间和数据条目都是 16 位的,其中时间粒度为 2 秒。 From 4118244f5940581a65a1a1967ba9929b19dd4924 Mon Sep 17 00:00:00 2001 From: Wu Meng Shi Date: Fri, 22 Sep 2023 11:59:12 +0800 Subject: [PATCH 67/71] bugfix(mesh): remove reset link state on receiving prov_data packets --- components/bt/esp_ble_mesh/core/prov_node.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index d32e4f2af3c..bf6bb3cb85e 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -944,8 +944,6 @@ static void prov_data(const uint8_t *data) /* Ignore any further PDUs on this link */ prov_link.expect = 0U; - reset_state(); - #if CONFIG_BLE_MESH_RPR_SRV /* For NPPI, no need to perform the following actions */ if (bt_mesh_atomic_test_bit(prov_link.flags, PB_NPPI)) { From 3e43a6b69f95b87617546cbb549a0db60274b421 Mon Sep 17 00:00:00 2001 From: Wu Meng Shi Date: Fri, 22 Sep 2023 14:20:38 +0800 Subject: [PATCH 68/71] bugfix(mesh): Fix PB-GATT adv is reported to the app layer too frequently --- components/bt/esp_ble_mesh/core/prov_pvnr.c | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index 8c200be7780..4a57e44e1ae 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -35,6 +35,8 @@ _Static_assert(BLE_MESH_MAX_CONN >= CONFIG_BLE_MESH_PBG_SAME_TIME, #define UNICAST_ADDR_LIMIT 0x7FFF +#define PROV_SVC_ADV_RX_CHECK(pre, cur) ((cur) < (pre) ? ((cur) + (UINT32_MAX - (pre)) >= 200) : ((cur) - (pre) >= 200)) + /* Provisioner link structure allocation * |--------------------------------------------------------| * | Link(PB-ADV) | Link(PB-GATT) | @@ -2923,6 +2925,21 @@ int bt_mesh_provisioner_prov_deinit(bool erase) } #endif /* CONFIG_BLE_MESH_DEINIT */ +static bool bt_mesh_prov_svc_adv_filter(void) +{ + static uint32_t timestamp = 0; + static uint32_t pre_timestamp = 0; + + timestamp = k_uptime_get_32(); + + if (PROV_SVC_ADV_RX_CHECK(pre_timestamp, timestamp)) { + pre_timestamp = timestamp; + return false; + } + + return true; +} + static bool notify_unprov_dev_info(bt_mesh_prov_bearer_t bearer, const uint8_t uuid[16], const bt_mesh_addr_t *addr, uint16_t oob_info, int8_t rssi) { @@ -2940,6 +2957,11 @@ static bool notify_unprov_dev_info(bt_mesh_prov_bearer_t bearer, const uint8_t u if (i == ARRAY_SIZE(unprov_dev)) { BT_DBG("Device not in queue, notify to app layer"); + + if (bt_mesh_prov_svc_adv_filter()) { + return true; + } + if (notify_unprov_adv_pkt_cb) { notify_unprov_adv_pkt_cb(addr->val, addr->type, adv_type, uuid, oob_info, bearer, rssi); From 735fab40cdd4a739b9a7468c1ae84879fc4b1383 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 29 May 2023 10:25:55 +0200 Subject: [PATCH 69/71] fix(soc): correct SOC_IROM_MASK_HIGH for esp32s3 Fixes corrupted backtraces on S3 when a function is in ROM. Closes https://github.com/espressif/esp-idf/issues/11512 --- components/soc/esp32s3/include/soc/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/soc/esp32s3/include/soc/soc.h b/components/soc/esp32s3/include/soc/soc.h index a2d50317690..37c0cb2502d 100644 --- a/components/soc/esp32s3/include/soc/soc.h +++ b/components/soc/esp32s3/include/soc/soc.h @@ -187,7 +187,7 @@ #define SOC_EXTRAM_DATA_LOW 0x3C000000 #define SOC_EXTRAM_DATA_HIGH 0x3E000000 #define SOC_IROM_MASK_LOW 0x40000000 -#define SOC_IROM_MASK_HIGH 0x4001A100 +#define SOC_IROM_MASK_HIGH 0x40060000 #define SOC_EXTRAM_DATA_SIZE (SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW) #define SOC_MAX_CONTIGUOUS_RAM_SIZE (SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW) ///< Largest span of contiguous memory (DRAM or IRAM) in the address space From 2ac972e2c7a46c95d681a9b044d0683fdcafe66e Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 13 Jun 2023 11:17:22 +0200 Subject: [PATCH 70/71] fix(soc): update SOC_IROM_MASK_HIGH for esp32, c6, h2 for consistency --- components/soc/esp32/include/soc/soc.h | 2 +- components/soc/esp32c6/include/soc/soc.h | 4 ++-- components/soc/esp32h2/include/soc/soc.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/soc/esp32/include/soc/soc.h b/components/soc/esp32/include/soc/soc.h index d02aa8277e5..05e2a3fb7ee 100644 --- a/components/soc/esp32/include/soc/soc.h +++ b/components/soc/esp32/include/soc/soc.h @@ -178,7 +178,7 @@ #define SOC_IROM_LOW 0x400D0000 #define SOC_IROM_HIGH 0x40400000 #define SOC_IROM_MASK_LOW 0x40000000 -#define SOC_IROM_MASK_HIGH 0x40064F00 +#define SOC_IROM_MASK_HIGH 0x40070000 #define SOC_CACHE_PRO_LOW 0x40070000 #define SOC_CACHE_PRO_HIGH 0x40078000 #define SOC_CACHE_APP_LOW 0x40078000 diff --git a/components/soc/esp32c6/include/soc/soc.h b/components/soc/esp32c6/include/soc/soc.h index b89a2529721..97fe076c6f3 100644 --- a/components/soc/esp32c6/include/soc/soc.h +++ b/components/soc/esp32c6/include/soc/soc.h @@ -159,8 +159,8 @@ #define SOC_DROM_LOW SOC_IROM_LOW #define SOC_DROM_HIGH SOC_IROM_HIGH #define SOC_IROM_MASK_LOW 0x40000000 -#define SOC_IROM_MASK_HIGH 0x4004AC00 -#define SOC_DROM_MASK_LOW 0x4004AC00 +#define SOC_IROM_MASK_HIGH 0x40050000 +#define SOC_DROM_MASK_LOW 0x40000000 #define SOC_DROM_MASK_HIGH 0x40050000 #define SOC_IRAM_LOW 0x40800000 #define SOC_IRAM_HIGH 0x40880000 diff --git a/components/soc/esp32h2/include/soc/soc.h b/components/soc/esp32h2/include/soc/soc.h index a08c4929ae7..a560492e7fd 100644 --- a/components/soc/esp32h2/include/soc/soc.h +++ b/components/soc/esp32h2/include/soc/soc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -157,8 +157,8 @@ #define SOC_DROM_LOW SOC_IROM_LOW #define SOC_DROM_HIGH SOC_IROM_HIGH #define SOC_IROM_MASK_LOW 0x40000000 -#define SOC_IROM_MASK_HIGH 0x4001C400 -#define SOC_DROM_MASK_LOW 0x4001C400 +#define SOC_IROM_MASK_HIGH 0x40020000 +#define SOC_DROM_MASK_LOW 0x40000000 #define SOC_DROM_MASK_HIGH 0x40020000 #define SOC_IRAM_LOW 0x40800000 #define SOC_IRAM_HIGH 0x40850000 From 467a28f7913fd671ec2a481c26199e2bcf1ea67e Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Mon, 18 Sep 2023 19:28:09 +0800 Subject: [PATCH 71/71] fix(usb_serial_jtag): Clean-up usb_serial_jtag lose byte fix, Closes https://github.com/espressif/esp-idf/pull/11344 --- .../driver/usb_serial_jtag/usb_serial_jtag.c | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/components/driver/usb_serial_jtag/usb_serial_jtag.c b/components/driver/usb_serial_jtag/usb_serial_jtag.c index 19268338cb2..01df0ae39cb 100644 --- a/components/driver/usb_serial_jtag/usb_serial_jtag.c +++ b/components/driver/usb_serial_jtag/usb_serial_jtag.c @@ -27,7 +27,7 @@ typedef struct{ // RX parameters RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler */ uint32_t rx_buf_size; /*!< TX buffer size */ - uint8_t rx_data_buf[64]; /*!< Data buffer to stash FIFO data */ + uint8_t rx_data_buf[USB_SER_JTAG_ENDP_SIZE]; /*!< Data buffer to stash FIFO data */ // TX parameters uint32_t tx_buf_size; /*!< TX buffer size */ @@ -40,9 +40,9 @@ static usb_serial_jtag_obj_t *p_usb_serial_jtag_obj = NULL; static const char* USB_SERIAL_JTAG_TAG = "usb_serial_jtag"; -static int usb_serial_jtag_write_and_flush(const uint8_t *buf, uint32_t wr_len) +static size_t usb_serial_jtag_write_and_flush(const uint8_t *buf, uint32_t wr_len) { - int size = usb_serial_jtag_ll_write_txfifo(buf, wr_len); + size_t size = usb_serial_jtag_ll_write_txfifo(buf, wr_len); usb_serial_jtag_ll_txfifo_flush(); return size; } @@ -56,7 +56,7 @@ static void usb_serial_jtag_isr_handler_default(void *arg) { // Interrupt tells us the host picked up the data we sent. // If we have more data, we can put it in the buffer and the host will pick that up next. // Send data in isr. - // If the hardware fifo is avaliable, write in it. Otherwise, do nothing. + // If the hardware fifo is available, write in it. Otherwise, do nothing. if (usb_serial_jtag_ll_txfifo_writable() == 1) { // We disable the interrupt here so that the interrupt won't be triggered if there is no data to send. usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); @@ -68,8 +68,7 @@ static void usb_serial_jtag_isr_handler_default(void *arg) { queued_buff = p_usb_serial_jtag_obj->tx_data_buf; queued_size = p_usb_serial_jtag_obj->tx_stash_cnt; is_stashed_data = true; - } - else { + } else { // Max 64 data payload size in a single EndPoint queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(p_usb_serial_jtag_obj->tx_ring_buf, &queued_size, USB_SER_JTAG_ENDP_SIZE); } @@ -88,14 +87,14 @@ static void usb_serial_jtag_isr_handler_default(void *arg) { if (sent_size < queued_size) { // Not all bytes could be sent at once, stash the unwritten bytes in a tx buffer - size_t stash_size = MIN(USB_SER_JTAG_ENDP_SIZE, queued_size - sent_size); - - // Copy the missed bytes to tx stash buffer. May copy from stash buffer to itself + // stash_size will not larger than USB_SER_JTAG_ENDP_SIZE because queued_size is got from xRingbufferReceiveUpToFromISR + size_t stash_size = queued_size - sent_size; memcpy(p_usb_serial_jtag_obj->tx_data_buf, &queued_buff[sent_size], stash_size); p_usb_serial_jtag_obj->tx_stash_cnt = stash_size; - } - else { + } else { p_usb_serial_jtag_obj->tx_stash_cnt = 0; + // assert if sent_size is larger than queued_size. + assert(sent_size <= queued_size); } } if (is_stashed_data == false) { @@ -200,8 +199,6 @@ int usb_serial_jtag_write_bytes(const void* src, size_t size, TickType_t ticks_t ESP_RETURN_ON_FALSE(src != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "Invalid buffer pointer."); ESP_RETURN_ON_FALSE(p_usb_serial_jtag_obj != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "The driver hasn't been initialized"); - int ret_size = 0; - const uint8_t *buff = (const uint8_t *)src; // Blocking method, Sending data to ringbuffer, and handle the data in ISR. BaseType_t result = xRingbufferSend(p_usb_serial_jtag_obj->tx_ring_buf, (void*) (buff), size, ticks_to_wait);