Merge branch 'feat/ulp_component_split' into 'master'

refactor(ulp): separate the ULP coprocessor code from the driver

Closes IDF-15957

See merge request espressif/esp-idf!52268
This commit is contained in:
Sudeep Mohanty
2026-09-15 11:49:23 +02:00
116 changed files with 583 additions and 526 deletions

View File

@@ -1,347 +1,159 @@
# The application's driver for the ULP coprocessor. The code that runs on the
# ULP coprocessor is built from the components in subproject/components, whose
# headers this component also publishes: they are on the application's include
# path.
if(__ULP_BUILDV2)
idf_die("The ulp component is not built for the ULP coprocessor. A ULP "
"program is built against the components in ulp/subproject.")
endif()
set(srcs "")
set(includes "")
set(requires "")
set(priv_requires "")
if(__ULP_BUILDV2)
if(ULP_TYPE STREQUAL "riscv")
list(APPEND includes
ulp_common/include
ulp_riscv/include
ulp_riscv/shared/include
ulp_riscv/ulp_core/include)
list(APPEND srcs
"ulp_riscv/ulp_core/ulp_riscv_vectors.S"
"ulp_riscv/ulp_core/start.S"
"ulp_riscv/ulp_core/ulp_riscv_adc.c"
"ulp_riscv/ulp_core/ulp_riscv_lock.c"
"ulp_riscv/ulp_core/ulp_riscv_uart.c"
"ulp_riscv/ulp_core/ulp_riscv_print.c"
"ulp_riscv/ulp_core/ulp_riscv_i2c.c"
"ulp_riscv/ulp_core/ulp_riscv_utils.c"
"ulp_riscv/ulp_core/ulp_riscv_touch.c"
"ulp_riscv/ulp_core/ulp_riscv_gpio.c"
"ulp_riscv/ulp_core/ulp_riscv_interrupt.c")
list(APPEND requires
esp_common
esp_hal_ana_conv
esp_hal_gpio
esp_hal_i2c
esp_hal_touch_sens
esp_hw_support
riscv
soc)
elseif(ULP_TYPE STREQUAL "lp_core")
list(APPEND includes
ulp_common/include
lp_core/include
lp_core/lp_core/include
lp_core/shared/include)
list(APPEND srcs
"lp_core/lp_core/start.S"
"lp_core/lp_core/vector.S"
"lp_core/lp_core/port/${target}/vector_table.S"
"lp_core/shared/ulp_lp_core_memory_shared.c"
"lp_core/lp_core/lp_core_startup.c"
"lp_core/lp_core/lp_core_pmp.c"
"lp_core/lp_core/lp_core_utils.c"
"lp_core/lp_core/lp_core_print.c"
"lp_core/lp_core/lp_core_panic.c"
"lp_core/lp_core/lp_core_interrupt.c"
"lp_core/lp_core/lp_core_ubsan.c"
"lp_core/lp_core/lp_core_mailbox.c"
"lp_core/shared/ulp_lp_core_critical_section_shared.c")
# TODO(IDF-15993): Keep esp_driver_gpio and esp_adc public for compatibility
# with the CMake v1 dependency graph until downstream users are fixed.
list(APPEND requires
esp_adc
esp_driver_gpio)
list(APPEND requires
esp_common
esp_hal_gpio
esp_hal_uart
esp_rom
hal
riscv
soc)
list(APPEND priv_requires
esp_hal_pmu
esp_hw_support)
if(CONFIG_SOC_RTC_TIMER_V2 OR CONFIG_SOC_RTC_TIMER_V3)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_timer_shared.c")
list(APPEND priv_requires
esp_hal_clock
esp_hal_rtc_timer)
endif()
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
list(APPEND srcs "lp_core/lp_core/lp_core_i2c.c")
list(APPEND requires esp_hal_i2c)
endif()
if(CONFIG_SOC_LP_SPI_SUPPORTED)
list(APPEND srcs "lp_core/lp_core/lp_core_spi.c")
list(APPEND priv_requires esp_hal_gpspi)
endif()
if(CONFIG_SOC_ULP_LP_UART_SUPPORTED)
list(APPEND srcs
"lp_core/shared/ulp_lp_core_lp_uart_shared.c"
"lp_core/lp_core/lp_core_uart.c")
list(APPEND requires esp_driver_uart)
endif()
if(CONFIG_SOC_LP_MAILBOX_SUPPORTED)
list(APPEND srcs "lp_core/lp_core/port/lp_core_mailbox_impl_hw.c")
else()
list(APPEND srcs "lp_core/lp_core/port/lp_core_mailbox_impl_sw.c")
endif()
if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED)
list(APPEND srcs "lp_core/lp_core/lp_core_touch.c")
list(APPEND requires esp_hal_touch_sens)
endif()
if(CONFIG_SOC_LP_ADC_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_adc_shared.c")
list(APPEND requires
esp_adc
esp_hal_ana_conv)
endif()
if(CONFIG_SOC_LP_VAD_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_vad_shared.c")
list(APPEND requires esp_driver_i2s)
endif()
elseif(ULP_TYPE STREQUAL "fsm")
list(APPEND includes
ulp_common/include
ulp_fsm/include
ulp_fsm/include/${target})
list(APPEND requires soc)
else()
message(FATAL_ERROR "__ULP_BUILDV2 requires ULP_TYPE to be one of: riscv, lp_core, fsm.")
endif()
else()
# TODO(IDF-15993): Keep esp_driver_gpio and esp_adc public for compatibility
# with the CMake v1 dependency graph until downstream users are fixed.
if(CONFIG_ULP_COPROC_ENABLED OR CONFIG_IDF_DOC_BUILD)
list(APPEND includes
ulp_common/include)
list(APPEND requires
esp_adc
esp_driver_gpio)
esp_common
soc)
endif()
if(CONFIG_ULP_COPROC_ENABLED OR CONFIG_IDF_DOC_BUILD)
list(APPEND includes
ulp_common/include)
list(APPEND requires
esp_common
soc)
endif()
if(CONFIG_ULP_COPROC_TYPE_FSM OR (CONFIG_IDF_DOC_BUILD AND CONFIG_SOC_ULP_FSM_SUPPORTED))
list(APPEND includes
ulp_fsm/include
ulp_fsm/include/${target})
list(APPEND requires esp_hw_support)
endif()
if(CONFIG_ULP_COPROC_TYPE_FSM OR (CONFIG_IDF_DOC_BUILD AND CONFIG_SOC_ULP_FSM_SUPPORTED))
list(APPEND includes
ulp_fsm/include
ulp_fsm/include/${target})
list(APPEND requires esp_hw_support)
endif()
if(CONFIG_ULP_COPROC_TYPE_RISCV OR CONFIG_IDF_DOC_BUILD)
list(APPEND includes
ulp_riscv/include
ulp_riscv/shared/include
subproject/components/ulp_riscv/include)
list(APPEND requires esp_hw_support)
endif()
if(CONFIG_ULP_COPROC_TYPE_RISCV OR CONFIG_IDF_DOC_BUILD)
list(APPEND includes
ulp_riscv/include
ulp_riscv/shared/include
ulp_riscv/ulp_core/include)
list(APPEND requires esp_hw_support)
endif()
if(CONFIG_ULP_COPROC_TYPE_LP_CORE OR CONFIG_IDF_DOC_BUILD)
list(APPEND includes
lp_core/include
subproject/components/lp_core/include
lp_core/shared/include)
endif()
if(CONFIG_ULP_COPROC_TYPE_LP_CORE OR CONFIG_IDF_DOC_BUILD)
list(APPEND includes
lp_core/include
lp_core/lp_core/include
lp_core/shared/include)
endif()
if(CONFIG_ULP_COPROC_TYPE_FSM OR CONFIG_ULP_COPROC_TYPE_RISCV)
list(APPEND srcs
"ulp_common/ulp_common.c"
"ulp_common/ulp_adc.c")
if(CONFIG_ULP_COPROC_TYPE_FSM OR CONFIG_ULP_COPROC_TYPE_RISCV)
if(CONFIG_ULP_COPROC_TYPE_FSM)
list(APPEND srcs
"ulp_common/ulp_common.c"
"ulp_common/ulp_adc.c")
if(CONFIG_ULP_COPROC_TYPE_FSM)
list(APPEND srcs
"ulp_fsm/ulp.c"
"ulp_fsm/ulp_macro.c")
endif()
if(CONFIG_ULP_COPROC_TYPE_RISCV)
list(APPEND srcs
"ulp_riscv/ulp_riscv.c"
"ulp_riscv/ulp_riscv_lock.c"
"ulp_riscv/ulp_riscv_i2c.c")
list(APPEND priv_requires esp_driver_gpio)
list(APPEND requires
# ulp/ulp_riscv/ulp_core/include/ulp_riscv_touch_ulp_core.h
# includes hal/touch_sens_types.h.
esp_hal_touch_sens
esp_hal_i2c
hal)
endif()
"ulp_fsm/ulp.c"
"ulp_fsm/ulp_macro.c")
endif()
if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
if(CONFIG_ULP_COPROC_TYPE_RISCV)
list(APPEND srcs
"lp_core/lp_core.c"
"lp_core/shared/ulp_lp_core_memory_shared.c"
"lp_core/shared/ulp_lp_core_critical_section_shared.c")
"ulp_riscv/ulp_riscv.c"
"ulp_riscv/ulp_riscv_lock.c"
"ulp_riscv/ulp_riscv_i2c.c")
list(APPEND priv_requires esp_driver_gpio)
list(APPEND requires
esp_common
esp_hal_pmu
esp_rom
hal
riscv
soc)
if(CONFIG_SOC_ULP_LP_UART_SUPPORTED)
list(APPEND srcs
"lp_core/lp_core_uart.c"
"lp_core/shared/ulp_lp_core_lp_uart_shared.c")
list(APPEND requires
esp_driver_gpio
esp_driver_uart)
endif()
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
list(APPEND srcs "lp_core/lp_core_i2c.c")
list(APPEND requires
esp_driver_gpio
esp_hal_i2c)
endif()
if(CONFIG_SOC_RTC_TIMER_V2 OR CONFIG_SOC_RTC_TIMER_V3)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_timer_shared.c")
list(APPEND requires
esp_hal_clock
esp_hal_rtc_timer)
endif()
if(CONFIG_SOC_LP_SPI_SUPPORTED)
list(APPEND srcs "lp_core/lp_core_spi.c")
list(APPEND requires
esp_driver_gpio
esp_hal_gpspi)
endif()
if(CONFIG_SOC_LP_CORE_SUPPORT_ETM)
list(APPEND srcs "lp_core/lp_core_etm.c")
endif()
if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED)
list(APPEND requires esp_hal_touch_sens)
endif()
if(CONFIG_SOC_LP_ADC_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_adc_shared.c")
list(APPEND priv_requires esp_hw_support)
endif()
if(CONFIG_SOC_LP_VAD_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_vad_shared.c")
list(APPEND requires esp_driver_i2s)
endif()
list(APPEND srcs "lp_core/lp_core_mailbox.c")
if(CONFIG_SOC_LP_MAILBOX_SUPPORTED)
list(APPEND srcs "lp_core/lp_core_mailbox_impl_hw.c")
else()
list(APPEND srcs "lp_core/lp_core_mailbox_impl_sw.c")
endif()
endif()
if(srcs)
list(APPEND priv_requires
bootloader_support
esp_mm)
# ulp/subproject/components/ulp_riscv/include/ulp_riscv_touch_ulp_core.h
# includes hal/touch_sens_types.h.
esp_hal_touch_sens
esp_hal_i2c
hal)
endif()
endif()
if(requires)
list(REMOVE_DUPLICATES requires)
if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
list(APPEND srcs
"lp_core/lp_core.c"
"lp_core/shared/ulp_lp_core_memory_shared.c"
"lp_core/shared/ulp_lp_core_critical_section_shared.c")
list(APPEND requires
esp_common
esp_hal_pmu
esp_rom
hal
riscv
soc)
if(CONFIG_SOC_ULP_LP_UART_SUPPORTED)
list(APPEND srcs
"lp_core/lp_core_uart.c"
"lp_core/shared/ulp_lp_core_lp_uart_shared.c")
list(APPEND requires
esp_driver_gpio
esp_driver_uart)
endif()
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
list(APPEND srcs "lp_core/lp_core_i2c.c")
list(APPEND requires
esp_driver_gpio
esp_hal_i2c)
endif()
if(CONFIG_SOC_RTC_TIMER_V2 OR CONFIG_SOC_RTC_TIMER_V3)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_timer_shared.c")
list(APPEND requires
esp_hal_clock
esp_hal_rtc_timer)
endif()
if(CONFIG_SOC_LP_SPI_SUPPORTED)
list(APPEND srcs "lp_core/lp_core_spi.c")
list(APPEND requires
esp_driver_gpio
esp_hal_gpspi)
endif()
if(CONFIG_SOC_LP_CORE_SUPPORT_ETM)
list(APPEND srcs "lp_core/lp_core_etm.c")
endif()
if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED)
list(APPEND requires esp_hal_touch_sens)
endif()
if(CONFIG_SOC_LP_ADC_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_adc_shared.c")
list(APPEND priv_requires esp_hw_support)
endif()
if(CONFIG_SOC_LP_VAD_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_vad_shared.c")
list(APPEND requires esp_driver_i2s)
endif()
list(APPEND srcs "lp_core/lp_core_mailbox.c")
if(CONFIG_SOC_LP_MAILBOX_SUPPORTED)
list(APPEND srcs "lp_core/lp_core_mailbox_impl_hw.c")
else()
list(APPEND srcs "lp_core/lp_core_mailbox_impl_sw.c")
endif()
endif()
if(priv_requires)
list(REMOVE_DUPLICATES priv_requires)
endif()
set(whole_archive)
if(__ULP_BUILDV2)
# Legacy ULP child builds added the LP-core runtime sources directly to the
# executable. Preserve that behavior so strong handlers such as
# ulp_lp_core_panic_handler are not dropped in favor of weak defaults from
# other runtime objects.
set(whole_archive WHOLE_ARCHIVE)
if(srcs)
list(APPEND priv_requires
bootloader_support
esp_mm)
endif()
list(REMOVE_DUPLICATES requires)
list(REMOVE_DUPLICATES priv_requires)
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes}
REQUIRES ${requires}
PRIV_REQUIRES ${priv_requires}
${whole_archive})
PRIV_REQUIRES ${priv_requires})
# In the parent app build, the ulp component only provides the host-side API.
# The executable/linker setup below is for native ULP child projects.
if(NOT __ULP_BUILDV2)
idf_define_esp_err_codes(HEADERS ulp_fsm/include/ulp_fsm_common.h)
return()
endif()
# Preprocessor flags shared by every ULP memory-layout template. The template
# is a ".in" file, so the standard target_linker_script flow runs the C
# preprocessor on it. -D__ASSEMBLER__ keeps SoC headers to their macro-only
# form, and the component's own ld directory is available for relative
# includes.
set(ulp_ld_flags "-D__ASSEMBLER__ -I\"${CMAKE_CURRENT_SOURCE_DIR}/ld\"")
# Select the linker template and target-specific link options used by the ULP
# executable created in the child project. The memory-layout template is
# registered with target_linker_script so the standard build system
# preprocesses and attaches it; per-type FLAGS supply the include directories
# its #include lines need.
if(ULP_TYPE STREQUAL "riscv")
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/ulp_riscv.ld.in" MEMORY
FLAGS "${ulp_ld_flags}")
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/${target}.peripherals.ld")
target_link_options(${COMPONENT_LIB} INTERFACE
-nostartfiles
-Wl,--gc-sections
-Wl,--no-warn-rwx-segments
LINKER:-u,main)
target_compile_definitions(${COMPONENT_LIB} PUBLIC
IS_ULP_COCPU
ULP_RISCV_REGISTER_OPS)
elseif(ULP_TYPE STREQUAL "lp_core")
# lp_core_riscv.ld includes soc/soc.h and esp_common headers, which are
# resolved automatically from the linked component graph. It also includes
# the esp_system ld snippets (ld.common, ld.hp_mem_defs); those live in the
# component's ld/ directory, which is not a public include dir, so pass it
# via FLAGS.
idf_component_get_property(esp_system_dir esp_system COMPONENT_DIR)
set(lp_core_ld_flags "${ulp_ld_flags} -I\"${esp_system_dir}/ld\" -I\"${esp_system_dir}/ld/${target}\"")
# A user-supplied LINKER layout replaces the default one composed into
# lp_core_riscv.ld.in. It reaches this child project as LP_CORE_LINKER_SCRIPT
# (passed by __setup_ulp_project, same as the CMake v1 path). Hand it to the
# wrapper as the LP_CORE_LINKER_INCLUDE macro it #includes. The escaped quotes
# survive separate_arguments() in the linker-script preprocessor so the macro
# expands to a quoted header-name token ("/abs/path.ld").
if(LP_CORE_LINKER_SCRIPT)
message(STATUS "Using custom LP-core linker layout: ${LP_CORE_LINKER_SCRIPT}")
string(APPEND lp_core_ld_flags " -DLP_CORE_LINKER_INCLUDE=\\\"${LP_CORE_LINKER_SCRIPT}\\\"")
endif()
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/lp_core_riscv.ld.in" MEMORY
FLAGS "${lp_core_ld_flags}")
target_link_options(${COMPONENT_LIB} INTERFACE
-nostartfiles
-Wl,--gc-sections
-Wl,--no-warn-rwx-segments
LINKER:-u,main)
target_compile_definitions(${COMPONENT_LIB} PUBLIC IS_ULP_COCPU)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough)
elseif(ULP_TYPE STREQUAL "fsm")
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/ulp_fsm.ld.in" MEMORY
FLAGS "${ulp_ld_flags}")
target_link_options(${COMPONENT_LIB} INTERFACE "SHELL:-u entry")
endif()
idf_define_esp_err_codes(HEADERS ulp_fsm/include/ulp_fsm_common.h)

View File

@@ -54,20 +54,8 @@ menu "Ultra Low Power (ULP) Co-processor"
menu "ULP RISC-V Settings"
depends on ULP_COPROC_TYPE_RISCV
config ULP_RISCV_INTERRUPT_ENABLE
bool
prompt "Enable ULP RISC-V interrupts"
default "n"
help
Turn on this setting to enabled interrupts on the ULP RISC-V core.
config ULP_RISCV_UART_BAUDRATE
int
prompt "Baudrate used by the bitbanged ULP RISC-V UART driver"
default 9600
help
The accuracy of the bitbanged UART driver is limited, it is not
recommend to increase the value above 19200.
# Declared by the component that builds the ULP RISC-V program.
rsource "subproject/components/ulp_riscv/Kconfig.ulp_riscv"
config ULP_RISCV_I2C_RW_TIMEOUT
int
@@ -117,28 +105,8 @@ menu "Ultra Low Power (ULP) Co-processor"
HP application.
endmenu
config ULP_ROM_PRINT_ENABLE
depends on ULP_COPROC_TYPE_LP_CORE && ESP_ROM_HAS_LP_ROM
bool
prompt "Enable print utilities from LP ROM"
default "y"
help
Set this option to enable printf functionality from LP ROM. This option
can help reduce the LP core binary size by not linking printf functionality
from RAM code.
Note: For LP ROM prints to work properly, make sure that the LP core boots
from the LP ROM.
config ULP_LP_CORE_MEMPROT
bool "Enable LP Core memory protection (PMP)"
depends on ULP_COPROC_TYPE_LP_CORE && SOC_LP_CORE_HAS_PMP && !ULP_COPROC_RUN_FROM_HP_MEM
default n
help
Configures the LP CPU's PMP entries to enforce memory protection.
LP RAM is split into executable (.text) and data (.data/.bss/stack)
regions. Regions not explicitly permitted are inaccessible.
Not available when "Run LP Core from HP memory" is enabled.
Disable this if you need full control over PMP configuration.
# Declared by the component that builds the LP core program.
rsource "subproject/components/lp_core/Kconfig.lp_core"
config ULP_TRAP_WAKEUP
depends on ULP_COPROC_TYPE_LP_CORE
@@ -150,38 +118,8 @@ menu "Ultra Low Power (ULP) Co-processor"
the LP-core encounters an exception.
menu "ULP Debugging Options"
config ULP_PANIC_OUTPUT_ENABLE
depends on ULP_COPROC_TYPE_LP_CORE && SOC_ULP_LP_UART_SUPPORTED
bool
prompt "Enable panic handler which outputs over LP UART"
default "n"
help
Set this option to enable panic handler functionality. If this option is
enabled then the LP Core will output a panic dump over LP UART,
similar to what the main core does. Output depends on LP UART already being
initialized and configured.
Disabling this option will reduce the LP core binary size by not
linking in panic handler functionality.
config ULP_HP_UART_CONSOLE_PRINT
depends on ULP_COPROC_TYPE_LP_CORE
bool
prompt "Route lp_core_printf to the console HP-UART"
help
Set this option to route lp_core_printf to the console HP-UART.
This allows you to easily view print outputs from the LP core, without
having to connect to the LP-UART. This option comes with the following
limitations:
1. There is no mutual exclusion between the HP-Core and the LP-Core accessing
the HP-UART, which means that if both cores are logging heavily the output
strings might get mangled together.
2. The HP-UART can only work while the HP-Core is running, which means that
if the HP-Core is in deep sleep, the LP-Core will not be able to print to the
console HP-UART.
Due to these limitations it is only recommended to use this option for easy debugging.
For more serious use-cases you should use the LP-UART.
# Declared by the component that builds the LP core program.
rsource "subproject/components/lp_core/Kconfig.lp_core_debug"
config ULP_NORESET_UNDER_DEBUG
bool "Avoid resetting LP core when debugger is attached"

View File

@@ -10,7 +10,7 @@ function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name
s_sources exp_dep_srcs linker_script)
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
set(ulp_cmake_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/cmake")
set(ulp_subproject_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/subproject")
set(sources "")
spaces2list(s_sources)
foreach(source ${s_sources})
@@ -95,7 +95,7 @@ function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name
"Only FSM type is available for ULP on this target.")
endif()
endif()
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-${idf_target}-ulp.cmake)
set(TOOLCHAIN_FLAG ${ulp_subproject_dir}/components/ulp_fsm/toolchain-${idf_target}-ulp.cmake)
set(ULP_IS_RISCV OFF)
elseif(IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET STREQUAL "esp32s3")
# If both FSM and RISC-V are enabled in sdkconfig and a TYPE was
@@ -105,21 +105,21 @@ function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name
message(STATUS "Both RISCV and FSM are enabled, using '${type}' toolchain for ${app_name} ULP project.")
string(TOLOWER "${type}" type_lower)
if(type_lower STREQUAL "riscv")
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-ulp-riscv.cmake)
set(TOOLCHAIN_FLAG ${ulp_subproject_dir}/components/ulp_riscv/toolchain-ulp-riscv.cmake)
elseif(type_lower STREQUAL "fsm")
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-${idf_target}-ulp.cmake)
set(TOOLCHAIN_FLAG ${ulp_subproject_dir}/components/ulp_fsm/toolchain-${idf_target}-ulp.cmake)
else()
message(FATAL_ERROR "Invalid ULP_TYPE '${type}'; expected 'fsm' or 'riscv'.")
endif()
else()
if(CONFIG_ULP_COPROC_TYPE_RISCV STREQUAL "y")
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-ulp-riscv.cmake)
set(TOOLCHAIN_FLAG ${ulp_subproject_dir}/components/ulp_riscv/toolchain-ulp-riscv.cmake)
else()
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-${idf_target}-ulp.cmake)
set(TOOLCHAIN_FLAG ${ulp_subproject_dir}/components/ulp_fsm/toolchain-${idf_target}-ulp.cmake)
endif()
endif()
elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE)
set(TOOLCHAIN_FLAG ${ulp_cmake_dir}/toolchain-lp-core-riscv.cmake)
set(TOOLCHAIN_FLAG ${ulp_subproject_dir}/components/lp_core/toolchain-lp-core-riscv.cmake)
endif()
set(ulp_project_args)
@@ -133,7 +133,7 @@ function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name
-DIDF_DEFAULT_PROJECT_NAME=${app_name}
-DULP_APP_NAME=${app_name}
-DIDF_BUILD_V2=y
-DCMAKE_MODULE_PATH=${ulp_cmake_dir}
-DCMAKE_MODULE_PATH=${ulp_subproject_dir}
# Internal marker for ULP child component graphs. Only the
# IDF_BUILD_V2 path sets it for now.
-D__ULP_BUILDV2=1
@@ -176,7 +176,7 @@ function(__setup_ulp_project app_name project_path prefix prefix_append_bin_name
-DSDKCONFIG_HEADER=${SDKCONFIG_HEADER}
-DSDKCONFIG_CMAKE=${SDKCONFIG_CMAKE}
# The v1 ULP child resolves include(IDFULPProject) via the module path.
-DCMAKE_MODULE_PATH=${ulp_cmake_dir})
-DCMAKE_MODULE_PATH=${ulp_subproject_dir})
endif()
externalproject_add(${app_name}
@@ -315,9 +315,9 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs)
set(ULP_TYPE "${ulp_resolved_type}")
endif()
__resolve_lp_core_linker("${ULP_LINKER_LAYOUT}" "${ulp_resolved_type}" LP_CORE_LINKER)
set(ulp_cmake_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/cmake")
set(ulp_subproject_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/subproject")
__setup_ulp_project("${app_name}" "${ulp_cmake_dir}"
__setup_ulp_project("${app_name}" "${ulp_subproject_dir}"
"${ULP_PREFIX}" FALSE "${ULP_TYPE}"
"${app_name}"
"${s_sources}" "${exp_dep_srcs}" "${LP_CORE_LINKER}")

View File

@@ -1,6 +1,6 @@
# CMake v2 default ULP project for ulp_embed_binary() callers. The ULP runtime
# is built from the ulp component graph, and the legacy source list is attached
# directly to the executable, matching the CMake v1 link semantics.
# CMake v2 default ULP project for ulp_embed_binary() callers. The ULP program
# is built against the component for its architecture, and the call-site source
# list is linked before it, matching the build system v1 link semantics.
include(${CMAKE_CURRENT_LIST_DIR}/ulp_project.cmake)
if("${ULP_TYPE}" STREQUAL "fsm")
@@ -49,7 +49,9 @@ function(__ulp_embed_binary_add_legacy_sources executable)
__idf_build_link_whole_archive(${executable} PRIVATE ${legacy_sources_lib} BEFORE)
endfunction()
set(executable_args COMPONENTS ulp)
__ulp_arch_component(ulp_component)
set(executable_args COMPONENTS ${ulp_component})
if(NOT BUILD_FSM)
list(APPEND executable_args MAPFILE_TARGET ${ULP_APP_NAME}_mapfile)
endif()

View File

@@ -1,5 +1,5 @@
# This is the CMake v1 (legacy) ULP child entry point, used by ulp_embed_binary.
# CMake v2 full-subproject builds include components/ulp/cmake/ulp_project.cmake
# CMake v2 full-subproject builds include components/ulp/subproject/ulp_project.cmake
# instead.
#
# Legacy ULP child projects are plain CMake projects, so the parent-provided
@@ -103,11 +103,11 @@ function(ulp_apply_default_sources ulp_app_name)
# replaces the layout, swapped in by the wrapper. This is supported for the
# LP-core type only.
if(BUILD_RISCV)
set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/ulp_riscv.ld.in)
set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ld/ulp_riscv.ld.in)
elseif(BUILD_LP_CORE)
set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/lp_core_riscv.ld.in)
set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/subproject/components/lp_core/ld/lp_core_riscv.ld.in)
elseif(BUILD_FSM)
set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/ulp_fsm.ld.in)
set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/subproject/components/ulp_fsm/ld/ulp_fsm.ld.in)
else()
message(FATAL_ERROR "Unable to determine ULP type. ")
endif()
@@ -143,24 +143,27 @@ function(ulp_apply_default_sources ulp_app_name)
if(BUILD_RISCV)
#risc-v ulp uses extra files for building:
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_vectors.S"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/start.S"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_adc.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_lock.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_uart.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_print.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_i2c.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_utils.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_touch.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_gpio.c"
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_interrupt.c")
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_vectors.S"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/start.S"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_adc.c"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_lock.c"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_uart.c"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_print.c"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_i2c.c"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_utils.c"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_touch.c"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_gpio.c"
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ulp_riscv_interrupt.c")
target_sources(${ulp_app_name} PRIVATE ${ULP_S_SOURCES})
#Makes the csr utillies for riscv visible:
target_include_directories(${ulp_app_name} PRIVATE "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/include"
"${IDF_PATH}/components/ulp/ulp_riscv/shared/include"
"${IDF_PATH}/components/riscv/include")
target_link_options(${ulp_app_name} PRIVATE SHELL:-T ${IDF_PATH}/components/ulp/ld/${IDF_TARGET}.peripherals.ld)
target_include_directories(${ulp_app_name} PRIVATE
"${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/include"
"${IDF_PATH}/components/ulp/ulp_riscv/shared/include"
"${IDF_PATH}/components/riscv/include")
target_link_options(${ulp_app_name}
PRIVATE SHELL:-T
${IDF_PATH}/components/ulp/subproject/components/ulp_riscv/ld/${IDF_TARGET}.peripherals.ld)
target_compile_definitions(${ulp_app_name} PRIVATE IS_ULP_COCPU)
target_compile_definitions(${ulp_app_name} PRIVATE ULP_RISCV_REGISTER_OPS)
@@ -191,31 +194,31 @@ function(ulp_apply_default_sources ulp_app_name)
elseif(BUILD_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/vector.S"
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/${IDF_TARGET}/vector_table.S"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/start.S"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/vector.S"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/port/${IDF_TARGET}/vector_table.S"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_startup.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_pmp.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_utils.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_print.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_panic.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_interrupt.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_ubsan.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_mailbox.c"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_startup.c"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_pmp.c"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_utils.c"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_print.c"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_panic.c"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_interrupt.c"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_ubsan.c"
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_mailbox.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_vad_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_critical_section_shared.c")
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c")
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_i2c.c")
endif()
if(CONFIG_SOC_LP_SPI_SUPPORTED)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_spi.c")
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_spi.c")
endif()
if(CONFIG_SOC_ULP_LP_UART_SUPPORTED)
@@ -224,20 +227,20 @@ function(ulp_apply_default_sources ulp_app_name)
"${IDF_PATH}/components/esp_driver_uart/src/uart_wakeup.c"
"${IDF_PATH}/components/esp_hal_uart/uart_hal_iram.c"
"${IDF_PATH}/components/esp_hal_uart/uart_hal.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_uart.c")
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_uart.c")
endif()
if(CONFIG_SOC_LP_MAILBOX_SUPPORTED)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/lp_core_mailbox_impl_hw.c")
"${IDF_PATH}/components/ulp/subproject/components/lp_core/port/lp_core_mailbox_impl_hw.c")
else()
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/lp_core_mailbox_impl_sw.c")
"${IDF_PATH}/components/ulp/subproject/components/lp_core/port/lp_core_mailbox_impl_sw.c")
endif()
if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_touch.c")
"${IDF_PATH}/components/ulp/subproject/components/lp_core/lp_core_touch.c")
endif()
set(target_folder ${IDF_TARGET})
@@ -257,8 +260,9 @@ function(ulp_apply_default_sources ulp_app_name)
endif()
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"
"${IDF_PATH}/components/ulp/lp_core/shared/include")
target_include_directories(${ulp_app_name} PRIVATE
"${IDF_PATH}/components/ulp/subproject/components/lp_core/include"
"${IDF_PATH}/components/ulp/lp_core/shared/include")
target_compile_definitions(${ulp_app_name} PRIVATE IS_ULP_COCPU)
endif()

View File

@@ -1,3 +1,8 @@
# The directory of this file, captured while it is being processed:
# CMAKE_CURRENT_LIST_DIR inside a function resolves at call time, which is the
# caller's directory, not this one.
set(__ULP_SUBPROJECT_DIR "${CMAKE_CURRENT_LIST_DIR}")
macro(ulp_detect_build_type)
# Logic to determine ULP type and set reusable flags
set(BUILD_RISCV OFF)
@@ -49,7 +54,7 @@ function(ulp_add_build_binary_targets ulp_app_name)
set(ULP_BASE_ADDR "0x50000000")
endif()
set(ULP_MAP_GEN ${PYTHON} ${IDF_PATH}/components/ulp/esp32ulp_mapgen.py)
set(ULP_MAP_GEN ${PYTHON} ${__ULP_SUBPROJECT_DIR}/esp32ulp_mapgen.py)
# Dump the list of global symbols in a convenient format
add_custom_command(OUTPUT ${ulp_app_name}.sym

View File

@@ -0,0 +1,120 @@
# The code compiled for the LP core.
#
# Sources shared with the driver stay in components/ulp and are named by path
# from here.
idf_build_get_property(target IDF_TARGET)
get_filename_component(ulp_dir "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
set(srcs "start.S"
"vector.S"
"port/${target}/vector_table.S"
"${ulp_dir}/lp_core/shared/ulp_lp_core_memory_shared.c"
"lp_core_startup.c"
"lp_core_pmp.c"
"lp_core_utils.c"
"lp_core_print.c"
"lp_core_panic.c"
"lp_core_interrupt.c"
"lp_core_ubsan.c"
"lp_core_mailbox.c"
"${ulp_dir}/lp_core/shared/ulp_lp_core_critical_section_shared.c")
set(requires esp_common
esp_hal_gpio
esp_hal_uart
esp_rom
hal
riscv
soc)
set(priv_requires esp_hal_pmu
esp_hw_support)
if(CONFIG_SOC_RTC_TIMER_V2 OR CONFIG_SOC_RTC_TIMER_V3)
list(APPEND srcs "${ulp_dir}/lp_core/shared/ulp_lp_core_lp_timer_shared.c")
list(APPEND priv_requires esp_hal_clock esp_hal_rtc_timer)
endif()
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
list(APPEND srcs "lp_core_i2c.c")
list(APPEND requires esp_hal_i2c)
endif()
if(CONFIG_SOC_LP_SPI_SUPPORTED)
list(APPEND srcs "lp_core_spi.c")
list(APPEND priv_requires esp_hal_gpspi)
endif()
if(CONFIG_SOC_ULP_LP_UART_SUPPORTED)
list(APPEND srcs
"${ulp_dir}/lp_core/shared/ulp_lp_core_lp_uart_shared.c"
"lp_core_uart.c")
list(APPEND requires esp_driver_uart)
endif()
if(CONFIG_SOC_LP_MAILBOX_SUPPORTED)
list(APPEND srcs "port/lp_core_mailbox_impl_hw.c")
else()
list(APPEND srcs "port/lp_core_mailbox_impl_sw.c")
endif()
if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED)
list(APPEND srcs "lp_core_touch.c")
list(APPEND requires esp_hal_touch_sens)
endif()
if(CONFIG_SOC_LP_ADC_SUPPORTED)
list(APPEND srcs "${ulp_dir}/lp_core/shared/ulp_lp_core_lp_adc_shared.c")
list(APPEND requires esp_adc esp_hal_ana_conv)
endif()
if(CONFIG_SOC_LP_VAD_SUPPORTED)
list(APPEND srcs "${ulp_dir}/lp_core/shared/ulp_lp_core_lp_vad_shared.c")
list(APPEND requires esp_driver_i2s)
endif()
# The ULP subproject in build system v1 adds these sources straight to the
# executable, so a strong handler such as ulp_lp_core_panic_handler is not
# dropped in favour of a weak default from another runtime object.
# WHOLE_ARCHIVE keeps that behaviour here.
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS "${ulp_dir}/ulp_common/include"
"${ulp_dir}/lp_core/include"
"include"
"${ulp_dir}/lp_core/shared/include"
REQUIRES ${requires}
PRIV_REQUIRES ${priv_requires}
WHOLE_ARCHIVE)
# -D__ASSEMBLER__ keeps the SoC headers to their macro-only form.
set(ulp_ld_flags "-D__ASSEMBLER__ -I\"${CMAKE_CURRENT_SOURCE_DIR}/ld\"")
# lp_core_riscv.ld includes soc/soc.h and esp_common headers, resolved from the
# linked component graph. It also includes the esp_system ld snippets
# (ld.common, ld.hp_mem_defs); those live in that component's ld/ directory,
# which is not a public include dir, so pass it via FLAGS.
idf_component_get_property(esp_system_dir esp_system COMPONENT_DIR)
set(lp_core_ld_flags "${ulp_ld_flags} -I\"${esp_system_dir}/ld\" -I\"${esp_system_dir}/ld/${target}\"")
# A user-supplied LINKER layout replaces the default one composed into
# lp_core_riscv.ld.in. It reaches this child project as LP_CORE_LINKER_SCRIPT
# (passed by __setup_ulp_project, same as the build system v1 path). Hand it to
# the wrapper as the LP_CORE_LINKER_INCLUDE macro it #includes. The escaped
# quotes survive separate_arguments() in the linker-script preprocessor so the
# macro expands to a quoted header-name token ("/abs/path.ld").
if(LP_CORE_LINKER_SCRIPT)
message(STATUS "Using custom LP-core linker layout: ${LP_CORE_LINKER_SCRIPT}")
string(APPEND lp_core_ld_flags " -DLP_CORE_LINKER_INCLUDE=\\\"${LP_CORE_LINKER_SCRIPT}\\\"")
endif()
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/lp_core_riscv.ld.in" MEMORY
FLAGS "${lp_core_ld_flags}")
target_link_options(${COMPONENT_LIB} INTERFACE
-nostartfiles
-Wl,--gc-sections
-Wl,--no-warn-rwx-segments
LINKER:-u,main)
target_compile_definitions(${COMPONENT_LIB} PUBLIC IS_ULP_COCPU)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough)

View File

@@ -0,0 +1,26 @@
# Sourced by the ULP coprocessor driver on the HP core, in
# components/ulp/Kconfig. Not named Kconfig, which would also attach it to
# this component and define every option twice.
config ULP_ROM_PRINT_ENABLE
depends on ULP_COPROC_TYPE_LP_CORE && ESP_ROM_HAS_LP_ROM
bool
prompt "Enable print utilities from LP ROM"
default "y"
help
Set this option to enable printf functionality from LP ROM. This option
can help reduce the LP core binary size by not linking printf functionality
from RAM code.
Note: For LP ROM prints to work properly, make sure that the LP core boots
from the LP ROM.
config ULP_LP_CORE_MEMPROT
bool "Enable LP Core memory protection (PMP)"
depends on ULP_COPROC_TYPE_LP_CORE && SOC_LP_CORE_HAS_PMP && !ULP_COPROC_RUN_FROM_HP_MEM
default n
help
Configures the LP CPU's PMP entries to enforce memory protection.
LP RAM is split into executable (.text) and data (.data/.bss/stack)
regions. Regions not explicitly permitted are inaccessible.
Not available when "Run LP Core from HP memory" is enabled.
Disable this if you need full control over PMP configuration.

View File

@@ -0,0 +1,36 @@
# Sourced by the ULP coprocessor driver on the HP core, in
# components/ulp/Kconfig. Not named Kconfig, which would also attach it to
# this component and define every option twice.
config ULP_PANIC_OUTPUT_ENABLE
depends on ULP_COPROC_TYPE_LP_CORE && SOC_ULP_LP_UART_SUPPORTED
bool
prompt "Enable panic handler which outputs over LP UART"
default "n"
help
Set this option to enable panic handler functionality. If this option is
enabled then the LP Core will output a panic dump over LP UART,
similar to what the main core does. Output depends on LP UART already being
initialized and configured.
Disabling this option will reduce the LP core binary size by not
linking in panic handler functionality.
config ULP_HP_UART_CONSOLE_PRINT
depends on ULP_COPROC_TYPE_LP_CORE
bool
prompt "Route lp_core_printf to the console HP-UART"
help
Set this option to route lp_core_printf to the console HP-UART.
This allows you to easily view print outputs from the LP core, without
having to connect to the LP-UART. This option comes with the following
limitations:
1. There is no mutual exclusion between the HP-Core and the LP-Core accessing
the HP-UART, which means that if both cores are logging heavily the output
strings might get mangled together.
2. The HP-UART can only work while the HP-Core is running, which means that
if the HP-Core is in deep sleep, the LP-Core will not be able to print to the
console HP-UART.
Due to these limitations it is only recommended to use this option for easy debugging.
For more serious use-cases you should use the LP-UART.

View File

@@ -0,0 +1,21 @@
# What a ULP FSM program is built against.
#
# An FSM program is assembled from the application's own sources, so this
# component carries no sources of its own: it publishes the headers the program
# is written against and the memory layout it is linked with.
idf_build_get_property(target IDF_TARGET)
get_filename_component(ulp_dir "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
idf_component_register(
INCLUDE_DIRS "${ulp_dir}/ulp_common/include"
"${ulp_dir}/ulp_fsm/include"
"${ulp_dir}/ulp_fsm/include/${target}"
REQUIRES soc)
# -D__ASSEMBLER__ keeps the SoC headers to their macro-only form.
set(ulp_ld_flags "-D__ASSEMBLER__ -I\"${CMAKE_CURRENT_SOURCE_DIR}/ld\"")
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/ulp_fsm.ld.in" MEMORY
FLAGS "${ulp_ld_flags}")
target_link_options(${COMPONENT_LIB} INTERFACE "SHELL:-u entry")

View File

@@ -0,0 +1,53 @@
# The code compiled for the ULP RISC-V coprocessor.
#
# Sources shared with the driver stay in components/ulp and are named by path
# from here.
idf_build_get_property(target IDF_TARGET)
get_filename_component(ulp_dir "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
# The ULP subproject in build system v1 adds these sources straight to the
# executable, so a strong handler is not dropped in favour of a weak default
# from another runtime object. WHOLE_ARCHIVE keeps that behaviour here.
idf_component_register(
SRCS "ulp_riscv_vectors.S"
"start.S"
"ulp_riscv_adc.c"
"ulp_riscv_lock.c"
"ulp_riscv_uart.c"
"ulp_riscv_print.c"
"ulp_riscv_i2c.c"
"ulp_riscv_utils.c"
"ulp_riscv_touch.c"
"ulp_riscv_gpio.c"
"ulp_riscv_interrupt.c"
INCLUDE_DIRS "${ulp_dir}/ulp_common/include"
"${ulp_dir}/ulp_riscv/include"
"${ulp_dir}/ulp_riscv/shared/include"
"include"
REQUIRES esp_common
esp_hal_ana_conv
esp_hal_gpio
esp_hal_i2c
esp_hal_touch_sens
esp_hw_support
riscv
soc
WHOLE_ARCHIVE)
# -D__ASSEMBLER__ keeps the SoC headers to their macro-only form.
set(ulp_ld_flags "-D__ASSEMBLER__ -I\"${CMAKE_CURRENT_SOURCE_DIR}/ld\"")
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/ulp_riscv.ld.in" MEMORY
FLAGS "${ulp_ld_flags}")
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/${target}.peripherals.ld")
target_link_options(${COMPONENT_LIB} INTERFACE
-nostartfiles
-Wl,--gc-sections
-Wl,--no-warn-rwx-segments
LINKER:-u,main)
target_compile_definitions(${COMPONENT_LIB} PUBLIC
IS_ULP_COCPU
ULP_RISCV_REGISTER_OPS)

View File

@@ -0,0 +1,20 @@
# Sourced by the ULP coprocessor driver on the HP core, in
# components/ulp/Kconfig. Not named Kconfig, which would also attach it to
# this component and define every option twice.
config ULP_RISCV_INTERRUPT_ENABLE
depends on ULP_COPROC_TYPE_RISCV
bool
prompt "Enable ULP RISC-V interrupts"
default "n"
help
Turn on this setting to enable interrupts on the ULP RISC-V core.
config ULP_RISCV_UART_BAUDRATE
depends on ULP_COPROC_TYPE_RISCV
int
prompt "Baudrate used by the bitbanged ULP RISC-V UART driver"
default 9600
help
The accuracy of the bitbanged UART driver is limited, it is not
recommended to increase the value above 19200.

View File

@@ -80,7 +80,7 @@ r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
/**
* Instruction: retirq
* Description: This instruction copies the value of Q0 to CPU PC, and renables interrupts
* Description: This instruction copies the value of Q0 to CPU PC, and re-enables interrupts
*/
#define retirq_insn() \
r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)

View File

@@ -6,6 +6,11 @@
# ulp_project_default, the ULP analogs of idf_project_init,
# idf_build_executable, idf_build_binary and idf_project_default.
# The components a ULP program is built against live inside this subproject, so
# an application build does not discover them. Added before components are
# searched for.
list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/components")
include(${IDF_PATH}/tools/cmakev2/idf.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/IDFULPProjectCommon.cmake)
@@ -17,6 +22,21 @@ if(__ULP_BUILDV2)
idf_build_set_property(NON_OS_BUILD 1)
endif()
# The component a ULP program of the detected architecture is built against.
function(__ulp_arch_component out_var)
if(BUILD_RISCV)
set(component ulp_riscv)
elseif(BUILD_LP_CORE)
set(component lp_core)
elseif(BUILD_FSM)
set(component ulp_fsm)
else()
idf_die("Unable to determine the ULP type. Set ULP_TYPE to riscv, lp_core or fsm.")
endif()
set(${out_var} "${component}" PARENT_SCOPE)
endfunction()
# Reset the compile/link state inherited from the parent app build and select
# ULP-specific build behavior. Idempotent within a child configure.
function(__ulp_prepare_build)
@@ -44,11 +64,18 @@ function(__ulp_prepare_build)
idf_build_set_property(${property} "")
endforeach()
# Do not apply the default app component closure to ULP child projects.
# ULP components should contribute dependencies explicitly.
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "")
idf_build_set_property(__COMMON_COMPONENT_INTERFACES "")
# A ULP program is built against the component for its architecture, so
# every component of the child gets it without naming it. Nothing else of
# the application component closure applies, and the interfaces are set
# here rather than through __init_common_components, which would also add
# the target's architecture component.
__ulp_arch_component(ulp_component)
idf_component_get_property(ulp_component_interface "${ulp_component}" COMPONENT_INTERFACE)
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${ulp_component}")
idf_build_set_property(__COMMON_COMPONENT_INTERFACES "${ulp_component_interface}")
idf_build_set_property(__COMMON_COMPONENTS_INITIALIZED YES)
idf_component_include("${ulp_component}")
idf_build_set_property(__ULP_BUILD_PREPARED YES)
endfunction()

View File

@@ -2,7 +2,7 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.22)
include(${IDF_PATH}/components/ulp/cmake/ulp_project.cmake)
include(${IDF_PATH}/components/ulp/subproject/ulp_project.cmake)
project(${IDF_DEFAULT_PROJECT_NAME} C CXX ASM)

View File

@@ -1,4 +1,3 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
idf_component_register(SRCS "main.c"
REQUIRES ulp)
idf_component_register(SRCS "main.c")

View File

@@ -22,7 +22,7 @@
* LP UART read_bytes return-value test (HP + LP):
* The burst must fit in the hardware RX FIFO yet typically exceed the LP UART
* driver's default RX FIFO full threshold (LP_UART_FULL_THRESH_DEFAULT in
* components/ulp/lp_core/lp_core/lp_core_uart.c). If either value changes,
* components/ulp/subproject/components/lp_core/lp_core_uart.c). If either value changes,
* revisit this guard.
*/
#if (SOC_LP_UART_FIFO_LEN) < 12

View File

@@ -80,7 +80,7 @@ esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* prog
* 7. .text section
* 8. .data section
*
* Linker script in components/ulp/ld/esp32.ulp.ld produces ELF files which
* Linker script in components/ulp/subproject/components/ulp_fsm/ld/ulp_fsm.ld produces ELF files which
* correspond to this format. This linker script produces binaries with load_addr == 0.
*
* @param load_addr address where the program should be loaded, expressed in 32-bit words

View File

@@ -93,7 +93,7 @@ esp_err_t ulp_riscv_run(void);
* Different than ULP FSM, the binary program has no special format, it is the ELF
* file generated by RISC-V toolchain converted to binary format using objcopy.
*
* Linker script in components/ulp/ld/ulp_riscv.ld produces ELF files which
* Linker script in components/ulp/subproject/components/ulp_riscv/ld/ulp_riscv.ld produces ELF files which
* correspond to this format. This linker script produces binaries with load_addr == 0.
*
* @param program_binary pointer to program binary