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_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);
/**
* @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
}
#endif

View File

@ -20,11 +20,14 @@
#include "ulp_test_app.h"
#include "unity.h"
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
typedef enum{
RISCV_READ_WRITE_TEST = 1,
RISCV_DEEP_SLEEP_WAKEUP_TEST,
RISCV_LIGHT_SLEEP_WAKEUP_TEST,
RISCV_STOP_TEST,
RISCV_NO_COMMAND,
} 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;
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;
}
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;
@ -141,3 +144,64 @@ TEST_CASE("ULP-RISC-V is able to wakeup main CPU from deep sleep", "[ulp][reset=
esp_deep_sleep_start();
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 "ulp_riscv/ulp_riscv.h"
#include "ulp_riscv/ulp_riscv_utils.h"
#include "ulp_riscv/ulp_riscv_gpio.h"
typedef enum{
RISCV_READ_WRITE_TEST = 1,
RISCV_DEEP_SLEEP_WAKEUP_TEST,
RISCV_LIGHT_SLEEP_WAKEUP_TEST,
RISCV_STOP_TEST,
RISCV_NO_COMMAND,
} 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 uint32_t riscv_test_data_in = 0;
volatile uint32_t riscv_test_data_out = 0;
volatile uint32_t riscv_counter = 0;
void handle_commands(riscv_test_commands_t cmd)
{
riscv_counter++;
switch (cmd) {
case RISCV_READ_WRITE_TEST:
/* 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();
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:
main_cpu_reply = RISCV_COMMAND_OK;
break;
@ -87,6 +105,6 @@ int main (void)
break;
}
/* ulp_riscv_shutdown() is called automatically when main exits */
/* ulp_riscv_halt() is called automatically when main exits */
return 0;
}

View File

@ -97,6 +97,27 @@ esp_err_t ulp_riscv_run(void)
#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)
{
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
* 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
* its processing, it will trigger the timer for the next wakeup,
* 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; \
asm volatile("rdcycle %0;" : "=r"(__ccount)); \

View File

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

View File

@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// 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.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ulp_riscv/ulp_riscv.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);
}
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. */
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 */
}
}
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;
}
/* 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,
according to ulp_set_wakeup_period()
*/

View File

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

View File

@ -2069,7 +2069,6 @@ components/ulp/ulp_macro.c
components/ulp/ulp_private.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/ulp_riscv_utils.c
components/unity/include/priv/setjmp.h
components/unity/include/unity_config.h
components/unity/include/unity_fixture_extras.h