From bce129d1aeb53881a16daf8a5023de02b71f5445 Mon Sep 17 00:00:00 2001 From: Martin Havlik Date: Mon, 6 Oct 2025 15:19:06 +0200 Subject: [PATCH 01/84] feat(examples/storage): Add NVS statistics example Add a new example showcasing how to obtain and interpret statistics about the usage of an NVS partition. Also demonstrates how stats change after writing some key-value pairs in 2 separate namespaces. --- examples/storage/README.md | 2 + examples/storage/nvs/.build-test-rules.yml | 7 + .../storage/nvs/nvs_statistics/CMakeLists.txt | 8 + examples/storage/nvs/nvs_statistics/README.md | 119 +++++++++ .../nvs/nvs_statistics/main/CMakeLists.txt | 3 + .../main/nvs_statistics_example.c | 234 ++++++++++++++++++ .../nvs_statistics/pytest_nvs_statistics.py | 17 ++ .../storage/nvs/nvs_statistics/sdkconfig.ci | 0 8 files changed, 390 insertions(+) create mode 100644 examples/storage/nvs/nvs_statistics/CMakeLists.txt create mode 100644 examples/storage/nvs/nvs_statistics/README.md create mode 100644 examples/storage/nvs/nvs_statistics/main/CMakeLists.txt create mode 100644 examples/storage/nvs/nvs_statistics/main/nvs_statistics_example.c create mode 100644 examples/storage/nvs/nvs_statistics/pytest_nvs_statistics.py create mode 100644 examples/storage/nvs/nvs_statistics/sdkconfig.ci diff --git a/examples/storage/README.md b/examples/storage/README.md index 36b74acd12..f3f1e7c351 100644 --- a/examples/storage/README.md +++ b/examples/storage/README.md @@ -18,6 +18,8 @@ The examples are grouped into sub-directories by category. Each category directo * `nvs_rw_value` example demonstrates how to read and write a single integer value using NVS. * `nvs_rw_value_cxx` example demonstrates how to read and write a single integer value using NVS (it uses the C++ NVS handle API). * `nvs_console` example demonstrates how to use NVS through an interactive console interface. +* `nvs_statistics` example demonstrates how to obtain and interpret stats about used/available NVS storage entries in given NVS partition. +* `nvs_iteration` TODO * `partition_api` examples demonstrate how to use different partition APIs. * `parttool` example demonstrates common operations the partitions tool allows the user to perform. * `sd_card` examples demonstrate how to use an SD card with an ESP device. diff --git a/examples/storage/nvs/.build-test-rules.yml b/examples/storage/nvs/.build-test-rules.yml index aada4fee7e..2825974a74 100644 --- a/examples/storage/nvs/.build-test-rules.yml +++ b/examples/storage/nvs/.build-test-rules.yml @@ -45,3 +45,10 @@ examples/storage/nvs/nvsgen: disable_test: - if: IDF_TARGET != "esp32" reason: only one target needed + +examples/storage/nvs/nvs_statistics: + depends_components: + - nvs_flash + disable_test: + - if: IDF_TARGET not in ["esp32", "esp32c3"] + reason: only one target per arch needed \ No newline at end of file diff --git a/examples/storage/nvs/nvs_statistics/CMakeLists.txt b/examples/storage/nvs/nvs_statistics/CMakeLists.txt new file mode 100644 index 0000000000..daddbbc620 --- /dev/null +++ b/examples/storage/nvs/nvs_statistics/CMakeLists.txt @@ -0,0 +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.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(nvs_statistics) diff --git a/examples/storage/nvs/nvs_statistics/README.md b/examples/storage/nvs/nvs_statistics/README.md new file mode 100644 index 0000000000..6991746e29 --- /dev/null +++ b/examples/storage/nvs/nvs_statistics/README.md @@ -0,0 +1,119 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | + +# Non-Volatile Storage (NVS) Statistics Example + +This example demonstrates the usage of obtaining and interpreting statistics about the a given NVS partition, namely free/used/available/total entries and namespace count. + +The default "nvs" partition is first erased, then a mock string data configuration is written to 2 different namespaces, followed by checking the changed statistics and mainly the number of newly used NVS entries. + +Statistics obtained via [nvs_get_stats()](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_flash.html#_CPPv413nvs_get_statsPKcP11nvs_stats_t) are the following: +| | | +| -------------- | ------------------- | +| `available entries` | Essential statistic, specifies free non-reserved entries available for data storage. | +| `used entries` | Includes 1 overhead entry per namespace + actual data entries used by data storage. | +| `free entries` | Free entries are both the free available to the user entries, and free but internally reserved (not available to the user). | +| `total entries` | Number of all entries (free + used). | + + +Detailed functional description of NVS and API is provided in [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html). + +## How to use example + +### Hardware required + +This example does not require any special hardware, and can be run on any common development board. + +### Build and flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +... +I (265) nvs_statistics_example: Erasing the contents of the default NVS partition... +I (475) nvs_statistics_example: Opening Non-Volatile Storage (NVS) handle for namespace '_mock_data'... +I (485) nvs_statistics_example: Getting NVS statistics... +I (485) nvs_statistics_example: NVS statistics: +I (485) nvs_statistics_example: Used NVS entries: 1 +I (485) nvs_statistics_example: Free NVS entries: 755 +I (495) nvs_statistics_example: Available NVS entries: 629 +I (495) nvs_statistics_example: Total NVS entries: 756 +I (505) nvs_statistics_example: Namespace count: 1 +I (505) nvs_statistics_example: Writing mock data key-value pairs to NVS namespace '_mock_data'... +I (525) nvs_statistics_example: Committing data in NVS namespace '_mock_data'... +I (525) nvs_statistics_example: Getting post-commit NVS statistics... +I (525) nvs_statistics_example: NVS statistics: +I (535) nvs_statistics_example: Used NVS entries: 30 +I (535) nvs_statistics_example: Free NVS entries: 726 +I (545) nvs_statistics_example: Available NVS entries: 600 +I (545) nvs_statistics_example: Total NVS entries: 756 +I (555) nvs_statistics_example: Namespace count: 1 +I (555) nvs_statistics_example: Newly used entries match expectation. +I (565) nvs_statistics_example: Newly used entries: 29, expected: 29. +I (575) nvs_statistics_example: NVS handle for namespace '_mock_data' closed. +I (575) nvs_statistics_example: Opening Non-Volatile Storage (NVS) handle for namespace '_mock_data'... +I (585) nvs_statistics_example: Reading stored data from NVS namespace '_mock_data'... +I (595) nvs_statistics_example: Read key-value pair from NVS: 'wifi_ssid':'HomeNetwork' +I (605) nvs_statistics_example: Read key-value pair from NVS: 'wifi_pass':'MySecretPass' +I (605) nvs_statistics_example: Read key-value pair from NVS: 'dev_name':'LivingRoomThermostat' +I (615) nvs_statistics_example: Read key-value pair from NVS: 'temp_unit':'Celsius' +I (625) nvs_statistics_example: Read key-value pair from NVS: 'target_temp':'22' +I (635) nvs_statistics_example: Read key-value pair from NVS: 'eco_mode':'false' +I (635) nvs_statistics_example: Read key-value pair from NVS: 'fw_version':'1.2.3' +I (645) nvs_statistics_example: Read key-value pair from NVS: 'led_bright':'80' +I (655) nvs_statistics_example: Read key-value pair from NVS: 'auto_update':'true' +I (665) nvs_statistics_example: Read key-value pair from NVS: 'last_sync':'2025-01-01T08:00:00Z' +I (665) nvs_statistics_example: Read key-value pair from NVS: 'user_lang':'en' +I (675) nvs_statistics_example: Read key-value pair from NVS: 'long_token':'2f8c1e7b5a4d9c6e3b0f1a8e5d7c2b6f4e1a9c7b' +I (685) nvs_statistics_example: Read key-value pair from NVS: 'very_long_token':'7e2b1c9f5a4d8e3b0f1a6c7e2d9b5a4c8e1f7b2d6c3a9e5b0f1a8c7e2d9b5a4c8e1f7b2d6c3a9e5b' +I (705) nvs_statistics_example: NVS handle for namespace '_mock_data' closed. +I (705) nvs_statistics_example: Opening Non-Volatile Storage (NVS) handle for namespace '_mock_backup'... +I (715) nvs_statistics_example: Getting NVS statistics... +I (725) nvs_statistics_example: NVS statistics: +I (725) nvs_statistics_example: Used NVS entries: 31 +I (735) nvs_statistics_example: Free NVS entries: 725 +I (735) nvs_statistics_example: Available NVS entries: 599 +I (745) nvs_statistics_example: Total NVS entries: 756 +I (745) nvs_statistics_example: Namespace count: 2 +I (755) nvs_statistics_example: Writing mock data key-value pairs to NVS namespace '_mock_backup'... +I (765) nvs_statistics_example: Committing data in NVS namespace '_mock_backup'... +I (765) nvs_statistics_example: Getting post-commit NVS statistics... +I (775) nvs_statistics_example: NVS statistics: +I (775) nvs_statistics_example: Used NVS entries: 60 +I (785) nvs_statistics_example: Free NVS entries: 696 +I (785) nvs_statistics_example: Available NVS entries: 570 +I (795) nvs_statistics_example: Total NVS entries: 756 +I (795) nvs_statistics_example: Namespace count: 2 +I (805) nvs_statistics_example: Newly used entries match expectation. +I (805) nvs_statistics_example: Newly used entries: 29, expected: 29. +I (815) nvs_statistics_example: NVS handle for namespace '_mock_backup' closed. +I (825) nvs_statistics_example: Opening Non-Volatile Storage (NVS) handle for namespace '_mock_backup'... +I (835) nvs_statistics_example: Reading stored data from NVS namespace '_mock_backup'... +I (835) nvs_statistics_example: Read key-value pair from NVS: 'wifi_ssid':'HomeNetwork' +I (845) nvs_statistics_example: Read key-value pair from NVS: 'wifi_pass':'MySecretPass' +I (855) nvs_statistics_example: Read key-value pair from NVS: 'dev_name':'LivingRoomThermostat' +I (865) nvs_statistics_example: Read key-value pair from NVS: 'temp_unit':'Celsius' +I (865) nvs_statistics_example: Read key-value pair from NVS: 'target_temp':'22' +I (875) nvs_statistics_example: Read key-value pair from NVS: 'eco_mode':'false' +I (885) nvs_statistics_example: Read key-value pair from NVS: 'fw_version':'1.2.3' +I (895) nvs_statistics_example: Read key-value pair from NVS: 'led_bright':'80' +I (895) nvs_statistics_example: Read key-value pair from NVS: 'auto_update':'true' +I (905) nvs_statistics_example: Read key-value pair from NVS: 'last_sync':'2025-01-01T08:00:00Z' +I (915) nvs_statistics_example: Read key-value pair from NVS: 'user_lang':'en' +I (925) nvs_statistics_example: Read key-value pair from NVS: 'long_token':'2f8c1e7b5a4d9c6e3b0f1a8e5d7c2b6f4e1a9c7b' +I (935) nvs_statistics_example: Read key-value pair from NVS: 'very_long_token':'7e2b1c9f5a4d8e3b0f1a6c7e2d9b5a4c8e1f7b2d6c3a9e5b0f1a8c7e2d9b5a4c8e1f7b2d6c3a9e5b' +I (945) nvs_statistics_example: NVS handle for namespace '_mock_backup' closed. +I (955) nvs_statistics_example: Returning from app_main(). +I (955) main_task: Returned from app_main() +... +``` \ No newline at end of file diff --git a/examples/storage/nvs/nvs_statistics/main/CMakeLists.txt b/examples/storage/nvs/nvs_statistics/main/CMakeLists.txt new file mode 100644 index 0000000000..46493172d9 --- /dev/null +++ b/examples/storage/nvs/nvs_statistics/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "nvs_statistics_example.c" + PRIV_REQUIRES nvs_flash + INCLUDE_DIRS ".") diff --git a/examples/storage/nvs/nvs_statistics/main/nvs_statistics_example.c b/examples/storage/nvs/nvs_statistics/main/nvs_statistics_example.c new file mode 100644 index 0000000000..9b74d99d78 --- /dev/null +++ b/examples/storage/nvs/nvs_statistics/main/nvs_statistics_example.c @@ -0,0 +1,234 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Non-Volatile Storage (NVS) Statistics Example + + For other examples please check: + https://github.com/espressif/esp-idf/tree/master/examples + + 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 +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_check.h" +#include "esp_system.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "nvs.h" + +#define MOCK_DATA_NAMESPACE "_mock_data" +#define MOCK_DATA_BACKUP_NAMESPACE "_mock_backup" + +static const char *TAG = "nvs_statistics_example"; + +// Maximum key character length is 15 (NVS_KEY_NAME_MAX_SIZE-1) +static const char* mock_data_keys[] = { + "wifi_ssid", + "wifi_pass", + "dev_name", + "temp_unit", + "target_temp", + "eco_mode", + "fw_version", + "led_bright", + "auto_update", + "last_sync", + "user_lang", + "long_token", + "very_long_token" +}; + +// String values are limited in length by NVS implementation to 4000 bytes (including null character) +// Each string value occupies 1 overhead NVS entry + 1 NVS entry per each 32 characters including null character +#define CHARS_PER_STRING_VALUE_ENTRY 32 +static const char* mock_data_values[] = { + "HomeNetwork", + "MySecretPass", + "LivingRoomThermostat", + "Celsius", + "22", + "false", + "1.2.3", + "80", + "true", + "2025-01-01T08:00:00Z", + "en", + "2f8c1e7b5a4d9c6e3b0f1a8e5d7c2b6f4e1a9c7b", + "7e2b1c9f5a4d8e3b0f1a6c7e2d9b5a4c8e1f7b2d6c3a9e5b0f1a8c7e2d9b5a4c8e1f7b2d6c3a9e5b" +}; + +static const size_t mock_data_count = sizeof(mock_data_keys) / sizeof(mock_data_keys[0]); + +static void print_nvs_stats(nvs_stats_t *nvs_stats) +{ + ESP_LOGI(TAG, "NVS statistics:"); + ESP_LOGI(TAG, "Used NVS entries: %u", nvs_stats->used_entries); + ESP_LOGI(TAG, "Free NVS entries: %u", nvs_stats->free_entries); + ESP_LOGI(TAG, "Available NVS entries: %u", nvs_stats->available_entries); + ESP_LOGI(TAG, "Total NVS entries: %u", nvs_stats->total_entries); + ESP_LOGI(TAG, "Namespace count: %u", nvs_stats->namespace_count); +} + +static size_t calculate_expected_entries_for_string_array(const char** string_array, size_t array_size) +{ + size_t expected_newly_used_entries = 0; + for (int i = 0; i < array_size; i++) { + // Each string occupies 1 overhead entry + 1 entry per each 32 characters including null character + size_t str_len = strlen(string_array[i]); + size_t span = 1 + ((str_len + CHARS_PER_STRING_VALUE_ENTRY - 1) / CHARS_PER_STRING_VALUE_ENTRY); // 1 overhead + integer division rounding up + expected_newly_used_entries += span; + } + return expected_newly_used_entries; +} + +static esp_err_t save_mock_data_to_namespace(const char* namespace_name) +{ + ESP_LOGI(TAG, "Opening Non-Volatile Storage (NVS) handle for namespace '%s'...", namespace_name); + nvs_handle_t my_handle; + // Opening NVS storage handle uses up 1 entry for the namespace + esp_err_t ret = nvs_open(namespace_name, NVS_READWRITE, &my_handle); + ESP_RETURN_ON_ERROR(ret, TAG, "Error (%s) opening NVS handle for namespace '%s'!", esp_err_to_name(ret), namespace_name); + + ESP_LOGI(TAG, "Getting NVS statistics..."); + nvs_stats_t nvs_stats; + ret = nvs_get_stats(NVS_DEFAULT_PART_NAME, &nvs_stats); + ESP_GOTO_ON_ERROR(ret, nvs_close_label, TAG, "Error (%s) getting NVS statistics!", esp_err_to_name(ret)); + + // Print the pre-write NVS statistics + print_nvs_stats(&nvs_stats); + + ESP_LOGI(TAG, "Writing mock data key-value pairs to NVS namespace '%s'...", namespace_name); + for (int i = 0; i < mock_data_count; i++) { + // Write string values + ret = nvs_set_str(my_handle, mock_data_keys[i], mock_data_values[i]); + // Don't break/abort on error, try to continue writing + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) writing '%s':'%s' pair!", esp_err_to_name(ret), mock_data_keys[i], mock_data_values[i]); + } + } + + ESP_LOGI(TAG, "Committing data in NVS namespace '%s'...", namespace_name); + ret = nvs_commit(my_handle); + ESP_GOTO_ON_ERROR(ret, nvs_close_label, TAG, "Error (%s) committing data for namespace '%s'!", esp_err_to_name(ret), namespace_name); + + ESP_LOGI(TAG, "Getting post-commit NVS statistics..."); + nvs_stats_t new_nvs_stats; + ret = nvs_get_stats(NVS_DEFAULT_PART_NAME, &new_nvs_stats); + ESP_GOTO_ON_ERROR(ret, nvs_close_label, TAG, "Error (%s) getting NVS statistics!", esp_err_to_name(ret)); + + // Print the post-write NVS statistics + print_nvs_stats(&new_nvs_stats); + + size_t expected_newly_used_entries = calculate_expected_entries_for_string_array(mock_data_values, mock_data_count); + + if (new_nvs_stats.used_entries - nvs_stats.used_entries != expected_newly_used_entries) { + ESP_LOGE(TAG, "Newly used entries: %u, expected: %u.", + new_nvs_stats.used_entries - nvs_stats.used_entries, + expected_newly_used_entries); + } else { + ESP_LOGI(TAG, "Newly used entries match expectation."); + ESP_LOGI(TAG, "Newly used entries: %u, expected: %u.", + new_nvs_stats.used_entries - nvs_stats.used_entries, + expected_newly_used_entries); + } + + nvs_close_label: + // Close the storage handle, freeing allocated resources + nvs_close(my_handle); + ESP_LOGI(TAG, "NVS handle for namespace '%s' closed.", namespace_name); + + return ESP_OK; +} + +static esp_err_t read_mock_data_from_namespace(const char* namespace_name) +{ + ESP_LOGI(TAG, "Opening Non-Volatile Storage (NVS) handle for namespace '%s'...", namespace_name); + nvs_handle_t my_handle; + esp_err_t ret = nvs_open(namespace_name, NVS_READONLY, &my_handle); + ESP_RETURN_ON_ERROR(ret, TAG, "Error (%s) opening NVS handle for namespace '%s'!", esp_err_to_name(ret), namespace_name); + + ESP_LOGI(TAG, "Reading stored data from NVS namespace '%s'...", namespace_name); + for (int i = 0; i < mock_data_count; i++) { + size_t required_size = 0; + // Obtain required size of the string value including null character + ret = nvs_get_str(my_handle, mock_data_keys[i], NULL, &required_size); + if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGE(TAG, "Error (%s) getting required size for key '%s'!", esp_err_to_name(ret), mock_data_keys[i]); + continue; + } + if (ret == ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGW(TAG, "Key '%s' not found in namespace '%s'!", mock_data_keys[i], namespace_name); + continue; + } + + // Allocate memory for the string value + char* value = malloc(required_size); + if (value == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for key '%s'!", mock_data_keys[i]); + continue; + } + + // Read the string value + ret = nvs_get_str(my_handle, mock_data_keys[i], value, &required_size); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) reading key '%s'!", esp_err_to_name(ret), mock_data_keys[i]); + free(value); + continue; + } + + ESP_LOGI(TAG, "Read key-value pair from NVS: '%s':'%s'", mock_data_keys[i], value); + free(value); + } + + // Close the storage handle, freeing allocated resources + nvs_close(my_handle); + ESP_LOGI(TAG, "NVS handle for namespace '%s' closed.", namespace_name); + + return ESP_OK; +} + +void app_main(void) +{ + // Erase the contents of the default NVS partition for clean run of this example + ESP_LOGI(TAG, "Erasing the contents of the default NVS partition..."); + ESP_ERROR_CHECK(nvs_flash_erase()); + + // Initialize NVS on default "nvs" partition + esp_err_t ret = nvs_flash_init(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) initializing NVS on default 'nvs' partition!", esp_err_to_name(ret)); + return; + } + + // Write and read mock data + ret = save_mock_data_to_namespace(MOCK_DATA_NAMESPACE); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) saving mock data data to namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + } + + ret = read_mock_data_from_namespace(MOCK_DATA_NAMESPACE); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) reading back stored data from namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + } + + // Write and read mock data "backup" + ret = save_mock_data_to_namespace(MOCK_DATA_BACKUP_NAMESPACE); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) saving mock data to namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_BACKUP_NAMESPACE); + } + + ret = read_mock_data_from_namespace(MOCK_DATA_BACKUP_NAMESPACE); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) reading back stored data from namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_BACKUP_NAMESPACE); + } + + ESP_LOGI(TAG, "Returning from app_main()."); +} diff --git a/examples/storage/nvs/nvs_statistics/pytest_nvs_statistics.py b/examples/storage/nvs/nvs_statistics/pytest_nvs_statistics.py new file mode 100644 index 0000000000..17fdfe738b --- /dev/null +++ b/examples/storage/nvs/nvs_statistics/pytest_nvs_statistics.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize + + +@pytest.mark.generic +@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target']) +def test_examples_nvs_statistics(dut: Dut) -> None: + dut.expect('Getting post-commit NVS statistics...', timeout=5) + dut.expect('Newly used entries match expectation.', timeout=5) + + dut.expect('Getting post-commit NVS statistics...', timeout=5) + dut.expect('Newly used entries match expectation.', timeout=5) + + dut.expect('Returning from app_main().', timeout=5) diff --git a/examples/storage/nvs/nvs_statistics/sdkconfig.ci b/examples/storage/nvs/nvs_statistics/sdkconfig.ci new file mode 100644 index 0000000000..e69de29bb2 From 15c9aaf3d55f125206c31c738b755ec8dca53d93 Mon Sep 17 00:00:00 2001 From: Martin Havlik Date: Mon, 6 Oct 2025 14:56:56 +0200 Subject: [PATCH 02/84] feat(examples/storage): Add NVS iteration example Add a new example showcasing iterating over NVS entries of a specific (or any) type, and the info to be obtained from therein. --- examples/storage/README.md | 2 +- examples/storage/nvs/.build-test-rules.yml | 22 +- .../storage/nvs/nvs_iteration/CMakeLists.txt | 8 + examples/storage/nvs/nvs_iteration/README.md | 69 ++++++ .../nvs/nvs_iteration/main/CMakeLists.txt | 3 + .../main/nvs_iteration_example.c | 220 ++++++++++++++++++ .../nvs/nvs_iteration/pytest_nvs_iteration.py | 16 ++ .../storage/nvs/nvs_iteration/sdkconfig.ci | 0 8 files changed, 332 insertions(+), 8 deletions(-) create mode 100644 examples/storage/nvs/nvs_iteration/CMakeLists.txt create mode 100644 examples/storage/nvs/nvs_iteration/README.md create mode 100644 examples/storage/nvs/nvs_iteration/main/CMakeLists.txt create mode 100644 examples/storage/nvs/nvs_iteration/main/nvs_iteration_example.c create mode 100644 examples/storage/nvs/nvs_iteration/pytest_nvs_iteration.py create mode 100644 examples/storage/nvs/nvs_iteration/sdkconfig.ci diff --git a/examples/storage/README.md b/examples/storage/README.md index f3f1e7c351..6a29811042 100644 --- a/examples/storage/README.md +++ b/examples/storage/README.md @@ -19,7 +19,7 @@ The examples are grouped into sub-directories by category. Each category directo * `nvs_rw_value_cxx` example demonstrates how to read and write a single integer value using NVS (it uses the C++ NVS handle API). * `nvs_console` example demonstrates how to use NVS through an interactive console interface. * `nvs_statistics` example demonstrates how to obtain and interpret stats about used/available NVS storage entries in given NVS partition. -* `nvs_iteration` TODO +* `nvs_iteration` example demonstrates iterating over entries of specific (or any) data type in given namespace, and the info to be obtained about the entries while doing so. * `partition_api` examples demonstrate how to use different partition APIs. * `parttool` example demonstrates common operations the partitions tool allows the user to perform. * `sd_card` examples demonstrate how to use an SD card with an ESP device. diff --git a/examples/storage/nvs/.build-test-rules.yml b/examples/storage/nvs/.build-test-rules.yml index 2825974a74..2bd58e1c49 100644 --- a/examples/storage/nvs/.build-test-rules.yml +++ b/examples/storage/nvs/.build-test-rules.yml @@ -17,6 +17,14 @@ examples/storage/nvs/nvs_console: disable_test: - if: IDF_TARGET not in ["esp32", "esp32c3"] reason: only one target per arch needed + +examples/storage/nvs/nvs_iteration: + depends_components: + - nvs_flash + disable_test: + - if: IDF_TARGET not in ["esp32", "esp32c3"] + reason: only one target per arch needed + examples/storage/nvs/nvs_rw_blob: depends_components: - nvs_flash @@ -39,16 +47,16 @@ examples/storage/nvs/nvs_rw_value_cxx: - if: IDF_TARGET not in ["esp32", "esp32c3"] reason: only one target per arch needed +examples/storage/nvs/nvs_statistics: + depends_components: + - nvs_flash + disable_test: + - if: IDF_TARGET not in ["esp32", "esp32c3"] + reason: only one target per arch needed + examples/storage/nvs/nvsgen: depends_components: - nvs_flash disable_test: - if: IDF_TARGET != "esp32" reason: only one target needed - -examples/storage/nvs/nvs_statistics: - depends_components: - - nvs_flash - disable_test: - - if: IDF_TARGET not in ["esp32", "esp32c3"] - reason: only one target per arch needed \ No newline at end of file diff --git a/examples/storage/nvs/nvs_iteration/CMakeLists.txt b/examples/storage/nvs/nvs_iteration/CMakeLists.txt new file mode 100644 index 0000000000..f362aeaef2 --- /dev/null +++ b/examples/storage/nvs/nvs_iteration/CMakeLists.txt @@ -0,0 +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.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(nvs_iteration) diff --git a/examples/storage/nvs/nvs_iteration/README.md b/examples/storage/nvs/nvs_iteration/README.md new file mode 100644 index 0000000000..a88f9aa2ec --- /dev/null +++ b/examples/storage/nvs/nvs_iteration/README.md @@ -0,0 +1,69 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | + +# Non-Volatile Storage (NVS) Iteration Example + +This example showcases how to iterate and obtain info about NVS entries of a specific (or any) NVS datatype. + +Default "nvs" partition is first erased to allow for clean example run, followed by writing 2 sets of key value pairs of different types to NVS storage. +After that, iteration is performed over the individual data types, as well as the generic `NVS_TYPE_ANY`, and relevant entry info gained from iteration is verbosely logged. + +Iterator creation in this example is performed by [nvs_entry_find()](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_flash.html#_CPPv414nvs_entry_findPKcPKc10nvs_type_tP14nvs_iterator_t) and accessing entry info by [nvs_entry_info()](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_flash.html#_CPPv414nvs_entry_infoK14nvs_iterator_tP16nvs_entry_info_t). + + +Detailed functional description of NVS and API is provided in [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html). + +## How to use example + +### Hardware required + +This example does not require any special hardware, and can be run on any common development board. + +### Build and flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +... +I (265) nvs_iteration_example: Erasing the contents of the default NVS partition... +I (595) nvs_iteration_example: Opening Non-Volatile Storage (NVS) handle for namespace '_mock_data'... +I (605) nvs_iteration_example: Writing u32 mock data key-value pairs to NVS namespace '_mock_data'... +I (605) nvs_iteration_example: Wrote 7 u32 mock data key-value pairs to NVS namespace '_mock_data'. +I (615) nvs_iteration_example: Writing i8 mock data key-value pairs to NVS namespace '_mock_data'... +I (625) nvs_iteration_example: Wrote 7 i8 mock data key-value pairs to NVS namespace '_mock_data'. +I (625) nvs_iteration_example: Committing data in NVS namespace '_mock_data'... +I (635) nvs_iteration_example: NVS handle for namespace '_mock_data' closed. +I (645) nvs_iteration_example: Iterating over NVS_TYPE_U32 data in namespace '_mock_data'... +I (655) nvs_iteration_example: Entry info: key 'system_startup' for data type type NVS_TYPE_U32 in namespace '_mock_data' +I (665) nvs_iteration_example: Entry info: key 'user_login' for data type type NVS_TYPE_U32 in namespace '_mock_data' +I (675) nvs_iteration_example: Entry info: key 'data_backup' for data type type NVS_TYPE_U32 in namespace '_mock_data' +I (685) nvs_iteration_example: Entry info: key 'sched_update' for data type type NVS_TYPE_U32 in namespace '_mock_data' +I (695) nvs_iteration_example: Entry info: key 'db_cleanup' for data type type NVS_TYPE_U32 in namespace '_mock_data' +I (705) nvs_iteration_example: Entry info: key 'security_scan' for data type type NVS_TYPE_U32 in namespace '_mock_data' +I (715) nvs_iteration_example: Entry info: key 'system_shutdown' for data type type NVS_TYPE_U32 in namespace '_mock_data' +I (725) nvs_iteration_example: Iterated over 7 entries. +I (725) nvs_iteration_example: Iterating over NVS_TYPE_I8 data in namespace '_mock_data'... +I (735) nvs_iteration_example: Entry info: key 'temperature' for data type type NVS_TYPE_I8 in namespace '_mock_data' +I (745) nvs_iteration_example: Entry info: key 'humidity' for data type type NVS_TYPE_I8 in namespace '_mock_data' +I (755) nvs_iteration_example: Entry info: key 'light_level' for data type type NVS_TYPE_I8 in namespace '_mock_data' +I (765) nvs_iteration_example: Entry info: key 'motion_detected' for data type type NVS_TYPE_I8 in namespace '_mock_data' +I (775) nvs_iteration_example: Entry info: key 'battery_level' for data type type NVS_TYPE_I8 in namespace '_mock_data' +I (785) nvs_iteration_example: Entry info: key 'signal_strength' for data type type NVS_TYPE_I8 in namespace '_mock_data' +I (795) nvs_iteration_example: Entry info: key 'error_code' for data type type NVS_TYPE_I8 in namespace '_mock_data' +I (805) nvs_iteration_example: Iterated over 7 entries. +I (815) nvs_iteration_example: Iterating over NVS_TYPE_ANY data in namespace '_mock_data'... +I (825) nvs_iteration_example: Iterated over 14 entries. +I (825) nvs_iteration_example: Returning from app_main(). +I (835) main_task: Returned from app_main() +... +``` \ No newline at end of file diff --git a/examples/storage/nvs/nvs_iteration/main/CMakeLists.txt b/examples/storage/nvs/nvs_iteration/main/CMakeLists.txt new file mode 100644 index 0000000000..b7ab6c1dd4 --- /dev/null +++ b/examples/storage/nvs/nvs_iteration/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "nvs_iteration_example.c" + PRIV_REQUIRES nvs_flash + INCLUDE_DIRS ".") diff --git a/examples/storage/nvs/nvs_iteration/main/nvs_iteration_example.c b/examples/storage/nvs/nvs_iteration/main/nvs_iteration_example.c new file mode 100644 index 0000000000..eb5a0d4e74 --- /dev/null +++ b/examples/storage/nvs/nvs_iteration/main/nvs_iteration_example.c @@ -0,0 +1,220 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Non-Volatile Storage (NVS) Iteration Example + + For other examples please check: + https://github.com/espressif/esp-idf/tree/master/examples + + 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 +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_check.h" +#include "esp_system.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "nvs.h" + +#define MOCK_DATA_NAMESPACE "_mock_data" + +static const char *TAG = "nvs_iteration_example"; + +static const char *u32_mock_data_keys[] = { + "system_startup", + "user_login", + "data_backup", + "sched_update", + "db_cleanup", + "security_scan", + "system_shutdown" +}; +// Unix timestamps +static const uint32_t u32_mock_data_values[] = { + 1704067200, + 1704067260, + 1704067320, + 1704067440, + 1704067500, + 1704067560, + 1704067620 +}; + +static const size_t u32_mock_data_count = sizeof(u32_mock_data_keys) / sizeof(u32_mock_data_keys[0]); + +static const char *i8_mock_data_keys[] = { + "temperature", + "humidity", + "light_level", + "motion_detected", + "battery_level", + "signal_strength", + "error_code" +}; + +static const int8_t i8_mock_data_values[] = { + 22, + 45, + -5, + 1, + 95, + -10, + -42 +}; + +static const size_t i8_mock_data_count = sizeof(i8_mock_data_keys) / sizeof(i8_mock_data_keys[0]); + +static esp_err_t save_mock_data(void) +{ + + ESP_LOGI(TAG, "Opening Non-Volatile Storage (NVS) handle for namespace '%s'...", MOCK_DATA_NAMESPACE); + nvs_handle_t my_handle; + esp_err_t ret = nvs_open(MOCK_DATA_NAMESPACE, NVS_READWRITE, &my_handle); + ESP_RETURN_ON_ERROR(ret, TAG, "Error (%s) opening NVS handle for namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + + size_t successfully_written_entries = 0; + + ESP_LOGI(TAG, "Writing u32 mock data key-value pairs to NVS namespace '%s'...", MOCK_DATA_NAMESPACE); + for (int i = 0; i < u32_mock_data_count; i++) { + // Write uint32_t values + ret = nvs_set_u32(my_handle, u32_mock_data_keys[i], u32_mock_data_values[i]); + // Don't break/abort on error, try to continue writing + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) writing '%s':'%u' pair!", esp_err_to_name(ret), u32_mock_data_keys[i], u32_mock_data_values[i]); + } else { + successfully_written_entries++; + } + } + ESP_LOGI(TAG, "Wrote %u u32 mock data key-value pairs to NVS namespace '%s'.", successfully_written_entries, MOCK_DATA_NAMESPACE); + + successfully_written_entries = 0; + + ESP_LOGI(TAG, "Writing i8 mock data key-value pairs to NVS namespace '%s'...", MOCK_DATA_NAMESPACE); + for (int i = 0; i < i8_mock_data_count; i++) { + // Write int8_t values + ret = nvs_set_i8(my_handle, i8_mock_data_keys[i], i8_mock_data_values[i]); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) writing '%s':'%d' pair!", esp_err_to_name(ret), i8_mock_data_keys[i], i8_mock_data_values[i]); + } else { + successfully_written_entries++; + } + } + ESP_LOGI(TAG, "Wrote %u i8 mock data key-value pairs to NVS namespace '%s'.", successfully_written_entries, MOCK_DATA_NAMESPACE); + + ESP_LOGI(TAG, "Committing data in NVS namespace '%s'...", MOCK_DATA_NAMESPACE); + ret = nvs_commit(my_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) committing data for namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + } + + // Close the storage handle, freeing allocated resources + nvs_close(my_handle); + ESP_LOGI(TAG, "NVS handle for namespace '%s' closed.", MOCK_DATA_NAMESPACE); + + return ESP_OK; +} + +static esp_err_t iterate_over_mock_data(void) +{ + ESP_LOGI(TAG, "Iterating over NVS_TYPE_U32 data in namespace '%s'...", MOCK_DATA_NAMESPACE); + nvs_iterator_t it = NULL; + size_t entries_iterated = 0; + // Find only entries of type NVS_TYPE_U32 and iterate over them + esp_err_t ret = nvs_entry_find(NVS_DEFAULT_PART_NAME, MOCK_DATA_NAMESPACE, NVS_TYPE_U32, &it); + while (ret == ESP_OK) { + nvs_entry_info_t info; + ret = nvs_entry_info(it, &info); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) obtaining entry info in namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + } else { + ESP_LOGI(TAG, "Entry info: key '%s' for data type type %s in namespace '%s'", info.key, info.type == NVS_TYPE_U32 ? "NVS_TYPE_U32" : "Error: not the expected NVS_TYPE_U32!", info.namespace_name); + } + entries_iterated++; + // ret gets checked in the while() condition, terminating the loop if it's not ESP_OK + ret = nvs_entry_next(&it); + // ESP_ERR_NVS_NOT_FOUND is expected to be returned when there is no next entry to iterate over (valid return value for last entry) + if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGE(TAG, "Error (%s) obtaining next entry in namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + break; + } + } + nvs_release_iterator(it); + ESP_LOGI(TAG, "Iterated over %u entries.", entries_iterated); + + ESP_LOGI(TAG, "Iterating over NVS_TYPE_I8 data in namespace '%s'...", MOCK_DATA_NAMESPACE); + it = NULL; + entries_iterated = 0; + // Find only entries of type NVS_TYPE_I8 and iterate over them + ret = nvs_entry_find(NVS_DEFAULT_PART_NAME, MOCK_DATA_NAMESPACE, NVS_TYPE_I8, &it); + while (ret == ESP_OK) { + nvs_entry_info_t info; + ret = nvs_entry_info(it, &info); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) obtaining entry info in namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + } else { + ESP_LOGI(TAG, "Entry info: key '%s' for data type type %s in namespace '%s'", info.key, info.type == NVS_TYPE_I8 ? "NVS_TYPE_I8" : "Error: not the expected NVS_TYPE_I8!", info.namespace_name); + } + entries_iterated++; + ret = nvs_entry_next(&it); + if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGE(TAG, "Error (%s) obtaining next entry in namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + break; + } + } + + nvs_release_iterator(it); + ESP_LOGI(TAG, "Iterated over %u entries.", entries_iterated); + + ESP_LOGI(TAG, "Iterating over NVS_TYPE_ANY data in namespace '%s'...", MOCK_DATA_NAMESPACE); + it = NULL; + entries_iterated = 0; + // Iterate over NVS_TYPE_ANY entries only to count them + ret = nvs_entry_find(NVS_DEFAULT_PART_NAME, MOCK_DATA_NAMESPACE, NVS_TYPE_ANY, &it); + while (ret == ESP_OK) { + entries_iterated++; + ret = nvs_entry_next(&it); + if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGE(TAG, "Error (%s) obtaining next entry in namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + break; + } + } + nvs_release_iterator(it); + ESP_LOGI(TAG, "Iterated over %u entries.", entries_iterated); + + return ESP_OK; +} + +void app_main(void) +{ + ESP_LOGI(TAG, "Erasing the contents of the default NVS partition..."); + ESP_ERROR_CHECK(nvs_flash_erase()); + + // Initialize NVS on default "nvs" partition + esp_err_t ret = nvs_flash_init(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) initializing NVS on default 'nvs' partition!", esp_err_to_name(ret)); + return; + } + + // Write mock data + ret = save_mock_data(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) saving mock data to namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + } + + // Iterate over mock data + ret = iterate_over_mock_data(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error (%s) iterating over namespace '%s'!", esp_err_to_name(ret), MOCK_DATA_NAMESPACE); + } + + ESP_LOGI(TAG, "Returning from app_main()."); +} diff --git a/examples/storage/nvs/nvs_iteration/pytest_nvs_iteration.py b/examples/storage/nvs/nvs_iteration/pytest_nvs_iteration.py new file mode 100644 index 0000000000..71293cf472 --- /dev/null +++ b/examples/storage/nvs/nvs_iteration/pytest_nvs_iteration.py @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize + + +@pytest.mark.generic +@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target']) +def test_examples_nvs_iteration(dut: Dut) -> None: + dut.expect("Iterating over NVS_TYPE_U32 data in namespace '_mock_data'...", timeout=5) + dut.expect('Iterated over 7 entries.', timeout=5) + dut.expect("Iterating over NVS_TYPE_I8 data in namespace '_mock_data'...", timeout=5) + dut.expect('Iterated over 7 entries.', timeout=5) + dut.expect("Iterating over NVS_TYPE_ANY data in namespace '_mock_data'...", timeout=5) + dut.expect('Iterated over 14 entries.', timeout=5) diff --git a/examples/storage/nvs/nvs_iteration/sdkconfig.ci b/examples/storage/nvs/nvs_iteration/sdkconfig.ci new file mode 100644 index 0000000000..e69de29bb2 From df2cc81186a10a7d93928942ada19da0a50ecf2a Mon Sep 17 00:00:00 2001 From: Martin Havlik Date: Mon, 13 Oct 2025 15:59:27 +0200 Subject: [PATCH 03/84] docs(examples/storage): Add docs entries for 2 new NVS examples Extend the existing mentions of NVS examples with 2 newly added `nvs_statistics` and `nvs_iteration`. --- .../en/api-guides/file-system-considerations.rst | 2 ++ docs/en/api-reference/storage/index.rst | 4 ++++ docs/en/api-reference/storage/nvs_flash.rst | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/docs/en/api-guides/file-system-considerations.rst b/docs/en/api-guides/file-system-considerations.rst index 5437a41e53..3eac68726f 100644 --- a/docs/en/api-guides/file-system-considerations.rst +++ b/docs/en/api-guides/file-system-considerations.rst @@ -183,6 +183,8 @@ Points to keep in mind when developing NVS related code: - :example:`storage/nvs/nvs_rw_value` demonstrates how to use NVS to write and read a single integer value. - :example:`storage/nvs/nvs_rw_blob` demonstrates how to use NVS to write and read a blob. +- :example:`storage/nvs/nvs_statistics` demonstrates how to obtain and interpret NVS usage statistics: free/used/available/total number of entries and number of namespaces in given NVS partition. +- :example:`storage/nvs/nvs_iteration` demonstrates how to iterate over entries of specific (or any) NVS data type and how to obtain info about such entries. - :example:`security/nvs_encryption_hmac` demonstrates NVS encryption using the HMAC peripheral, where the encryption keys are derived from the HMAC key burnt in eFuse. - :example:`security/flash_encryption` demonstrates the flash encryption workflow including NVS partition creation and usage. diff --git a/docs/en/api-reference/storage/index.rst b/docs/en/api-reference/storage/index.rst index af8361a002..f268e3e11f 100644 --- a/docs/en/api-reference/storage/index.rst +++ b/docs/en/api-reference/storage/index.rst @@ -53,6 +53,10 @@ Examples - Shows the use of the C-style API to read and write integer data types in NVS flash. * - :example:`nvs_rw_value_cxx ` - Shows the use of the C++-style API to read and write integer data types in NVS flash. + * - :example:`nvs_statistics ` + - Shows the use of the C-style API to obtain NVS usage statistics: free/used/available/total number of entries and number of namespaces in given NVS partition. + * - :example:`nvs_iteration ` + - Shows the use of the C-style API to iterate over entries of specific (or any) NVS data type and how to obtain info about such entries. * - :example:`nvs_bootloader ` - Shows the use of the API available to the bootloader code to read NVS data. * - :example:`nvsgen ` diff --git a/docs/en/api-reference/storage/nvs_flash.rst b/docs/en/api-reference/storage/nvs_flash.rst index 4824a0bef9..5694f4b97f 100644 --- a/docs/en/api-reference/storage/nvs_flash.rst +++ b/docs/en/api-reference/storage/nvs_flash.rst @@ -177,6 +177,22 @@ You can find code examples in the :example:`storage/nvs` directory of ESP-IDF ex This example does exactly the same as :example:`storage/nvs/nvs_rw_value`, except that it uses the C++ NVS handle class. +:example:`storage/nvs/nvs_statistics` + + This example demonstrates how to obtain and interpret NVS usage statistics: free/used/available/total number of entries and number of namespaces in given NVS partition. + + Default NVS partition is erased for a clean run of this example. Then mock data string values are written. + + Usage statistics are obtained prior to and post writing, with the differences being compared to expected values of newly used entries. + +:example:`storage/nvs/nvs_iteration` + + This example demonstrates how to iterate over entries of specific (or any) NVS data type and how to obtain info about such entries. + + Default NVS partition is erased for a clean run of this example. Then mock data consisting of different NVS integer data types are written. + + After that, iteration is performed over the individual data types, as well as the generic ``NVS_TYPE_ANY``, and relevant entry info gained from iteration is logged. + Internals --------- From 81830a342c67a1352d7d1d8020aa97e880af1da1 Mon Sep 17 00:00:00 2001 From: Zhang Shuxian Date: Mon, 3 Nov 2025 10:49:52 +0800 Subject: [PATCH 04/84] docs: Update CN translation for NVS statistics example --- docs/en/api-reference/storage/nvs_flash.rst | 2 +- .../api-guides/file-system-considerations.rst | 2 ++ docs/zh_CN/api-reference/storage/index.rst | 4 ++++ docs/zh_CN/api-reference/storage/nvs_flash.rst | 16 ++++++++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/en/api-reference/storage/nvs_flash.rst b/docs/en/api-reference/storage/nvs_flash.rst index 5694f4b97f..47a2bdf45f 100644 --- a/docs/en/api-reference/storage/nvs_flash.rst +++ b/docs/en/api-reference/storage/nvs_flash.rst @@ -191,7 +191,7 @@ You can find code examples in the :example:`storage/nvs` directory of ESP-IDF ex Default NVS partition is erased for a clean run of this example. Then mock data consisting of different NVS integer data types are written. - After that, iteration is performed over the individual data types, as well as the generic ``NVS_TYPE_ANY``, and relevant entry info gained from iteration is logged. + After that, the example iterates over each individual data type as well as the generic ``NVS_TYPE_ANY`` type, and logs the information obtained from each iteration. Internals --------- diff --git a/docs/zh_CN/api-guides/file-system-considerations.rst b/docs/zh_CN/api-guides/file-system-considerations.rst index 0db811f5a6..357127bf40 100644 --- a/docs/zh_CN/api-guides/file-system-considerations.rst +++ b/docs/zh_CN/api-guides/file-system-considerations.rst @@ -183,6 +183,8 @@ NVS 具有如下特性: - :example:`storage/nvs/nvs_rw_value` 演示了如何写入和读取一个整数值。 - :example:`storage/nvs/nvs_rw_blob` 演示如何写入和读取一个 blob。 +- :example:`storage/nvs/nvs_statistics` 演示了如何获取并解读 NVS 使用情况统计信息:包括指定 NVS 分区中的空闲、已用、可用、总条目数、以及命名空间数量。 +- :example:`storage/nvs/nvs_iteration` 演示了如何遍历特定(或任意)NVS 数据类型的条目,以及如何获取这些条目的相关信息。 - :example:`security/nvs_encryption_hmac` 演示了如何用 HMAC 外设进行 NVS 加密,并通过 efuse 中的 HMAC 密钥生成加密密钥。 - :example:`security/flash_encryption` 演示了如何进行 flash 加密,包括创建和使用 NVS 分区。 diff --git a/docs/zh_CN/api-reference/storage/index.rst b/docs/zh_CN/api-reference/storage/index.rst index e5b8d0c067..3145750668 100644 --- a/docs/zh_CN/api-reference/storage/index.rst +++ b/docs/zh_CN/api-reference/storage/index.rst @@ -53,6 +53,10 @@ - 演示了如何在 NVS flash 中使用 C 语言 API 读写整数数据类型。 * - :example:`nvs_rw_value ` - 演示了如何在 NVS flash 中使用 C++ 语言 API 读写整数数据类型。 + * - :example:`nvs_statistics ` + - 演示了如何使用 C 风格 API 获取 NVS 使用情况统计信息,包括指定 NVS 分区中的空闲、已用、可用、总条目数、以及命名空间数量。 + * - :example:`nvs_iteration ` + - 演示了如何使用 C 风格 API 遍历特定(或任意)NVS 数据类型的条目,以及如何获取这些条目的相关信息。 * - :example:`nvs_bootloader ` - 演示了如何使用引导加载程序代码中可用的 API 来读取 NVS 数据。 * - :example:`nvsgen ` diff --git a/docs/zh_CN/api-reference/storage/nvs_flash.rst b/docs/zh_CN/api-reference/storage/nvs_flash.rst index 4aacccb751..1c5847312d 100644 --- a/docs/zh_CN/api-reference/storage/nvs_flash.rst +++ b/docs/zh_CN/api-reference/storage/nvs_flash.rst @@ -177,6 +177,22 @@ ESP-IDF :example:`storage/nvs` 目录下提供了数个代码示例: 这个例子与 :example:`storage/nvs/nvs_rw_value` 完全一样,只是使用了 C++ 的 NVS 句柄类。 +:example:`storage/nvs/nvs_statistics` + + 该示例演示了如何获取并解读 NVS 使用情况统计信息:包括指定 NVS 分区中的空闲、已用、可用、总条目数、以及命名空间数量。 + + 默认的 NVS 分区会在运行本示例前被擦除,以确保干净的运行环境。随后,会写入模拟的字符串类型数据。 + + 在写入数据前后分别获取使用情况统计信息,并将两者的差异与新占用条目的预期值进行比较。 + +:example:`storage/nvs/nvs_iteration` + + 该示例演示了如何遍历特定(或任意)NVS 数据类型的条目,以及如何获取这些条目的相关信息。 + + 默认的 NVS 分区会在运行本示例前被擦除,以确保干净的运行环境。随后,会写入包含不同 NVS 整型数据类型的模拟数据。 + + 之后,本示例会遍历各个数据类型以及通用的 ``NVS_TYPE_ANY`` 类型,并记录在每次遍历过程中获取到的信息。 + 内部实现 --------- From 1991aa6da033e2deb9cff4b980199f14294295bb Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Wed, 5 Nov 2025 14:15:55 +0100 Subject: [PATCH 05/84] fix(espcoredump): prevent double exception during int_wdt panic with custom stack --- components/espcoredump/CMakeLists.txt | 5 +- .../include_core_dump/esp_core_dump_port.h | 19 +- .../port/riscv/esp_core_dump_port_impl.h | 64 ------- .../port/xtensa/esp_core_dump_port_impl.h | 99 ---------- components/espcoredump/src/core_dump_common.c | 166 ++++++++--------- components/espcoredump/src/core_dump_elf.c | 1 - .../src/port/riscv/core_dump_port.c | 87 ++++++++- .../src/port/xtensa/core_dump_port.c | 16 +- .../src/port/xtensa/core_dump_stack_switch.S | 170 ++++++++++++++++++ components/xtensa/include/xt_instr_macros.h | 10 +- tools/test_apps/system/panic/pytest_panic.py | 4 +- 11 files changed, 371 insertions(+), 270 deletions(-) delete mode 100644 components/espcoredump/include_core_dump/port/riscv/esp_core_dump_port_impl.h delete mode 100644 components/espcoredump/include_core_dump/port/xtensa/esp_core_dump_port_impl.h create mode 100644 components/espcoredump/src/port/xtensa/core_dump_stack_switch.S diff --git a/components/espcoredump/CMakeLists.txt b/components/espcoredump/CMakeLists.txt index cc4cd78977..e28d52878c 100644 --- a/components/espcoredump/CMakeLists.txt +++ b/components/espcoredump/CMakeLists.txt @@ -19,13 +19,12 @@ set(priv_includes "include_core_dump") idf_build_get_property(target IDF_TARGET) if(CONFIG_IDF_TARGET_ARCH_XTENSA) - list(APPEND srcs "src/port/xtensa/core_dump_port.c") + list(APPEND srcs "src/port/xtensa/core_dump_port.c" + "src/port/xtensa/core_dump_stack_switch.S") list(APPEND includes "include/port/xtensa") - list(APPEND priv_includes "include_core_dump/port/xtensa") elseif(CONFIG_IDF_TARGET_ARCH_RISCV) list(APPEND srcs "src/port/riscv/core_dump_port.c") list(APPEND includes "include/port/riscv") - list(APPEND priv_includes "include_core_dump/port/riscv") endif() idf_component_register(SRCS ${srcs} diff --git a/components/espcoredump/include_core_dump/esp_core_dump_port.h b/components/espcoredump/include_core_dump/esp_core_dump_port.h index 39658b29dd..c5bdd62a9d 100644 --- a/components/espcoredump/include_core_dump/esp_core_dump_port.h +++ b/components/espcoredump/include_core_dump/esp_core_dump_port.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,7 +20,6 @@ #include "freertos/FreeRTOS.h" #include "esp_app_format.h" #include "esp_core_dump_types.h" -#include "esp_core_dump_port_impl.h" #include "esp_core_dump.h" #ifdef __cplusplus @@ -106,10 +105,10 @@ uint32_t esp_core_dump_get_stack(core_dump_task_header_t* task_snapshot, * @note The goal of this function is to check whether the task passed is the * task that crashed or not. If this is the case and if it didn't crash * within an ISR, its stack pointer will be set to the panic frame, - * containing all the registers values when the error occured. This + * containing all the registers values when the error occurred. This * function also checks if the TCB address is sane or not. * - * @param task Pointer to the frame exception generated when the panic occured. + * @param task Pointer to the frame exception generated when the panic occurred. * * @return True if the TCB is sane, false else. */ @@ -120,7 +119,7 @@ bool esp_core_dump_check_task(core_dump_task_header_t *task); * * @note In practice, this function is used to fill the ELF file with the * PR_STATUS sections for all the existing tasks. This structure - * contains the CPU registers value when the exception occured. + * contains the CPU registers value when the exception occurred. * * @param task Task to dump the registers from. * @param reg_dump Pointer that will be filled with the registers dump. @@ -182,6 +181,16 @@ void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info const void *paddr, uint32_t stack_size); #endif /* CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ +/** + * @brief Stack switching implemented in C for RISC-V, Assembly for Xtensa + * + * This function switches to the coredump stack, writes the ELF core dump, + * reports stack usage, and restores the original stack. + * @param new_stack new stack buffer address + * @param new_sp aligned stack pointer address + */ +void esp_core_dump_port_write(uint32_t new_stack, uint32_t new_sp); + #ifdef __cplusplus } #endif diff --git a/components/espcoredump/include_core_dump/port/riscv/esp_core_dump_port_impl.h b/components/espcoredump/include_core_dump/port/riscv/esp_core_dump_port_impl.h deleted file mode 100644 index fa2db73afb..0000000000 --- a/components/espcoredump/include_core_dump/port/riscv/esp_core_dump_port_impl.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ESP_CORE_DUMP_PORT_IMPL_H_ -#define ESP_CORE_DUMP_PORT_IMPL_H_ - -/** - * @file - * @brief Core dump port interface implementation for RISC-V. - */ - -#include "sdkconfig.h" -#include "esp_core_dump_types.h" -#include "esp_app_format.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Define the type that will be used to describe the current context when - * doing a backup of the current stack. This same structure is used to restore the stack. - */ -typedef struct { - uint32_t sp; -#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD - uint32_t sp_min; - uint32_t sp_max; -#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD -} core_dump_stack_context_t; - -/** - * @brief Set the stack pointer to the address passed as a parameter. - * @note This function must be inlined. - * - * @param new_sp New stack pointer to set in sp register. - * @param old_ctx CPU context, related to SP, to fill. It will be given back when restoring SP. - */ -FORCE_INLINE_ATTR void esp_core_dump_replace_sp(void* new_sp, core_dump_stack_context_t* old_ctx) -{ - asm volatile("mv %0, sp \n\t\ - mv sp, %1 \n\t\ - " - : "=&r"(old_ctx->sp) - : "r"(new_sp)); -} - -/** - * @brief Restore the stack pointer that was returned when calling `esp_core_dump_replace_sp()` function. - * - * @param ctx CPU context, related to SP, to restore. - */ -FORCE_INLINE_ATTR void esp_core_dump_restore_sp(core_dump_stack_context_t* old_ctx) -{ - asm volatile("mv sp, %0 \n\t" :: "r"(old_ctx->sp)); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/espcoredump/include_core_dump/port/xtensa/esp_core_dump_port_impl.h b/components/espcoredump/include_core_dump/port/xtensa/esp_core_dump_port_impl.h deleted file mode 100644 index 6d62f59495..0000000000 --- a/components/espcoredump/include_core_dump/port/xtensa/esp_core_dump_port_impl.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ESP_CORE_DUMP_PORT_IMPL_H_ -#define ESP_CORE_DUMP_PORT_IMPL_H_ - -/** - * @file - * @brief Core dump port interface implementation for Xtensa boards. - */ -#include "esp_core_dump_types.h" -#include "esp_app_format.h" -/** - * Included for SET_STACK macro - */ -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Define the type that will be used to describe the current context when - * doing a backup of the current stack. This same structure is used to restore the stack. - */ -typedef struct { - uint32_t sp; - uint32_t a0; - uint32_t ps; - uint32_t windowbase; - uint32_t windowstart; -} core_dump_stack_context_t; - -/** - * @brief Set the stack pointer to the address passed as a parameter. - * @note This function must be inlined. - * - * @param new_sp New stack pointer to set in sp register. - * @param old_ctx CPU context, related to SP, to fill. It will be given back when restoring SP. - */ -FORCE_INLINE_ATTR void esp_core_dump_replace_sp(void* new_sp, core_dump_stack_context_t* old_ctx) -{ - /* We have to spill all the windows to the stack first as the new stack pointer - * represents a clean new environment. */ - xthal_window_spill(); - - /* Backup the special registers PS, WindowBase and WindowStart. We will need to restore them later */ - asm volatile("mov %0, sp \n" \ - "mov %1, a0 \n" \ - "rsr.ps %2 \n"\ - "rsr.windowbase %3 \n"\ - "rsr.windowstart %4 \n"\ - : "=r"(old_ctx->sp), - "=r"(old_ctx->a0), - "=r"(old_ctx->ps), - "=r"(old_ctx->windowbase), - "=r"(old_ctx->windowstart) :); - - /* Set the new stack */ - SET_STACK(new_sp); -} - -/** - * @brief Restore the stack pointer that was returned when calling `esp_core_dump_replace_sp()` function. - * - * @param ctx CPU context, related to SP, to restore. - */ -FORCE_INLINE_ATTR void esp_core_dump_restore_sp(core_dump_stack_context_t* old_ctx) -{ - /* Start by disabling WindowOverflowEnable bit from PS to make sure we won't get a Window Overflow exception - * restoring WindowBase and WindowStart registers */ - const uint32_t ps_woe = old_ctx->ps & ~(PS_WOE_MASK); - asm volatile(\ - "wsr.ps %0 \n"\ - "rsync \n"\ - "wsr.windowbase %1 \n"\ - "rsync \n"\ - "wsr.windowstart %2 \n"\ - "rsync \n"\ - "mov sp, %3 \n" \ - "mov a0, %4 \n" \ - "wsr.ps %5 \n"\ - "rsync \n"\ - :: "r"(ps_woe), - "r"(old_ctx->windowbase), - "r"(old_ctx->windowstart), - "r"(old_ctx->sp), - "r"(old_ctx->a0), - "r"(old_ctx->ps)); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/espcoredump/src/core_dump_common.c b/components/espcoredump/src/core_dump_common.c index 7442d85688..14aad492b7 100644 --- a/components/espcoredump/src/core_dump_common.c +++ b/components/espcoredump/src/core_dump_common.c @@ -1,8 +1,11 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include "sdkconfig.h" + +#include #include #include #include "sdkconfig.h" @@ -12,9 +15,7 @@ #include "esp_rom_sys.h" #include "esp_core_dump_port.h" #include "esp_core_dump_common.h" -#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD -#include "esp_private/hw_stack_guard.h" -#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD +#include "esp_cpu.h" const static char TAG[] __attribute__((unused)) = "esp_core_dump_common"; @@ -55,9 +56,34 @@ extern int _coredump_rtc_fast_start; extern int _coredump_rtc_fast_end; #endif +static void* s_exc_frame = NULL; +static uint32_t s_coredump_sp = 0; + /** - * @brief In the menconfig, it is possible to specify a specific stack size for - * core dump generation. + * @brief Configuration validation: If USE_STACK_SIZE is enabled, STACK_SIZE must be > 0 + */ +#if CONFIG_ESP_COREDUMP_USE_STACK_SIZE && CONFIG_ESP_COREDUMP_STACK_SIZE == 0 +#error "CONFIG_ESP_COREDUMP_STACK_SIZE must not be 0 when CONFIG_ESP_COREDUMP_USE_STACK_SIZE is enabled" +#endif + +/** + * @brief Write ELF core dump and log any errors. + * + * This function wraps esp_core_dump_write_elf() and handles error logging. + * Can be called from both C and assembly code. + * + * @return esp_err_t ESP_OK on success, error code otherwise + */ +void esp_core_dump_write_elf_and_check(void) +{ + esp_err_t err = esp_core_dump_store(); + if (err != ESP_OK) { + ESP_COREDUMP_LOGE("Core dump write failed with error=%d", err); + } +} + +/** + * @brief In the menconfig, it is possible to specify a specific stack size for core dump generation. */ #if CONFIG_ESP_COREDUMP_STACK_SIZE > 0 @@ -67,7 +93,7 @@ extern int _coredump_rtc_fast_end; */ #if LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG /* Increase stack size in verbose mode */ -#define ESP_COREDUMP_STACK_SIZE (CONFIG_ESP_COREDUMP_STACK_SIZE+100) +#define ESP_COREDUMP_STACK_SIZE (CONFIG_ESP_COREDUMP_STACK_SIZE + 100) #else #define ESP_COREDUMP_STACK_SIZE CONFIG_ESP_COREDUMP_STACK_SIZE #endif @@ -75,43 +101,15 @@ extern int _coredump_rtc_fast_end; #define COREDUMP_STACK_FILL_BYTE (0xa5U) static uint8_t s_coredump_stack[ESP_COREDUMP_STACK_SIZE]; -static uint8_t* s_core_dump_sp = NULL; -static core_dump_stack_context_t s_stack_context; -/** - * @brief Function setting up the core dump stack. - * - * @note This function **must** be aligned as it modifies the - * stack pointer register. - */ -FORCE_INLINE_ATTR void esp_core_dump_setup_stack(void) +void esp_core_dump_setup_stack(void) { - s_core_dump_sp = (uint8_t *)((uint32_t)(s_coredump_stack + ESP_COREDUMP_STACK_SIZE - 1) & ~0xf); + s_coredump_sp = (uint32_t)(s_coredump_stack + ESP_COREDUMP_STACK_SIZE - 1) & ~0xf; memset(s_coredump_stack, COREDUMP_STACK_FILL_BYTE, ESP_COREDUMP_STACK_SIZE); - /* watchpoint 1 can be used for task stack overflow detection, reuse it, it is no more necessary */ - //esp_cpu_clear_watchpoint(1); - //esp_cpu_set_watchpoint(1, s_coredump_stack, 1, ESP_WATCHPOINT_STORE); - -#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD - /* Save the current area we are watching to restore it later */ - esp_hw_stack_guard_get_bounds(xPortGetCoreID(), &s_stack_context.sp_min, &s_stack_context.sp_max); - /* Since the stack is going to change, make sure we disable protection or an exception would be triggered */ - esp_hw_stack_guard_monitor_stop(); -#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD - - /* Replace the stack pointer depending on the architecture, but save the - * current stack pointer, in order to be able too restore it later. - * This function must be inlined. */ - esp_core_dump_replace_sp(s_core_dump_sp, &s_stack_context); - ESP_COREDUMP_LOGI("Backing up stack @ 0x%" PRIx32 " and use core dump stack @ %p", - s_stack_context.sp, esp_cpu_get_sp()); - -#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD - /* Re-enable the stack guard to check if the stack is big enough for coredump generation */ - esp_hw_stack_guard_set_bounds((uint32_t) s_coredump_stack, (uint32_t) s_core_dump_sp); - esp_hw_stack_guard_monitor_start(); -#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD + /* Stack overflow detection. Watchpoint is set to the end of the core dump stack */ + esp_cpu_clear_watchpoint(1); + esp_cpu_set_watchpoint(1, s_coredump_stack, 1, ESP_CPU_WATCHPOINT_STORE); } /** @@ -132,73 +130,60 @@ FORCE_INLINE_ATTR uint32_t esp_core_dump_free_stack_space(const uint8_t *pucStac } /** - * @brief Print how many bytes have been used on the stack to create the core - * dump. + * @brief Print how many bytes have been used on the stack to create the core dump. + * */ -FORCE_INLINE_ATTR void esp_core_dump_report_stack_usage(void) +void esp_core_dump_report_stack_usage(uint32_t new_sp) { -#if CONFIG_ESP_COREDUMP_LOGS - uint32_t bytes_free = esp_core_dump_free_stack_space(s_coredump_stack); + uint32_t __attribute__((unused)) bytes_free = esp_core_dump_free_stack_space(s_coredump_stack); ESP_COREDUMP_LOGI("Core dump used %" PRIu32 " bytes on stack. %" PRIu32 " bytes left free.", - s_core_dump_sp - s_coredump_stack - bytes_free, bytes_free); -#endif + new_sp - (uint32_t)s_coredump_stack - bytes_free, bytes_free); +} - /* Restore the stack pointer. */ - ESP_COREDUMP_LOGI("Restoring stack @ 0x%" PRIx32, s_stack_context.sp); -#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD - esp_hw_stack_guard_monitor_stop(); -#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD - esp_core_dump_restore_sp(&s_stack_context); -#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD - /* Monitor the same stack area that was set before replacing the stack pointer */ - esp_hw_stack_guard_set_bounds(s_stack_context.sp_min, s_stack_context.sp_max); - esp_hw_stack_guard_monitor_start(); -#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD +void esp_core_dump_report_backup_stack(uint32_t old_sp) +{ + ESP_COREDUMP_LOGI("Backing up stack @ 0x%" PRIx32 " and use core dump stack @ %p", + old_sp, esp_cpu_get_sp()); +} + +void esp_core_dump_report_restore_stack(uint32_t old_sp) +{ + ESP_COREDUMP_LOGI("Restoring stack @ 0x%" PRIx32, old_sp); } #else // CONFIG_ESP_COREDUMP_STACK_SIZE == 0 -/* Here, we are not going to use a custom stack for coredump. Make sure the current configuration doesn't require one. */ -#if CONFIG_ESP_COREDUMP_USE_STACK_SIZE -#pragma error "CONFIG_ESP_COREDUMP_STACK_SIZE must not be 0 in the current configuration" -#endif // ESP_COREDUMP_USE_STACK_SIZE +static uint8_t *s_coredump_stack = NULL; -FORCE_INLINE_ATTR void esp_core_dump_setup_stack(void) +void esp_core_dump_setup_stack(void) { /* No stack setup is needed */ } + +/** + * @brief Setup watchpoint for stack overflow detection when no custom stack is configured. + * + * If we are in ISR context, sets up a watchpoint at the end of the ISR stack. + * For tasks, stack overflow detection should be enabled in menuconfig. + * TODO: If not enabled in menuconfig enable it ourselves. + */ +static void esp_core_dump_enable_stack_overflow_detection(void) { - /* If we are in ISR set watchpoint to the end of ISR stack */ if (esp_core_dump_in_isr_context()) { - uint8_t* topStack = esp_core_dump_get_isr_stack_top(); + uint8_t *topStack = esp_core_dump_get_isr_stack_top(); esp_cpu_clear_watchpoint(1); - esp_cpu_set_watchpoint(1, topStack + xPortGetCoreID()*configISR_STACK_SIZE, 1, ESP_CPU_WATCHPOINT_STORE); - } else { - /* for tasks user should enable stack overflow detection in menuconfig - TODO: if not enabled in menuconfig enable it ourselves */ + esp_cpu_set_watchpoint(1, topStack + xPortGetCoreID() * configISR_STACK_SIZE, 1, ESP_CPU_WATCHPOINT_STORE); } } -FORCE_INLINE_ATTR void esp_core_dump_report_stack_usage(void) +void esp_core_dump_port_write(uint32_t new_stack, uint32_t new_sp) { + (void)new_stack; + (void)new_sp; + + esp_core_dump_enable_stack_overflow_detection(); + esp_core_dump_write_elf_and_check(); } #endif // CONFIG_ESP_COREDUMP_STACK_SIZE > 0 -static void* s_exc_frame = NULL; - -inline static void esp_core_dump_write_internal(panic_info_t *info) -{ - bool isr_context = esp_core_dump_in_isr_context(); - - s_exc_frame = (void *)info->frame; - - esp_core_dump_setup_stack(); - esp_core_dump_port_init(info, isr_context); - esp_err_t err = esp_core_dump_store(); - if (err != ESP_OK) { - ESP_COREDUMP_LOGE("Core dump write failed with error=%d", err); - } - esp_core_dump_report_stack_usage(); -} - void __attribute__((weak)) esp_core_dump_init(void) { /* do nothing by default */ @@ -340,8 +325,13 @@ void esp_core_dump_write(panic_info_t *info) return; #endif + s_exc_frame = (void *)info->frame; esp_core_dump_print_write_start(); - esp_core_dump_write_internal(info); + + esp_core_dump_port_init(info, esp_core_dump_in_isr_context()); + esp_core_dump_setup_stack(); + esp_core_dump_port_write((uint32_t)s_coredump_stack, s_coredump_sp); + esp_core_dump_print_write_end(); } diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index 9d0037249e..5f74e890e4 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -10,7 +10,6 @@ #include "sdkconfig.h" #include "core_dump_checksum.h" #include "esp_core_dump_port.h" -#include "esp_core_dump_port_impl.h" #include "esp_core_dump_common.h" #include "hal/efuse_hal.h" #include "esp_task_wdt.h" diff --git a/components/espcoredump/src/port/riscv/core_dump_port.c b/components/espcoredump/src/port/riscv/core_dump_port.c index 7d872ce62e..38c6d74910 100644 --- a/components/espcoredump/src/port/riscv/core_dump_port.c +++ b/components/espcoredump/src/port/riscv/core_dump_port.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -447,4 +447,89 @@ void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info #endif /* #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ +#if CONFIG_ESP_COREDUMP_STACK_SIZE > 0 + +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD +#include "esp_private/hw_stack_guard.h" +#endif + +/** + * @brief Define the type that will be used to describe the current context when + * doing a backup of the current stack. This same structure is used to restore the stack. + */ +typedef struct { + uint32_t sp; +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD + uint32_t sp_min; + uint32_t sp_max; +#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD +} core_dump_stack_context_t; + +static core_dump_stack_context_t s_stack_context; + +/* Helper functions defined in core_dump_common.c */ +void esp_core_dump_report_backup_stack(uint32_t old_sp); +void esp_core_dump_report_restore_stack(uint32_t old_sp); +void esp_core_dump_write_elf_and_check(void); +void esp_core_dump_report_stack_usage(uint32_t new_sp); + +/** + * @brief Function setting up the core dump stack. + * + * @note This function **must** be inlined as it modifies the stack pointer. + */ +FORCE_INLINE_ATTR void esp_core_dump_replace_stack(uint32_t new_stack, uint32_t new_sp) +{ +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD + /* Save the current area we are watching to restore it later */ + esp_hw_stack_guard_get_bounds(xPortGetCoreID(), &s_stack_context.sp_min, &s_stack_context.sp_max); + /* Since the stack is going to change, make sure we disable protection or an exception would be triggered */ + esp_hw_stack_guard_monitor_stop(); +#endif + + /* Save the current stack pointer and replace it with the core dump stack pointer */ + asm volatile("mv %0, sp \n\t\ + mv sp, %1 \n\t\ + " + : "=&r"(s_stack_context.sp) + : "r"(new_sp)); + + esp_core_dump_report_backup_stack(s_stack_context.sp); + +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD + /* Re-enable the stack guard to check if the stack is big enough for coredump generation */ + esp_hw_stack_guard_set_bounds(new_stack, new_sp); + esp_hw_stack_guard_monitor_start(); +#endif +} + +FORCE_INLINE_ATTR void esp_core_dump_restore_stack(void) +{ + /* Restore the stack pointer. */ + esp_core_dump_report_restore_stack(s_stack_context.sp); + +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD + esp_hw_stack_guard_monitor_stop(); +#endif + + /* Restore the stack pointer to the original value */ + asm volatile("mv sp, %0 \n\t" :: "r"(s_stack_context.sp)); + +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD + /* Monitor the same stack area that was set before replacing the stack pointer */ + esp_hw_stack_guard_set_bounds(s_stack_context.sp_min, s_stack_context.sp_max); + esp_hw_stack_guard_monitor_start(); +#endif +} + +void esp_core_dump_port_write(uint32_t new_stack, uint32_t new_sp) +{ + esp_core_dump_replace_stack(new_stack, new_sp); + esp_core_dump_write_elf_and_check(); + esp_core_dump_report_stack_usage(new_sp); + esp_core_dump_restore_stack(); +} + +#endif // CONFIG_ESP_COREDUMP_STACK_SIZE > 0 + #endif diff --git a/components/espcoredump/src/port/xtensa/core_dump_port.c b/components/espcoredump/src/port/xtensa/core_dump_port.c index 3aff19c537..0e6a54dcf3 100644 --- a/components/espcoredump/src/port/xtensa/core_dump_port.c +++ b/components/espcoredump/src/port/xtensa/core_dump_port.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -565,4 +565,16 @@ void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info #endif /* #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ -#endif +#if CONFIG_ESP_COREDUMP_STACK_SIZE > 0 + +/* Helper function defined in core_dump_stack_switch.S */ +void esp_core_dump_port_write_on_new_stack(uint32_t new_sp); + +void esp_core_dump_port_write(uint32_t new_stack, uint32_t new_sp) +{ + (void)new_stack; + esp_core_dump_port_write_on_new_stack(new_sp); +} +#endif // CONFIG_ESP_COREDUMP_STACK_SIZE > 0 + +#endif // CONFIG_ESP_COREDUMP_ENABLE diff --git a/components/espcoredump/src/port/xtensa/core_dump_stack_switch.S b/components/espcoredump/src/port/xtensa/core_dump_stack_switch.S new file mode 100644 index 0000000000..063227fa54 --- /dev/null +++ b/components/espcoredump/src/port/xtensa/core_dump_stack_switch.S @@ -0,0 +1,170 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Assembly implementation for switching to a new stack during coredump. + * + * This implementation properly handles window spilling without lowering the + * interrupt level, making it safe to use from high-priority interrupt contexts + * (e.g., interrupt watchdog at level 4). + */ + +#include +#include +#include +#include "xt_asm_utils.h" +#include "xt_instr_macros.h" /* For SET_STACK macro */ +#include "sdkconfig.h" + + .extern esp_core_dump_write_elf_and_check + .extern esp_core_dump_report_stack_usage + .extern esp_core_dump_report_backup_stack + .extern esp_core_dump_report_restore_stack + +/** + * @brief Stack context structure layout (offsets in bytes) + * + * This structure defines the layout of s_stack_context used for saving/restoring + * the original stack context when switching to the coredump stack. + */ + .equ STACK_CTX_SP, 0 + .equ STACK_CTX_A0, 4 + .equ STACK_CTX_PS, 8 + .equ STACK_CTX_WINDOWBASE, 12 + .equ STACK_CTX_WINDOWSTART, 16 + .equ STACK_CTX_SIZE, 20 + + .section .bss + .align 4 + .global s_stack_context + .type s_stack_context,@object +s_stack_context: + .space STACK_CTX_SIZE + .size s_stack_context, STACK_CTX_SIZE + + .text + +/** + * @brief Execute core dump write on a new stack + * + * This function spills register windows and switches to new stack. + * Calls C functions and restores original stack and context. + */ +#if CONFIG_ESP_COREDUMP_STACK_SIZE > 0 + + .global esp_core_dump_port_write_on_new_stack + .type esp_core_dump_port_write_on_new_stack,@function + .align 4 +esp_core_dump_port_write_on_new_stack: + +#ifndef __XTENSA_CALL0_ABI__ + entry a1, 32 + + /* Save necessary parameters on stack before window spilling */ + s32i a0, a1, 0 /* Save return address */ + s32i a2, a1, 4 /* Save coredump_sp parameter */ + + /* Prepare for window spilling: + * - Clear PS.EXCM and set PS.WOE to enable window overflow exceptions + * - Raise INTLEVEL to at least XCHAL_EXCM_LEVEL (to maintain interrupt masking) + * - Save/restore EPC1 (clobbered by window overflow exceptions) + * - Only use a0-a3 here (a4-a15 may hold live data from previous windows) + */ + rsr a2, PS /* Save PS to be restored after SPILL_ALL_WINDOWS */ + movi a0, PS_INTLEVEL_MASK + and a3, a2, a0 /* Extract current INTLEVEL */ + bgeui a3, XCHAL_EXCM_LEVEL, 1f /* Ensure INTLEVEL >= XCHAL_EXCM_LEVEL */ + movi a3, XCHAL_EXCM_LEVEL +1: + movi a0, PS_UM | PS_WOE /* Clear EXCM, enable WOE */ + or a3, a3, a0 + wsr a3, PS + rsr a0, EPC1 /* Save EPC1 to be restored after SPILL_ALL_WINDOWS */ + + SPILL_ALL_WINDOWS + + /* Restore PS and EPC1 */ + wsr a2, PS + rsync + wsr a0, EPC1 + + /* Restore return address and save context to s_stack_context */ + mov a6, a1 /* a6 = SP */ + l32i a7, a1, 0 /* a7 = return address (from stack) */ + l32i a12, a1, 4 /* a12 = coredump_sp (from stack) */ + rsr a8, PS + rsr a9, WINDOWBASE + rsr a10, WINDOWSTART + movi a11, s_stack_context + s32i a6, a11, STACK_CTX_SP /* Save SP */ + s32i a7, a11, STACK_CTX_A0 /* Save A0 */ + s32i a8, a11, STACK_CTX_PS /* Save PS */ + s32i a9, a11, STACK_CTX_WINDOWBASE /* Save WindowBase */ + s32i a10, a11, STACK_CTX_WINDOWSTART /* Save WindowStart */ + + /* Switch to coredump stack (use saved coredump_sp from stack) */ + mov a6, a12 /* a6 = coredump_sp */ + SET_STACK a6, a7, a8 + + /* Report backup stack */ + l32i a10, a11, STACK_CTX_SP /* a10 = old SP */ + movi a14, esp_core_dump_report_backup_stack + callx8 a14 + + /* Write ELF core dump */ + movi a14, esp_core_dump_write_elf_and_check + callx8 a14 + + /* Report stack usage */ + mov a10, a12 /* a10 = coredump_sp */ + movi a14, esp_core_dump_report_stack_usage + callx8 a14 + + /* Report restore stack */ + l32i a10, a11, STACK_CTX_SP /* a10 = old SP */ + movi a14, esp_core_dump_report_restore_stack + callx8 a14 + + /* Load original context from s_stack_context */ + movi a11, s_stack_context + l32i a2, a11, STACK_CTX_SP /* Load SP */ + l32i a3, a11, STACK_CTX_A0 /* Load A0 */ + l32i a4, a11, STACK_CTX_PS /* Load PS */ + l32i a5, a11, STACK_CTX_WINDOWBASE /* Load WindowBase */ + l32i a6, a11, STACK_CTX_WINDOWSTART /* Load WindowStart */ + + /* Write PS with WOE disabled */ + movi a8, ~PS_WOE_MASK + and a7, a4, a8 + wsr a7, PS + rsync + + /* Restore WindowBase */ + wsr a5, WINDOWBASE + rsync + + /* Restore WindowStart */ + wsr a6, WINDOWSTART + rsync + + /* Restore SP */ + mov a1, a2 + + /* Restore A0 */ + mov a0, a3 + + /* Restore PS (final with original WOE setting) */ + wsr a4, PS + rsync + + retw + +#else + #error "this code is written for Window ABI" +#endif + +#endif // CONFIG_ESP_COREDUMP_STACK_SIZE > 0 diff --git a/components/xtensa/include/xt_instr_macros.h b/components/xtensa/include/xt_instr_macros.h index e3a1199020..773fd009e4 100644 --- a/components/xtensa/include/xt_instr_macros.h +++ b/components/xtensa/include/xt_instr_macros.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,10 +53,10 @@ */ #ifdef __ASSEMBLER__ .macro SET_STACK new_sp tmp1 tmp2 - addi tmp1, new_sp, -SAVE_AREA_OFFSET - addi tmp2, tmp1, -BASE_AREA_SP_OFFSET - s32i new_sp, tmp2, 0 - addi new_sp, tmp1, 0 + addi \tmp1, \new_sp, -SAVE_AREA_OFFSET + addi \tmp2, \tmp1, -BASE_AREA_SP_OFFSET + s32i \new_sp, \tmp2, 0 + addi \new_sp, \tmp1, 0 rsr.ps \tmp1 movi \tmp2, ~(PS_WOE_MASK | PS_OWB_MASK | PS_CALLINC_MASK) and \tmp1, \tmp1, \tmp2 diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index 51d4d00677..6d0281fce1 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -39,12 +39,12 @@ CONFIGS = list( 'coredump_flash_elf_soft_sha', 'coredump_uart_bin_crc', 'coredump_uart_elf_crc', + 'coredump_flash_custom_stack', 'gdbstub', 'panic', ], TARGETS_ALL, - ), - itertools.product(['coredump_flash_custom_stack'], TARGETS_RISCV), + ) ) ) From 2f63b7bc000893c369d0f4fc5b419fb6a9f703d3 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Fri, 12 Dec 2025 11:08:13 +0100 Subject: [PATCH 06/84] fix(xtensa): Fix clang assembler errors in STRUCT_AFIELD_A macro --- components/xtensa/include/xtensa/xtruntime-frames.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/xtensa/include/xtensa/xtruntime-frames.h b/components/xtensa/include/xtensa/xtruntime-frames.h index b78095e0dd..3557e0c17b 100644 --- a/components/xtensa/include/xtensa/xtruntime-frames.h +++ b/components/xtensa/include/xtensa/xtruntime-frames.h @@ -37,8 +37,10 @@ #define STRUCT_FIELD(ctype,size,pre,name) .set pre##name, XT_STRUCT_OFFSET; .set XT_STRUCT_OFFSET, pre##name + size #define STRUCT_AFIELD(ctype,size,pre,name,n) .set pre##name, XT_STRUCT_OFFSET;\ .set XT_STRUCT_OFFSET, pre##name + (size)*(n); -#define STRUCT_AFIELD_A(ctype,size,align,pre,name,n) .set pre##name, XT_STRUCT_OFFSET\ - .ifgt (align-1); .set pre##name, XT_STRUCT_OFFSET + (align - (XT_STRUCT_OFFSET & (align-1))); .endif\ +#define STRUCT_AFIELD_A(ctype,size,align,pre,name,n) .set pre##name, XT_STRUCT_OFFSET; \ + .ifgt (align-1); \ + .set pre##name, XT_STRUCT_OFFSET + (align - (XT_STRUCT_OFFSET & (align-1))); \ + .endif; \ .set XT_STRUCT_OFFSET, pre##name + (size)*(n); #define STRUCT_END(sname) .set sname##Size, XT_STRUCT_OFFSET; #else /* __clang__ */ @@ -67,7 +69,7 @@ * stack frame is limited to 128 bytes (currently at 64). */ STRUCT_BEGIN -STRUCT_FIELD (long,4,KEXC_,pc) /* "parm" */ +STRUCT_FIELD (long,4,KEXC_,pc) /* "param" */ STRUCT_FIELD (long,4,KEXC_,ps) STRUCT_AFIELD(long,4,KEXC_,areg, 4) /* a12 .. a15 */ STRUCT_FIELD (long,4,KEXC_,sar) /* "save" */ From a9a379084d5f92df5d2975485767bafb45d8f5b5 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Mon, 10 Nov 2025 13:12:43 +0100 Subject: [PATCH 07/84] docs(jtag): document program_esp_bins command --- docs/en/api-guides/jtag-debugging/index.rst | 32 +++++++++++++++++-- .../zh_CN/api-guides/jtag-debugging/index.rst | 31 +++++++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/docs/en/api-guides/jtag-debugging/index.rst b/docs/en/api-guides/jtag-debugging/index.rst index a4b442917c..b251be8784 100644 --- a/docs/en/api-guides/jtag-debugging/index.rst +++ b/docs/en/api-guides/jtag-debugging/index.rst @@ -221,7 +221,7 @@ Another option is to write application image to flash using OpenOCD via JTAG wit OpenOCD flashing command ``program_esp`` has the following format: -``program_esp [verify] [reset] [exit] [compress] [encrypt]`` +``program_esp [verify] [reset] [exit] [compress] [encrypt] [no_clock_boost] [restore_clock] [skip_loaded]`` - ``image_file`` - Path to program image file. - ``offset`` - Offset in flash bank to write image. @@ -232,10 +232,38 @@ OpenOCD flashing command ``program_esp`` has the following format: - ``encrypt`` - Optional. Encrypt binary before writing to flash. Same functionality with ``idf.py encrypted-flash`` - ``no_clock_boost`` - Optional. Disable setting target clock frequency to its maximum possible value before programming. Clock boost is enabled by default. - ``restore_clock`` - Optional. Restore clock frequency to its initial value after programming. Disabled by default. + - ``skip_loaded`` - Optional. Skip flashing if the binary is already loaded. Disabled by default. + +Alternative Method: Using program_esp_bins +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For convenience when working with ESP-IDF projects, OpenOCD provides an alternative command ``program_esp_bins`` that can flash multiple binaries in a single command by reading the build configuration from the ``flasher_args.json`` file generated during the ESP-IDF build process. + +This method is particularly useful because: + +* It automatically reads all the binary files and their flash addresses from the build output +* It handles encrypted partitions automatically based on the project configuration +* It eliminates the need to manually specify addresses for each binary (bootloader, partition table, application, etc.) + +Basic usage: + +.. code-block:: bash + + openocd -f board/esp32-wrover-kit-3.3v.cfg -c "program_esp_bins build flasher_args.json verify exit" + +Command Format +"""""""""""""" + +The OpenOCD flashing command ``program_esp_bins`` has the following format: + +``program_esp_bins [verify] [reset] [exit] [compress] [no_clock_boost] [restore_clock] [skip_loaded]`` + + - ``build_dir`` - Path to the build directory containing the ``flasher_args.json`` file. + - ``json_file`` - Name of the JSON file containing flash configuration (typically ``flasher_args.json``). + - Other optional parameters work the same as ``program_esp`` command. See :ref:`jtag-upload-app-debug` section for details. You are now ready to start application debugging. Follow the steps described in the section below. - .. _jtag-debugging-launching-debugger: Launching Debugger diff --git a/docs/zh_CN/api-guides/jtag-debugging/index.rst b/docs/zh_CN/api-guides/jtag-debugging/index.rst index 796cf4fbcf..52dfd16605 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/index.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/index.rst @@ -221,7 +221,7 @@ OpenOCD 安装完成后就可以配置 {IDF_TARGET_NAME} 目标(即带 JTAG 其中 OpenOCD 的烧写命令 ``program_esp`` 格式如下: -``program_esp [verify] [reset] [exit] [compress] [encrypt]`` +``program_esp [verify] [reset] [exit] [compress] [encrypt] [no_clock_boost] [restore_clock] [skip_loaded]`` - ``image_file`` - 程序镜像文件存放的路径 - ``offset`` - 镜像烧写到 flash 中的偏移地址 @@ -232,6 +232,35 @@ OpenOCD 安装完成后就可以配置 {IDF_TARGET_NAME} 目标(即带 JTAG - ``encrypt`` - 烧写到 flash 前加密二进制文件,与 ``idf.py encrypted-flash`` 功能相同(可选) - ``no_clock_boost`` - 禁用在烧写前将目标时钟频率设置为其最大可能值(可选)。默认情况下禁用该选项,即默认启用时钟提升。 - ``restore_clock`` - 可选。烧写完成后将时钟频率恢复到初始值。默认情况下不启用。 +- ``skip_loaded`` - 可选。如果二进制文件已加载,则跳过烧写。默认情况下不启用。 + +替代方法:使用 program_esp_bins +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +为方便 ESP-IDF 项目的使用,OpenOCD 提供了一个替代命令 ``program_esp_bins``,该命令可以通过读取 ESP-IDF 构建过程中生成的 ``flasher_args.json`` 文件中的构建配置,在单个命令中烧写多个二进制文件。 + +该方法特别有用,因为: + +* 它会自动从构建输出中读取所有二进制文件及其 flash 地址 +* 它会根据项目配置自动处理加密分区 +* 它无需手动指定每个二进制文件(引导加载程序、分区表、应用程序等)的地址 + +基本用法: + +.. code-block:: bash + + openocd -f board/esp32-wrover-kit-3.3v.cfg -c "program_esp_bins build flasher_args.json verify exit" + +命令格式 +"""""""""""""" + +OpenOCD 烧写命令 ``program_esp_bins`` 格式如下: + +``program_esp_bins [verify] [reset] [exit] [compress] [no_clock_boost] [restore_clock] [skip_loaded]`` + + - ``build_dir`` - 包含 ``flasher_args.json`` 文件的构建目录路径。 + - ``json_file`` - 包含 flash 配置的 JSON 文件名称(通常为 ``flasher_args.json``)。 + - 其他可选参数与 ``program_esp`` 命令相同。详情请参阅 :ref:`jtag-upload-app-debug` 章节。 现在可以调试应用程序了,请按照以下章节中的步骤进行操作。 From d9aac3ba33f321b8d5d8ee5662aba6ba8efaa60d Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Tue, 2 Dec 2025 11:57:52 +0800 Subject: [PATCH 08/84] feat(802.15.4): add SW data request detection --- .../hal/include/hal/ieee802154_common_ll.h | 5 ++++ .../ieee802154/driver/esp_ieee802154_ack.c | 19 ++++++++------- .../ieee802154/driver/esp_ieee802154_frame.c | 24 ++++++++++++++++++- .../private_include/esp_ieee802154_frame.h | 9 +++++++ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/components/hal/include/hal/ieee802154_common_ll.h b/components/hal/include/hal/ieee802154_common_ll.h index 1fe732f2c4..9f20e517ea 100644 --- a/components/hal/include/hal/ieee802154_common_ll.h +++ b/components/hal/include/hal/ieee802154_common_ll.h @@ -414,6 +414,11 @@ static inline void ieee802154_ll_set_pending_mode(bool enable) IEEE802154.conf.pending_enhance = enable; } +static inline bool ieee802154_ll_get_pending_mode(void) +{ + return IEEE802154.conf.pending_enhance; +} + FORCE_INLINE_ATTR void ieee802154_ll_set_pending_bit(bool pending) { IEEE802154.pending_cfg.pending = pending; diff --git a/components/ieee802154/driver/esp_ieee802154_ack.c b/components/ieee802154/driver/esp_ieee802154_ack.c index cb21dd72a0..5b03c7e707 100644 --- a/components/ieee802154/driver/esp_ieee802154_ack.c +++ b/components/ieee802154/driver/esp_ieee802154_ack.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -130,6 +130,13 @@ bool ieee802154_ack_config_pending_bit(const uint8_t *frame) // Only set the HW pending bit for the frames with version 0b00 or 0b01. bool set_to_hw = (ieee802154_frame_get_version(frame) <= IEEE802154_FRAME_VERSION_1); + // Check SW should check whether the frame is data request or not. + bool sw_check_data_req = ieee802154_ll_get_pending_mode(); + + if (sw_check_data_req) { + pending_bit = ieee802154_is_data_request(frame); + } + ieee802154_ll_pending_mode_t pending_mode = ieee802154_pib_get_pending_mode(); switch (pending_mode) { @@ -140,20 +147,14 @@ bool ieee802154_ack_config_pending_bit(const uint8_t *frame) case IEEE802154_AUTO_PENDING_ENABLE: case IEEE802154_AUTO_PENDING_ENHANCED: src_mode = ieee802154_frame_get_src_addr(frame, addr); - if (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT || src_mode == IEEE802154_FRAME_SRC_MODE_EXT) { - if (ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)) { - pending_bit = true; - } + pending_bit = ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT); } break; case IEEE802154_AUTO_PENDING_ZIGBEE: // If the address type is short and in pending table, set 'pending_bit' false, otherwise set true. src_mode = ieee802154_frame_get_src_addr(frame, addr); - pending_bit = true; - if (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT && ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)) { - pending_bit = false; - } + pending_bit = !(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT && ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)); break; default: IEEE802154_ASSERT(false); diff --git a/components/ieee802154/driver/esp_ieee802154_frame.c b/components/ieee802154/driver/esp_ieee802154_frame.c index 07573d15f6..79642c9bad 100644 --- a/components/ieee802154/driver/esp_ieee802154_frame.c +++ b/components/ieee802154/driver/esp_ieee802154_frame.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -290,6 +290,28 @@ IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_payload_offset(const uint8_ return offset - 1; } +bool ieee802154_is_data_request(const uint8_t *frame) +{ + if (ieee802154_frame_get_type(frame) != IEEE802154_FRAME_TYPE_COMMAND) { + return false; + } + uint8_t offset = ieee802154_frame_security_header_offset(frame); + if (is_security_enabled(frame)) { + // skip security field. + offset += ieee802154_frame_get_security_field_len(frame); + } + + if (ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_2 && is_ie_present(frame)) { + // skip IE fields. + offset += ieee802154_frame_get_ie_field_len(frame); + } + if (frame[offset] == IEEE802154_CMD_DATA_REQ) { + return true; + } + + return false; +} + uint8_t IEEE802154_INLINE ieee802154_frame_get_type(const uint8_t *frame) { return frame[IEEE802154_FRAME_TYPE_OFFSET] & IEEE802154_FRAME_TYPE_MASK; diff --git a/components/ieee802154/private_include/esp_ieee802154_frame.h b/components/ieee802154/private_include/esp_ieee802154_frame.h index fea20ca9c0..c46fb31e71 100644 --- a/components/ieee802154/private_include/esp_ieee802154_frame.h +++ b/components/ieee802154/private_include/esp_ieee802154_frame.h @@ -203,6 +203,15 @@ esp_err_t ieee802154_frame_get_dest_panid(const uint8_t *frame, uint8_t *panid); * */ esp_err_t ieee802154_frame_get_src_panid(const uint8_t *frame, uint8_t *panid); + +/** + * @brief Check whether the given frame is a MAC Data Request command. + * + * @param[in] frame Pointer to the raw MAC frame buffer. + * + * @return true if the frame is a Data Request command, false otherwise. + */ +bool ieee802154_is_data_request(const uint8_t *frame); #ifdef __cplusplus } #endif From 1e8adea6fdabe574ed5d1174814bae6f74cc2914 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 4 Dec 2025 17:33:56 +0800 Subject: [PATCH 09/84] feat(802.15.4): add multipan pending table support --- components/ieee802154/Kconfig | 10 +++ .../ieee802154/driver/esp_ieee802154_ack.c | 65 +++++++------- .../ieee802154/driver/esp_ieee802154_dev.c | 87 ++++++++++++++++++- .../ieee802154/driver/esp_ieee802154_frame.c | 7 ++ .../ieee802154/driver/esp_ieee802154_pib.c | 22 +++-- components/ieee802154/esp_ieee802154.c | 57 +++++++++--- .../ieee802154/include/esp_ieee802154.h | 76 +++++++++++++++- .../ieee802154/include/esp_ieee802154_types.h | 1 + .../private_include/esp_ieee802154_ack.h | 11 +-- .../private_include/esp_ieee802154_dev.h | 2 +- .../private_include/esp_ieee802154_pib.h | 9 +- 11 files changed, 285 insertions(+), 62 deletions(-) diff --git a/components/ieee802154/Kconfig b/components/ieee802154/Kconfig index 54e7229aff..0948408932 100644 --- a/components/ieee802154/Kconfig +++ b/components/ieee802154/Kconfig @@ -72,6 +72,16 @@ menu "IEEE 802.15.4" help Enable IEEE802154 multi-pan + config IEEE802154_INTERFACE_NUM + int "Number of IEEE802154 interfaces" + depends on IEEE802154_ENABLED + range 1 1 if !IEEE802154_MULTI_PAN_ENABLE + range 1 4 if IEEE802154_MULTI_PAN_ENABLE + default 1 if !IEEE802154_MULTI_PAN_ENABLE + default 2 if IEEE802154_MULTI_PAN_ENABLE + help + Number of IEEE802154 interfaces + config IEEE802154_TIMING_OPTIMIZATION bool "Enable throughput optimization" depends on IEEE802154_ENABLED diff --git a/components/ieee802154/driver/esp_ieee802154_ack.c b/components/ieee802154/driver/esp_ieee802154_ack.c index 5b03c7e707..60302a1dd1 100644 --- a/components/ieee802154/driver/esp_ieee802154_ack.c +++ b/components/ieee802154/driver/esp_ieee802154_ack.c @@ -15,7 +15,7 @@ #include "esp_ieee802154_types.h" #include "esp_ieee802154_util.h" -static ieee802154_pending_table_t ieee802154_pending_table; +static ieee802154_pending_table_t ieee802154_pending_table[CONFIG_IEEE802154_INTERFACE_NUM]; #define GET_MASK_ITEM_FROM_TABLE(mask, pos) (mask[(pos) / IEEE802154_PENDING_TABLE_MASK_BITS]) @@ -23,21 +23,21 @@ static ieee802154_pending_table_t ieee802154_pending_table; #define BIT_CLR(mask, pos) (GET_MASK_ITEM_FROM_TABLE(mask, pos) &= ~(1UL << (pos % IEEE802154_PENDING_TABLE_MASK_BITS))) #define BIT_IST(mask, pos) (GET_MASK_ITEM_FROM_TABLE(mask, pos) & (1UL << (pos % IEEE802154_PENDING_TABLE_MASK_BITS))) -static IRAM_ATTR bool ieee802154_addr_in_pending_table(const uint8_t *addr, bool is_short) +static IRAM_ATTR bool ieee802154_addr_in_pending_table(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short) { bool ret = false; if (is_short) { for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) { - if (BIT_IST(ieee802154_pending_table.short_addr_mask, index) && - memcmp(addr, ieee802154_pending_table.short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) { + if (BIT_IST(ieee802154_pending_table[inf_index].short_addr_mask, index) && + memcmp(addr, ieee802154_pending_table[inf_index].short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) { ret = true; break; } } } else { for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) { - if (BIT_IST(ieee802154_pending_table.ext_addr_mask, index) && - memcmp(addr, ieee802154_pending_table.ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) { + if (BIT_IST(ieee802154_pending_table[inf_index].ext_addr_mask, index) && + memcmp(addr, ieee802154_pending_table[inf_index].ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) { ret = true; break; } @@ -46,63 +46,63 @@ static IRAM_ATTR bool ieee802154_addr_in_pending_table(const uint8_t *addr, bool return ret; } -esp_err_t ieee802154_add_pending_addr(const uint8_t *addr, bool is_short) +esp_err_t ieee802154_add_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short) { esp_err_t ret = ESP_FAIL; int8_t first_empty_index = -1; if (is_short) { for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) { - if (!BIT_IST(ieee802154_pending_table.short_addr_mask, index)) { + if (!BIT_IST(ieee802154_pending_table[inf_index].short_addr_mask, index)) { // record the first empty index first_empty_index = (first_empty_index == -1 ? index : first_empty_index); - } else if (memcmp(addr, ieee802154_pending_table.short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) { + } else if (memcmp(addr, ieee802154_pending_table[inf_index].short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) { // The address is in the table already. ret = ESP_OK; return ret; } } if (first_empty_index != -1) { - memcpy(ieee802154_pending_table.short_addr[first_empty_index], addr, IEEE802154_FRAME_SHORT_ADDR_SIZE); - BIT_SET(ieee802154_pending_table.short_addr_mask, first_empty_index); + memcpy(ieee802154_pending_table[inf_index].short_addr[first_empty_index], addr, IEEE802154_FRAME_SHORT_ADDR_SIZE); + BIT_SET(ieee802154_pending_table[inf_index].short_addr_mask, first_empty_index); ret = ESP_OK; } } else { for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) { - if (!BIT_IST(ieee802154_pending_table.ext_addr_mask, index)) { + if (!BIT_IST(ieee802154_pending_table[inf_index].ext_addr_mask, index)) { first_empty_index = (first_empty_index == -1 ? index : first_empty_index); - } else if (memcmp(addr, ieee802154_pending_table.ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) { + } else if (memcmp(addr, ieee802154_pending_table[inf_index].ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) { // The address is already in the pending table. ret = ESP_OK; return ret; } } if (first_empty_index != -1) { - memcpy(ieee802154_pending_table.ext_addr[first_empty_index], addr, IEEE802154_FRAME_EXT_ADDR_SIZE); - BIT_SET(ieee802154_pending_table.ext_addr_mask, first_empty_index); + memcpy(ieee802154_pending_table[inf_index].ext_addr[first_empty_index], addr, IEEE802154_FRAME_EXT_ADDR_SIZE); + BIT_SET(ieee802154_pending_table[inf_index].ext_addr_mask, first_empty_index); ret = ESP_OK; } } return ret; } -esp_err_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short) +esp_err_t ieee802154_clear_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short) { esp_err_t ret = ESP_FAIL; // Consider this function may be called in ISR, only clear the mask bits for finishing the process quickly. if (is_short) { for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) { - if (BIT_IST(ieee802154_pending_table.short_addr_mask, index) && - memcmp(addr, ieee802154_pending_table.short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) { - BIT_CLR(ieee802154_pending_table.short_addr_mask, index); + if (BIT_IST(ieee802154_pending_table[inf_index].short_addr_mask, index) && + memcmp(addr, ieee802154_pending_table[inf_index].short_addr[index], IEEE802154_FRAME_SHORT_ADDR_SIZE) == 0) { + BIT_CLR(ieee802154_pending_table[inf_index].short_addr_mask, index); ret = ESP_OK; break; } } } else { for (uint8_t index = 0; index < CONFIG_IEEE802154_PENDING_TABLE_SIZE; index++) { - if (BIT_IST(ieee802154_pending_table.ext_addr_mask, index) && - memcmp(addr, ieee802154_pending_table.ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) { - BIT_CLR(ieee802154_pending_table.ext_addr_mask, index); + if (BIT_IST(ieee802154_pending_table[inf_index].ext_addr_mask, index) && + memcmp(addr, ieee802154_pending_table[inf_index].ext_addr[index], IEEE802154_FRAME_EXT_ADDR_SIZE) == 0) { + BIT_CLR(ieee802154_pending_table[inf_index].ext_addr_mask, index); ret = ESP_OK; break; } @@ -112,18 +112,25 @@ esp_err_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short) return ret; } -void ieee802154_reset_pending_table(bool is_short) +void ieee802154_reset_pending_table(esp_ieee802154_multipan_index_t inf_index, bool is_short) { // Consider this function may be called in ISR, only clear the mask bits for finishing the process quickly. if (is_short) { - memset(ieee802154_pending_table.short_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE); + memset(ieee802154_pending_table[inf_index].short_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE); } else { - memset(ieee802154_pending_table.ext_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE); + memset(ieee802154_pending_table[inf_index].ext_addr_mask, 0, IEEE802154_PENDING_TABLE_MASK_SIZE); } } -bool ieee802154_ack_config_pending_bit(const uint8_t *frame) +bool ieee802154_ack_config_pending_bit(const uint8_t *frame, const esp_ieee802154_frame_info_t *frame_info) { + esp_ieee802154_multipan_index_t inf_index = 0; +#if CONFIG_IEEE802154_MULTI_PAN_ENABLE + inf_index = frame_info->mpf_index; + if (inf_index >= ESP_IEEE802154_MULTIPAN_MAX || inf_index < ESP_IEEE802154_MULTIPAN_0) { + return false; + } +#endif bool pending_bit = false; uint8_t addr[IEEE802154_FRAME_EXT_ADDR_SIZE] = {0}; uint8_t src_mode = 0; @@ -137,7 +144,7 @@ bool ieee802154_ack_config_pending_bit(const uint8_t *frame) pending_bit = ieee802154_is_data_request(frame); } - ieee802154_ll_pending_mode_t pending_mode = ieee802154_pib_get_pending_mode(); + ieee802154_ll_pending_mode_t pending_mode = ieee802154_pib_get_pending_mode(inf_index); switch (pending_mode) { case IEEE802154_AUTO_PENDING_DISABLE: @@ -148,13 +155,13 @@ bool ieee802154_ack_config_pending_bit(const uint8_t *frame) case IEEE802154_AUTO_PENDING_ENHANCED: src_mode = ieee802154_frame_get_src_addr(frame, addr); if (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT || src_mode == IEEE802154_FRAME_SRC_MODE_EXT) { - pending_bit = ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT); + pending_bit = ieee802154_addr_in_pending_table(inf_index, addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT); } break; case IEEE802154_AUTO_PENDING_ZIGBEE: // If the address type is short and in pending table, set 'pending_bit' false, otherwise set true. src_mode = ieee802154_frame_get_src_addr(frame, addr); - pending_bit = !(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT && ieee802154_addr_in_pending_table(addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)); + pending_bit = !(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT && ieee802154_addr_in_pending_table(inf_index, addr, src_mode == IEEE802154_FRAME_SRC_MODE_SHORT)); break; default: IEEE802154_ASSERT(false); diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 4664a3591a..594a79d24f 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -145,12 +145,93 @@ static IRAM_ATTR void receive_ack_timeout_timer_start(uint32_t duration) } #endif +#if CONFIG_IEEE802154_MULTI_PAN_ENABLE +IEEE802154_STATIC IEEE802154_NOINLINE bool is_broadcast_panid(uint8_t *target_panid) +{ + if (target_panid[0] == 0xff && target_panid[1] == 0xff) { + return true; + } + return false; +} + +static IEEE802154_NOINLINE bool is_broadcast_addr(uint8_t *dest_addr, uint8_t addr_mode) +{ + uint8_t target[IEEE802154_FRAME_EXT_ADDR_SIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + if (addr_mode == IEEE802154_FRAME_DST_MODE_NONE) { + return false; + } + + size_t addr_size = (addr_mode == IEEE802154_FRAME_DST_MODE_SHORT) ? IEEE802154_FRAME_SHORT_ADDR_SIZE : IEEE802154_FRAME_EXT_ADDR_SIZE; + if (memcmp(dest_addr, target, addr_size) == 0) { + return true; + } + return false; +} + +IEEE802154_STATIC IEEE802154_NOINLINE void update_mpf_index(void) +{ + uint8_t *frame = s_rx_frame[s_rx_index]; + uint8_t frame_type = ieee802154_frame_get_type(frame); + s_rx_frame_info[s_rx_index].mpf_index = ESP_IEEE802154_MULTIPAN_MAX; + bool is_target_panid_present = false; + uint8_t dest_addr_mode = IEEE802154_FRAME_DST_MODE_NONE; + uint8_t dest_addr[IEEE802154_FRAME_EXT_ADDR_SIZE] = {0}; + uint8_t target_panid[IEEE802154_FRAME_PANID_SIZE] = {0}; + + // Get dest addr and panid from the raw packet. + if (frame_type == IEEE802154_FRAME_TYPE_BEACON) { + is_target_panid_present = (ieee802154_frame_get_src_panid(frame, target_panid) == ESP_OK) ? true : false; + } else { + is_target_panid_present = (ieee802154_frame_get_dest_panid(frame, target_panid) == ESP_OK) ? true : false; + } + dest_addr_mode = ieee802154_frame_get_dst_addr(frame, dest_addr); + // Check is this packet is Broadcast + if (is_broadcast_addr(dest_addr, dest_addr_mode) || (is_target_panid_present && is_broadcast_panid(target_panid))) { + return; + } + + for (esp_ieee802154_multipan_index_t index = 0; index < CONFIG_IEEE802154_INTERFACE_NUM; index++) { + if (is_target_panid_present == true) { + uint16_t panid = target_panid[1]; + panid = (panid << 8) | target_panid[0]; + if (panid != esp_ieee802154_get_multipan_panid(index)) { + continue; + } + } + + if (dest_addr_mode == IEEE802154_FRAME_DST_MODE_SHORT) { + uint16_t short_addr = dest_addr[1]; + short_addr = (short_addr << 8) | dest_addr[0]; + if (short_addr != esp_ieee802154_get_multipan_short_address(index)) { + continue; + } else { + s_rx_frame_info[s_rx_index].mpf_index = index; + return; + } + } else if (dest_addr_mode == IEEE802154_FRAME_DST_MODE_EXT) { + uint8_t ext_addr[IEEE802154_FRAME_EXT_ADDR_SIZE] = {0}; + esp_ieee802154_get_multipan_extended_address(index, ext_addr); + if (memcmp(dest_addr, ext_addr, IEEE802154_FRAME_EXT_ADDR_SIZE) != 0) { + continue; + } else { + s_rx_frame_info[s_rx_index].mpf_index = index; + return; + } + } + } +} +#endif + static IEEE802154_NOINLINE void ieee802154_rx_frame_info_update(void) { uint8_t len = s_rx_frame[s_rx_index][0]; int8_t rssi = s_rx_frame[s_rx_index][len - 1]; // crc is not written to rx buffer uint8_t lqi = s_rx_frame[s_rx_index][len]; +#if CONFIG_IEEE802154_MULTI_PAN_ENABLE + update_mpf_index(); +#endif + s_rx_frame_info[s_rx_index].channel = ieee802154_freq_to_channel(ieee802154_ll_get_freq()); s_rx_frame_info[s_rx_index].rssi = rssi + IEEE802154_RSSI_COMPENSATION_VALUE; s_rx_frame_info[s_rx_index].lqi = lqi; @@ -434,12 +515,12 @@ static IRAM_ATTR void isr_handle_rx_done(void) && ieee802154_ll_get_tx_auto_ack()) { extcoex_tx_stage_start(); // auto tx ack only works for the frame with version 0b00 and 0b01 - s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index]); + s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); ieee802154_set_state(IEEE802154_STATE_TX_ACK); NEEDS_NEXT_OPT(false); } else if (ieee802154_frame_is_ack_required(s_rx_frame[s_rx_index]) && ieee802154_frame_get_version(s_rx_frame[s_rx_index]) == IEEE802154_FRAME_VERSION_2 && ieee802154_ll_get_tx_enhance_ack()) { - s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index]); + s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); // For 2015 enh-ack, SW should generate an enh-ack then send it manually if (ieee802154_inner_enh_ack_generator(s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index], s_enh_ack_frame) == ESP_OK) { extcoex_tx_stage_start(); diff --git a/components/ieee802154/driver/esp_ieee802154_frame.c b/components/ieee802154/driver/esp_ieee802154_frame.c index 79642c9bad..61357d8bcb 100644 --- a/components/ieee802154/driver/esp_ieee802154_frame.c +++ b/components/ieee802154/driver/esp_ieee802154_frame.c @@ -333,6 +333,9 @@ uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr) uint8_t offset = ieee802154_frame_address_offset(frame); uint8_t dst_mode = dst_addr_mode(frame); + if (dst_mode == IEEE802154_FRAME_DST_MODE_NONE) { + return dst_mode; + } uint8_t addr_size; ESP_RETURN_ON_FALSE_ISR(dst_mode == IEEE802154_FRAME_DST_MODE_SHORT || dst_mode == IEEE802154_FRAME_DST_MODE_EXT, dst_mode, IEEE802154_TAG, "invalid address mode"); @@ -357,6 +360,10 @@ uint8_t ieee802154_frame_get_src_addr(const uint8_t *frame, uint8_t *addr) uint8_t src_mode = src_addr_mode(frame); uint8_t addr_size; + if (src_mode == IEEE802154_FRAME_SRC_MODE_NONE) { + return src_mode; + } + ESP_RETURN_ON_FALSE_ISR(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT || src_mode == IEEE802154_FRAME_SRC_MODE_EXT, src_mode, IEEE802154_TAG, "invalid address mode"); addr_size = (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT) ? IEEE802154_FRAME_SHORT_ADDR_SIZE : IEEE802154_FRAME_EXT_ADDR_SIZE; diff --git a/components/ieee802154/driver/esp_ieee802154_pib.c b/components/ieee802154/driver/esp_ieee802154_pib.c index 57204949c1..bcfc13d290 100644 --- a/components/ieee802154/driver/esp_ieee802154_pib.c +++ b/components/ieee802154/driver/esp_ieee802154_pib.c @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include +#include "sdkconfig.h" #include "hal/ieee802154_ll.h" #include "esp_check.h" #include "esp_ieee802154_pib.h" @@ -74,7 +75,14 @@ void ieee802154_pib_update(void) ieee802154_ll_set_coordinator(s_ieee802154_pib.coordinator); ieee802154_ll_set_promiscuous(s_ieee802154_pib.promiscuous); - ieee802154_ll_set_pending_mode(s_ieee802154_pib.pending_mode == IEEE802154_AUTO_PENDING_ENHANCED); + bool target_mode = false; + for (int i = 0; i < CONFIG_IEEE802154_INTERFACE_NUM; i++) { + if (s_ieee802154_pib.pending_mode[i] == IEEE802154_AUTO_PENDING_ENHANCED || s_ieee802154_pib.pending_mode[i] == IEEE802154_AUTO_PENDING_ZIGBEE) { + target_mode = true; + break; + } + } + ieee802154_ll_set_pending_mode(target_mode); clr_pending(); } @@ -231,15 +239,15 @@ void ieee802154_pib_set_coordinator(bool enable) } } -ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(void) +ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(esp_ieee802154_multipan_index_t inf_index) { - return s_ieee802154_pib.pending_mode; + return s_ieee802154_pib.pending_mode[inf_index]; } -void ieee802154_pib_set_pending_mode(ieee802154_ll_pending_mode_t pending_mode) +void ieee802154_pib_set_pending_mode(esp_ieee802154_multipan_index_t inf_index, ieee802154_ll_pending_mode_t pending_mode) { - if (s_ieee802154_pib.pending_mode != pending_mode) { - s_ieee802154_pib.pending_mode = pending_mode; + if (s_ieee802154_pib.pending_mode[inf_index] != pending_mode) { + s_ieee802154_pib.pending_mode[inf_index] = pending_mode; set_pending(); } } diff --git a/components/ieee802154/esp_ieee802154.c b/components/ieee802154/esp_ieee802154.c index 39342eba8f..6f6f4282fc 100644 --- a/components/ieee802154/esp_ieee802154.c +++ b/components/ieee802154/esp_ieee802154.c @@ -163,40 +163,40 @@ esp_err_t esp_ieee802154_set_coordinator(bool enable) uint16_t esp_ieee802154_get_multipan_panid(esp_ieee802154_multipan_index_t index) { - assert(index < ESP_IEEE802154_MULTIPAN_MAX); + assert(index < CONFIG_IEEE802154_INTERFACE_NUM); return ieee802154_ll_get_multipan_panid(index); } esp_err_t esp_ieee802154_set_multipan_panid(esp_ieee802154_multipan_index_t index, uint16_t panid) { - assert(index < ESP_IEEE802154_MULTIPAN_MAX); + assert(index < CONFIG_IEEE802154_INTERFACE_NUM); ieee802154_ll_set_multipan_panid(index, panid); return ESP_OK; } uint16_t esp_ieee802154_get_multipan_short_address(esp_ieee802154_multipan_index_t index) { - assert(index < ESP_IEEE802154_MULTIPAN_MAX); + assert(index < CONFIG_IEEE802154_INTERFACE_NUM); return ieee802154_ll_get_multipan_short_addr(index); } esp_err_t esp_ieee802154_set_multipan_short_address(esp_ieee802154_multipan_index_t index, uint16_t short_address) { - assert(index < ESP_IEEE802154_MULTIPAN_MAX); + assert(index < CONFIG_IEEE802154_INTERFACE_NUM); ieee802154_ll_set_multipan_short_addr(index, short_address); return ESP_OK; } esp_err_t esp_ieee802154_get_multipan_extended_address(esp_ieee802154_multipan_index_t index, uint8_t *ext_addr) { - assert(index < ESP_IEEE802154_MULTIPAN_MAX); + assert(index < CONFIG_IEEE802154_INTERFACE_NUM); ieee802154_ll_get_multipan_ext_addr(index, ext_addr); return ESP_OK; } esp_err_t esp_ieee802154_set_multipan_extended_address(esp_ieee802154_multipan_index_t index, const uint8_t *ext_addr) { - assert(index < ESP_IEEE802154_MULTIPAN_MAX); + assert(index < CONFIG_IEEE802154_INTERFACE_NUM); ieee802154_ll_set_multipan_ext_addr(index, ext_addr); return ESP_OK; } @@ -208,10 +208,43 @@ uint8_t esp_ieee802154_get_multipan_enable(void) esp_err_t esp_ieee802154_set_multipan_enable(uint8_t mask) { - assert(mask < (1 << ESP_IEEE802154_MULTIPAN_MAX)); + assert(mask < (1 << CONFIG_IEEE802154_INTERFACE_NUM)); ieee802154_ll_set_multipan_enable_mask(mask); return ESP_OK; } + +esp_ieee802154_pending_mode_t esp_ieee802154_multipan_get_pending_mode(esp_ieee802154_multipan_index_t index) +{ + assert(index < CONFIG_IEEE802154_INTERFACE_NUM); + return ieee802154_pib_get_pending_mode(index); +} + +esp_err_t esp_ieee802154_multipan_set_pending_mode(esp_ieee802154_multipan_index_t inf_index, esp_ieee802154_pending_mode_t pending_mode) +{ + assert(inf_index < CONFIG_IEEE802154_INTERFACE_NUM); + ieee802154_pib_set_pending_mode(inf_index, pending_mode); + return ESP_OK; +} + +esp_err_t esp_ieee802154_multipan_add_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short) +{ + assert(inf_index < CONFIG_IEEE802154_INTERFACE_NUM); + return ieee802154_add_pending_addr(inf_index, addr, is_short); +} + +esp_err_t esp_ieee802154_multipan_clear_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short) +{ + assert(inf_index < CONFIG_IEEE802154_INTERFACE_NUM); + return ieee802154_clear_pending_addr(inf_index, addr, is_short); +} + +esp_err_t esp_ieee802154_multipan_reset_pending_table(esp_ieee802154_multipan_index_t inf_index, bool is_short) +{ + assert(inf_index < CONFIG_IEEE802154_INTERFACE_NUM); + ieee802154_reset_pending_table(inf_index, is_short); + return ESP_OK; +} + #endif // CONFIG_IEEE802154_MULTI_PAN_ENABLE esp_err_t esp_ieee802154_set_ack_timeout(uint32_t timeout) @@ -266,12 +299,12 @@ esp_err_t esp_ieee802154_set_extended_address(const uint8_t *ext_addr) esp_ieee802154_pending_mode_t esp_ieee802154_get_pending_mode(void) { - return ieee802154_pib_get_pending_mode(); + return ieee802154_pib_get_pending_mode(ESP_IEEE802154_MULTIPAN_0); } esp_err_t esp_ieee802154_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode) { - ieee802154_pib_set_pending_mode(pending_mode); + ieee802154_pib_set_pending_mode(ESP_IEEE802154_MULTIPAN_0, pending_mode); return ESP_OK; } @@ -359,17 +392,17 @@ esp_err_t esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uin esp_err_t esp_ieee802154_add_pending_addr(const uint8_t *addr, bool is_short) { - return ieee802154_add_pending_addr(addr, is_short); + return ieee802154_add_pending_addr(0, addr, is_short); } esp_err_t esp_ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short) { - return ieee802154_clear_pending_addr(addr, is_short); + return ieee802154_clear_pending_addr(0, addr, is_short); } esp_err_t esp_ieee802154_reset_pending_table(bool is_short) { - ieee802154_reset_pending_table(is_short); + ieee802154_reset_pending_table(0, is_short); return ESP_OK; } diff --git a/components/ieee802154/include/esp_ieee802154.h b/components/ieee802154/include/esp_ieee802154.h index 2971cc22c6..8eb07142a7 100644 --- a/components/ieee802154/include/esp_ieee802154.h +++ b/components/ieee802154/include/esp_ieee802154.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -756,6 +756,80 @@ esp_err_t esp_ieee802154_event_callback_list_register(esp_ieee802154_event_cb_li */ esp_err_t esp_ieee802154_event_callback_list_unregister(void); +/** + * @brief Add a pending address to the multipan table for the specified interface. + * + * @note This API should be called only when the IEEE 802.15.4 subsystem is enabled. + * + * @param inf_index Index of the interface. + * @param addr Pointer to the address to add. + * @param is_short True if the address is a short address, false if extended. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_multipan_add_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short); + +/** + * @brief Remove a pending address from the multipan table for the specified interface. + * + * @note This API should be called only when the IEEE 802.15.4 subsystem is enabled. + * + * @param inf_index Index of the interface. + * @param addr Pointer to the address to remove. + * @param is_short True if the address is a short address, false if extended. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_multipan_clear_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short); + +/** + * @brief Reset the pending address table for the specified interface. + * + * @note This API clears all pending addresses of the specified type (short or extended) for the interface. + * + * @param inf_index Index of the interface. + * @param is_short True to reset short addresses, false to reset extended addresses. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_multipan_reset_pending_table(esp_ieee802154_multipan_index_t inf_index, bool is_short); + +/** + * @brief Get the auto frame pending mode of the specified multipan interface. + * + * @note This API returns the logical pending mode configured for a given multipan + * interface. The value is used by the ACK generation logic together with the + * per-interface pending address table. + * + * @param inf_index Index of the multipan interface. + * + * @return + * - Current pending mode of type ::esp_ieee802154_pending_mode_t. + */ +esp_ieee802154_pending_mode_t esp_ieee802154_multipan_get_pending_mode(esp_ieee802154_multipan_index_t inf_index); + +/** + * @brief Set the auto frame pending mode of the specified multipan interface. + * + * @note This API configures the logical pending mode for a given multipan interface. + * The configured mode is used by the ACK generation logic together with the + * per-interface pending address table. + * + * @param inf_index Index of the multipan interface. + * @param pending_mode Pending mode to set for this interface. + * + * @return + * - ESP_OK on success. + * - ESP_FAIL on failure. + */ +esp_err_t esp_ieee802154_multipan_set_pending_mode(esp_ieee802154_multipan_index_t inf_index, esp_ieee802154_pending_mode_t pending_mode); + #ifdef __cplusplus } #endif diff --git a/components/ieee802154/include/esp_ieee802154_types.h b/components/ieee802154/include/esp_ieee802154_types.h index bf52ed91a4..ce01937fb9 100644 --- a/components/ieee802154/include/esp_ieee802154_types.h +++ b/components/ieee802154/include/esp_ieee802154_types.h @@ -82,6 +82,7 @@ typedef struct { int8_t rssi; /*!< RSSI */ uint8_t lqi; /*!< LQI */ uint64_t timestamp; /*!< The timestamp when the frame's SFD field was received */ + esp_ieee802154_multipan_index_t mpf_index; /*!< Multipan interface that matches the frame, ESP_IEEE802154_MULTIPAN_MAX if none */ } esp_ieee802154_frame_info_t; /** diff --git a/components/ieee802154/private_include/esp_ieee802154_ack.h b/components/ieee802154/private_include/esp_ieee802154_ack.h index 2910a561b4..83154e409f 100644 --- a/components/ieee802154/private_include/esp_ieee802154_ack.h +++ b/components/ieee802154/private_include/esp_ieee802154_ack.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include #include "sdkconfig.h" #include "esp_err.h" +#include "esp_ieee802154_types.h" #include "esp_ieee802154_frame.h" #ifdef __cplusplus @@ -40,7 +41,7 @@ typedef struct { * - ESP_FAIL on failure due to the table is full. * */ -esp_err_t ieee802154_add_pending_addr(const uint8_t *addr, bool is_short); +esp_err_t ieee802154_add_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short); /** * @brief Remove an address in pending table. @@ -53,7 +54,7 @@ esp_err_t ieee802154_add_pending_addr(const uint8_t *addr, bool is_short); * - ESP_FAIL on failure if the given address is not present in the pending table. * */ -esp_err_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short); +esp_err_t ieee802154_clear_pending_addr(esp_ieee802154_multipan_index_t inf_index, const uint8_t *addr, bool is_short); /** * @brief Reset the pending table, only clear the mask bits for finishing the process quickly. @@ -61,7 +62,7 @@ esp_err_t ieee802154_clear_pending_addr(const uint8_t *addr, bool is_short); * @param[in] is_short The type of address, true for resetting short address table, false for extended. * */ -void ieee802154_reset_pending_table(bool is_short); +void ieee802154_reset_pending_table(esp_ieee802154_multipan_index_t inf_index, bool is_short); /** * @brief Check whether the pending bit should be set or not in the ack frame. @@ -72,7 +73,7 @@ void ieee802154_reset_pending_table(bool is_short); * - True The pending bit should be set, otherwise False. * */ -bool ieee802154_ack_config_pending_bit(const uint8_t *frame); +bool ieee802154_ack_config_pending_bit(const uint8_t *frame, const esp_ieee802154_frame_info_t *frame_info); #ifdef __cplusplus } diff --git a/components/ieee802154/private_include/esp_ieee802154_dev.h b/components/ieee802154/private_include/esp_ieee802154_dev.h index 1d53af66f0..aaeed472ee 100644 --- a/components/ieee802154/private_include/esp_ieee802154_dev.h +++ b/components/ieee802154/private_include/esp_ieee802154_dev.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/ieee802154/private_include/esp_ieee802154_pib.h b/components/ieee802154/private_include/esp_ieee802154_pib.h index c6edcde134..3824852b9c 100644 --- a/components/ieee802154/private_include/esp_ieee802154_pib.h +++ b/components/ieee802154/private_include/esp_ieee802154_pib.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include #include +#include "sdkconfig.h" #include "hal/ieee802154_ll.h" #include "esp_ieee802154_frame.h" #include "esp_ieee802154_types.h" @@ -28,7 +29,7 @@ typedef struct { bool rx_when_idle; /*!< A flag indicates the device is rx on when idle or not */ esp_ieee802154_txpower_table_t power_table; /*!< The power table configuration */ uint8_t channel; /*!< Channel configuration */ - ieee802154_ll_pending_mode_t pending_mode; /*!< Pending mode configuration */ + ieee802154_ll_pending_mode_t pending_mode[CONFIG_IEEE802154_INTERFACE_NUM]; /*!< Pending mode configuration */ int8_t cca_threshold; /*!< CCA threshold */ ieee802154_ll_cca_mode_t cca_mode; /*!< CCA mode */ } ieee802154_pib_t; @@ -248,7 +249,7 @@ bool ieee802154_pib_get_coordinator(void); * @param[in] pending_mode The pending mode. * */ -void ieee802154_pib_set_pending_mode(ieee802154_ll_pending_mode_t pending_mode); +void ieee802154_pib_set_pending_mode(esp_ieee802154_multipan_index_t inf_index, ieee802154_ll_pending_mode_t pending_mode); /** * @brief Get the pending mode from the PIB. @@ -256,7 +257,7 @@ void ieee802154_pib_set_pending_mode(ieee802154_ll_pending_mode_t pending_mode); * @return * - The pending mode has been set in the PIB. */ -ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(void); +ieee802154_ll_pending_mode_t ieee802154_pib_get_pending_mode(esp_ieee802154_multipan_index_t inf_index); /** * @brief Configure the radio mode when the radio is going to enter idle to the PIB. From a4e621eb9c06e463fdda36cdb3a607a385974584 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Wed, 31 Dec 2025 16:44:47 +0800 Subject: [PATCH 10/84] fix(802.15.4): move multipan and data request helpers into IRAM --- components/ieee802154/linker.lf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/ieee802154/linker.lf b/components/ieee802154/linker.lf index ad766e556f..5931d3cfac 100644 --- a/components/ieee802154/linker.lf +++ b/components/ieee802154/linker.lf @@ -17,6 +17,10 @@ entries: esp_ieee802154_frame: ieee802154_frame_get_security_payload_offset (noflash) esp_ieee802154_frame: ieee802154_frame_get_src_addr (noflash) esp_ieee802154_frame: ieee802154_frame_security_header_offset (noflash) + esp_ieee802154_frame: ieee802154_frame_get_dest_panid (noflash) + esp_ieee802154_frame: ieee802154_frame_get_dst_addr (noflash) + esp_ieee802154_frame: ieee802154_frame_get_src_panid (noflash) + esp_ieee802154_frame: ieee802154_is_data_request (noflash) esp_ieee802154_frame: is_dst_panid_present (noflash) esp_ieee802154_frame: is_src_panid_present (noflash) esp_ieee802154_pib: ieee802154_pib_get_pending_mode (noflash) @@ -72,3 +76,11 @@ entries: esp_ieee802154_timer: isr_handle_timer0_done (noflash) esp_ieee802154_timer: isr_handle_timer1_done (noflash) esp_ieee802154_util: ieee802154_channel_to_freq (noflash) + + if IEEE802154_MULTI_PAN_ENABLE = y: + esp_ieee802154: esp_ieee802154_get_multipan_extended_address (noflash) + esp_ieee802154: esp_ieee802154_get_multipan_panid (noflash) + esp_ieee802154: esp_ieee802154_get_multipan_short_address (noflash) + esp_ieee802154_dev: is_broadcast_addr (noflash) + esp_ieee802154_dev: is_broadcast_panid (noflash) + esp_ieee802154_dev: update_mpf_index (noflash) From db4802a9efc818d898902960e2b6876a080e1dc7 Mon Sep 17 00:00:00 2001 From: Luo Xu Date: Thu, 15 Jan 2026 17:43:27 +0800 Subject: [PATCH 11/84] feat(ble_mesh): update log compression for ble mesh lib (cherry picked from commit 7c4b104f616f9027c09068c18618f114a044bb05) Co-authored-by: luoxu --- components/bt/CMakeLists.txt | 17 +++--- .../log_compression/ble_log_compression.c | 61 +++++++++++++------ .../include/log_compression/utils.h | 2 + components/bt/esp_ble_mesh/lib/ext.c | 29 +++++++++ 4 files changed, 83 insertions(+), 26 deletions(-) diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index af71a578fa..f0f48d1a51 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -1084,26 +1084,29 @@ if(CONFIG_BT_ENABLED) endif() if(CONFIG_BLE_MESH_V11_SUPPORT) + +set(BLE_MESH_LIB_NAME "libble_mesh.a") + if(CONFIG_IDF_TARGET_ESP32) - add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32/libble_mesh.a") + add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32/${BLE_MESH_LIB_NAME}") target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) elseif(CONFIG_IDF_TARGET_ESP32S3) - add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32s3/libble_mesh.a") + add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32s3/${BLE_MESH_LIB_NAME}") target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) elseif(CONFIG_IDF_TARGET_ESP32C3) - add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32c3/libble_mesh.a") + add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32c3/${BLE_MESH_LIB_NAME}") target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) elseif(CONFIG_IDF_TARGET_ESP32C6) - add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32c6/libble_mesh.a") + add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32c6/${BLE_MESH_LIB_NAME}") target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) elseif(CONFIG_IDF_TARGET_ESP32C61) - add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32c61/libble_mesh.a") + add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32c61/${BLE_MESH_LIB_NAME}") target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) elseif(CONFIG_IDF_TARGET_ESP32H2) - add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32h2/libble_mesh.a") + add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32h2/${BLE_MESH_LIB_NAME}") target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) elseif(CONFIG_IDF_TARGET_ESP32C5) - add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32c5/libble_mesh.a") + add_prebuilt_library(ble_mesh "esp_ble_mesh/lib/lib/esp32c5/${BLE_MESH_LIB_NAME}") target_link_libraries(${COMPONENT_LIB} PRIVATE ble_mesh) endif() endif() diff --git a/components/bt/common/ble_log/extension/log_compression/ble_log_compression.c b/components/bt/common/ble_log/extension/log_compression/ble_log_compression.c index 382c33a2cf..904bd5e284 100644 --- a/components/bt/common/ble_log/extension/log_compression/ble_log_compression.c +++ b/components/bt/common/ble_log/extension/log_compression/ble_log_compression.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -61,6 +61,7 @@ int ble_compressed_log_cb_get(uint8_t source, ble_cp_log_buffer_mgmt_t **mgmt) { #if CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE case BLE_COMPRESSED_LOG_OUT_SOURCE_MESH: + case BLE_COMPRESSED_LOG_OUT_SOURCE_MESH_LIB: buffer_mgmt = BUF_MGMT_NAME(mesh); last_handle = &mesh_last_task_handle; break; @@ -102,23 +103,10 @@ static inline int ble_compressed_log_buffer_free(ble_cp_log_buffer_mgmt_t *mgmt) return 0; } -int ble_log_compressed_hex_print(uint8_t source, uint32_t log_index, size_t args_cnt, ...) +static inline +int ble_log_compressed_hex_print_internal(ble_cp_log_buffer_mgmt_t *mgmt, uint32_t log_index, size_t args_cnt, va_list args) { - ble_cp_log_buffer_mgmt_t *mgmt = NULL; uint8_t arg_type = 0; - va_list args; - - ble_compressed_log_cb_get(source, &mgmt); - - if (args_cnt == 0) { - ble_log_cp_push_u8(mgmt, LOG_HEADER(LOG_TYPE_HEX_ARGS, 0)); - ble_log_cp_push_u16(mgmt, log_index); - ble_compressed_log_output(source, mgmt->buffer, mgmt->idx); - ble_compressed_log_buffer_free(mgmt); - return 0; - } - - va_start(args, args_cnt); ble_log_cp_push_u8(mgmt, LOG_HEADER(LOG_TYPE_HEX_ARGS, args_cnt)); ble_log_cp_push_u16(mgmt, log_index); @@ -142,7 +130,7 @@ int ble_log_compressed_hex_print(uint8_t source, uint32_t log_index, size_t args } if (arg_type >= ARG_SIZE_TYPE_MAX) { printf("Found invalid arg type %08lx type %d", log_index, arg_type); - assert(0); + return 0; } } @@ -232,10 +220,43 @@ int ble_log_compressed_hex_print(uint8_t source, uint32_t log_index, size_t args break; } } + return 0; +} + +int ble_log_compressed_hex_printv(uint8_t source, uint32_t log_index, size_t args_cnt, va_list args) +{ + ble_cp_log_buffer_mgmt_t *mgmt = NULL; + + if (ble_compressed_log_cb_get(source, &mgmt)) { + return 0; + } + + ble_log_compressed_hex_print_internal(mgmt, log_index, args_cnt, args); + ble_compressed_log_output(source, mgmt->buffer, mgmt->idx); + ble_compressed_log_buffer_free(mgmt); + return 0; +} + +int ble_log_compressed_hex_print(uint8_t source, uint32_t log_index, size_t args_cnt, ...) +{ + ble_cp_log_buffer_mgmt_t *mgmt = NULL; + + if (ble_compressed_log_cb_get(source, &mgmt)) { + return 0; + } + + if (args_cnt == 0) { + ble_log_cp_push_u8(mgmt, LOG_HEADER(LOG_TYPE_HEX_ARGS, 0)); + ble_log_cp_push_u16(mgmt, log_index); + } else { + va_list args; + va_start(args, args_cnt); + ble_log_compressed_hex_print_internal(mgmt, log_index, args_cnt, args); + va_end(args); + } ble_compressed_log_output(source, mgmt->buffer, mgmt->idx); ble_compressed_log_buffer_free(mgmt); - va_end(args); return 0; } @@ -243,7 +264,9 @@ int ble_log_compressed_hex_print_buf(uint8_t source, uint32_t log_index, uint8_t { ble_cp_log_buffer_mgmt_t *mgmt = NULL; - ble_compressed_log_cb_get(source, &mgmt); + if (ble_compressed_log_cb_get(source, &mgmt)) { + return 0; + } if (buf == NULL && len != 0) { ble_log_cp_push_u8(mgmt, LOG_HEADER(LOG_TYPE_INFO, LOG_TYPE_INFO_NULL_BUF)); diff --git a/components/bt/common/ble_log/extension/log_compression/include/log_compression/utils.h b/components/bt/common/ble_log/extension/log_compression/include/log_compression/utils.h index 5365939e0e..b6cce4af75 100644 --- a/components/bt/common/ble_log/extension/log_compression/include/log_compression/utils.h +++ b/components/bt/common/ble_log/extension/log_compression/include/log_compression/utils.h @@ -7,6 +7,7 @@ #define _BLE_LOG_COMPRESSION_UTILS_H #include "ble_log.h" +#include #define CONCAT(a, b) a##b #define _CONCAT(a, b) CONCAT(a, b) @@ -47,6 +48,7 @@ enum { BLE_COMPRESSED_LOG_OUT_SOURCE_HOST, BLE_COMPRESSED_LOG_OUT_SOURCE_MESH, + BLE_COMPRESSED_LOG_OUT_SOURCE_MESH_LIB, }; enum { diff --git a/components/bt/esp_ble_mesh/lib/ext.c b/components/bt/esp_ble_mesh/lib/ext.c index 3f654f82de..db62c25c49 100644 --- a/components/bt/esp_ble_mesh/lib/ext.c +++ b/components/bt/esp_ble_mesh/lib/ext.c @@ -14,6 +14,10 @@ #include "bta/bta_api.h" #endif +#if CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE +#include "log_compression/utils.h" +#endif + #include "btc_ble_mesh_agg_model.h" #include "btc_ble_mesh_brc_model.h" #include "btc_ble_mesh_df_model.h" @@ -5042,6 +5046,31 @@ void bt_mesh_lib_log_debug(const char *format, ...) #endif } +void ble_mesh_lib_compressed_out(uint8_t log_level, uint32_t log_index, size_t arg_cnt, ...) +{ +#if CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE + if (BLE_MESH_LOG_LEVEL >= log_level) { + va_list args = {0}; + va_start(args, arg_cnt); + extern int ble_log_compressed_hex_printv(uint8_t source, uint32_t log_index, size_t args_cnt, va_list args); + ble_log_compressed_hex_printv(BLE_COMPRESSED_LOG_OUT_SOURCE_MESH_LIB, log_index, arg_cnt, args); + va_end(args); + } +#endif + return; +} + +void ble_mesh_lib_compressed_buf_out(uint8_t log_level, uint32_t log_index, uint8_t buf_idx, const uint8_t *buf, uint8_t len) +{ +#if CONFIG_BLE_MESH_COMPRESSED_LOG_ENABLE + if (BLE_MESH_LOG_LEVEL >= log_level) { + extern int ble_log_compressed_hex_print_buf(uint8_t source, uint32_t log_index, uint8_t buf_idx, const uint8_t *buf, size_t len); + ble_log_compressed_hex_print_buf(BLE_COMPRESSED_LOG_OUT_SOURCE_MESH_LIB, log_index, buf_idx, buf, len); + } +#endif + return; +} + /** * @brief Keep symbols alive. * @note Dummy function to stop the linker from From 3feac750e3f82254cbc1a6f8a9650fc2e5700c10 Mon Sep 17 00:00:00 2001 From: yiwenxiu Date: Tue, 25 Nov 2025 17:55:47 +0800 Subject: [PATCH 12/84] feat(openthread): add C5 sleep test case --- examples/openthread/.build-test-rules.yml | 4 --- examples/openthread/ot_ci_function.py | 3 ++- .../ot_sleepy_device/light_sleep/README.md | 4 +-- examples/openthread/pytest_otbr.py | 26 ++++++++++++++++--- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/examples/openthread/.build-test-rules.yml b/examples/openthread/.build-test-rules.yml index 559a7957ce..30822b2ea0 100644 --- a/examples/openthread/.build-test-rules.yml +++ b/examples/openthread/.build-test-rules.yml @@ -58,10 +58,6 @@ examples/openthread/ot_sleepy_device/deep_sleep: examples/openthread/ot_sleepy_device/light_sleep: enable: - if: SOC_IEEE802154_SUPPORTED == 1 - disable: - - if: IDF_TARGET in ["esp32c5"] - temporary: true - reason: Not supported yet, TZ-958 <<: [*openthread_dependencies, *openthread_sleep_dependencies] examples/openthread/ot_trel: diff --git a/examples/openthread/ot_ci_function.py b/examples/openthread/ot_ci_function.py index 3b7c45d748..ddb791de66 100644 --- a/examples/openthread/ot_ci_function.py +++ b/examples/openthread/ot_ci_function.py @@ -208,8 +208,9 @@ def reset_thread(dut: IdfDut) -> None: def hardreset_dut(dut: IdfDut) -> None: dut.serial.hard_reset() - time.sleep(5) + dut.expect('OpenThread attached to netif', timeout=20) execute_command(dut, 'factoryreset') + dut.expect('OpenThread attached to netif', timeout=20) # get the mleid address of the thread diff --git a/examples/openthread/ot_sleepy_device/light_sleep/README.md b/examples/openthread/ot_sleepy_device/light_sleep/README.md index 24ed4aa192..6eea2789b6 100644 --- a/examples/openthread/ot_sleepy_device/light_sleep/README.md +++ b/examples/openthread/ot_sleepy_device/light_sleep/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C6 | ESP32-H2 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | -------- | # OpenThread Sleepy Device Example The example demonstrates the Thread Sleepy End Device (SED), the device will enter [Light Sleep mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/api-reference/system/sleep_modes.html#sleep-modes) during idle state. diff --git a/examples/openthread/pytest_otbr.py b/examples/openthread/pytest_otbr.py index 9d5072337c..8cd91bd742 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 # !/usr/bin/env python3 import copy @@ -99,8 +99,9 @@ default_cli_ot_para = ocf.thread_parameter('router', '', '', '', False) ESPPORT1 = os.getenv('ESPPORT1') ESPPORT2 = os.getenv('ESPPORT2') ESPPORT3 = os.getenv('ESPPORT3') +ESPPORT4 = os.getenv('ESPPORT4') -PORT_MAPPING = {'ESPPORT1': 'esp32h2', 'ESPPORT2': 'esp32s3', 'ESPPORT3': 'esp32c6'} +PORT_MAPPING = {'ESPPORT1': 'esp32h2', 'ESPPORT2': 'esp32s3', 'ESPPORT3': 'esp32c6', 'ESPPORT4': 'esp32c5'} # Case 1: Thread network formation and attaching @@ -661,6 +662,15 @@ def test_TCP_NAT64(Init_interface: bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> f'{ESPPORT3}|{ESPPORT1}', id='c6-h2', ), + pytest.param( + 'cli|sleepy', + 2, + f'{os.path.join(os.path.dirname(__file__), "ot_cli")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_sleepy_device/light_sleep")}', + 'esp32h2|esp32c5', + f'{ESPPORT1}|{ESPPORT4}', + id='h2-c5', + ), ], indirect=True, ) @@ -677,10 +687,15 @@ def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None: ocf.wait(leader, 5) dataset = ocf.getDataset(leader) ocf.execute_command(sleepy_device, 'mode -') + sleepy_device.expect('Done', timeout=5) ocf.execute_command(sleepy_device, 'pollperiod 3000') + sleepy_device.expect('Done', timeout=5) ocf.execute_command(sleepy_device, 'dataset set active ' + dataset) + sleepy_device.expect('Done', timeout=5) ocf.execute_command(sleepy_device, 'ifconfig up') + sleepy_device.expect('Done', timeout=5) ocf.execute_command(sleepy_device, 'thread start') + sleepy_device.expect('Done', timeout=5) info = sleepy_device.expect(r'(.+)detached -> child', timeout=20)[1].decode(errors='replace') assert not bool(fail_info.search(str(info))) info = sleepy_device.expect(r'(.+)PMU_SLEEP_PD_TOP: True', timeout=10)[1].decode(errors='replace') @@ -693,7 +708,9 @@ def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None: output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5) assert not bool(fail_info.search(str(output))) finally: + logging.info('Cleaning up...') ocf.execute_command(leader, 'factoryreset') + leader.expect('OpenThread attached to netif', timeout=20) ocf.hardreset_dut(sleepy_device) time.sleep(3) @@ -994,9 +1011,10 @@ def test_ot_ssed_device(dut: Tuple[IdfDut, IdfDut]) -> None: leader = dut[0] ssed_device = dut[1] try: - ocf.hardreset_dut(ssed_device) + ocf.clean_buffer(ssed_device) + ssed_device.serial.hard_reset() # CI device must have external XTAL to run SSED case, we will check this here first - ssed_device.expect('32k XTAL in use', timeout=10) + ssed_device.expect('32k XTAL in use', timeout=20) ocf.init_thread(leader) time.sleep(3) leader_para = ocf.thread_parameter('leader', '', '12', '7766554433221100', False) From 343fbafafef860d7bd59bebc1d10bc310b41a636 Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Thu, 15 Jan 2026 23:44:05 +0800 Subject: [PATCH 13/84] Revert "fix(esp_system): limit CPU clock to 160MHz in ESP32-C5 for flash encryption" This reverts commit cca0ac8c563993e4c2a555f47776ab14605a6244. --- components/esp_security/src/init.c | 10 ---------- components/esp_system/port/soc/esp32c5/Kconfig.cpu | 8 +------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/components/esp_security/src/init.c b/components/esp_security/src/init.c index 86cc0a6fd2..16ef897bad 100644 --- a/components/esp_security/src/init.c +++ b/components/esp_security/src/init.c @@ -55,16 +55,6 @@ static void esp_key_mgr_init(void) ESP_SYSTEM_INIT_FN(esp_security_init, SECONDARY, BIT(0), 103) { -#if CONFIG_IDF_TARGET_ESP32C5 - // Check for unsupported configuration: flash encryption with CPU frequency > 160MHz - // Manual encrypted flash writes are not stable at higher CPU clock. - // Please refer to the ESP32-C5 SoC Errata document for more details. - if (efuse_hal_flash_encryption_enabled() && CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ > 160) { - ESP_EARLY_LOGE(TAG, "Flash encryption with CPU frequency > 160MHz is not supported. Please reconfigure the CPU frequency."); - return ESP_ERR_NOT_SUPPORTED; - } -#endif - esp_crypto_clk_init(); esp_key_mgr_init(); #if CONFIG_ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP diff --git a/components/esp_system/port/soc/esp32c5/Kconfig.cpu b/components/esp_system/port/soc/esp32c5/Kconfig.cpu index 95c3b92cbc..a9fd58e28f 100644 --- a/components/esp_system/port/soc/esp32c5/Kconfig.cpu +++ b/components/esp_system/port/soc/esp32c5/Kconfig.cpu @@ -1,12 +1,9 @@ choice ESP_DEFAULT_CPU_FREQ_MHZ prompt "CPU frequency" default ESP_DEFAULT_CPU_FREQ_MHZ_40 if IDF_ENV_FPGA - default ESP_DEFAULT_CPU_FREQ_MHZ_160 if SECURE_FLASH_ENC_ENABLED default ESP_DEFAULT_CPU_FREQ_MHZ_240 help - CPU frequency to be set on application startup. For flash encryption enabled case, - the default CPU frequency is 160MHz as the encrypted flash writes are not stable at - higher CPU clock. Please see SoC Errata document for details. + CPU frequency to be set on application startup. config ESP_DEFAULT_CPU_FREQ_MHZ_40 bool "40 MHz" @@ -16,9 +13,6 @@ choice ESP_DEFAULT_CPU_FREQ_MHZ config ESP_DEFAULT_CPU_FREQ_MHZ_160 bool "160 MHz" config ESP_DEFAULT_CPU_FREQ_MHZ_240 - # Encrypted flash writes aren't supported at 240 MHz. - # Please see SoC Errata document for details. - depends on !SECURE_FLASH_ENC_ENABLED bool "240 MHz" help When 240MHz is selected, esp_flash_write_encrypted() will automatically limit CPU frequency during From 340d7655adfb534a57ea3b203bf22b5b2f521a3b Mon Sep 17 00:00:00 2001 From: Deomid rojer Ryabkov Date: Sat, 14 Jun 2025 18:31:32 +0300 Subject: [PATCH 14/84] fix(esp_adc): Release the peripheral after calibration --- components/esp_adc/adc_common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_adc/adc_common.c b/components/esp_adc/adc_common.c index 1b5a8d599e..d3dccb9999 100644 --- a/components/esp_adc/adc_common.c +++ b/components/esp_adc/adc_common.c @@ -77,5 +77,6 @@ static __attribute__((constructor)) void adc_hw_calibration(void) } } ANALOG_CLOCK_DISABLE(); + adc_apb_periph_free(); } #endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED From 286d9b2091678ded10870b76e5ae84dc67691682 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Tue, 25 Nov 2025 15:58:29 +0800 Subject: [PATCH 15/84] fix(adc): fix P4 ADC2 oneshot error and refactor apb claim macor --- components/esp_adc/adc_common.c | 12 +++++-- components/esp_adc/adc_oneshot.c | 38 ++++++++++---------- components/hal/esp32/include/hal/adc_ll.h | 3 +- components/hal/esp32c2/include/hal/adc_ll.h | 2 ++ components/hal/esp32c3/include/hal/adc_ll.h | 3 +- components/hal/esp32c5/include/hal/adc_ll.h | 3 +- components/hal/esp32c6/include/hal/adc_ll.h | 3 +- components/hal/esp32c61/include/hal/adc_ll.h | 3 +- components/hal/esp32h2/include/hal/adc_ll.h | 3 +- components/hal/esp32p4/include/hal/adc_ll.h | 3 +- components/hal/esp32s2/include/hal/adc_ll.h | 3 +- components/hal/esp32s3/include/hal/adc_ll.h | 3 +- 12 files changed, 48 insertions(+), 31 deletions(-) diff --git a/components/esp_adc/adc_common.c b/components/esp_adc/adc_common.c index d3dccb9999..93720e405d 100644 --- a/components/esp_adc/adc_common.c +++ b/components/esp_adc/adc_common.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,6 +17,7 @@ #include "hal/adc_hal_common.h" #include "esp_private/regi2c_ctrl.h" #include "soc/adc_periph.h" +#include "hal/adc_ll.h" static const char *TAG = "adc_common"; @@ -57,10 +58,13 @@ esp_err_t adc_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int * con ---------------------------------------------------------------*/ static __attribute__((constructor)) void adc_hw_calibration(void) { - adc_apb_periph_claim(); ANALOG_CLOCK_ENABLE(); //Calculate all ICode for (int i = 0; i < SOC_ADC_PERIPH_NUM; i++) { + if (ADC_LL_NEED_APB_PERIPH_CLAIM(i)) { + adc_apb_periph_claim(); + } + adc_hal_calibration_init(i); for (int j = 0; j < SOC_ADC_ATTEN_NUM; j++) { /** @@ -75,8 +79,10 @@ static __attribute__((constructor)) void adc_hw_calibration(void) } #endif } + if (ADC_LL_NEED_APB_PERIPH_CLAIM(i)) { + adc_apb_periph_free(); + } } ANALOG_CLOCK_DISABLE(); - adc_apb_periph_free(); } #endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED diff --git a/components/esp_adc/adc_oneshot.c b/components/esp_adc/adc_oneshot.c index 1af0bdb8db..0d185ba341 100644 --- a/components/esp_adc/adc_oneshot.c +++ b/components/esp_adc/adc_oneshot.c @@ -144,15 +144,15 @@ esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, a adc_oneshot_hal_init(&(unit->hal), &config); -#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED - //To enable the APB_SARADC periph if needed - _lock_acquire(&s_ctx.mutex); - s_ctx.apb_periph_ref_cnts++; - if (s_ctx.apb_periph_ref_cnts == 1) { - adc_apb_periph_claim(); + if (ADC_LL_NEED_APB_PERIPH_CLAIM(unit->unit_id)) { + //To enable the APB_SARADC periph if needed + _lock_acquire(&s_ctx.mutex); + s_ctx.apb_periph_ref_cnts++; + if (s_ctx.apb_periph_ref_cnts == 1) { + adc_apb_periph_claim(); + } + _lock_release(&s_ctx.mutex); } - _lock_release(&s_ctx.mutex); -#endif if (init_config->ulp_mode == ADC_ULP_MODE_DISABLE) { sar_periph_ctrl_adc_oneshot_power_acquire(); @@ -297,18 +297,20 @@ esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle) #endif ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)(handle->hal.clk_src), false)); } - free(handle); -#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED - //To free the APB_SARADC periph if needed - _lock_acquire(&s_ctx.mutex); - s_ctx.apb_periph_ref_cnts--; - assert(s_ctx.apb_periph_ref_cnts >= 0); - if (s_ctx.apb_periph_ref_cnts == 0) { - adc_apb_periph_free(); + if (ADC_LL_NEED_APB_PERIPH_CLAIM(handle->unit_id)) { + //To free the APB_SARADC periph if needed + _lock_acquire(&s_ctx.mutex); + s_ctx.apb_periph_ref_cnts--; + assert(s_ctx.apb_periph_ref_cnts >= 0); + if (s_ctx.apb_periph_ref_cnts == 0) { + adc_apb_periph_free(); + } + _lock_release(&s_ctx.mutex); } - _lock_release(&s_ctx.mutex); -#endif + + ESP_LOGD(TAG, "adc unit%"PRId32" is deleted", handle->unit_id); + free(handle); #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP //TODO: IDF-8475: Depends to SLEEP_RETENTION_MODULE_CLOCK_MODEM retention module after ADC retention supported. diff --git a/components/hal/esp32/include/hal/adc_ll.h b/components/hal/esp32/include/hal/adc_ll.h index d4cca33a47..8c939d5c8b 100644 --- a/components/hal/esp32/include/hal/adc_ll.h +++ b/components/hal/esp32/include/hal/adc_ll.h @@ -26,7 +26,8 @@ extern "C" { #define ADC_LL_EVENT_ADC1_ONESHOT_DONE (1 << 0) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE (1 << 1) -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0 +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (0) /*--------------------------------------------------------------- Oneshot diff --git a/components/hal/esp32c2/include/hal/adc_ll.h b/components/hal/esp32c2/include/hal/adc_ll.h index 2e234d740c..b54453820e 100644 --- a/components/hal/esp32c2/include/hal/adc_ll.h +++ b/components/hal/esp32c2/include/hal/adc_ll.h @@ -30,6 +30,8 @@ extern "C" { #define ADC_LL_EVENT_ADC1_ONESHOT_DONE BIT(31) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE BIT(30) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1) + /*--------------------------------------------------------------- Oneshot ---------------------------------------------------------------*/ diff --git a/components/hal/esp32c3/include/hal/adc_ll.h b/components/hal/esp32c3/include/hal/adc_ll.h index 93ef061fd2..c169dd7812 100644 --- a/components/hal/esp32c3/include/hal/adc_ll.h +++ b/components/hal/esp32c3/include/hal/adc_ll.h @@ -38,7 +38,8 @@ extern "C" { #define ADC_LL_GET_HIGH_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_THRES0_HIGH_INT_ST_M : APB_SARADC_THRES1_HIGH_INT_ST_M) #define ADC_LL_GET_LOW_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_THRES0_LOW_INT_ST_M : APB_SARADC_THRES1_LOW_INT_ST_M) -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0 +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1) /*--------------------------------------------------------------- Oneshot diff --git a/components/hal/esp32c5/include/hal/adc_ll.h b/components/hal/esp32c5/include/hal/adc_ll.h index 0483dc9d8b..21e616d5c2 100644 --- a/components/hal/esp32c5/include/hal/adc_ll.h +++ b/components/hal/esp32c5/include/hal/adc_ll.h @@ -40,8 +40,9 @@ extern "C" { #define ADC_LL_GET_LOW_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_APB_SARADC_THRES0_LOW_INT_ST_M : APB_SARADC_APB_SARADC_THRES1_LOW_INT_ST_M) #define ADC_LL_ADC_FE_ON_MODEM_DOMAIN (1) +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1) -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0 /*--------------------------------------------------------------- Oneshot ---------------------------------------------------------------*/ diff --git a/components/hal/esp32c6/include/hal/adc_ll.h b/components/hal/esp32c6/include/hal/adc_ll.h index 7fe369d11f..6afdfa2c75 100644 --- a/components/hal/esp32c6/include/hal/adc_ll.h +++ b/components/hal/esp32c6/include/hal/adc_ll.h @@ -39,8 +39,9 @@ extern "C" { #define ADC_LL_GET_LOW_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_APB_SARADC_THRES0_LOW_INT_ST_M : APB_SARADC_APB_SARADC_THRES1_LOW_INT_ST_M) #define ADC_LL_ADC_FE_ON_MODEM_DOMAIN (1) +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1) -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0 /*--------------------------------------------------------------- Oneshot ---------------------------------------------------------------*/ diff --git a/components/hal/esp32c61/include/hal/adc_ll.h b/components/hal/esp32c61/include/hal/adc_ll.h index 4b1b1addc9..b69c567e66 100644 --- a/components/hal/esp32c61/include/hal/adc_ll.h +++ b/components/hal/esp32c61/include/hal/adc_ll.h @@ -40,8 +40,9 @@ extern "C" { #define ADC_LL_GET_LOW_THRES_MASK(monitor_id) ((monitor_id == 0) ? SARADC_THRES0_LOW_INT_ST_M : SARADC_THRES1_LOW_INT_ST_M) #define ADC_LL_ADC_FE_ON_MODEM_DOMAIN (1) +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1) -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0 /*--------------------------------------------------------------- Oneshot ---------------------------------------------------------------*/ diff --git a/components/hal/esp32h2/include/hal/adc_ll.h b/components/hal/esp32h2/include/hal/adc_ll.h index 3e2baaa7ab..0254ea1480 100644 --- a/components/hal/esp32h2/include/hal/adc_ll.h +++ b/components/hal/esp32h2/include/hal/adc_ll.h @@ -39,8 +39,9 @@ extern "C" { #define ADC_LL_GET_LOW_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_APB_SARADC_THRES0_LOW_INT_ST_M : APB_SARADC_APB_SARADC_THRES1_LOW_INT_ST_M) #define ADC_LL_ADC_FE_ON_MODEM_DOMAIN (1) +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1) -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0 /*--------------------------------------------------------------- Oneshot ---------------------------------------------------------------*/ diff --git a/components/hal/esp32p4/include/hal/adc_ll.h b/components/hal/esp32p4/include/hal/adc_ll.h index f3c7487c1d..a5e87fa1cd 100644 --- a/components/hal/esp32p4/include/hal/adc_ll.h +++ b/components/hal/esp32p4/include/hal/adc_ll.h @@ -35,8 +35,7 @@ extern "C" { #define LP_ADC_FORCE_XPD_SAR_PU 3 // Force power up // ESP32P4 ADC2 channel is 2-7, so we need to subtract 2 to get the correct channel -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 2 - +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (2) #define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (((ADC_UNIT) == ADC_UNIT_1) ? 0 : 1) /*--------------------------------------------------------------- diff --git a/components/hal/esp32s2/include/hal/adc_ll.h b/components/hal/esp32s2/include/hal/adc_ll.h index bde4116bde..203cf9b5d5 100644 --- a/components/hal/esp32s2/include/hal/adc_ll.h +++ b/components/hal/esp32s2/include/hal/adc_ll.h @@ -36,7 +36,8 @@ extern "C" { #define ADC_LL_GET_HIGH_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_ADC1_THRES_INT_ST_M : APB_SARADC_ADC2_THRES_INT_ST_M) #define ADC_LL_GET_LOW_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_ADC1_THRES_INT_ST_M : APB_SARADC_ADC2_THRES_INT_ST_M) -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0 +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (0) /*--------------------------------------------------------------- Oneshot diff --git a/components/hal/esp32s3/include/hal/adc_ll.h b/components/hal/esp32s3/include/hal/adc_ll.h index 2e14adad1c..064bc28c7c 100644 --- a/components/hal/esp32s3/include/hal/adc_ll.h +++ b/components/hal/esp32s3/include/hal/adc_ll.h @@ -38,7 +38,8 @@ extern "C" { #define ADC_LL_GET_HIGH_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_THRES0_HIGH_INT_ST_M : APB_SARADC_THRES1_HIGH_INT_ST_M) #define ADC_LL_GET_LOW_THRES_MASK(monitor_id) ((monitor_id == 0) ? APB_SARADC_THRES0_LOW_INT_ST_M : APB_SARADC_THRES1_LOW_INT_ST_M) -#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0 +#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0) +#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (0) /*--------------------------------------------------------------- Oneshot From 3d23fff7e25a4c2d6cb6b0907c5865d14e280582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Fri, 16 Jan 2026 11:43:26 +0100 Subject: [PATCH 16/84] fix(examples): Make sd_card examples depend on fatfs component --- examples/storage/.build-test-rules.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/storage/.build-test-rules.yml b/examples/storage/.build-test-rules.yml index 7775365d8d..b29551b8a2 100644 --- a/examples/storage/.build-test-rules.yml +++ b/examples/storage/.build-test-rules.yml @@ -70,6 +70,7 @@ examples/storage/perf_benchmark: examples/storage/sd_card/sdmmc: depends_components: + - fatfs - vfs - sdmmc - esp_driver_sdmmc @@ -82,6 +83,7 @@ examples/storage/sd_card/sdmmc: examples/storage/sd_card/sdspi: depends_components: + - fatfs - vfs - sdmmc - esp_driver_sdspi From bfb2c74b203901e99532ed5d3b4d1b663c6562bb Mon Sep 17 00:00:00 2001 From: Ferdinand Bachmann Date: Thu, 8 Jan 2026 16:35:27 +0100 Subject: [PATCH 17/84] fix(cmake): Fix "IMPORTED_LOCATION not set for imported target" errors esp-idf uses imported targets as dummy targets that are never linked. Previous CMake versions would ignore these and not error on unset IMPORTED_LOCATION if they are never actually linked. CMake 4.2 and newer errors during codemodel-v2 api queries when imported targets are missing IMPORTED_LOCATION, so set a dummy location that would error when actually linked, which fixes the error during api queries. Closes https://github.com/espressif/esp-idf/pull/18103 --- tools/cmake/build.cmake | 2 ++ tools/cmake/component.cmake | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index 6f77a72278..62973aff02 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -239,6 +239,8 @@ function(__build_init idf_path) # Create the build target, to which the ESP-IDF build properties, dependencies are attached to. # Must be global so as to be accessible from any subdirectory in custom projects. add_library(__idf_build_target STATIC IMPORTED GLOBAL) + # Set the IMPORTED_LOCATION property to avoid errors on IDE codemodel queries with CMake >=4.2 + set_property(TARGET __idf_build_target PROPERTY IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/dummy.a") # Set the Python path (which may be passed in via -DPYTHON=) and store in a build property set_default(PYTHON "python") diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 37721f5555..0fdb105ee5 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -167,6 +167,8 @@ function(__component_add component_dir prefix component_source) if(NOT component_target IN_LIST component_targets) if(NOT TARGET ${component_target}) add_library(${component_target} STATIC IMPORTED) + # Set the IMPORTED_LOCATION property to avoid errors on IDE codemodel queries with CMake >=4.2 + set_property(TARGET ${component_target} PROPERTY IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/dummy.a") endif() idf_build_set_property(__COMPONENT_TARGETS ${component_target} APPEND) else() From 77aca8fddeb50700ab48174c44c2c61b9a27aef8 Mon Sep 17 00:00:00 2001 From: "yanzihan@espressif.com" Date: Mon, 17 Nov 2025 16:19:33 +0800 Subject: [PATCH 18/84] feat(esp_hw_support): use pvt to auto control digital ldo and rtc ldo for esp32p4 eco5 --- components/esp_hw_support/port/esp32p4/include/soc/rtc.h | 5 +++++ components/esp_hw_support/port/esp32p4/pmu_param.c | 4 ++-- components/esp_hw_support/port/esp32p4/pmu_pvt.c | 8 ++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/components/esp_hw_support/port/esp32p4/include/soc/rtc.h b/components/esp_hw_support/port/esp32p4/include/soc/rtc.h index d1c59a0884..c48fb35065 100644 --- a/components/esp_hw_support/port/esp32p4/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32p4/include/soc/rtc.h @@ -109,8 +109,13 @@ set sleep_init default param #define PVT_TARGET 0x7d00 #define PVT_CLK_DIV 1 #define PVT_EDG_MODE 1 +#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3 #define PVT_DELAY_NUM_HIGH 164 #define PVT_DELAY_NUM_LOW 157 +#else +#define PVT_DELAY_NUM_HIGH 160 +#define PVT_DELAY_NUM_LOW 153 +#endif /** * @brief Initialize PVT related parameters diff --git a/components/esp_hw_support/port/esp32p4/pmu_param.c b/components/esp_hw_support/port/esp32p4/pmu_param.c index 295a8fe492..e0968a1d1a 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_param.c +++ b/components/esp_hw_support/port/esp32p4/pmu_param.c @@ -336,7 +336,7 @@ uint32_t get_act_hp_dbias(void) uint32_t hp_cali_dbias = HP_CALI_ACTIVE_DBIAS_DEFAULT; uint32_t blk_version = efuse_hal_blk_version(); uint32_t hp_cali_dbias_efuse = 0; - if (blk_version >= 2 && blk_version < 100) { + if (blk_version >= 2 && blk_version != 100) { hp_cali_dbias_efuse = efuse_ll_get_active_hp_dbias(); } if (hp_cali_dbias_efuse > 0) { @@ -357,7 +357,7 @@ uint32_t get_act_lp_dbias(void) uint32_t lp_cali_dbias = LP_CALI_ACTIVE_DBIAS_DEFAULT; uint32_t blk_version = efuse_hal_blk_version(); uint32_t lp_cali_dbias_efuse = 0; - if (blk_version >= 2 && blk_version < 100) { + if (blk_version >= 2 && blk_version != 100) { lp_cali_dbias_efuse = efuse_ll_get_active_lp_dbias(); } if (lp_cali_dbias_efuse > 0) { diff --git a/components/esp_hw_support/port/esp32p4/pmu_pvt.c b/components/esp_hw_support/port/esp32p4/pmu_pvt.c index 1eda49d0cc..132ec84680 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_pvt.c +++ b/components/esp_hw_support/port/esp32p4/pmu_pvt.c @@ -33,7 +33,7 @@ static uint8_t get_lp_hp_gap(void) int8_t lp_hp_gap = 0; uint32_t blk_version = efuse_hal_blk_version(); uint8_t lp_hp_gap_efuse = 0; - if (blk_version >= 2 && blk_version < 100) { + if (blk_version >= 2 && blk_version != 100) { lp_hp_gap_efuse = efuse_ll_get_dbias_vol_gap(); bool gap_flag = lp_hp_gap_efuse >> 4; uint8_t gap_abs_value = lp_hp_gap_efuse & 0xf; @@ -77,7 +77,7 @@ static uint32_t pvt_get_lp_dbias(void) void pvt_auto_dbias_init(void) { uint32_t blk_version = efuse_hal_blk_version(); - if (blk_version >= 2 && blk_version < 100) { + if (blk_version >= 2 && blk_version != 100) { SET_PERI_REG_MASK(HP_SYS_CLKRST_REF_CLK_CTRL2_REG, HP_SYS_CLKRST_REG_REF_160M_CLK_EN); SET_PERI_REG_MASK(HP_SYS_CLKRST_SOC_CLK_CTRL1_REG, HP_SYS_CLKRST_REG_PVT_SYS_CLK_EN); /*config for dbias func*/ @@ -120,7 +120,7 @@ void pvt_auto_dbias_init(void) void pvt_func_enable(bool enable) { uint32_t blk_version = efuse_hal_blk_version(); - if (blk_version >= 2 && blk_version < 100){ + if (blk_version >= 2 && blk_version != 100){ if (enable) { SET_PERI_REG_MASK(HP_SYS_CLKRST_REF_CLK_CTRL2_REG, HP_SYS_CLKRST_REG_REF_160M_CLK_EN); @@ -133,7 +133,7 @@ void pvt_func_enable(bool enable) SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // Start calibration @HP_CALI_DBIAS_DEFAULT SET_PERI_REG_MASK(PVT_CLK_CFG_REG, PVT_MONITOR_CLK_PVT_EN); // Once enable cannot be closed SET_PERI_REG_MASK(PVT_COMB_PD_SITE3_UNIT0_VT1_CONF1_REG, PVT_MONITOR_EN_VT1_PD_SITE3_UNIT0); // Enable pvt clk - esp_rom_delay_us(1000); + esp_rom_delay_us(10); CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pvt CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // Must clear @HP_CALI_DBIAS_DEFAULT SET_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); // Enable auto dbias From 42ccf5d6262e0ea61cd571ff5b0058e96ce281ce Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 9 Jan 2026 17:21:48 +0800 Subject: [PATCH 19/84] feat(esp_hw_support): esp32p4 rev3.1 no need MSPI workaround --- components/esp_hw_support/sleep_modes.c | 2 +- components/soc/esp32p4/system_retention_periph.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 163d7cabd5..e153188edf 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -960,7 +960,7 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint #if SOC_PM_RETENTION_SW_TRIGGER_REGDMA sleep_retention_do_system_retention(false); #endif -#if CONFIG_IDF_TARGET_ESP32P4 && (CONFIG_ESP_REV_MIN_FULL == 300) +#if CONFIG_P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND sleep_flash_p4_rev3_workaround(); sleep_retention_do_extra_retention(false); #endif diff --git a/components/soc/esp32p4/system_retention_periph.c b/components/soc/esp32p4/system_retention_periph.c index 33bff9c55a..3df795ebf2 100644 --- a/components/soc/esp32p4/system_retention_periph.c +++ b/components/soc/esp32p4/system_retention_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -134,7 +134,7 @@ _Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "In #define N_REGS_SPI0_C_MEM_1() (((SPI_MEM_C_SMEM_AC_REG - SPI_MEM_C_FMEM__PMS0_ATTR_REG) / 4) + 1) #define N_REGS_SPI0_C_MEM_2() (1) #define N_REGS_SPI0_C_MEM_3() (((SPI_MEM_C_DPA_CTRL_REG - SPI_MEM_C_MMU_POWER_CTRL_REG) / 4) + 1) -#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 +#if (CONFIG_ESP_REV_MIN_FULL == 300) // Workaround for rev3.0 MSPI Power UP issue only. #define FLASH_SPIMEM_RETENTION_ENTRY (ENTRY(0) | REGDMA_SW_TRIGGER_ENTRY) #else #define FLASH_SPIMEM_RETENTION_ENTRY ENTRY(0) @@ -179,8 +179,8 @@ const regdma_entries_config_t psram_spimem_regs_retention[SPIMEM_PSRAM_RETENTION [9] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x11), SPI1_MEM_S_INT_ENA_REG, SPI1_MEM_S_INT_ENA_REG, N_REGS_SPI1_S_MEM_2(), 0, 0), .owner = ENTRY(0) }, [10] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x12), SPI1_MEM_S_TIMING_CALI_REG, SPI1_MEM_S_TIMING_CALI_REG, N_REGS_SPI1_S_MEM_3(), 0, 0), .owner = ENTRY(0) }, [11] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SPIMEM_LINK(0x13), SPI1_MEM_S_CLOCK_GATE_REG, SPI1_MEM_S_CLOCK_GATE_REG, N_REGS_SPI1_S_MEM_4(), 0, 0), .owner = ENTRY(0) }, - [12] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x14), HP_SYS_CLKRST_PERI_CLK_CTRL00_REG, 0, HP_SYS_CLKRST_REG_PSRAM_CORE_CLK_EN_M, 0, 1), .owner = ENTRY(0) }, // Enable PSRAM mspi core clock on backup - [13] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x15), HP_SYS_CLKRST_SOC_CLK_CTRL0_REG, 0, HP_SYS_CLKRST_REG_PSRAM_SYS_CLK_EN_M, 0, 1), .owner = ENTRY(0) }, // Enable PSRAM mspi core clock on backup + [12] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x14), HP_SYS_CLKRST_PERI_CLK_CTRL00_REG, 0, HP_SYS_CLKRST_REG_PSRAM_CORE_CLK_EN_M, 0, 1), .owner = ENTRY(0) }, // Disable PSRAM mspi core clock on backup + [13] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_SPIMEM_LINK(0x15), HP_SYS_CLKRST_SOC_CLK_CTRL0_REG, 0, HP_SYS_CLKRST_REG_PSRAM_SYS_CLK_EN_M, 0, 1), .owner = ENTRY(0) }, // Disable PSRAM mspi core clock on backup }; _Static_assert(ARRAY_SIZE(psram_spimem_regs_retention) == SPIMEM_PSRAM_RETENTION_LINK_LEN, "Inconsistent PSRAM SPI Mem retention link length definitions"); @@ -221,6 +221,6 @@ _Static_assert(ARRAY_SIZE(pau_regs_retention) == HP_SYSTEM_RETENTION_LINK_LEN, " /* PVT Registers Context */ #define N_REGS_PVT (((PVT_COMB_PD_SITE3_UNIT0_VT1_CONF2_REG - DR_REG_PVT_MONITOR_BASE) / 4) + 1) const regdma_entries_config_t pvt_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PVT_LINK(0x00), DR_REG_PVT_MONITOR_BASE, DR_REG_PVT_MONITOR_BASE, N_REGS_PVT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PVT_LINK(0x00), DR_REG_PVT_MONITOR_BASE, DR_REG_PVT_MONITOR_BASE, N_REGS_PVT, 0, 0), .owner = ENTRY(0)}, }; _Static_assert(ARRAY_SIZE(pvt_regs_retention) == PVT_RETENTION_LINK_LEN, "Inconsistent PVT retention link length definitions"); From b21e7bda2304eb1434d7a179ba59c26b7b7022ae Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Fri, 16 Jan 2026 11:28:26 +0800 Subject: [PATCH 20/84] feat(vbat): update vbat charger threshold on p4 revision 3 --- .../power_supply/port/esp32p4/Kconfig.power | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/components/esp_hw_support/power_supply/port/esp32p4/Kconfig.power b/components/esp_hw_support/power_supply/port/esp32p4/Kconfig.power index acdd8b8648..a6c5e2b4e5 100644 --- a/components/esp_hw_support/power_supply/port/esp32p4/Kconfig.power +++ b/components/esp_hw_support/power_supply/port/esp32p4/Kconfig.power @@ -89,9 +89,9 @@ menu "Power Supplier" Use this option carefully to avoid damage to non-rechargeable batteries. choice ESP_VBAT_DET_LVL_LOW_SEL - prompt "VBAT start charging voltage level" + prompt "VBAT start charging voltage level (P4 revision < v3.0)" default ESP_VBAT_DET_LVL_LOW_SEL_6 - depends on ESP_VBAT_USE_RECHARGEABLE_BATTERY + depends on ESP_VBAT_USE_RECHARGEABLE_BATTERY && ESP32P4_SELECTS_REV_LESS_V3 help The brownout detector will start charging when the supply voltage drops below the selected threshold. This ensures that the power supply is maintained at a stable level. @@ -104,10 +104,26 @@ menu "Power Supplier" bool "2.42V" endchoice + choice ESP_VBAT_DET_LVL_LOW_SEL_V3 + prompt "VBAT start charging voltage level (P4 revision >= v3.0)" + default ESP_VBAT_DET_LVL_LOW_SEL_6_V3 + depends on ESP_VBAT_USE_RECHARGEABLE_BATTERY && !ESP32P4_SELECTS_REV_LESS_V3 + help + The brownout detector will start charging when the supply voltage drops below the selected threshold. + This ensures that the power supply is maintained at a stable level. + + config ESP_VBAT_DET_LVL_LOW_SEL_7_V3 + bool "2.84V" + config ESP_VBAT_DET_LVL_LOW_SEL_6_V3 + bool "2.74V" + config ESP_VBAT_DET_LVL_LOW_SEL_5_V3 + bool "2.64V" + endchoice + choice ESP_VBAT_DET_LVL_HIGH_SEL - prompt "VBAT stop charging voltage level" + prompt "VBAT stop charging voltage level (P4 revision < v3.0)" default ESP_VBAT_DET_LVL_HIGH_SEL_7 - depends on ESP_VBAT_USE_RECHARGEABLE_BATTERY + depends on ESP_VBAT_USE_RECHARGEABLE_BATTERY && ESP32P4_SELECTS_REV_LESS_V3 help The brownout detector will stop charging when the supply voltage arrives the selected threshold. @@ -119,6 +135,21 @@ menu "Power Supplier" bool "2.42V" endchoice + choice ESP_VBAT_DET_LVL_HIGH_SEL_V3 + prompt "VBAT stop charging voltage level (P4 revision >= v3.0)" + default ESP_VBAT_DET_LVL_HIGH_SEL_7_V3 + depends on ESP_VBAT_USE_RECHARGEABLE_BATTERY && !ESP32P4_SELECTS_REV_LESS_V3 + help + The brownout detector will stop charging when the supply voltage arrives the selected threshold. + + config ESP_VBAT_DET_LVL_HIGH_SEL_7_V3 + bool "2.84V" + config ESP_VBAT_DET_LVL_HIGH_SEL_6_V3 + bool "2.74V" + config ESP_VBAT_DET_LVL_HIGH_SEL_5_V3 + bool "2.64V" + endchoice + choice ESP_VBAT_BROWNOUT_DET_LVL_SEL prompt "VBAT brownout voltage level" default ESP_VBAT_BROWNOUT_DET_LVL_SEL_5 @@ -144,16 +175,16 @@ menu "Power Supplier" config ESP_VBAT_DET_LVL_LOW int depends on ESP_VBAT_USE_RECHARGEABLE_BATTERY - default 5 if ESP_VBAT_DET_LVL_LOW_SEL_5 - default 6 if ESP_VBAT_DET_LVL_LOW_SEL_6 - default 7 if ESP_VBAT_DET_LVL_LOW_SEL_7 + default 5 if ESP_VBAT_DET_LVL_LOW_SEL_5 || ESP_VBAT_DET_LVL_LOW_SEL_5_V3 + default 6 if ESP_VBAT_DET_LVL_LOW_SEL_6 || ESP_VBAT_DET_LVL_LOW_SEL_6_V3 + default 7 if ESP_VBAT_DET_LVL_LOW_SEL_7 || ESP_VBAT_DET_LVL_LOW_SEL_7_V3 config ESP_VBAT_DET_LVL_HIGH int depends on ESP_VBAT_USE_RECHARGEABLE_BATTERY - default 5 if ESP_VBAT_DET_LVL_HIGH_SEL_5 - default 6 if ESP_VBAT_DET_LVL_HIGH_SEL_6 - default 7 if ESP_VBAT_DET_LVL_HIGH_SEL_7 + default 5 if ESP_VBAT_DET_LVL_HIGH_SEL_5 || ESP_VBAT_DET_LVL_HIGH_SEL_5_V3 + default 6 if ESP_VBAT_DET_LVL_HIGH_SEL_6 || ESP_VBAT_DET_LVL_HIGH_SEL_6_V3 + default 7 if ESP_VBAT_DET_LVL_HIGH_SEL_7 || ESP_VBAT_DET_LVL_HIGH_SEL_7_V3 config ESP_VBAT_BROWNOUT_DET_LVL int From 51adb83f3930f2109779d2160c46c6f2eb1576bf Mon Sep 17 00:00:00 2001 From: "yanzihan@espressif.com" Date: Mon, 19 Jan 2026 14:25:25 +0800 Subject: [PATCH 21/84] feat(esp_hw_support): use pvt to auto control digital ldo and rtc ldo for esp32c5 v5.5 --- .../port/esp32c5/CMakeLists.txt | 4 + .../port/esp32c5/include/soc/rtc.h | 49 +++++- .../esp_hw_support/port/esp32c5/pmu_init.c | 22 ++- .../esp_hw_support/port/esp32c5/pmu_pvt.c | 161 ++++++++++++++++++ .../esp_hw_support/port/esp32c5/pmu_sleep.c | 4 + .../esp_hw_support/port/esp32c5/rtc_clk.c | 24 ++- .../port/esp32c5/rtc_clk_init.c | 2 + components/esp_hw_support/sleep_modes.c | 4 +- .../esp_hw_support/sleep_system_peripheral.c | 2 +- components/esp_system/port/soc/esp32c5/clk.c | 2 + .../hal/esp32c5/include/hal/clk_gate_ll.h | 2 +- .../esp32c5/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32c5/include/soc/soc_caps.h | 1 + .../include/soc/system_periph_retention.h | 12 +- components/soc/esp32c5/register/soc/pvt_reg.h | 32 ++-- .../soc/esp32c5/register/soc/pvt_struct.h | 38 ++++- .../soc/esp32c5/register/soc/reg_base.h | 1 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 8 + components/soc/esp32p4/include/soc/soc_caps.h | 2 + 19 files changed, 346 insertions(+), 28 deletions(-) create mode 100644 components/esp_hw_support/port/esp32c5/pmu_pvt.c diff --git a/components/esp_hw_support/port/esp32c5/CMakeLists.txt b/components/esp_hw_support/port/esp32c5/CMakeLists.txt index e1c7e438aa..b27e92b99c 100644 --- a/components/esp_hw_support/port/esp32c5/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32c5/CMakeLists.txt @@ -14,6 +14,10 @@ if(NOT non_os_build) list(APPEND srcs "sar_periph_ctrl.c") endif() +if(NOT BOOTLOADER_BUILD AND CONFIG_ESP_ENABLE_PVT) + list(APPEND srcs "pmu_pvt.c") +endif() + add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") target_sources(${COMPONENT_LIB} PRIVATE "${srcs}") diff --git a/components/esp_hw_support/port/esp32c5/include/soc/rtc.h b/components/esp_hw_support/port/esp32c5/include/soc/rtc.h index 76109b9980..dd755ff9a6 100644 --- a/components/esp_hw_support/port/esp32c5/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32c5/include/soc/rtc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -99,6 +99,53 @@ storing in efuse (based on ATE 5k ECO3 chips) #define V_RTC_MID_MUL10000 10800 #define V_DIG_MID_MUL10000 10860 +#if CONFIG_ESP_ENABLE_PVT +/* +set pvt default param +*/ +#define PVT_CHANNEL0_SEL 33 +#define PVT_CHANNEL1_SEL 37 +#define PVT_CHANNEL0_CFG 0x13e80 +#define PVT_CHANNEL1_CFG 0x13e80 +#define PVT_CHANNEL2_CFG 0x10000 +#define PVT_CMD0 0x24 +#define PVT_CMD1 0x5 +#define PVT_CMD2 0x427 +#define PVT_TARGET 0xffff +#define PVT_CLK_DIV 1 +#define PVT_DELAY_NUM_HIGH 150 +#define PVT_DELAY_NUM_LOW 143 +#define PVT_PUMP_CHANNEL_CODE 1 +#define PVT_PUMP_BITMAP 22 +#define PVT_PUMP_DRV 0 +#define PVT_DELAY_NUM_PUMP 139 + +/** + * @brief Initialize PVT related parameters + */ +void pvt_auto_dbias_init(void); + +/** + * @brief Enable or disable PVT functions + * + * @param enable true to enable, false to disable + */ +void pvt_func_enable(bool enable); + +/** + * @brief Initialize charge pump related parameters + */ +void charge_pump_init(void); + +/** + * @brief Enable or disable charge pump functions + * + * @param enable true to enable, false to disable + */ +void charge_pump_enable(bool enable); + +#endif //#if CONFIG_ESP_ENABLE_PVT + /** * @brief CPU clock configuration structure */ diff --git a/components/esp_hw_support/port/esp32c5/pmu_init.c b/components/esp_hw_support/port/esp32c5/pmu_init.c index ac3dd16c40..19f1e1b3aa 100644 --- a/components/esp_hw_support/port/esp32c5/pmu_init.c +++ b/components/esp_hw_support/port/esp32c5/pmu_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,10 @@ #include "regi2c_ctrl.h" #include "esp_private/ocode_init.h" #include "esp_rom_sys.h" +#include "esp_hw_log.h" +#include "soc/rtc.h" +#include "hal/efuse_ll.h" +#include "hal/efuse_hal.h" static __attribute__((unused)) const char *TAG = "pmu_init"; @@ -220,4 +224,20 @@ void pmu_init(void) esp_ocode_calib_init(); } #endif + +#if CONFIG_ESP_ENABLE_PVT + /*setup pvt function*/ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + pvt_auto_dbias_init(); + charge_pump_init(); + + pvt_func_enable(true); + charge_pump_enable(true); + esp_rom_delay_us(1000); + } + else { + ESP_HW_LOGW(TAG, "blk_version is less than 2, pvt function not supported in efuse."); + } +#endif } diff --git a/components/esp_hw_support/port/esp32c5/pmu_pvt.c b/components/esp_hw_support/port/esp32c5/pmu_pvt.c new file mode 100644 index 0000000000..f4fa36face --- /dev/null +++ b/components/esp_hw_support/port/esp32c5/pmu_pvt.c @@ -0,0 +1,161 @@ +/* + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "soc/soc.h" +#include "soc/pmu_struct.h" +#include "soc/pvt_reg.h" +#include "soc/pcr_reg.h" +#include "soc/pmu_reg.h" +#include "hal/pmu_hal.h" +#include "pmu_param.h" +#include "esp_rom_sys.h" +#include "esp_private/esp_pmu.h" +#include "soc/regi2c_dig_reg.h" +#include "regi2c_ctrl.h" +#include "soc/rtc.h" +#include "hal/efuse_ll.h" +#include "hal/efuse_hal.h" +#include "esp_hw_log.h" + +static __attribute__((unused)) const char *TAG = "pmu_pvt"; + +#if CONFIG_ESP_ENABLE_PVT + +static uint8_t get_lp_hp_gap(void) +{ + int8_t lp_hp_gap = 0; + uint32_t blk_version = efuse_hal_blk_version(); + uint8_t lp_hp_gap_efuse = 0; + if (blk_version >= 2) { + lp_hp_gap_efuse = efuse_ll_get_dbias_vol_gap(); + bool gap_flag = lp_hp_gap_efuse >> 4; + uint8_t gap_abs_value = lp_hp_gap_efuse & 0xf; + if (gap_flag) { + lp_hp_gap = -1 * gap_abs_value; + } else { + lp_hp_gap = gap_abs_value; + } + lp_hp_gap = lp_hp_gap - 8; + assert((lp_hp_gap >= -15) && (lp_hp_gap <= 7)); + if (lp_hp_gap < 0 ) { + lp_hp_gap = 16 - lp_hp_gap; + } + } + return lp_hp_gap; +} + +static void set_pvt_hp_lp_gap(uint8_t value) +{ + bool flag = value >> 4; + uint8_t abs_value = value & 0xf; + + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_FLAG, flag, PVT_DBIAS_CMD0_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD0_OFFSET_VALUE_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_FLAG, flag, PVT_DBIAS_CMD1_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD1_OFFSET_VALUE_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_FLAG, flag, PVT_DBIAS_CMD2_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD2_OFFSET_VALUE_S); +} + +FORCE_INLINE_ATTR uint32_t get_pvt_hp_dbias(void) +{ + return GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL_V, PMU_HP_DBIAS_VOL_S); +} + +FORCE_INLINE_ATTR uint32_t get_pvt_lp_dbias(void) +{ + return GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_LP_DBIAS_VOL_V, PMU_LP_DBIAS_VOL_S); +} + +void pvt_auto_dbias_init(void) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + SET_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN); + SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN); + /*config for dbias func*/ + CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); + esp_rom_delay_us(1); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL0_SEL, PVT_CHANNEL0_SEL, PVT_DBIAS_CHANNEL0_SEL_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL1_SEL, PVT_CHANNEL1_SEL, PVT_DBIAS_CHANNEL1_SEL_S); // Select monitor cell ,which used to monitor PVT situation + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL0_SEL_REG, PVT_DBIAS_CHANNEL0_CFG, PVT_CHANNEL0_CFG, PVT_DBIAS_CHANNEL0_CFG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL1_SEL_REG, PVT_DBIAS_CHANNEL1_CFG, PVT_CHANNEL1_CFG, PVT_DBIAS_CHANNEL1_CFG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL2_SEL_REG, PVT_DBIAS_CHANNEL2_CFG, PVT_CHANNEL2_CFG, PVT_DBIAS_CHANNEL2_CFG_S); // Configure filter threshold for avoiding auto-dbias overly sensitive regulation + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_PVT, PVT_CMD0, PVT_DBIAS_CMD0_PVT_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_PVT, PVT_CMD1, PVT_DBIAS_CMD1_PVT_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_PVT, PVT_CMD2, PVT_DBIAS_CMD2_PVT_S); // Configure auto-dbias adjust property, such as adjusting step + SET_PERI_REG_BITS(PVT_DBIAS_TIMER_REG, PVT_TIMER_TARGET, PVT_TARGET, PVT_TIMER_TARGET_S); // Configure auto-dbias voltage regulation cycle + + SET_PERI_REG_BITS(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_DIV_NUM, PVT_CLK_DIV, PCR_PVT_MONITOR_FUNC_CLK_DIV_NUM_S);//pvt function clock divider number + + /*config for pvt cell: unit0; site2; vt1*/ + SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_SEL); // choose pvt clk + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT0_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT0, PVT_DELAY_NUM_HIGH, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT0_S); // The threshold for determining whether the voltage is too high + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT1_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT1, PVT_DELAY_NUM_LOW, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT1_S); // The threshold for determining whether the voltage is too low + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT2_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT2, PVT_DELAY_NUM_PUMP, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT2_S); // The threshold for chargepump + + /*config lp offset for pvt func*/ + uint8_t lp_hp_gap = get_lp_hp_gap(); + set_pvt_hp_lp_gap(lp_hp_gap); + } +} + +void IRAM_ATTR pvt_func_enable(bool enable) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + if (enable) { + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // start calibration @HP_CALI_DBIAS_DEFAULT + SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN); + SET_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN); + SET_PERI_REG_MASK(PVT_CLK_CFG_REG, PVT_MONITOR_CLK_PVT_EN); // once enable cannot be closed + SET_PERI_REG_MASK(PVT_COMB_PD_SITE2_UNIT0_VT1_CONF1_REG, PVT_MONITOR_EN_VT1_PD_SITE2_UNIT0); // enable pvt clk + esp_rom_delay_us(10); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // hand over control of dbias to pvt + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // must clear @HP_CALI_DBIAS_DEFAULT + SET_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); // enable auto dbias + } else { + uint32_t pvt_hp_dbias = get_pvt_hp_dbias(); + uint32_t pvt_lp_dbias = get_pvt_lp_dbias(); // update pvt_cali_dbias + SET_PERI_REG_BITS(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, pvt_hp_dbias, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS_S); + SET_PERI_REG_BITS(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, pvt_lp_dbias, PMU_HP_SLEEP_LP_REGULATOR_DBIAS_S); + CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); //disable auto dbias + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // hand over control of dbias to pmu + CLEAR_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN); + CLEAR_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN); + } + } +} + +void charge_pump_init(void) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + /*config for charge pump*/ + SET_PERI_REG_BITS(PVT_PMUP_CHANNEL_CFG_REG, PVT_PUMP_CHANNEL_CODE0, PVT_PUMP_CHANNEL_CODE, PVT_PUMP_CHANNEL_CODE0_S); //Set channel code + WRITE_PERI_REG(PVT_PMUP_BITMAP_LOW0_REG, (1 << PVT_PUMP_BITMAP)); // Select monitor cell for charge pump + SET_PERI_REG_BITS(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_DRV0, PVT_PUMP_DRV, PVT_PUMP_DRV0_S); //Configure the charging intensity + } +} + +void IRAM_ATTR charge_pump_enable(bool enable) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + if (enable) { + SET_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); // enable charge pump + } else { + CLEAR_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); //disable charge pump + } + } +} + +#endif diff --git a/components/esp_hw_support/port/esp32c5/pmu_sleep.c b/components/esp_hw_support/port/esp32c5/pmu_sleep.c index 74b9a2590c..40a9be9ab3 100644 --- a/components/esp_hw_support/port/esp32c5/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c5/pmu_sleep.c @@ -324,6 +324,10 @@ static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_con pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.xpd); pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dbias); pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.drv_b); +#if CONFIG_ESP_ENABLE_PVT + uint32_t pvt_hp_dbias = GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL_V, PMU_HP_DBIAS_VOL_S); + pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(MODEM), pvt_hp_dbias); +#endif pmu_ll_lp_set_dbg_atten (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.dbg_atten); pmu_ll_lp_set_current_power_off (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.pd_cur); diff --git a/components/esp_hw_support/port/esp32c5/rtc_clk.c b/components/esp_hw_support/port/esp32c5/rtc_clk.c index 83bb547958..f602a6856c 100644 --- a/components/esp_hw_support/port/esp32c5/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c5/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,6 +24,8 @@ #include "hal/efuse_hal.h" #include "soc/chip_revision.h" #include "esp_private/regi2c_ctrl.h" +#include "esp_attr.h" +#include "esp_private/esp_pmu.h" static const char *TAG = "rtc_clk"; @@ -178,6 +180,10 @@ static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL); clk_ll_bus_update(); esp_rom_set_cpu_ticks_per_us(cpu_freq); +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + charge_pump_enable(false); + pvt_func_enable(false); +#endif } static void rtc_clk_cpu_freq_to_8m(void) @@ -187,6 +193,10 @@ static void rtc_clk_cpu_freq_to_8m(void) clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST); clk_ll_bus_update(); esp_rom_set_cpu_ticks_per_us(20); +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + charge_pump_enable(false); + pvt_func_enable(false); +#endif } /** @@ -196,6 +206,12 @@ static void rtc_clk_cpu_freq_to_8m(void) */ static void rtc_clk_cpu_freq_to_pll_240_mhz(int cpu_freq_mhz) { +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + pvt_auto_dbias_init(); + charge_pump_init(); + pvt_func_enable(true); + charge_pump_enable(true); +#endif // f_hp_root = 240MHz uint32_t cpu_divider = CLK_LL_PLL_240M_FREQ_MHZ / cpu_freq_mhz; clk_ll_cpu_set_divider(cpu_divider); @@ -216,6 +232,12 @@ static void rtc_clk_cpu_freq_to_pll_240_mhz(int cpu_freq_mhz) */ static void rtc_clk_cpu_freq_to_pll_160_mhz(int cpu_freq_mhz) { +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + pvt_auto_dbias_init(); + charge_pump_init(); + pvt_func_enable(true); + charge_pump_enable(true); +#endif // f_hp_root = 160MHz uint32_t cpu_divider = CLK_LL_PLL_160M_FREQ_MHZ / cpu_freq_mhz; clk_ll_cpu_set_divider(cpu_divider); diff --git a/components/esp_hw_support/port/esp32c5/rtc_clk_init.c b/components/esp_hw_support/port/esp32c5/rtc_clk_init.c index 18cb9a2830..bf8131cb82 100644 --- a/components/esp_hw_support/port/esp32c5/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32c5/rtc_clk_init.c @@ -83,6 +83,8 @@ void rtc_clk_init(rtc_clk_config_t cfg) uint32_t hp_cali_dbias = get_act_hp_dbias(); uint32_t lp_cali_dbias = get_act_lp_dbias(); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu + SET_PERI_REG_BITS(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, hp_cali_dbias, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS_S); SET_PERI_REG_BITS(PMU_HP_MODEM_HP_REGULATOR0_REG, PMU_HP_MODEM_HP_REGULATOR_DBIAS, hp_cali_dbias, PMU_HP_MODEM_HP_REGULATOR_DBIAS_S); SET_PERI_REG_BITS(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, lp_cali_dbias, PMU_HP_SLEEP_LP_REGULATOR_DBIAS_S); diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 163d7cabd5..913ad231da 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -755,7 +755,7 @@ static SLEEP_FN_ATTR void misc_modules_sleep_prepare(uint32_t sleep_flags, bool regi2c_tsens_reg_read(); #endif } -#if CONFIG_ESP_ENABLE_PVT +#if CONFIG_ESP_ENABLE_PVT && SOC_PVT_EN_WITH_SLEEP pvt_func_enable(false); #endif @@ -770,7 +770,7 @@ static SLEEP_FN_ATTR void misc_modules_sleep_prepare(uint32_t sleep_flags, bool */ static SLEEP_FN_ATTR void misc_modules_wake_prepare(uint32_t sleep_flags) { -#if CONFIG_ESP_ENABLE_PVT +#if CONFIG_ESP_ENABLE_PVT && SOC_PVT_EN_WITH_SLEEP pvt_func_enable(true); #endif diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index bd8297654f..286659d00c 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -164,7 +164,7 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_retention_init(void *a err = sleep_pau_retention_init(); if(err) goto error; #endif -#if CONFIG_ESP_ENABLE_PVT +#if CONFIG_ESP_ENABLE_PVT && SOC_PVT_RETENTION_BY_REGDMA err = sleep_pvt_retention_init(); if(err) goto error; #endif diff --git a/components/esp_system/port/soc/esp32c5/clk.c b/components/esp_system/port/soc/esp32c5/clk.c index 871b7a2ab2..c151b3d114 100644 --- a/components/esp_system/port/soc/esp32c5/clk.c +++ b/components/esp_system/port/soc/esp32c5/clk.c @@ -336,8 +336,10 @@ __attribute__((weak)) void esp_perip_clk_init(void) REG_CLR_BIT(PCR_TRACE_CONF_REG, PCR_TRACE_CLK_EN); REG_CLR_BIT(PCR_TCM_MEM_MONITOR_CONF_REG, PCR_TCM_MEM_MONITOR_CLK_EN); REG_CLR_BIT(PCR_PSRAM_MEM_MONITOR_CONF_REG, PCR_PSRAM_MEM_MONITOR_CLK_EN); +#if !CONFIG_ESP_ENABLE_PVT REG_CLR_BIT(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN); REG_CLR_BIT(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN); +#endif WRITE_PERI_REG(PCR_CTRL_CLK_OUT_EN_REG, 0); #if !CONFIG_USJ_ENABLE_USB_SERIAL_JTAG && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED diff --git a/components/hal/esp32c5/include/hal/clk_gate_ll.h b/components/hal/esp32c5/include/hal/clk_gate_ll.h index 4a1d7d2ac6..8ce11a1ab2 100644 --- a/components/hal/esp32c5/include/hal/clk_gate_ll.h +++ b/components/hal/esp32c5/include/hal/clk_gate_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 47d23baf0b..5dd71a207d 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -187,6 +187,10 @@ config SOC_PMU_SUPPORTED bool default y +config SOC_PMU_PVT_SUPPORTED + bool + default y + config SOC_PAU_SUPPORTED bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 581831d1ce..e8d8d312e3 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -63,6 +63,7 @@ #define SOC_BOD_SUPPORTED 1 #define SOC_APM_SUPPORTED 1 /*!< Support for APM peripheral */ #define SOC_PMU_SUPPORTED 1 +#define SOC_PMU_PVT_SUPPORTED 1 #define SOC_PAU_SUPPORTED 1 #define SOC_LP_TIMER_SUPPORTED 1 #define SOC_LP_AON_SUPPORTED 1 diff --git a/components/soc/esp32c5/include/soc/system_periph_retention.h b/components/soc/esp32c5/include/soc/system_periph_retention.h index dac1f0414d..febebb6594 100644 --- a/components/soc/esp32c5/include/soc/system_periph_retention.h +++ b/components/soc/esp32c5/include/soc/system_periph_retention.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -77,6 +77,16 @@ extern const regdma_entries_config_t flash_spimem_regs_retention[SPIMEM_RETENTIO #define SYSTIMER_RETENTION_LINK_LEN 19 extern const regdma_entries_config_t systimer_regs_retention[SYSTIMER_RETENTION_LINK_LEN]; +/** + * @brief Provide access to pvt configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define PVT_RETENTION_LINK_LEN 1 +extern const regdma_entries_config_t pvt_regs_retention[PVT_RETENTION_LINK_LEN]; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c5/register/soc/pvt_reg.h b/components/soc/esp32c5/register/soc/pvt_reg.h index 9baa78cbe3..6bd7e76a44 100644 --- a/components/soc/esp32c5/register/soc/pvt_reg.h +++ b/components/soc/esp32c5/register/soc/pvt_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -363,10 +363,12 @@ extern "C" { /** PVT_DBIAS_CMD0 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD0 0x0001FFFFU -#define PVT_DBIAS_CMD0_M (PVT_DBIAS_CMD0_V << PVT_DBIAS_CMD0_S) -#define PVT_DBIAS_CMD0_V 0x0001FFFFU -#define PVT_DBIAS_CMD0_S 0 +#define PVT_DBIAS_CMD0_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD0_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD0_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD0_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD0_PVT 0x7FF +#define PVT_DBIAS_CMD0_PVT_S 0 /** PVT_DBIAS_CMD1_REG register * needs desc @@ -375,10 +377,12 @@ extern "C" { /** PVT_DBIAS_CMD1 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD1 0x0001FFFFU -#define PVT_DBIAS_CMD1_M (PVT_DBIAS_CMD1_V << PVT_DBIAS_CMD1_S) -#define PVT_DBIAS_CMD1_V 0x0001FFFFU -#define PVT_DBIAS_CMD1_S 0 +#define PVT_DBIAS_CMD1_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD1_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD1_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD1_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD1_PVT 0x7FF +#define PVT_DBIAS_CMD1_PVT_S 0 /** PVT_DBIAS_CMD2_REG register * needs desc @@ -387,10 +391,12 @@ extern "C" { /** PVT_DBIAS_CMD2 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD2 0x0001FFFFU -#define PVT_DBIAS_CMD2_M (PVT_DBIAS_CMD2_V << PVT_DBIAS_CMD2_S) -#define PVT_DBIAS_CMD2_V 0x0001FFFFU -#define PVT_DBIAS_CMD2_S 0 +#define PVT_DBIAS_CMD2_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD2_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD2_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD2_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD2_PVT 0x7FF +#define PVT_DBIAS_CMD2_PVT_S 0 /** PVT_DBIAS_CMD3_REG register * needs desc diff --git a/components/soc/esp32c5/register/soc/pvt_struct.h b/components/soc/esp32c5/register/soc/pvt_struct.h index 964b0e0b87..9b73e118a8 100644 --- a/components/soc/esp32c5/register/soc/pvt_struct.h +++ b/components/soc/esp32c5/register/soc/pvt_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -347,10 +347,18 @@ typedef union { */ typedef union { struct { - /** dbias_cmd0 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd0 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd0:17; + uint32_t dbias_cmd0_pvt:11; + /** dbias_cmd0_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd0_offset_value:5; + /** dbias_cmd0_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd0_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val; @@ -361,10 +369,18 @@ typedef union { */ typedef union { struct { - /** dbias_cmd1 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd1 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd1:17; + uint32_t dbias_cmd1_pvt:11; + /** dbias_cmd1_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd1_offset_value:5; + /** dbias_cmd1_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd1_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val; @@ -375,10 +391,18 @@ typedef union { */ typedef union { struct { - /** dbias_cmd2 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd2 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd2:17; + uint32_t dbias_cmd2_pvt:11; + /** dbias_cmd2_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd2_offset_value:5; + /** dbias_cmd2_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd2_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val; diff --git a/components/soc/esp32c5/register/soc/reg_base.h b/components/soc/esp32c5/register/soc/reg_base.h index 4a86fe97d0..73bf9f02f1 100644 --- a/components/soc/esp32c5/register/soc/reg_base.h +++ b/components/soc/esp32c5/register/soc/reg_base.h @@ -37,6 +37,7 @@ #define DR_REG_SLCHOST_BASE 0x60018000 #define DR_REG_PVT_MONITOR_BASE 0x60019000 #define DR_REG_PSRAM_MEM_MONITOR_BASE 0x6001A000 +#define DR_REG_PVT_BASE DR_REG_PVT_MONITOR_BASE /** * @brief Peripheral 1 Modules diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 927f89a728..563dd879da 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -239,6 +239,14 @@ config SOC_PMU_PVT_SUPPORTED bool default y +config SOC_PVT_EN_WITH_SLEEP + bool + default y + +config SOC_PVT_RETENTION_BY_REGDMA + bool + default y + config SOC_DCDC_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 611bd48656..7b8d9f0eb3 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -76,6 +76,8 @@ #define SOC_APM_SUPPORTED 1 #define SOC_PMU_SUPPORTED 1 #define SOC_PMU_PVT_SUPPORTED 1 +#define SOC_PVT_EN_WITH_SLEEP 1 +#define SOC_PVT_RETENTION_BY_REGDMA 1 #define SOC_DCDC_SUPPORTED 1 #define SOC_PAU_SUPPORTED 1 //TODO: IDF-7531 #define SOC_LP_TIMER_SUPPORTED 1 From fb62b97ef6e5677314b4e75dae2b04675c9626e3 Mon Sep 17 00:00:00 2001 From: yangfeng Date: Mon, 12 Jan 2026 15:33:55 +0800 Subject: [PATCH 22/84] feat(bt): set BR/EDR max sync conn eff for Bluedroid HFP on ESP32 Closes https://github.com/espressif/esp-idf/issues/18060 --- components/bt/controller/esp32/Kconfig.in | 5 --- components/bt/controller/esp32/bt.c | 2 +- .../bt/controller/esp32/esp_bredr_cfg.h | 33 +++++++++++++++++++ components/bt/include/esp32/include/esp_bt.h | 5 +-- components/bt/sdkconfig.rename | 1 - 5 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 components/bt/controller/esp32/esp_bredr_cfg.h diff --git a/components/bt/controller/esp32/Kconfig.in b/components/bt/controller/esp32/Kconfig.in index 9cf9fddb29..9b1f39a9fb 100644 --- a/components/bt/controller/esp32/Kconfig.in +++ b/components/bt/controller/esp32/Kconfig.in @@ -195,11 +195,6 @@ config BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF default BTDM_CTRL_BR_EDR_MAX_ACL_CONN if BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM default 0 -config BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF - int - default BTDM_CTRL_BR_EDR_MAX_SYNC_CONN if BTDM_CTRL_MODE_BR_EDR_ONLY || BTDM_CTRL_MODE_BTDM - default 0 - choice BTDM_CTRL_PINNED_TO_CORE_CHOICE prompt "The cpu core which bluetooth controller run" depends on !FREERTOS_UNICORE diff --git a/components/bt/controller/esp32/bt.c b/components/bt/controller/esp32/bt.c index a18b4ee361..af5c16dfec 100644 --- a/components/bt/controller/esp32/bt.c +++ b/components/bt/controller/esp32/bt.c @@ -1674,7 +1674,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) } //overwrite some parameters - cfg->bt_max_sync_conn = CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF; + cfg->bt_max_sync_conn = UT_BR_EDR_CTRL_MAX_SYNC_CONN_EFF; cfg->magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL; if (((cfg->mode & ESP_BT_MODE_BLE) && (cfg->ble_max_conn <= 0 || cfg->ble_max_conn > BTDM_CONTROLLER_BLE_MAX_CONN_LIMIT)) diff --git a/components/bt/controller/esp32/esp_bredr_cfg.h b/components/bt/controller/esp32/esp_bredr_cfg.h new file mode 100644 index 0000000000..c245bf4dbe --- /dev/null +++ b/components/bt/controller/esp32/esp_bredr_cfg.h @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(CONFIG_BT_BLUEDROID_ENABLED) && (CONFIG_BT_BLUEDROID_ENABLED) && (CONFIG_BT_HFP_ENABLE) && \ + defined(CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN) && (CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN == 0) + +#pragma message ("BT: forcing BR/EDR max sync conn eff to 1 (Bluedroid HFP requires SCO/eSCO)") +#define UT_BR_EDR_CTRL_MAX_SYNC_CONN_EFF (1) + +#elif defined(CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN) + +#define UT_BR_EDR_CTRL_MAX_SYNC_CONN_EFF (CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN) + +#else + +#define UT_BR_EDR_CTRL_MAX_SYNC_CONN_EFF (0) + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index 0e9b5fd1a2..3988c53243 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -13,6 +13,7 @@ #include "sdkconfig.h" #include "esp_task.h" #include "esp_assert.h" +#include "../../../../controller/esp32/esp_bredr_cfg.h" #ifdef __cplusplus extern "C" { @@ -46,7 +47,7 @@ extern "C" { #define SOC_MEM_BT_EM_PER_SYNC_SIZE 0x870 -#define SOC_MEM_BT_EM_BREDR_REAL_END (SOC_MEM_BT_EM_BREDR_NO_SYNC_END + CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF * SOC_MEM_BT_EM_PER_SYNC_SIZE) +#define SOC_MEM_BT_EM_BREDR_REAL_END (SOC_MEM_BT_EM_BREDR_NO_SYNC_END + UT_BR_EDR_CTRL_MAX_SYNC_CONN_EFF * SOC_MEM_BT_EM_PER_SYNC_SIZE) #endif //CONFIG_BT_ENABLED @@ -241,7 +242,7 @@ the advertising packet will be discarded until the memory is restored. */ .bt_sco_datapath = CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF, \ .auto_latency = BTDM_CTRL_AUTO_LATENCY_EFF, \ .bt_legacy_auth_vs_evt = BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF, \ - .bt_max_sync_conn = CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF, \ + .bt_max_sync_conn = UT_BR_EDR_CTRL_MAX_SYNC_CONN_EFF, \ .ble_sca = CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF, \ .pcm_role = CONFIG_BTDM_CTRL_PCM_ROLE_EFF, \ .pcm_polar = CONFIG_BTDM_CTRL_PCM_POLAR_EFF, \ diff --git a/components/bt/sdkconfig.rename b/components/bt/sdkconfig.rename index 7e3b5e3ea2..12bd0e9d5e 100644 --- a/components/bt/sdkconfig.rename +++ b/components/bt/sdkconfig.rename @@ -10,7 +10,6 @@ CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN CONFIG_BTDM_CTRL_BR_ CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF -CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE_CHOICE CONFIG_BTDM_CTRL_PINNED_TO_CORE_CHOICE CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE CONFIG_BTDM_CTRL_PINNED_TO_CORE CONFIG_BTDM_CONTROLLER_HCI_MODE_CHOICE CONFIG_BTDM_CTRL_HCI_MODE_CHOICE From df0b21d42ce3d26625aadb0af6e030ccdaf1c36a Mon Sep 17 00:00:00 2001 From: Sajia Date: Wed, 12 Nov 2025 10:13:41 +0530 Subject: [PATCH 23/84] fix(wifi): Free eapol sm before alloc for new connection --- .../wpa_supplicant/esp_supplicant/src/esp_wpa_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index c08cbe2925..328b3d31f1 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -370,6 +370,11 @@ static int check_n_add_wps_sta(struct hostapd_data *hapd, struct sta_info *sta_i } sta_info->wps_ie = wps_ie; + + if (sta_info->eapol_sm) { + ieee802_1x_free_station(hapd, sta_info); + } + sta_info->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta_info); if (sta_info->eapol_sm) { From 139d4d8952a87bbcfbc2b25493763d0929c071b7 Mon Sep 17 00:00:00 2001 From: "yanzihan@espressif.com" Date: Mon, 19 Jan 2026 15:59:47 +0800 Subject: [PATCH 24/84] feat(esp_hw_support): use pvt to auto control digital ldo and rtc ldo for esp32c61 v5.5 --- .../port/esp32c61/CMakeLists.txt | 4 + .../port/esp32c61/include/soc/rtc.h | 49 +++++- .../esp_hw_support/port/esp32c61/pmu_init.c | 22 ++- .../esp_hw_support/port/esp32c61/pmu_pvt.c | 160 ++++++++++++++++++ .../esp_hw_support/port/esp32c61/pmu_sleep.c | 4 + .../esp_hw_support/port/esp32c61/rtc_clk.c | 18 +- .../port/esp32c61/rtc_clk_init.c | 2 + .../esp32c61/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32c61/include/soc/soc_caps.h | 1 + .../include/soc/system_periph_retention.h | 12 +- .../soc/esp32c61/register/soc/pvt_reg.h | 32 ++-- .../soc/esp32c61/register/soc/pvt_struct.h | 38 ++++- 12 files changed, 322 insertions(+), 24 deletions(-) create mode 100644 components/esp_hw_support/port/esp32c61/pmu_pvt.c diff --git a/components/esp_hw_support/port/esp32c61/CMakeLists.txt b/components/esp_hw_support/port/esp32c61/CMakeLists.txt index ea0e988a9d..3486832b4f 100644 --- a/components/esp_hw_support/port/esp32c61/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32c61/CMakeLists.txt @@ -17,6 +17,10 @@ if(NOT BOOTLOADER_BUILD) endif() +if(NOT BOOTLOADER_BUILD AND CONFIG_ESP_ENABLE_PVT) + list(APPEND srcs "pmu_pvt.c") +endif() + add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") target_sources(${COMPONENT_LIB} PRIVATE "${srcs}") diff --git a/components/esp_hw_support/port/esp32c61/include/soc/rtc.h b/components/esp_hw_support/port/esp32c61/include/soc/rtc.h index 72d5c0033a..839e381c21 100644 --- a/components/esp_hw_support/port/esp32c61/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32c61/include/soc/rtc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -99,6 +99,53 @@ storing in efuse (based on ATE 5k ECO3 chips) #define V_RTC_MID_MUL10000 10800 #define V_DIG_MID_MUL10000 10860 +#if CONFIG_ESP_ENABLE_PVT +/* +set pvt default param +*/ +#define PVT_CHANNEL0_SEL 33 +#define PVT_CHANNEL1_SEL 37 +#define PVT_CHANNEL0_CFG 0x13e80 +#define PVT_CHANNEL1_CFG 0x13e80 +#define PVT_CHANNEL2_CFG 0x10000 +#define PVT_CMD0 0x24 +#define PVT_CMD1 0x5 +#define PVT_CMD2 0x427 +#define PVT_TARGET 0xffff +#define PVT_CLK_DIV 1 +#define PVT_DELAY_NUM_HIGH 142 +#define PVT_DELAY_NUM_LOW 135 +#define PVT_PUMP_CHANNEL_CODE 1 +#define PVT_PUMP_BITMAP 22 +#define PVT_PUMP_DRV 0 +#define PVT_DELAY_NUM_PUMP 132 + +/** + * @brief Initialize PVT related parameters + */ +void pvt_auto_dbias_init(void); + +/** + * @brief Enable or disable PVT functions + * + * @param enable true to enable, false to disable + */ +void pvt_func_enable(bool enable); + +/** + * @brief Initialize charge pump related parameters + */ +void charge_pump_init(void); + +/** + * @brief Enable or disable charge pump functions + * + * @param enable true to enable, false to disable + */ +void charge_pump_enable(bool enable); + +#endif //#if CONFIG_ESP_ENABLE_PVT + /** * @brief CPU clock configuration structure */ diff --git a/components/esp_hw_support/port/esp32c61/pmu_init.c b/components/esp_hw_support/port/esp32c61/pmu_init.c index a1df8ec31b..f508f3fba1 100644 --- a/components/esp_hw_support/port/esp32c61/pmu_init.c +++ b/components/esp_hw_support/port/esp32c61/pmu_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,10 @@ #include "regi2c_ctrl.h" #include "esp_private/ocode_init.h" #include "esp_rom_sys.h" +#include "esp_hw_log.h" +#include "soc/rtc.h" +#include "hal/efuse_ll.h" +#include "hal/efuse_hal.h" static __attribute__((unused)) const char *TAG = "pmu_init"; @@ -221,4 +225,20 @@ void pmu_init(void) esp_ocode_calib_init(); } #endif + +#if CONFIG_ESP_ENABLE_PVT + /*setup pvt function*/ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + pvt_auto_dbias_init(); + charge_pump_init(); + + pvt_func_enable(true); + charge_pump_enable(true); + esp_rom_delay_us(1000); + } + else { + ESP_HW_LOGW(TAG, "blk_version is less than 2, pvt function not supported in efuse."); + } +#endif } diff --git a/components/esp_hw_support/port/esp32c61/pmu_pvt.c b/components/esp_hw_support/port/esp32c61/pmu_pvt.c new file mode 100644 index 0000000000..4258f77155 --- /dev/null +++ b/components/esp_hw_support/port/esp32c61/pmu_pvt.c @@ -0,0 +1,160 @@ +/* + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "soc/soc.h" +#include "soc/pmu_struct.h" +#include "soc/pvt_reg.h" +#include "soc/pcr_reg.h" +#include "soc/pmu_reg.h" +#include "hal/pmu_hal.h" +#include "pmu_param.h" +#include "esp_rom_sys.h" +#include "esp_private/esp_pmu.h" +#include "soc/regi2c_dig_reg.h" +#include "soc/rtc.h" +#include "hal/efuse_ll.h" +#include "hal/efuse_hal.h" +#include "esp_hw_log.h" + +static __attribute__((unused)) const char *TAG = "pmu_pvt"; + +#if CONFIG_ESP_ENABLE_PVT + +static uint8_t get_lp_hp_gap(void) +{ + int8_t lp_hp_gap = 0; + uint32_t blk_version = efuse_hal_blk_version(); + uint8_t lp_hp_gap_efuse = 0; + if (blk_version >= 2) { + lp_hp_gap_efuse = efuse_ll_get_dbias_vol_gap(); + bool gap_flag = lp_hp_gap_efuse >> 4; + uint8_t gap_abs_value = lp_hp_gap_efuse & 0xf; + if (gap_flag) { + lp_hp_gap = -1 * gap_abs_value; + } else { + lp_hp_gap = gap_abs_value; + } + lp_hp_gap = lp_hp_gap - 8; + assert((lp_hp_gap >= -15) && (lp_hp_gap <= 7)); + if (lp_hp_gap < 0 ) { + lp_hp_gap = 16 - lp_hp_gap; + } + } + return lp_hp_gap; +} + +static void set_pvt_hp_lp_gap(uint8_t value) +{ + bool flag = value >> 4; + uint8_t abs_value = value & 0xf; + + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_FLAG, flag, PVT_DBIAS_CMD0_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD0_OFFSET_VALUE_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_FLAG, flag, PVT_DBIAS_CMD1_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD1_OFFSET_VALUE_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_FLAG, flag, PVT_DBIAS_CMD2_OFFSET_FLAG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD2_OFFSET_VALUE_S); +} + +FORCE_INLINE_ATTR uint32_t get_pvt_hp_dbias(void) +{ + return GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL_V, PMU_HP_DBIAS_VOL_S); +} + +FORCE_INLINE_ATTR uint32_t get_pvt_lp_dbias(void) +{ + return GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_LP_DBIAS_VOL_V, PMU_LP_DBIAS_VOL_S); +} + +void pvt_auto_dbias_init(void) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + SET_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN); + SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN); + /*config for dbias func*/ + CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); + esp_rom_delay_us(1); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL0_SEL, PVT_CHANNEL0_SEL, PVT_DBIAS_CHANNEL0_SEL_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL1_SEL, PVT_CHANNEL1_SEL, PVT_DBIAS_CHANNEL1_SEL_S); // Select monitor cell ,which used to monitor PVT situation + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL0_SEL_REG, PVT_DBIAS_CHANNEL0_CFG, PVT_CHANNEL0_CFG, PVT_DBIAS_CHANNEL0_CFG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL1_SEL_REG, PVT_DBIAS_CHANNEL1_CFG, PVT_CHANNEL1_CFG, PVT_DBIAS_CHANNEL1_CFG_S); + SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL2_SEL_REG, PVT_DBIAS_CHANNEL2_CFG, PVT_CHANNEL2_CFG, PVT_DBIAS_CHANNEL2_CFG_S); // Configure filter threshold for avoiding auto-dbias overly sensitive regulation + SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_PVT, PVT_CMD0, PVT_DBIAS_CMD0_PVT_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_PVT, PVT_CMD1, PVT_DBIAS_CMD1_PVT_S); + SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_PVT, PVT_CMD2, PVT_DBIAS_CMD2_PVT_S); // Configure auto-dbias adjust property, such as adjusting step + SET_PERI_REG_BITS(PVT_DBIAS_TIMER_REG, PVT_TIMER_TARGET, PVT_TARGET, PVT_TIMER_TARGET_S); // Configure auto-dbias voltage regulation cycle + + SET_PERI_REG_BITS(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_DIV_NUM, PVT_CLK_DIV, PCR_PVT_MONITOR_FUNC_CLK_DIV_NUM_S);//pvt function clock divider number + + /*config for pvt cell: unit0; site2; vt1*/ + SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_SEL); // choose pvt clk + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT0_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT0, PVT_DELAY_NUM_HIGH, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT0_S); // The threshold for determining whether the voltage is too high + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT1_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT1, PVT_DELAY_NUM_LOW, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT1_S); // The threshold for determining whether the voltage is too low + SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT2_VT1_CONF1_REG, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT2, PVT_DELAY_NUM_PUMP, PVT_DELAY_LIMIT_VT1_PD_SITE2_UNIT2_S); // The threshold for chargepump + + /*config lp offset for pvt func*/ + uint8_t lp_hp_gap = get_lp_hp_gap(); + set_pvt_hp_lp_gap(lp_hp_gap); + } +} + +void IRAM_ATTR pvt_func_enable(bool enable) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + if (enable) { + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // start calibration @HP_CALI_DBIAS_DEFAULT + SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN); + SET_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN); + SET_PERI_REG_MASK(PVT_CLK_CFG_REG, PVT_MONITOR_CLK_PVT_EN); // once enable cannot be closed + SET_PERI_REG_MASK(PVT_COMB_PD_SITE2_UNIT0_VT1_CONF1_REG, PVT_MONITOR_EN_VT1_PD_SITE2_UNIT0); // enable pvt clk + esp_rom_delay_us(10); + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // hand over control of dbias to pvt + CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // must clear @HP_CALI_DBIAS_DEFAULT + SET_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); // enable auto dbias + } else { + uint32_t pvt_hp_dbias = get_pvt_hp_dbias(); + uint32_t pvt_lp_dbias = get_pvt_lp_dbias(); // update pvt_cali_dbias + SET_PERI_REG_BITS(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, pvt_hp_dbias, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS_S); + SET_PERI_REG_BITS(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, pvt_lp_dbias, PMU_HP_SLEEP_LP_REGULATOR_DBIAS_S); + CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); //disable auto dbias + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // hand over control of dbias to pmu + CLEAR_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN); + CLEAR_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN); + } + } +} + +void charge_pump_init(void) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + /*config for charge pump*/ + SET_PERI_REG_BITS(PVT_PMUP_CHANNEL_CFG_REG, PVT_PUMP_CHANNEL_CODE0, PVT_PUMP_CHANNEL_CODE, PVT_PUMP_CHANNEL_CODE0_S); //Set channel code + WRITE_PERI_REG(PVT_PMUP_BITMAP_LOW0_REG, (1 << PVT_PUMP_BITMAP)); // Select monitor cell for charge pump + SET_PERI_REG_BITS(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_DRV0, PVT_PUMP_DRV, PVT_PUMP_DRV0_S); //Configure the charging intensity + } +} + +void IRAM_ATTR charge_pump_enable(bool enable) +{ + uint32_t blk_version = efuse_hal_blk_version(); + if (blk_version >= 2) { + if (enable) { + SET_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); // enable charge pump + } else { + CLEAR_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); //disable charge pump + } + } +} + +#endif diff --git a/components/esp_hw_support/port/esp32c61/pmu_sleep.c b/components/esp_hw_support/port/esp32c61/pmu_sleep.c index ca7edfb618..8f9128871a 100644 --- a/components/esp_hw_support/port/esp32c61/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c61/pmu_sleep.c @@ -307,6 +307,10 @@ static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_con pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.xpd); pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dbias); pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.drv_b); +#if CONFIG_ESP_ENABLE_PVT + uint32_t pvt_hp_dbias = GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL_V, PMU_HP_DBIAS_VOL_S); + pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(MODEM), pvt_hp_dbias); +#endif pmu_ll_lp_set_dbg_atten (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.dbg_atten); pmu_ll_lp_set_current_power_off (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.pd_cur); diff --git a/components/esp_hw_support/port/esp32c61/rtc_clk.c b/components/esp_hw_support/port/esp32c61/rtc_clk.c index 67d76464d5..9b6bd7b89b 100644 --- a/components/esp_hw_support/port/esp32c61/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c61/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,8 @@ #include "soc/lp_aon_reg.h" #include "esp_private/sleep_event.h" #include "esp_private/regi2c_ctrl.h" +#include "esp_attr.h" +#include "esp_private/esp_pmu.h" static const char *TAG = "rtc_clk"; @@ -176,6 +178,10 @@ static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL); clk_ll_bus_update(); esp_rom_set_cpu_ticks_per_us(cpu_freq); +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + charge_pump_enable(false); + pvt_func_enable(false); +#endif } static void rtc_clk_cpu_freq_to_8m(void) @@ -185,6 +191,10 @@ static void rtc_clk_cpu_freq_to_8m(void) clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST); clk_ll_bus_update(); esp_rom_set_cpu_ticks_per_us(20); +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + charge_pump_enable(false); + pvt_func_enable(false); +#endif } /** @@ -194,6 +204,12 @@ static void rtc_clk_cpu_freq_to_8m(void) */ static void rtc_clk_cpu_freq_to_pll_160_mhz(int cpu_freq_mhz) { +#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD) + pvt_auto_dbias_init(); + charge_pump_init(); + pvt_func_enable(true); + charge_pump_enable(true); +#endif // f_hp_root = 160MHz uint32_t cpu_divider = CLK_LL_PLL_160M_FREQ_MHZ / cpu_freq_mhz; clk_ll_cpu_set_divider(cpu_divider); diff --git a/components/esp_hw_support/port/esp32c61/rtc_clk_init.c b/components/esp_hw_support/port/esp32c61/rtc_clk_init.c index 965fabc705..ce65043730 100644 --- a/components/esp_hw_support/port/esp32c61/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32c61/rtc_clk_init.c @@ -84,6 +84,8 @@ void rtc_clk_init(rtc_clk_config_t cfg) uint32_t hp_cali_dbias = get_act_hp_dbias(); uint32_t lp_cali_dbias = get_act_lp_dbias(); + SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu + SET_PERI_REG_BITS(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, hp_cali_dbias, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS_S); SET_PERI_REG_BITS(PMU_HP_MODEM_HP_REGULATOR0_REG, PMU_HP_MODEM_HP_REGULATOR_DBIAS, hp_cali_dbias, PMU_HP_MODEM_HP_REGULATOR_DBIAS_S); SET_PERI_REG_BITS(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, lp_cali_dbias, PMU_HP_SLEEP_LP_REGULATOR_DBIAS_S); diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 542b058f90..8bedb03d18 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -119,6 +119,10 @@ config SOC_PMU_SUPPORTED bool default y +config SOC_PMU_PVT_SUPPORTED + bool + default y + config SOC_LP_TIMER_SUPPORTED bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 145d5d1168..97756ec12b 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -48,6 +48,7 @@ #define SOC_BOD_SUPPORTED 1 #define SOC_APM_SUPPORTED 1 /*!< Support for APM peripheral */ #define SOC_PMU_SUPPORTED 1 +#define SOC_PMU_PVT_SUPPORTED 1 #define SOC_LP_TIMER_SUPPORTED 1 #define SOC_LP_AON_SUPPORTED 1 #define SOC_CLK_TREE_SUPPORTED 1 diff --git a/components/soc/esp32c61/include/soc/system_periph_retention.h b/components/soc/esp32c61/include/soc/system_periph_retention.h index 83304975fb..313f27281b 100644 --- a/components/soc/esp32c61/include/soc/system_periph_retention.h +++ b/components/soc/esp32c61/include/soc/system_periph_retention.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -77,6 +77,16 @@ extern const regdma_entries_config_t flash_spimem_regs_retention[SPIMEM_RETENTIO #define SYSTIMER_RETENTION_LINK_LEN 19 extern const regdma_entries_config_t systimer_regs_retention[SYSTIMER_RETENTION_LINK_LEN]; +/** + * @brief Provide access to pvt configuration registers retention + * context definition. + * + * This is an internal function of the sleep retention driver, and is not + * useful for external use. + */ +#define PVT_RETENTION_LINK_LEN 1 +extern const regdma_entries_config_t pvt_regs_retention[PVT_RETENTION_LINK_LEN]; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c61/register/soc/pvt_reg.h b/components/soc/esp32c61/register/soc/pvt_reg.h index b501935008..77ca8ec10f 100644 --- a/components/soc/esp32c61/register/soc/pvt_reg.h +++ b/components/soc/esp32c61/register/soc/pvt_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -363,10 +363,12 @@ extern "C" { /** PVT_DBIAS_CMD0 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD0 0x0001FFFFU -#define PVT_DBIAS_CMD0_M (PVT_DBIAS_CMD0_V << PVT_DBIAS_CMD0_S) -#define PVT_DBIAS_CMD0_V 0x0001FFFFU -#define PVT_DBIAS_CMD0_S 0 +#define PVT_DBIAS_CMD0_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD0_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD0_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD0_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD0_PVT 0x7FF +#define PVT_DBIAS_CMD0_PVT_S 0 /** PVT_DBIAS_CMD1_REG register * needs desc @@ -375,10 +377,12 @@ extern "C" { /** PVT_DBIAS_CMD1 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD1 0x0001FFFFU -#define PVT_DBIAS_CMD1_M (PVT_DBIAS_CMD1_V << PVT_DBIAS_CMD1_S) -#define PVT_DBIAS_CMD1_V 0x0001FFFFU -#define PVT_DBIAS_CMD1_S 0 +#define PVT_DBIAS_CMD1_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD1_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD1_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD1_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD1_PVT 0x7FF +#define PVT_DBIAS_CMD1_PVT_S 0 /** PVT_DBIAS_CMD2_REG register * needs desc @@ -387,10 +391,12 @@ extern "C" { /** PVT_DBIAS_CMD2 : R/W; bitpos: [16:0]; default: 0; * needs field desc */ -#define PVT_DBIAS_CMD2 0x0001FFFFU -#define PVT_DBIAS_CMD2_M (PVT_DBIAS_CMD2_V << PVT_DBIAS_CMD2_S) -#define PVT_DBIAS_CMD2_V 0x0001FFFFU -#define PVT_DBIAS_CMD2_S 0 +#define PVT_DBIAS_CMD2_OFFSET_FLAG 1 +#define PVT_DBIAS_CMD2_OFFSET_FLAG_S 16 +#define PVT_DBIAS_CMD2_OFFSET_VALUE 0x1F +#define PVT_DBIAS_CMD2_OFFSET_VALUE_S 11 +#define PVT_DBIAS_CMD2_PVT 0x7FF +#define PVT_DBIAS_CMD2_PVT_S 0 /** PVT_DBIAS_CMD3_REG register * needs desc diff --git a/components/soc/esp32c61/register/soc/pvt_struct.h b/components/soc/esp32c61/register/soc/pvt_struct.h index 875bcd5308..064a76cd39 100644 --- a/components/soc/esp32c61/register/soc/pvt_struct.h +++ b/components/soc/esp32c61/register/soc/pvt_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -347,10 +347,18 @@ typedef union { */ typedef union { struct { - /** dbias_cmd0 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd0 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd0:17; + uint32_t dbias_cmd0_pvt:11; + /** dbias_cmd0_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd0_offset_value:5; + /** dbias_cmd0_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd0_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val; @@ -361,10 +369,18 @@ typedef union { */ typedef union { struct { - /** dbias_cmd1 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd1 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd1:17; + uint32_t dbias_cmd1_pvt:11; + /** dbias_cmd1_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd1_offset_value:5; + /** dbias_cmd1_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd1_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val; @@ -375,10 +391,18 @@ typedef union { */ typedef union { struct { - /** dbias_cmd2 : R/W; bitpos: [16:0]; default: 0; + /** dbias_cmd2 : R/W; bitpos: [10:0]; default: 0; * needs field desc */ - uint32_t dbias_cmd2:17; + uint32_t dbias_cmd2_pvt:11; + /** dbias_cmd2_offset_value : R/W; bitpos: [15:11]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd2_offset_value:5; + /** dbias_cmd2_offset_flag : R/W; bitpos: [16]; default: 0; + * needs field desc + */ + uint32_t dbias_cmd2_offset_flag:1; uint32_t reserved_17:15; }; uint32_t val; From 9b6e661aba48ce915467063d1451672e7162f4d1 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Thu, 8 Jan 2026 09:36:46 +0800 Subject: [PATCH 25/84] fix(bt/bluedroid): A2DP source at acceptor side will miss ESP_A2D_AUDIO_CFG_EVT --- .../bt/host/bluedroid/bta/av/bta_av_aact.c | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) 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 2e4f5ec078..a23f4e5f87 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_aact.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_aact.c @@ -1277,19 +1277,19 @@ void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) bta_av_adjust_seps_idx(p_scb, avdt_handle); APPL_TRACE_DEBUG("bta_av_setconfig_rsp: sep_idx: %d cur_psc_mask:0x%x", p_scb->sep_idx, p_scb->cur_psc_mask); + if ((p_data->ci_setconfig.err_code == AVDT_SUCCESS) && + (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL)) { + p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_CFG_EVT, + (tBTA_AV_MEDIA *)p_scb->cfg.codec_info); + } + if (AVDT_TSEP_SNK == local_sep) { - if ((p_data->ci_setconfig.err_code == AVDT_SUCCESS) && - (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL)) { - p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_CFG_EVT, - (tBTA_AV_MEDIA *)p_scb->cfg.codec_info); - } if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT) { psc_cfg.psc_mask |= BTA_AV_PSC_DEALY_RPT; } (*bta_av_cb.p_cback)(BTA_AV_SNK_PSC_CFG_EVT, (tBTA_AV *)&psc_cfg); } - AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code, p_data->ci_setconfig.category); @@ -1908,24 +1908,18 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) cfg.psc_mask &= p_scb->p_cap->psc_mask; p_scb->cur_psc_mask = cfg.psc_mask; + if (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL) { + APPL_TRACE_DEBUG(" Configure Deoder for A2DP Connection "); + p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_CFG_EVT, + (tBTA_AV_MEDIA *)p_scb->cfg.codec_info); + } + if (uuid_int == UUID_SERVCLASS_AUDIO_SINK) { - if (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL) { - APPL_TRACE_DEBUG(" Configure Deoder for Sink Connection "); - p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_CFG_EVT, - (tBTA_AV_MEDIA *)p_scb->cfg.codec_info); - } if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT) { psc_cfg.psc_mask |= BTA_AV_PSC_DEALY_RPT; } (*bta_av_cb.p_cback)(BTA_AV_SNK_PSC_CFG_EVT, (tBTA_AV *)&psc_cfg); } - else { - /* UUID_SERVCLASS_AUDIO_SOURCE */ - if (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL) { - p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_CFG_EVT, - (tBTA_AV_MEDIA *)p_scb->cfg.codec_info); - } - } /* open the stream */ AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr, From 41edf56707305e05967db566cf39ec16227c6a6b Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 22 Dec 2025 16:47:18 +0800 Subject: [PATCH 26/84] fix(bt): validated UUID parameters in BTA_JvStartDiscovery --- components/bt/host/bluedroid/bta/jv/bta_jv_api.c | 5 +++++ .../bt/host/bluedroid/btc/profile/std/spp/btc_spp.c | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c index 7fb74fdfa8..cfa0ff9091 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c @@ -283,6 +283,11 @@ tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, UINT16 num_uuid, tBTA_JV_API_START_DISCOVERY *p_msg; APPL_TRACE_API( "BTA_JvStartDiscovery"); + if ((num_uuid > BTA_JV_MAX_UUIDS) || ((num_uuid > 0) && (p_uuid_list == NULL))) { + APPL_TRACE_ERROR("invalid uuid list: num_uuid=%u", num_uuid); + return BTA_JV_FAILURE; + } + if ((p_msg = (tBTA_JV_API_START_DISCOVERY *)osi_malloc(sizeof(tBTA_JV_API_START_DISCOVERY))) != NULL) { p_msg->hdr.event = BTA_JV_API_START_DISCOVERY_EVT; bdcpy(p_msg->bd_addr, bd_addr); diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index 31a71992dc..3426688edd 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -652,7 +652,11 @@ static void btc_spp_start_discovery(btc_spp_args_t *arg) ret = ESP_SPP_NEED_INIT; break; } - BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL); + tBTA_JV_STATUS status = BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL); + if (status != BTA_JV_SUCCESS) { + BTC_TRACE_ERROR("%s SPP failed to start discovery\n", __func__); + ret = ESP_SPP_NO_RESOURCE; + } } while (0); if (ret != ESP_SPP_SUCCESS) { From 0126907574f52339f716067cde4e9fb41001ce5b Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 22 Dec 2025 17:11:29 +0800 Subject: [PATCH 27/84] fix(bt): enhanced packet length check for HCI module --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 4 ++++ components/bt/host/bluedroid/hci/hci_layer.c | 19 +++++++++++++++++++ .../bluedroid/hci/include/hci/hci_internals.h | 4 ++++ .../bt/host/bluedroid/hci/packet_fragmenter.c | 11 +++++++++++ 4 files changed, 38 insertions(+) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index cadf70005f..475af54302 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -481,6 +481,10 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) packet->len--; if (type == HCI_BLE_EVENT) { #if (!CONFIG_BT_STACK_NO_LOG) + if (packet->len < 1) { + osi_free(packet); + return; + } uint8_t len = 0; STREAM_TO_UINT8(len, stream); #endif diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index c6a6efa4ee..2ed3172c25 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -447,12 +447,26 @@ static bool filter_incoming_event(BT_HDR *packet) uint8_t event_code; command_opcode_t opcode; + if (packet == NULL) { + return true; + } + + if (packet->len < HCI_EVENT_PREAMBLE_SIZE) { + HCI_TRACE_WARNING("dropping too short HCI event (len=%u)", packet->len); + osi_free(packet); + return true; + } STREAM_TO_UINT8(event_code, stream); STREAM_SKIP_UINT8(stream); // Skip the parameter total length field HCI_TRACE_DEBUG("Receive packet event_code=0x%x\n", event_code); if (event_code == HCI_COMMAND_COMPLETE_EVT) { + if (packet->len < HCI_EVENT_PREAMBLE_SIZE + HCI_CC_EVENT_MIN_PARAM_LEN) { + HCI_TRACE_WARNING("dropping too short Command Complete (len=%u)", packet->len); + osi_free(packet); + return true; + } STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); wait_entry = get_waiting_command(opcode); @@ -481,6 +495,11 @@ static bool filter_incoming_event(BT_HDR *packet) goto intercepted; } else if (event_code == HCI_COMMAND_STATUS_EVT) { uint8_t status; + if (packet->len < HCI_EVENT_PREAMBLE_SIZE + HCI_CS_EVENT_MIN_PARAM_LEN) { + HCI_TRACE_WARNING("dropping too short Command Status (len=%u)", packet->len); + osi_free(packet); + return true; + } STREAM_TO_UINT8(status, stream); STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_internals.h b/components/bt/host/bluedroid/hci/include/hci/hci_internals.h index 41c792cf3c..7d336e8a13 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_internals.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_internals.h @@ -27,5 +27,9 @@ #define HCI_SCO_PREAMBLE_SIZE 3 // 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4) #define HCI_EVENT_PREAMBLE_SIZE 2 +// 1 byte for Num_HCI_Command_Packets, 2 bytes for Commnad_Opcode (Volume 4, Part E, 7.7.14) +#define HCI_CC_EVENT_MIN_PARAM_LEN 3 +// 1 byte for status, 1 byte for Num_HCI_Command_Packets, 2 bytes for Commnad_Opcode (Volume 4, Part E, 7.7.15) +#define HCI_CS_EVENT_MIN_PARAM_LEN 4 #endif /* _HCI_INTERNALS_H_ */ diff --git a/components/bt/host/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c index ccc220fbf1..0827ecb4fe 100644 --- a/components/bt/host/bluedroid/hci/packet_fragmenter.c +++ b/components/bt/host/bluedroid/hci/packet_fragmenter.c @@ -37,6 +37,7 @@ #define START_PACKET_BOUNDARY 2 #define CONTINUATION_PACKET_BOUNDARY 1 #define L2CAP_HEADER_SIZE 4 +#define L2CAP_LENGTH_SIZE 2 // TODO(zachoverflow): find good value for this #define NUMBER_OF_BUCKETS 42 @@ -81,6 +82,11 @@ static void fragment_and_dispatch(BT_HDR *packet) callbacks->fragmented(packet, true); return; } + if (packet->len < HCI_ACL_PREAMBLE_SIZE) { + HCI_TRACE_ERROR("ACL packet too short for preamble (len=%u)", packet->len); + callbacks->fragmented(packet, true); + return; + } max_data_size = SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID ? @@ -143,6 +149,11 @@ static void reassemble_and_dispatch(BT_HDR *packet) uint16_t l2cap_length; uint16_t acl_length __attribute__((unused)); + if (packet->len < HCI_ACL_PREAMBLE_SIZE + L2CAP_LENGTH_SIZE) { + HCI_TRACE_ERROR("ACL packet too short (len=%u)\n", packet->len); + osi_free(packet); + return; + } STREAM_TO_UINT16(handle, stream); STREAM_TO_UINT16(acl_length, stream); STREAM_TO_UINT16(l2cap_length, stream); From 458150888d7267403f673afca6fbbe4cab31c30b Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 22 Dec 2025 17:16:45 +0800 Subject: [PATCH 28/84] fix(bt): enhanced packet length check for avrc_pars_vendor_cmd --- .../host/bluedroid/stack/avrc/avrc_pars_tg.c | 74 ++++++++++--------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c index cae87a2a9e..0e967877fb 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c @@ -106,46 +106,54 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */ - BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p); - if (len != (p_result->get_cur_app_val.num_attr + 1)) { + if (len < 1) { status = AVRC_STS_INTERNAL_ERR; - break; - } - p_u8 = p_result->get_cur_app_val.attrs; - for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) { - /* only report the valid player app attributes */ - if (AVRC_IsValidPlayerAttr(*p)) { - p_u8[yy++] = *p; + } else { + BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p); + if (len != (p_result->get_cur_app_val.num_attr + 1)) { + status = AVRC_STS_INTERNAL_ERR; + break; + } + p_u8 = p_result->get_cur_app_val.attrs; + for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) { + /* only report the valid player app attributes */ + if (AVRC_IsValidPlayerAttr(*p)) { + p_u8[yy++] = *p; + } + p++; + } + p_result->get_cur_app_val.num_attr = yy; + if (yy == 0) { + status = AVRC_STS_BAD_PARAM; } - p++; - } - p_result->get_cur_app_val.num_attr = yy; - if (yy == 0) { - status = AVRC_STS_BAD_PARAM; } break; case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */ - BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p); - size_needed = sizeof(tAVRC_APP_SETTING); - if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) { - p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf; - p_app_set = p_result->set_app_val.p_vals; - for (xx = 0; ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) { - p_app_set[xx].attr_id = *p++; - p_app_set[xx].attr_val = *p++; - if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) { - status = AVRC_STS_BAD_PARAM; - } - } - if (xx != p_result->set_app_val.num_val) { - AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d", - xx, p_result->set_app_val.num_val); - p_result->set_app_val.num_val = xx; - } - } else { - AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len"); + if (len < 1) { status = AVRC_STS_INTERNAL_ERR; + } else { + BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p); + size_needed = sizeof(tAVRC_APP_SETTING); + if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) { + p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf; + p_app_set = p_result->set_app_val.p_vals; + for (xx = 0; ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) { + p_app_set[xx].attr_id = *p++; + p_app_set[xx].attr_val = *p++; + if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) { + status = AVRC_STS_BAD_PARAM; + } + } + if (xx != p_result->set_app_val.num_val) { + AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d", + xx, p_result->set_app_val.num_val); + p_result->set_app_val.num_val = xx; + } + } else { + AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len"); + status = AVRC_STS_INTERNAL_ERR; + } } break; From 46baa2dac17650dfbaf7ff954cd3a62dd0127a64 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 22 Dec 2025 17:33:45 +0800 Subject: [PATCH 29/84] fix(bt): enhanced packet length check in sdp_server.c --- .../bt/host/bluedroid/stack/sdp/sdp_server.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_server.c b/components/bt/host/bluedroid/stack/sdp/sdp_server.c index 43e3664baf..d36b4115c9 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_server.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_server.c @@ -118,6 +118,10 @@ void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg) UINT8 pdu_id; UINT16 trans_num, param_len; + if (p_msg->len < 5) { + SDP_TRACE_WARNING("SDP - short request received: len=%u\n", p_msg->len); + return; + } /* Start inactivity timer */ btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); @@ -187,6 +191,11 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, return; } + if (p_req + 2 > p_req_end) { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST); + return; + } + /* Get the max replies we can send. Cap it at our max anyways. */ BE_STREAM_TO_UINT16 (max_replies, p_req); @@ -194,7 +203,6 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, max_replies = SDP_MAX_RECORDS; } - if ((!p_req) || (p_req > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST); return; @@ -322,14 +330,13 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, BOOLEAN is_cont = FALSE; UINT16 attr_len; - /* Extract the record handle */ - BE_STREAM_TO_UINT32 (rec_handle, p_req); - - if (p_req > p_req_end) { + if (p_req + 4 + 2 > p_req_end) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE); return; } + /* Extract the record handle */ + BE_STREAM_TO_UINT32 (rec_handle, p_req); /* Get the max list length we can send. Cap it at MTU size minus overhead */ BE_STREAM_TO_UINT16 (max_list_len, p_req); @@ -371,7 +378,7 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, return; } - if (*p_req++ != SDP_CONTINUATION_LEN) { + if ((*p_req++ != SDP_CONTINUATION_LEN) || (p_req + 2 > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); return; } From e421e7d2c0d72a2e9e9e4edbd403787a2e013f78 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 22 Dec 2025 17:37:28 +0800 Subject: [PATCH 30/84] fix(bt): fixed semaphore deletion condition in UART DMA deinit --- .../bt/porting/transport/driver/uart/hci_driver_uart_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c index 7bc3cc7c0b..0da3695915 100644 --- a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c @@ -590,7 +590,7 @@ hci_driver_uart_dma_deinit(void) ESP_ERROR_CHECK(uart_driver_delete(s_hci_driver_uart_dma_env.hci_uart_params->hci_uart_port)); hci_driver_uart_dma_memory_deinit(); - if (!s_hci_driver_uart_dma_env.process_sem) { + if (s_hci_driver_uart_dma_env.process_sem) { vSemaphoreDelete(s_hci_driver_uart_dma_env.process_sem); } From 3d22ac034c61918c52b28485d4902135993585d4 Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Sun, 18 Jan 2026 04:26:00 +0800 Subject: [PATCH 31/84] fix(esp32p4): fix rom and ld misuse min_rev --- components/bootloader/subproject/CMakeLists.txt | 2 +- components/esp_rom/CMakeLists.txt | 15 +++++++-------- components/esp_system/ld/ld.cmake | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/components/bootloader/subproject/CMakeLists.txt b/components/bootloader/subproject/CMakeLists.txt index 6915038401..ffee61a76c 100644 --- a/components/bootloader/subproject/CMakeLists.txt +++ b/components/bootloader/subproject/CMakeLists.txt @@ -69,7 +69,7 @@ idf_build_set_property(__OUTPUT_SDKCONFIG 0) set(LD_DEFAULT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/main/ld/${IDF_TARGET}") idf_build_set_property(BOOTLOADER_LINKER_SCRIPT "${LD_DEFAULT_PATH}/bootloader.rom.ld" APPEND) project(bootloader) -if(CONFIG_ESP32P4_REV_MIN_300) +if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) target_linker_script("__idf_main" INTERFACE "${LD_DEFAULT_PATH}/bootloader.rev3.ld") else() target_linker_script("__idf_main" INTERFACE "${LD_DEFAULT_PATH}/bootloader.ld") diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 9be2ca49b7..e2c1801928 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -101,8 +101,7 @@ if(target STREQUAL "linux") target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-integer-overflow -Wno-shift-count-overflow) endif() else() - # TODO: IDF-13410. Update to (CONFIG_ESP32P4_REV_MIN_FULL GREATER_EQUAL 200) when chip efuse is correct. - if(CONFIG_ESP32P4_REV_MIN_300) + if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) target_linker_script(${COMPONENT_LIB} INTERFACE "${target_folder}/${ld_folder}/${target}.rom.eco5.ld") else() target_linker_script(${COMPONENT_LIB} INTERFACE "${target_folder}/${ld_folder}/${target}.rom.ld") @@ -115,13 +114,13 @@ else() endif() if(CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB) - if(CONFIG_ESP32P4_REV_MIN_300) # TODO: IDF-13410 + if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) rom_linker_script("eco5.libgcc") else() rom_linker_script("libgcc") endif() else() - if(CONFIG_ESP32P4_REV_MIN_300) # TODO: IDF-13410. + if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) rom_linker_script("eco5.rvfp") else() rom_linker_script("rvfp") @@ -167,7 +166,7 @@ if(BOOTLOADER_BUILD) if(target STREQUAL "esp32" OR target STREQUAL "esp32s2") rom_linker_script("libc-funcs") else() - if(CONFIG_ESP32P4_REV_MIN_300) # TODO: IDF-13410 + if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) rom_linker_script("eco5.libc") else() rom_linker_script("libc") @@ -177,7 +176,7 @@ if(BOOTLOADER_BUILD) rom_linker_script("libc-suboptimal_for_misaligned_mem") endif() if(CONFIG_LIBC_NEWLIB) - if(CONFIG_ESP32P4_REV_MIN_300) # TODO: IDF-13410 + if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) rom_linker_script("eco5.newlib") else() rom_linker_script("newlib") @@ -339,7 +338,7 @@ else() # Regular app build if(CONFIG_ESP_ROM_HAS_NEWLIB AND NOT target STREQUAL "esp32" AND NOT target STREQUAL "esp32s2") # ESP32 and S2 are a bit different, keep them as special cases in the target specific include section - if(CONFIG_ESP32P4_REV_MIN_300) # TODO: IDF-13410 + if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) rom_linker_script("eco5.libc") else() rom_linker_script("libc") @@ -348,7 +347,7 @@ else() # Regular app build rom_linker_script("libc-suboptimal_for_misaligned_mem") endif() if(CONFIG_LIBC_NEWLIB) - if(CONFIG_ESP32P4_REV_MIN_300) # TODO: IDF-13410 + if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) rom_linker_script("eco5.newlib") else() rom_linker_script("newlib") diff --git a/components/esp_system/ld/ld.cmake b/components/esp_system/ld/ld.cmake index 7ddc776c9a..9464a569ad 100644 --- a/components/esp_system/ld/ld.cmake +++ b/components/esp_system/ld/ld.cmake @@ -48,7 +48,7 @@ preprocess_linker_file("memory.ld.in" "memory.ld" ld_out_path) target_linker_script(${COMPONENT_LIB} INTERFACE "${ld_out_path}") # Generate sections.ld.in and pass it through linker script generator -if(CONFIG_ESP32P4_REV_MIN_300) +if(CONFIG_IDF_TARGET_ESP32P4 AND NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) preprocess_linker_file("sections.rev3.ld.in" "sections.ld.in" ld_out_path) else() preprocess_linker_file("sections.ld.in" "sections.ld.in" ld_out_path) From bb79e6f2460c078945fd41735f292dfd09c51e9b Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Sun, 18 Jan 2026 04:30:46 +0800 Subject: [PATCH 32/84] fix(esp32p4): fix efuse, encryption and other rev_min usage --- .../bootloader_support/src/flash_encrypt.c | 4 +-- .../efuse/esp32p4/include/esp_efuse_chip.h | 4 +-- .../efuse/esp32p4/include/esp_efuse_table.h | 2 +- components/efuse/esp32p4/sources.cmake | 2 +- .../esp32p4/Kconfig.p4_rev3_mspi_workaround | 4 +-- .../esp_hw_support/port/esp32p4/pmu_init.c | 4 +-- .../port/esp32p4/rtc_clk_init.c | 4 +-- .../mipi_dsi_lcd/main/test_mipi_dsi_panel.c | 2 +- components/esp_psram/system_layer/esp_psram.c | 11 +++++--- components/esp_system/port/cpu_start.c | 2 +- .../port/soc/esp32p4/system_internal.c | 25 +++++++++++-------- 11 files changed, 36 insertions(+), 28 deletions(-) diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c index 9e311b156d..baaa948226 100644 --- a/components/bootloader_support/src/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encrypt.c @@ -211,7 +211,7 @@ void esp_flash_encryption_set_release_mode(void) #endif // !CONFIG_IDF_TARGET_ESP32 #if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL < 300) -#ifdef SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND +#if SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) { uint8_t xts_pseudo_level = 0; esp_efuse_read_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count); @@ -485,7 +485,7 @@ bool esp_flash_encryption_cfg_verify_release_mode(void) result &= secure; #if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL < 300) -#if SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND +#if SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) { uint8_t xts_pseudo_level = 0; esp_efuse_read_field_blob(ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL, &xts_pseudo_level, ESP_EFUSE_XTS_DPA_PSEUDO_LEVEL[0]->bit_count); diff --git a/components/efuse/esp32p4/include/esp_efuse_chip.h b/components/efuse/esp32p4/include/esp_efuse_chip.h index b9e6bcc234..958fa239e9 100644 --- a/components/efuse/esp32p4/include/esp_efuse_chip.h +++ b/components/efuse/esp32p4/include/esp_efuse_chip.h @@ -66,7 +66,7 @@ typedef enum { ESP_EFUSE_KEY_PURPOSE_USER = 0, /**< User purposes (software-only use) */ ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY = 1, /**< ECDSA private key (Expected in little endian order)*/ -#if CONFIG_ESP32P4_REV_MIN_FULL >= 300 +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY_P256 = ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY, /**< ECDSA private key (P256) (Expected in little endian order)*/ #endif @@ -82,7 +82,7 @@ typedef enum { ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 = 11, /**< SECURE_BOOT_DIGEST2 (Secure Boot key digest) */ ESP_EFUSE_KEY_PURPOSE_KM_INIT_KEY = 12, /**< KM_INIT_KEY */ -#if CONFIG_ESP32P4_REV_MIN_FULL >= 300 +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_PSRAM_KEY_1 = 13, /**< PSRAM encryption key (XTS_AES_256_KEY_1) */ ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_PSRAM_KEY_2 = 14, /**< PSRAM encryption key (XTS_AES_256_KEY_2) */ ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_PSRAM_KEY = 15, /**< PSRAM encryption key (XTS_AES_128_KEY) */ diff --git a/components/efuse/esp32p4/include/esp_efuse_table.h b/components/efuse/esp32p4/include/esp_efuse_table.h index fed2072d5b..a2803f5bde 100644 --- a/components/efuse/esp32p4/include/esp_efuse_table.h +++ b/components/efuse/esp32p4/include/esp_efuse_table.h @@ -10,7 +10,7 @@ extern "C" { #include "sdkconfig.h" -#if CONFIG_ESP32P4_REV_MIN_FULL >= 300 +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 #include "esp_efuse_table_v3.0.h" #else #include "esp_efuse_table_v0.0_v2.0.h" diff --git a/components/efuse/esp32p4/sources.cmake b/components/efuse/esp32p4/sources.cmake index 7712caeded..7896c3d353 100644 --- a/components/efuse/esp32p4/sources.cmake +++ b/components/efuse/esp32p4/sources.cmake @@ -4,7 +4,7 @@ set(EFUSE_SOC_SRCS "esp_efuse_rtc_calib.c" ) -if(CONFIG_ESP32P4_REV_MIN_FULL GREATER_EQUAL 300) +if(NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) list(APPEND EFUSE_SOC_SRCS "esp_efuse_table_v3.0.c" ) diff --git a/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround b/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround index 5810818f79..8ff9ca2d65 100644 --- a/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround +++ b/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround @@ -1,10 +1,10 @@ config P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND bool depends on IDF_TARGET_ESP32P4 - default y if ESP32P4_REV_MIN_300 + default y if !ESP32P4_SELECTS_REV_LESS_V3 config P4_REV3_MSPI_WORKAROUND_SIZE hex depends on IDF_TARGET_ESP32P4 - default 0x100 if ESP32P4_REV_MIN_300 + default 0x100 if !ESP32P4_SELECTS_REV_LESS_V3 default 0 diff --git a/components/esp_hw_support/port/esp32p4/pmu_init.c b/components/esp_hw_support/port/esp32p4/pmu_init.c index 2a3b58e542..2dc70eda2f 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_init.c +++ b/components/esp_hw_support/port/esp32p4/pmu_init.c @@ -176,7 +176,7 @@ static void pmu_hp_system_init_default(pmu_context_t *ctx) pmu_hp_system_param_default(mode, ¶m); pmu_hp_system_init(ctx, mode, ¶m); } -#if CONFIG_ESP32P4_REV_MIN_FULL >= 300 +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 lp_sys_ll_set_hp_mem_lowpower_mode(MEM_AUX_DEEPSLEEP); #endif } @@ -195,7 +195,7 @@ static void pmu_lp_system_init_default(pmu_context_t *ctx) pmu_lp_system_param_default(mode, ¶m); pmu_lp_system_init(ctx, mode, ¶m); } -#if CONFIG_ESP32P4_REV_MIN_FULL >= 300 +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 lp_sys_ll_set_lp_mem_lowpower_mode(MEM_AUX_DEEPSLEEP); #endif } diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c index a49598ff2f..c0eaa0f5e0 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c @@ -68,7 +68,7 @@ void rtc_clk_init(rtc_clk_config_t cfg) hp_dcmvset = pvt_hp_dcmvset; } // Switch to DCDC -#if CONFIG_ESP32P4_REV_MIN_301 +#if (CONFIG_ESP32P4_REV_MIN_FULL >= 301) unsigned chip_version = efuse_hal_chip_revision(); if (ESP_CHIP_REV_ABOVE(chip_version, 301)) { SET_PERI_REG_MASK(PMU_DCM_CTRL_REG, PMU_DCDC_FB_RES_FORCE_PD); @@ -79,7 +79,7 @@ void rtc_clk_init(rtc_clk_config_t cfg) pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, hp_dcmvset); SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu esp_rom_delay_us(1000); -#if CONFIG_ESP32P4_REV_MIN_301 +#if (CONFIG_ESP32P4_REV_MIN_FULL >= 301) if (ESP_CHIP_REV_ABOVE(chip_version, 301)) { REG_SET_FIELD(LP_SYSTEM_REG_SYS_CTRL_REG, LP_SYSTEM_REG_LP_FIB_SEL, 0xEF);// lp_fib_sel bit4 set to 0: select dig_fib_reg instead of ana_fib_reg CLEAR_PERI_REG_MASK(PMU_DCM_CTRL_REG, PMU_DCDC_FB_RES_FORCE_PD); diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c index 5719c2ef23..ffb4d7dbe9 100644 --- a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c @@ -330,7 +330,7 @@ TEST_CASE("MIPI DSI draw YUV422 image (EK79007)", "[mipi_dsi]") test_bsp_disable_dsi_phy_power(); } -#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL < 300) +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 TEST_CASE("MIPI DSI draw Gray8 image (EK79007)", "[mipi_dsi]") { diff --git a/components/esp_psram/system_layer/esp_psram.c b/components/esp_psram/system_layer/esp_psram.c index 8b0251e1e7..1fcb016700 100644 --- a/components/esp_psram/system_layer/esp_psram.c +++ b/components/esp_psram/system_layer/esp_psram.c @@ -167,8 +167,9 @@ static void IRAM_ATTR s_mapping(int v_start, int size) } #endif //CONFIG_IDF_TARGET_ESP32 -#if CONFIG_ESP32P4_REV_MIN_FULL == 300 +#if CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 #include "hal/psram_ctrlr_ll.h" +#include "hal/efuse_hal.h" static void IRAM_ATTR esp_psram_p4_rev3_workaround(void) { spi_mem_s_dev_t backup_reg = {}; @@ -416,8 +417,12 @@ esp_err_t esp_psram_init(void) } } -#if CONFIG_ESP32P4_REV_MIN_FULL == 300 - esp_psram_p4_rev3_workaround(); +#if CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 + // This workaround is only needed for P4 rev 300 (3.0.0) + unsigned chip_revision = efuse_hal_chip_revision(); + if (chip_revision == 300) { + esp_psram_p4_rev3_workaround(); + } #endif uint32_t psram_available_size = 0; diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 8442310c41..2f7e148864 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -671,7 +671,7 @@ NOINLINE_ATTR static void system_early_init(const soc_reset_reason_t *rst_reas) REG_CLR_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RESETING); #endif #elif CONFIG_IDF_TARGET_ESP32P4 -#if CONFIG_ESP32P4_REV_MIN_FULL >= 300 +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 // In single core mode, the CPU system should ignore the WFI state of core1 when entering WFI autoclock gating mode. REG_CLR_BIT(HP_SYS_CLKRST_CPU_WAITI_CTRL0_REG, HP_SYS_CLKRST_REG_CORE1_WAITI_ICG_EN); #endif diff --git a/components/esp_system/port/soc/esp32p4/system_internal.c b/components/esp_system/port/soc/esp32p4/system_internal.c index a96eb7e45d..80e7feec77 100644 --- a/components/esp_system/port/soc/esp32p4/system_internal.c +++ b/components/esp_system/port/soc/esp32p4/system_internal.c @@ -32,6 +32,7 @@ #include "hal/axi_dma_ll.h" #include "hal/dw_gdma_ll.h" #include "hal/dma2d_ll.h" +#include "hal/efuse_hal.h" void esp_system_reset_modules_on_exit(void) { @@ -123,19 +124,21 @@ void esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_RSA); CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_SHA); -#if CONFIG_ESP32P4_REV_MIN_FULL <= 100 - // enable soc clk and reset parent crypto - SET_PERI_REG_MASK(HP_SYS_CLKRST_SOC_CLK_CTRL1_REG, HP_SYS_CLKRST_REG_CRYPTO_SYS_CLK_EN); - SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_CRYPTO); - CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_CRYPTO); +#if CONFIG_ESP32P4_REV_MIN_FULL < 101 + if (efuse_hal_chip_revision() < 101) { + // enable soc clk and reset parent crypto + SET_PERI_REG_MASK(HP_SYS_CLKRST_SOC_CLK_CTRL1_REG, HP_SYS_CLKRST_REG_CRYPTO_SYS_CLK_EN); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_CRYPTO); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_CRYPTO); - // enable soc clk for key manager - SET_PERI_REG_MASK(HP_SYS_CLKRST_SOC_CLK_CTRL1_REG, HP_SYS_CLKRST_REG_KEY_MANAGER_SYS_CLK_EN); + // enable soc clk for key manager + SET_PERI_REG_MASK(HP_SYS_CLKRST_SOC_CLK_CTRL1_REG, HP_SYS_CLKRST_REG_KEY_MANAGER_SYS_CLK_EN); - // enable key manager peripheral clock and reset - SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_CRYPTO_KM_CLK_EN); - SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_KM); - CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_KM); + // enable key manager peripheral clock and reset + SET_PERI_REG_MASK(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_CRYPTO_KM_CLK_EN); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_KM); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_KM); + } #endif #if CONFIG_ESP32P4_REV_MIN_FULL == 0 From e8814fc0f151d4f8a27c322476f1e26250cf5d8d Mon Sep 17 00:00:00 2001 From: armando Date: Mon, 19 Jan 2026 13:14:30 +0800 Subject: [PATCH 33/84] feat(p4): changed to rev3.1 by default --- .../port/esp32p4/Kconfig.p4_rev3_mspi_workaround | 2 +- .../esp_hw_support/port/esp32p4/Kconfig.hw_support | 6 +++--- components/esp_hw_support/port/esp32p4/pmu_sleep.c | 8 ++++++-- .../esp_hw_support/port/esp32p4/rtc_clk_init.c | 12 +++++++----- components/soc/include/soc/chip_revision.h | 2 ++ 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround b/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround index 8ff9ca2d65..50ed53a400 100644 --- a/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround +++ b/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround @@ -1,7 +1,7 @@ config P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND bool depends on IDF_TARGET_ESP32P4 - default y if !ESP32P4_SELECTS_REV_LESS_V3 + default y if !ESP32P4_SELECTS_REV_LESS_V3 # Fixed since REV3.1 config P4_REV3_MSPI_WORKAROUND_SIZE hex diff --git a/components/esp_hw_support/port/esp32p4/Kconfig.hw_support b/components/esp_hw_support/port/esp32p4/Kconfig.hw_support index 779fb19e95..9236f41d8c 100644 --- a/components/esp_hw_support/port/esp32p4/Kconfig.hw_support +++ b/components/esp_hw_support/port/esp32p4/Kconfig.hw_support @@ -3,8 +3,7 @@ comment "Read the help text of the option below for explanation" config ESP32P4_SELECTS_REV_LESS_V3 bool "Select ESP32-P4 revisions <3.0 (No >=3.x Support)" - default n if IDF_CI_BUILD - default y + default n help Select this option to support ESP32-P4 revisions 0.x and 1.x. Revisions higher than 3.0 (included) and revisions less than 3.0 @@ -13,7 +12,8 @@ config ESP32P4_SELECTS_REV_LESS_V3 choice ESP32P4_REV_MIN prompt "Minimum Supported ESP32-P4 Revision" - default ESP32P4_REV_MIN_1 + default ESP32P4_REV_MIN_300 if IDF_CI_BUILD + default ESP32P4_REV_MIN_301 help Required minimum chip revision. ESP-IDF will check for it and reject to boot if the chip revision fails the check. diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 1d0330180e..e54715e8a5 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -425,7 +425,9 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, } } else { #if CONFIG_P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND + if (efuse_hal_chip_revision() == 300) { lp_clkrst_ll_boot_from_lp_ram(true); + } #endif } @@ -456,8 +458,10 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, ldo_ll_enable(LDO_ID2UNIT(CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN), true); #endif #if CONFIG_P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND - // Set reset vector back to HP ROM after deepsleep request rejected - lp_clkrst_ll_boot_from_lp_ram(false); + if (efuse_hal_chip_revision() == 300) { + // Set reset vector back to HP ROM after deepsleep request rejected + lp_clkrst_ll_boot_from_lp_ram(false); + } #endif } diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c index c0eaa0f5e0..6a88840899 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -68,9 +68,10 @@ void rtc_clk_init(rtc_clk_config_t cfg) hp_dcmvset = pvt_hp_dcmvset; } // Switch to DCDC -#if (CONFIG_ESP32P4_REV_MIN_FULL >= 301) +#if (CONFIG_ESP32P4_REV_MIN_FULL >= 300) unsigned chip_version = efuse_hal_chip_revision(); - if (ESP_CHIP_REV_ABOVE(chip_version, 301)) { + if (ESP_CHIP_REV_BETWEEN(chip_version, 300, 301)) { + // This workaround is only needed for P4 rev3.1 SET_PERI_REG_MASK(PMU_DCM_CTRL_REG, PMU_DCDC_FB_RES_FORCE_PD); } #endif @@ -79,8 +80,9 @@ void rtc_clk_init(rtc_clk_config_t cfg) pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, hp_dcmvset); SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu esp_rom_delay_us(1000); -#if (CONFIG_ESP32P4_REV_MIN_FULL >= 301) - if (ESP_CHIP_REV_ABOVE(chip_version, 301)) { +#if (CONFIG_ESP32P4_REV_MIN_FULL >= 300) + if (ESP_CHIP_REV_BETWEEN(chip_version, 300, 301)) { + // This workaround is only needed for P4 rev3.1 REG_SET_FIELD(LP_SYSTEM_REG_SYS_CTRL_REG, LP_SYSTEM_REG_LP_FIB_SEL, 0xEF);// lp_fib_sel bit4 set to 0: select dig_fib_reg instead of ana_fib_reg CLEAR_PERI_REG_MASK(PMU_DCM_CTRL_REG, PMU_DCDC_FB_RES_FORCE_PD); esp_rom_delay_us(10); diff --git a/components/soc/include/soc/chip_revision.h b/components/soc/include/soc/chip_revision.h index 3654469ef4..373c5ee30a 100644 --- a/components/soc/include/soc/chip_revision.h +++ b/components/soc/include/soc/chip_revision.h @@ -29,12 +29,14 @@ extern "C" { */ #define ESP_CHIP_REV_ABOVE(rev, min_rev) ((min_rev) <= (rev)) +#define ESP_CHIP_REV_BETWEEN(rev, min_rev, max_rev) (((min_rev) <= (rev)) && ((rev) <= (max_rev))) #define ESP_CHIP_REV_MAJOR_AND_ABOVE(rev, min_rev) (((rev) / 100 == (min_rev) / 100) && ((rev) >= (min_rev))) /** * eFuse block revision strategy is same as chip revision */ #define ESP_EFUSE_BLK_REV_ABOVE(rev, min_rev) ESP_CHIP_REV_ABOVE(rev, min_rev) +#define ESP_EFUSE_BLK_REV_BETWEEN(rev, min_rev, max_rev) ESP_CHIP_REV_BETWEEN(rev, min_rev, max_rev) #define ESP_EFUSE_BLK_REV_MAJOR_AND_ABOVE(rev, min_rev) ESP_CHIP_REV_MAJOR_AND_ABOVE(rev, min_rev) #ifdef __cplusplus From c65cf33daed345f852099293b409c0290c679642 Mon Sep 17 00:00:00 2001 From: liuning Date: Sat, 11 Oct 2025 11:43:39 +0800 Subject: [PATCH 34/84] bugfix(wifi): fix incomplete phy initialization due to absence of bb clocks at coexistence scenarios --- .../include/esp_private/periph_ctrl.h | 14 ++++ components/esp_hw_support/modem_clock.c | 17 ++++- components/esp_hw_support/periph_ctrl.c | 69 ++++++++++++++++++- components/esp_phy/src/phy_init.c | 24 +------ components/esp_phy/src/phy_init_esp32hxx.c | 3 + .../hal/esp32/include/hal/clk_gate_ll.h | 10 +++ .../hal/esp32c2/include/hal/clk_gate_ll.h | 12 ++++ .../hal/esp32c3/include/hal/clk_gate_ll.h | 12 ++++ .../hal/esp32s2/include/hal/clk_gate_ll.h | 12 ++++ .../hal/esp32s3/include/hal/clk_gate_ll.h | 12 ++++ .../soc/esp32/include/soc/periph_defs.h | 1 + .../soc/esp32c2/include/soc/periph_defs.h | 1 + .../soc/esp32c2/register/soc/syscon_reg.h | 2 + .../soc/esp32c3/include/soc/periph_defs.h | 1 + .../soc/esp32c3/register/soc/syscon_reg.h | 2 + .../soc/esp32c6/include/soc/periph_defs.h | 3 +- .../soc/esp32h2/include/soc/periph_defs.h | 3 +- .../soc/esp32h21/include/soc/periph_defs.h | 3 +- .../soc/esp32h4/include/soc/periph_defs.h | 4 +- .../soc/esp32s2/include/soc/periph_defs.h | 1 + .../soc/esp32s2/register/soc/syscon_reg.h | 3 + .../soc/esp32s3/include/soc/periph_defs.h | 1 + .../soc/esp32s3/register/soc/syscon_reg.h | 2 + 23 files changed, 181 insertions(+), 31 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/periph_ctrl.h b/components/esp_hw_support/include/esp_private/periph_ctrl.h index a126750ba1..fad1b8166d 100644 --- a/components/esp_hw_support/include/esp_private/periph_ctrl.h +++ b/components/esp_hw_support/include/esp_private/periph_ctrl.h @@ -153,6 +153,20 @@ void wifi_module_enable(void); */ void wifi_module_disable(void); +/** + * @brief Enable phy module by un-gating related clock and de-asserting the reset signal. + * + * @note This function acquires clocks required during the PHY enable sequence. + */ +void phy_module_enable(void); + +/** + * @brief Disable phy module by gating related clock and asserting the reset signal. + * + * @note This function releases clocks required during the PHY enable sequence. + */ +void phy_module_disable(void); + #undef __PERIPH_CTRL_DEPRECATE_ATTR #ifdef __cplusplus diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index 64430bf902..7ed372685a 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -311,8 +311,21 @@ void IRAM_ATTR modem_clock_module_mac_reset(periph_module_t module) #define MODEM_ETM_CLOCK_DEPS (BIT(MODEM_CLOCK_ETM)) #define MODEM_ADC_COMMON_FE_CLOCK_DEPS (BIT(MODEM_CLOCK_MODEM_ADC_COMMON_FE)) #if SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT -#define PHY_CALIBRATION_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_APB) | BIT(MODEM_CLOCK_WIFI_BB_44M)) +#define PHY_CALIBRATION_WIFI_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_MAC) | BIT(MODEM_CLOCK_WIFI_APB) | BIT(MODEM_CLOCK_WIFI_BB) | BIT(MODEM_CLOCK_WIFI_BB_44M)) +#define PHY_CALIBRATION_BT_I154_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_APB) | BIT(MODEM_CLOCK_WIFI_BB_44M) | BIT(MODEM_CLOCK_BT_I154_COMMON_BB)) +#else +#define PHY_CALIBRATION_WIFI_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_MAC) | BIT(MODEM_CLOCK_WIFI_BB)) +#define PHY_CALIBRATION_BT_I154_CLOCK_DEPS (BIT(MODEM_CLOCK_BT_I154_COMMON_BB)) #endif +#ifndef SOC_WIFI_SUPPORTED +#undef PHY_CALIBRATION_WIFI_CLOCK_DEPS +#define PHY_CALIBRATION_WIFI_CLOCK_DEPS 0 +#endif +#if !defined(SOC_BT_SUPPORTED) && !defined(SOC_IEEE802154_SUPPORTED) +#undef PHY_CALIBRATION_BT_I154_CLOCK_DEPS +#define PHY_CALIBRATION_BT_I154_CLOCK_DEPS 0 +#endif +#define PHY_CALIBRATION_CLOCK_DEPS (PHY_CALIBRATION_WIFI_CLOCK_DEPS | PHY_CALIBRATION_BT_I154_CLOCK_DEPS) static IRAM_ATTR uint32_t modem_clock_get_module_deps(periph_module_t module) { @@ -330,9 +343,7 @@ static IRAM_ATTR uint32_t modem_clock_get_module_deps(periph_module_t module) #if SOC_BT_SUPPORTED case PERIPH_BT_MODULE: deps = BLE_CLOCK_DEPS; break; #endif -#if SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT case PERIPH_PHY_CALIBRATION_MODULE: deps = PHY_CALIBRATION_CLOCK_DEPS; break; -#endif #if SOC_IEEE802154_SUPPORTED case PERIPH_IEEE802154_MODULE: deps = IEEE802154_CLOCK_DEPS; break; #endif diff --git a/components/esp_hw_support/periph_ctrl.c b/components/esp_hw_support/periph_ctrl.c index 3aeacc32fc..1f36791272 100644 --- a/components/esp_hw_support/periph_ctrl.c +++ b/components/esp_hw_support/periph_ctrl.c @@ -130,7 +130,10 @@ void wifi_module_enable(void) modem_clock_module_enable(PERIPH_WIFI_MODULE); #else portENTER_CRITICAL_SAFE(&periph_spinlock); - periph_ll_wifi_module_enable_clk_clear_rst(); + if (ref_counts[PERIPH_WIFI_MODULE] == 0) { + periph_ll_wifi_module_enable_clk_clear_rst(); + } + ref_counts[PERIPH_WIFI_MODULE]++; portEXIT_CRITICAL_SAFE(&periph_spinlock); #endif } @@ -141,8 +144,70 @@ void wifi_module_disable(void) modem_clock_module_disable(PERIPH_WIFI_MODULE); #else portENTER_CRITICAL_SAFE(&periph_spinlock); - periph_ll_wifi_module_disable_clk_set_rst(); + ref_counts[PERIPH_WIFI_MODULE]--; + if (ref_counts[PERIPH_WIFI_MODULE] == 0) { + periph_ll_wifi_module_disable_clk_set_rst(); + } portEXIT_CRITICAL_SAFE(&periph_spinlock); #endif } #endif // CONFIG_ESP_WIFI_ENABLED + +#if SOC_BT_SUPPORTED || SOC_WIFI_SUPPORTED || SOC_IEEE802154_SUPPORTED +// PERIPH_WIFI_BT_COMMON_MODULE is enabled outside +IRAM_ATTR void phy_module_enable(void) +{ +#if SOC_MODEM_CLOCK_IS_INDEPENDENT + modem_clock_module_enable(PERIPH_PHY_CALIBRATION_MODULE); +#else + portENTER_CRITICAL_SAFE(&periph_spinlock); +#if SOC_WIFI_SUPPORTED || SOC_BT_SUPPORTED + periph_ll_phy_calibration_module_enable_clk_clear_rst(); + if (ref_counts[PERIPH_RNG_MODULE] == 0) { + periph_ll_enable_clk_clear_rst(PERIPH_RNG_MODULE); + } + ref_counts[PERIPH_RNG_MODULE]++; +#endif +#if SOC_WIFI_SUPPORTED + if (ref_counts[PERIPH_WIFI_MODULE] == 0) { + periph_ll_wifi_module_enable_clk_clear_rst(); + } + ref_counts[PERIPH_WIFI_MODULE]++; +#endif +#if SOC_BT_SUPPORTED + if (ref_counts[PERIPH_BT_MODULE] == 0) { + periph_ll_enable_clk_clear_rst(PERIPH_BT_MODULE); + } + ref_counts[PERIPH_BT_MODULE]++; +#endif + portEXIT_CRITICAL_SAFE(&periph_spinlock); +#endif +} + +// PERIPH_WIFI_BT_COMMON_MODULE is disabled outside +IRAM_ATTR void phy_module_disable(void) +{ +#if SOC_MODEM_CLOCK_IS_INDEPENDENT + modem_clock_module_disable(PERIPH_PHY_CALIBRATION_MODULE); +#else + portENTER_CRITICAL_SAFE(&periph_spinlock); +#if SOC_BT_SUPPORTED + ref_counts[PERIPH_BT_MODULE]--; + if (ref_counts[PERIPH_BT_MODULE] == 0) { + periph_ll_disable_clk_set_rst(PERIPH_BT_MODULE); + } +#endif +#if SOC_WIFI_SUPPORTED + ref_counts[PERIPH_WIFI_MODULE]--; + if (ref_counts[PERIPH_WIFI_MODULE] == 0) { + periph_ll_wifi_module_disable_clk_set_rst(); + } +#endif +#if SOC_WIFI_SUPPORTED || SOC_BT_SUPPORTED + // Do not disable PHY clock and RNG clock + ref_counts[PERIPH_RNG_MODULE]--; +#endif + portEXIT_CRITICAL_SAFE(&periph_spinlock); +#endif +} +#endif //#if SOC_BT_SUPPORTED || SOC_WIFI_SUPPORTED || SOC_IEEE802154_SUPPORTED diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index 5a3858ebe6..4d97c1ebc0 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -272,22 +272,6 @@ IRAM_ATTR void esp_phy_common_clock_disable(void) wifi_bt_common_module_disable(); } -#if SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT -IRAM_ATTR void esp_phy_calibration_clock_enable(esp_phy_modem_t modem) -{ - if (modem == PHY_MODEM_BT || modem == PHY_MODEM_IEEE802154) { - modem_clock_module_enable(PERIPH_PHY_CALIBRATION_MODULE); - } -} - -IRAM_ATTR void esp_phy_calibration_clock_disable(esp_phy_modem_t modem) -{ - if (modem == PHY_MODEM_BT || modem == PHY_MODEM_IEEE802154) { - modem_clock_module_disable(PERIPH_PHY_CALIBRATION_MODULE); - } -} -#endif - #if SOC_PM_MODEM_RETENTION_BY_BACKUPDMA static inline void phy_digital_regs_store(void) { @@ -316,9 +300,7 @@ void esp_phy_enable(esp_phy_modem_t modem) phy_update_wifi_mac_time(false, s_phy_rf_en_ts); #endif esp_phy_common_clock_enable(); -#if SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT - esp_phy_calibration_clock_enable(modem); -#endif + phy_module_enable(); if (s_is_phy_calibrated == false) { esp_phy_load_cal_and_init(); s_is_phy_calibrated = true; @@ -360,9 +342,7 @@ void esp_phy_enable(esp_phy_modem_t modem) phy_ant_update(); phy_ant_clr_update_flag(); } -#if SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT - esp_phy_calibration_clock_disable(modem); -#endif + phy_module_disable(); } phy_set_modem_flag(modem); #if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_ESP_PHY_DISABLE_PLL_TRACK diff --git a/components/esp_phy/src/phy_init_esp32hxx.c b/components/esp_phy/src/phy_init_esp32hxx.c index a3de469155..83000c57a9 100644 --- a/components/esp_phy/src/phy_init_esp32hxx.c +++ b/components/esp_phy/src/phy_init_esp32hxx.c @@ -9,6 +9,7 @@ #include "esp_phy_init.h" #include "esp_private/phy.h" #include "esp_timer.h" +#include "esp_private/periph_ctrl.h" #if SOC_MODEM_CLOCK_IS_INDEPENDENT #include "esp_private/esp_modem_clock.h" @@ -106,6 +107,7 @@ void esp_phy_enable(esp_phy_modem_t modem) #if SOC_MODEM_CLOCK_IS_INDEPENDENT modem_clock_module_enable(PERIPH_PHY_MODULE); #endif + phy_module_enable(); if (!s_phy_is_enabled) { register_chipv7_phy(NULL, NULL, PHY_RF_CAL_FULL); phy_version_print(); @@ -116,6 +118,7 @@ void esp_phy_enable(esp_phy_modem_t modem) #if !CONFIG_ESP_PHY_DISABLE_PLL_TRACK phy_track_pll_init(); #endif + phy_module_disable(); } phy_set_modem_flag(modem); // Immediately track pll when phy enabled. diff --git a/components/hal/esp32/include/hal/clk_gate_ll.h b/components/hal/esp32/include/hal/clk_gate_ll.h index 56aaadc77d..1ba86097c6 100644 --- a/components/hal/esp32/include/hal/clk_gate_ll.h +++ b/components/hal/esp32/include/hal/clk_gate_ll.h @@ -266,6 +266,16 @@ static inline void periph_ll_wifi_module_disable_clk_set_rst(void) DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0); } +static inline void periph_ll_phy_calibration_module_enable_clk_clear_rst(void) +{ + // No clock bit only for phy calibration on ESP32 +} + +static inline void periph_ll_phy_calibration_module_disable_clk_set_rst(void) +{ + // No clock bit only for phy calibration on ESP32 +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c2/include/hal/clk_gate_ll.h b/components/hal/esp32c2/include/hal/clk_gate_ll.h index 9e36fb4d14..f91522ebf9 100644 --- a/components/hal/esp32c2/include/hal/clk_gate_ll.h +++ b/components/hal/esp32c2/include/hal/clk_gate_ll.h @@ -214,6 +214,18 @@ static inline void periph_ll_wifi_module_disable_clk_set_rst(void) DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); } +static inline void periph_ll_phy_calibration_module_enable_clk_clear_rst(void) +{ + DPORT_SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_PHY_EN_M); + DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + +static inline void periph_ll_phy_calibration_module_disable_clk_set_rst(void) +{ + DPORT_CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_PHY_EN_M); + DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/clk_gate_ll.h b/components/hal/esp32c3/include/hal/clk_gate_ll.h index daf544184b..c32432e19c 100644 --- a/components/hal/esp32c3/include/hal/clk_gate_ll.h +++ b/components/hal/esp32c3/include/hal/clk_gate_ll.h @@ -263,6 +263,18 @@ static inline void periph_ll_wifi_module_disable_clk_set_rst(void) DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); } +static inline void periph_ll_phy_calibration_module_enable_clk_clear_rst(void) +{ + DPORT_SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_PHY_EN_M); + DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + +static inline void periph_ll_phy_calibration_module_disable_clk_set_rst(void) +{ + DPORT_CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_PHY_EN_M); + DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/clk_gate_ll.h b/components/hal/esp32s2/include/hal/clk_gate_ll.h index 82725b9c59..4777a9bd7d 100644 --- a/components/hal/esp32s2/include/hal/clk_gate_ll.h +++ b/components/hal/esp32s2/include/hal/clk_gate_ll.h @@ -277,6 +277,18 @@ static inline void periph_ll_wifi_module_disable_clk_set_rst(void) DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0); } +static inline void periph_ll_phy_calibration_module_enable_clk_clear_rst(void) +{ + DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_PHY_EN_M); + DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0); +} + +static inline void periph_ll_phy_calibration_module_disable_clk_set_rst(void) +{ + DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_PHY_EN_M); + DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/clk_gate_ll.h b/components/hal/esp32s3/include/hal/clk_gate_ll.h index 0d43fd4bb8..b2007ec964 100644 --- a/components/hal/esp32s3/include/hal/clk_gate_ll.h +++ b/components/hal/esp32s3/include/hal/clk_gate_ll.h @@ -298,6 +298,18 @@ static inline void periph_ll_wifi_module_disable_clk_set_rst(void) DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); } +static inline void periph_ll_phy_calibration_module_enable_clk_clear_rst(void) +{ + DPORT_SET_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_PHY_EN_M); + DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + +static inline void periph_ll_phy_calibration_module_disable_clk_set_rst(void) +{ + DPORT_CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_PHY_EN_M); + DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0); +} + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32/include/soc/periph_defs.h b/components/soc/esp32/include/soc/periph_defs.h index da81a70d59..09bb66287c 100644 --- a/components/soc/esp32/include/soc/periph_defs.h +++ b/components/soc/esp32/include/soc/periph_defs.h @@ -46,6 +46,7 @@ typedef enum { PERIPH_SHA_MODULE, PERIPH_RSA_MODULE, PERIPH_SARADC_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX } periph_module_t; diff --git a/components/soc/esp32c2/include/soc/periph_defs.h b/components/soc/esp32c2/include/soc/periph_defs.h index fffb80134a..e3ee27848c 100644 --- a/components/soc/esp32c2/include/soc/periph_defs.h +++ b/components/soc/esp32c2/include/soc/periph_defs.h @@ -37,6 +37,7 @@ typedef enum { PERIPH_TEMPSENSOR_MODULE, PERIPH_MODEM_RPA_MODULE, PERIPH_ASSIST_DEBUG_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX } periph_module_t; diff --git a/components/soc/esp32c2/register/soc/syscon_reg.h b/components/soc/esp32c2/register/soc/syscon_reg.h index 3bebe8268e..2f3732609a 100644 --- a/components/soc/esp32c2/register/soc/syscon_reg.h +++ b/components/soc/esp32c2/register/soc/syscon_reg.h @@ -178,6 +178,8 @@ extern "C" { #define SYSTEM_WIFI_CLK_BT_EN_S 0 /* Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, 19, 20, 21, 22, 23 */ #define SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M 0x78078F +/* Mask for clock bits used by phy calibration, bit 22, 29, 30, 31 */ +#define SYSTEM_WIFI_CLK_PHY_EN_M 0xE0400000 /* Digital team to check */ //bluetooth baseband bit11 diff --git a/components/soc/esp32c3/include/soc/periph_defs.h b/components/soc/esp32c3/include/soc/periph_defs.h index 708ec23a83..7e1f2b3b3b 100644 --- a/components/soc/esp32c3/include/soc/periph_defs.h +++ b/components/soc/esp32c3/include/soc/periph_defs.h @@ -42,6 +42,7 @@ typedef enum { PERIPH_SARADC_MODULE, PERIPH_TEMPSENSOR_MODULE, PERIPH_ASSIST_DEBUG_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX } periph_module_t; diff --git a/components/soc/esp32c3/register/soc/syscon_reg.h b/components/soc/esp32c3/register/soc/syscon_reg.h index 8c6103aee2..8e63e6b0c3 100644 --- a/components/soc/esp32c3/register/soc/syscon_reg.h +++ b/components/soc/esp32c3/register/soc/syscon_reg.h @@ -177,6 +177,8 @@ extern "C" { #define SYSTEM_WIFI_CLK_BT_EN_S 0 /* Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, 19, 20, 21, 22, 23 */ #define SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M 0x78078F +/* Mask for clock bits used by phy calibration, bit 22 */ +#define SYSTEM_WIFI_CLK_PHY_EN_M 0x400000 /* Digital team to check */ //bluetooth baseband bit11 diff --git a/components/soc/esp32c6/include/soc/periph_defs.h b/components/soc/esp32c6/include/soc/periph_defs.h index 65cb21953c..ede5f3112d 100644 --- a/components/soc/esp32c6/include/soc/periph_defs.h +++ b/components/soc/esp32c6/include/soc/periph_defs.h @@ -57,12 +57,13 @@ typedef enum { PERIPH_ANA_I2C_MASTER_MODULE, PERIPH_MODEM_ETM_MODULE, PERIPH_MODEM_ADC_COMMON_FE_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX /* !!! Don't append soc modules here !!! */ } periph_module_t; #define PERIPH_MODEM_MODULE_MIN PERIPH_WIFI_MODULE -#define PERIPH_MODEM_MODULE_MAX PERIPH_MODEM_ADC_COMMON_FE_MODULE +#define PERIPH_MODEM_MODULE_MAX PERIPH_PHY_CALIBRATION_MODULE #define PERIPH_MODEM_MODULE_NUM (PERIPH_MODEM_MODULE_MAX - PERIPH_MODEM_MODULE_MIN + 1) #define IS_MODEM_MODULE(periph) ((periph>=PERIPH_MODEM_MODULE_MIN) && (periph<=PERIPH_MODEM_MODULE_MAX)) diff --git a/components/soc/esp32h2/include/soc/periph_defs.h b/components/soc/esp32h2/include/soc/periph_defs.h index 01faf4437c..04b1554bfb 100644 --- a/components/soc/esp32h2/include/soc/periph_defs.h +++ b/components/soc/esp32h2/include/soc/periph_defs.h @@ -52,12 +52,13 @@ typedef enum { PERIPH_ANA_I2C_MASTER_MODULE, PERIPH_MODEM_ETM_MODULE, PERIPH_MODEM_ADC_COMMON_FE_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX /* !!! Don't append soc modules here !!! */ } periph_module_t; #define PERIPH_MODEM_MODULE_MIN PERIPH_BT_MODULE -#define PERIPH_MODEM_MODULE_MAX PERIPH_MODEM_ADC_COMMON_FE_MODULE +#define PERIPH_MODEM_MODULE_MAX PERIPH_PHY_CALIBRATION_MODULE #define PERIPH_MODEM_MODULE_NUM (PERIPH_MODEM_MODULE_MAX - PERIPH_MODEM_MODULE_MIN + 1) #define IS_MODEM_MODULE(periph) ((periph>=PERIPH_MODEM_MODULE_MIN) && (periph<=PERIPH_MODEM_MODULE_MAX)) diff --git a/components/soc/esp32h21/include/soc/periph_defs.h b/components/soc/esp32h21/include/soc/periph_defs.h index 9044603a06..757beeed8d 100644 --- a/components/soc/esp32h21/include/soc/periph_defs.h +++ b/components/soc/esp32h21/include/soc/periph_defs.h @@ -53,12 +53,13 @@ typedef enum { PERIPH_ANA_I2C_MASTER_MODULE, PERIPH_MODEM_ETM_MODULE, PERIPH_MODEM_ADC_COMMON_FE_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX /* !!! Don't append soc modules here !!! */ } periph_module_t; #define PERIPH_MODEM_MODULE_MIN PERIPH_BT_MODULE -#define PERIPH_MODEM_MODULE_MAX PERIPH_MODEM_ADC_COMMON_FE_MODULE +#define PERIPH_MODEM_MODULE_MAX PERIPH_PHY_CALIBRATION_MODULE #define PERIPH_MODEM_MODULE_NUM (PERIPH_MODEM_MODULE_MAX - PERIPH_MODEM_MODULE_MIN + 1) #define IS_MODEM_MODULE(periph) ((periph>=PERIPH_MODEM_MODULE_MIN) && (periph<=PERIPH_MODEM_MODULE_MAX)) diff --git a/components/soc/esp32h4/include/soc/periph_defs.h b/components/soc/esp32h4/include/soc/periph_defs.h index 6a79279d72..8d2a7937d4 100644 --- a/components/soc/esp32h4/include/soc/periph_defs.h +++ b/components/soc/esp32h4/include/soc/periph_defs.h @@ -58,12 +58,14 @@ typedef enum { PERIPH_ANA_I2C_MASTER_MODULE, PERIPH_MODEM_ETM_MODULE, PERIPH_MODEM_ADC_COMMON_FE_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX /* !!! Don't append soc modules here !!! */ } periph_module_t; #define PERIPH_MODEM_MODULE_MIN PERIPH_WIFI_MODULE -#define PERIPH_MODEM_MODULE_MAX PERIPH_MODEM_ADC_COMMON_FE_MODULE +#define PERIPH_MODEM_MODULE_MAX PERIPH_PHY_CALIBRATION_MODULE + #define PERIPH_MODEM_MODULE_NUM (PERIPH_MODEM_MODULE_MAX - PERIPH_MODEM_MODULE_MIN + 1) #define IS_MODEM_MODULE(periph) ((periph>=PERIPH_MODEM_MODULE_MIN) && (periph<=PERIPH_MODEM_MODULE_MAX)) diff --git a/components/soc/esp32s2/include/soc/periph_defs.h b/components/soc/esp32s2/include/soc/periph_defs.h index 9616810f32..082c41477f 100644 --- a/components/soc/esp32s2/include/soc/periph_defs.h +++ b/components/soc/esp32s2/include/soc/periph_defs.h @@ -45,6 +45,7 @@ typedef enum { PERIPH_DEDIC_GPIO_MODULE, PERIPH_SARADC_MODULE, PERIPH_TEMPSENSOR_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX } periph_module_t; diff --git a/components/soc/esp32s2/register/soc/syscon_reg.h b/components/soc/esp32s2/register/soc/syscon_reg.h index 129ac57f2b..8af2536372 100644 --- a/components/soc/esp32s2/register/soc/syscon_reg.h +++ b/components/soc/esp32s2/register/soc/syscon_reg.h @@ -445,6 +445,9 @@ extern "C" { /* Mask for clock bits used by both WIFI and Bluetooth, bit 0, 3, 6, 7, 8, 9 */ #define SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M 0x000003c9 #define DPORT_WIFI_CLK_WIFI_BT_COMMON_M SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M +/* Mask for clock bits used by phy calibration, bit 22 */ +#define SYSTEM_WIFI_CLK_PHY_EN_M 0x400000 +#define DPORT_WIFI_CLK_PHY_EN_M SYSTEM_WIFI_CLK_PHY_EN_M /* Digital team to check */ //bluetooth baseband bit11 diff --git a/components/soc/esp32s3/include/soc/periph_defs.h b/components/soc/esp32s3/include/soc/periph_defs.h index ca93c51cbe..a78d5dd185 100644 --- a/components/soc/esp32s3/include/soc/periph_defs.h +++ b/components/soc/esp32s3/include/soc/periph_defs.h @@ -54,6 +54,7 @@ typedef enum { PERIPH_DEDIC_GPIO_MODULE, PERIPH_SARADC_MODULE, PERIPH_TEMPSENSOR_MODULE, + PERIPH_PHY_CALIBRATION_MODULE, PERIPH_MODULE_MAX } periph_module_t; diff --git a/components/soc/esp32s3/register/soc/syscon_reg.h b/components/soc/esp32s3/register/soc/syscon_reg.h index 75a58fcdb5..edddc0302c 100644 --- a/components/soc/esp32s3/register/soc/syscon_reg.h +++ b/components/soc/esp32s3/register/soc/syscon_reg.h @@ -178,6 +178,8 @@ extern "C" { #define SYSTEM_WIFI_CLK_BT_EN_S 0 /* Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, 19, 20, 21, 22, 23 */ #define SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M 0x78078F +/* Mask for clock bits used by phy calibration, bit 22 */ +#define SYSTEM_WIFI_CLK_PHY_EN_M 0x400000 //bluetooth baseband bit11 #define SYSTEM_BT_BASEBAND_EN BIT(11) From 824a30a11a6d6e2be218906f0f17671b0f5cc076 Mon Sep 17 00:00:00 2001 From: liuning Date: Tue, 18 Nov 2025 14:15:48 +0800 Subject: [PATCH 35/84] feat(phy): add check for required clock bits during phy enable --- .../include/esp_private/esp_modem_clock.h | 12 ++++++++++ .../include/esp_private/periph_ctrl.h | 8 +++++++ components/esp_hw_support/modem_clock.c | 23 +++++++++++++++++++ components/esp_hw_support/periph_ctrl.c | 20 ++++++++++++++++ .../esp_phy/esp32/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32c2/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32c3/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32c5/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32c6/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32c61/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32h2/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32h21/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32h4/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32s2/include/phy_init_deps.h | 9 ++++++++ .../esp_phy/esp32s3/include/phy_init_deps.h | 9 ++++++++ components/esp_phy/src/phy_init.c | 7 ++++++ components/esp_phy/src/phy_init_esp32hxx.c | 7 ++++++ .../hal/esp32c5/include/hal/modem_syscon_ll.h | 6 +++++ .../hal/esp32c6/include/hal/modem_syscon_ll.h | 8 ++++++- .../esp32c61/include/hal/modem_syscon_ll.h | 6 +++++ .../hal/esp32h2/include/hal/modem_syscon_ll.h | 6 +++++ .../esp32h21/include/hal/modem_syscon_ll.h | 6 +++++ 22 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 components/esp_phy/esp32/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32c2/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32c3/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32c5/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32c6/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32c61/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32h2/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32h21/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32h4/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32s2/include/phy_init_deps.h create mode 100644 components/esp_phy/esp32s3/include/phy_init_deps.h diff --git a/components/esp_hw_support/include/esp_private/esp_modem_clock.h b/components/esp_hw_support/include/esp_private/esp_modem_clock.h index 1fd4079944..9cd1ace197 100644 --- a/components/esp_hw_support/include/esp_private/esp_modem_clock.h +++ b/components/esp_hw_support/include/esp_private/esp_modem_clock.h @@ -62,6 +62,18 @@ void modem_clock_module_enable(periph_module_t module); */ void modem_clock_module_disable(periph_module_t module); +/** + * @brief Gets the clock bitmask associated with the specified modem module. + * + * This function returns the complete set of clock-enable bits that correspond + * to @p module. + * + * @param module Target shared peripheral clock module. + * + * @return Bitmask of clock-enable bits for the given module. + */ +uint32_t modem_clock_module_bits_get(periph_module_t module); + /** * @brief Reset the mac of modem module * diff --git a/components/esp_hw_support/include/esp_private/periph_ctrl.h b/components/esp_hw_support/include/esp_private/periph_ctrl.h index fad1b8166d..00e55b0d53 100644 --- a/components/esp_hw_support/include/esp_private/periph_ctrl.h +++ b/components/esp_hw_support/include/esp_private/periph_ctrl.h @@ -6,6 +6,7 @@ #pragma once #include +#include #include "sdkconfig.h" #include "soc/periph_defs.h" @@ -167,6 +168,13 @@ void phy_module_enable(void); */ void phy_module_disable(void); +/** + * @brief Checks whether phy module has all bits in @p mask set. + * + * @return true if all bits in @p mask are set; false otherwise. + */ +bool phy_module_has_clock_bits(uint32_t mask); + #undef __PERIPH_CTRL_DEPRECATE_ATTR #ifdef __cplusplus diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index 7ed372685a..74cbca5fd7 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -406,6 +406,29 @@ void IRAM_ATTR modem_clock_module_disable(periph_module_t module) modem_clock_device_disable(MODEM_CLOCK_instance(), deps); } +uint32_t IRAM_ATTR modem_clock_module_bits_get(periph_module_t module) +{ + assert(IS_MODEM_MODULE(module)); + uint32_t val = 0; + switch (module) + { +#if SOC_WIFI_SUPPORTED + case PERIPH_WIFI_MODULE: +#endif +#if SOC_BT_SUPPORTED + case PERIPH_BT_MODULE: +#endif +#if SOC_IEEE802154_SUPPORTED + case PERIPH_IEEE802154_MODULE: +#endif + case PERIPH_PHY_MODULE: + val = modem_syscon_ll_clk_conf1_get(MODEM_CLOCK_instance()->hal->syscon_dev); + default: + break; + } + return val; +} + void modem_clock_deselect_all_module_lp_clock_source(void) { #if SOC_WIFI_SUPPORTED diff --git a/components/esp_hw_support/periph_ctrl.c b/components/esp_hw_support/periph_ctrl.c index 1f36791272..ffd6cd390b 100644 --- a/components/esp_hw_support/periph_ctrl.c +++ b/components/esp_hw_support/periph_ctrl.c @@ -10,6 +10,7 @@ #ifdef __PERIPH_CTRL_ALLOW_LEGACY_API #include "hal/clk_gate_ll.h" #endif +#include "esp_log.h" #if SOC_MODEM_CLOCK_IS_INDEPENDENT && SOC_MODEM_CLOCK_SUPPORTED #include "esp_private/esp_modem_clock.h" @@ -210,4 +211,23 @@ IRAM_ATTR void phy_module_disable(void) portEXIT_CRITICAL_SAFE(&periph_spinlock); #endif } + +IRAM_ATTR bool phy_module_has_clock_bits(uint32_t mask) +{ + uint32_t val = 0; +#if SOC_MODEM_CLOCK_IS_INDEPENDENT + val = modem_clock_module_bits_get(PERIPH_PHY_MODULE); +#else +#if SOC_WIFI_SUPPORTED || SOC_BT_SUPPORTED + val = DPORT_REG_READ(periph_ll_get_clk_en_reg(PERIPH_WIFI_BT_COMMON_MODULE)); +#else + return true; +#endif +#endif + if ((val & mask) != mask) { + ESP_LOGW("periph_ctrl", "phy module clock bits 0x%x, required 0x%x", val, mask); + return false; + } + return true; +} #endif //#if SOC_BT_SUPPORTED || SOC_WIFI_SUPPORTED || SOC_IEEE802154_SUPPORTED diff --git a/components/esp_phy/esp32/include/phy_init_deps.h b/components/esp_phy/esp32/include/phy_init_deps.h new file mode 100644 index 0000000000..8edb1079f8 --- /dev/null +++ b/components/esp_phy/esp32/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x8FCF diff --git a/components/esp_phy/esp32c2/include/phy_init_deps.h b/components/esp_phy/esp32c2/include/phy_init_deps.h new file mode 100644 index 0000000000..391b532af4 --- /dev/null +++ b/components/esp_phy/esp32c2/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0xE0788FCF diff --git a/components/esp_phy/esp32c3/include/phy_init_deps.h b/components/esp_phy/esp32c3/include/phy_init_deps.h new file mode 100644 index 0000000000..27c26fdec1 --- /dev/null +++ b/components/esp_phy/esp32c3/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x788FCF diff --git a/components/esp_phy/esp32c5/include/phy_init_deps.h b/components/esp_phy/esp32c5/include/phy_init_deps.h new file mode 100644 index 0000000000..e1f9a86da7 --- /dev/null +++ b/components/esp_phy/esp32c5/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x3BE7FF diff --git a/components/esp_phy/esp32c6/include/phy_init_deps.h b/components/esp_phy/esp32c6/include/phy_init_deps.h new file mode 100644 index 0000000000..a284da576d --- /dev/null +++ b/components/esp_phy/esp32c6/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x7E7FF diff --git a/components/esp_phy/esp32c61/include/phy_init_deps.h b/components/esp_phy/esp32c61/include/phy_init_deps.h new file mode 100644 index 0000000000..e1f9a86da7 --- /dev/null +++ b/components/esp_phy/esp32c61/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x3BE7FF diff --git a/components/esp_phy/esp32h2/include/phy_init_deps.h b/components/esp_phy/esp32h2/include/phy_init_deps.h new file mode 100644 index 0000000000..7596013875 --- /dev/null +++ b/components/esp_phy/esp32h2/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x7f000 diff --git a/components/esp_phy/esp32h21/include/phy_init_deps.h b/components/esp_phy/esp32h21/include/phy_init_deps.h new file mode 100644 index 0000000000..b2114ff4b1 --- /dev/null +++ b/components/esp_phy/esp32h21/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x0 //TODO diff --git a/components/esp_phy/esp32h4/include/phy_init_deps.h b/components/esp_phy/esp32h4/include/phy_init_deps.h new file mode 100644 index 0000000000..b2114ff4b1 --- /dev/null +++ b/components/esp_phy/esp32h4/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x0 //TODO diff --git a/components/esp_phy/esp32s2/include/phy_init_deps.h b/components/esp_phy/esp32s2/include/phy_init_deps.h new file mode 100644 index 0000000000..ab597d9a3e --- /dev/null +++ b/components/esp_phy/esp32s2/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x7887CF diff --git a/components/esp_phy/esp32s3/include/phy_init_deps.h b/components/esp_phy/esp32s3/include/phy_init_deps.h new file mode 100644 index 0000000000..27c26fdec1 --- /dev/null +++ b/components/esp_phy/esp32s3/include/phy_init_deps.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x788FCF diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index 4d97c1ebc0..8707bfaecc 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -53,6 +53,12 @@ #include "esp_private/esp_modem_clock.h" #include "soc/periph_defs.h" #endif +#include "phy_init_deps.h" + +#ifndef PHY_INIT_MODEM_CLOCK_REQUIRED_BITS +#warning "PHY_INIT_MODEM_CLOCK_REQUIRED_BITS not defined; using default value 0" +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0 +#endif #if CONFIG_IDF_TARGET_ESP32 extern wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb; @@ -301,6 +307,7 @@ void esp_phy_enable(esp_phy_modem_t modem) #endif esp_phy_common_clock_enable(); phy_module_enable(); + assert(phy_module_has_clock_bits(PHY_INIT_MODEM_CLOCK_REQUIRED_BITS)); if (s_is_phy_calibrated == false) { esp_phy_load_cal_and_init(); s_is_phy_calibrated = true; diff --git a/components/esp_phy/src/phy_init_esp32hxx.c b/components/esp_phy/src/phy_init_esp32hxx.c index 83000c57a9..727cb8c8d5 100644 --- a/components/esp_phy/src/phy_init_esp32hxx.c +++ b/components/esp_phy/src/phy_init_esp32hxx.c @@ -14,6 +14,12 @@ #if SOC_MODEM_CLOCK_IS_INDEPENDENT #include "esp_private/esp_modem_clock.h" #endif +#include "phy_init_deps.h" + +#ifndef PHY_INIT_MODEM_CLOCK_REQUIRED_BITS +#warning "PHY_INIT_MODEM_CLOCK_REQUIRED_BITS not defined; using default value 0" +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0 +#endif #define PHY_ENABLE_VERSION_PRINT 1 @@ -108,6 +114,7 @@ void esp_phy_enable(esp_phy_modem_t modem) modem_clock_module_enable(PERIPH_PHY_MODULE); #endif phy_module_enable(); + assert(phy_module_has_clock_bits(PHY_INIT_MODEM_CLOCK_REQUIRED_BITS)); if (!s_phy_is_enabled) { register_chipv7_phy(NULL, NULL, PHY_RF_CAL_FULL); phy_version_print(); diff --git a/components/hal/esp32c5/include/hal/modem_syscon_ll.h b/components/hal/esp32c5/include/hal/modem_syscon_ll.h index 79a28fd082..fb4377cf1a 100644 --- a/components/hal/esp32c5/include/hal/modem_syscon_ll.h +++ b/components/hal/esp32c5/include/hal/modem_syscon_ll.h @@ -324,6 +324,12 @@ static inline void modem_syscon_ll_clk_conf1_configure(modem_syscon_dev_t *hw, b } } +__attribute__((always_inline)) +static inline uint32_t modem_syscon_ll_clk_conf1_get(modem_syscon_dev_t *hw) +{ + return hw->clk_conf1.val; +} + __attribute__((always_inline)) static inline void modem_syscon_ll_clk_wifibb_configure(modem_syscon_dev_t *hw, bool en) { diff --git a/components/hal/esp32c6/include/hal/modem_syscon_ll.h b/components/hal/esp32c6/include/hal/modem_syscon_ll.h index 27ad9187fe..44b268a8d1 100644 --- a/components/hal/esp32c6/include/hal/modem_syscon_ll.h +++ b/components/hal/esp32c6/include/hal/modem_syscon_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -293,6 +293,12 @@ static inline void modem_syscon_ll_clk_conf1_configure(modem_syscon_dev_t *hw, b } } +__attribute__((always_inline)) +static inline uint32_t modem_syscon_ll_clk_conf1_get(modem_syscon_dev_t *hw) +{ + return hw->clk_conf1.val; +} + __attribute__((always_inline)) static inline void modem_syscon_ll_clk_wifibb_configure(modem_syscon_dev_t *hw, bool en) { diff --git a/components/hal/esp32c61/include/hal/modem_syscon_ll.h b/components/hal/esp32c61/include/hal/modem_syscon_ll.h index 72c7f7eb18..06e9f4df8a 100644 --- a/components/hal/esp32c61/include/hal/modem_syscon_ll.h +++ b/components/hal/esp32c61/include/hal/modem_syscon_ll.h @@ -324,6 +324,12 @@ static inline void modem_syscon_ll_clk_conf1_configure(modem_syscon_dev_t *hw, b } } +__attribute__((always_inline)) +static inline uint32_t modem_syscon_ll_clk_conf1_get(modem_syscon_dev_t *hw) +{ + return hw->clk_conf1.val; +} + __attribute__((always_inline)) static inline void modem_syscon_ll_clk_wifibb_configure(modem_syscon_dev_t *hw, bool en) { diff --git a/components/hal/esp32h2/include/hal/modem_syscon_ll.h b/components/hal/esp32h2/include/hal/modem_syscon_ll.h index 1a29054dac..a07a66d178 100644 --- a/components/hal/esp32h2/include/hal/modem_syscon_ll.h +++ b/components/hal/esp32h2/include/hal/modem_syscon_ll.h @@ -197,6 +197,12 @@ static inline void modem_syscon_ll_clk_conf1_configure(modem_syscon_dev_t *hw, b } } +__attribute__((always_inline)) +static inline uint32_t modem_syscon_ll_clk_conf1_get(modem_syscon_dev_t *hw) +{ + return hw->clk_conf1.val; +} + __attribute__((always_inline)) static inline void modem_syscon_ll_enable_fe_16m_clock(modem_syscon_dev_t *hw, bool en) { diff --git a/components/hal/esp32h21/include/hal/modem_syscon_ll.h b/components/hal/esp32h21/include/hal/modem_syscon_ll.h index c322c2018a..53a08fc4a3 100644 --- a/components/hal/esp32h21/include/hal/modem_syscon_ll.h +++ b/components/hal/esp32h21/include/hal/modem_syscon_ll.h @@ -198,6 +198,12 @@ static inline void modem_syscon_ll_clk_conf1_configure(modem_syscon_dev_t *hw, b } } +__attribute__((always_inline)) +static inline uint32_t modem_syscon_ll_clk_conf1_get(modem_syscon_dev_t *hw) +{ + return hw->clk_conf1.val; +} + __attribute__((always_inline)) static inline void modem_syscon_ll_enable_fe_txlogain_clock(modem_syscon_dev_t *hw, bool en) { From 31769c930d0a7d690d7b0422469e29f0d2111f14 Mon Sep 17 00:00:00 2001 From: liuning Date: Wed, 24 Dec 2025 17:25:59 +0800 Subject: [PATCH 36/84] fix(wifi): allow to disable wifi modem clocks if wifi is not inited --- .../include/esp_private/esp_modem_clock.h | 9 ++++++ components/esp_hw_support/modem_clock.c | 29 ++++++++++++++++--- components/esp_wifi/src/wifi_init.c | 12 ++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/esp_modem_clock.h b/components/esp_hw_support/include/esp_private/esp_modem_clock.h index 9cd1ace197..a61999fc76 100644 --- a/components/esp_hw_support/include/esp_private/esp_modem_clock.h +++ b/components/esp_hw_support/include/esp_private/esp_modem_clock.h @@ -74,6 +74,15 @@ void modem_clock_module_disable(periph_module_t module); */ uint32_t modem_clock_module_bits_get(periph_module_t module); +#if SOC_WIFI_SUPPORTED +/** + * @brief Set Wi-Fi initialization status. + * + * @param inited Wi-Fi initialization status. + */ +void modem_clock_configure_wifi_status(bool inited); +#endif + /** * @brief Reset the mac of modem module * diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index 74cbca5fd7..64b4df8423 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -53,6 +53,8 @@ typedef enum { MODEM_CLOCK_DEVICE_MAX } modem_clock_device_t; +#define MODEM_STATUS_IDLE (0) +#define MODEM_STATUS_WIFI_INITED (0x1UL) typedef struct modem_clock_context { modem_clock_hal_context_t *hal; @@ -64,13 +66,16 @@ typedef struct modem_clock_context { } dev[MODEM_CLOCK_DEVICE_MAX]; /* the low-power clock source for each module */ modem_clock_lpclk_src_t lpclk_src[PERIPH_MODEM_MODULE_NUM]; +#if SOC_WIFI_SUPPORTED + uint32_t modem_status; +#endif } modem_clock_context_t; #if SOC_WIFI_SUPPORTED static void IRAM_ATTR modem_clock_wifi_mac_configure(modem_clock_context_t *ctx, bool enable) { - if (enable) { + if (enable || !(ctx->modem_status & MODEM_STATUS_WIFI_INITED)) { #if !SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT modem_syscon_ll_enable_wifi_apb_clock(ctx->hal->syscon_dev, enable); #endif @@ -80,7 +85,7 @@ static void IRAM_ATTR modem_clock_wifi_mac_configure(modem_clock_context_t *ctx, static void IRAM_ATTR modem_clock_wifi_bb_configure(modem_clock_context_t *ctx, bool enable) { - if (enable) { + if (enable || !(ctx->modem_status & MODEM_STATUS_WIFI_INITED)) { modem_syscon_ll_clk_wifibb_configure(ctx->hal->syscon_dev, enable); } } @@ -98,14 +103,14 @@ static void IRAM_ATTR modem_clock_ble_mac_configure(modem_clock_context_t *ctx, #if SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT static void IRAM_ATTR modem_clock_wifi_apb_configure(modem_clock_context_t *ctx, bool enable) { - if (enable) { + if (enable || !(ctx->modem_status & MODEM_STATUS_WIFI_INITED)) { modem_syscon_ll_enable_wifi_apb_clock(ctx->hal->syscon_dev, enable); } } static void IRAM_ATTR modem_clock_wifi_bb_44m_configure(modem_clock_context_t *ctx, bool enable) { - if (enable) { + if (enable || !(ctx->modem_status & MODEM_STATUS_WIFI_INITED)) { modem_syscon_ll_enable_wifibb_44m_clock(ctx->hal->syscon_dev, enable); } } @@ -195,6 +200,10 @@ modem_clock_context_t * __attribute__((weak)) IRAM_ATTR MODEM_CLOCK_instance(voi [MODEM_CLOCK_DATADUMP] = { .refs = 0, .configure = modem_clock_data_dump_configure } }, .lpclk_src = { [0 ... PERIPH_MODEM_MODULE_NUM - 1] = MODEM_CLOCK_LPCLK_SRC_INVALID } +#if SOC_WIFI_SUPPORTED + , + .modem_status = MODEM_STATUS_IDLE +#endif }; if (modem_clock_hal.syscon_dev == NULL || modem_clock_hal.lpcon_dev == NULL) { modem_clock_hal.syscon_dev = &MODEM_SYSCON; @@ -429,6 +438,18 @@ uint32_t IRAM_ATTR modem_clock_module_bits_get(periph_module_t module) return val; } +#if SOC_WIFI_SUPPORTED +void modem_clock_configure_wifi_status(bool inited) +{ + portENTER_CRITICAL_SAFE(&MODEM_CLOCK_instance()->lock); + if (inited) + MODEM_CLOCK_instance()->modem_status |= MODEM_STATUS_WIFI_INITED; + else + MODEM_CLOCK_instance()->modem_status &= ~MODEM_STATUS_WIFI_INITED; + portEXIT_CRITICAL_SAFE(&MODEM_CLOCK_instance()->lock); +} +#endif + void modem_clock_deselect_all_module_lp_clock_source(void) { #if SOC_WIFI_SUPPORTED diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 0461280d5a..4799e30eb4 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -42,6 +42,10 @@ #include "esp_roaming.h" #endif +#if SOC_MODEM_CLOCK_IS_INDEPENDENT +#include "esp_private/esp_modem_clock.h" +#endif + static bool s_wifi_inited = false; #if (CONFIG_ESP_WIFI_RX_BA_WIN > CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM) @@ -255,6 +259,10 @@ static esp_err_t wifi_deinit_internal(void) #endif s_wifi_inited = false; +#if SOC_MODEM_CLOCK_IS_INDEPENDENT + modem_clock_configure_wifi_status(s_wifi_inited); +#endif + return err; } @@ -490,6 +498,10 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) s_wifi_inited = true; +#if SOC_MODEM_CLOCK_IS_INDEPENDENT + modem_clock_configure_wifi_status(s_wifi_inited); +#endif + return result; _deinit: From efd6a10f180a9edd97bf45402795d8f653e0c67f Mon Sep 17 00:00:00 2001 From: zhuanghang Date: Mon, 29 Dec 2025 15:38:48 +0800 Subject: [PATCH 37/84] feat(802.15.4): set default pti and ed/cca pti to 3 for 154 --- components/hal/include/hal/ieee802154_common_ll.h | 6 +++--- components/ieee802154/driver/esp_ieee802154_dev.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/hal/include/hal/ieee802154_common_ll.h b/components/hal/include/hal/ieee802154_common_ll.h index 1fe732f2c4..05b3e5ef9d 100644 --- a/components/hal/include/hal/ieee802154_common_ll.h +++ b/components/hal/include/hal/ieee802154_common_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -470,8 +470,8 @@ static inline void ieee802154_ll_set_security_key(uint8_t *security_key) static inline void ieee802154_ll_disable_coex(void) { - IEEE802154.pti.pti = 1; - IEEE802154.pti.hw_ack_pti = 1; + IEEE802154.pti.pti = 3; + IEEE802154.pti.hw_ack_pti = 3; } static inline void ieee802154_ll_clear_debug_cnt(uint32_t clear_bits) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 4664a3591a..30d5ff93fd 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -1068,6 +1068,7 @@ esp_err_t ieee802154_energy_detect(uint32_t duration) stop_current_operation(); ieee802154_pib_update(); + IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_RX); start_ed(duration); ieee802154_set_state(IEEE802154_STATE_ED); @@ -1084,6 +1085,7 @@ esp_err_t ieee802154_cca(void) stop_current_operation(); ieee802154_pib_update(); + IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_RX); start_ed(CCA_DETECTION_TIME); ieee802154_set_state(IEEE802154_STATE_CCA); From 7c59e704dd440c22fc6ac87274ccc1fda479d155 Mon Sep 17 00:00:00 2001 From: liuning Date: Mon, 19 Jan 2026 15:00:10 +0800 Subject: [PATCH 38/84] fix(phy): wifi mac clock is not required during phy calibration --- components/esp_hw_support/modem_clock.c | 4 ++-- components/esp_phy/esp32/include/phy_init_deps.h | 2 +- components/esp_phy/esp32c2/include/phy_init_deps.h | 2 +- components/esp_phy/esp32c3/include/phy_init_deps.h | 2 +- components/esp_phy/esp32c5/include/phy_init_deps.h | 2 +- components/esp_phy/esp32c6/include/phy_init_deps.h | 2 +- components/esp_phy/esp32c61/include/phy_init_deps.h | 2 +- components/esp_phy/esp32s2/include/phy_init_deps.h | 2 +- components/esp_phy/esp32s3/include/phy_init_deps.h | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index 64b4df8423..f2075b45b8 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -320,10 +320,10 @@ void IRAM_ATTR modem_clock_module_mac_reset(periph_module_t module) #define MODEM_ETM_CLOCK_DEPS (BIT(MODEM_CLOCK_ETM)) #define MODEM_ADC_COMMON_FE_CLOCK_DEPS (BIT(MODEM_CLOCK_MODEM_ADC_COMMON_FE)) #if SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT -#define PHY_CALIBRATION_WIFI_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_MAC) | BIT(MODEM_CLOCK_WIFI_APB) | BIT(MODEM_CLOCK_WIFI_BB) | BIT(MODEM_CLOCK_WIFI_BB_44M)) +#define PHY_CALIBRATION_WIFI_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_APB) | BIT(MODEM_CLOCK_WIFI_BB) | BIT(MODEM_CLOCK_WIFI_BB_44M)) #define PHY_CALIBRATION_BT_I154_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_APB) | BIT(MODEM_CLOCK_WIFI_BB_44M) | BIT(MODEM_CLOCK_BT_I154_COMMON_BB)) #else -#define PHY_CALIBRATION_WIFI_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_MAC) | BIT(MODEM_CLOCK_WIFI_BB)) +#define PHY_CALIBRATION_WIFI_CLOCK_DEPS (BIT(MODEM_CLOCK_WIFI_BB)) #define PHY_CALIBRATION_BT_I154_CLOCK_DEPS (BIT(MODEM_CLOCK_BT_I154_COMMON_BB)) #endif #ifndef SOC_WIFI_SUPPORTED diff --git a/components/esp_phy/esp32/include/phy_init_deps.h b/components/esp_phy/esp32/include/phy_init_deps.h index 8edb1079f8..c0e9dfdc7d 100644 --- a/components/esp_phy/esp32/include/phy_init_deps.h +++ b/components/esp_phy/esp32/include/phy_init_deps.h @@ -6,4 +6,4 @@ #pragma once -#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x8FCF +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x8F8F diff --git a/components/esp_phy/esp32c2/include/phy_init_deps.h b/components/esp_phy/esp32c2/include/phy_init_deps.h index 391b532af4..605bd9a582 100644 --- a/components/esp_phy/esp32c2/include/phy_init_deps.h +++ b/components/esp_phy/esp32c2/include/phy_init_deps.h @@ -6,4 +6,4 @@ #pragma once -#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0xE0788FCF +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0xE0788F8F diff --git a/components/esp_phy/esp32c3/include/phy_init_deps.h b/components/esp_phy/esp32c3/include/phy_init_deps.h index 27c26fdec1..8837de5586 100644 --- a/components/esp_phy/esp32c3/include/phy_init_deps.h +++ b/components/esp_phy/esp32c3/include/phy_init_deps.h @@ -6,4 +6,4 @@ #pragma once -#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x788FCF +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x788F8F diff --git a/components/esp_phy/esp32c5/include/phy_init_deps.h b/components/esp_phy/esp32c5/include/phy_init_deps.h index e1f9a86da7..5b73d36565 100644 --- a/components/esp_phy/esp32c5/include/phy_init_deps.h +++ b/components/esp_phy/esp32c5/include/phy_init_deps.h @@ -6,4 +6,4 @@ #pragma once -#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x3BE7FF +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x3BE5FF diff --git a/components/esp_phy/esp32c6/include/phy_init_deps.h b/components/esp_phy/esp32c6/include/phy_init_deps.h index a284da576d..9390346e7b 100644 --- a/components/esp_phy/esp32c6/include/phy_init_deps.h +++ b/components/esp_phy/esp32c6/include/phy_init_deps.h @@ -6,4 +6,4 @@ #pragma once -#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x7E7FF +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x7E1FF diff --git a/components/esp_phy/esp32c61/include/phy_init_deps.h b/components/esp_phy/esp32c61/include/phy_init_deps.h index e1f9a86da7..5b73d36565 100644 --- a/components/esp_phy/esp32c61/include/phy_init_deps.h +++ b/components/esp_phy/esp32c61/include/phy_init_deps.h @@ -6,4 +6,4 @@ #pragma once -#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x3BE7FF +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x3BE5FF diff --git a/components/esp_phy/esp32s2/include/phy_init_deps.h b/components/esp_phy/esp32s2/include/phy_init_deps.h index ab597d9a3e..7f2ad52f71 100644 --- a/components/esp_phy/esp32s2/include/phy_init_deps.h +++ b/components/esp_phy/esp32s2/include/phy_init_deps.h @@ -6,4 +6,4 @@ #pragma once -#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x7887CF +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x78878F diff --git a/components/esp_phy/esp32s3/include/phy_init_deps.h b/components/esp_phy/esp32s3/include/phy_init_deps.h index 27c26fdec1..8837de5586 100644 --- a/components/esp_phy/esp32s3/include/phy_init_deps.h +++ b/components/esp_phy/esp32s3/include/phy_init_deps.h @@ -6,4 +6,4 @@ #pragma once -#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x788FCF +#define PHY_INIT_MODEM_CLOCK_REQUIRED_BITS 0x788F8F From cc91b64b05023ffae411288957903566e8598f67 Mon Sep 17 00:00:00 2001 From: zlq Date: Mon, 19 Jan 2026 20:05:17 +0800 Subject: [PATCH 39/84] feat(c6): fix pvt efuse print bug on c6 and adjust pvt prepare cost in sleep wakeup on c6/c5/c61 --- .../esp_hw_support/port/esp32c6/pmu_pvt.c | 10 +--------- components/esp_hw_support/sleep_modes.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/components/esp_hw_support/port/esp32c6/pmu_pvt.c b/components/esp_hw_support/port/esp32c6/pmu_pvt.c index c8a28616f7..33fb41edea 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_pvt.c +++ b/components/esp_hw_support/port/esp32c6/pmu_pvt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -106,8 +106,6 @@ void pvt_auto_dbias_init(void) /*config lp offset for pvt func*/ uint8_t lp_hp_gap = get_lp_hp_gap(); set_pvt_hp_lp_gap(lp_hp_gap); - } else { - ESP_HW_LOGD(TAG, "blk_version is less than 3, pvt auto dbias init not supported in efuse."); } } @@ -135,8 +133,6 @@ void IRAM_ATTR pvt_func_enable(bool enable) CLEAR_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN); CLEAR_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN); } - } else { - ESP_HW_LOGD(TAG, "blk_version is less than 3, pvt enable not supported in efuse."); } } @@ -148,8 +144,6 @@ void charge_pump_init(void) SET_PERI_REG_BITS(PVT_PMUP_CHANNEL_CFG_REG, PVT_PUMP_CHANNEL_CODE0, PVT_PUMP_CHANNEL_CODE, PVT_PUMP_CHANNEL_CODE0_S); //Set channel code WRITE_PERI_REG(PVT_PMUP_BITMAP_LOW0_REG, (1 << PVT_PUMP_BITMAP)); // Select monitor cell for charge pump SET_PERI_REG_BITS(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_DRV0, PVT_PUMP_DRV, PVT_PUMP_DRV0_S); //Configure the charging intensity - } else { - ESP_HW_LOGD(TAG, "blk_version is less than 3, pvt charge_pump init not supported in efuse."); } } @@ -162,8 +156,6 @@ void IRAM_ATTR charge_pump_enable(bool enable) } else { CLEAR_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); //disable charge pump } - } else { - ESP_HW_LOGD(TAG, "blk_version is less than 3, pvt charge_pump enable not supported in efuse."); } } diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 913ad231da..186b03605d 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -191,11 +191,14 @@ #elif CONFIG_IDF_TARGET_ESP32C6 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (318) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56) +#define PVT_REINIT_COST_US (60) #elif CONFIG_IDF_TARGET_ESP32C5 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (318) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56) +#define PVT_REINIT_COST_US (25) #elif CONFIG_IDF_TARGET_ESP32C61 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (230) +#define PVT_REINIT_COST_US (90) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (70) #elif CONFIG_IDF_TARGET_ESP32H2 #define DEFAULT_SLEEP_OUT_OVERHEAD_US (118) @@ -1477,9 +1480,9 @@ esp_err_t esp_light_sleep_start(void) // Re-calibrate the RTC clock sleep_low_power_clock_calibration(false); + uint32_t cur_cpu_freq = esp_clk_cpu_freq() / MHZ; + uint32_t xtal_freq = rtc_clk_xtal_freq_get(); if (s_config.overhead_out_need_remeasure) { - uint32_t cur_cpu_freq = esp_clk_cpu_freq() / MHZ; - uint32_t xtal_freq = rtc_clk_xtal_freq_get(); if (cur_cpu_freq < xtal_freq) { s_config.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US * xtal_freq / cur_cpu_freq; } else { @@ -1496,6 +1499,18 @@ esp_err_t esp_light_sleep_start(void) */ #if SOC_PMU_SUPPORTED int sleep_time_sw_adjustment = LIGHT_SLEEP_TIME_OVERHEAD_US + sleep_time_overhead_in + s_config.sleep_time_overhead_out; +#if CONFIG_ESP_ENABLE_PVT && !SOC_PVT_EN_WITH_SLEEP + + /* PVT will only be enabled during the wake-up process if the CPU's clock source is PLL when the CPU goes to sleep. */ + if ((cur_cpu_freq > xtal_freq) +#if CONFIG_IDF_TARGET_ESP32C5 + /* On esp32c5, CPU 40m is divided from PLL160/240M */ + || (xtal_freq == SOC_XTAL_FREQ_48M && cur_cpu_freq == 40) +#endif + ) { + sleep_time_sw_adjustment += PVT_REINIT_COST_US; + } +#endif int sleep_time_hw_adjustment = pmu_sleep_calculate_hw_wait_time(sleep_flags, rtc_clk_slow_src_get(), s_config.rtc_clk_cal_period, s_config.fast_clk_cal_period); s_config.sleep_time_adjustment = sleep_time_sw_adjustment + sleep_time_hw_adjustment; #else From f261c32624f2004a9647d99c495a6815a9faf3aa Mon Sep 17 00:00:00 2001 From: Junchi Chen Date: Mon, 19 Jan 2026 22:18:03 +0800 Subject: [PATCH 40/84] fix(wifi): btwt dwell timeout; esp32c2 disallow 40bw(backport 5.5) --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 8f933de0fd..66a31b2e11 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 8f933de0fdd1a6577f862db2810eafc61463d4d8 +Subproject commit 66a31b2e1161e20fb3cede2255b7e84586f47f63 From 85f30c2665f3063d6c417b72f5240950d2ce2d11 Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Mon, 19 Jan 2026 22:16:28 +0800 Subject: [PATCH 41/84] fix: fix DCDC patch on P4 rev3.1 --- components/bootloader_support/src/flash_encrypt.c | 4 ---- .../port/esp32p4/Kconfig.p4_rev3_mspi_workaround | 4 ++-- components/esp_hw_support/port/esp32p4/rtc_clk_init.c | 10 ++++------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c index baaa948226..4c0cbdfb08 100644 --- a/components/bootloader_support/src/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encrypt.c @@ -210,7 +210,6 @@ void esp_flash_encryption_set_release_mode(void) #endif // CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED #endif // !CONFIG_IDF_TARGET_ESP32 -#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL < 300) #if SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) { uint8_t xts_pseudo_level = 0; @@ -222,7 +221,6 @@ void esp_flash_encryption_set_release_mode(void) } } #endif -#endif #ifdef CONFIG_IDF_TARGET_ESP32 esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_DIS_CACHE); #else @@ -484,7 +482,6 @@ bool esp_flash_encryption_cfg_verify_release_mode(void) } result &= secure; -#if !(CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL < 300) #if SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 if (spi_flash_encrypt_ll_is_pseudo_rounds_function_supported()) { uint8_t xts_pseudo_level = 0; @@ -494,7 +491,6 @@ bool esp_flash_encryption_cfg_verify_release_mode(void) ESP_LOGW(TAG, "Not enabled XTS-AES pseudo rounds function (set XTS_DPA_PSEUDO_LEVEL->1 or more)"); } } -#endif #endif return result; } diff --git a/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround b/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround index 50ed53a400..c680003020 100644 --- a/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround +++ b/components/esp_hw_support/lowpower/port/esp32p4/Kconfig.p4_rev3_mspi_workaround @@ -1,10 +1,10 @@ config P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND bool depends on IDF_TARGET_ESP32P4 - default y if !ESP32P4_SELECTS_REV_LESS_V3 # Fixed since REV3.1 + default y if ESP32P4_REV_MIN_300 # Fixed since REV3.1 config P4_REV3_MSPI_WORKAROUND_SIZE hex depends on IDF_TARGET_ESP32P4 - default 0x100 if !ESP32P4_SELECTS_REV_LESS_V3 + default 0x100 if ESP32P4_REV_MIN_300 default 0 diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c index 6a88840899..f82d414a23 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c @@ -68,10 +68,9 @@ void rtc_clk_init(rtc_clk_config_t cfg) hp_dcmvset = pvt_hp_dcmvset; } // Switch to DCDC -#if (CONFIG_ESP32P4_REV_MIN_FULL >= 300) +#if CONFIG_ESP32P4_REV_MIN_FULL >= 300 unsigned chip_version = efuse_hal_chip_revision(); - if (ESP_CHIP_REV_BETWEEN(chip_version, 300, 301)) { - // This workaround is only needed for P4 rev3.1 + if (ESP_CHIP_REV_ABOVE(chip_version, 301)) { SET_PERI_REG_MASK(PMU_DCM_CTRL_REG, PMU_DCDC_FB_RES_FORCE_PD); } #endif @@ -80,9 +79,8 @@ void rtc_clk_init(rtc_clk_config_t cfg) pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, hp_dcmvset); SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu esp_rom_delay_us(1000); -#if (CONFIG_ESP32P4_REV_MIN_FULL >= 300) - if (ESP_CHIP_REV_BETWEEN(chip_version, 300, 301)) { - // This workaround is only needed for P4 rev3.1 +#if CONFIG_ESP32P4_REV_MIN_FULL >= 300 + if (ESP_CHIP_REV_ABOVE(chip_version, 301)) { REG_SET_FIELD(LP_SYSTEM_REG_SYS_CTRL_REG, LP_SYSTEM_REG_LP_FIB_SEL, 0xEF);// lp_fib_sel bit4 set to 0: select dig_fib_reg instead of ana_fib_reg CLEAR_PERI_REG_MASK(PMU_DCM_CTRL_REG, PMU_DCDC_FB_RES_FORCE_PD); esp_rom_delay_us(10); From a0685f893f73d04ca0c3db8cdac6f59a7b13af4a Mon Sep 17 00:00:00 2001 From: Marek Fiala Date: Mon, 5 Jan 2026 16:20:42 +0100 Subject: [PATCH 42/84] docs(tools): Updated argument via file with quotations Closes https://github.com/espressif/esp-idf/issues/18077 --- docs/en/api-guides/tools/idf-py.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/api-guides/tools/idf-py.rst b/docs/en/api-guides/tools/idf-py.rst index 426d542aa3..4948748de4 100644 --- a/docs/en/api-guides/tools/idf-py.rst +++ b/docs/en/api-guides/tools/idf-py.rst @@ -295,9 +295,9 @@ For example, let's have a file `custom_flash.txt`: flash --baud 115200 -Then the command can be executed as: ``idf.py @custom_flash.txt monitor`` +Then the command can be executed as: ``idf.py "@custom_flash.txt" monitor`` -Arguments from a file can be combined with additional command line arguments, and multiple files annotated with ``@`` can be used simultaneously. For instance, if there is a second file ``another_config.txt``, both can be utilized by specifying ``idf.py @custom_flash.txt @another_config.txt monitor``. +Arguments from a file can be combined with additional command line arguments, and multiple files annotated with ``@`` can be used simultaneously. For instance, if there is a second file ``another_config.txt``, both can be utilized by specifying ``idf.py "@custom_flash.txt" "@another_config.txt" monitor``. A further example of how this argument file can be used, e.g., creating configuration profile files via @filename, is in the :example_file:`Multiple Build Configurations Example `. From 2224e862a64aa4b131bf5b1707f036e4364b9a86 Mon Sep 17 00:00:00 2001 From: Shen Mengjing Date: Fri, 9 Jan 2026 10:42:40 +0800 Subject: [PATCH 43/84] docs: Update CN translation for idf-py.rst --- docs/zh_CN/api-guides/tools/idf-py.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/zh_CN/api-guides/tools/idf-py.rst b/docs/zh_CN/api-guides/tools/idf-py.rst index deab763205..299a509ace 100644 --- a/docs/zh_CN/api-guides/tools/idf-py.rst +++ b/docs/zh_CN/api-guides/tools/idf-py.rst @@ -295,9 +295,9 @@ uf2 二进制文件也可以通过 :ref:`idf.py uf2 ` 生 flash --baud 115200 -运行命令:``idf.py @custom_flash.txt monitor`` +运行命令:``idf.py "@custom_flash.txt" monitor`` -文件中的参数可以与额外的命令行参数结合使用,也支持同时使用带有 ``@`` 标注的多个文件。例如,另有一个文件 ``another_config.txt``,此时,可以通过指定 ``idf.py @custom_flash.txt @another_config.txt monitor`` 同时使用两个文件。 +文件中的参数可以与额外的命令行参数结合使用,也支持同时使用带有 ``@`` 标注的多个文件。例如,另有一个文件 ``another_config.txt``,此时,可以通过指定 ``idf.py "@custom_flash.txt" "@another_config.txt" monitor`` 同时使用两个文件。 关于参数文件的更多示例,如通过 @filename 创建配置文件概要,请参阅 :example_file:`多个构建配置示例 `。 From f8763f2700236a96d2274a8adc4deb4e47fadd3d Mon Sep 17 00:00:00 2001 From: luoxu Date: Wed, 2 Apr 2025 19:23:28 +0800 Subject: [PATCH 44/84] feat(ble_mesh): unify tinycrypto component --- components/bt/CMakeLists.txt | 40 ++++++++++++++++----------- components/bt/esp_ble_mesh/Kconfig.in | 8 ++++++ 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index af71a578fa..b1dc0f82ef 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -29,7 +29,6 @@ set(common_include_dirs set(ble_mesh_include_dirs "esp_ble_mesh/common/include" - "esp_ble_mesh/common/tinycrypt/include" "esp_ble_mesh/core" "esp_ble_mesh/core/include" "esp_ble_mesh/core/storage" @@ -42,6 +41,10 @@ set(ble_mesh_include_dirs "esp_ble_mesh/api" ) +set(ble_mesh_tinycrypt_dirs + "esp_ble_mesh/common/tinycrypt/include" +) + set(ble_mesh_v11_include_dirs "esp_ble_mesh/lib/include" "esp_ble_mesh/v1.1/api/core/include" @@ -546,21 +549,6 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/btc/btc_ble_mesh_prov.c" "esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c" "esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c" - "esp_ble_mesh/common/tinycrypt/src/aes_decrypt.c" - "esp_ble_mesh/common/tinycrypt/src/aes_encrypt.c" - "esp_ble_mesh/common/tinycrypt/src/cbc_mode.c" - "esp_ble_mesh/common/tinycrypt/src/ccm_mode.c" - "esp_ble_mesh/common/tinycrypt/src/cmac_mode.c" - "esp_ble_mesh/common/tinycrypt/src/ctr_mode.c" - "esp_ble_mesh/common/tinycrypt/src/ctr_prng.c" - "esp_ble_mesh/common/tinycrypt/src/ecc_dh.c" - "esp_ble_mesh/common/tinycrypt/src/ecc_dsa.c" - "esp_ble_mesh/common/tinycrypt/src/ecc_platform_specific.c" - "esp_ble_mesh/common/tinycrypt/src/ecc.c" - "esp_ble_mesh/common/tinycrypt/src/hmac_prng.c" - "esp_ble_mesh/common/tinycrypt/src/hmac.c" - "esp_ble_mesh/common/tinycrypt/src/sha256.c" - "esp_ble_mesh/common/tinycrypt/src/utils.c" "esp_ble_mesh/common/atomic.c" "esp_ble_mesh/common/buf.c" "esp_ble_mesh/common/common.c" @@ -610,6 +598,26 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/models/server/state_binding.c" "esp_ble_mesh/models/server/state_transition.c" "esp_ble_mesh/models/server/time_scene_server.c") + + if(NOT CONFIG_BLE_MESH_USE_UNIFIED_CRYPTO) + list(APPEND include_dirs ${ble_mesh_tinycrypt_dirs}) + list(APPEND srcs + "esp_ble_mesh/common/tinycrypt/src/aes_decrypt.c" + "esp_ble_mesh/common/tinycrypt/src/aes_encrypt.c" + "esp_ble_mesh/common/tinycrypt/src/cbc_mode.c" + "esp_ble_mesh/common/tinycrypt/src/ccm_mode.c" + "esp_ble_mesh/common/tinycrypt/src/cmac_mode.c" + "esp_ble_mesh/common/tinycrypt/src/ctr_mode.c" + "esp_ble_mesh/common/tinycrypt/src/ctr_prng.c" + "esp_ble_mesh/common/tinycrypt/src/ecc_dh.c" + "esp_ble_mesh/common/tinycrypt/src/ecc_dsa.c" + "esp_ble_mesh/common/tinycrypt/src/ecc_platform_specific.c" + "esp_ble_mesh/common/tinycrypt/src/ecc.c" + "esp_ble_mesh/common/tinycrypt/src/hmac_prng.c" + "esp_ble_mesh/common/tinycrypt/src/hmac.c" + "esp_ble_mesh/common/tinycrypt/src/sha256.c" + "esp_ble_mesh/common/tinycrypt/src/utils.c") + endif() if(CONFIG_BLE_MESH_V11_SUPPORT) list(APPEND include_dirs ${ble_mesh_v11_include_dirs}) diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index e6c19f0e45..b1157256e0 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -22,6 +22,14 @@ if BLE_MESH for mesh packets. And this could help avoid collision of advertising packets. + config BLE_MESH_USE_UNIFIED_CRYPTO + bool "Use the unified BLE tinycrypt implementation" + depends on !BT_LE_CRYPTO_STACK_MBEDTLS && !BT_NIMBLE_CRYPTO_STACK_MBEDTLS + default n + help + Enable this option to use the unified BLE tinycrypt solution + instead of the default one in BLE Mesh stack. + menuconfig BLE_MESH_USE_BLE_50 bool "Support using BLE 5.0 APIs for BLE Mesh" depends on BLE_MESH_EXPERIMENTAL From 58f10936a3a23f1926de1073ed4ecfeeddcad62b Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 23 Dec 2025 20:58:44 +0800 Subject: [PATCH 45/84] feat(ble_mesh): unified ble mesh crypto --- components/bt/CMakeLists.txt | 19 +- components/bt/esp_ble_mesh/Kconfig.in | 1 + .../bt/esp_ble_mesh/common/crypto_mbedtls.c | 541 +++++++++++++ .../bt/esp_ble_mesh/common/crypto_psa.c | 711 ++++++++++++++++++ components/bt/esp_ble_mesh/common/crypto_tc.c | 340 +++++++++ .../esp_ble_mesh/common/include/mesh/common.h | 1 + .../esp_ble_mesh/common/include/mesh/crypto.h | 349 +++++++++ .../core/bluedroid_host/adapter.c | 194 +---- components/bt/esp_ble_mesh/core/crypto.c | 355 +-------- components/bt/esp_ble_mesh/core/crypto.h | 21 +- .../esp_ble_mesh/core/include/mesh/adapter.h | 17 +- .../esp_ble_mesh/core/nimble_host/adapter.c | 206 +---- components/bt/esp_ble_mesh/core/prov_node.c | 23 +- components/bt/esp_ble_mesh/core/prov_pvnr.c | 17 +- components/bt/esp_ble_mesh/lib/ext.c | 29 +- 15 files changed, 1998 insertions(+), 826 deletions(-) create mode 100644 components/bt/esp_ble_mesh/common/crypto_mbedtls.c create mode 100644 components/bt/esp_ble_mesh/common/crypto_psa.c create mode 100644 components/bt/esp_ble_mesh/common/crypto_tc.c create mode 100644 components/bt/esp_ble_mesh/common/include/mesh/crypto.h diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index b1dc0f82ef..8fb8f1cd05 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -556,8 +556,21 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/common/mutex.c" "esp_ble_mesh/common/queue.c" "esp_ble_mesh/common/timer.c" - "esp_ble_mesh/common/utils.c" - "esp_ble_mesh/core/storage/settings_nvs.c" + "esp_ble_mesh/common/utils.c") + + # Select crypto implementation based on config + if(CONFIG_BT_SMP_CRYPTO_STACK_TINYCRYPT OR + CONFIG_BT_SMP_CRYPTO_STACK_NATIVE) + list(APPEND srcs "esp_ble_mesh/common/crypto_tc.c") + elseif(CONFIG_BT_SMP_CRYPTO_STACK_MBEDTLS) + if(CONFIG_MBEDTLS_VER_4_X_SUPPORT) + list(APPEND srcs "esp_ble_mesh/common/crypto_psa.c") + else() + list(APPEND srcs "esp_ble_mesh/common/crypto_mbedtls.c") + endif() + endif() + + list(APPEND srcs "esp_ble_mesh/core/storage/settings_nvs.c" "esp_ble_mesh/core/storage/settings_uid.c" "esp_ble_mesh/core/storage/settings.c" "esp_ble_mesh/core/access.c" @@ -599,7 +612,7 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/models/server/state_transition.c" "esp_ble_mesh/models/server/time_scene_server.c") - if(NOT CONFIG_BLE_MESH_USE_UNIFIED_CRYPTO) + if(CONFIG_BT_SMP_CRYPTO_STACK_NATIVE) list(APPEND include_dirs ${ble_mesh_tinycrypt_dirs}) list(APPEND srcs "esp_ble_mesh/common/tinycrypt/src/aes_decrypt.c" diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index b1157256e0..896b3541c5 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -25,6 +25,7 @@ if BLE_MESH config BLE_MESH_USE_UNIFIED_CRYPTO bool "Use the unified BLE tinycrypt implementation" depends on !BT_LE_CRYPTO_STACK_MBEDTLS && !BT_NIMBLE_CRYPTO_STACK_MBEDTLS + default y if BT_SMP_CRYPTO_STACK_TINYCRYPT default n help Enable this option to use the unified BLE tinycrypt solution diff --git a/components/bt/esp_ble_mesh/common/crypto_mbedtls.c b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c new file mode 100644 index 0000000000..24b0b76308 --- /dev/null +++ b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c @@ -0,0 +1,541 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_random.h" + +#include "mbedtls/aes.h" +#include "mbedtls/cmac.h" +#include "mbedtls/md.h" +#include "mbedtls/ecp.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ccm.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" + +#include "mesh/common.h" +#include "mesh/crypto.h" +#include "mesh/trace.h" +#include "mesh/config.h" + +/* ECC key storage + * + * MbedTLS functions expect BIG-ENDIAN format. + */ +static struct { + bool is_ready; + uint8_t private_key[PRIV_KEY_SIZE]; /* Big-endian */ + uint8_t public_key[PUB_KEY_SIZE]; /* Big-endian */ +} dh_pair; + +int bt_mesh_crypto_init(void) +{ + memset(&dh_pair, 0, sizeof(dh_pair)); + dh_pair.is_ready = false; + return 0; +} + +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + mbedtls_aes_context ctx; + int ret; + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_enc(&ctx, key->key, 128); + if (ret != 0) { + mbedtls_aes_free(&ctx); + return -EIO; + } + + ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, enc_data); + mbedtls_aes_free(&ctx); + + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + mbedtls_ccm_context ctx; + int ret; + + mbedtls_ccm_init(&ctx); + + ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key->key, 128); + if (ret != 0) { + mbedtls_ccm_free(&ctx); + return -EIO; + } + + ret = mbedtls_ccm_encrypt_and_tag(&ctx, len, nonce, 13, aad, aad_len, + plaintext, enc_data, enc_data + len, mic_size); + + mbedtls_ccm_free(&ctx); + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + mbedtls_ccm_context ctx; + int ret; + + mbedtls_ccm_init(&ctx); + + ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key->key, 128); + if (ret != 0) { + mbedtls_ccm_free(&ctx); + return -EIO; + } + + ret = mbedtls_ccm_auth_decrypt(&ctx, len, nonce, 13, aad, aad_len, + enc_data, plaintext, enc_data + len, mic_size); + + mbedtls_ccm_free(&ctx); + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + + memcpy(mesh_key.key, key, 16); + return bt_mesh_ccm_encrypt(&mesh_key, nonce, plaintext, len, aad, aad_len, + enc_data, mic_size); +} + +int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + + memcpy(mesh_key.key, key, 16); + return bt_mesh_ccm_decrypt(&mesh_key, nonce, enc_data, len, aad, aad_len, + plaintext, mic_size); +} + +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, + struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]) +{ + return bt_mesh_aes_cmac_raw_key(key->key, sg, sg_len, mac); +} + +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]) +{ + mbedtls_cipher_context_t ctx; + const mbedtls_cipher_info_t *info; + int ret; + + info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); + if (info == NULL) { + return -EIO; + } + + mbedtls_cipher_init(&ctx); + + ret = mbedtls_cipher_setup(&ctx, info); + if (ret != 0) { + mbedtls_cipher_free(&ctx); + return -EIO; + } + + ret = mbedtls_cipher_cmac_starts(&ctx, key, 128); + if (ret != 0) { + mbedtls_cipher_free(&ctx); + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + ret = mbedtls_cipher_cmac_update(&ctx, sg->data, sg->len); + if (ret != 0) { + mbedtls_cipher_free(&ctx); + return -EIO; + } + } + + ret = mbedtls_cipher_cmac_finish(&ctx, mac); + mbedtls_cipher_free(&ctx); + + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[32]) +{ + mbedtls_md_context_t ctx; + const mbedtls_md_info_t *info; + int ret; + + info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + if (info == NULL) { + return -EIO; + } + + mbedtls_md_init(&ctx); + + ret = mbedtls_md_setup(&ctx, info, 1); /* 1 = HMAC mode */ + if (ret != 0) { + mbedtls_md_free(&ctx); + return -EIO; + } + + ret = mbedtls_md_hmac_starts(&ctx, key, 32); + if (ret != 0) { + mbedtls_md_free(&ctx); + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + ret = mbedtls_md_hmac_update(&ctx, sg->data, sg->len); + if (ret != 0) { + mbedtls_md_free(&ctx); + return -EIO; + } + } + + ret = mbedtls_md_hmac_finish(&ctx, mac); + mbedtls_md_free(&ctx); + + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_pub_key_gen(void) +{ + mbedtls_ecp_group grp; + mbedtls_mpi d; + mbedtls_ecp_point Q; + uint8_t private_key_be[PRIV_KEY_SIZE]; + uint8_t public_key_be[PUB_KEY_SIZE]; + int ret; + int err; + + dh_pair.is_ready = false; + + do { + err = bt_mesh_rand(dh_pair.private_key, sizeof(dh_pair.private_key)); + if (err) { + BT_ERR("Failed to generate random private key"); + return err; + } + /* Ensure the private key is valid (non-zero last bytes in LE) */ + } while (dh_pair.private_key[0] == 0 && + dh_pair.private_key[1] == 0); + + mbedtls_ecp_group_init(&grp); + mbedtls_mpi_init(&d); + mbedtls_ecp_point_init(&Q); + + ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + if (ret != 0) { + goto cleanup; + } + + /* Read private key into MPI (MbedTLS expects big-endian) */ + ret = mbedtls_mpi_read_binary(&d, dh_pair.private_key, PRIV_KEY_SIZE); + if (ret != 0) { + goto cleanup; + } + + /* Compute public key: Q = d * G */ + ret = mbedtls_ecp_mul(&grp, &Q, &d, &grp.G, NULL, NULL); + if (ret != 0) { + goto cleanup; + } + + /* Export public key point in big-endian */ + ret = mbedtls_mpi_write_binary(&Q.MBEDTLS_PRIVATE(X), dh_pair.public_key, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_write_binary(&Q.MBEDTLS_PRIVATE(Y), dh_pair.public_key + 32, 32); + if (ret != 0) { + goto cleanup; + } + + dh_pair.is_ready = true; + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); + + return ret == 0 ? 0 : -EIO; +} + +const uint8_t *bt_mesh_pub_key_get(void) +{ + if (!dh_pair.is_ready) { + if (bt_mesh_pub_key_gen() != 0) { + return NULL; + } + } + + return dh_pair.public_key; +} + +void bt_mesh_set_private_key(const uint8_t pri_key[32]) +{ + mbedtls_ecp_group grp; + mbedtls_mpi d; + mbedtls_ecp_point Q; + int ret; + + dh_pair.is_ready = false; + + memcpy(dh_pair.private_key, pri_key, PRIV_KEY_SIZE); + + /* Compute public key from private key */ + mbedtls_ecp_group_init(&grp); + mbedtls_mpi_init(&d); + mbedtls_ecp_point_init(&Q); + + ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&d, pri_key, PRIV_KEY_SIZE); + if (ret != 0) { + goto cleanup; + } + + /* Compute public key: Q = d * G (no RNG needed for deterministic computation) */ + ret = mbedtls_ecp_mul(&grp, &Q, &d, &grp.G, NULL, NULL); + if (ret != 0) { + goto cleanup; + } + + /* Export public key point in big-endian */ + ret = mbedtls_mpi_write_binary(&Q.MBEDTLS_PRIVATE(X), dh_pair.public_key, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_write_binary(&Q.MBEDTLS_PRIVATE(Y), dh_pair.public_key + 32, 32); + if (ret != 0) { + goto cleanup; + } + + dh_pair.is_ready = true; + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); +} + +bool bt_mesh_check_public_key(const uint8_t key[64]) +{ + mbedtls_ecp_group grp; + mbedtls_ecp_point Q; + uint8_t pub_key_be[PUB_KEY_SIZE]; + int ret; + + mbedtls_ecp_group_init(&grp); + mbedtls_ecp_point_init(&Q); + + ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&Q.MBEDTLS_PRIVATE(X), dh_pair.public_key, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&Q.MBEDTLS_PRIVATE(Y), dh_pair.public_key + 32, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_lset(&Q.MBEDTLS_PRIVATE(Z), 1); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_ecp_check_pubkey(&grp, &Q); + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&Q); + + return ret == 0; +} + +int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) +{ + mbedtls_ecp_group grp; + mbedtls_mpi d; + mbedtls_ecp_point Q; + mbedtls_ecp_point result; + int ret; + + mbedtls_ecp_group_init(&grp); + mbedtls_mpi_init(&d); + mbedtls_ecp_point_init(&Q); + mbedtls_ecp_point_init(&result); + + ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&d, priv_key ? priv_key : dh_pair.private_key, PRIV_KEY_SIZE); + if (ret != 0) { + goto cleanup; + } + + /* Load public key point */ + ret = mbedtls_mpi_read_binary(&Q.MBEDTLS_PRIVATE(X), dh_pair.public_key, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_read_binary(&Q.MBEDTLS_PRIVATE(Y), dh_pair.public_key + 32, 32); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_mpi_lset(&Q.MBEDTLS_PRIVATE(Z), 1); + if (ret != 0) { + goto cleanup; + } + + /* Check the peer's public key */ + ret = mbedtls_ecp_check_pubkey(&grp, &Q); + if (ret != 0) { + goto cleanup; + } + + /* Calculate shared secret: result = d * Q (no RNG needed for deterministic computation) */ + ret = mbedtls_ecp_mul(&grp, &result, &d, &Q, NULL, NULL); + if (ret != 0) { + goto cleanup; + } + + /* Export X coordinate as DH key (big-endian) */ + ret = mbedtls_mpi_write_binary(&result.MBEDTLS_PRIVATE(X), dhkey, DH_KEY_SIZE); + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_mpi_free(&d); + mbedtls_ecp_point_free(&Q); + mbedtls_ecp_point_free(&result); + + return ret == 0 ? 0 : -EIO; +} + +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out) +{ + (void)type; /* Not used for non-PSA implementation */ + memcpy(out->key, in, 16); + return 0; +} + +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in) +{ + memcpy(out, in->key, 16); + return 0; +} + +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src) +{ + memcpy(dst, src, sizeof(struct bt_mesh_key)); +} + +int bt_mesh_key_destroy(const struct bt_mesh_key *key) +{ + (void)key; /* No cleanup needed for non-PSA implementation */ + return 0; +} + +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key) +{ + return memcmp(raw_key, key->key, 16); +} + +int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + mbedtls_aes_context ctx; + uint8_t tmp[16]; + int ret; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + mbedtls_aes_init(&ctx); + + /* Swap key bytes (LE to BE) */ + sys_memcpy_swap(tmp, key, 16); + + ret = mbedtls_aes_setkey_enc(&ctx, tmp, 128); + if (ret != 0) { + mbedtls_aes_free(&ctx); + return -EINVAL; + } + + /* Swap plaintext bytes and encrypt */ + sys_memcpy_swap(tmp, plaintext, 16); + + ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, tmp, enc_data); + mbedtls_aes_free(&ctx); + + if (ret != 0) { + return -EINVAL; + } + + /* Swap result bytes (BE to LE) */ + sys_mem_swap(enc_data, 16); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} + +int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + mbedtls_aes_context ctx; + int ret; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_enc(&ctx, key, 128); + if (ret != 0) { + mbedtls_aes_free(&ctx); + return -EINVAL; + } + + ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, enc_data); + mbedtls_aes_free(&ctx); + + if (ret != 0) { + return -EINVAL; + } + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} diff --git a/components/bt/esp_ble_mesh/common/crypto_psa.c b/components/bt/esp_ble_mesh/common/crypto_psa.c new file mode 100644 index 0000000000..9619700634 --- /dev/null +++ b/components/bt/esp_ble_mesh/common/crypto_psa.c @@ -0,0 +1,711 @@ +/* + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_random.h" +#include "psa/crypto.h" + +#include "mesh/common.h" +#include "mesh/crypto.h" +#include "mesh/trace.h" +#include "mesh/config.h" + +/* PSA Key ID range for BLE Mesh */ +#define BT_MESH_PSA_KEY_ID_MIN 0x0001A000 +#define BT_MESH_PSA_KEY_ID_RANGE_SIZE \ + (2 * CONFIG_BLE_MESH_SUBNET_COUNT + 2 * CONFIG_BLE_MESH_APP_KEY_COUNT + 2) + +/* Internal DH key pair storage + * + * PSA functions expect BIG-ENDIAN format. + */ +static struct { + bool is_ready; + psa_key_id_t priv_key_id; + uint8_t public_key[PUB_KEY_SIZE + 1]; /* Big-endian, PSA format: 0x04 + X + Y */ +} dh_pair; + +/* Bitmap for tracking allocated key IDs */ +static uint32_t pst_keys[(BT_MESH_PSA_KEY_ID_RANGE_SIZE + 31) / 32]; + +static psa_key_id_t keyid_alloc(void) +{ + for (int i = 0; i < BT_MESH_PSA_KEY_ID_RANGE_SIZE; i++) { + int word = i / 32; + int bit = i % 32; + if (!(pst_keys[word] & (1U << bit))) { + pst_keys[word] |= (1U << bit); + return BT_MESH_PSA_KEY_ID_MIN + i; + } + } + return PSA_KEY_ID_NULL; +} + +static int keyid_free(psa_key_id_t key_id) +{ + if (key_id >= BT_MESH_PSA_KEY_ID_MIN && + key_id < BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE) { + int idx = key_id - BT_MESH_PSA_KEY_ID_MIN; + int word = idx / 32; + int bit = idx % 32; + pst_keys[word] &= ~(1U << bit); + return 0; + } + return -EIO; +} + +static void keyid_assign(psa_key_id_t key_id) +{ + if (key_id >= BT_MESH_PSA_KEY_ID_MIN && + key_id < BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE) { + int idx = key_id - BT_MESH_PSA_KEY_ID_MIN; + int word = idx / 32; + int bit = idx % 32; + pst_keys[word] |= (1U << bit); + } +} + +int bt_mesh_crypto_init(void) +{ + psa_status_t status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + BT_ERR("PSA crypto init failed: %d", status); + return -EIO; + } + + dh_pair.is_ready = false; + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + memset(pst_keys, 0, sizeof(pst_keys)); + + return 0; +} + +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + size_t output_len; + psa_status_t status; + + status = psa_cipher_encrypt(key->key, PSA_ALG_ECB_NO_PADDING, + plaintext, 16, enc_data, 16, &output_len); + + if (status != PSA_SUCCESS || output_len != 16) { + BT_ERR("PSA cipher encrypt failed: %d", status); + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + size_t output_len; + psa_status_t status; + psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, mic_size); + + status = psa_aead_encrypt(key->key, alg, nonce, 13, aad, aad_len, + plaintext, len, enc_data, len + mic_size, &output_len); + + if (status != PSA_SUCCESS || output_len != len + mic_size) { + BT_ERR("PSA AEAD encrypt failed: %d", status); + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + size_t output_len; + psa_status_t status; + psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, mic_size); + + status = psa_aead_decrypt(key->key, alg, nonce, 13, aad, aad_len, + enc_data, len + mic_size, plaintext, len, &output_len); + + if (status != PSA_SUCCESS || output_len != len) { + BT_ERR("PSA AEAD decrypt failed: %d", status); + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + int err; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CCM, key, &mesh_key); + if (err) { + return err; + } + + err = bt_mesh_ccm_encrypt(&mesh_key, nonce, plaintext, len, aad, aad_len, + enc_data, mic_size); + + psa_destroy_key(mesh_key.key); + return err; +} + +int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + int err; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CCM, key, &mesh_key); + if (err) { + return err; + } + + err = bt_mesh_ccm_decrypt(&mesh_key, nonce, enc_data, len, aad, aad_len, + plaintext, mic_size); + + psa_destroy_key(mesh_key.key); + return err; +} + +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, + struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]) +{ + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + psa_status_t status; + size_t mac_len; + + status = psa_mac_sign_setup(&operation, key->key, PSA_ALG_CMAC); + if (status != PSA_SUCCESS) { + BT_ERR("PSA MAC setup failed: %d", status); + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + status = psa_mac_update(&operation, sg->data, sg->len); + if (status != PSA_SUCCESS) { + psa_mac_abort(&operation); + BT_ERR("PSA MAC update failed: %d", status); + return -EIO; + } + } + + status = psa_mac_sign_finish(&operation, mac, 16, &mac_len); + if (status != PSA_SUCCESS || mac_len != 16) { + BT_ERR("PSA MAC finish failed: %d", status); + return -EIO; + } + + return 0; +} + +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]) +{ + struct bt_mesh_key key_id; + int err; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CMAC, key, &key_id); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_mesh_key(&key_id, sg, sg_len, mac); + + psa_destroy_key(key_id.key); + + return err; +} + +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[32]) +{ + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id; + psa_status_t status; + size_t mac_len; + int err = 0; + + /* Import HMAC key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, key, 32, &key_id); + if (status != PSA_SUCCESS) { + BT_ERR("PSA import HMAC key failed: %d", status); + return -EIO; + } + psa_reset_key_attributes(&attributes); + + status = psa_mac_sign_setup(&operation, key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + if (status != PSA_SUCCESS) { + BT_ERR("PSA HMAC setup failed: %d", status); + err = -EIO; + goto end; + } + + for (; sg_len; sg_len--, sg++) { + status = psa_mac_update(&operation, sg->data, sg->len); + if (status != PSA_SUCCESS) { + psa_mac_abort(&operation); + BT_ERR("PSA HMAC update failed: %d", status); + err = -EIO; + goto end; + } + } + + status = psa_mac_sign_finish(&operation, mac, 32, &mac_len); + if (status != PSA_SUCCESS || mac_len != 32) { + BT_ERR("PSA HMAC finish failed: %d", status); + err = -EIO; + } + +end: + psa_destroy_key(key_id); + return err; +} + +int bt_mesh_pub_key_gen(void) +{ + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + uint8_t private_key[PRIV_KEY_SIZE]; + size_t key_len; + int err; + + /* Destroy any existing key */ + if (dh_pair.priv_key_id != PSA_KEY_ID_NULL) { + psa_destroy_key(dh_pair.priv_key_id); + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + } + dh_pair.is_ready = false; + + /* Generate a random private key (in little-endian format for storage) */ + do { + err = bt_mesh_rand(private_key, sizeof(private_key)); + if (err) { + BT_ERR("Failed to generate random private key"); + return err; + } + /* Ensure the private key is valid (non-zero first bytes in BE) */ + } while (private_key[0] == 0 && private_key[1] == 0); + + /* Configure key attributes for ECDH with P-256 */ + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDH); + psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&key_attributes, 256); + + /* Import the private key */ + status = psa_import_key(&key_attributes, private_key, sizeof(private_key), + &dh_pair.priv_key_id); + if (status != PSA_SUCCESS) { + BT_ERR("PSA import private key failed: %d", status); + psa_reset_key_attributes(&key_attributes); + return -EIO; + } + + /* Export public key (PSA computes it from the private key) */ + status = psa_export_public_key(dh_pair.priv_key_id, dh_pair.public_key, + sizeof(dh_pair.public_key), &key_len); + if (status != PSA_SUCCESS || key_len != PUB_KEY_SIZE + 1) { + BT_ERR("PSA export public key failed: %d", status); + psa_destroy_key(dh_pair.priv_key_id); + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + psa_reset_key_attributes(&key_attributes); + return -EIO; + } + + dh_pair.is_ready = true; + psa_reset_key_attributes(&key_attributes); + + return 0; +} + +const uint8_t *bt_mesh_pub_key_get(void) +{ + if (!dh_pair.is_ready) { + if (bt_mesh_pub_key_gen() != 0) { + return NULL; + } + } + + return &dh_pair.public_key[1]; +} + +void bt_mesh_set_private_key(const uint8_t pri_key[32]) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + size_t key_len; + + /* Destroy any existing key */ + if (dh_pair.priv_key_id != PSA_KEY_ID_NULL) { + psa_destroy_key(dh_pair.priv_key_id); + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + } + dh_pair.is_ready = false; + + /* Import the provided private key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDH); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, pri_key, PRIV_KEY_SIZE, &dh_pair.priv_key_id); + if (status != PSA_SUCCESS) { + BT_ERR("PSA import private key failed: %d", status); + psa_reset_key_attributes(&attributes); + return; + } + + /* Export public key (PSA computes it from the private key) */ + status = psa_export_public_key(dh_pair.priv_key_id, dh_pair.public_key, + sizeof(dh_pair.public_key), &key_len); + if (status != PSA_SUCCESS || key_len != PUB_KEY_SIZE + 1) { + BT_ERR("PSA export public key failed: %d", status); + psa_destroy_key(dh_pair.priv_key_id); + dh_pair.priv_key_id = PSA_KEY_ID_NULL; + psa_reset_key_attributes(&attributes); + return; + } + + dh_pair.is_ready = true; + psa_reset_key_attributes(&attributes); +} + +bool bt_mesh_check_public_key(const uint8_t key[64]) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id; + psa_status_t status; + uint8_t pub_be[PUB_KEY_SIZE + 1]; + + /* PSA requires 0x04 prefix for uncompressed point */ + pub_be[0] = 0x04; + /* Convert from little-endian to big-endian */ + memcpy(&pub_be[1], key, 32); + memcpy(&pub_be[33], key + 32, 32); + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, pub_be, sizeof(pub_be), &key_id); + psa_reset_key_attributes(&attributes); + + if (status != PSA_SUCCESS) { + return false; + } + + psa_destroy_key(key_id); + return true; +} + +int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) +{ + psa_key_id_t priv_key_id = PSA_KEY_ID_NULL; + uint8_t public_key_be[PUB_KEY_SIZE + 1]; + psa_status_t status; + size_t dh_key_len; + int err = 0; + + if (priv_key) { + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + + /* Import custom private key */ + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDH); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + + status = psa_import_key(&attributes, priv_key, PRIV_KEY_SIZE, &priv_key_id); + psa_reset_key_attributes(&attributes); + + if (status != PSA_SUCCESS) { + BT_ERR("PSA import private key failed: %d", status); + return -EIO; + } + } else { + priv_key_id = dh_pair.priv_key_id; + } + + /* Prepare public key with 0x04 prefix in big-endian format */ + public_key_be[0] = 0x04; + /* Convert from little-endian to big-endian */ + memcpy(public_key_be + 1, pub_key, 32); + memcpy(public_key_be + 33, pub_key + 32, 32); + + /* Calculate shared secret */ + status = psa_raw_key_agreement(PSA_ALG_ECDH, priv_key_id, public_key_be, + PUB_KEY_SIZE + 1, dhkey, DH_KEY_SIZE, &dh_key_len); + + if (status != PSA_SUCCESS || dh_key_len != DH_KEY_SIZE) { + BT_ERR("PSA ECDH failed: %d", status); + err = -EIO; + } + + if (priv_key && priv_key_id != PSA_KEY_ID_NULL) { + psa_destroy_key(priv_key_id); + } + + return err; +} + +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out) +{ + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + + switch (type) { + case BT_MESH_KEY_TYPE_ECB: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&key_attributes, PSA_ALG_ECB_NO_PADDING); + break; + case BT_MESH_KEY_TYPE_CCM: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&key_attributes, + PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 4)); + break; + case BT_MESH_KEY_TYPE_CMAC: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_algorithm(&key_attributes, PSA_ALG_CMAC); + break; + case BT_MESH_KEY_TYPE_NET: +#if CONFIG_BT_SETTINGS + key_id = keyid_alloc(); + if (key_id == PSA_KEY_ID_NULL) { + return -ENOMEM; + } + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&key_attributes, key_id); +#else + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); +#endif + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_EXPORT); + break; + case BT_MESH_KEY_TYPE_APP: + case BT_MESH_KEY_TYPE_DEV: +#if CONFIG_BT_SETTINGS + key_id = keyid_alloc(); + if (key_id == PSA_KEY_ID_NULL) { + return -ENOMEM; + } + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&key_attributes, key_id); +#else + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); +#endif + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_EXPORT); + psa_set_key_algorithm(&key_attributes, + PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 4)); + break; + default: + return -EINVAL; + } + + psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&key_attributes, 128); + + status = psa_import_key(&key_attributes, in, 16, &out->key); + if (status == PSA_ERROR_ALREADY_EXISTS) { + BT_WARN("Key 0x%04x already exists, destroying and reimporting", key_id); + psa_destroy_key(key_id); + status = psa_import_key(&key_attributes, in, 16, &out->key); + } + + psa_reset_key_attributes(&key_attributes); + + if (status != PSA_SUCCESS) { + BT_ERR("PSA import key failed: %d", status); + if (key_id != PSA_KEY_ID_NULL) { + keyid_free(key_id); + } + return -EIO; + } + + return 0; +} + +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in) +{ + size_t data_length; + psa_status_t status; + + status = psa_export_key(in->key, out, 16, &data_length); + if (status != PSA_SUCCESS || data_length != 16) { + BT_ERR("PSA export key failed: %d", status); + return -EIO; + } + + return 0; +} + +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src) +{ + memcpy(dst, src, sizeof(struct bt_mesh_key)); +#if CONFIG_BT_SETTINGS + keyid_assign(dst->key); +#endif +} + +int bt_mesh_key_destroy(const struct bt_mesh_key *key) +{ + psa_status_t status; + + status = psa_destroy_key(key->key); + if (status != PSA_SUCCESS) { + BT_ERR("PSA destroy key failed: %d", status); + return -EIO; + } + +#if CONFIG_BT_SETTINGS + return keyid_free(key->key); +#else + return 0; +#endif +} + +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key) +{ + uint8_t out[16]; + int err; + + err = bt_mesh_key_export(out, key); + if (err) { + return err; + } + + return memcmp(out, raw_key, 16); +} + +int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id; + psa_status_t status; + uint8_t tmp[16]; + size_t output_len; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + /* Swap key bytes (LE to BE) */ + sys_memcpy_swap(tmp, key, 16); + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + status = psa_import_key(&attributes, tmp, 16, &key_id); + psa_reset_key_attributes(&attributes); + + if (status != PSA_SUCCESS) { + BT_ERR("PSA import key failed: %d", status); + return -EINVAL; + } + + /* Swap plaintext bytes and encrypt */ + sys_memcpy_swap(tmp, plaintext, 16); + + status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, + tmp, 16, enc_data, 16, &output_len); + + psa_destroy_key(key_id); + + if (status != PSA_SUCCESS || output_len != 16) { + BT_ERR("PSA encrypt failed: %d", status); + return -EINVAL; + } + + /* Swap result bytes (BE to LE) */ + sys_mem_swap(enc_data, 16); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} + +int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id; + psa_status_t status; + size_t output_len; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING); + psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attributes, 128); + + status = psa_import_key(&attributes, key, 16, &key_id); + psa_reset_key_attributes(&attributes); + + if (status != PSA_SUCCESS) { + BT_ERR("PSA import key failed: %d", status); + return -EINVAL; + } + + status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, + plaintext, 16, enc_data, 16, &output_len); + + psa_destroy_key(key_id); + + if (status != PSA_SUCCESS || output_len != 16) { + BT_ERR("PSA encrypt failed: %d", status); + return -EINVAL; + } + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} + +#if 0 +int bt_mesh_rand(void *buf, size_t len) +{ + psa_status_t status; + + if (buf == NULL || len == 0) { + return -EINVAL; + } + + status = psa_generate_random(buf, len); + return status == PSA_SUCCESS ? 0 : -EIO; +} +#endif diff --git a/components/bt/esp_ble_mesh/common/crypto_tc.c b/components/bt/esp_ble_mesh/common/crypto_tc.c new file mode 100644 index 0000000000..9fd9e97b91 --- /dev/null +++ b/components/bt/esp_ble_mesh/common/crypto_tc.c @@ -0,0 +1,340 @@ +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "esp_random.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "mesh/common.h" +#include "mesh/crypto.h" +#include "mesh/trace.h" + +/* Internal DH key pair storage + * + * TinyCrypt's uECC functions expect BIG-ENDIAN format. + */ +static struct { + bool is_ready; + uint8_t private_key[PRIV_KEY_SIZE]; /* Big-endian */ + uint8_t public_key[PUB_KEY_SIZE]; /* Big-endian */ +} dh_pair; + +int bt_mesh_crypto_init(void) +{ + memset(&dh_pair, 0, sizeof(dh_pair)); + dh_pair.is_ready = false; + return 0; +} + +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + struct tc_aes_key_sched_struct sched; + + if (tc_aes128_set_encrypt_key(&sched, key->key) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_aes_encrypt(enc_data, plaintext, &sched) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + struct tc_ccm_mode_struct ccm; + struct tc_aes_key_sched_struct sched; + + if (tc_aes128_set_encrypt_key(&sched, key->key) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_ccm_config(&ccm, &sched, nonce, 13, mic_size) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_ccm_generation_encryption(enc_data, len + mic_size, aad, aad_len, + plaintext, len, &ccm) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + struct tc_ccm_mode_struct ccm; + struct tc_aes_key_sched_struct sched; + + if (tc_aes128_set_encrypt_key(&sched, key->key) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_ccm_config(&ccm, &sched, nonce, 13, mic_size) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_ccm_decryption_verification(plaintext, len, aad, aad_len, + enc_data, len + mic_size, &ccm) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + + memcpy(mesh_key.key, key, 16); + return bt_mesh_ccm_encrypt(&mesh_key, nonce, plaintext, len, aad, aad_len, + enc_data, mic_size); +} + +int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size) +{ + struct bt_mesh_key mesh_key; + + memcpy(mesh_key.key, key, 16); + return bt_mesh_ccm_decrypt(&mesh_key, nonce, enc_data, len, aad, aad_len, + plaintext, mic_size); +} + +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]) +{ + struct tc_aes_key_sched_struct sched; + struct tc_cmac_struct state; + + if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + if (tc_cmac_update(&state, sg->data, sg->len) == TC_CRYPTO_FAIL) { + return -EIO; + } + } + + if (tc_cmac_final(mac, &state) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, + struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]) +{ + return bt_mesh_aes_cmac_raw_key(key->key, sg, sg_len, mac); +} + +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[32]) +{ + struct tc_hmac_state_struct h; + + if (tc_hmac_set_key(&h, key, 32) == TC_CRYPTO_FAIL) { + return -EIO; + } + + if (tc_hmac_init(&h) == TC_CRYPTO_FAIL) { + return -EIO; + } + + for (; sg_len; sg_len--, sg++) { + if (tc_hmac_update(&h, sg->data, sg->len) == TC_CRYPTO_FAIL) { + return -EIO; + } + } + + if (tc_hmac_final(mac, 32, &h) == TC_CRYPTO_FAIL) { + return -EIO; + } + + return 0; +} + +int bt_mesh_pub_key_gen(void) +{ + int rc; + + /* Generate a random private key */ + do { + rc = bt_mesh_rand(dh_pair.private_key, sizeof(dh_pair.private_key)); + if (rc) { + BT_ERR("Failed to generate random private key"); + return rc; + } + /* Ensure the private key is valid (first bytes in BE shall be non-zero) */ + } while (dh_pair.private_key[0] == 0 && + dh_pair.private_key[1] == 0); + + /* Compute the public key from the private key */ + rc = uECC_compute_public_key(dh_pair.private_key, dh_pair.public_key, uECC_secp256r1()); + if (rc != TC_CRYPTO_SUCCESS) { + dh_pair.is_ready = false; + BT_ERR("Failed to compute public key"); + return -EIO; + } + + dh_pair.is_ready = true; + return 0; +} + +const uint8_t *bt_mesh_pub_key_get(void) +{ + if (!dh_pair.is_ready) { + if (bt_mesh_pub_key_gen() != 0) { + return NULL; + } + } + + return dh_pair.public_key; +} + +void bt_mesh_set_private_key(const uint8_t pri_key[32]) +{ + int rc; + + memcpy(dh_pair.private_key, pri_key, PRIV_KEY_SIZE); + + /* Compute the public key from the provided private key */ + rc = uECC_compute_public_key(dh_pair.private_key, dh_pair.public_key, uECC_secp256r1()); + if (rc != TC_CRYPTO_SUCCESS) { + dh_pair.is_ready = false; + BT_ERR("Failed to compute public key from private key"); + return; + } + + dh_pair.is_ready = true; +} + +bool bt_mesh_check_public_key(const uint8_t key[64]) +{ + return uECC_valid_public_key(key, uECC_secp256r1()) == 0; +} + +int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) +{ + if (uECC_valid_public_key(pub_key, uECC_secp256r1()) != 0) { + BT_ERR("Public key is not valid"); + return -EIO; + } + + if (uECC_shared_secret(pub_key, priv_key ? priv_key : dh_pair.private_key, + dhkey, uECC_secp256r1()) != TC_CRYPTO_SUCCESS) { + BT_ERR("DHKey generation failed"); + return -EIO; + } + + return 0; +} + +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out) +{ + (void)type; /* Type is not used for TinyCrypt, just store raw key */ + memcpy(out->key, in, 16); + return 0; +} + +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in) +{ + memcpy(out, in->key, 16); + return 0; +} + +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src) +{ + memcpy(dst->key, src->key, 16); +} + +int bt_mesh_key_destroy(const struct bt_mesh_key *key) +{ + (void)key; /* Nothing to destroy for TinyCrypt */ + return 0; +} + +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key) +{ + return memcmp(raw_key, key->key, 16); +} + +int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + struct tc_aes_key_sched_struct sched; + uint8_t tmp[16]; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + /* Swap key bytes (LE to BE) */ + sys_memcpy_swap(tmp, key, 16); + + if (tc_aes128_set_encrypt_key(&sched, tmp) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + /* Swap plaintext bytes (LE to BE) */ + sys_memcpy_swap(tmp, plaintext, 16); + + if (tc_aes_encrypt(enc_data, tmp, &sched) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + /* Swap result bytes (BE to LE) */ + sys_mem_swap(enc_data, 16); + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} + +int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + struct tc_aes_key_sched_struct sched; + + BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); + + if (tc_aes128_set_encrypt_key(&sched, key) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + if (tc_aes_encrypt(enc_data, plaintext, &sched) == TC_CRYPTO_FAIL) { + return -EINVAL; + } + + BT_DBG("enc_data %s", bt_hex(enc_data, 16)); + return 0; +} diff --git a/components/bt/esp_ble_mesh/common/include/mesh/common.h b/components/bt/esp_ble_mesh/common/include/mesh/common.h index a1cfa673a2..8be5e40d06 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/common.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/common.h @@ -22,6 +22,7 @@ #include "mesh/trace.h" #include "mesh/mutex.h" #include "mesh/access.h" +#include "mesh/crypto.h" #ifdef __cplusplus extern "C" { diff --git a/components/bt/esp_ble_mesh/common/include/mesh/crypto.h b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h new file mode 100644 index 0000000000..38a8b3f208 --- /dev/null +++ b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h @@ -0,0 +1,349 @@ +/* + * SPDX-FileCopyrightText: 2017 Intel Corporation + * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA + * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _BLE_MESH_CRYPTO_H_ +#define _BLE_MESH_CRYPTO_H_ + +#include +#include +#include + +#include "sdkconfig.h" + +#include "mesh/common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Key sizes */ +#define PRIV_KEY_SIZE 32 +#define PUB_KEY_SIZE 64 +#define DH_KEY_SIZE 32 + +/** + * @brief Scatter-Gather data structure for cryptographic operations + */ +struct bt_mesh_sg { + const void *data; + size_t len; +}; + +/** + * @brief Mesh key type enumeration + */ +enum bt_mesh_key_type { + BT_MESH_KEY_TYPE_ECB, /**< AES-ECB encryption/decryption */ + BT_MESH_KEY_TYPE_CCM, /**< AES-CCM AEAD */ + BT_MESH_KEY_TYPE_CMAC, /**< AES-CMAC */ + BT_MESH_KEY_TYPE_NET, /**< Network key */ + BT_MESH_KEY_TYPE_APP, /**< Application key */ + BT_MESH_KEY_TYPE_DEV, /**< Device key */ +}; + +/** + * @brief Mesh key structure + * + * For TinyCrypt/MbedTLS: stores raw key bytes + * For PSA: stores PSA key ID + */ +struct bt_mesh_key { +#if CONFIG_BT_SMP_CRYPTO_STACK_MBEDTLS && CONFIG_MBEDTLS_VER_4_X_SUPPORT + uint32_t key; /* PSA key ID */ +#else + uint8_t key[16]; /* Raw key bytes */ +#endif +}; + +/** + * @brief Initialize the cryptographic subsystem + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_crypto_init(void); + +/** + * @brief AES-ECB encryption (big-endian) + * + * @param key Pointer to mesh key structure + * @param plaintext 16-byte plaintext + * @param enc_data 16-byte output buffer for encrypted data + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]); + +/** + * @brief AES-CCM encryption + * + * @param key Pointer to mesh key structure + * @param nonce 13-byte nonce + * @param plaintext Input plaintext + * @param len Length of plaintext + * @param aad Additional authenticated data + * @param aad_len Length of AAD + * @param enc_data Output buffer (must be len + mic_size bytes) + * @param mic_size Size of MIC (4, 8, or 16 bytes) + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size); + +/** + * @brief AES-CCM decryption + * + * @param key Pointer to mesh key structure + * @param nonce 13-byte nonce + * @param enc_data Encrypted data with MIC + * @param len Length of plaintext (without MIC) + * @param aad Additional authenticated data + * @param aad_len Length of AAD + * @param plaintext Output buffer for plaintext + * @param mic_size Size of MIC (4, 8, or 16 bytes) + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size); + +/** + * @brief AES-CCM encryption using raw key bytes + * + * @param key 16-byte raw key + * @param nonce 13-byte nonce + * @param plaintext Input plaintext + * @param len Length of plaintext + * @param aad Additional authenticated data + * @param aad_len Length of AAD + * @param enc_data Output buffer (must be len + mic_size bytes) + * @param mic_size Size of MIC (4, 8, or 16 bytes) + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *plaintext, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *enc_data, size_t mic_size); + +/** + * @brief AES-CCM decryption using raw key bytes + * + * @param key 16-byte raw key + * @param nonce 13-byte nonce + * @param enc_data Encrypted data with MIC + * @param len Length of plaintext (without MIC) + * @param aad Additional authenticated data + * @param aad_len Length of AAD + * @param plaintext Output buffer for plaintext + * @param mic_size Size of MIC (4, 8, or 16 bytes) + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13], + const uint8_t *enc_data, size_t len, + const uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t mic_size); + +/** + * @brief AES-CMAC using mesh key structure + * + * @param key Pointer to mesh key structure + * @param sg Scatter-gather list of input data + * @param sg_len Number of scatter-gather entries + * @param mac 16-byte output buffer for MAC + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, + struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]); + +/** + * @brief AES-CMAC using raw key bytes + * + * @param key 16-byte raw key + * @param sg Scatter-gather list of input data + * @param sg_len Number of scatter-gather entries + * @param mac 16-byte output buffer for MAC + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]); + +/** + * @brief AES-CMAC with single data input (convenience wrapper) + */ +static inline int bt_mesh_aes_cmac_one(const uint8_t key[16], const void *m, + size_t len, uint8_t mac[16]) +{ + struct bt_mesh_sg sg = { m, len }; + return bt_mesh_aes_cmac_raw_key(key, &sg, 1, mac); +} + +/** + * @brief HMAC-SHA256 using raw key bytes + * + * @param key 32-byte raw key + * @param sg Scatter-gather list of input data + * @param sg_len Number of scatter-gather entries + * @param mac 32-byte output buffer for MAC + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[32]); + +/** + * @brief HMAC-SHA256 with single data input (convenience wrapper) + */ +static inline int bt_mesh_sha256_hmac_one(const uint8_t key[32], const void *m, + size_t len, uint8_t mac[32]) +{ + struct bt_mesh_sg sg = { m, len }; + return bt_mesh_sha256_hmac_raw_key(key, &sg, 1, mac); +} + +/** + * @brief Generate a new ECC public key pair + * + * Generates a new P-256 key pair for ECDH operations. + * The private key is stored internally. + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_pub_key_gen(void); + +/** + * @brief Get the current public key + * + * @return Pointer to 64-byte public key (X || Y), or NULL if not ready + */ +const uint8_t *bt_mesh_pub_key_get(void); + +/** + * @brief Set a custom private key + * + * @param pri_key 32-byte private key + */ +void bt_mesh_set_private_key(const uint8_t pri_key[32]); + +/** + * @brief Check if a public key is valid + * + * Verifies that the given public key is a valid point on the P-256 curve. + * + * @param key 64-byte public key (X || Y) + * + * @return true if valid, false otherwise + */ +bool bt_mesh_check_public_key(const uint8_t key[64]); + +/** + * @brief Generate ECDH shared secret (DHKey) + * + * @param pub_key 64-byte remote public key (X || Y) + * @param priv_key 32-byte private key (NULL to use internal key) + * @param dhkey 32-byte output buffer for shared secret + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey); + +#define bt_mesh_dh_key_gen(pubkey, dhkey) bt_mesh_dhkey_gen(pubkey, NULL, dhkey) + +/** + * @brief Import a raw key into mesh key structure + * + * @param type Key type (determines key usage) + * @param in 16-byte raw key + * @param out Output mesh key structure + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out); + +/** + * @brief Export raw key bytes from mesh key structure + * + * @param out 16-byte output buffer + * @param in Input mesh key structure + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in); + +/** + * @brief Assign (copy) a mesh key + * + * @param dst Destination mesh key + * @param src Source mesh key + */ +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src); + +/** + * @brief Destroy a mesh key + * + * Releases any resources associated with the key. + * + * @param key Mesh key to destroy + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_key_destroy(const struct bt_mesh_key *key); + +/** + * @brief Compare a raw key with a mesh key + * + * @param raw_key 16-byte raw key + * @param key Mesh key structure to compare + * + * @return 0 if equal, non-zero otherwise + */ +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key); + +/** + * @brief AES encryption (little-endian byte order) + * + * The key and plaintext are byte-swapped before encryption, + * and the result is byte-swapped after encryption. + * + * @param key 16-byte key + * @param plaintext 16-byte plaintext + * @param enc_data 16-byte output buffer + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]); + +/** + * @brief AES encryption (big-endian byte order) + * + * Standard AES-ECB encryption without byte swapping. + * + * @param key 16-byte key + * @param plaintext 16-byte plaintext + * @param enc_data 16-byte output buffer + * + * @return 0 on success, negative error code otherwise + */ +int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]); +#ifdef __cplusplus +} +#endif + +#endif /* _BLE_MESH_CRYPTO_H_ */ diff --git a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c index a322c0ab86..3826ca5c25 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2016 Intel Corporation - * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,14 +17,6 @@ #include "p_256_ecc_pp.h" #include "osi/future.h" #include "device/controller.h" - -#if CONFIG_MBEDTLS_HARDWARE_AES -#include "mbedtls/aes.h" -#endif - -#include -#include - #include "mesh/hci.h" #include "mesh/adapter.h" #include "mesh/common.h" @@ -56,10 +48,6 @@ struct bt_mesh_dev bt_mesh_dev; */ #define BLE_MESH_DEV 0 -/* P-256 Variables */ -static uint8_t bt_mesh_public_key[64]; -static uint8_t bt_mesh_private_key[32]; - /* Scan related functions */ static bt_mesh_scan_cb_t *bt_mesh_scan_dev_found_cb; @@ -2481,185 +2469,9 @@ void bt_mesh_gatt_deinit(void) void bt_mesh_adapt_init(void) { - /* initialization of P-256 parameters */ - p_256_init_curve(KEY_LENGTH_DWORDS_P256); - - /* Set "bt_mesh_dev.flags" to 0 (only the "BLE_MESH_DEV_HAS_PUB_KEY" - * flag is used) here, because we need to make sure each time after - * the private key is initialized, a corresponding public key must - * be generated. - */ + /* Use unified crypto module initialization */ + bt_mesh_crypto_init(); bt_mesh_atomic_set(bt_mesh_dev.flags, 0); - bt_mesh_rand(bt_mesh_private_key, sizeof(bt_mesh_private_key)); -} - -void bt_mesh_set_private_key(const uint8_t pri_key[32]) -{ - memcpy(bt_mesh_private_key, pri_key, 32); -} - -const uint8_t *bt_mesh_pub_key_get(void) -{ - uint8_t private_key[32] = {0}; - Point public_key = {0}; - - if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY)) { - return bt_mesh_public_key; - } - - /* BLE Mesh BQB test case MESH/NODE/PROV/UPD/BV-12-C requires - * different public key for each provisioning procedure. - * Note: if enabled, when Provisioner provision multiple devices - * at the same time, this may cause invalid confirmation value. - * - * Use the following code for generating different private key - * for each provisioning procedure. - * - * if (bt_mesh_rand(bt_mesh_private_key, BT_OCTET32_LEN)) { - * BT_ERR("%s, Unable to generate bt_mesh_private_key", __func__); - * return NULL; - * } - */ - - memcpy(private_key, bt_mesh_private_key, BT_OCTET32_LEN); - ECC_PointMult(&public_key, &(curve_p256.G), (DWORD *)private_key, KEY_LENGTH_DWORDS_P256); - - memcpy(bt_mesh_public_key, public_key.x, BT_OCTET32_LEN); - memcpy(bt_mesh_public_key + BT_OCTET32_LEN, public_key.y, BT_OCTET32_LEN); - - bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY); - - BT_DBG("Public Key %s", bt_hex(bt_mesh_public_key, sizeof(bt_mesh_public_key))); - - return bt_mesh_public_key; -} - -bool bt_mesh_check_public_key(const uint8_t key[64]) -{ - struct p256_pub_key { - uint8_t x[32]; - uint8_t y[32]; - } check = {0}; - - sys_memcpy_swap(check.x, key, 32); - sys_memcpy_swap(check.y, key + 32, 32); - - return ECC_CheckPointIsInElliCur_P256((Point *)&check); -} - -int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]) -{ - uint8_t private_key[32] = {0}; - Point peer_pub_key = {0}; - Point new_pub_key = {0}; - - BT_DBG("private key = %s", bt_hex(bt_mesh_private_key, BT_OCTET32_LEN)); - - memcpy(private_key, bt_mesh_private_key, BT_OCTET32_LEN); - memcpy(peer_pub_key.x, remote_pub_key, BT_OCTET32_LEN); - memcpy(peer_pub_key.y, &remote_pub_key[BT_OCTET32_LEN], BT_OCTET32_LEN); - - BT_DBG("remote public key x = %s", bt_hex(peer_pub_key.x, BT_OCTET32_LEN)); - BT_DBG("remote public key y = %s", bt_hex(peer_pub_key.y, BT_OCTET32_LEN)); - - ECC_PointMult(&new_pub_key, &peer_pub_key, (DWORD *)private_key, KEY_LENGTH_DWORDS_P256); - - BT_DBG("new public key x = %s", bt_hex(new_pub_key.x, 32)); - BT_DBG("new public key y = %s", bt_hex(new_pub_key.y, 32)); - - memcpy(dhkey, new_pub_key.x, 32); - - return 0; -} - -int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]) -{ - uint8_t tmp[16] = {0}; - - BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); - -#if CONFIG_MBEDTLS_HARDWARE_AES - mbedtls_aes_context ctx = {0}; - - mbedtls_aes_init(&ctx); - - sys_memcpy_swap(tmp, key, 16); - - if (mbedtls_aes_setkey_enc(&ctx, tmp, 128) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - sys_memcpy_swap(tmp, plaintext, 16); - - if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, - tmp, enc_data) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - mbedtls_aes_free(&ctx); -#else /* CONFIG_MBEDTLS_HARDWARE_AES */ - struct tc_aes_key_sched_struct s = {0}; - - sys_memcpy_swap(tmp, key, 16); - - if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) { - return -EINVAL; - } - - sys_memcpy_swap(tmp, plaintext, 16); - - if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) { - return -EINVAL; - } -#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ - - sys_mem_swap(enc_data, 16); - - BT_DBG("enc_data %s", bt_hex(enc_data, 16)); - - return 0; -} - -int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]) -{ - BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); - -#if CONFIG_MBEDTLS_HARDWARE_AES - mbedtls_aes_context ctx = {0}; - - mbedtls_aes_init(&ctx); - - if (mbedtls_aes_setkey_enc(&ctx, key, 128) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, - plaintext, enc_data) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - mbedtls_aes_free(&ctx); -#else /* CONFIG_MBEDTLS_HARDWARE_AES */ - struct tc_aes_key_sched_struct s = {0}; - - if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) { - return -EINVAL; - } - - if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) { - return -EINVAL; - } -#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ - - BT_DBG("enc_data %s", bt_hex(enc_data, 16)); - - return 0; } #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN diff --git a/components/bt/esp_ble_mesh/core/crypto.c b/components/bt/esp_ble_mesh/core/crypto.c index 3adba0be1f..37102ae6ef 100644 --- a/components/bt/esp_ble_mesh/core/crypto.c +++ b/components/bt/esp_ble_mesh/core/crypto.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,12 +11,6 @@ #include #include -#include -#include -#include -#include -#include - #include "crypto.h" #include "mesh/config.h" #include "mesh/common.h" @@ -29,29 +23,7 @@ #define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) #define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, - size_t sg_len, uint8_t mac[16]) -{ - struct tc_aes_key_sched_struct sched = {0}; - struct tc_cmac_struct state = {0}; - - if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { - return -EIO; - } - - for (; sg_len; sg_len--, sg++) { - if (tc_cmac_update(&state, sg->data, - sg->len) == TC_CRYPTO_FAIL) { - return -EIO; - } - } - - if (tc_cmac_final(mac, &state) == TC_CRYPTO_FAIL) { - return -EIO; - } - - return 0; -} +/* bt_mesh_aes_cmac is now mapped to bt_mesh_aes_cmac_raw_key from common crypto module */ int bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16], const char *info, uint8_t okm[16]) @@ -199,326 +171,9 @@ int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16]) return bt_mesh_k1(n, 16, salt, id128, out); } -static int bt_mesh_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t *enc_msg, size_t msg_len, - const uint8_t *aad, size_t aad_len, - uint8_t *out_msg, size_t mic_size) -{ - uint8_t msg[16] = {0}, pmsg[16] = {0}, cmic[16] = {0}, - cmsg[16] = {0}, Xn[16] = {0}, mic[16] = {0}; - uint16_t last_blk = 0U, blk_cnt = 0U; - size_t i = 0U, j = 0U; - int err = 0; - - if (msg_len < 1 || aad_len >= 0xff00) { - return -EINVAL; - } - - /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(0x0000, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmic); - if (err) { - return err; - } - - /* X_0 = e(AppKey, 0x09 || nonce || length) */ - if (mic_size == sizeof(uint64_t)) { - pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00); - } else { - pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00); - } - - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(msg_len, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* If AAD is being used to authenticate, include it here */ - if (aad_len) { - sys_put_be16(aad_len, pmsg); - - for (i = 0; i < sizeof(uint16_t); i++) { - pmsg[i] = Xn[i] ^ pmsg[i]; - } - - j = 0; - aad_len += sizeof(uint16_t); - while (aad_len > 16) { - do { - pmsg[i] = Xn[i] ^ aad[j]; - i++, j++; - } while (i < 16); - - aad_len -= 16; - i = 0; - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - for (; i < aad_len; i++, j++) { - pmsg[i] = Xn[i] ^ aad[j]; - } - - for (i = aad_len; i < 16; i++) { - pmsg[i] = Xn[i]; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16U; - } - - for (j = 0; j < blk_cnt; j++) { - if (j + 1 == blk_cnt) { - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - for (i = 0; i < last_blk; i++) { - msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i]; - } - - memcpy(out_msg + (j * 16), msg, last_blk); - - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < last_blk; i++) { - pmsg[i] = Xn[i] ^ msg[i]; - } - - for (i = last_blk; i < 16; i++) { - pmsg[i] = Xn[i] ^ 0x00; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* MIC = C_mic ^ X_1 */ - for (i = 0; i < sizeof(mic); i++) { - mic[i] = cmic[i] ^ Xn[i]; - } - } else { - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - for (i = 0; i < 16; i++) { - msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i]; - } - - memcpy(out_msg + (j * 16), msg, 16); - - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < 16; i++) { - pmsg[i] = Xn[i] ^ msg[i]; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - } - - if (memcmp(mic, enc_msg + msg_len, mic_size)) { - return -EBADMSG; - } - - return 0; -} - -static int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t *msg, size_t msg_len, - const uint8_t *aad, size_t aad_len, - uint8_t *out_msg, size_t mic_size) -{ - uint8_t pmsg[16] = {0}, cmic[16] = {0}, cmsg[16] = {0}, - mic[16] = {0}, Xn[16] = {0}; - uint16_t blk_cnt = 0U, last_blk = 0U; - size_t i = 0U, j = 0U; - int err = 0; - - BT_DBG("CCMEncrypt"); - BT_DBG("Key %s", bt_hex(key, 16)); - BT_DBG("Nonce %s", bt_hex(nonce, 13)); - BT_DBG("Len %u: %s", msg_len, bt_hex(msg, msg_len)); - BT_DBG("AADLen %u MicSize %u", aad_len, mic_size); - - /* Unsupported AAD size */ - if (aad_len >= 0xff00) { - return -EINVAL; - } - - /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(0x0000, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmic); - if (err) { - return err; - } - - /* X_0 = e(AppKey, 0x09 || nonce || length) */ - if (mic_size == sizeof(uint64_t)) { - pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00); - } else { - pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00); - } - - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(msg_len, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* If AAD is being used to authenticate, include it here */ - if (aad_len) { - sys_put_be16(aad_len, pmsg); - - for (i = 0; i < sizeof(uint16_t); i++) { - pmsg[i] = Xn[i] ^ pmsg[i]; - } - - j = 0; - aad_len += sizeof(uint16_t); - while (aad_len > 16) { - do { - pmsg[i] = Xn[i] ^ aad[j]; - i++, j++; - } while (i < 16); - - aad_len -= 16; - i = 0; - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - for (; i < aad_len; i++, j++) { - pmsg[i] = Xn[i] ^ aad[j]; - } - - for (i = aad_len; i < 16; i++) { - pmsg[i] = Xn[i]; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - } - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16U; - } - - for (j = 0; j < blk_cnt; j++) { - if (j + 1 == blk_cnt) { - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < last_blk; i++) { - pmsg[i] = Xn[i] ^ msg[(j * 16) + i]; - } - for (i = last_blk; i < 16; i++) { - pmsg[i] = Xn[i] ^ 0x00; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* MIC = C_mic ^ X_1 */ - for (i = 0; i < sizeof(mic); i++) { - mic[i] = cmic[i] ^ Xn[i]; - } - - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - for (i = 0; i < last_blk; i++) { - out_msg[(j * 16) + i] = - msg[(j * 16) + i] ^ cmsg[i]; - } - } else { - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - for (i = 0; i < 16; i++) { - pmsg[i] = Xn[i] ^ msg[(j * 16) + i]; - } - - err = bt_mesh_encrypt_be(key, pmsg, Xn); - if (err) { - return err; - } - - /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - pmsg[0] = 0x01; - memcpy(pmsg + 1, nonce, 13); - sys_put_be16(j + 1, pmsg + 14); - - err = bt_mesh_encrypt_be(key, pmsg, cmsg); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_N */ - for (i = 0; i < 16; i++) { - out_msg[(j * 16) + i] = - msg[(j * 16) + i] ^ cmsg[i]; - } - - } - } - - memcpy(out_msg + msg_len, mic, mic_size); - - return 0; -} +/* Use the unified crypto module for CCM operations */ +#define bt_mesh_ccm_decrypt bt_mesh_ccm_decrypt_raw_key +#define bt_mesh_ccm_encrypt bt_mesh_ccm_encrypt_raw_key #if CONFIG_BLE_MESH_PROXY static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu, diff --git a/components/bt/esp_ble_mesh/core/crypto.h b/components/bt/esp_ble_mesh/core/crypto.h index 69627c956b..5d5ecbc375 100644 --- a/components/bt/esp_ble_mesh/core/crypto.h +++ b/components/bt/esp_ble_mesh/core/crypto.h @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,26 +12,17 @@ #include #include "mesh/buf.h" +#include "mesh/crypto.h" /* Include common crypto API */ #ifdef __cplusplus extern "C" { #endif -struct bt_mesh_sg { - const void *data; - size_t len; -}; +/* Map bt_mesh_aes_cmac to bt_mesh_aes_cmac_raw_key from common crypto module. + * struct bt_mesh_sg is defined in mesh/crypto.h */ +#define bt_mesh_aes_cmac bt_mesh_aes_cmac_raw_key -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, - size_t sg_len, uint8_t mac[16]); - -static inline int bt_mesh_aes_cmac_one(const uint8_t key[16], const void *m, - size_t len, uint8_t mac[16]) -{ - struct bt_mesh_sg sg = { m, len }; - - return bt_mesh_aes_cmac(key, &sg, 1, mac); -} +/* bt_mesh_aes_cmac_one is defined as inline in mesh/crypto.h */ static inline bool bt_mesh_s1(const char *m, uint8_t salt[16]) { diff --git a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h index 20c656e690..ee06bff7f8 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2017 Intel Corporation - * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include "mesh/utils.h" #include "mesh/uuid.h" #include "mesh/buf.h" +#include "mesh/crypto.h" #ifdef __cplusplus extern "C" { @@ -932,20 +933,6 @@ void bt_mesh_gatt_deinit(void); void bt_mesh_adapt_init(void); -void bt_mesh_set_private_key(const uint8_t pri_key[32]); - -const uint8_t *bt_mesh_pub_key_get(void); - -bool bt_mesh_check_public_key(const uint8_t key[64]); - -int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]); - -int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]); - -int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]); - enum { BLE_MESH_EXCEP_LIST_SUB_CODE_ADD = 0, BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c index 1992fb87b3..5b7c82e567 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2016 Intel Corporation - * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,20 +10,12 @@ #include "btc/btc_task.h" #include "osi/alarm.h" - -#include "mbedtls/aes.h" -#include "mbedtls/ecp.h" - #include "host/ble_hs.h" #include "host/ble_uuid.h" #include "host/ble_att.h" #include "host/ble_gatt.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" - -#include -#include - #include "mesh/hci.h" #include "mesh/common.h" #include "prov_pvnr.h" @@ -65,10 +57,6 @@ static uint16_t proxy_svc_start_handle, prov_svc_start_handle; struct bt_mesh_dev bt_mesh_dev; -/* P-256 Variables */ -static uint8_t bt_mesh_public_key[64]; -static uint8_t bt_mesh_private_key[32]; - /* Scan related functions */ static bt_mesh_scan_cb_t *bt_mesh_scan_dev_found_cb; #if CONFIG_BLE_MESH_NODE @@ -2606,199 +2594,11 @@ void bt_mesh_gatt_deinit(void) } #endif /* CONFIG_BLE_MESH_DEINIT */ -void ble_sm_alg_ecc_init(void); - void bt_mesh_adapt_init(void) { - /* initialization of P-256 parameters */ - ble_sm_alg_ecc_init(); - - /* Set "bt_mesh_dev.flags" to 0 (only the "BLE_MESH_DEV_HAS_PUB_KEY" - * flag is used) here, because we need to make sure each time after - * the private key is initialized, a corresponding public key must - * be generated. - */ + /* Use unified crypto module initialization */ + bt_mesh_crypto_init(); bt_mesh_atomic_set(bt_mesh_dev.flags, 0); - bt_mesh_rand(bt_mesh_private_key, sizeof(bt_mesh_private_key)); -} - -void bt_mesh_set_private_key(const uint8_t pri_key[32]) -{ - memcpy(bt_mesh_private_key, pri_key, 32); -} - -int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); - -const uint8_t *bt_mesh_pub_key_get(void) -{ - uint8_t pri_key[32] = {0}; - -#if 1 - if (bt_mesh_atomic_test_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY)) { - return bt_mesh_public_key; - } -#else - /* BLE Mesh BQB test case MESH/NODE/PROV/UPD/BV-12-C requires - * different public key for each provisioning procedure. - * Note: if enabled, when Provisioner provision multiple devices - * at the same time, this may cause invalid confirmation value. - */ - if (bt_mesh_rand(bt_mesh_private_key, 32)) { - BT_ERR("%s, Unable to generate bt_mesh_private_key", __func__); - return NULL; - } -#endif - - int rc = ble_sm_alg_gen_key_pair(bt_mesh_public_key, pri_key); - if (rc != 0) { - BT_ERR("Failed to generate the key pair"); - return NULL; - } - memcpy(bt_mesh_private_key, pri_key, 32); - - bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_HAS_PUB_KEY); - - BT_DBG("Public Key %s", bt_hex(bt_mesh_public_key, sizeof(bt_mesh_public_key))); - - return bt_mesh_public_key; -} - -bool bt_mesh_check_public_key(const uint8_t key[64]) -{ - struct mbedtls_ecp_point pt = {0}; - mbedtls_ecp_group grp = {0}; - bool rc = false; - - uint8_t pub[65] = {0}; - /* Hardcoded first byte of pub key for MBEDTLS_ECP_PF_UNCOMPRESSED */ - pub[0] = 0x04; - memcpy(&pub[1], key, 64); - - /* Initialize the required structures here */ - mbedtls_ecp_point_init(&pt); - mbedtls_ecp_group_init(&grp); - - /* Below 3 steps are to validate public key on curve secp256r1 */ - if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) { - goto exit; - } - - if (mbedtls_ecp_point_read_binary(&grp, &pt, pub, 65) != 0) { - goto exit; - } - - if (mbedtls_ecp_check_pubkey(&grp, &pt) != 0) { - goto exit; - } - - rc = true; - -exit: - mbedtls_ecp_point_free(&pt); - mbedtls_ecp_group_free(&grp); - return rc; - -} - -int ble_sm_alg_gen_dhkey(uint8_t *peer_pub_key_x, uint8_t *peer_pub_key_y, - uint8_t *our_priv_key, uint8_t *out_dhkey); - -int bt_mesh_dh_key_gen(const uint8_t remote_pub_key[64], uint8_t dhkey[32]) -{ - BT_DBG("private key = %s", bt_hex(bt_mesh_private_key, 32)); - - return ble_sm_alg_gen_dhkey((uint8_t *)&remote_pub_key[0], (uint8_t *)&remote_pub_key[32], - bt_mesh_private_key, dhkey); -} - -int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]) -{ - uint8_t tmp[16] = {0}; - - BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); - -#if CONFIG_MBEDTLS_HARDWARE_AES - mbedtls_aes_context ctx = {0}; - - mbedtls_aes_init(&ctx); - - sys_memcpy_swap(tmp, key, 16); - - if (mbedtls_aes_setkey_enc(&ctx, tmp, 128) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - sys_memcpy_swap(tmp, plaintext, 16); - - if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, - tmp, enc_data) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - mbedtls_aes_free(&ctx); -#else /* CONFIG_MBEDTLS_HARDWARE_AES */ - struct tc_aes_key_sched_struct s = {0}; - - sys_memcpy_swap(tmp, key, 16); - - if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) { - return -EINVAL; - } - - sys_memcpy_swap(tmp, plaintext, 16); - - if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) { - return -EINVAL; - } -#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ - - sys_mem_swap(enc_data, 16); - - BT_DBG("enc_data %s", bt_hex(enc_data, 16)); - - return 0; -} - -int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], - uint8_t enc_data[16]) -{ - BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16)); - -#if CONFIG_MBEDTLS_HARDWARE_AES - mbedtls_aes_context ctx = {0}; - - mbedtls_aes_init(&ctx); - - if (mbedtls_aes_setkey_enc(&ctx, key, 128) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, - plaintext, enc_data) != 0) { - mbedtls_aes_free(&ctx); - return -EINVAL; - } - - mbedtls_aes_free(&ctx); -#else /* CONFIG_MBEDTLS_HARDWARE_AES */ - struct tc_aes_key_sched_struct s = {0}; - - if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) { - return -EINVAL; - } - - if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) { - return -EINVAL; - } -#endif /* CONFIG_MBEDTLS_HARDWARE_AES */ - - BT_DBG("enc_data %s", bt_hex(enc_data, 16)); - - return 0; } #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index 973239097d..90ce7d9bde 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -625,8 +625,8 @@ static void send_pub_key(void) * buffer as a temporary storage location. The validating * of the remote public key is finished when it is received. */ - sys_memcpy_swap(buf.data, &prov_link.conf_inputs[17], 32); - sys_memcpy_swap(&buf.data[32], &prov_link.conf_inputs[49], 32); + memcpy(buf.data, &prov_link.conf_inputs[17], 32); + memcpy(&buf.data[32], &prov_link.conf_inputs[49], 32); if (bt_mesh_dh_key_gen(buf.data, dhkey)) { BT_ERR("Unable to generate DHKey"); @@ -634,7 +634,7 @@ static void send_pub_key(void) return; } - sys_memcpy_swap(prov_link.dhkey, dhkey, 32); + memcpy(prov_link.dhkey, dhkey, 32); BT_DBG("DHkey: %s", bt_hex(prov_link.dhkey, 32)); @@ -652,8 +652,8 @@ static void send_pub_key(void) bt_mesh_prov_buf_init(&buf, PROV_PUB_KEY); /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32); + memcpy(net_buf_simple_add(&buf, 32), key, 32); + memcpy(net_buf_simple_add(&buf, 32), &key[32], 32); memcpy(&prov_link.conf_inputs[81], &buf.data[1], 64); @@ -673,8 +673,8 @@ static int bt_mesh_calc_dh_key(void) /* Copy remote key in little-endian for generating DHKey. * X and Y halves are swapped independently. */ - sys_memcpy_swap(&pub_key[0], &prov_link.conf_inputs[17], 32); - sys_memcpy_swap(&pub_key[32], &prov_link.conf_inputs[49], 32); + memcpy(&pub_key[0], &prov_link.conf_inputs[17], 32); + memcpy(&pub_key[32], &prov_link.conf_inputs[49], 32); if (bt_mesh_dh_key_gen(pub_key, dhkey)) { BT_ERR("Unable to generate DHKey"); @@ -682,7 +682,7 @@ static int bt_mesh_calc_dh_key(void) return -EIO; } - sys_memcpy_swap(prov_link.dhkey, dhkey, 32); + memcpy(prov_link.dhkey, dhkey, 32); BT_DBG("DHkey: %s", bt_hex(prov_link.dhkey, 32)); @@ -1558,8 +1558,6 @@ static void protocol_timeout(struct k_work *work) int bt_mesh_prov_init(void) { - const uint8_t *key = NULL; - if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; @@ -1574,8 +1572,7 @@ int bt_mesh_prov_init(void) __ASSERT(bt_mesh_prov_get()->uuid, "Device UUID not initialized"); - key = bt_mesh_pub_key_get(); - if (!key) { + if (bt_mesh_pub_key_gen()) { BT_ERR("Failed to generate public key"); return -EIO; } diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index d1df4a69e1..9e6beba21e 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1764,8 +1764,8 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) /* Copy public key in little-endian for generating DHKey. * X and Y halves are swapped independently. */ - sys_memcpy_swap(&pub_key[0], &link->conf_inputs[81], 32); - sys_memcpy_swap(&pub_key[32], &link->conf_inputs[113], 32); + memcpy(&pub_key[0], &link->conf_inputs[81], 32); + memcpy(&pub_key[32], &link->conf_inputs[113], 32); if (bt_mesh_dh_key_gen(pub_key, dhkey)) { BT_ERR("Failed to generate DHKey"); @@ -1773,7 +1773,7 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) return; } - sys_memcpy_swap(link->dhkey, dhkey, 32); + memcpy(link->dhkey, dhkey, 32); BT_DBG("DHKey: %s", bt_hex(link->dhkey, 32)); @@ -1861,9 +1861,8 @@ static void send_pub_key(struct bt_mesh_prov_link *link) bt_mesh_prov_buf_init(&buf, PROV_PUB_KEY); - /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32); + memcpy(net_buf_simple_add(&buf, 32), key, 32); + memcpy(net_buf_simple_add(&buf, 32), &key[32], 32); /* Store provisioner public key value in conf_inputs */ memcpy(&link->conf_inputs[17], &buf.data[1], 64); @@ -2819,7 +2818,6 @@ static void protocol_timeout(struct k_work *work) int bt_mesh_provisioner_prov_init(void) { - const uint8_t *key = NULL; int i; if (bt_mesh_prov_get() == NULL) { @@ -2827,8 +2825,7 @@ int bt_mesh_provisioner_prov_init(void) return -EINVAL; } - key = bt_mesh_pub_key_get(); - if (!key) { + if (bt_mesh_pub_key_gen()) { BT_ERR("Failed to generate Public Key"); return -EIO; } diff --git a/components/bt/esp_ble_mesh/lib/ext.c b/components/bt/esp_ble_mesh/lib/ext.c index 3f654f82de..4e15b43556 100644 --- a/components/bt/esp_ble_mesh/lib/ext.c +++ b/components/bt/esp_ble_mesh/lib/ext.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,8 +35,6 @@ #include "lpn.h" #include "rpl.h" #include "foundation.h" -#include -#include #include "mesh/buf.h" #include "mesh/slist.h" #include "mesh/config.h" @@ -562,24 +560,9 @@ int bt_mesh_ext_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, return bt_mesh_net_decrypt(key, buf, iv_index, proxy, proxy_solic); } -int bt_mesh_ext_tc_hmac_set_key(void *ctx, const uint8_t *key, unsigned int key_size) +int bt_mesh_ext_hmac_sha_256(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_len, uint8_t mac[32]) { - return tc_hmac_set_key(ctx, key, key_size); -} - -int bt_mesh_ext_tc_hmac_init(void *ctx) -{ - return tc_hmac_init(ctx); -} - -int bt_mesh_ext_tc_hmac_update(void *ctx, const void *data, unsigned int data_length) -{ - return tc_hmac_update(ctx, data, data_length); -} - -int bt_mesh_ext_tc_hmac_final(uint8_t *tag, unsigned int taglen, void *ctx) -{ - return tc_hmac_final(tag, taglen, ctx); + return bt_mesh_sha256_hmac_raw_key(key, sg, sg_len, mac); } /* Mutex */ @@ -4274,12 +4257,6 @@ static const bt_mesh_ext_config_t bt_mesh_ext_cfg = { .struct_addr_off_val = offsetof(bt_mesh_addr_t, val), .struct_sg_size = sizeof(struct bt_mesh_sg), .struct_sg_off_len = offsetof(struct bt_mesh_sg, len), - .struct_tc_sha256_state = sizeof(struct tc_sha256_state_struct), - .struct_tc_sha256_off_bits_hashed = offsetof(struct tc_sha256_state_struct, bits_hashed), - .struct_tc_sha256_off_leftover = offsetof(struct tc_sha256_state_struct, leftover), - .struct_tc_sha256_off_leftover_offset = offsetof(struct tc_sha256_state_struct, leftover_offset), - .struct_tc_hmac_state_size = sizeof(struct tc_hmac_state_struct), - .struct_tc_hmac_state_off_key = offsetof(struct tc_hmac_state_struct, key), .btc_ble_mesh_evt_agg_client_send_timeout = BTC_BLE_MESH_EVT_AGG_CLIENT_SEND_TIMEOUT, .btc_ble_mesh_evt_agg_client_recv_rsp = BTC_BLE_MESH_EVT_AGG_CLIENT_RECV_RSP, From b8571b135847d6d6a5fd13495159086fd4123f6a Mon Sep 17 00:00:00 2001 From: luoxu Date: Thu, 25 Dec 2025 20:28:45 +0800 Subject: [PATCH 46/84] feat(ble_mesh): supported using little endian crypto components --- .../bt/esp_ble_mesh/common/crypto_mbedtls.c | 10 +- .../bt/esp_ble_mesh/common/crypto_psa.c | 10 +- components/bt/esp_ble_mesh/common/crypto_tc.c | 10 +- .../esp_ble_mesh/common/include/mesh/crypto.h | 187 ++++++++++++++++-- components/bt/esp_ble_mesh/core/prov_node.c | 13 +- components/bt/esp_ble_mesh/core/prov_pvnr.c | 12 +- 6 files changed, 203 insertions(+), 39 deletions(-) diff --git a/components/bt/esp_ble_mesh/common/crypto_mbedtls.c b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c index 24b0b76308..5ff9670b5f 100644 --- a/components/bt/esp_ble_mesh/common/crypto_mbedtls.c +++ b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c @@ -281,7 +281,7 @@ cleanup: return ret == 0 ? 0 : -EIO; } -const uint8_t *bt_mesh_pub_key_get(void) +const uint8_t *bt_mesh_pub_key_get_raw(void) { if (!dh_pair.is_ready) { if (bt_mesh_pub_key_gen() != 0) { @@ -292,7 +292,7 @@ const uint8_t *bt_mesh_pub_key_get(void) return dh_pair.public_key; } -void bt_mesh_set_private_key(const uint8_t pri_key[32]) +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) { mbedtls_ecp_group grp; mbedtls_mpi d; @@ -343,7 +343,7 @@ cleanup: mbedtls_ecp_point_free(&Q); } -bool bt_mesh_check_public_key(const uint8_t key[64]) +bool bt_mesh_check_public_key_raw(const uint8_t key[64]) { mbedtls_ecp_group grp; mbedtls_ecp_point Q; @@ -382,8 +382,8 @@ cleanup: return ret == 0; } -int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, - uint8_t *dhkey) +int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) { mbedtls_ecp_group grp; mbedtls_mpi d; diff --git a/components/bt/esp_ble_mesh/common/crypto_psa.c b/components/bt/esp_ble_mesh/common/crypto_psa.c index 9619700634..16dd15bca0 100644 --- a/components/bt/esp_ble_mesh/common/crypto_psa.c +++ b/components/bt/esp_ble_mesh/common/crypto_psa.c @@ -343,7 +343,7 @@ int bt_mesh_pub_key_gen(void) return 0; } -const uint8_t *bt_mesh_pub_key_get(void) +const uint8_t *bt_mesh_pub_key_get_raw(void) { if (!dh_pair.is_ready) { if (bt_mesh_pub_key_gen() != 0) { @@ -354,7 +354,7 @@ const uint8_t *bt_mesh_pub_key_get(void) return &dh_pair.public_key[1]; } -void bt_mesh_set_private_key(const uint8_t pri_key[32]) +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_status_t status; @@ -396,7 +396,7 @@ void bt_mesh_set_private_key(const uint8_t pri_key[32]) psa_reset_key_attributes(&attributes); } -bool bt_mesh_check_public_key(const uint8_t key[64]) +bool bt_mesh_check_public_key_raw(const uint8_t key[64]) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_id_t key_id; @@ -425,8 +425,8 @@ bool bt_mesh_check_public_key(const uint8_t key[64]) return true; } -int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, - uint8_t *dhkey) +int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) { psa_key_id_t priv_key_id = PSA_KEY_ID_NULL; uint8_t public_key_be[PUB_KEY_SIZE + 1]; diff --git a/components/bt/esp_ble_mesh/common/crypto_tc.c b/components/bt/esp_ble_mesh/common/crypto_tc.c index 9fd9e97b91..f4c780edd6 100644 --- a/components/bt/esp_ble_mesh/common/crypto_tc.c +++ b/components/bt/esp_ble_mesh/common/crypto_tc.c @@ -211,7 +211,7 @@ int bt_mesh_pub_key_gen(void) return 0; } -const uint8_t *bt_mesh_pub_key_get(void) +const uint8_t *bt_mesh_pub_key_get_raw(void) { if (!dh_pair.is_ready) { if (bt_mesh_pub_key_gen() != 0) { @@ -222,7 +222,7 @@ const uint8_t *bt_mesh_pub_key_get(void) return dh_pair.public_key; } -void bt_mesh_set_private_key(const uint8_t pri_key[32]) +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) { int rc; @@ -239,13 +239,13 @@ void bt_mesh_set_private_key(const uint8_t pri_key[32]) dh_pair.is_ready = true; } -bool bt_mesh_check_public_key(const uint8_t key[64]) +bool bt_mesh_check_public_key_raw(const uint8_t key[64]) { return uECC_valid_public_key(key, uECC_secp256r1()) == 0; } -int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, - uint8_t *dhkey) +int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) { if (uECC_valid_public_key(pub_key, uECC_secp256r1()) != 0) { BT_ERR("Public key is not valid"); diff --git a/components/bt/esp_ble_mesh/common/include/mesh/crypto.h b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h index 38a8b3f208..806e84f479 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/crypto.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h @@ -25,6 +25,87 @@ extern "C" { #define PUB_KEY_SIZE 64 #define DH_KEY_SIZE 32 +/** + * @brief Crypto module endianness definitions + * + * BLE Mesh protocol uses big-endian format for ECC operations. + * These macros define whether the underlying crypto implementation + * expects big-endian or little-endian input. + * + * - BT_MESH_CRYPTO_ENDIAN_BIG: Module expects big-endian (TinyCrypt, MbedTLS, PSA) + * - BT_MESH_CRYPTO_ENDIAN_LITTLE: Module expects little-endian (future implementations) + */ +#define BT_MESH_CRYPTO_ENDIAN_BIG 0 +#define BT_MESH_CRYPTO_ENDIAN_LITTLE 1 + +/** + * @brief Current crypto module endianness + * + * This macro should be defined by the crypto implementation. + * Default is big-endian (matching TinyCrypt, MbedTLS, PSA). + */ +#ifndef BT_MESH_CRYPTO_ENDIAN +#define BT_MESH_CRYPTO_ENDIAN BT_MESH_CRYPTO_ENDIAN_BIG +#endif + +/** + * @brief Parameter conversion macros for endianness handling + * + * These macros automatically handle byte order conversion between + * BLE Mesh's big-endian format and the crypto module's expected format. + * + * For public keys (64 bytes = X + Y), the X and Y coordinates must be + * swapped separately, not as a single 64-byte block. + */ +#if (BT_MESH_CRYPTO_ENDIAN == BT_MESH_CRYPTO_ENDIAN_LITTLE) + +/* Little-endian mode: need byte order conversion */ +#define CRYPTO_PARAM_DECLARE(name, size) \ + uint8_t _##name[size] + +#define CRYPTO_PARAM_IN(name, size) \ + sys_memcpy_swap(_##name, name, size) + +#define CRYPTO_PARAM_OUT(name, size) \ + sys_memcpy_swap((uint8_t *)(name), _##name, size) + +#define CRYPTO_PARAM(name) (_##name) + +/* Public key (64 bytes) needs special handling: swap X and Y separately */ +#define CRYPTO_PARAM_PUBKEY_IN(name) \ + do { \ + sys_memcpy_swap(_##name, name, 32); \ + sys_memcpy_swap(_##name + 32, (name) + 32, 32); \ + } while (0) + +#define CRYPTO_PARAM_PUBKEY_OUT(name) \ + do { \ + sys_memcpy_swap((uint8_t *)(name), _##name, 32); \ + sys_memcpy_swap((uint8_t *)(name) + 32, _##name + 32, 32); \ + } while (0) + +#else /* BT_MESH_CRYPTO_ENDIAN_BIG */ + +/* Big-endian mode: no conversion needed, use original parameters directly */ +#define CRYPTO_PARAM_DECLARE(name, size) \ + (void)0 + +#define CRYPTO_PARAM_IN(name, size) \ + (void)0 + +#define CRYPTO_PARAM_OUT(name, size) \ + (void)0 + +#define CRYPTO_PARAM(name) (name) + +#define CRYPTO_PARAM_PUBKEY_IN(name) \ + (void)0 + +#define CRYPTO_PARAM_PUBKEY_OUT(name) \ + (void)0 + +#endif /* BT_MESH_CRYPTO_ENDIAN */ + /** * @brief Scatter-Gather data structure for cryptographic operations */ @@ -214,6 +295,25 @@ static inline int bt_mesh_sha256_hmac_one(const uint8_t key[32], const void *m, return bt_mesh_sha256_hmac_raw_key(key, &sg, 1, mac); } +/* ============================================================================ + * Internal Low-Level ECC APIs + * ============================================================================ + * These functions operate in the crypto module's native byte order. + * Do NOT call these directly - use the public wrapper functions below. + */ +const uint8_t *bt_mesh_pub_key_get_raw(void); +void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]); +bool bt_mesh_check_public_key_raw(const uint8_t key[64]); +int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey); + +/* ============================================================================ + * Public ECC APIs (with automatic endianness conversion) + * ============================================================================ + * All public key and DHKey parameters use big-endian format (BLE Mesh protocol). + * For little-endian crypto modules, conversion is handled automatically. + */ + /** * @brief Generate a new ECC public key pair * @@ -225,41 +325,106 @@ static inline int bt_mesh_sha256_hmac_one(const uint8_t key[32], const void *m, int bt_mesh_pub_key_gen(void); /** - * @brief Get the current public key + * @brief Get the current public key (raw pointer) * - * @return Pointer to 64-byte public key (X || Y), or NULL if not ready + * Returns pointer to the internal public key storage. + * Note: The byte order depends on crypto module's native format. + * Use bt_mesh_pub_key_copy() to get big-endian format. + * + * @return Pointer to 64-byte public key, or NULL if not ready */ -const uint8_t *bt_mesh_pub_key_get(void); +#define bt_mesh_pub_key_get() bt_mesh_pub_key_get_raw() + +/** + * @brief Copy current public key to user buffer (big-endian output) + * + * Copies the public key to the provided buffer, converting to big-endian + * format (BLE Mesh protocol format) if necessary. + * + * @param buf 64-byte output buffer for public key (big-endian output) + * + * @return 0 on success, -EAGAIN if public key not ready + */ +static inline int bt_mesh_pub_key_copy(uint8_t buf[64]) +{ + const uint8_t *key = bt_mesh_pub_key_get_raw(); + + if (key == NULL) { + return -EAGAIN; + } + +#if (BT_MESH_CRYPTO_ENDIAN == BT_MESH_CRYPTO_ENDIAN_LITTLE) + /* Swap X and Y coordinates separately to big-endian */ + sys_memcpy_swap(buf, key, 32); + sys_memcpy_swap(buf + 32, key + 32, 32); +#else + memcpy(buf, key, PUB_KEY_SIZE); +#endif + + return 0; +} /** * @brief Set a custom private key * - * @param pri_key 32-byte private key + * @param pri_key 32-byte private key (big-endian, BLE Mesh format) */ -void bt_mesh_set_private_key(const uint8_t pri_key[32]); +static inline void bt_mesh_set_private_key(const uint8_t pri_key[32]) +{ + CRYPTO_PARAM_DECLARE(pri_key, PRIV_KEY_SIZE); + CRYPTO_PARAM_IN(pri_key, PRIV_KEY_SIZE); + bt_mesh_set_private_key_raw(CRYPTO_PARAM(pri_key)); +} /** * @brief Check if a public key is valid * * Verifies that the given public key is a valid point on the P-256 curve. * - * @param key 64-byte public key (X || Y) + * @param key 64-byte public key (X || Y, big-endian, BLE Mesh format) * * @return true if valid, false otherwise */ -bool bt_mesh_check_public_key(const uint8_t key[64]); +static inline bool bt_mesh_check_public_key(const uint8_t key[64]) +{ + CRYPTO_PARAM_DECLARE(key, PUB_KEY_SIZE); + CRYPTO_PARAM_PUBKEY_IN(key); + return bt_mesh_check_public_key_raw(CRYPTO_PARAM(key)); +} /** * @brief Generate ECDH shared secret (DHKey) * - * @param pub_key 64-byte remote public key (X || Y) + * @param pub_key 64-byte remote public key (X || Y, big-endian, BLE Mesh format) * @param priv_key 32-byte private key (NULL to use internal key) - * @param dhkey 32-byte output buffer for shared secret + * @param dhkey 32-byte output buffer for shared secret (big-endian output) * * @return 0 on success, negative error code otherwise */ -int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, - uint8_t *dhkey); +static inline int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, + uint8_t *dhkey) +{ + int rc; + CRYPTO_PARAM_DECLARE(pub_key, PUB_KEY_SIZE); + CRYPTO_PARAM_DECLARE(priv_key, PRIV_KEY_SIZE); + CRYPTO_PARAM_DECLARE(dhkey, DH_KEY_SIZE); + + /* Public key: swap X and Y coordinates separately */ + CRYPTO_PARAM_PUBKEY_IN(pub_key); + if (priv_key != NULL) { + CRYPTO_PARAM_IN(priv_key, PRIV_KEY_SIZE); + } + + rc = bt_mesh_dhkey_gen_raw(CRYPTO_PARAM(pub_key), + priv_key ? CRYPTO_PARAM(priv_key) : NULL, + CRYPTO_PARAM(dhkey)); + if (rc) { + return rc; + } + + CRYPTO_PARAM_OUT(dhkey, DH_KEY_SIZE); + return rc; +} #define bt_mesh_dh_key_gen(pubkey, dhkey) bt_mesh_dhkey_gen(pubkey, NULL, dhkey) diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index 90ce7d9bde..dc550594df 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -616,7 +616,7 @@ int bt_mesh_input_string(const char *str) static void send_pub_key(void) { - const uint8_t *key = NULL; + uint8_t pub_key[64] = {0}; uint8_t dhkey[32] = {0}; PROV_BUF(buf, 65); @@ -640,20 +640,19 @@ static void send_pub_key(void) bt_mesh_atomic_set_bit(prov_link.flags, HAVE_DHKEY); - key = bt_mesh_pub_key_get(); - if (!key) { + if (bt_mesh_pub_key_copy(pub_key)) { BT_ERR("No public key available"); close_link(PROV_ERR_UNEXP_ERR); return; } - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); + BT_DBG("Local Public Key: %s", bt_hex(pub_key, 64)); bt_mesh_prov_buf_init(&buf, PROV_PUB_KEY); - /* Swap X and Y halves independently to big-endian */ - memcpy(net_buf_simple_add(&buf, 32), key, 32); - memcpy(net_buf_simple_add(&buf, 32), &key[32], 32); + /* Public key is already in big-endian format from bt_mesh_pub_key_copy() */ + memcpy(net_buf_simple_add(&buf, 32), pub_key, 32); + memcpy(net_buf_simple_add(&buf, 32), &pub_key[32], 32); memcpy(&prov_link.conf_inputs[81], &buf.data[1], 64); diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index 9e6beba21e..26fb72e167 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -1847,22 +1847,22 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) static void send_pub_key(struct bt_mesh_prov_link *link) { - const uint8_t *key = NULL; + uint8_t pub_key[64] = {0}; PROV_BUF(buf, 65); - key = bt_mesh_pub_key_get(); - if (!key) { + if (bt_mesh_pub_key_copy(pub_key)) { BT_ERR("No public key available"); close_link(link, CLOSE_REASON_FAILED); return; } - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); + BT_DBG("Local Public Key: %s", bt_hex(pub_key, 64)); bt_mesh_prov_buf_init(&buf, PROV_PUB_KEY); - memcpy(net_buf_simple_add(&buf, 32), key, 32); - memcpy(net_buf_simple_add(&buf, 32), &key[32], 32); + /* Public key is already in big-endian format from bt_mesh_pub_key_copy() */ + memcpy(net_buf_simple_add(&buf, 32), pub_key, 32); + memcpy(net_buf_simple_add(&buf, 32), &pub_key[32], 32); /* Store provisioner public key value in conf_inputs */ memcpy(&link->conf_inputs[17], &buf.data[1], 64); From 8a600bbeeb2646c124e3e6ac52611db0ec2db5e8 Mon Sep 17 00:00:00 2001 From: luoxu Date: Fri, 26 Dec 2025 15:46:56 +0800 Subject: [PATCH 47/84] feat(ble_mesh): fixed issues where the incorrect node oob private setting --- .../api/core/include/esp_ble_mesh_provisioning_api.h | 8 ++++---- components/bt/esp_ble_mesh/common/crypto_mbedtls.c | 2 ++ components/bt/esp_ble_mesh/common/crypto_psa.c | 2 ++ components/bt/esp_ble_mesh/common/crypto_tc.c | 2 ++ components/bt/esp_ble_mesh/common/include/mesh/crypto.h | 4 ++-- components/bt/esp_ble_mesh/core/prov_node.c | 5 ++++- 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h index 58ad280468..a603689769 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -67,9 +67,9 @@ esp_err_t esp_ble_mesh_node_prov_disable(esp_ble_mesh_prov_bearer_t bearers); * So as an unprovisioned device, it should use this function to input * the Public Key exchanged through the out-of-band mechanism. * - * @param[in] pub_key_x: Unprovisioned device's Public Key X - * @param[in] pub_key_y: Unprovisioned device's Public Key Y - * @param[in] private_key: Unprovisioned device's Private Key + * @param[in] pub_key_x: Unprovisioned device's Public Key X(Little Endian) + * @param[in] pub_key_y: Unprovisioned device's Public Key Y(Little Endian) + * @param[in] private_key: Unprovisioned device's Private Key(Little Endian) * * @return ESP_OK on success or error code otherwise. */ diff --git a/components/bt/esp_ble_mesh/common/crypto_mbedtls.c b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c index 5ff9670b5f..45fe7a78bb 100644 --- a/components/bt/esp_ble_mesh/common/crypto_mbedtls.c +++ b/components/bt/esp_ble_mesh/common/crypto_mbedtls.c @@ -335,6 +335,8 @@ void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) goto cleanup; } + BT_DBG("Pubkey:%s", bt_hex(dh_pair.public_key, PUB_KEY_SIZE)); + BT_DBG("Privkey:%s", bt_hex(dh_pair.private_key, PRIV_KEY_SIZE)); dh_pair.is_ready = true; cleanup: diff --git a/components/bt/esp_ble_mesh/common/crypto_psa.c b/components/bt/esp_ble_mesh/common/crypto_psa.c index 16dd15bca0..3655c48cb6 100644 --- a/components/bt/esp_ble_mesh/common/crypto_psa.c +++ b/components/bt/esp_ble_mesh/common/crypto_psa.c @@ -392,6 +392,8 @@ void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) return; } + BT_DBG("Pubkey:%s", bt_hex(&dh_pair.public_key[1], PUB_KEY_SIZE)); + BT_DBG("Privkey:%s", bt_hex(pri_key, PRIV_KEY_SIZE)); dh_pair.is_ready = true; psa_reset_key_attributes(&attributes); } diff --git a/components/bt/esp_ble_mesh/common/crypto_tc.c b/components/bt/esp_ble_mesh/common/crypto_tc.c index f4c780edd6..2c4d39499b 100644 --- a/components/bt/esp_ble_mesh/common/crypto_tc.c +++ b/components/bt/esp_ble_mesh/common/crypto_tc.c @@ -236,6 +236,8 @@ void bt_mesh_set_private_key_raw(const uint8_t pri_key[32]) return; } + BT_DBG("Pubkey:%s", bt_hex(dh_pair.public_key, PUB_KEY_SIZE)); + BT_DBG("Privkey:%s", bt_hex(dh_pair.private_key, PRIV_KEY_SIZE)); dh_pair.is_ready = true; } diff --git a/components/bt/esp_ble_mesh/common/include/mesh/crypto.h b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h index 806e84f479..0ae0cad1cb 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/crypto.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/crypto.h @@ -345,11 +345,11 @@ int bt_mesh_pub_key_gen(void); * * @return 0 on success, -EAGAIN if public key not ready */ -static inline int bt_mesh_pub_key_copy(uint8_t buf[64]) +static inline int bt_mesh_pub_key_copy(uint8_t *buf) { const uint8_t *key = bt_mesh_pub_key_get_raw(); - if (key == NULL) { + if (key == NULL || buf == NULL) { return -EAGAIN; } diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index dc550594df..15f24bf3d6 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -703,6 +703,8 @@ int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], const uint8_t pub_key_y[32], const uint8_t pri_key[32]) { + uint8_t privkey[32] = {0}; + if (!pub_key_x || !pub_key_y || !pri_key) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -714,7 +716,8 @@ int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], */ sys_memcpy_swap(&prov_link.conf_inputs[81], pub_key_x, 32); sys_memcpy_swap(&prov_link.conf_inputs[81] + 32, pub_key_y, 32); - bt_mesh_set_private_key(pri_key); + sys_memcpy_swap(privkey, pri_key, 32); + bt_mesh_set_private_key(privkey); bt_mesh_atomic_set_bit(prov_link.flags, OOB_PUB_KEY); From de411d18a499b543c840f812e208fbe3f0a57d9c Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 6 Jan 2026 14:34:09 +0800 Subject: [PATCH 48/84] feat(ble_mesh): update lib commit to d48251ab82 --- components/bt/esp_ble_mesh/lib/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/esp_ble_mesh/lib/lib b/components/bt/esp_ble_mesh/lib/lib index 85e64e61f8..e44762384e 160000 --- a/components/bt/esp_ble_mesh/lib/lib +++ b/components/bt/esp_ble_mesh/lib/lib @@ -1 +1 @@ -Subproject commit 85e64e61f8471f34bd940e1fe1bdc92f58ed6bef +Subproject commit e44762384ed104a0ebc78f134eeba5f3ab648ddc From 6f8cd3c9ac1ff653184dcecd3dfe6f0144e377a7 Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 6 Jan 2026 14:40:10 +0800 Subject: [PATCH 49/84] feat(ble): Make Tinycrypto the default encryption choice for BLE components --- components/bt/common/Kconfig.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/common/Kconfig.in b/components/bt/common/Kconfig.in index 0c0b040ab4..654e11b391 100644 --- a/components/bt/common/Kconfig.in +++ b/components/bt/common/Kconfig.in @@ -9,7 +9,7 @@ config BT_ALARM_MAX_NUM choice BT_SMP_CRYPTO_STACK prompt "SMP cryptographic stack" depends on (BT_BLE_SMP_ENABLE || BT_SMP_ENABLE || BT_NIMBLE_SECURITY_ENABLE) - default BT_SMP_CRYPTO_STACK_NATIVE + default BT_SMP_CRYPTO_STACK_TINYCRYPT help Select the cryptographic library to use for SMP operations (AES, AES-CMAC, ECDH P-256). From 67ea80c78a07b2d45343e6293ae5cad85f669168 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Tue, 6 Jan 2026 19:37:45 +0800 Subject: [PATCH 50/84] fix(ble/bluedroid): Fixed smp unit test failed if mbedTLS or TinyCrypt is enabled --- .../basic_unit_test/main/CMakeLists.txt | 7 +++ .../test_apps/basic_unit_test/main/test_smp.c | 59 ++++++++----------- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/components/bt/test_apps/basic_unit_test/main/CMakeLists.txt b/components/bt/test_apps/basic_unit_test/main/CMakeLists.txt index 6aecb24e3d..d873380d2b 100644 --- a/components/bt/test_apps/basic_unit_test/main/CMakeLists.txt +++ b/components/bt/test_apps/basic_unit_test/main/CMakeLists.txt @@ -4,3 +4,10 @@ idf_component_register(SRCS "test_bt_main.c" INCLUDE_DIRS "." PRIV_REQUIRES unity bt WHOLE_ARCHIVE) + +# Add private include directories from bt component to access internal headers +idf_component_get_property(bt_dir bt COMPONENT_DIR) +target_include_directories(${COMPONENT_LIB} PRIVATE ${bt_dir}/host/bluedroid/stack/smp/include) +target_include_directories(${COMPONENT_LIB} PRIVATE ${bt_dir}/host/bluedroid/common/include) +target_include_directories(${COMPONENT_LIB} PRIVATE ${bt_dir}/host/bluedroid/stack/include) +target_include_directories(${COMPONENT_LIB} PRIVATE ${bt_dir}/common/include) diff --git a/components/bt/test_apps/basic_unit_test/main/test_smp.c b/components/bt/test_apps/basic_unit_test/main/test_smp.c index ea89ec261b..01bbc5b64c 100644 --- a/components/bt/test_apps/basic_unit_test/main/test_smp.c +++ b/components/bt/test_apps/basic_unit_test/main/test_smp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -18,42 +18,14 @@ #include "esp_bt_main.h" #include "esp_bt_device.h" #include "esp_gap_ble_api.h" +#include "sdkconfig.h" + +#if defined(CONFIG_BT_SMP_CRYPTO_STACK_NATIVE) && CONFIG_BT_SMP_CRYPTO_STACK_NATIVE +/* Native Bluedroid crypto implementation tests */ +#include "p_256_ecc_pp.h" #define KEY_LENGTH_DWORDS_P256 8 -typedef unsigned long DWORD; -typedef uint32_t UINT32; - -typedef struct { - DWORD x[KEY_LENGTH_DWORDS_P256]; - DWORD y[KEY_LENGTH_DWORDS_P256]; - DWORD z[KEY_LENGTH_DWORDS_P256]; -} Point; - -typedef struct { - // curve's coefficients - DWORD a[KEY_LENGTH_DWORDS_P256]; - DWORD b[KEY_LENGTH_DWORDS_P256]; - - //whether a is -3 - int a_minus3; - - // prime modulus - DWORD p[KEY_LENGTH_DWORDS_P256]; - - // Omega, p = 2^m -omega - DWORD omega[KEY_LENGTH_DWORDS_P256]; - - // base point, a point on E of order r - Point G; - -} elliptic_curve_t; - -extern void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength); -extern bool ECC_CheckPointIsInElliCur_P256(Point *p); -extern void p_256_init_curve(UINT32 keyLength); -extern elliptic_curve_t curve_p256; - static void bt_rand(void *buf, size_t len) { if (!len) { @@ -70,7 +42,17 @@ static void bt_rand(void *buf, size_t len) return; } -TEST_CASE("ble_smp_public_key_check", "[ble_smp]") +/** + * @brief Test ECC public key validation for native Bluedroid crypto implementation + * + * This test is only compiled when SMP_CRYPTO_STACK_NATIVE is enabled. + * It tests the native Bluedroid ECC implementation including: + * - Public key generation from private key + * - Public key validation on elliptic curve + * - Attack simulation (invalid public key detection) + * - Random key generation and validation + */ +TEST_CASE("ble_smp_public_key_check", "[ble_smp][native_crypto]") { /* We wait init finish 200ms here */ vTaskDelay(200 / portTICK_PERIOD_MS); @@ -96,7 +78,14 @@ TEST_CASE("ble_smp_public_key_check", "[ble_smp]") TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key)); } } +#endif /* CONFIG_BT_SMP_CRYPTO_STACK_NATIVE */ +/** + * @brief Test static passkey set/clear functionality + * + * This test is applicable to all crypto stack implementations (Native, TinyCrypt, mbedTLS). + * It tests the SMP security parameter API for setting and clearing static passkeys. + */ TEST_CASE("ble_smp_set_clear_static_passkey", "[ble_smp]") { /* We wait init finish 200ms here */ From 85240aef96e9ca4886d0f85af325309c06c89810 Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Wed, 26 Nov 2025 13:15:39 +0100 Subject: [PATCH 51/84] ci: introduce default marker `rev_default` --- tools/ci/idf_pytest/constants.py | 9 +++++++++ tools/ci/idf_pytest/plugin.py | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/tools/ci/idf_pytest/constants.py b/tools/ci/idf_pytest/constants.py index 17f107258e..b148792b3c 100644 --- a/tools/ci/idf_pytest/constants.py +++ b/tools/ci/idf_pytest/constants.py @@ -151,6 +151,7 @@ ENV_MARKERS = { 'recovery_bootloader': 'Runner with recovery bootloader offset set in eFuse', 'esp32p4_eco4': 'Runner with esp32p4 eco4 connected', 'esp32c5_eco3': 'Runner with esp32c5 eco3 connected', + 'rev_default': 'Runner with default revision connected', } # by default the timeout is 1h, for some special cases we need to extend it @@ -363,3 +364,11 @@ class PytestCase: msg += '\nMight be a issue of .build-test-rules.yml files' print(msg) return msg + + +ECO_MARKERS = [ + 'esp32eco3', + 'esp32c2eco4', + 'esp32c3eco7', + 'esp32p4_eco4', +] diff --git a/tools/ci/idf_pytest/plugin.py b/tools/ci/idf_pytest/plugin.py index c74313ac84..43113271e4 100644 --- a/tools/ci/idf_pytest/plugin.py +++ b/tools/ci/idf_pytest/plugin.py @@ -26,6 +26,7 @@ from pytest_ignore_test_results.ignore_results import ChildCase from pytest_ignore_test_results.ignore_results import ChildCasesStashKey from .constants import DEFAULT_SDKCONFIG +from .constants import ECO_MARKERS from .constants import PREVIEW_TARGETS from .constants import SUPPORTED_TARGETS from .constants import CollectMode @@ -318,6 +319,12 @@ class IdfPytestEmbedded: if 'esp32c2' in self.target and 'esp32c2' in case.targets and 'xtal_26mhz' not in case.all_markers: item.add_marker('xtal_40mhz') + for eco_marker in ECO_MARKERS: + if eco_marker in case.all_markers: + break + else: + item.add_marker('rev_default') + def pytest_report_collectionfinish(self, items: t.List[Function]) -> None: self.cases = [item.stash[ITEM_PYTEST_CASE_KEY] for item in items] From b6dd851bed36b25012868171cb9bd230f0553142 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Sat, 17 Jan 2026 16:37:29 +0530 Subject: [PATCH 52/84] fix(nimble): Fix memory leak in controller/stack deinit sequence --- 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 d9a6fa8630..883c9ebed0 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit d9a6fa863017fd6d8486c50d244acfbbb898a590 +Subproject commit 883c9ebed02e937fc3756a3d9fc1e3008500bb69 From 58acd42c431ceef6a77abae5860ee0ab054d4a35 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Mon, 5 Jan 2026 15:50:57 +0800 Subject: [PATCH 53/84] fix(esp_hal_wdt): replace the erroneous RWDT timeout config in ROM with the code in ram --- components/esp_rom/esp32p4/ld/esp32p4.rom.wdt.ld | 2 +- components/esp_rom/patches/esp_rom_wdt.c | 15 ++++++++++++++- components/hal/include/hal/wdt_hal.h | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.wdt.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.wdt.ld index 6b872fa581..ed3bfd3d81 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.wdt.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.wdt.ld @@ -20,7 +20,7 @@ /* Functions */ wdt_hal_init = 0x4fc001fc; wdt_hal_deinit = 0x4fc00200; -wdt_hal_config_stage = 0x4fc00204; +rom_wdt_hal_config_stage = 0x4fc00204; wdt_hal_write_protect_disable = 0x4fc00208; wdt_hal_write_protect_enable = 0x4fc0020c; wdt_hal_enable = 0x4fc00210; diff --git a/components/esp_rom/patches/esp_rom_wdt.c b/components/esp_rom/patches/esp_rom_wdt.c index 7770911a46..d3582fdfed 100644 --- a/components/esp_rom/patches/esp_rom_wdt.c +++ b/components/esp_rom/patches/esp_rom_wdt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -118,6 +118,19 @@ void wdt_hal_deinit(wdt_hal_context_t *hal) //Deinit HAL context hal->mwdt_dev = NULL; } + +#if CONFIG_IDF_TARGET_ESP32P4 +extern void rom_wdt_hal_config_stage(wdt_hal_context_t *hal, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior); + +/* rwdt_ll_config_stage is implemented erroneously in ESP32P4 rom code, TODO: PM-654*/ +void wdt_hal_config_stage(wdt_hal_context_t *hal, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior) +{ + if (hal->inst == WDT_RWDT && stage == WDT_STAGE0) { + timeout_ticks = timeout_ticks >> (1 + REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_WDT_DELAY_SEL)); + } + rom_wdt_hal_config_stage(hal, stage, timeout_ticks, behavior); +} +#endif // CONFIG_IDF_TARGET_ESP32P4 #endif // ESP_ROM_WDT_INIT_PATCH #endif // CONFIG_HAL_WDT_USE_ROM_IMPL diff --git a/components/hal/include/hal/wdt_hal.h b/components/hal/include/hal/wdt_hal.h index 87a31f6eca..a46f78a290 100644 --- a/components/hal/include/hal/wdt_hal.h +++ b/components/hal/include/hal/wdt_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ From 65a26973b8f552e4311d3703372257db9879def0 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 20 Jan 2026 21:14:17 +0800 Subject: [PATCH 54/84] fix(esp_hw_support): revert cache writeback/invalidate in wakeup process --- components/esp_hw_support/sleep_modes.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 913ad231da..0dd6be69a5 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1173,18 +1173,6 @@ static esp_err_t SLEEP_FN_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t cl if (!deep_sleep) { if (result == ESP_OK) { s_config.ccount_ticks_record = esp_cpu_get_cycle_count(); -#if !CONFIG_PM_SLP_IRAM_OPT && !(CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32P4) -#if CONFIG_SPIRAM - // TODO: PM-651 - Cache_WriteBack_All(); -#endif - /* When the IRAM optimization for the sleep flow is disabled, all - * cache contents are forcibly invalidated before exiting the sleep - * flow. This ensures that the code execution time of sleep exit - * flow remains consistent, allowing the use of ccount to - * dynamically calculate the sleep adjustment time. */ - cache_ll_invalidate_all(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL); -#endif } misc_modules_wake_prepare(sleep_flags); } From b38c003cb14b3c5253757b76e687955eb2e07ba0 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Fri, 16 Jan 2026 21:44:53 +0300 Subject: [PATCH 55/84] test(panic): add retry logic to espcoredump subprocess call --- .../system/panic/test_panic_util/panic_dut.py | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/tools/test_apps/system/panic/test_panic_util/panic_dut.py b/tools/test_apps/system/panic/test_panic_util/panic_dut.py index 0e03d201ae..3f6c4d7c04 100644 --- a/tools/test_apps/system/panic/test_panic_util/panic_dut.py +++ b/tools/test_apps/system/panic/test_panic_util/panic_dut.py @@ -1,10 +1,11 @@ -# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 import logging import os import re import subprocess import sys +import time from typing import Any from typing import Dict from typing import List @@ -13,8 +14,8 @@ from typing import TextIO from typing import Union import pexpect -from panic_utils import attach_logger from panic_utils import NoGdbProcessError +from panic_utils import attach_logger from panic_utils import quote_string from panic_utils import sha256 from panic_utils import verify_valid_gdb_subprocess @@ -32,7 +33,10 @@ class PanicTestDut(IdfDut): COREDUMP_UART_END = r'================= CORE DUMP END =================' COREDUMP_CHECKSUM = r"Coredump checksum='([a-fA-F0-9]+)'" REBOOT = r'.*Rebooting\.\.\.' - CPU_RESET = r'.*rst:.*(RTC_SW_CPU_RST|SW_CPU_RESET|SW_CPU|RTCWDT_RTC_RESET|LP_WDT_SYS|RTCWDT_RTC_RST|CHIP_LP_WDT_RESET|RTC_WDT_SYS)\b' + CPU_RESET = ( + r'.*rst:.*(RTC_SW_CPU_RST|SW_CPU_RESET|SW_CPU|RTCWDT_RTC_RESET|' + r'LP_WDT_SYS|RTCWDT_RTC_RST|CHIP_LP_WDT_RESET|RTC_WDT_SYS)\b' + ) app: IdfApp serial: IdfSerial @@ -113,9 +117,7 @@ class PanicTestDut(IdfDut): def expect_elf_sha256(self, caption: str = 'ELF file SHA256: ') -> None: """Expect method for ELF SHA256 line""" elf_sha256 = sha256(self.app.elf_file) - elf_sha256_len = int( - self.app.sdkconfig.get('CONFIG_APP_RETRIEVE_LEN_ELF_SHA', '9') - ) + elf_sha256_len = int(self.app.sdkconfig.get('CONFIG_APP_RETRIEVE_LEN_ELF_SHA', '9')) self.expect_exact(caption + elf_sha256[0:elf_sha256_len]) def expect_coredump(self, output_file_name: str, patterns: List[Union[str, re.Pattern]]) -> None: @@ -131,16 +133,12 @@ class PanicTestDut(IdfDut): else: raise ValueError(f'Unsupported input type: {type(pattern).__name__}') - def _call_espcoredump( - self, extra_args: List[str], output_file_name: str - ) -> None: + def _call_espcoredump(self, extra_args: list[str], output_file_name: str, max_retries: int = 3) -> None: # no "with" here, since we need the file to be open for later inspection by the test case if not self.coredump_output: self.coredump_output = open(output_file_name, 'w') - espcoredump_script = os.path.join( - os.environ['IDF_PATH'], 'components', 'espcoredump', 'espcoredump.py' - ) + espcoredump_script = os.path.join(os.environ['IDF_PATH'], 'components', 'espcoredump', 'espcoredump.py') espcoredump_args = [ sys.executable, espcoredump_script, @@ -153,18 +151,31 @@ class PanicTestDut(IdfDut): logging.info('espcoredump output is written to %s', self.coredump_output.name) self.serial.close() - try: - subprocess.check_call(espcoredump_args, stdout=self.coredump_output, stderr=self.coredump_output) - except subprocess.CalledProcessError: - self.coredump_output.flush() - with open(output_file_name, 'r') as file: - logging.error('espcoredump failed with output: %s', file.read()) - raise - finally: - self.coredump_output.seek(0) + for attempt in range(max_retries): + try: + if attempt > 0: + # Reset output file for retry + time.sleep(1) + self.coredump_output.seek(0) + self.coredump_output.truncate() + logging.info(f'Retrying espcoredump (attempt {attempt + 1}/{max_retries})') + subprocess.check_call(espcoredump_args, stdout=self.coredump_output, stderr=self.coredump_output) + self.coredump_output.seek(0) + return # Success + except subprocess.CalledProcessError: + self.coredump_output.flush() + with open(output_file_name) as file: + content = file.read() + if attempt < max_retries - 1: + logging.warning(f'espcoredump attempt {attempt + 1}/{max_retries} failed with output: {content}') + else: + logging.error(f'espcoredump failed after {max_retries} attempts with output: {content}') + raise def process_coredump_uart( - self, coredump_base64: Any, expected: Optional[List[Union[str, re.Pattern]]] = None, + self, + coredump_base64: Any, + expected: Optional[List[Union[str, re.Pattern]]] = None, ) -> Any: with open(os.path.join(self.logdir, 'coredump_data.b64'), 'w') as coredump_file: logging.info('Writing UART base64 core dump to %s', coredump_file.name) @@ -183,9 +194,7 @@ class PanicTestDut(IdfDut): coredump_file_name = os.path.join(self.logdir, 'coredump_data.bin') logging.info('Writing flash binary core dump to %s', coredump_file_name) output_file_name = os.path.join(self.logdir, 'coredump_flash_result.txt') - self._call_espcoredump( - ['--core-format', 'raw', '--save-core', coredump_file_name], output_file_name - ) + self._call_espcoredump(['--core-format', 'raw', '--save-core', coredump_file_name], output_file_name) if expected: self.expect_coredump(output_file_name, expected) return coredump_file_name @@ -210,12 +219,14 @@ class PanicTestDut(IdfDut): gdb_path = 'riscv32-esp-elf-gdb' try: from pygdbmi.constants import GdbTimeoutError + gdb_command = [gdb_path] + gdb_args self.gdbmi = GdbController(command=gdb_command) pygdbmi_logger = attach_logger() except ImportError: # fallback for pygdbmi<0.10.0.0. from pygdbmi.gdbcontroller import GdbTimeoutError + self.gdbmi = GdbController(gdb_path=gdb_path, gdb_args=gdb_args) pygdbmi_logger = self.gdbmi.logger @@ -225,9 +236,7 @@ class PanicTestDut(IdfDut): while pygdbmi_logger.hasHandlers(): pygdbmi_logger.removeHandler(pygdbmi_logger.handlers[0]) log_handler = logging.FileHandler(pygdbmi_log_file_name) - log_handler.setFormatter( - logging.Formatter('%(asctime)s %(levelname)s: %(message)s') - ) + log_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s')) logging.info(f'Saving pygdbmi logs to {pygdbmi_log_file_name}') pygdbmi_logger.addHandler(log_handler) try: @@ -251,16 +260,12 @@ class PanicTestDut(IdfDut): logging.info('GDB response: %s', resp) break # success except GdbTimeoutError: - logging.warning( - 'GDB internal error: cannot get response from the subprocess' - ) + logging.warning('GDB internal error: cannot get response from the subprocess') except NoGdbProcessError: logging.error('GDB internal error: process is not running') break # failure - TODO: create another GdbController except ValueError: - logging.error( - 'GDB internal error: select() returned an unexpected file number' - ) + logging.error('GDB internal error: select() returned an unexpected file number') # Set up logging for GDB remote protocol gdb_remotelog_file_name = os.path.join(self.logdir, 'gdb_remote_log.txt') @@ -271,7 +276,6 @@ class PanicTestDut(IdfDut): # Prepare gdb for the gdb stub def start_gdb_for_gdbstub(self) -> None: - self.run_gdb() # Connect GDB to UART @@ -280,8 +284,9 @@ class PanicTestDut(IdfDut): self.gdb_write('-gdb-set serial baud 115200') if sys.platform == 'darwin': - assert '/dev/tty.' not in self.serial.port, \ - '/dev/tty.* ports can\'t be used with GDB on macOS. Use with /dev/cu.* instead.' + assert '/dev/tty.' not in self.serial.port, ( + "/dev/tty.* ports can't be used with GDB on macOS. Use with /dev/cu.* instead." + ) # Make sure we get the 'stopped' notification responses = self.gdb_write('-target-select remote ' + self.serial.port) @@ -307,7 +312,6 @@ class PanicTestDut(IdfDut): # Prepare gdb to debug coredump file def start_gdb_for_coredump(self, elf_file: str) -> None: - self.run_gdb() self.gdb_write('core {}'.format(elf_file)) @@ -326,9 +330,7 @@ class PanicTestDut(IdfDut): return self.find_gdb_response('done', 'result', responses)['payload']['value'] @staticmethod - def verify_gdb_backtrace( - gdb_backtrace: List[Any], expected_functions_list: List[Any] - ) -> None: + def verify_gdb_backtrace(gdb_backtrace: List[Any], expected_functions_list: List[Any]) -> None: """ Raises an assert if the function names listed in expected_functions_list do not match the backtrace given by gdb_backtrace argument. The latter is in the same format as returned by gdb_backtrace() @@ -341,9 +343,7 @@ class PanicTestDut(IdfDut): assert False, 'Got unexpected backtrace' @staticmethod - def find_gdb_response( - message: str, response_type: str, responses: List[Any] - ) -> Any: + def find_gdb_response(message: str, response_type: str, responses: List[Any]) -> Any: """ Helper function which extracts one response from an array of GDB responses, filtering by message and type. Returned message is a dictionary, refer to pygdbmi docs for the format. From 5d5eafac76bd0e7272bc862dadb17d597ccc68c6 Mon Sep 17 00:00:00 2001 From: armando Date: Tue, 20 Jan 2026 16:59:17 +0800 Subject: [PATCH 56/84] fix(isp): fixed wbg shadow not working issue --- components/esp_driver_isp/include/esp_private/isp_private.h | 4 ++++ components/esp_driver_isp/src/isp_wbg.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/components/esp_driver_isp/include/esp_private/isp_private.h b/components/esp_driver_isp/include/esp_private/isp_private.h index 7684801b84..5701d9ef59 100644 --- a/components/esp_driver_isp/include/esp_private/isp_private.h +++ b/components/esp_driver_isp/include/esp_private/isp_private.h @@ -106,6 +106,10 @@ typedef struct isp_processor_t { uint32_t hist_isr_added: 1; } isr_users; + struct { + uint32_t wbg_update_once_configured: 1; + } sub_module_flags; + } isp_processor_t; #endif diff --git a/components/esp_driver_isp/src/isp_wbg.c b/components/esp_driver_isp/src/isp_wbg.c index b17d7d9ecc..851a746039 100644 --- a/components/esp_driver_isp/src/isp_wbg.c +++ b/components/esp_driver_isp/src/isp_wbg.c @@ -40,6 +40,8 @@ esp_err_t esp_isp_wbg_configure(isp_proc_handle_t isp_proc, const esp_isp_wbg_co bool valid = isp_ll_shadow_update_wbg(isp_proc->hal.hw, config->flags.update_once_configured); ESP_RETURN_ON_FALSE_ISR(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update wbg shadow register"); + isp_proc->sub_module_flags.wbg_update_once_configured = config->flags.update_once_configured; + return ESP_OK; } @@ -64,6 +66,9 @@ esp_err_t esp_isp_wbg_set_wb_gain(isp_proc_handle_t isp_proc, isp_wbg_gain_t gai // Set WBG gain isp_ll_awb_set_wb_gain(isp_proc->hal.hw, gain); + bool valid = isp_ll_shadow_update_wbg(isp_proc->hal.hw, isp_proc->sub_module_flags.wbg_update_once_configured); + ESP_RETURN_ON_FALSE_ISR(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update wbg shadow register"); + return ESP_OK; } From eec9c8843a4869ffb335382307b2e4de4b82700f Mon Sep 17 00:00:00 2001 From: hebinglin Date: Tue, 6 Jan 2026 17:35:45 +0800 Subject: [PATCH 57/84] fix(esp_hw_support): fix cpu restart failed due to rtc_clk in flash --- .../esp_hw_support/port/esp32/rtc_clk.c | 11 +++++----- .../esp_hw_support/port/esp32c2/rtc_clk.c | 11 +++++----- .../esp_hw_support/port/esp32c3/rtc_clk.c | 11 +++++----- .../esp_hw_support/port/esp32c5/rtc_clk.c | 6 +++--- .../esp_hw_support/port/esp32c6/rtc_clk.c | 7 ++++--- .../esp_hw_support/port/esp32c61/rtc_clk.c | 6 +++--- .../esp_hw_support/port/esp32h2/rtc_clk.c | 9 ++++---- .../esp_hw_support/port/esp32h21/rtc_clk.c | 9 ++++---- .../esp_hw_support/port/esp32h4/rtc_clk.c | 9 ++++---- .../esp_hw_support/port/esp32p4/rtc_clk.c | 9 ++++---- .../esp_hw_support/port/esp32s2/rtc_clk.c | 7 ++++--- .../esp_hw_support/port/esp32s3/rtc_clk.c | 21 ++++++++++--------- 12 files changed, 63 insertions(+), 53 deletions(-) diff --git a/components/esp_hw_support/port/esp32/rtc_clk.c b/components/esp_hw_support/port/esp32/rtc_clk.c index 18c28f390b..cbe1464170 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-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -31,6 +31,7 @@ #include "esp_private/systimer.h" #include "hal/timer_ll.h" #endif +#include "esp_attr.h" #define XTAL_32K_BOOTSTRAP_TIME_US 7 @@ -369,7 +370,7 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { esp_rom_set_cpu_ticks_per_us(cpu_freq); /* set divider from XTAL to APB clock */ @@ -461,7 +462,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -607,7 +608,7 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t* config) } } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { @@ -621,7 +622,7 @@ void rtc_clk_xtal_freq_update(soc_xtal_freq_t xtal_freq) clk_ll_xtal_store_freq_mhz((uint32_t)xtal_freq); } -void rtc_clk_apb_freq_update(uint32_t apb_freq) +FORCE_IRAM_ATTR void rtc_clk_apb_freq_update(uint32_t apb_freq) { clk_ll_apb_store_freq_hz(apb_freq); } diff --git a/components/esp_hw_support/port/esp32c2/rtc_clk.c b/components/esp_hw_support/port/esp32c2/rtc_clk.c index e0dcfb9540..5e05f7e89e 100644 --- a/components/esp_hw_support/port/esp32c2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c2/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,6 +21,7 @@ #include "esp_rom_sys.h" #include "hal/clk_tree_ll.h" #include "hal/regi2c_ctrl_ll.h" +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -289,7 +290,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -306,7 +307,7 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { 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. */ @@ -325,7 +326,7 @@ static void rtc_clk_cpu_freq_to_8m(void) rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX); } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { @@ -340,7 +341,7 @@ void rtc_clk_xtal_freq_update(soc_xtal_freq_t xtal_freq) clk_ll_xtal_store_freq_mhz(xtal_freq); } -void rtc_clk_apb_freq_update(uint32_t apb_freq) +FORCE_IRAM_ATTR void rtc_clk_apb_freq_update(uint32_t apb_freq) { clk_ll_apb_store_freq_hz(apb_freq); } diff --git a/components/esp_hw_support/port/esp32c3/rtc_clk.c b/components/esp_hw_support/port/esp32c3/rtc_clk.c index d1a2217fb1..aed9508f84 100644 --- a/components/esp_hw_support/port/esp32c3/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c3/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,7 @@ #include "esp_rom_sys.h" #include "hal/clk_tree_ll.h" #include "hal/regi2c_ctrl_ll.h" +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -318,7 +319,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -335,7 +336,7 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +static FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { 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. */ @@ -354,7 +355,7 @@ static void rtc_clk_cpu_freq_to_8m(void) rtc_clk_apb_freq_update(SOC_CLK_RC_FAST_FREQ_APPROX); } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { @@ -369,7 +370,7 @@ void rtc_clk_xtal_freq_update(soc_xtal_freq_t xtal_freq) clk_ll_xtal_store_freq_mhz(xtal_freq); } -void rtc_clk_apb_freq_update(uint32_t apb_freq) +FORCE_IRAM_ATTR void rtc_clk_apb_freq_update(uint32_t apb_freq) { clk_ll_apb_store_freq_hz(apb_freq); } diff --git a/components/esp_hw_support/port/esp32c5/rtc_clk.c b/components/esp_hw_support/port/esp32c5/rtc_clk.c index f602a6856c..e984a07920 100644 --- a/components/esp_hw_support/port/esp32c5/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c5/rtc_clk.c @@ -172,7 +172,7 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +static FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { // let f_cpu = f_ahb clk_ll_cpu_set_divider(div); @@ -451,7 +451,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); #ifndef BOOTLOADER_BUILD @@ -497,7 +497,7 @@ void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz) } #endif -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_get_freq_mhz(); assert(xtal_freq_mhz == SOC_XTAL_FREQ_48M || xtal_freq_mhz == SOC_XTAL_FREQ_40M); diff --git a/components/esp_hw_support/port/esp32c6/rtc_clk.c b/components/esp_hw_support/port/esp32c6/rtc_clk.c index 95ebe55901..f1c5edcf00 100644 --- a/components/esp_hw_support/port/esp32c6/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c6/rtc_clk.c @@ -22,6 +22,7 @@ #include "soc/lp_aon_reg.h" #include "esp_private/sleep_event.h" #include "esp_private/regi2c_ctrl.h" +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -184,7 +185,7 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +static FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { clk_ll_ahb_set_ls_divider(div); clk_ll_cpu_set_ls_divider(div); @@ -359,7 +360,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -378,7 +379,7 @@ void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz) clk_ll_cpu_clk_src_lock_release(); } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { diff --git a/components/esp_hw_support/port/esp32c61/rtc_clk.c b/components/esp_hw_support/port/esp32c61/rtc_clk.c index 9b6bd7b89b..2c2db7a2c4 100644 --- a/components/esp_hw_support/port/esp32c61/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c61/rtc_clk.c @@ -170,7 +170,7 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +static FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { // let f_cpu = f_ahb clk_ll_cpu_set_divider(div); @@ -345,7 +345,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -364,7 +364,7 @@ void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz) clk_ll_cpu_clk_src_lock_release(); } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_get_freq_mhz(); assert(xtal_freq_mhz == SOC_XTAL_FREQ_40M); diff --git a/components/esp_hw_support/port/esp32h2/rtc_clk.c b/components/esp_hw_support/port/esp32h2/rtc_clk.c index 71f89c4583..d376c1ad40 100644 --- a/components/esp_hw_support/port/esp32h2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32h2/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,7 @@ #include "soc/lp_aon_reg.h" #include "esp_private/sleep_event.h" #include "esp_private/regi2c_ctrl.h" +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -195,7 +196,7 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +static FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { // let f_cpu = f_ahb clk_ll_cpu_set_divider(div); @@ -400,7 +401,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -413,7 +414,7 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void) rtc_clk_cpu_set_to_default_config(); } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { diff --git a/components/esp_hw_support/port/esp32h21/rtc_clk.c b/components/esp_hw_support/port/esp32h21/rtc_clk.c index e04dfa1f0f..ab9c002c7a 100644 --- a/components/esp_hw_support/port/esp32h21/rtc_clk.c +++ b/components/esp_hw_support/port/esp32h21/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,7 @@ #include "soc/lp_aon_reg.h" #include "esp_private/sleep_event.h" #include "esp_private/regi2c_ctrl.h" +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -195,7 +196,7 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +static FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { // let f_cpu = f_ahb clk_ll_cpu_set_divider(div); @@ -400,7 +401,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -413,7 +414,7 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void) rtc_clk_cpu_set_to_default_config(); } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { diff --git a/components/esp_hw_support/port/esp32h4/rtc_clk.c b/components/esp_hw_support/port/esp32h4/rtc_clk.c index ffff13458b..a74f517f13 100644 --- a/components/esp_hw_support/port/esp32h4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32h4/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,6 +21,7 @@ #include "soc/io_mux_reg.h" #include "soc/lp_aon_reg.h" #include "esp_private/sleep_event.h" +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -175,7 +176,7 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +static FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) { clk_ll_ahb_set_ls_divider(div); clk_ll_cpu_set_ls_divider(div); @@ -339,7 +340,7 @@ void rtc_clk_cpu_freq_set_xtal(void) } } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -357,7 +358,7 @@ void rtc_clk_cpu_freq_to_pll_and_pll_lock_release(int cpu_freq_mhz) clk_ll_cpu_clk_src_lock_release(); } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { #if !CONFIG_IDF_ENV_FPGA uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index 201e0e6a7a..c93626d73b 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,6 +23,7 @@ #include "soc/io_mux_reg.h" #include "esp_private/sleep_event.h" #include "esp_private/regi2c_ctrl.h" +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -179,7 +180,7 @@ static void rtc_clk_cpll_configure(soc_xtal_freq_t xtal_freq, int cpll_freq) * If to_default is set, then will configure CPU - MEM - SYS - APB frequencies back to power-on reset configuration (40 - 20 - 20 - 10) * If to_default is not set, then will configure to 40 - 40 - 40 - 40 */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div, bool to_default) +static FORCE_IRAM_ATTR void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div, bool to_default) { // let f_cpu = f_mem = f_sys = f_apb uint32_t mem_divider = 1; @@ -494,7 +495,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_cpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -509,7 +510,7 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void) s_cur_cpll_freq = 0; // no disable PLL, but set freq to 0 to trigger a PLL calibration after wake-up from sleep } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { diff --git a/components/esp_hw_support/port/esp32s2/rtc_clk.c b/components/esp_hw_support/port/esp32s2/rtc_clk.c index 6b06d139bf..b50220e503 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-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,7 @@ #include "esp_private/systimer.h" #include "hal/systimer_ll.h" #endif +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -445,7 +446,7 @@ void rtc_clk_cpu_freq_set_xtal(void) /* BBPLL is kept enabled */ } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { rtc_clk_cpu_freq_to_xtal(CLK_LL_XTAL_FREQ_MHZ, 1); } @@ -460,7 +461,7 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void) * Must satisfy: cpu_freq = XTAL_FREQ / div. * Does not disable the PLL. */ -static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +static FORCE_IRAM_ATTR 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); diff --git a/components/esp_hw_support/port/esp32s3/rtc_clk.c b/components/esp_hw_support/port/esp32s3/rtc_clk.c index 0df4ef98c1..b44133da3c 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-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,7 @@ #include "soc/regi2c_dig_reg.h" #include "soc/sens_reg.h" #include "sdkconfig.h" +#include "esp_attr.h" static const char *TAG = "rtc_clk"; @@ -316,7 +317,7 @@ void rtc_clk_cpu_freq_set_config(const rtc_cpu_freq_config_t *config) } } -void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) +FORCE_IRAM_ATTR void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) { soc_cpu_clk_src_t source = clk_ll_cpu_get_src(); uint32_t source_freq_mhz; @@ -339,8 +340,8 @@ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) } else if (freq_mhz == CLK_LL_PLL_240M_FREQ_MHZ && source_freq_mhz == CLK_LL_PLL_480M_FREQ_MHZ) { div = 2; } else { - ESP_HW_LOGE(TAG, "unsupported frequency configuration"); - return; + // Unsupported frequency configuration + abort(); } break; } @@ -350,8 +351,8 @@ void rtc_clk_cpu_freq_get_config(rtc_cpu_freq_config_t *out_config) freq_mhz = source_freq_mhz; break; default: - ESP_HW_LOGE(TAG, "unsupported frequency configuration"); - return; + // Unsupported frequency configuration + abort(); } *out_config = (rtc_cpu_freq_config_t) { .source = source, @@ -380,7 +381,7 @@ void rtc_clk_cpu_freq_set_xtal(void) rtc_clk_bbpll_disable(); } -void rtc_clk_cpu_set_to_default_config(void) +FORCE_IRAM_ATTR void rtc_clk_cpu_set_to_default_config(void) { int freq_mhz = (int)rtc_clk_xtal_freq_get(); @@ -399,7 +400,7 @@ void rtc_clk_cpu_freq_set_xtal_for_sleep(void) * * Public function for testing only. */ -void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div) +FORCE_IRAM_ATTR 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); @@ -433,7 +434,7 @@ static void rtc_clk_cpu_freq_to_8m(void) REG_SET_FIELD(RTC_CNTL_DATE_REG, RTC_CNTL_SLAVE_PD, DEFAULT_LDO_SLAVE); } -soc_xtal_freq_t rtc_clk_xtal_freq_get(void) +FORCE_IRAM_ATTR soc_xtal_freq_t rtc_clk_xtal_freq_get(void) { uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { @@ -448,7 +449,7 @@ void rtc_clk_xtal_freq_update(soc_xtal_freq_t xtal_freq) clk_ll_xtal_store_freq_mhz(xtal_freq); } -void rtc_clk_apb_freq_update(uint32_t apb_freq) +FORCE_IRAM_ATTR void rtc_clk_apb_freq_update(uint32_t apb_freq) { s_apb_freq = apb_freq; } From 824e26eab9fb28657499714c0fde2b8c3e09c587 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Wed, 7 Jan 2026 11:38:09 +0800 Subject: [PATCH 58/84] fix(esp_hw_support): remove ESP32 linker.lf api that conflict with FORCE_IRAM_ATTR --- components/esp_hw_support/linker.lf | 1 - 1 file changed, 1 deletion(-) diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index d839f8bf8b..51b0e7d22d 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -18,7 +18,6 @@ entries: rtc_clk (noflash) if IDF_TARGET_ESP32 = y: rtc_clk:rtc_clk_cpu_freq_to_pll_mhz (noflash) - rtc_clk:rtc_clk_cpu_freq_to_xtal (noflash) if RTC_TIME_FUNC_IN_IRAM = y: rtc_time (noflash_text) if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED = y: From 90ad25a0c97391e90c2954c148bbe70e2c1024d0 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 16 Jan 2026 17:13:25 +0800 Subject: [PATCH 59/84] change(ble): [AUTO_MR] Update lib_esp32h2 to 17fdc66e (cherry picked from commit 57b4819474e88b702178a9e62dd1f978acb3dc88) Co-authored-by: Zhou Xiao --- components/bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index 1034b3c595..27ca7c0a07 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit 1034b3c595cc3a570d2bfb6e0b08b45f3b1f5fae +Subproject commit 27ca7c0a074804c382409d01f86f5f46b4382bca From 666086a33d2de5141f9ce49ccb389c30f883dabc Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 16 Jan 2026 17:13:25 +0800 Subject: [PATCH 60/84] change(ble): [AUTO_MR] Update lib_esp32c5 to 17fdc66e (cherry picked from commit 7631a6f1587ae521936b0b7869dc67102eb175f8) Co-authored-by: Zhou Xiao --- components/bt/controller/lib_esp32c5/esp32c5-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib index 95899f11a3..bbff15b4d8 160000 --- a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib +++ b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib @@ -1 +1 @@ -Subproject commit 95899f11a3f21aae115121ea778cfb8cb1047885 +Subproject commit bbff15b4d8cecad7c9e44b84bc32efc80cb3c6b2 From 63025accd33df98f7b3f39e11f3edc5c3641d4f7 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 16 Jan 2026 17:13:25 +0800 Subject: [PATCH 61/84] change(ble): [AUTO_MR] Update lib_esp32c6 to 17fdc66e (cherry picked from commit 54e5f358bf544e51175dfb9ca3075a8d577800fe) Co-authored-by: Zhou Xiao --- components/bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index d40be82077..d8b5341796 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit d40be82077fab8d80aed1eecc39f30673dbcc90d +Subproject commit d8b5341796e19d39aaa011dcdc3b71ca6f9450f0 From 9c881644060f23e959ae91e5dda95bf2df7041c4 Mon Sep 17 00:00:00 2001 From: cjin Date: Tue, 13 Jan 2026 10:22:34 +0800 Subject: [PATCH 62/84] feat(ble): add config to enable sid filter feat --- components/bt/host/nimble/Kconfig.in | 18 ++++++++++++++++++ .../host/nimble/port/include/esp_nimble_cfg.h | 18 +++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index dc82f62561..f8c8249ee6 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -1619,6 +1619,24 @@ menu "Vendor / Optimization" depends on BT_NIMBLE_ENABLED help This enable BLE high duty advertising interval feature + + config BT_NIMBLE_ADV_SEND_CONSTANT_DID + bool "Enable BLE Ext Adv to Send with Specific DID" + depends on SOC_ESP_NIMBLE_CONTROLLER && BT_NIMBLE_50_FEATURE_SUPPORT && !(IDF_TARGET_ESP32C2) + select BT_NIMBLE_VS_SUPPORT + help + This enable vendor-specific APIs to send specific DID for different advertising data in extended + advertising. + + config BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER + bool "Enable BLE Ext Scan to Receive Packet with Specific ADI" + depends on SOC_ESP_NIMBLE_CONTROLLER && BT_NIMBLE_50_FEATURE_SUPPORT && !(IDF_TARGET_ESP32C2) + select BT_NIMBLE_VS_SUPPORT + help + This enables vendor-specific APIs to only receive specific groups of ADIs, and implements DIDs + duplicate filtering for extended scanning. Enabling this can reduce the unnecessary reception of + secondary channel PDUs carrying non-targeted ADIs. + endmenu #Vendor menu "Helper Utils" 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 8155a2a6d0..cf36dec256 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -2356,4 +2356,20 @@ #endif #endif +#ifndef MYNEWT_VAL_BLE_ADV_SEND_CONSTANT_DID +#ifdef CONFIG_BT_NIMBLE_ADV_SEND_CONSTANT_DID +#define MYNEWT_VAL_BLE_ADV_SEND_CONSTANT_DID (CONFIG_BT_NIMBLE_ADV_SEND_CONSTANT_DID) +#else +#define MYNEWT_VAL_BLE_ADV_SEND_CONSTANT_DID (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_SCAN_ALLOW_ENH_ADI_FILTER +#ifdef CONFIG_BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER +#define MYNEWT_VAL_BLE_SCAN_ALLOW_ENH_ADI_FILTER (CONFIG_BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER) +#else +#define MYNEWT_VAL_BLE_SCAN_ALLOW_ENH_ADI_FILTER (0) +#endif +#endif + #endif From fac081442cb3457d85fc94b607b066780206ba91 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 16 Jan 2026 17:13:26 +0800 Subject: [PATCH 63/84] feat(ble): support sid filter feature on ESP32C5 (cherry picked from commit debd743a0b72ec1b203dea1342dc1531887574c5) Co-authored-by: cjin --- components/bt/controller/esp32c5/ble.c | 25 ++++++++++++++++++- components/bt/controller/esp32c5/esp_bt_cfg.h | 14 ++++++++++- .../bt/include/esp32c5/include/esp_bt.h | 4 ++- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/esp32c5/ble.c b/components/bt/controller/esp32c5/ble.c index 0b6fc1e7d0..b9fd93c43c 100644 --- a/components/bt/controller/esp32c5/ble.c +++ b/components/bt/controller/esp32c5/ble.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -27,6 +27,11 @@ void extAdv_stack_deinitEnv(void); int extAdv_stack_enable(void); void extAdv_stack_disable(void); +int scan_stack_initEnv(void); +void scan_stack_deinitEnv(void); +int scan_stack_enable(void); +void scan_stack_disable(void); + int sync_stack_initEnv(void); void sync_stack_deinitEnv(void); int sync_stack_enable(void); @@ -84,6 +89,12 @@ void winWiden_stack_enableSetConstPeerScaVsCmd(bool en); void adv_stack_enableScanReqRxdVsEvent(bool en); void conn_stack_enableChanMapUpdCompVsEvent(bool en); void sleep_stack_enableWakeupVsEvent(bool en); +#if DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER +void scan_stack_enableSetScanADIOnlyFilterVsCmd(bool en); +#endif // DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER +#if DEFAULT_BT_ADV_SEND_CONSTANT_DID +void extAdv_stack_setExtAdvConstantDidVsCmd(bool en); +#endif // DEFAULT_BT_ADV_SEND_CONSTANT_DID #endif // (CONFIG_BT_NIMBLE_ENABLED || CONFIG_BT_BLUEDROID_ENABLED) #if CONFIG_BT_LE_RXBUF_OPT_ENABLED extern void mmgmt_enableRxbufOptFeature(void); @@ -136,6 +147,11 @@ int ble_stack_initEnv(void) return rc; } + rc = scan_stack_initEnv(); + if (rc) { + return rc; + } + rc = sync_stack_initEnv(); if (rc) { return rc; @@ -210,6 +226,7 @@ void ble_stack_deinitEnv(void) #endif // CONFIG_BT_LE_DTM_ENABLED sync_stack_deinitEnv(); + scan_stack_deinitEnv(); extAdv_stack_deinitEnv(); adv_stack_deinitEnv(); base_stack_deinitEnv(); @@ -234,6 +251,11 @@ int ble_stack_enable(void) return rc; } + rc = scan_stack_enable(); + if (rc) { + return rc; + } + rc = sync_stack_enable(); if (rc) { return rc; @@ -302,6 +324,7 @@ void ble_stack_disable(void) dtm_stack_disable(); #endif // CONFIG_BT_LE_DTM_ENABLED sync_stack_disable(); + scan_stack_disable(); extAdv_stack_disable(); adv_stack_disable(); base_stack_disable(); diff --git a/components/bt/controller/esp32c5/esp_bt_cfg.h b/components/bt/controller/esp32c5/esp_bt_cfg.h index 20f2ec7edb..401c36bc90 100644 --- a/components/bt/controller/esp32c5/esp_bt_cfg.h +++ b/components/bt/controller/esp32c5/esp_bt_cfg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -50,6 +50,16 @@ extern "C" { #else #define DEFAULT_BT_LE_PAWR_SUPPORTED (0) #endif // CONFIG_BT_NIMBLE_PERIODIC_ADV_WITH_RESPONSES + #if CONFIG_BT_NIMBLE_ADV_SEND_CONSTANT_DID + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (1) + #else + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (0) + #endif // CONFIG_BT_NIMBLE_ADV_SEND_CONSTANT_DID + #if CONFIG_BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (1) + #else + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (0) + #endif // CONFIG_BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER #else #if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY @@ -155,6 +165,8 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) #endif + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (0) + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (0) #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF diff --git a/components/bt/include/esp32c5/include/esp_bt.h b/components/bt/include/esp32c5/include/esp_bt.h index 478c4df11a..02eaab43a3 100644 --- a/components/bt/include/esp32c5/include/esp_bt.h +++ b/components/bt/include/esp32c5/include/esp_bt.h @@ -159,7 +159,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20251125 +#define CONFIG_VERSION 0x20251211 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -237,6 +237,7 @@ typedef struct { uint8_t priority_level_cfg; /*!< The option for priority level configuration */ uint8_t slv_fst_rx_lat_en; /*!< The option for enabling slave fast PDU reception during latency. */ uint8_t dl_itvl_phy_sync_en; /*!< The option for automatically initiate the data length update when phy update or connect interval update. */ + uint8_t scan_allow_adi_filter; /*!< The option for ext scan to allow PDU with specific adi. */ uint32_t config_magic; /*!< Magic number for configuration validation */ } esp_bt_controller_config_t; @@ -301,6 +302,7 @@ typedef struct { .priority_level_cfg = BT_LL_CTRL_PRIO_LVL_CFG, \ .slv_fst_rx_lat_en = DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN, \ .dl_itvl_phy_sync_en = DEFAULT_BT_LE_CTRL_DL_ITVL_PHY_SYNC_EN, \ + .scan_allow_adi_filter = DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER, \ .config_magic = CONFIG_MAGIC, \ } From 6e59e1bf4fcf29248edec6d99c0d45f492176461 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 16 Jan 2026 17:13:26 +0800 Subject: [PATCH 64/84] feat(ble): support sid filter feature on ESP32H2 (cherry picked from commit e4e42f01661d2d74b392195e51e2fe558fcf9dc0) Co-authored-by: cjin --- components/bt/controller/esp32h2/ble.c | 23 ++++++++++++++++++- components/bt/controller/esp32h2/esp_bt_cfg.h | 14 ++++++++++- .../bt/include/esp32h2/include/esp_bt.h | 4 +++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/esp32h2/ble.c b/components/bt/controller/esp32h2/ble.c index 0b6fc1e7d0..411c0a69f9 100644 --- a/components/bt/controller/esp32h2/ble.c +++ b/components/bt/controller/esp32h2/ble.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -27,6 +27,11 @@ void extAdv_stack_deinitEnv(void); int extAdv_stack_enable(void); void extAdv_stack_disable(void); +int scan_stack_initEnv(void); +void scan_stack_deinitEnv(void); +int scan_stack_enable(void); +void scan_stack_disable(void); + int sync_stack_initEnv(void); void sync_stack_deinitEnv(void); int sync_stack_enable(void); @@ -84,6 +89,10 @@ void winWiden_stack_enableSetConstPeerScaVsCmd(bool en); void adv_stack_enableScanReqRxdVsEvent(bool en); void conn_stack_enableChanMapUpdCompVsEvent(bool en); void sleep_stack_enableWakeupVsEvent(bool en); +#if DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER +void scan_stack_enableSetScanADIOnlyFilterVsCmd(bool en); +#endif // DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER +void extAdv_stack_setExtAdvConstantDidVsCmd(bool en); #endif // (CONFIG_BT_NIMBLE_ENABLED || CONFIG_BT_BLUEDROID_ENABLED) #if CONFIG_BT_LE_RXBUF_OPT_ENABLED extern void mmgmt_enableRxbufOptFeature(void); @@ -136,6 +145,11 @@ int ble_stack_initEnv(void) return rc; } + rc = scan_stack_initEnv(); + if (rc) { + return rc; + } + rc = sync_stack_initEnv(); if (rc) { return rc; @@ -210,6 +224,7 @@ void ble_stack_deinitEnv(void) #endif // CONFIG_BT_LE_DTM_ENABLED sync_stack_deinitEnv(); + scan_stack_deinitEnv(); extAdv_stack_deinitEnv(); adv_stack_deinitEnv(); base_stack_deinitEnv(); @@ -234,6 +249,11 @@ int ble_stack_enable(void) return rc; } + rc = scan_stack_enable(); + if (rc) { + return rc; + } + rc = sync_stack_enable(); if (rc) { return rc; @@ -302,6 +322,7 @@ void ble_stack_disable(void) dtm_stack_disable(); #endif // CONFIG_BT_LE_DTM_ENABLED sync_stack_disable(); + scan_stack_disable(); extAdv_stack_disable(); adv_stack_disable(); base_stack_disable(); diff --git a/components/bt/controller/esp32h2/esp_bt_cfg.h b/components/bt/controller/esp32h2/esp_bt_cfg.h index 20f2ec7edb..401c36bc90 100644 --- a/components/bt/controller/esp32h2/esp_bt_cfg.h +++ b/components/bt/controller/esp32h2/esp_bt_cfg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -50,6 +50,16 @@ extern "C" { #else #define DEFAULT_BT_LE_PAWR_SUPPORTED (0) #endif // CONFIG_BT_NIMBLE_PERIODIC_ADV_WITH_RESPONSES + #if CONFIG_BT_NIMBLE_ADV_SEND_CONSTANT_DID + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (1) + #else + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (0) + #endif // CONFIG_BT_NIMBLE_ADV_SEND_CONSTANT_DID + #if CONFIG_BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (1) + #else + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (0) + #endif // CONFIG_BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER #else #if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY @@ -155,6 +165,8 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) #endif + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (0) + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (0) #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF diff --git a/components/bt/include/esp32h2/include/esp_bt.h b/components/bt/include/esp32h2/include/esp_bt.h index f3d06ac7c5..374ca4e7ad 100644 --- a/components/bt/include/esp32h2/include/esp_bt.h +++ b/components/bt/include/esp32h2/include/esp_bt.h @@ -161,7 +161,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20251125 +#define CONFIG_VERSION 0x20251211 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -239,6 +239,7 @@ typedef struct { uint8_t priority_level_cfg; /*!< The option for priority level configuration */ uint8_t slv_fst_rx_lat_en; /*!< The option for enabling slave fast PDU reception during latency. */ uint8_t dl_itvl_phy_sync_en; /*!< The option for automatically initiate the data length update when phy update or connect interval update. */ + uint8_t scan_allow_adi_filter; /*!< The option for ext scan to allow PDU with specific adi. */ uint32_t config_magic; /*!< Configuration magic value */ } esp_bt_controller_config_t; @@ -304,6 +305,7 @@ typedef struct { .priority_level_cfg = BT_LL_CTRL_PRIO_LVL_CFG, \ .slv_fst_rx_lat_en = DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN, \ .dl_itvl_phy_sync_en = DEFAULT_BT_LE_CTRL_DL_ITVL_PHY_SYNC_EN, \ + .scan_allow_adi_filter = DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER, \ .config_magic = CONFIG_MAGIC, \ } From dcebe6bbac043891b03baa0d77c8871d1e20b105 Mon Sep 17 00:00:00 2001 From: cjin Date: Tue, 13 Jan 2026 10:21:33 +0800 Subject: [PATCH 65/84] feat(ble): support sid filter feature on ESP32C6 --- components/bt/controller/esp32c6/ble.c | 36 ++++++++++++++++++- components/bt/controller/esp32c6/esp_bt_cfg.h | 14 +++++++- .../bt/include/esp32c6/include/esp_bt.h | 4 ++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/esp32c6/ble.c b/components/bt/controller/esp32c6/ble.c index 792211e83f..7b5e76abe8 100644 --- a/components/bt/controller/esp32c6/ble.c +++ b/components/bt/controller/esp32c6/ble.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -27,6 +27,16 @@ void extAdv_stack_deinitEnv(void); int extAdv_stack_enable(void); void extAdv_stack_disable(void); +int scan_stack_initEnv(void); +void scan_stack_deinitEnv(void); +int scan_stack_enable(void); +void scan_stack_disable(void); + +int scan_stack_initEnv(void); +void scan_stack_deinitEnv(void); +int scan_stack_enable(void); +void scan_stack_disable(void); + int sync_stack_initEnv(void); void sync_stack_deinitEnv(void); int sync_stack_enable(void); @@ -84,6 +94,12 @@ void winWiden_stack_enableSetConstPeerScaVsCmd(bool en); void adv_stack_enableScanReqRxdVsEvent(bool en); void conn_stack_enableChanMapUpdCompVsEvent(bool en); void sleep_stack_enableWakeupVsEvent(bool en); +#if DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER +void scan_stack_enableSetScanADIOnlyFilterVsCmd(bool en); +#endif // DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER +#if DEFAULT_BT_ADV_SEND_CONSTANT_DID +void extAdv_stack_setExtAdvConstantDidVsCmd(bool en); +#endif // DEFAULT_BT_ADV_SEND_CONSTANT_DID #endif // (CONFIG_BT_NIMBLE_ENABLED || CONFIG_BT_BLUEDROID_ENABLED) #if CONFIG_BT_LE_RXBUF_OPT_ENABLED extern void mmgmt_enableRxbufOptFeature(void); @@ -104,6 +120,12 @@ void ble_stack_enableVsCmds(bool en) log_stack_enableLogsRelatedVsCmd(en); hci_stack_enableSetVsEvtMaskVsCmd(en); winWiden_stack_enableSetConstPeerScaVsCmd(en); +#if DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER + scan_stack_enableSetScanADIOnlyFilterVsCmd(en); +#endif // DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER +#if DEFAULT_BT_ADV_SEND_CONSTANT_DID + extAdv_stack_setExtAdvConstantDidVsCmd(en); +#endif // DEFAULT_BT_ADV_SEND_CONSTANT_DID } void ble_stack_enableVsEvents(bool en) @@ -136,6 +158,11 @@ int ble_stack_initEnv(void) return rc; } + rc = scan_stack_initEnv(); + if (rc) { + return rc; + } + rc = sync_stack_initEnv(); if (rc) { return rc; @@ -210,6 +237,7 @@ void ble_stack_deinitEnv(void) #endif // CONFIG_BT_LE_DTM_ENABLED sync_stack_deinitEnv(); + scan_stack_deinitEnv(); extAdv_stack_deinitEnv(); adv_stack_deinitEnv(); base_stack_deinitEnv(); @@ -234,6 +262,11 @@ int ble_stack_enable(void) return rc; } + rc = scan_stack_enable(); + if (rc) { + return rc; + } + rc = sync_stack_enable(); if (rc) { return rc; @@ -302,6 +335,7 @@ void ble_stack_disable(void) dtm_stack_disable(); #endif // CONFIG_BT_LE_DTM_ENABLED sync_stack_disable(); + scan_stack_disable(); extAdv_stack_disable(); adv_stack_disable(); base_stack_disable(); diff --git a/components/bt/controller/esp32c6/esp_bt_cfg.h b/components/bt/controller/esp32c6/esp_bt_cfg.h index e5d378ad9b..27371322ef 100644 --- a/components/bt/controller/esp32c6/esp_bt_cfg.h +++ b/components/bt/controller/esp32c6/esp_bt_cfg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -51,6 +51,16 @@ extern "C" { #else #define DEFAULT_BT_LE_PAWR_SUPPORTED (0) #endif // CONFIG_BT_NIMBLE_PERIODIC_ADV_WITH_RESPONSES + #if CONFIG_BT_NIMBLE_ADV_SEND_CONSTANT_DID + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (1) + #else + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (0) + #endif // CONFIG_BT_NIMBLE_ADV_SEND_CONSTANT_DID + #if CONFIG_BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (1) + #else + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (0) + #endif // CONFIG_BT_NIMBLE_SCAN_ALLOW_ENH_ADI_FILTER #else #if CONFIG_BT_LE_LL_CFG_FEAT_LE_CODED_PHY @@ -158,6 +168,8 @@ extern "C" { #endif #define DEFAULT_BT_LE_SUBRATE_ENABLED 0 + #define DEFAULT_BT_ADV_SEND_CONSTANT_DID (0) + #define DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER (0) #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF diff --git a/components/bt/include/esp32c6/include/esp_bt.h b/components/bt/include/esp32c6/include/esp_bt.h index 5771335a99..666c0e3b92 100644 --- a/components/bt/include/esp32c6/include/esp_bt.h +++ b/components/bt/include/esp32c6/include/esp_bt.h @@ -156,7 +156,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20251125 +#define CONFIG_VERSION 0x20251211 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -237,6 +237,7 @@ typedef struct { uint8_t priority_level_cfg; /*!< The option for priority level configuration */ uint8_t slv_fst_rx_lat_en; /*!< The option for enabling slave fast PDU reception during latency. */ uint8_t dl_itvl_phy_sync_en; /*!< The option for automatically initiate the data length update when phy update or connect interval update. */ + uint8_t scan_allow_adi_filter; /*!< The option for ext scan to allow PDU with specific adi. */ uint32_t config_magic; /*!< Magic number for configuration validation */ } esp_bt_controller_config_t; @@ -304,6 +305,7 @@ typedef struct { .priority_level_cfg = BT_LL_CTRL_PRIO_LVL_CFG, \ .slv_fst_rx_lat_en = DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN, \ .dl_itvl_phy_sync_en = DEFAULT_BT_LE_CTRL_DL_ITVL_PHY_SYNC_EN, \ + .scan_allow_adi_filter = DEFAULT_BT_SCAN_ALLOW_ENH_ADI_FILTER, \ .config_magic = CONFIG_MAGIC, \ } #elif CONFIG_IDF_TARGET_ESP32C61 From 91547794a0bcd23f0789bdb37e71a658757caa1d Mon Sep 17 00:00:00 2001 From: Astha Verma Date: Mon, 8 Sep 2025 15:37:45 +0530 Subject: [PATCH 66/84] fix(nimble): Reset HID service during deinit --- components/bt/host/nimble/nimble | 2 +- components/esp_hid/src/nimble_hidd.c | 20 +++-- .../esp_hid_device/main/esp_hid_gap.c | 84 ++++++++++++++++++- .../esp_hid_device/main/esp_hid_gap.h | 1 + .../bluetooth/esp_hid_host/main/esp_hid_gap.h | 2 + 5 files changed, 102 insertions(+), 7 deletions(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 883c9ebed0..039d2d62ed 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 883c9ebed02e937fc3756a3d9fc1e3008500bb69 +Subproject commit 039d2d62ed97fed632827fd51294f04068b2ca60 diff --git a/components/esp_hid/src/nimble_hidd.c b/components/esp_hid/src/nimble_hidd.c index 6c4904160c..505adcab2a 100644 --- a/components/esp_hid/src/nimble_hidd.c +++ b/components/esp_hid/src/nimble_hidd.c @@ -35,6 +35,11 @@ static const char *TAG = "NIMBLE_HIDD"; typedef struct esp_ble_hidd_dev_s esp_ble_hidd_dev_t; // there can be only one BLE HID device static esp_ble_hidd_dev_t *s_dev = NULL; +/** service index is used to identify the hid service instance + of the registered characteristic. + Assuming the first instance of the hid service is registered first. + Increment service index as the hid services get registered */ +static int service_index = -1; typedef hidd_report_item_t hidd_le_report_item_t; @@ -183,6 +188,15 @@ static int nimble_hid_stop_gatts(esp_ble_hidd_dev_t *dev) /* stop gatt database */ ble_gatts_stop(); + + ble_svc_hid_deinit(); + ble_svc_hid_reset(); + ble_svc_dis_deinit(); + ble_svc_bas_deinit(); + ble_svc_sps_deinit(); + ble_svc_gatt_deinit(); + ble_svc_gap_deinit(); + return rc; } @@ -283,6 +297,7 @@ static int nimble_hidd_dev_deinit(void *devp) return ESP_FAIL; } s_dev = NULL; + service_index = -1; // resetting the value nimble_hid_stop_gatts(dev); esp_event_post_to(dev->event_loop_handle, ESP_HIDD_EVENTS, ESP_HIDD_STOP_EVENT, NULL, 0, portMAX_DELAY); @@ -521,11 +536,6 @@ static int nimble_hid_gap_event(struct ble_gap_event *event, void *arg) return 0; } -/** service index is used to identify the hid service instance - of the registered characteristic. - Assuming the first instance of the hid service is registered first. - Increment service index as the hid services get registered */ -static int service_index = -1; static void nimble_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { char buf[BLE_UUID_STR_LEN]; diff --git a/examples/bluetooth/esp_hid_device/main/esp_hid_gap.c b/examples/bluetooth/esp_hid_device/main/esp_hid_gap.c index 9c87942f88..fcc9270798 100644 --- a/examples/bluetooth/esp_hid_device/main/esp_hid_gap.c +++ b/examples/bluetooth/esp_hid_device/main/esp_hid_gap.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -1021,6 +1021,44 @@ static esp_err_t init_low_level(uint8_t mode) #endif /* CONFIG_BT_BLE_ENABLED */ return ret; } + +static esp_err_t deinit_low_level(void) +{ + esp_err_t ret; + + if (bt_scan_results) { + esp_hid_scan_results_free(bt_scan_results); + bt_scan_results = NULL; + num_bt_scan_results = 0; + } + if (ble_scan_results) { + esp_hid_scan_results_free(ble_scan_results); + ble_scan_results = NULL; + num_ble_scan_results = 0; + } + + ret = esp_bluedroid_disable(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_bluedroid_disable failed: %d", ret); + } + + ret = esp_bluedroid_deinit(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_bluedroid_deinit failed: %d", ret); + } + + ret = esp_bt_controller_disable(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_bt_controller_disable failed: %d", ret); + } + + ret = esp_bt_controller_deinit(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_bt_controller_deinit failed: %d", ret); + } + + return ESP_OK; +} #endif #if CONFIG_BT_NIMBLE_ENABLED @@ -1057,8 +1095,52 @@ static esp_err_t init_low_level(uint8_t mode) return ret; } + +static esp_err_t deinit_low_level(void) +{ + esp_err_t ret; + + ret = esp_nimble_deinit(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_nimble_deinit failed: %d", ret); + } + + ret = esp_bt_controller_disable(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_bt_controller_disable failed: %d", ret); + } + + ret = esp_bt_controller_deinit(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_bt_controller_deinit failed: %d", ret); + } + + return ESP_OK; +} #endif +esp_err_t esp_hid_gap_deinit(void) +{ + esp_err_t ret; + + ret = deinit_low_level(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "deinit_low_level failed: %d", ret); + } + + if (bt_hidh_cb_semaphore != NULL) { + vSemaphoreDelete(bt_hidh_cb_semaphore); + bt_hidh_cb_semaphore = NULL; + } + + if (ble_hidh_cb_semaphore != NULL) { + vSemaphoreDelete(ble_hidh_cb_semaphore); + ble_hidh_cb_semaphore = NULL; + } + + return ESP_OK; +} + esp_err_t esp_hid_gap_init(uint8_t mode) { esp_err_t ret; diff --git a/examples/bluetooth/esp_hid_device/main/esp_hid_gap.h b/examples/bluetooth/esp_hid_device/main/esp_hid_gap.h index 5211c90c83..fe01fc77ee 100644 --- a/examples/bluetooth/esp_hid_device/main/esp_hid_gap.h +++ b/examples/bluetooth/esp_hid_device/main/esp_hid_gap.h @@ -74,6 +74,7 @@ void print_uuid(esp_bt_uuid_t *uuid); #endif esp_err_t esp_hid_gap_init(uint8_t mode); +esp_err_t esp_hid_gap_deinit(void); esp_err_t esp_hid_ble_gap_adv_init(uint16_t appearance, const char *device_name); esp_err_t esp_hid_ble_gap_adv_start(void); diff --git a/examples/bluetooth/esp_hid_host/main/esp_hid_gap.h b/examples/bluetooth/esp_hid_host/main/esp_hid_gap.h index 33bad93103..758de01dff 100644 --- a/examples/bluetooth/esp_hid_host/main/esp_hid_gap.h +++ b/examples/bluetooth/esp_hid_host/main/esp_hid_gap.h @@ -83,6 +83,8 @@ typedef struct esp_hidh_scan_result_s { } esp_hid_scan_result_t; esp_err_t esp_hid_gap_init(uint8_t mode); +esp_err_t esp_hid_gap_deinit(void); + esp_err_t esp_hid_scan(uint32_t seconds, size_t *num_results, esp_hid_scan_result_t **results); void esp_hid_scan_results_free(esp_hid_scan_result_t *results); From f02ea04a25dc7da135905ba1d4bd7353e2301c79 Mon Sep 17 00:00:00 2001 From: Astha Verma Date: Tue, 14 Oct 2025 17:53:14 +0530 Subject: [PATCH 67/84] fix(nimble): Support for concatenation of same type UUID during adv data parsing --- components/bt/host/nimble/Kconfig.in | 9 +++++++++ components/bt/host/nimble/port/include/esp_nimble_cfg.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index dc82f62561..26c17ae3c4 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -1216,6 +1216,15 @@ menu "Extra Features" help This option is used to enable encrypted advertising data. + config BT_NIMBLE_ADV_UUID_CONCAT + bool "concatenate uuids while parsing advertising data" + default n + depends on BT_NIMBLE_ENABLED + help + Enables concatenation of multiple UUIDs of the same type while parsing + advertising data on the central device. When disabled, only the last + parsed UUID of a given type is retained. + config BT_NIMBLE_MAX_EADS int "Maximum number of EAD devices to save across reboots" default 10 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 8155a2a6d0..4ddd4b4edb 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -118,6 +118,12 @@ #define MYNEWT_VAL_ENC_ADV_DATA (CONFIG_BT_NIMBLE_ENC_ADV_DATA) #endif +#ifndef CONFIG_BT_NIMBLE_ADV_UUID_CONCAT +#define MYNEWT_VAL_BLE_ADV_UUID_CONCAT (0) +#else +#define MYNEWT_VAL_BLE_ADV_UUID_CONCAT (CONFIG_BT_NIMBLE_ADV_UUID_CONCAT) +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) #define BLE_SCAN_RSP_DATA_MAX_LEN_N (1650) #else From bae31a685de7ede5af6085d07931506a80d85e35 Mon Sep 17 00:00:00 2001 From: Astha Verma Date: Mon, 12 Jan 2026 17:54:52 +0530 Subject: [PATCH 68/84] fix(nimble): fix esp_hid_device example when static_to_dynamic enabled --- components/bt/host/nimble/Kconfig.in | 2 +- components/esp_hid/src/nimble_hidh.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index 26c17ae3c4..eb8ed7cfc4 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -290,7 +290,7 @@ menu "GAP" config BT_NIMBLE_MAX_CCCDS int "Maximum number of CCC descriptors to save across reboots" default 8 - depends on BT_NIMBLE_ENABLED && BT_NIMBLE_NVS_PERSIST + depends on BT_NIMBLE_ENABLED help Defines maximum number of CCC descriptors to save diff --git a/components/esp_hid/src/nimble_hidh.c b/components/esp_hid/src/nimble_hidh.c index 134baca889..93bc0279a9 100644 --- a/components/esp_hid/src/nimble_hidh.c +++ b/components/esp_hid/src/nimble_hidh.c @@ -289,7 +289,7 @@ desc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, } /* this api does the following things : -** does service, characteristic and discriptor discovery and +** does service, characteristic and descriptor discovery and ** fills the hid device information accordingly in dev */ static void read_device_services(esp_hidh_dev_t *dev) { @@ -466,7 +466,7 @@ static void read_device_services(esp_hidh_dev_t *dev) chr_end_handle, desc_disced, descr_result); WAIT_CB(); if (status != 0) { - ESP_LOGE(TAG, "failed to find discriptors for characteristic : %d", c); + ESP_LOGE(TAG, "failed to find descriptors for characteristic : %d", c); assert(status == 0); } dcount = dscs_discovered; @@ -949,6 +949,7 @@ esp_hidh_dev_t *esp_ble_hidh_dev_open(uint8_t *bda, uint8_t address_type) dev->report_write = esp_ble_hidh_dev_report_write; dev->report_read = esp_ble_hidh_dev_report_read; dev->dump = esp_ble_hidh_dev_dump; + dev->connected = true; /* perform service discovery and fill the report maps */ read_device_services(dev); From 6c000e04f678250abef4b5018b0857f07348ec08 Mon Sep 17 00:00:00 2001 From: armando Date: Tue, 20 Jan 2026 10:07:54 +0800 Subject: [PATCH 69/84] change(flash): improve bootloader_flash_read log --- .../bootloader_flash/src/bootloader_flash.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c index 0b63c884f5..1118ec1be5 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -537,16 +537,8 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt) { - if (src_addr & 3) { - ESP_EARLY_LOGE(TAG, "bootloader_flash_read src_addr 0x%x not 4-byte aligned", src_addr); - return ESP_FAIL; - } - if (size & 3) { - ESP_EARLY_LOGE(TAG, "bootloader_flash_read size 0x%x not 4-byte aligned", size); - return ESP_FAIL; - } - if ((intptr_t)dest & 3) { - ESP_EARLY_LOGE(TAG, "bootloader_flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest); + if ((src_addr & 3) || (size & 3) || ((intptr_t)dest & 3)) { + ESP_EARLY_LOGE(TAG, "bootloader_flash_read src_addr 0x%x, size 0x%x or dest 0x%x not 4-byte aligned", src_addr, size, (intptr_t)dest); return ESP_FAIL; } From 4b884d0f463ccf4b399b0eeb40d38635853f0ab4 Mon Sep 17 00:00:00 2001 From: armando Date: Thu, 22 Jan 2026 10:00:52 +0800 Subject: [PATCH 70/84] fix(kconfig): fixed default cpu freq issue on Date: Wed, 7 Jan 2026 15:28:05 +0800 Subject: [PATCH 71/84] feat(ieee802154): separated the 802.15.4 HAL codes from the HAL component --- components/esp_hal_ieee802154/CMakeLists.txt | 15 +++++++++++++++ .../esp32c5}/ieee802154_periph.c | 4 ++-- .../esp32c5/include/hal/ieee802154_ll.h | 3 +-- .../esp32c6/ieee802154_periph.c | 4 ++-- .../esp32c6/include/hal/ieee802154_ll.h | 3 +-- .../esp32h2}/ieee802154_periph.c | 4 ++-- .../esp32h2/include/hal/ieee802154_ll.h | 3 +-- .../include/hal/ieee802154_common_ll.h | 2 +- .../include/hal}/ieee802154_periph.h | 2 +- components/ieee802154/CMakeLists.txt | 2 +- components/ieee802154/driver/esp_ieee802154_dev.c | 2 +- components/soc/CMakeLists.txt | 6 ------ 12 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 components/esp_hal_ieee802154/CMakeLists.txt rename components/{soc/esp32h2 => esp_hal_ieee802154/esp32c5}/ieee802154_periph.c (64%) rename components/{hal => esp_hal_ieee802154}/esp32c5/include/hal/ieee802154_ll.h (76%) rename components/{soc => esp_hal_ieee802154}/esp32c6/ieee802154_periph.c (64%) rename components/{hal => esp_hal_ieee802154}/esp32c6/include/hal/ieee802154_ll.h (76%) rename components/{soc/esp32c5 => esp_hal_ieee802154/esp32h2}/ieee802154_periph.c (64%) rename components/{hal => esp_hal_ieee802154}/esp32h2/include/hal/ieee802154_ll.h (81%) rename components/{hal => esp_hal_ieee802154}/include/hal/ieee802154_common_ll.h (99%) rename components/{soc/include/soc => esp_hal_ieee802154/include/hal}/ieee802154_periph.h (86%) diff --git a/components/esp_hal_ieee802154/CMakeLists.txt b/components/esp_hal_ieee802154/CMakeLists.txt new file mode 100644 index 0000000000..a73de4d326 --- /dev/null +++ b/components/esp_hal_ieee802154/CMakeLists.txt @@ -0,0 +1,15 @@ +idf_build_get_property(target IDF_TARGET) + +set(includes "include") +set(srcs "") + +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/include") + list(APPEND includes "${target}/include") +endif() + +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/ieee802154_periph.c") + list(APPEND srcs "${target}/ieee802154_periph.c") +endif() + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS ${includes}) diff --git a/components/soc/esp32h2/ieee802154_periph.c b/components/esp_hal_ieee802154/esp32c5/ieee802154_periph.c similarity index 64% rename from components/soc/esp32h2/ieee802154_periph.c rename to components/esp_hal_ieee802154/esp32c5/ieee802154_periph.c index 104bc61c12..c6aa36edba 100644 --- a/components/soc/esp32h2/ieee802154_periph.c +++ b/components/esp_hal_ieee802154/esp32c5/ieee802154_periph.c @@ -1,10 +1,10 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/ieee802154_periph.h" +#include "hal/ieee802154_periph.h" const ieee802154_conn_t ieee802154_periph = { .module = PERIPH_IEEE802154_MODULE, diff --git a/components/hal/esp32c5/include/hal/ieee802154_ll.h b/components/esp_hal_ieee802154/esp32c5/include/hal/ieee802154_ll.h similarity index 76% rename from components/hal/esp32c5/include/hal/ieee802154_ll.h rename to components/esp_hal_ieee802154/esp32c5/include/hal/ieee802154_ll.h index f480050ccd..d867995893 100644 --- a/components/hal/esp32c5/include/hal/ieee802154_ll.h +++ b/components/esp_hal_ieee802154/esp32c5/include/hal/ieee802154_ll.h @@ -1,12 +1,11 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include #include "hal/ieee802154_common_ll.h" #define IEEE802154_TXPOWER_VALUE_MAX 20 diff --git a/components/soc/esp32c6/ieee802154_periph.c b/components/esp_hal_ieee802154/esp32c6/ieee802154_periph.c similarity index 64% rename from components/soc/esp32c6/ieee802154_periph.c rename to components/esp_hal_ieee802154/esp32c6/ieee802154_periph.c index 6e9f436aba..39d8c24c3d 100644 --- a/components/soc/esp32c6/ieee802154_periph.c +++ b/components/esp_hal_ieee802154/esp32c6/ieee802154_periph.c @@ -1,10 +1,10 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/ieee802154_periph.h" +#include "hal/ieee802154_periph.h" const ieee802154_conn_t ieee802154_periph = { .module = PERIPH_IEEE802154_MODULE, diff --git a/components/hal/esp32c6/include/hal/ieee802154_ll.h b/components/esp_hal_ieee802154/esp32c6/include/hal/ieee802154_ll.h similarity index 76% rename from components/hal/esp32c6/include/hal/ieee802154_ll.h rename to components/esp_hal_ieee802154/esp32c6/include/hal/ieee802154_ll.h index 14e548a1d3..d867995893 100644 --- a/components/hal/esp32c6/include/hal/ieee802154_ll.h +++ b/components/esp_hal_ieee802154/esp32c6/include/hal/ieee802154_ll.h @@ -1,12 +1,11 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include #include "hal/ieee802154_common_ll.h" #define IEEE802154_TXPOWER_VALUE_MAX 20 diff --git a/components/soc/esp32c5/ieee802154_periph.c b/components/esp_hal_ieee802154/esp32h2/ieee802154_periph.c similarity index 64% rename from components/soc/esp32c5/ieee802154_periph.c rename to components/esp_hal_ieee802154/esp32h2/ieee802154_periph.c index ec346c396e..c6aa36edba 100644 --- a/components/soc/esp32c5/ieee802154_periph.c +++ b/components/esp_hal_ieee802154/esp32h2/ieee802154_periph.c @@ -1,10 +1,10 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/ieee802154_periph.h" +#include "hal/ieee802154_periph.h" const ieee802154_conn_t ieee802154_periph = { .module = PERIPH_IEEE802154_MODULE, diff --git a/components/hal/esp32h2/include/hal/ieee802154_ll.h b/components/esp_hal_ieee802154/esp32h2/include/hal/ieee802154_ll.h similarity index 81% rename from components/hal/esp32h2/include/hal/ieee802154_ll.h rename to components/esp_hal_ieee802154/esp32h2/include/hal/ieee802154_ll.h index 2795fc4896..ab1ad15e2a 100644 --- a/components/hal/esp32h2/include/hal/ieee802154_ll.h +++ b/components/esp_hal_ieee802154/esp32h2/include/hal/ieee802154_ll.h @@ -1,12 +1,11 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include #include "hal/ieee802154_common_ll.h" #ifdef __cplusplus diff --git a/components/hal/include/hal/ieee802154_common_ll.h b/components/esp_hal_ieee802154/include/hal/ieee802154_common_ll.h similarity index 99% rename from components/hal/include/hal/ieee802154_common_ll.h rename to components/esp_hal_ieee802154/include/hal/ieee802154_common_ll.h index 07617b7dab..d0faf3b622 100644 --- a/components/hal/include/hal/ieee802154_common_ll.h +++ b/components/esp_hal_ieee802154/include/hal/ieee802154_common_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/soc/include/soc/ieee802154_periph.h b/components/esp_hal_ieee802154/include/hal/ieee802154_periph.h similarity index 86% rename from components/soc/include/soc/ieee802154_periph.h rename to components/esp_hal_ieee802154/include/hal/ieee802154_periph.h index 5c414e91f6..34f2a9da68 100644 --- a/components/soc/include/soc/ieee802154_periph.h +++ b/components/esp_hal_ieee802154/include/hal/ieee802154_periph.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/ieee802154/CMakeLists.txt b/components/ieee802154/CMakeLists.txt index 2b556a12cf..5f410b3e9b 100644 --- a/components/ieee802154/CMakeLists.txt +++ b/components/ieee802154/CMakeLists.txt @@ -37,5 +37,5 @@ idf_component_register( PRIV_INCLUDE_DIRS "${private_include}" LDFRAGMENTS linker.lf REQUIRES esp_coex - PRIV_REQUIRES esp_phy esp_timer soc hal esp_pm + PRIV_REQUIRES esp_phy esp_timer soc hal esp_pm esp_hal_ieee802154 ) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 1a558d432c..01b3c4aae7 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -9,7 +9,7 @@ #include "freertos/portmacro.h" #include "soc/periph_defs.h" #include "soc/soc.h" -#include "soc/ieee802154_periph.h" +#include "hal/ieee802154_periph.h" #include "esp_private/esp_modem_clock.h" #include "esp_check.h" #include "esp_coex_i154.h" diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index fada5c4c2d..79564e640b 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -151,12 +151,6 @@ if(CONFIG_SOC_WDT_SUPPORTED) list(APPEND srcs "${target_folder}/wdt_periph.c") endif() -if(CONFIG_SOC_IEEE802154_SUPPORTED) - if(NOT target STREQUAL "esp32h4") - list(APPEND srcs "${target_folder}/ieee802154_periph.c") - endif() -endif() - if(CONFIG_SOC_USB_OTG_SUPPORTED) list(APPEND srcs "${target_folder}/usb_dwc_periph.c") endif() From 4c0c9d2d6adb50d347c7d1b2440b8575170ce897 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Wed, 14 Jan 2026 11:17:33 +0800 Subject: [PATCH 72/84] fix: fixes potential ws server deadlock with blocking work queue Closes https://github.com/espressif/esp-idf/issues/17591 --- .../esp_http_server/src/esp_httpd_priv.h | 12 ++++++++++- components/esp_http_server/src/httpd_main.c | 7 ++++++- components/esp_http_server/src/httpd_sess.c | 20 ++++++++++++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/components/esp_http_server/src/esp_httpd_priv.h b/components/esp_http_server/src/esp_httpd_priv.h index 54c6923c6d..ca57ceea14 100644 --- a/components/esp_http_server/src/esp_httpd_priv.h +++ b/components/esp_http_server/src/esp_httpd_priv.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -576,6 +576,16 @@ esp_err_t httpd_ws_get_frame_type(httpd_req_t *req); */ esp_err_t httpd_sess_trigger_close_(httpd_handle_t handle, struct sock_db *session); +/** + * @brief Directly closes the least recently used session + * + * @param[in] hd Server instance data + * + * @return + * - ESP_OK : if session closed successfully + */ +esp_err_t httpd_sess_close_lru_direct(struct httpd_data *hd); + /** End of WebSocket related functions * @} */ diff --git a/components/esp_http_server/src/httpd_main.c b/components/esp_http_server/src/httpd_main.c index 943075317f..61b44d086d 100644 --- a/components/esp_http_server/src/httpd_main.c +++ b/components/esp_http_server/src/httpd_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -54,7 +54,12 @@ static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd) if (hd->config.lru_purge_enable == true) { if (!httpd_is_sess_available(hd)) { /* Queue asynchronous closure of the least recently used session */ +#if CONFIG_HTTPD_QUEUE_WORK_BLOCKING + /* In case of blocking mode, close the least recently used session directly */ + return httpd_sess_close_lru_direct(hd); +#else return httpd_sess_close_lru(hd); +#endif /* CONFIG_HTTPD_QUEUE_WORK_BLOCKING */ /* Returning from this allows the main server thread to process * the queued asynchronous control message for closing LRU session. * Since connection request hasn't been addressed yet using accept() diff --git a/components/esp_http_server/src/httpd_sess.c b/components/esp_http_server/src/httpd_sess.c index eaeaee7c1a..5b2fd3e347 100644 --- a/components/esp_http_server/src/httpd_sess.c +++ b/components/esp_http_server/src/httpd_sess.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -498,3 +498,21 @@ void httpd_sess_close_all(struct httpd_data *hd) }; httpd_sess_enum(hd, enum_function, &context); } + +esp_err_t httpd_sess_close_lru_direct(struct httpd_data *hd) +{ + enum_context_t context = { + .task = HTTPD_TASK_FIND_LOWEST_LRU, + .lru_counter = UINT64_MAX, + .fd = -1 + }; + httpd_sess_enum(hd, enum_function, &context); + if (!context.session) { + return ESP_OK; + } + + ESP_LOGD(TAG, LOG_FMT("Directly closing session with fd %d"), context.session->fd); + // Call httpd_sess_delete directly instead of going through work queue + httpd_sess_delete(hd, context.session); + return ESP_OK; +} From 7ef71e977041ab134aed6c19f5e47eff578959d0 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Wed, 14 Jan 2026 10:56:35 +0800 Subject: [PATCH 73/84] fix: stop reading ws data when peer closes the connection Closes https://github.com/espressif/esp-idf/issues/17822 --- components/esp_http_server/src/httpd_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_http_server/src/httpd_txrx.c b/components/esp_http_server/src/httpd_txrx.c index 4ab4891394..8bb20de26d 100644 --- a/components/esp_http_server/src/httpd_txrx.c +++ b/components/esp_http_server/src/httpd_txrx.c @@ -122,7 +122,7 @@ int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, httpd_recv_op size_t recv_len = pending_len; do { int ret = ra->sd->recv_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0); - if (ret < 0) { + if (ret <= 0) { ESP_LOGD(TAG, LOG_FMT("error in recv_fn")); if ((ret == HTTPD_SOCK_ERR_TIMEOUT) && (pending_len != 0)) { /* If recv() timeout occurred, but pending data is From 1e27eb204b4f922134ae0c4c97606dc1ef7eeda0 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Wed, 21 Jan 2026 17:04:13 +0800 Subject: [PATCH 74/84] feat(esp_http_client): adds API to get transport socket --- components/esp_http_client/esp_http_client.c | 11 ++++++++++- .../esp_http_client/include/esp_http_client.h | 13 ++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 01966f9741..32c9c621e8 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -2034,3 +2034,12 @@ bool esp_http_client_is_persistent_connection(esp_http_client_handle_t client) } return false; } + +int esp_http_client_get_socket(esp_http_client_handle_t client) +{ + if (client == NULL || client->transport == NULL) { + return -1; + } + + return esp_transport_get_socket(client->transport); +} diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index e2cf27a584..a17c4d1400 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -857,6 +857,17 @@ esp_err_t esp_http_client_get_chunk_length(esp_http_client_handle_t client, int */ bool esp_http_client_is_persistent_connection(esp_http_client_handle_t client); +/** + * @brief Get the socket from the underlying transport + * + * @param client The HTTP client handle + * + * @return + * - -1 if the client is NULL or the transport is not initialized + * - The socket file descriptor if successful + */ +int esp_http_client_get_socket(esp_http_client_handle_t client); + #ifdef __cplusplus } #endif From b306fa566b2259f2fd79bf0e73ecb665fb621479 Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Wed, 29 Oct 2025 20:13:30 +0100 Subject: [PATCH 75/84] fix(storage/spiffs): fix readdir setting errno on directory end spiffs_res_to_errno maps `SPIFFS_ERR_END_OF_OBJECT` to EIO which breaks the common contract where errno should be 0 if readdir iterated through all the entries in a directory. The fix is explicitly checking for `SPIFFS_ERR_END_OF_OBJECT` and in that case set errno to 0. --- components/spiffs/esp_spiffs.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/spiffs/esp_spiffs.c b/components/spiffs/esp_spiffs.c index b4820f5098..f1ed250a01 100644 --- a/components/spiffs/esp_spiffs.c +++ b/components/spiffs/esp_spiffs.c @@ -745,7 +745,15 @@ static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry, char * item_name; do { if (SPIFFS_readdir(&dir->d, &out) == 0) { - errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); + s32_t spiffs_res = SPIFFS_errno(efs->fs); + switch (spiffs_res) { + case SPIFFS_ERR_END_OF_OBJECT: + errno = 0; + break; + default: + errno = spiffs_res_to_errno(spiffs_res); + break; + } SPIFFS_clearerr(efs->fs); if (!errno) { *out_dirent = NULL; From 8a742930a926623b042b73b186bcc6151a87c662 Mon Sep 17 00:00:00 2001 From: zwx Date: Tue, 20 Jan 2026 15:43:44 +0800 Subject: [PATCH 76/84] fix(802.15.4): fixed security frame configuration --- .../ieee802154/driver/esp_ieee802154_dev.c | 23 +++++++++++++++---- .../ieee802154/driver/esp_ieee802154_frame.c | 6 ++--- .../ieee802154/driver/esp_ieee802154_sec.c | 15 +++++++----- components/ieee802154/linker.lf | 2 +- .../private_include/esp_ieee802154_frame.h | 12 +++++++++- .../private_include/esp_ieee802154_sec.h | 7 +++--- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 01b3c4aae7..fa5bdf079e 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -122,7 +122,6 @@ static IRAM_ATTR void event_end_process(void) { ieee802154_etm_channel_clear(IEEE802154_ETM_CHANNEL0); ieee802154_etm_channel_clear(IEEE802154_ETM_CHANNEL1); - ieee802154_ll_set_transmit_security(false); ieee802154_timer0_stop(); ieee802154_timer1_stop(); } @@ -301,6 +300,7 @@ IEEE802154_NOINLINE static bool stop_rx(void) IEEE802154_NOINLINE static bool stop_tx_ack(void) { ieee802154_set_cmd(IEEE802154_CMD_STOP); + ieee802154_sec_clear(); ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); @@ -314,6 +314,7 @@ IEEE802154_NOINLINE static bool stop_tx(void) ieee802154_ll_events events; ieee802154_set_cmd(IEEE802154_CMD_STOP); + ieee802154_sec_clear(); events = ieee802154_ll_get_events(); @@ -468,6 +469,7 @@ static IRAM_ATTR void next_operation(void) static IRAM_ATTR void isr_handle_tx_done(void) { + ieee802154_sec_clear(); event_end_process(); #if !CONFIG_IEEE802154_TEST if (!ieee802154_is_supported_frame_type(ieee802154_frame_get_type(s_tx_frame))) { @@ -528,7 +530,6 @@ static IRAM_ATTR void isr_handle_rx_done(void) // Send the Enh-Ack frame if generator succeeds. ieee802154_ll_set_tx_addr(s_enh_ack_frame); s_tx_frame = s_enh_ack_frame; - ieee802154_sec_update(); ieee802154_ll_enhack_generate_done_notify(); ieee802154_set_state(IEEE802154_STATE_TX_ENH_ACK); #endif @@ -548,6 +549,7 @@ static IRAM_ATTR void isr_handle_rx_done(void) static IRAM_ATTR void isr_handle_ack_tx_done(void) { + ieee802154_sec_clear(); extcoex_rx_stage_start(); ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); NEEDS_NEXT_OPT(true); @@ -602,13 +604,17 @@ static IRAM_ATTR void isr_handle_rx_phase_rx_abort(ieee802154_ll_rx_abort_reason static IRAM_ATTR void isr_handle_tx_ack_phase_rx_abort(ieee802154_ll_rx_abort_reason_t rx_abort_reason) { + ieee802154_sec_clear(); event_end_process(); #if CONFIG_IEEE802154_TEST uint32_t rx_status = ieee802154_ll_get_rx_status(); #endif switch (rx_abort_reason) { - case IEEE802154_RX_ABORT_BY_RX_STOP: case IEEE802154_RX_ABORT_BY_TX_ACK_STOP: +#if CONFIG_IEEE802154_TEST + ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); +#endif + case IEEE802154_RX_ABORT_BY_RX_STOP: case IEEE802154_RX_ABORT_BY_ED_STOP: case IEEE802154_RX_ABORT_BY_SFD_TIMEOUT: case IEEE802154_RX_ABORT_BY_CRC_ERROR: @@ -652,11 +658,19 @@ static IRAM_ATTR void isr_handle_tx_ack_phase_rx_abort(ieee802154_ll_rx_abort_re static IRAM_ATTR void isr_handle_tx_abort(ieee802154_ll_tx_abort_reason_t tx_abort_reason) { + ieee802154_sec_clear(); event_end_process(); switch (tx_abort_reason) { case IEEE802154_TX_ABORT_BY_RX_ACK_STOP: +#if CONFIG_IEEE802154_TEST + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); + break; +#endif case IEEE802154_TX_ABORT_BY_TX_STOP: // do nothing +#if CONFIG_IEEE802154_TEST + ieee802154_inner_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_ABORT); +#endif break; case IEEE802154_TX_ABORT_BY_RX_ACK_SFD_TIMEOUT: case IEEE802154_TX_ABORT_BY_RX_ACK_CRC_ERROR: @@ -734,7 +748,6 @@ IEEE802154_NOINLINE static void ieee802154_isr(void *arg) ieee802154_ll_events events = ieee802154_ll_get_events(); ieee802154_ll_rx_abort_reason_t rx_abort_reason = ieee802154_ll_get_rx_abort_reason(); ieee802154_ll_tx_abort_reason_t tx_abort_reason = ieee802154_ll_get_tx_abort_reason(); - IEEE802154_PROBE(events); ieee802154_ll_clear_events(events); @@ -923,7 +936,6 @@ IEEE802154_STATIC void tx_init(const uint8_t *frame) s_tx_frame = (uint8_t *)frame; stop_current_operation(); ieee802154_pib_update(); - ieee802154_sec_update(); ieee802154_ll_set_tx_addr(s_tx_frame); @@ -967,6 +979,7 @@ esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca) } else { ieee802154_inner_transmit_failed(frame, ESP_IEEE802154_TX_ERR_ABORT); } + ieee802154_sec_clear(); IEEE802154_TX_DEFERRED_NUMS_UPDATE(); ieee802154_exit_critical(); return ESP_OK; diff --git a/components/ieee802154/driver/esp_ieee802154_frame.c b/components/ieee802154/driver/esp_ieee802154_frame.c index 61357d8bcb..35e4eb5b84 100644 --- a/components/ieee802154/driver/esp_ieee802154_frame.c +++ b/components/ieee802154/driver/esp_ieee802154_frame.c @@ -11,7 +11,7 @@ #include "esp_ieee802154_frame.h" #include "esp_ieee802154_util.h" -IEEE802154_STATIC IEEE802154_INLINE bool is_security_enabled(const uint8_t *frame) +bool ieee802154_frame_is_security_enabled(const uint8_t *frame) { return frame[IEEE802154_FRAME_SECURITY_OFFSET] & IEEE802154_FRAME_SECURITY_BIT; } @@ -269,7 +269,7 @@ IEEE802154_STATIC uint8_t ieee802154_frame_get_ie_field_len(const uint8_t *frame IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_payload_offset(const uint8_t *frame) { uint8_t offset = ieee802154_frame_security_header_offset(frame); - if (is_security_enabled(frame)) { + if (ieee802154_frame_is_security_enabled(frame)) { // skip security field. offset += ieee802154_frame_get_security_field_len(frame); } @@ -296,7 +296,7 @@ bool ieee802154_is_data_request(const uint8_t *frame) return false; } uint8_t offset = ieee802154_frame_security_header_offset(frame); - if (is_security_enabled(frame)) { + if (ieee802154_frame_is_security_enabled(frame)) { // skip security field. offset += ieee802154_frame_get_security_field_len(frame); } diff --git a/components/ieee802154/driver/esp_ieee802154_sec.c b/components/ieee802154/driver/esp_ieee802154_sec.c index 2192550ab3..c628666b0a 100644 --- a/components/ieee802154/driver/esp_ieee802154_sec.c +++ b/components/ieee802154/driver/esp_ieee802154_sec.c @@ -1,28 +1,31 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include "sdkconfig.h" #include #include "esp_err.h" #include "hal/ieee802154_ll.h" #include "esp_ieee802154_frame.h" #include "esp_ieee802154_sec.h" +#include "esp_ieee802154_util.h" #include "esp_ieee802154.h" -static bool s_is_security = false; void ieee802154_transmit_security_config(uint8_t *frame, uint8_t *key, uint8_t *addr) { +#if !CONFIG_IEEE802154_TEST + IEEE802154_ASSERT(ieee802154_frame_is_security_enabled(frame)); +#endif ieee802154_ll_set_security_addr(addr); ieee802154_ll_set_security_key(key); ieee802154_ll_set_security_offset(ieee802154_frame_get_security_payload_offset(frame)); - s_is_security = true; + ieee802154_ll_set_transmit_security(true); } -void ieee802154_sec_update(void) +void ieee802154_sec_clear(void) { - ieee802154_ll_set_transmit_security(s_is_security); - s_is_security = false; + ieee802154_ll_set_transmit_security(false); } diff --git a/components/ieee802154/linker.lf b/components/ieee802154/linker.lf index 5931d3cfac..b5149bedb0 100644 --- a/components/ieee802154/linker.lf +++ b/components/ieee802154/linker.lf @@ -20,12 +20,12 @@ entries: esp_ieee802154_frame: ieee802154_frame_get_dest_panid (noflash) esp_ieee802154_frame: ieee802154_frame_get_dst_addr (noflash) esp_ieee802154_frame: ieee802154_frame_get_src_panid (noflash) + esp_ieee802154_frame: ieee802154_frame_is_security_enabled(noflash) esp_ieee802154_frame: ieee802154_is_data_request (noflash) esp_ieee802154_frame: is_dst_panid_present (noflash) esp_ieee802154_frame: is_src_panid_present (noflash) esp_ieee802154_pib: ieee802154_pib_get_pending_mode (noflash) esp_ieee802154_pib: ieee802154_pib_get_rx_when_idle (noflash) - esp_ieee802154_sec: ieee802154_sec_update (noflash) esp_ieee802154_sec: ieee802154_transmit_security_config (noflash) esp_ieee802154_timer: ieee802154_timer0_set_threshold (noflash) esp_ieee802154_timer: ieee802154_timer0_start (noflash) diff --git a/components/ieee802154/private_include/esp_ieee802154_frame.h b/components/ieee802154/private_include/esp_ieee802154_frame.h index c46fb31e71..4d68a3640f 100644 --- a/components/ieee802154/private_include/esp_ieee802154_frame.h +++ b/components/ieee802154/private_include/esp_ieee802154_frame.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -141,6 +141,16 @@ uint8_t ieee802154_frame_get_version(const uint8_t *frame); */ bool ieee802154_frame_is_ack_required(const uint8_t *frame); +/** + * @brief Is the frame security enabled. + * + * @param[in] frame The pointer to the frame. + * + * @return + * - True if the frame is security enabled, otherwise false. + * + */ +bool ieee802154_frame_is_security_enabled(const uint8_t *frame); /** * @brief Get the destination address of the frame. * diff --git a/components/ieee802154/private_include/esp_ieee802154_sec.h b/components/ieee802154/private_include/esp_ieee802154_sec.h index 7c822a82da..bb01575f1b 100644 --- a/components/ieee802154/private_include/esp_ieee802154_sec.h +++ b/components/ieee802154/private_include/esp_ieee802154_sec.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,11 +25,10 @@ extern "C" { void ieee802154_transmit_security_config(uint8_t *frame, uint8_t *key, uint8_t *addr); /** - * @brief Update the encryption enabled configuration of the next transmission. - * + * @brief Clear the encryption enabled configuration. * */ -void ieee802154_sec_update(void); +void ieee802154_sec_clear(void); #ifdef __cplusplus } From 14c2425def3dee1db8fefd1302a8f49ed40e796b Mon Sep 17 00:00:00 2001 From: zwx Date: Thu, 22 Jan 2026 19:45:27 +0800 Subject: [PATCH 77/84] fix(802.15.4): locate the ieee802154_sec_clear on the noflash --- components/ieee802154/linker.lf | 1 + 1 file changed, 1 insertion(+) diff --git a/components/ieee802154/linker.lf b/components/ieee802154/linker.lf index b5149bedb0..dbe150462c 100644 --- a/components/ieee802154/linker.lf +++ b/components/ieee802154/linker.lf @@ -26,6 +26,7 @@ entries: esp_ieee802154_frame: is_src_panid_present (noflash) esp_ieee802154_pib: ieee802154_pib_get_pending_mode (noflash) esp_ieee802154_pib: ieee802154_pib_get_rx_when_idle (noflash) + esp_ieee802154_sec: ieee802154_sec_clear (noflash) esp_ieee802154_sec: ieee802154_transmit_security_config (noflash) esp_ieee802154_timer: ieee802154_timer0_set_threshold (noflash) esp_ieee802154_timer: ieee802154_timer0_start (noflash) From 07527a5670e44b4eb620caf0af38b7770baf4215 Mon Sep 17 00:00:00 2001 From: "wangtao@espressif.com" Date: Fri, 23 Jan 2026 16:28:07 +0800 Subject: [PATCH 78/84] fix(wifi): fix esp32c2 set vendor ie issue --- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index ab59a9deaf..ad5dcf6b89 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -896,7 +896,7 @@ dbg_hmac_rxtx_statis_dump = 0x4000202c; dbg_hmac_statis_dump = 0x40002030; /* ieee80211_send_action_vendor_spec = 0x40002034; */ /* ieee80211_vnd_lora_ie_size = 0x40002048; */ -ieee80211_vnd_ie_size = 0x4000204c; +//ieee80211_vnd_ie_size = 0x4000204c; ieee80211_add_ssid = 0x40002050; ieee80211_add_rates = 0x40002054; /*ieee80211_add_xrates = 0x40002058;*/ @@ -919,7 +919,7 @@ sta_auth_shared = 0x400020a4; /* cnx_coexist_timeout_process = 0x400020ac; */ ieee80211_alloc_challenge = 0x400020b0; cnx_assoc_timeout = 0x400020b4; -ieee80211_vnd_ie_set = 0x400020b8; +//ieee80211_vnd_ie_set = 0x400020b8; ieee80211_vnd_lora_ie_set = 0x400020bc; ieee80211_add_wme_param = 0x400020c0; /*ieee80211_add_dsparams = 0x400020c4;*/ From 3adb2a22c9134ed9bee0267635ce55c4ee8839db Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Mon, 2 Feb 2026 12:36:42 +0100 Subject: [PATCH 79/84] ci: ignore eco3 marker from adding rev_default marker --- tools/ci/idf_pytest/constants.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci/idf_pytest/constants.py b/tools/ci/idf_pytest/constants.py index b148792b3c..29e5ab52da 100644 --- a/tools/ci/idf_pytest/constants.py +++ b/tools/ci/idf_pytest/constants.py @@ -371,4 +371,5 @@ ECO_MARKERS = [ 'esp32c2eco4', 'esp32c3eco7', 'esp32p4_eco4', + 'esp32c5_eco3', ] From 692d47b6b788a47a7ff2f9fa41e09b7cbc008c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8E=E5=B0=8F=E4=B8=98?= Date: Tue, 3 Feb 2026 13:55:55 +0800 Subject: [PATCH 80/84] fix(esp-tls): Remove unused MBEDTLS_PK_RSA_ALT_SUPPORT dependency from DS peripheral option --- components/esp-tls/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp-tls/Kconfig b/components/esp-tls/Kconfig index 80e9606089..b56f3bbf04 100644 --- a/components/esp-tls/Kconfig +++ b/components/esp-tls/Kconfig @@ -25,7 +25,7 @@ menu "ESP-TLS" config ESP_TLS_USE_DS_PERIPHERAL bool "Use Digital Signature (DS) Peripheral with ESP-TLS" - depends on ESP_TLS_USING_MBEDTLS && SOC_DIG_SIGN_SUPPORTED && MBEDTLS_PK_RSA_ALT_SUPPORT + depends on ESP_TLS_USING_MBEDTLS && SOC_DIG_SIGN_SUPPORTED default y help Enable use of the Digital Signature Peripheral for ESP-TLS.The DS peripheral From 562a730d7c2abfcf5fe20660e4c4616a3adc4557 Mon Sep 17 00:00:00 2001 From: "igor.udot" Date: Thu, 5 Feb 2026 13:21:09 +0800 Subject: [PATCH 81/84] ci: remove esp32c3 from sdcard_sdmode --- components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py b/components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py index b0657186d2..1121bd222b 100644 --- a/components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py +++ b/components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py @@ -13,7 +13,7 @@ from pytest_embedded_idf.utils import idf_parametrize 'release', ], ) -@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target']) +@idf_parametrize('target', ['esp32'], indirect=['target']) def test_fatfs_sdcard_generic_sdmmc(dut: Dut) -> None: dut.run_all_single_board_cases(group='sdmmc', timeout=180) From 080f7ae4a6fe40d46db23554434d66739c9216f8 Mon Sep 17 00:00:00 2001 From: wanckl Date: Tue, 3 Feb 2026 18:46:37 +0800 Subject: [PATCH 82/84] fixed(driver_spi): fixed p4 spi dma trans data error v5.5 --- components/esp_driver_spi/src/gpspi/spi_master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_driver_spi/src/gpspi/spi_master.c b/components/esp_driver_spi/src/gpspi/spi_master.c index e59f8bb8b4..e971f0b3e5 100644 --- a/components/esp_driver_spi/src/gpspi/spi_master.c +++ b/components/esp_driver_spi/src/gpspi/spi_master.c @@ -1210,11 +1210,11 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_dma_priv_buffer(spi_host_t *host, uin } buffer = temp; } - if (use_psram) { + *ret_buffer = buffer; + if (use_psram || (host->bus_attr->cache_align_int > 1)) { esp_err_t ret = esp_cache_msync((void *)buffer, len, is_tx ? (ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED) : ESP_CACHE_MSYNC_FLAG_DIR_M2C); ESP_RETURN_ON_FALSE_ISR(ret == ESP_OK, ESP_ERR_INVALID_ARG, SPI_TAG, "sync failed for %s buffer", is_tx ? "TX" : "RX"); } - *ret_buffer = buffer; return ESP_OK; } From fc5a5f7c77ffbcb1612a8c7d1b5ef6df7b3a97ef Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Tue, 27 Jan 2026 15:05:35 +0800 Subject: [PATCH 83/84] fix(gdma): skip alignment check for AHBDMA version 1 when flash enc --- components/esp_hw_support/dma/gdma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/dma/gdma.c b/components/esp_hw_support/dma/gdma.c index 23c6f12b47..e61a222df0 100644 --- a/components/esp_hw_support/dma/gdma.c +++ b/components/esp_hw_support/dma/gdma.c @@ -383,7 +383,9 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf bool en_desc_burst = true; bool en_data_burst = max_data_burst_size > 0; -#if SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH + // There's auto alignment for AHB GDMA version 1, so we don't need to do anything here + // While, for AHB GDMA version 2 and AXI GDMA, we need to ensure the alignment by software +#if (SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH) && SOC_AHB_GDMA_VERSION != 1 // if MSPI encryption is enabled, and DMA wants to read/write external memory if (efuse_hal_flash_encryption_enabled() && config->access_ext_mem) { uint32_t enc_mem_alignment = GDMA_LL_ACCESS_ENCRYPTION_MEM_ALIGNMENT; From 9fcb7078fc69f6b31ea25d84a70245d6ba6cea17 Mon Sep 17 00:00:00 2001 From: Shreyas Sheth Date: Mon, 17 Nov 2025 16:36:52 +0530 Subject: [PATCH 84/84] fix(esp_wifi): Fix memory leak for sae commit queue --- components/wpa_supplicant/esp_supplicant/src/esp_hostap.c | 3 ++- components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c b/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c index d1d107a3fe..f748787f0a 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c @@ -211,6 +211,7 @@ void *hostap_init(void) } #ifdef CONFIG_SAE + dl_list_init(&hapd->sae_commit_queue); auth_conf->sae_require_mfp = 1; #endif /* CONFIG_SAE */ @@ -263,7 +264,7 @@ void hostapd_cleanup(struct hostapd_data *hapd) struct hostapd_sae_commit_queue *q, *tmp; - if (dl_list_empty(&hapd->sae_commit_queue)) { + if (!dl_list_empty(&hapd->sae_commit_queue)) { dl_list_for_each_safe(q, tmp, &hapd->sae_commit_queue, struct hostapd_sae_commit_queue, list) { dl_list_del(&q->list); diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c index 21a7c4e379..5f351739bd 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c @@ -653,8 +653,6 @@ int wpa3_hostap_auth_init(void *data) return ESP_FAIL; } - struct hostapd_data *hapd = (struct hostapd_data *)data; - dl_list_init(&hapd->sae_commit_queue); return ESP_OK; }