From 3cc399f3990f8fda008f991696fbbf4c6c40fd1c Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Mon, 30 Jan 2023 15:53:39 +0100 Subject: [PATCH] ulp-riscv: Added API ulp_riscv_reset to reset the ULP core This commit adds a new API ulp_reisv_reset() to enable reseting of the ULP core from the main core. This is particularly necessary in case the ULP crashes due to any reason. Earlier the only way to recover the ULP was to do a power reset. This commit also adds new test cases which exercise this scenario. --- .../test_apps/ulp_riscv/main/CMakeLists.txt | 6 + .../test_apps/ulp_riscv/main/test_ulp_riscv.c | 118 +++++++++++++++--- .../main/ulp/test_main_cocpu_crash.c | 18 +++ .../ulp/test_main_second_cocpu_firmware.c | 17 +++ components/ulp/ulp_riscv/include/ulp_riscv.h | 9 ++ components/ulp/ulp_riscv/ulp_riscv.c | 9 ++ 6 files changed, 157 insertions(+), 20 deletions(-) create mode 100644 components/ulp/test_apps/ulp_riscv/main/ulp/test_main_cocpu_crash.c create mode 100644 components/ulp/test_apps/ulp_riscv/main/ulp/test_main_second_cocpu_firmware.c 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) {