Skip to content

Commit

Permalink
ulp-riscv: Added API ulp_riscv_reset to reset the ULP core
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sudeep-mohanty authored and espressif-bot committed Feb 8, 2023
1 parent 080fd7e commit 3cc399f
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 20 deletions.
6 changes: 6 additions & 0 deletions components/ulp/test_apps/ulp_riscv/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
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"
REQUIRES ulp unity
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}")
118 changes: 98 additions & 20 deletions components/ulp/test_apps/ulp_riscv/main/test_ulp_riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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");
}
}

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand All @@ -136,30 +145,99 @@ 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]")
{
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 */
Expand All @@ -171,21 +249,21 @@ 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));
}



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;
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
9 changes: 9 additions & 0 deletions components/ulp/ulp_riscv/include/ulp_riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions components/ulp/ulp_riscv/ulp_riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 3cc399f

Please sign in to comment.