diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index e6b02e1d22..eab81b1bcb 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/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; } diff --git a/components/esp_system/ld/esp32h2/memory.ld.in b/components/esp_system/ld/esp32h2/memory.ld.in index 83f4b5ce00..be4ee545c8 100644 --- a/components/esp_system/ld/esp32h2/memory.ld.in +++ b/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 } diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 4903749cec..e5cabe3a06 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index c8e68480e2..73084e087b 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/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 diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 96615ff958..d8ece5fa25 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index ee2cd1e40b..23105dbba6 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/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 diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 05e230dd21..8ce2957c29 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/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 diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index b5adb69135..16fda2cc10 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index ae43b4c74b..90ef2b613e 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/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 diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index f890f8b755..39d13cbc01 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 1199a7fdd3..3a5afcfe12 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/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 diff --git a/components/ulp/.build-test-rules.yml b/components/ulp/.build-test-rules.yml index 8316bbd3fb..9bb58bc05d 100644 --- a/components/ulp/.build-test-rules.yml +++ b/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 diff --git a/components/ulp/CMakeLists.txt b/components/ulp/CMakeLists.txt index cdf18b5eb7..4d336620bb 100644 --- a/components/ulp/CMakeLists.txt +++ b/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) diff --git a/components/ulp/Kconfig b/components/ulp/Kconfig index c276327f30..5997ea5ae6 100644 --- a/components/ulp/Kconfig +++ b/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. diff --git a/components/ulp/cmake/CMakeLists.txt b/components/ulp/cmake/CMakeLists.txt index 545b863d1a..5a945563cf 100644 --- a/components/ulp/cmake/CMakeLists.txt +++ b/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 diff --git a/components/ulp/cmake/toolchain-lp-core-riscv.cmake b/components/ulp/cmake/toolchain-lp-core-riscv.cmake new file mode 100644 index 0000000000..3f4d5d4e68 --- /dev/null +++ b/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") diff --git a/components/ulp/component_ulp_common.cmake b/components/ulp/component_ulp_common.cmake index 30cbe44a72..35271642bf 100644 --- a/components/ulp/component_ulp_common.cmake +++ b/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) diff --git a/components/ulp/ld/lp_core_riscv.ld b/components/ulp/ld/lp_core_riscv.ld new file mode 100644 index 0000000000..ab288c633e --- /dev/null +++ b/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); +} diff --git a/components/ulp/lp_core/include/ulp_lp_core.h b/components/ulp/lp_core/include/ulp_lp_core.h new file mode 100644 index 0000000000..07e7efa198 --- /dev/null +++ b/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 +#include +#include +#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 diff --git a/components/ulp/lp_core/lp_core.c b/components/ulp/lp_core/lp_core.c new file mode 100644 index 0000000000..47b9822d40 --- /dev/null +++ b/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; +} diff --git a/components/ulp/lp_core/lp_core/lp_core_startup.c b/components/ulp/lp_core/lp_core/lp_core_startup.c new file mode 100644 index 0000000000..fc8d3d6d7c --- /dev/null +++ b/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(); +} diff --git a/components/ulp/lp_core/lp_core/start.S b/components/ulp/lp_core/lp_core/start.S new file mode 100644 index 0000000000..f13a8819bd --- /dev/null +++ b/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 diff --git a/components/ulp/project_include.cmake b/components/ulp/project_include.cmake index 48e7fa2235..47df252e01 100644 --- a/components/ulp/project_include.cmake +++ b/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} diff --git a/components/ulp/test_apps/lp_core/CMakeLists.txt b/components/ulp/test_apps/lp_core/CMakeLists.txt new file mode 100644 index 0000000000..276fd98fd8 --- /dev/null +++ b/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) diff --git a/components/ulp/test_apps/lp_core/README.md b/components/ulp/test_apps/lp_core/README.md new file mode 100644 index 0000000000..65eeecb079 --- /dev/null +++ b/components/ulp/test_apps/lp_core/README.md @@ -0,0 +1,3 @@ +| Supported Targets | ESP32-C6 | +| ----------------- | -------- | + diff --git a/components/ulp/test_apps/lp_core/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/main/CMakeLists.txt new file mode 100644 index 0000000000..f9003f5147 --- /dev/null +++ b/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}") diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main.c b/components/ulp/test_apps/lp_core/main/lp_core/test_main.c new file mode 100644 index 0000000000..91d8818764 --- /dev/null +++ b/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 +#include +#include +#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; +} diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_shared.h b/components/ulp/test_apps/lp_core/main/lp_core/test_shared.h new file mode 100644 index 0000000000..384b0b1656 --- /dev/null +++ b/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; diff --git a/components/ulp/test_apps/lp_core/main/test_app_main.c b/components/ulp/test_apps/lp_core/main/test_app_main.c new file mode 100644 index 0000000000..d8a9a98ccc --- /dev/null +++ b/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(); +} diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core.c b/components/ulp/test_apps/lp_core/main/test_lp_core.c new file mode 100644 index 0000000000..c2bd74e5d5 --- /dev/null +++ b/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 +#include +#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; +} diff --git a/components/ulp/test_apps/lp_core/pytest_lp_core.py b/components/ulp/test_apps/lp_core/pytest_lp_core.py new file mode 100644 index 0000000000..8c8b5079ee --- /dev/null +++ b/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() diff --git a/components/ulp/test_apps/lp_core/sdkconfig.defaults b/components/ulp/test_apps/lp_core/sdkconfig.defaults new file mode 100644 index 0000000000..b1dc7fcf8c --- /dev/null +++ b/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 diff --git a/components/ulp/ulp_common/include/esp32c6/ulp_common_defs.h b/components/ulp/ulp_common/include/esp32c6/ulp_common_defs.h new file mode 100644 index 0000000000..1fa8ec6a91 --- /dev/null +++ b/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__