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.
This commit is contained in:
Sudeep Mohanty
2023-01-30 15:53:39 +01:00
committed by BOT
parent 080fd7e14f
commit 3cc399f399
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(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}")

View File

@@ -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 <sys/time.h>
@@ -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);

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);
/**
* @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

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);
}
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) {