Merge branch 'feature/ulp_riscv_test_multiple_firmware' into 'master'

ulp-riscv: Added API ulp_riscv_reset to reset the ULP core

See merge request espressif/esp-idf!22165
This commit is contained in:
Sudeep Mohanty 2023-02-13 15:36:10 +08:00
commit 27be8a1ebb
6 changed files with 157 additions and 20 deletions

View File

@ -1,5 +1,7 @@
set(app_sources "test_app_main.c" "test_ulp_riscv.c") set(app_sources "test_app_main.c" "test_ulp_riscv.c")
set(ulp_sources "ulp/test_main.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} idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "ulp" INCLUDE_DIRS "ulp"
@ -7,5 +9,9 @@ idf_component_register(SRCS ${app_sources}
WHOLE_ARCHIVE) WHOLE_ARCHIVE)
set(ulp_app_name ulp_test_app) 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}) set(ulp_exp_dep_srcs ${app_sources})
ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}") 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}")

View File

@ -14,6 +14,7 @@
#include "ulp_riscv.h" #include "ulp_riscv.h"
#include "ulp_riscv_lock.h" #include "ulp_riscv_lock.h"
#include "ulp_test_app.h" #include "ulp_test_app.h"
#include "ulp_test_app2.h"
#include "ulp_test_shared.h" #include "ulp_test_shared.h"
#include "unity.h" #include "unity.h"
#include <sys/time.h> #include <sys/time.h>
@ -22,20 +23,28 @@
#define ULP_WAKEUP_PERIOD 1000000 // 1 second #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_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 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) { if (!firmware_loaded) {
TEST_ASSERT(ulp_riscv_load_binary(ulp_main_bin_start, TEST_ASSERT(ulp_riscv_load_binary(ulp_bin, ulp_bin_len) == ESP_OK);
(ulp_main_bin_end - ulp_main_bin_start)) == ESP_OK);
TEST_ASSERT(ulp_set_wakeup_period(0, ULP_WAKEUP_PERIOD) == ESP_OK); TEST_ASSERT(ulp_set_wakeup_period(0, ULP_WAKEUP_PERIOD) == ESP_OK);
TEST_ASSERT(ulp_riscv_run() == ESP_OK); TEST_ASSERT(ulp_riscv_run() == ESP_OK);
firmware_loaded = true; 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; struct timeval start, end;
/* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ /* 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 */ /* Setup wakeup triggers */
TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK); 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; struct timeval start, end;
/* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ /* 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 */ /* Setup wakeup triggers */
TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK); 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; 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 */ /* Wait a few ULP wakeup cycles to ensure ULP has run */
vTaskDelay((5 * ULP_WAKEUP_PERIOD / 1000) / portTICK_PERIOD_MS); 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); 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 */ /* 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]") 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 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"); printf("Stopping the ULP\n");
ulp_riscv_timer_stop(); ulp_riscv_timer_stop();
ulp_riscv_halt(); ulp_riscv_halt();
TEST_ASSERT(!ulp_riscv_is_running()); TEST_ASSERT(!ulp_riscv_is_running(&ulp_riscv_counter));
printf("Resuming the ULP\n"); printf("Resuming the ULP\n");
ulp_riscv_timer_resume(); 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]") 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; 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 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"); printf("Stopping the ULP\n");
/* Setup test data */ /* 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 */ /* Wait a bit to ensure ULP finished shutting down */
vTaskDelay(100 / portTICK_PERIOD_MS); 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"); printf("Resuming the ULP\n");
ulp_main_cpu_command = RISCV_NO_COMMAND; ulp_main_cpu_command = RISCV_NO_COMMAND;
ulp_riscv_timer_resume(); 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]") TEST_CASE("ULP-RISC-V mutex", "[ulp]")
{ {
/* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */ /* 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 */ /* Setup test data */
ulp_riscv_incrementer = 0; 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 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 */ /* Setup wakeup triggers */
TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK); TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK);

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdint.h>
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;
}

View File

@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
volatile uint32_t riscv_counter2 = 0;
int main (void)
{
riscv_counter2++;
/* ulp_riscv_halt() is called automatically when main exits */
return 0;
}

View File

@ -92,6 +92,15 @@ void ulp_riscv_timer_resume(void);
*/ */
void ulp_riscv_halt(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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -142,6 +142,15 @@ void ulp_riscv_halt(void)
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN); 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) esp_err_t ulp_riscv_load_binary(const uint8_t* program_binary, size_t program_size_bytes)
{ {
if (program_binary == NULL) { if (program_binary == NULL) {