فهرست منبع

ulp: added basic support for building and running a binary in the lp core

Marius Vikhammer 2 سال پیش
والد
کامیت
284dabf17f
33فایلهای تغییر یافته به همراه517 افزوده شده و 23 حذف شده
  1. 3 1
      components/esp_hw_support/sleep_modes.c
  2. 0 5
      components/esp_system/ld/esp32h2/memory.ld.in
  3. 4 0
      components/soc/esp32/include/soc/Kconfig.soc_caps.in
  4. 1 0
      components/soc/esp32/include/soc/soc_caps.h
  5. 4 0
      components/soc/esp32c6/include/soc/Kconfig.soc_caps.in
  6. 1 1
      components/soc/esp32c6/include/soc/soc_caps.h
  7. 0 1
      components/soc/esp32h2/include/soc/soc_caps.h
  8. 4 0
      components/soc/esp32s2/include/soc/Kconfig.soc_caps.in
  9. 1 0
      components/soc/esp32s2/include/soc/soc_caps.h
  10. 4 0
      components/soc/esp32s3/include/soc/Kconfig.soc_caps.in
  11. 1 0
      components/soc/esp32s3/include/soc/soc_caps.h
  12. 3 0
      components/ulp/.build-test-rules.yml
  13. 12 0
      components/ulp/CMakeLists.txt
  14. 9 6
      components/ulp/Kconfig
  15. 22 5
      components/ulp/cmake/CMakeLists.txt
  16. 15 0
      components/ulp/cmake/toolchain-lp-core-riscv.cmake
  17. 0 4
      components/ulp/component_ulp_common.cmake
  18. 59 0
      components/ulp/ld/lp_core_riscv.ld
  19. 53 0
      components/ulp/lp_core/include/ulp_lp_core.h
  20. 51 0
      components/ulp/lp_core/lp_core.c
  21. 12 0
      components/ulp/lp_core/lp_core/lp_core_startup.c
  22. 20 0
      components/ulp/lp_core/lp_core/start.S
  23. 4 0
      components/ulp/project_include.cmake
  24. 8 0
      components/ulp/test_apps/lp_core/CMakeLists.txt
  25. 3 0
      components/ulp/test_apps/lp_core/README.md
  26. 11 0
      components/ulp/test_apps/lp_core/main/CMakeLists.txt
  27. 55 0
      components/ulp/test_apps/lp_core/main/lp_core/test_main.c
  28. 19 0
      components/ulp/test_apps/lp_core/main/lp_core/test_shared.h
  29. 41 0
      components/ulp/test_apps/lp_core/main/test_app_main.c
  30. 62 0
      components/ulp/test_apps/lp_core/main/test_lp_core.c
  31. 11 0
      components/ulp/test_apps/lp_core/pytest_lp_core.py
  32. 5 0
      components/ulp/test_apps/lp_core/sdkconfig.defaults
  33. 19 0
      components/ulp/ulp_common/include/esp32c6/ulp_common_defs.h

+ 3 - 1
components/esp_hw_support/sleep_modes.c

@@ -483,6 +483,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo
     }
 #endif
 
+#if !CONFIG_IDF_TARGET_ESP32C6 // TODO IDF-7012 Add sleep support for lp core
 #if CONFIG_ULP_COPROC_ENABLED
     // Enable ULP wakeup
     if (s_config.wakeup_triggers & RTC_ULP_TRIG_EN) {
@@ -493,6 +494,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo
 #endif
     }
 #endif
+#endif //!CONFIG_IDF_TARGET_ESP32C6
 
     if (!deep_sleep) {
         misc_modules_sleep_prepare();
@@ -1000,7 +1002,7 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source)
     } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_UART, (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN))) {
         s_config.wakeup_triggers &= ~(RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN);
     }
-#if CONFIG_ULP_COPROC_ENABLED
+#if CONFIG_ULP_COPROC_ENABLED && !CONFIG_IDF_TARGET_ESP32C6 // TODO IDF-7012 Add sleep support for lp core
     else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_ULP, RTC_ULP_TRIG_EN)) {
         s_config.wakeup_triggers &= ~RTC_ULP_TRIG_EN;
     }

+ 0 - 5
components/esp_system/ld/esp32h2/memory.ld.in

@@ -91,12 +91,7 @@ MEMORY
   /**
    * lp ram memory (RWX). Persists over deep sleep. // ESP32H2-TODO IDF-6272
    */
-#if CONFIG_ULP_COPROC_ENABLED
-  lp_ram_seg(RW)  :                 org = 0x50000000 + CONFIG_ULP_COPROC_RESERVE_MEM,
-                                    len = 0x1000 - CONFIG_ULP_COPROC_RESERVE_MEM
-#else
   lp_ram_seg(RW)  :                org = 0x50000000 , len = 0x1000
-#endif // CONFIG_ULP_COPROC_ENABLED
 
 }
 

+ 4 - 0
components/soc/esp32/include/soc/Kconfig.soc_caps.in

@@ -143,6 +143,10 @@ config SOC_BOD_SUPPORTED
     bool
     default y
 
+config SOC_ULP_FSM_SUPPORTED
+    bool
+    default y
+
 config SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL
     int
     default 5

+ 1 - 0
components/soc/esp32/include/soc/soc_caps.h

@@ -95,6 +95,7 @@
 #define SOC_SECURE_BOOT_SUPPORTED   1
 #define SOC_TOUCH_SENSOR_SUPPORTED  1
 #define SOC_BOD_SUPPORTED           1
+#define SOC_ULP_FSM_SUPPORTED       1
 
 #if SOC_CAPS_ECO_VER < 200
 #define SOC_DPORT_WORKAROUND                   1

+ 4 - 0
components/soc/esp32c6/include/soc/Kconfig.soc_caps.in

@@ -71,6 +71,10 @@ config SOC_SUPPORTS_SECURE_DL_MODE
     bool
     default y
 
+config SOC_LP_CORE_SUPPORTED
+    bool
+    default y
+
 config SOC_EFUSE_KEY_PURPOSE_FIELD
     bool
     default y

+ 1 - 1
components/soc/esp32c6/include/soc/soc_caps.h

@@ -42,7 +42,7 @@
 #define SOC_TEMP_SENSOR_SUPPORTED       1
 #define SOC_WIFI_SUPPORTED              1
 #define SOC_SUPPORTS_SECURE_DL_MODE     1
-//#define SOC_RISCV_COPROC_SUPPORTED       1 // TODO: IDF-5816
+#define SOC_LP_CORE_SUPPORTED           1
 #define SOC_EFUSE_KEY_PURPOSE_FIELD     1
 #define SOC_RTC_FAST_MEM_SUPPORTED      1
 #define SOC_RTC_MEM_SUPPORTED           1

+ 0 - 1
components/soc/esp32h2/include/soc/soc_caps.h

@@ -40,7 +40,6 @@
 #define SOC_USB_SERIAL_JTAG_SUPPORTED   1
 #define SOC_TEMP_SENSOR_SUPPORTED       1
 #define SOC_SUPPORTS_SECURE_DL_MODE     1
-//#define SOC_RISCV_COPROC_SUPPORTED       1 // TODO: IDF-6272
 #define SOC_EFUSE_KEY_PURPOSE_FIELD     1
 #define SOC_RTC_FAST_MEM_SUPPORTED      1
 #define SOC_RTC_MEM_SUPPORTED           1

+ 4 - 0
components/soc/esp32s2/include/soc/Kconfig.soc_caps.in

@@ -35,6 +35,10 @@ config SOC_SUPPORTS_SECURE_DL_MODE
     bool
     default y
 
+config SOC_ULP_FSM_SUPPORTED
+    bool
+    default y
+
 config SOC_RISCV_COPROC_SUPPORTED
     bool
     default y

+ 1 - 0
components/soc/esp32s2/include/soc/soc_caps.h

@@ -47,6 +47,7 @@
 #define SOC_DEDICATED_GPIO_SUPPORTED    1
 #define SOC_GPTIMER_SUPPORTED           1
 #define SOC_SUPPORTS_SECURE_DL_MODE     1
+#define SOC_ULP_FSM_SUPPORTED           1
 #define SOC_RISCV_COPROC_SUPPORTED      1
 #define SOC_USB_OTG_SUPPORTED           1
 #define SOC_PCNT_SUPPORTED              1

+ 4 - 0
components/soc/esp32s3/include/soc/Kconfig.soc_caps.in

@@ -71,6 +71,10 @@ config SOC_ULP_SUPPORTED
     bool
     default y
 
+config SOC_ULP_FSM_SUPPORTED
+    bool
+    default y
+
 config SOC_RISCV_COPROC_SUPPORTED
     bool
     default y

+ 1 - 0
components/soc/esp32s3/include/soc/soc_caps.h

@@ -37,6 +37,7 @@
 #define SOC_DEDICATED_GPIO_SUPPORTED    1
 #define SOC_CACHE_SUPPORT_WRAP          1
 #define SOC_ULP_SUPPORTED               1
+#define SOC_ULP_FSM_SUPPORTED           1
 #define SOC_RISCV_COPROC_SUPPORTED      1
 #define SOC_BT_SUPPORTED                1
 #define SOC_USB_OTG_SUPPORTED           1

+ 3 - 0
components/ulp/.build-test-rules.yml

@@ -1,5 +1,8 @@
 # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
 
+components/ulp/test_apps/lp_core:
+  disable:
+    - if: SOC_LP_CORE_SUPPORTED != 1
 components/ulp/test_apps/ulp_fsm:
   enable:
     - if: SOC_ULP_SUPPORTED == 1

+ 12 - 0
components/ulp/CMakeLists.txt

@@ -34,6 +34,18 @@ if(CONFIG_SOC_ULP_SUPPORTED OR CONFIG_SOC_RISCV_COPROC_SUPPORTED)
     endif()
 endif()
 
+if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
+   list(APPEND includes
+        ulp_common/include
+        ulp_common/include/${target})
+
+    list(APPEND srcs
+        "lp_core/lp_core.c")
+
+    list(APPEND includes
+        "lp_core/include")
+endif()
+
 idf_component_register(SRCS ${srcs}
                        INCLUDE_DIRS ${includes}
                        REQUIRES driver esp_adc)

+ 9 - 6
components/ulp/Kconfig

@@ -1,5 +1,5 @@
 menu "Ultra Low Power (ULP) Co-processor"
-    depends on (SOC_ULP_SUPPORTED || SOC_RISCV_COPROC_SUPPORTED)
+    depends on (SOC_ULP_SUPPORTED || SOC_RISCV_COPROC_SUPPORTED || SOC_LP_CORE_SUPPORTED)
 
     config ULP_COPROC_ENABLED
         bool "Enable Ultra Low Power (ULP) Co-processor"
@@ -11,17 +11,19 @@ menu "Ultra Low Power (ULP) Co-processor"
     choice ULP_COPROC_TYPE
         prompt "ULP Co-processor type"
         depends on ULP_COPROC_ENABLED
-        default ULP_COPROC_TYPE_FSM if IDF_TARGET_ESP32
         default ULP_COPROC_TYPE_RISCV if (IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3)
         help
             Choose the ULP Coprocessor type: ULP FSM (Finite State Machine) or ULP RISC-V.
-            Please note that ESP32 only supports ULP FSM.
 
         config ULP_COPROC_TYPE_FSM
             bool "ULP FSM (Finite State Machine)"
+            depends on SOC_ULP_FSM_SUPPORTED
         config ULP_COPROC_TYPE_RISCV
             bool "ULP RISC-V"
-            depends on !IDF_TARGET_ESP32
+            depends on SOC_RISCV_COPROC_SUPPORTED
+        config ULP_COPROC_TYPE_LP_CORE
+            bool "LP core RISC-V"
+            depends on SOC_LP_CORE_SUPPORTED
     endchoice
 
     config ULP_COPROC_RESERVE_MEM
@@ -29,8 +31,9 @@ menu "Ultra Low Power (ULP) Co-processor"
         prompt "RTC slow memory reserved for coprocessor"
         depends on ULP_COPROC_ENABLED
         default 512 if IDF_TARGET_ESP32
-        default 4096 if (IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3)
-        range 32 8176
+        default 4096 if !IDF_TARGET_ESP32
+        range 32 8176 if !IDF_TARGET_ESP32C6
+        range 32 16352 if IDF_TARGET_ESP32C6
         help
             Bytes of memory to reserve for ULP Co-processor firmware & data.
             Data is reserved at the beginning of RTC slow memory.

+ 22 - 5
components/ulp/cmake/CMakeLists.txt

@@ -6,11 +6,12 @@ add_executable(${ULP_APP_NAME})
 set(CMAKE_EXECUTABLE_SUFFIX ".elf")
 
 option(ULP_COCPU_IS_RISCV "Use RISC-V based ULP" OFF)
+option(ULP_COCPU_IS_LP_CORE "Use RISC-V based LP Core" OFF)
 
 message(STATUS "Building ULP app ${ULP_APP_NAME}")
 
 # Check the supported assembler version
-if(NOT ULP_COCPU_IS_RISCV)
+if(NOT (ULP_COCPU_IS_RISCV OR ULP_COCPU_IS_LP_CORE))
     check_expected_tool_version("esp32ulp-elf" ${CMAKE_ASM_COMPILER})
 endif()
 
@@ -33,9 +34,12 @@ list(APPEND ULP_PREPROCESSOR_ARGS -D__ASSEMBLER__)
 # Pre-process the linker script
 if(ULP_COCPU_IS_RISCV)
     set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/ulp_riscv.ld)
+elseif(ULP_COCPU_IS_LP_CORE)
+    set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/lp_core_riscv.ld)
 else()
     set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/ulp_fsm.ld)
 endif()
+
 get_filename_component(ULP_LD_SCRIPT ${ULP_LD_TEMPLATE} NAME)
 add_custom_command(OUTPUT ${ULP_LD_SCRIPT}
                    COMMAND ${CMAKE_C_COMPILER} -E -P -xc -o ${ULP_LD_SCRIPT} ${ULP_PREPROCESSOR_ARGS} ${ULP_LD_TEMPLATE}
@@ -72,8 +76,19 @@ if(ULP_COCPU_IS_RISCV)
     target_link_options(${ULP_APP_NAME} PRIVATE "-Wl,--no-warn-rwx-segments")
     target_compile_definitions(${ULP_APP_NAME} PRIVATE IS_ULP_COCPU)
 
-else()
+elseif(ULP_COCPU_IS_LP_CORE)
+    list(APPEND ULP_S_SOURCES
+    "${IDF_PATH}/components/ulp/lp_core/lp_core/start.S"
+    "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_startup.c")
+
+    target_link_options(${ULP_APP_NAME} PRIVATE "-nostartfiles")
+    target_link_options(${ULP_APP_NAME} PRIVATE "-Wl,--no-warn-rwx-segments")
+    target_link_options(${ULP_APP_NAME} PRIVATE -Wl,--gc-sections)
+    target_link_options(${ULP_APP_NAME} PRIVATE -Wl,-Map=${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}.map)
+    target_sources(${ULP_APP_NAME} PRIVATE ${ULP_S_SOURCES})
+    target_include_directories(${ULP_APP_NAME} PRIVATE "${IDF_PATH}/components/ulp/lp_core/lp_core/include")
 
+else()
     foreach(ulp_s_source ${ULP_S_SOURCES})
         get_filename_component(ulp_ps_source ${ulp_s_source} NAME_WE)
         set(ulp_ps_output ${CMAKE_CURRENT_BINARY_DIR}/${ulp_ps_source}.ulp.S)
@@ -96,9 +111,11 @@ else()
 
 endif()
 
-# Currently all the supported targets have the same base address of the ULP memory in the CPU address space.
-# Modify this or pull this out of some SoC header file, if that becomes necessary.
-set(ULP_BASE_ADDR "0x50000000")
+if(ULP_COCPU_IS_LP_CORE)
+    set(ULP_BASE_ADDR "0x0")
+else()
+    set(ULP_BASE_ADDR "0x50000000")
+endif()
 
 # Dump the list of global symbols in a convenient format
 add_custom_command(OUTPUT ${ULP_APP_NAME}.sym

+ 15 - 0
components/ulp/cmake/toolchain-lp-core-riscv.cmake

@@ -0,0 +1,15 @@
+# CMake toolchain file for ULP LP core
+set(CMAKE_SYSTEM_NAME Generic)
+
+set(CMAKE_C_COMPILER "riscv32-esp-elf-gcc")
+set(CMAKE_CXX_COMPILER "riscv32-esp-elf-g++")
+set(CMAKE_ASM_COMPILER "riscv32-esp-elf-gcc")
+
+set(CMAKE_C_FLAGS "-Os -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections"
+    CACHE STRING "C Compiler Base Flags")
+set(CMAKE_CXX_FLAGS "-Os -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections"
+    CACHE STRING "C++ Compiler Base Flags")
+set(CMAKE_ASM_FLAGS "-march=rv32imac -x assembler-with-cpp"
+    CACHE STRING "Assembler Base Flags")
+set(CMAKE_EXE_LINKER_FLAGS "-march=rv32imac_zicsr_zifencei --specs=nano.specs --specs=nosys.specs"
+    CACHE STRING "Linker Base Flags")

+ 0 - 4
components/ulp/component_ulp_common.cmake

@@ -1,7 +1,3 @@
-message(WARNING "Embedding ULP binary by including \
-${IDF_PATH}/components/ulp/component_ulp_common.cmake is deprecated. Use `ulp_embed_binary` instead. \
-See API Guide for more details.")
-
 spaces2list(ULP_S_SOURCES)
 spaces2list(ULP_EXP_DEP_SRCS)
 

+ 59 - 0
components/ulp/ld/lp_core_riscv.ld

@@ -0,0 +1,59 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "sdkconfig.h"
+
+ENTRY(reset_vector)
+
+MEMORY
+{
+    /*first 128byte for exception/interrupt vectors*/
+    vector_table(RX) :   ORIGIN = 0x50000000, LENGTH = 0x80
+    ram(RWX) :           ORIGIN = 0x50000080, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM - 0x80
+}
+
+SECTIONS
+{
+    .vector.text :
+    {
+        /*exception/interrupt vectors*/
+        __mtvec_base = .;
+        KEEP (*(.init.vector .init.vector.*))
+    } > vector_table
+
+    . = ORIGIN(ram);
+
+    .text ALIGN(4):
+    {
+        *(.text.vectors) /* Default reset vector must link to offset 0x80 */
+        *(.text)
+        *(.text*)
+    } >ram
+
+    .rodata ALIGN(4):
+    {
+        *(.rodata)
+        *(.rodata*)
+    } > ram
+
+    .data ALIGN(4):
+    {
+        *(.data)
+        *(.data*)
+        *(.sdata)
+        *(.sdata*)
+    } > ram
+
+    .bss ALIGN(4) :
+    {
+        *(.bss)
+        *(.bss*)
+        *(.sbss)
+        *(.sbss*)
+        PROVIDE(end = .);
+    } >ram
+
+    __stack_top = ORIGIN(ram) + LENGTH(ram);
+}

+ 53 - 0
components/ulp/lp_core/include/ulp_lp_core.h

@@ -0,0 +1,53 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "esp_err.h"
+#include "ulp_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef enum {
+    ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,  // LP core is started by HP core (1 single wakeup)
+} ulp_lp_core_wakeup_source_t;
+
+/**
+ * @brief ULP LP core init parameters
+ *
+ */
+typedef struct {
+    ulp_lp_core_wakeup_source_t wakeup_source;
+} ulp_lp_core_cfg_t;
+
+/**
+ * @brief Configure the ULP
+ *        and run the program loaded into RTC memory
+ *
+ * @return  ESP_OK on success
+ */
+esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg);
+
+/**
+ * @brief Load the program binary into RTC memory
+ *
+ * @param program_binary pointer to program binary
+ * @param program_size_bytes size of the program binary
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_ERR_INVALID_SIZE if program_size_bytes is more than KiB
+ */
+esp_err_t ulp_lp_core_load_binary(const uint8_t* program_binary, size_t program_size_bytes);
+
+
+#ifdef __cplusplus
+}
+#endif

+ 51 - 0
components/ulp/lp_core/lp_core.c

@@ -0,0 +1,51 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "sdkconfig.h"
+#include "esp_log.h"
+#include "soc/pmu_reg.h"
+#include "soc/lpperi_reg.h"
+#include "hal/misc.h"
+#include "ulp_common.h"
+#include "ulp_lp_core.h"
+
+
+const static char* TAG = "ulp-lp-core";
+
+
+esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg)
+{
+
+    REG_SET_FIELD(PMU_LP_CPU_PWR1_REG, PMU_LP_CPU_WAKEUP_EN, 1);
+
+    switch(cfg->wakeup_source) {
+        case ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU:
+            REG_SET_FIELD(PMU_HP_LP_CPU_COMM_REG, PMU_HP_TRIGGER_LP, 1);
+            break;
+        default:
+            ESP_LOGE(TAG, "No valid wakeup source specified");
+            break;
+        }
+    return ESP_OK;
+}
+
+esp_err_t ulp_lp_core_load_binary(const uint8_t* program_binary, size_t program_size_bytes)
+{
+    if (program_binary == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (program_size_bytes > CONFIG_ULP_COPROC_RESERVE_MEM) {
+        return ESP_ERR_INVALID_SIZE;
+    }
+
+    uint8_t* base = (uint8_t*) RTC_SLOW_MEM;
+
+    //Start by clearing memory reserved with zeros, this will also will initialize the bss:
+    hal_memset(base, 0, CONFIG_ULP_COPROC_RESERVE_MEM);
+    hal_memcpy(base, program_binary, program_size_bytes);
+
+    return ESP_OK;
+}

+ 12 - 0
components/ulp/lp_core/lp_core/lp_core_startup.c

@@ -0,0 +1,12 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+extern void main();
+
+/* Initialize lp core related system functions before calling user's main*/
+void lp_core_startup()
+{
+    main();
+}

+ 20 - 0
components/ulp/lp_core/lp_core/start.S

@@ -0,0 +1,20 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+	.section .text.vectors
+	.global reset_vector
+
+/* The reset vector, jumps to startup code */
+reset_vector:
+	j __start
+
+__start:
+
+	/* setup the stack pointer */
+	la sp, __stack_top
+	call lp_core_startup
+loop:
+	j loop

+ 4 - 0
components/ulp/project_include.cmake

@@ -46,6 +46,9 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs)
                 set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-${idf_target}-ulp.cmake)
                 set(ULP_IS_RISCV OFF)
             endif()
+        elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE)
+                set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-lp-core-riscv.cmake)
+                set(ULP_IS_LP_CORE_RISCV ON)
         endif()
 
         externalproject_add(${app_name}
@@ -63,6 +66,7 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs)
                             -DSDKCONFIG_HEADER=${SDKCONFIG_HEADER}
                             -DPYTHON=${python}
                             -DULP_COCPU_IS_RISCV=${ULP_IS_RISCV}
+                            -DULP_COCPU_IS_LP_CORE=${ULP_IS_LP_CORE_RISCV}
                             ${extra_cmake_args}
                 BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/${app_name} --target build
                 BUILD_BYPRODUCTS ${ulp_artifacts} ${ulp_artifacts_extras} ${ulp_ps_sources}

+ 8 - 0
components/ulp/test_apps/lp_core/CMakeLists.txt

@@ -0,0 +1,8 @@
+# This is the project CMakeLists.txt file for the test subproject
+cmake_minimum_required(VERSION 3.16)
+
+set(SDKCONFIG_DEFAULTS "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers")
+list(APPEND SDKCONFIG_DEFAULTS "sdkconfig.defaults")
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(lp_core_test)

+ 3 - 0
components/ulp/test_apps/lp_core/README.md

@@ -0,0 +1,3 @@
+| Supported Targets | ESP32-C6 |
+| ----------------- | -------- |
+

+ 11 - 0
components/ulp/test_apps/lp_core/main/CMakeLists.txt

@@ -0,0 +1,11 @@
+set(app_sources "test_app_main.c" "test_lp_core.c")
+set(lp_core_sources "lp_core/test_main.c")
+
+idf_component_register(SRCS ${app_sources}
+                       INCLUDE_DIRS "lp_core"
+                       REQUIRES ulp unity
+                       WHOLE_ARCHIVE)
+
+set(lp_core_app_name lp_core_test_app)
+set(lp_core_exp_dep_srcs ${app_sources})
+ulp_embed_binary(${lp_core_app_name} "${lp_core_sources}" "${lp_core_exp_dep_srcs}")

+ 55 - 0
components/ulp/test_apps/lp_core/main/lp_core/test_main.c

@@ -0,0 +1,55 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "test_shared.h"
+
+
+volatile lp_core_test_commands_t main_cpu_command = LP_CORE_NO_COMMAND;
+volatile lp_core_test_command_reply_t main_cpu_reply = LP_CORE_COMMAND_INVALID;
+volatile lp_core_test_commands_t command_resp = LP_CORE_NO_COMMAND;
+volatile uint32_t test_data_in = 0;
+volatile uint32_t test_data_out = 0;
+volatile uint32_t counter = 0;
+
+volatile uint32_t incrementer = 0;
+
+void handle_commands(lp_core_test_commands_t cmd)
+{
+    counter++;
+
+    switch (cmd) {
+        case LP_CORE_READ_WRITE_TEST:
+            /* Echo the command ID back to the main CPU */
+            command_resp = LP_CORE_READ_WRITE_TEST;
+
+            /* Process test data */
+            test_data_out = test_data_in ^ XOR_MASK;
+
+            /* Set the command reply status */
+            main_cpu_reply = LP_CORE_COMMAND_OK;
+            break;
+
+        case LP_CORE_NO_COMMAND:
+            main_cpu_reply = LP_CORE_COMMAND_OK;
+            break;
+
+        default:
+            main_cpu_reply = LP_CORE_COMMAND_NOK;
+            break;
+    }
+}
+
+int main (void)
+{
+    while (1) {
+        handle_commands(main_cpu_command);
+    }
+
+    return 0;
+}

+ 19 - 0
components/ulp/test_apps/lp_core/main/lp_core/test_shared.h

@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+#pragma once
+
+#define XOR_MASK 0xDEADBEEF
+
+typedef enum{
+    LP_CORE_READ_WRITE_TEST = 1,
+    LP_CORE_NO_COMMAND,
+} lp_core_test_commands_t;
+
+typedef enum {
+    LP_CORE_COMMAND_OK = 1,
+    LP_CORE_COMMAND_NOK,
+    LP_CORE_COMMAND_INVALID,
+} lp_core_test_command_reply_t;

+ 41 - 0
components/ulp/test_apps/lp_core/main/test_app_main.c

@@ -0,0 +1,41 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "unity.h"
+#include "unity_test_runner.h"
+#include "esp_heap_caps.h"
+
+// Some resources are lazy allocated in the sleep code, the threshold is left for that case
+#define TEST_MEMORY_LEAK_THRESHOLD (-500)
+
+static size_t before_free_8bit;
+static size_t before_free_32bit;
+
+static void check_leak(size_t before_free, size_t after_free, const char *type)
+{
+    ssize_t delta = after_free - before_free;
+    printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
+    TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
+}
+
+void setUp(void)
+{
+    before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
+    before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
+}
+
+void tearDown(void)
+{
+    size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
+    size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
+    check_leak(before_free_8bit, after_free_8bit, "8BIT");
+    check_leak(before_free_32bit, after_free_32bit, "32BIT");
+}
+
+void app_main(void)
+{
+    unity_run_menu();
+}

+ 62 - 0
components/ulp/test_apps/lp_core/main/test_lp_core.c

@@ -0,0 +1,62 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include "lp_core_test_app.h"
+#include "ulp_lp_core.h"
+#include "test_shared.h"
+#include "unity.h"
+
+extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_test_app_bin_start");
+extern const uint8_t lp_core_main_bin_end[]   asm("_binary_lp_core_test_app_bin_end");
+static bool  firmware_loaded = false;
+
+static void load_and_start_lp_core_firmware(void)
+{
+    if (!firmware_loaded) {
+
+        ulp_lp_core_cfg_t cfg = {
+            .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,
+        };
+
+        TEST_ASSERT(ulp_lp_core_load_binary(lp_core_main_bin_start,
+                            (lp_core_main_bin_end - lp_core_main_bin_start)) == ESP_OK);
+
+        TEST_ASSERT(ulp_lp_core_run(&cfg) == ESP_OK);
+
+        firmware_loaded = true;
+    }
+}
+
+TEST_CASE("LP core and main CPU are able to exchange data", "[lp_core]")
+{
+    const uint32_t test_data = 0x12345678;
+
+    /* Load ULP RISC-V firmware and start the coprocessor */
+    load_and_start_lp_core_firmware();
+
+    /* Setup test data */
+    ulp_test_data_in = test_data ^ XOR_MASK;
+    ulp_main_cpu_command = LP_CORE_READ_WRITE_TEST;
+
+    /* Wait till we receive the correct command response */
+    while (ulp_command_resp != LP_CORE_READ_WRITE_TEST) {
+    }
+
+    /* Verify test data */
+    TEST_ASSERT(ulp_command_resp == LP_CORE_READ_WRITE_TEST);
+
+    /* Wait till we receive COMMAND_OK reply */
+    while (ulp_main_cpu_reply != LP_CORE_COMMAND_OK) {
+    }
+
+    printf("data out: 0x%" PRIx32 ", expected: 0x%" PRIx32 " \n", ulp_test_data_out, test_data);
+    TEST_ASSERT(test_data == ulp_test_data_out);
+
+    /* Clear test data */
+    ulp_main_cpu_command = LP_CORE_NO_COMMAND;
+}

+ 11 - 0
components/ulp/test_apps/lp_core/pytest_lp_core.py

@@ -0,0 +1,11 @@
+# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: CC0-1.0
+
+import pytest
+from pytest_embedded import Dut
+
+
+@pytest.mark.esp32c6
+@pytest.mark.generic
+def test_lp_core(dut: Dut) -> None:
+    dut.run_all_single_board_cases()

+ 5 - 0
components/ulp/test_apps/lp_core/sdkconfig.defaults

@@ -0,0 +1,5 @@
+CONFIG_ESP_TASK_WDT_INIT=n
+
+CONFIG_ULP_COPROC_ENABLED=y
+CONFIG_ULP_COPROC_TYPE_LP_CORE=y
+CONFIG_ULP_COPROC_RESERVE_MEM=4096

+ 19 - 0
components/ulp/ulp_common/include/esp32c6/ulp_common_defs.h

@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef __ULP_COMMON_DEFS_H__
+#define __ULP_COMMON_DEFS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTC_SLOW_MEM ((uint32_t*) 0x50000000)       /*!< LP memory, 16k size */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ULP_COMMON_DEFS_H__