diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 649007cdfa..dc5ffda133 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -330,6 +330,17 @@ static void start_other_core(void) } #if !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#if CONFIG_IDF_TARGET_ESP32 +static void restore_app_mmu_from_pro_mmu(void) +{ + const int mmu_reg_num = 2048; + volatile uint32_t* from = (uint32_t*)DR_REG_FLASH_MMU_TABLE_PRO; + volatile uint32_t* to = (uint32_t*)DR_REG_FLASH_MMU_TABLE_APP; + for (int i = 0; i < mmu_reg_num; i++) { + *(to++) = *(from++); + } +} +#endif // This function is needed to make the multicore app runnable on a unicore bootloader (built with FREERTOS UNICORE). // It does some cache settings for other CPUs. void IRAM_ATTR do_multicore_settings(void) @@ -341,9 +352,11 @@ void IRAM_ATTR do_multicore_settings(void) Cache_Read_Disable(1); Cache_Flush(1); DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); + mmu_init(1); DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); // We do not enable cache for CPU1 now because it will be done later in start_other_core(). } + restore_app_mmu_from_pro_mmu(); #endif cache_bus_mask_t cache_bus_mask_core0 = cache_ll_l1_get_enabled_bus(0); diff --git a/tools/test_apps/system/unicore_bootloader/main/CMakeLists.txt b/tools/test_apps/system/unicore_bootloader/main/CMakeLists.txt index 34613e8e3c..8f8dd1b8d6 100644 --- a/tools/test_apps/system/unicore_bootloader/main/CMakeLists.txt +++ b/tools/test_apps/system/unicore_bootloader/main/CMakeLists.txt @@ -1 +1,2 @@ -idf_component_register(SRCS "main.c") +idf_component_register(SRCS "main.c" + PRIV_REQUIRES nvs_flash esp_psram) diff --git a/tools/test_apps/system/unicore_bootloader/main/main.c b/tools/test_apps/system/unicore_bootloader/main/main.c index 50c39ad016..327754428e 100644 --- a/tools/test_apps/system/unicore_bootloader/main/main.c +++ b/tools/test_apps/system/unicore_bootloader/main/main.c @@ -5,8 +5,70 @@ */ #include +#include + +#include "nvs_flash.h" +#include "nvs.h" void app_main(void) { printf("App is running\n"); + + // One difference of multicore bootloader is whether it resets all the MMU. If not, it may cause the nvs fail to + // call mmap. Test code copied from examples/storage/nvs_rw_value. + + // Initialize NVS + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + // NVS partition was truncated and needs to be erased + // Retry nvs_flash_init + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + + // Open + printf("Opening Non-Volatile Storage (NVS) handle... "); + nvs_handle_t my_handle; + err = nvs_open("storage", NVS_READWRITE, &my_handle); + if (err != ESP_OK) { + printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err)); + } else { + printf("Done\n"); + + // Read + printf("Reading restart counter from NVS ... "); + int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS + err = nvs_get_i32(my_handle, "restart_counter", &restart_counter); + switch (err) { + case ESP_OK: + printf("Done\n"); + printf("Restart counter = %" PRIu32 "\n", restart_counter); + break; + case ESP_ERR_NVS_NOT_FOUND: + printf("The value is not initialized yet!\n"); + break; + default : + printf("Error (%s) reading!\n", esp_err_to_name(err)); + } + + // Write + printf("Updating restart counter in NVS ... "); + restart_counter++; + err = nvs_set_i32(my_handle, "restart_counter", restart_counter); + printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); + + // Commit written value. + // After setting any values, nvs_commit() must be called to ensure changes are written + // to flash storage. Implementations may write to storage at other times, + // but this is not guaranteed. + printf("Committing updates in NVS ... "); + err = nvs_commit(my_handle); + printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); + + // Close + nvs_close(my_handle); + } + + printf("NVS test done\n"); } diff --git a/tools/test_apps/system/unicore_bootloader/pytest_unicore_bootloader.py b/tools/test_apps/system/unicore_bootloader/pytest_unicore_bootloader.py index f0193dbe04..da16ff07db 100644 --- a/tools/test_apps/system/unicore_bootloader/pytest_unicore_bootloader.py +++ b/tools/test_apps/system/unicore_bootloader/pytest_unicore_bootloader.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import os +import re import pytest from artifacts_handler import ArtifactType @@ -12,13 +13,16 @@ from pytest_embedded import Dut @pytest.mark.esp32s3 @pytest.mark.esp32p4 @pytest.mark.generic -@pytest.mark.parametrize('config', ['multicore'], indirect=True) -def test_multicore_app_and_unicore_bootloader(dut: Dut, app_downloader) -> None: # type: ignore +@pytest.mark.parametrize('config', ['multicore', 'multicore_psram'], indirect=True) +def test_multicore_app_and_unicore_bootloader(dut: Dut, app_downloader, config) -> None: # type: ignore dut.expect('Multicore bootloader') dut.expect('Multicore app') dut.expect('App is running') - path_to_unicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_unicore') + assert 'multicore' in config + app_config = config.replace('multicore', 'unicore') + + path_to_unicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_{app_config}') if app_downloader: app_downloader.download_app( os.path.relpath(path_to_unicore_build, IDF_PATH), ArtifactType.BUILD_DIR_WITHOUT_MAP_AND_ELF_FILES @@ -27,20 +31,26 @@ def test_multicore_app_and_unicore_bootloader(dut: Dut, app_downloader) -> None: dut.serial.bootloader_flash(path_to_unicore_build) dut.expect('Unicore bootloader') dut.expect('Multicore app') + if 'psram' in config: + dut.expect(re.compile(r'Adding pool of \d+K of PSRAM memory to heap allocator')) dut.expect('App is running') + dut.expect('NVS test done\n') @pytest.mark.esp32 @pytest.mark.esp32s3 @pytest.mark.esp32p4 @pytest.mark.generic -@pytest.mark.parametrize('config', ['unicore'], indirect=True) -def test_unicore_app_and_multicore_bootloader(dut: Dut, app_downloader) -> None: # type: ignore +@pytest.mark.parametrize('config', ['unicore', 'unicore_psram'], indirect=True) +def test_unicore_app_and_multicore_bootloader(dut: Dut, app_downloader, config) -> None: # type: ignore dut.expect('Unicore bootloader') dut.expect('Unicore app') dut.expect('App is running') - path_to_multicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_multicore') + assert 'unicore' in config + app_config = config.replace('unicore', 'multicore') + + path_to_multicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_{app_config}') if app_downloader: app_downloader.download_app( os.path.relpath(path_to_multicore_build, IDF_PATH), ArtifactType.BUILD_DIR_WITHOUT_MAP_AND_ELF_FILES @@ -49,4 +59,7 @@ def test_unicore_app_and_multicore_bootloader(dut: Dut, app_downloader) -> None: dut.serial.bootloader_flash(path_to_multicore_build) dut.expect('Multicore bootloader') dut.expect('Unicore app') + if 'psram' in config: + dut.expect(re.compile(r'Adding pool of \d+K of PSRAM memory to heap allocator')) dut.expect('App is running') + dut.expect('NVS test done\n') diff --git a/tools/test_apps/system/unicore_bootloader/sdkconfig.ci.multicore_psram b/tools/test_apps/system/unicore_bootloader/sdkconfig.ci.multicore_psram new file mode 100644 index 0000000000..cc641ea603 --- /dev/null +++ b/tools/test_apps/system/unicore_bootloader/sdkconfig.ci.multicore_psram @@ -0,0 +1 @@ +CONFIG_SPIRAM=y diff --git a/tools/test_apps/system/unicore_bootloader/sdkconfig.ci.unicore_psram b/tools/test_apps/system/unicore_bootloader/sdkconfig.ci.unicore_psram new file mode 100644 index 0000000000..4bcf432a60 --- /dev/null +++ b/tools/test_apps/system/unicore_bootloader/sdkconfig.ci.unicore_psram @@ -0,0 +1,2 @@ +CONFIG_FREERTOS_UNICORE=y +CONFIG_SPIRAM=y