Просмотр исходного кода

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
Marius Vikhammer 4 лет назад
Родитель
Сommit
cbe23087fc

+ 26 - 0
components/ulp/include/esp32s2/ulp_riscv.h

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

+ 26 - 0
components/ulp/include/esp32s3/ulp_riscv.h

@@ -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

+ 66 - 2
components/ulp/test/ulp_riscv/test_ulp_riscv_main.c

@@ -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());
+}

+ 19 - 1
components/ulp/test/ulp_riscv/ulp/test_main.c

@@ -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;
 }

+ 21 - 0
components/ulp/ulp_riscv.c

@@ -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) {

+ 23 - 1
components/ulp/ulp_riscv/include/ulp_riscv/ulp_riscv_utils.h

@@ -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)); \

+ 1 - 1
components/ulp/ulp_riscv/start.S

@@ -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

+ 16 - 14
components/ulp/ulp_riscv/ulp_riscv_utils.c

@@ -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);
+}

+ 1 - 1
examples/system/ulp_riscv/ds18b20_onewire/main/ulp/main.c

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

+ 1 - 1
examples/system/ulp_riscv/gpio/main/ulp/main.c

@@ -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;
 }

+ 0 - 1
tools/ci/check_copyright_ignore.txt

@@ -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