Merge branch 'feature/ulp_stop' into 'master'

ULP: add functions for stopping/restarting the ulp-riscv

Closes IDFGH-6588

See merge request espressif/esp-idf!16853
This commit is contained in:
Marius Vikhammer 2022-01-21 01:37:04 +00:00
commit cbe23087fc
11 changed files with 200 additions and 22 deletions

View File

@ -33,3 +33,29 @@ esp_err_t ulp_riscv_run(void);
* - ESP_ERR_INVALID_SIZE if program_size_bytes is more than 8KiB * - ESP_ERR_INVALID_SIZE if program_size_bytes is more than 8KiB
*/ */
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);
/**
* @brief Stop the ULP timer
*
* @note This will stop the ULP from waking up if halted, but will not abort any program
* currently executing on the ULP.
*/
void ulp_riscv_timer_stop(void);
/**
* @brief Resumes the ULP timer
*
* @note This will resume an already configured timer, but does no other configuration
*
*/
void ulp_riscv_timer_resume(void);
/**
* @brief Halts the program currently running on the ULP-RISC-V
*
* @note Program will restart at the next ULP timer trigger if timer is still running.
* If you want to stop the ULP from waking up then call ulp_riscv_timer_stop() first.
*/
void ulp_riscv_halt(void);

View File

@ -38,6 +38,32 @@ esp_err_t ulp_riscv_run(void);
*/ */
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);
/**
* @brief Stop the ULP timer
*
* @note This will stop the ULP from waking up if halted, but will not abort any program
* currently executing on the ULP.
*/
void ulp_riscv_timer_stop(void);
/**
* @brief Resumes the ULP timer
*
* @note This will resume an already configured timer, but does no other configuration
*
*/
void ulp_riscv_timer_resume(void);
/**
* @brief Halts the program currently running on the ULP-RISC-V
*
* @note Program will restart at the next ULP timer trigger if timer is still running.
* If you want to stop the ULP from waking up then call ulp_riscv_timer_stop() first.
*/
void ulp_riscv_halt(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -20,11 +20,14 @@
#include "ulp_test_app.h" #include "ulp_test_app.h"
#include "unity.h" #include "unity.h"
#include <sys/time.h> #include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
typedef enum{ typedef enum{
RISCV_READ_WRITE_TEST = 1, RISCV_READ_WRITE_TEST = 1,
RISCV_DEEP_SLEEP_WAKEUP_TEST, RISCV_DEEP_SLEEP_WAKEUP_TEST,
RISCV_LIGHT_SLEEP_WAKEUP_TEST, RISCV_LIGHT_SLEEP_WAKEUP_TEST,
RISCV_STOP_TEST,
RISCV_NO_COMMAND, RISCV_NO_COMMAND,
} riscv_test_commands_t; } riscv_test_commands_t;
@ -54,7 +57,7 @@ static void load_and_start_ulp_firmware(void)
} }
} }
TEST_CASE("ULP-RISC-V and main CPU are able to exchange data", "[ulp][ignore]") TEST_CASE("ULP-RISC-V and main CPU are able to exchange data", "[ulp]")
{ {
const uint32_t test_data = 0x12345678; const uint32_t test_data = 0x12345678;
struct timeval start, end; struct timeval start, end;
@ -92,7 +95,7 @@ TEST_CASE("ULP-RISC-V and main CPU are able to exchange data", "[ulp][ignore]")
ulp_main_cpu_command = RISCV_NO_COMMAND; ulp_main_cpu_command = RISCV_NO_COMMAND;
} }
TEST_CASE("ULP-RISC-V is able to wakeup main CPU from light sleep", "[ulp][ignore]") TEST_CASE("ULP-RISC-V is able to wakeup main CPU from light sleep", "[ulp]")
{ {
struct timeval start, end; struct timeval start, end;
@ -141,3 +144,64 @@ TEST_CASE("ULP-RISC-V is able to wakeup main CPU from deep sleep", "[ulp][reset=
esp_deep_sleep_start(); esp_deep_sleep_start();
UNITY_TEST_FAIL(__LINE__, "Should not get here!"); UNITY_TEST_FAIL(__LINE__, "Should not get here!");
} }
static bool ulp_riscv_is_running(void)
{
uint32_t start_cnt = ulp_riscv_counter;
/* 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;
printf("start run count: %d, end run count %d\n", start_cnt, end_cnt);
/* If the ulp is running the counter should have been incremented */
return (start_cnt != end_cnt);
}
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();
TEST_ASSERT(ulp_riscv_is_running());
printf("Stopping the ULP\n");
ulp_riscv_timer_stop();
ulp_riscv_halt();
TEST_ASSERT(!ulp_riscv_is_running());
printf("Resuming the ULP\n");
ulp_riscv_timer_resume();
TEST_ASSERT(ulp_riscv_is_running());
}
TEST_CASE("ULP-RISC-V can stop itself and be resumed from the main CPU", "[ulp]")
{
volatile riscv_test_commands_t *command_resp = &ulp_command_resp;
/* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
load_and_start_ulp_firmware();
TEST_ASSERT(ulp_riscv_is_running());
printf("Stopping the ULP\n");
/* Setup test data */
ulp_main_cpu_command = RISCV_STOP_TEST;
while (*command_resp != RISCV_STOP_TEST) {
}
/* Wait a bit to ensure ULP finished shutting down */
vTaskDelay(100 / portTICK_PERIOD_MS);
TEST_ASSERT(!ulp_riscv_is_running());
printf("Resuming the ULP\n");
ulp_main_cpu_command = RISCV_NO_COMMAND;
ulp_riscv_timer_resume();
TEST_ASSERT(ulp_riscv_is_running());
}

View File

@ -9,11 +9,13 @@
#include <stdbool.h> #include <stdbool.h>
#include "ulp_riscv/ulp_riscv.h" #include "ulp_riscv/ulp_riscv.h"
#include "ulp_riscv/ulp_riscv_utils.h" #include "ulp_riscv/ulp_riscv_utils.h"
#include "ulp_riscv/ulp_riscv_gpio.h"
typedef enum{ typedef enum{
RISCV_READ_WRITE_TEST = 1, RISCV_READ_WRITE_TEST = 1,
RISCV_DEEP_SLEEP_WAKEUP_TEST, RISCV_DEEP_SLEEP_WAKEUP_TEST,
RISCV_LIGHT_SLEEP_WAKEUP_TEST, RISCV_LIGHT_SLEEP_WAKEUP_TEST,
RISCV_STOP_TEST,
RISCV_NO_COMMAND, RISCV_NO_COMMAND,
} riscv_test_commands_t; } riscv_test_commands_t;
@ -30,9 +32,12 @@ volatile riscv_test_command_reply_t main_cpu_reply = RISCV_COMMAND_INVALID;
volatile riscv_test_commands_t command_resp = RISCV_NO_COMMAND; volatile riscv_test_commands_t command_resp = RISCV_NO_COMMAND;
volatile uint32_t riscv_test_data_in = 0; volatile uint32_t riscv_test_data_in = 0;
volatile uint32_t riscv_test_data_out = 0; volatile uint32_t riscv_test_data_out = 0;
volatile uint32_t riscv_counter = 0;
void handle_commands(riscv_test_commands_t cmd) void handle_commands(riscv_test_commands_t cmd)
{ {
riscv_counter++;
switch (cmd) { switch (cmd) {
case RISCV_READ_WRITE_TEST: case RISCV_READ_WRITE_TEST:
/* Echo the command ID back to the main CPU */ /* Echo the command ID back to the main CPU */
@ -70,6 +75,19 @@ void handle_commands(riscv_test_commands_t cmd)
ulp_riscv_wakeup_main_processor(); ulp_riscv_wakeup_main_processor();
break; break;
case RISCV_STOP_TEST:
/* Echo the command ID back to the main CPU */
command_resp = RISCV_STOP_TEST;
/* Set the command reply status */
main_cpu_reply = RISCV_COMMAND_OK;
/* Will never return from here */
ulp_riscv_timer_stop();
ulp_riscv_halt();
break;
case RISCV_NO_COMMAND: case RISCV_NO_COMMAND:
main_cpu_reply = RISCV_COMMAND_OK; main_cpu_reply = RISCV_COMMAND_OK;
break; break;
@ -87,6 +105,6 @@ int main (void)
break; break;
} }
/* ulp_riscv_shutdown() is called automatically when main exits */ /* ulp_riscv_halt() is called automatically when main exits */
return 0; return 0;
} }

View File

@ -97,6 +97,27 @@ esp_err_t ulp_riscv_run(void)
#endif #endif
} }
void ulp_riscv_timer_stop(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
}
void ulp_riscv_timer_resume(void)
{
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
}
void ulp_riscv_halt(void)
{
ulp_riscv_timer_stop();
/* suspends the ulp operation*/
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE);
/* Resets the processor */
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) {

View File

@ -43,12 +43,34 @@ void ulp_riscv_rescue_from_monitor(void);
* @note Returning from main() in the ULP program results on * @note Returning from main() in the ULP program results on
* calling this function. * calling this function.
* *
* @note To stop the ULP from waking up, call ulp_riscv_timer_stop()
* before halting.
*
* This function should be called after the ULP program Finishes * This function should be called after the ULP program Finishes
* its processing, it will trigger the timer for the next wakeup, * its processing, it will trigger the timer for the next wakeup,
* put the ULP in monitor mode and triggers a reset. * put the ULP in monitor mode and triggers a reset.
* *
*/ */
void __attribute__((noreturn)) ulp_riscv_shutdown(void); void __attribute__((noreturn)) ulp_riscv_halt(void);
#define ulp_riscv_shutdown ulp_riscv_halt
/**
* @brief Stop the ULP timer
*
* @note This will stop the ULP from waking up if halted, but will not abort any program
* currently executing on the ULP.
*/
void ulp_riscv_timer_stop(void);
/**
* @brief Resumes the ULP timer
*
* @note This will resume an already configured timer, but does no other configuration
*
*/
void ulp_riscv_timer_resume(void);
#define ULP_RISCV_GET_CCOUNT() ({ int __ccount; \ #define ULP_RISCV_GET_CCOUNT() ({ int __ccount; \
asm volatile("rdcycle %0;" : "=r"(__ccount)); \ asm volatile("rdcycle %0;" : "=r"(__ccount)); \

View File

@ -18,6 +18,6 @@ __start:
la sp, __stack_top la sp, __stack_top
call ulp_riscv_rescue_from_monitor call ulp_riscv_rescue_from_monitor
call main call main
call ulp_riscv_shutdown call ulp_riscv_halt
loop: loop:
j loop j loop

View File

@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ulp_riscv/ulp_riscv.h" #include "ulp_riscv/ulp_riscv.h"
#include "ulp_riscv/ulp_riscv_utils.h" #include "ulp_riscv/ulp_riscv_utils.h"
@ -26,7 +18,7 @@ void ulp_riscv_wakeup_main_processor(void)
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SW_CPU_INT); SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SW_CPU_INT);
} }
void ulp_riscv_shutdown(void) void ulp_riscv_halt(void)
{ {
/* Setting the delay time after RISCV recv `DONE` signal, Ensure that action `RESET` can be executed in time. */ /* Setting the delay time after RISCV recv `DONE` signal, Ensure that action `RESET` can be executed in time. */
REG_SET_FIELD(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_2_CLK_DIS, 0x3F); REG_SET_FIELD(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_2_CLK_DIS, 0x3F);
@ -48,3 +40,13 @@ void ulp_riscv_delay_cycles(uint32_t cycles)
/* Wait */ /* Wait */
} }
} }
void ulp_riscv_timer_stop(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
}
void ulp_riscv_timer_resume(void)
{
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
}

View File

@ -148,7 +148,7 @@ int main (void)
break; break;
} }
/* ulp_riscv_shutdown() is called automatically when main exits, /* ulp_riscv_halt() is called automatically when main exits,
main will be executed again at the next timeout period, main will be executed again at the next timeout period,
according to ulp_set_wakeup_period() according to ulp_set_wakeup_period()
*/ */

View File

@ -36,6 +36,6 @@ int main (void)
break; break;
} }
} }
/* ulp_riscv_shutdown() is called automatically when main exits */ /* ulp_riscv_halt() is called automatically when main exits */
return 0; return 0;
} }

View File

@ -2069,7 +2069,6 @@ components/ulp/ulp_macro.c
components/ulp/ulp_private.h components/ulp/ulp_private.h
components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv.h components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv.h
components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_register_ops.h components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_register_ops.h
components/ulp/ulp_riscv/ulp_riscv_utils.c
components/unity/include/priv/setjmp.h components/unity/include/priv/setjmp.h
components/unity/include/unity_config.h components/unity/include/unity_config.h
components/unity/include/unity_fixture_extras.h components/unity/include/unity_fixture_extras.h