diff --git a/components/ulp/test_apps/ulp_riscv/main/CMakeLists.txt b/components/ulp/test_apps/ulp_riscv/main/CMakeLists.txt index 3e153055b5..3ba838bd9b 100644 --- a/components/ulp/test_apps/ulp_riscv/main/CMakeLists.txt +++ b/components/ulp/test_apps/ulp_riscv/main/CMakeLists.txt @@ -1,5 +1,7 @@ set(app_sources "test_app_main.c" "test_ulp_riscv.c") set(ulp_sources "ulp/test_main.c") +set(ulp_sources2 "ulp/test_main_second_cocpu_firmware.c") +set(ulp_sources3 "ulp/test_main_cocpu_crash.c") idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "ulp" @@ -7,5 +9,9 @@ idf_component_register(SRCS ${app_sources} WHOLE_ARCHIVE) set(ulp_app_name ulp_test_app) +set(ulp_app_name2 ulp_test_app2) +set(ulp_app_name3 ulp_test_app3) set(ulp_exp_dep_srcs ${app_sources}) ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}") +ulp_embed_binary(${ulp_app_name2} "${ulp_sources2}" "${ulp_exp_dep_srcs}") +ulp_embed_binary(${ulp_app_name3} "${ulp_sources3}" "${ulp_exp_dep_srcs}") diff --git a/components/ulp/test_apps/ulp_riscv/main/test_ulp_riscv.c b/components/ulp/test_apps/ulp_riscv/main/test_ulp_riscv.c index 3ee995e6a3..8362b777a0 100644 --- a/components/ulp/test_apps/ulp_riscv/main/test_ulp_riscv.c +++ b/components/ulp/test_apps/ulp_riscv/main/test_ulp_riscv.c @@ -14,6 +14,7 @@ #include "ulp_riscv.h" #include "ulp_riscv_lock.h" #include "ulp_test_app.h" +#include "ulp_test_app2.h" #include "ulp_test_shared.h" #include "unity.h" #include @@ -22,20 +23,28 @@ #define ULP_WAKEUP_PERIOD 1000000 // 1 second +// First ULP firmware extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_test_app_bin_start"); -extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_test_app_bin_end"); +extern const size_t ulp_main_bin_length asm("ulp_test_app_bin_length"); static bool firmware_loaded = false; -static void load_and_start_ulp_firmware(void) +// Second ULP firmware +extern const uint8_t ulp_test_app2_bin_start[] asm("_binary_ulp_test_app2_bin_start"); +extern const size_t ulp_test_app2_bin_length asm("ulp_test_app2_bin_length"); + +// Faulty ULP firmware +extern const uint8_t ulp_test_app3_bin_start[] asm("_binary_ulp_test_app3_bin_start"); +extern const size_t ulp_test_app3_bin_length asm("ulp_test_app3_bin_length"); + +static void load_and_start_ulp_firmware(const uint8_t* ulp_bin, size_t ulp_bin_len) { if (!firmware_loaded) { - TEST_ASSERT(ulp_riscv_load_binary(ulp_main_bin_start, - (ulp_main_bin_end - ulp_main_bin_start)) == ESP_OK); - + TEST_ASSERT(ulp_riscv_load_binary(ulp_bin, ulp_bin_len) == ESP_OK); TEST_ASSERT(ulp_set_wakeup_period(0, ULP_WAKEUP_PERIOD) == ESP_OK); TEST_ASSERT(ulp_riscv_run() == ESP_OK); firmware_loaded = true; + printf("New ULP firmware loaded\n"); } } @@ -45,7 +54,7 @@ TEST_CASE("ULP-RISC-V and main CPU are able to exchange data", "[ulp]") struct timeval start, end; /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ - load_and_start_ulp_firmware(); + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); /* Setup wakeup triggers */ TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK); @@ -79,7 +88,7 @@ TEST_CASE("ULP-RISC-V is able to wakeup main CPU from light sleep", "[ulp]") struct timeval start, end; /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ - load_and_start_ulp_firmware(); + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); /* Setup wakeup triggers */ TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK); @@ -119,14 +128,14 @@ TEST_CASE("ULP-RISC-V is able to wakeup main CPU from light sleep", "[ulp]") ulp_main_cpu_command = RISCV_NO_COMMAND; } -static bool ulp_riscv_is_running(void) +static bool ulp_riscv_is_running(uint32_t *counter_variable) { - uint32_t start_cnt = ulp_riscv_counter; + uint32_t start_cnt = *counter_variable; /* Wait a few ULP wakeup cycles to ensure ULP has run */ vTaskDelay((5 * ULP_WAKEUP_PERIOD / 1000) / portTICK_PERIOD_MS); - uint32_t end_cnt = ulp_riscv_counter; + uint32_t end_cnt = *counter_variable; printf("start run count: %" PRIu32 ", end run count %" PRIu32 "\n", start_cnt, end_cnt); /* If the ulp is running the counter should have been incremented */ @@ -136,20 +145,89 @@ static bool ulp_riscv_is_running(void) TEST_CASE("ULP-RISC-V can be stopped and resumed from main CPU", "[ulp]") { /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ - load_and_start_ulp_firmware(); + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); - TEST_ASSERT(ulp_riscv_is_running()); + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter)); printf("Stopping the ULP\n"); ulp_riscv_timer_stop(); ulp_riscv_halt(); - TEST_ASSERT(!ulp_riscv_is_running()); + TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter)); printf("Resuming the ULP\n"); ulp_riscv_timer_resume(); - TEST_ASSERT(ulp_riscv_is_running()); + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter)); +} + +TEST_CASE("ULP-RISC-V can be loaded with and run multiple firmwares", "[ulp]") +{ + /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); + + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter)); + + printf("Stopping the ULP\n"); + ulp_riscv_timer_stop(); + ulp_riscv_halt(); + + TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter)); + + printf("Loading second firmware on the ULP\n"); + firmware_loaded = false; + load_and_start_ulp_firmware(ulp_test_app2_bin_start, ulp_test_app2_bin_length); + + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter2)); + + printf("Stopping the ULP\n"); + ulp_riscv_timer_stop(); + ulp_riscv_halt(); + + TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter2)); + + printf("Loading the first firmware again on the ULP\n"); + firmware_loaded = false; + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); + + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter)); +} + +TEST_CASE("ULP-RISC-V can be reloaded with a good fimware after a crash", "[ulp]") +{ + /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); + + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter)); + + printf("Stopping the ULP\n"); + ulp_riscv_timer_stop(); + ulp_riscv_halt(); + + TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter)); + + /* Enable ULP wakeup */ + TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK); + + printf("Loading faulty firmware on the ULP and go into light sleep\n"); + firmware_loaded = false; + load_and_start_ulp_firmware(ulp_test_app3_bin_start, ulp_test_app3_bin_length); + esp_light_sleep_start(); + + /* Verify that main CPU wakes up by a COCPU trap signal trigger */ + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + TEST_ASSERT(cause != ESP_SLEEP_WAKEUP_COCPU); + + printf("Resetting the ULP\n"); + ulp_riscv_reset(); + + esp_rom_delay_us(20); + + printf("Loading the good firmware on ULP\n"); + firmware_loaded = false; + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); + + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter)); } TEST_CASE("ULP-RISC-V can stop itself and be resumed from the main CPU", "[ulp]") @@ -157,9 +235,9 @@ TEST_CASE("ULP-RISC-V can stop itself and be resumed from the main CPU", "[ulp]" volatile riscv_test_commands_t *command_resp = (riscv_test_commands_t*)&ulp_command_resp; /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ - load_and_start_ulp_firmware(); + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); - TEST_ASSERT(ulp_riscv_is_running()); + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter)); printf("Stopping the ULP\n"); /* Setup test data */ @@ -171,13 +249,13 @@ TEST_CASE("ULP-RISC-V can stop itself and be resumed from the main CPU", "[ulp]" /* Wait a bit to ensure ULP finished shutting down */ vTaskDelay(100 / portTICK_PERIOD_MS); - TEST_ASSERT(!ulp_riscv_is_running()); + TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter)); printf("Resuming the ULP\n"); ulp_main_cpu_command = RISCV_NO_COMMAND; ulp_riscv_timer_resume(); - TEST_ASSERT(ulp_riscv_is_running()); + TEST_ASSERT(ulp_riscv_is_running(&ulp_riscv_counter)); } @@ -185,7 +263,7 @@ TEST_CASE("ULP-RISC-V can stop itself and be resumed from the main CPU", "[ulp]" TEST_CASE("ULP-RISC-V mutex", "[ulp]") { /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ - load_and_start_ulp_firmware(); + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); /* Setup test data */ ulp_riscv_incrementer = 0; @@ -219,7 +297,7 @@ static void do_ulp_wakeup_deepsleep(riscv_test_commands_t ulp_cmd, bool rtc_peri } /* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ - load_and_start_ulp_firmware(); + load_and_start_ulp_firmware(ulp_main_bin_start, ulp_main_bin_length); /* Setup wakeup triggers */ TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK); diff --git a/components/ulp/test_apps/ulp_riscv/main/ulp/test_main_cocpu_crash.c b/components/ulp/test_apps/ulp_riscv/main/ulp/test_main_cocpu_crash.c new file mode 100644 index 0000000000..80ca7b9400 --- /dev/null +++ b/components/ulp/test_apps/ulp_riscv/main/ulp/test_main_cocpu_crash.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int main (void) +{ + /* Make sure ULP core crashes by doing a NULL pointer access */ + uint32_t *null_ptr = NULL; + *null_ptr = 1; + + /* ulp_riscv_halt() is called automatically when main exits */ + return 0; +} diff --git a/components/ulp/test_apps/ulp_riscv/main/ulp/test_main_second_cocpu_firmware.c b/components/ulp/test_apps/ulp_riscv/main/ulp/test_main_second_cocpu_firmware.c new file mode 100644 index 0000000000..80c97ff206 --- /dev/null +++ b/components/ulp/test_apps/ulp_riscv/main/ulp/test_main_second_cocpu_firmware.c @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +volatile uint32_t riscv_counter2 = 0; + +int main (void) +{ + riscv_counter2++; + + /* ulp_riscv_halt() is called automatically when main exits */ + return 0; +} diff --git a/components/ulp/ulp_riscv/include/ulp_riscv.h b/components/ulp/ulp_riscv/include/ulp_riscv.h index 994bc801a4..bf7056f7b7 100644 --- a/components/ulp/ulp_riscv/include/ulp_riscv.h +++ b/components/ulp/ulp_riscv/include/ulp_riscv.h @@ -92,6 +92,15 @@ void ulp_riscv_timer_resume(void); */ void ulp_riscv_halt(void); +/** + * @brief Resets the ULP-RISC-V core from the main CPU + * + * @note This will reset the ULP core from the main CPU. It is intended to be used when the + * ULP is in a bad state and cannot run as intended due to a corrupt firmware or any other reason. + * The main core can reset the ULP core with this API and then re-initilialize the ULP. + */ +void ulp_riscv_reset(void); + #ifdef __cplusplus } #endif diff --git a/components/ulp/ulp_riscv/ulp_riscv.c b/components/ulp/ulp_riscv/ulp_riscv.c index f18360a99b..8c6b05ce33 100644 --- a/components/ulp/ulp_riscv/ulp_riscv.c +++ b/components/ulp/ulp_riscv/ulp_riscv.c @@ -142,6 +142,15 @@ void ulp_riscv_halt(void) SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN); } +void ulp_riscv_reset() +{ + CLEAR_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT | RTC_CNTL_COCPU_DONE); + CLEAR_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN); + esp_rom_delay_us(20); + SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT | RTC_CNTL_COCPU_DONE); + SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN); +} + esp_err_t ulp_riscv_load_binary(const uint8_t* program_binary, size_t program_size_bytes) { if (program_binary == NULL) {