Merge branch 'feat/ulp_debug' into 'master'

feat(ulp): Add LP core debugging support

See merge request espressif/esp-idf!31802
This commit is contained in:
Alexey Gerenkov 2024-09-04 22:56:16 +08:00
commit a07eed67ef
17 changed files with 580 additions and 5 deletions

View File

@ -125,6 +125,16 @@ menu "Ultra Low Power (ULP) Co-processor"
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.
config ULP_NORESET_UNDER_DEBUG
bool "Avoid resetting LP core when debugger is attached"
depends on ULP_COPROC_TYPE_LP_CORE
default "y"
help
Enable this feature to avoid resetting LP core in sleep mode when debugger is attached,
otherwise configured HW breakpoints and dcsr.ebreak* bits will be missed.
This is a workaround until it will be fixed in HW.
endmenu
endmenu # Ultra Low Power (ULP) Co-processor

View File

@ -123,7 +123,8 @@ function(ulp_apply_default_sources ulp_app_name)
"${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_i2c.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_spi.c")
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_spi.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_ubsan.c")
set(target_folder ${IDF_TARGET})

View File

@ -9,6 +9,7 @@
#include "soc/soc_caps.h"
#include "esp_log.h"
#include "esp_assert.h"
#include "esp_cpu.h"
#include "soc/pmu_reg.h"
#include "hal/misc.h"
#include "esp_private/periph_ctrl.h"
@ -100,7 +101,9 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg)
lp_core_ll_stall_at_sleep_request(true);
/* Enable reset CPU when going to sleep */
lp_core_ll_rst_at_sleep_enable(true);
/* Avoid resetting chip in sleep mode when debugger is attached,
otherwise configured HW breakpoints and dcsr.ebreak* bits will be missed */
lp_core_ll_rst_at_sleep_enable(!(CONFIG_ULP_NORESET_UNDER_DEBUG && esp_cpu_dbgr_is_attached()));
/* Set wake-up sources */
lp_core_ll_set_wakeup_source(lp_core_get_wakeup_source_hw_flags(cfg->wakeup_source));
@ -161,6 +164,15 @@ esp_err_t ulp_lp_core_load_binary(const uint8_t* program_binary, size_t program_
void ulp_lp_core_stop(void)
{
if (esp_cpu_dbgr_is_attached()) {
/* upon SW reset debugger puts LP core into the infinite loop at reset vector,
so configure it to stall when going to sleep */
lp_core_ll_stall_at_sleep_request(true);
/* Avoid resetting chip in sleep mode when debugger is attached,
otherwise configured HW breakpoints and dcsr.ebreak* bits will be missed */
lp_core_ll_rst_at_sleep_enable(!CONFIG_ULP_NORESET_UNDER_DEBUG);
lp_core_ll_debug_module_enable(true);
}
/* Disable wake-up source and put lp core to sleep */
lp_core_ll_set_wakeup_source(0);
lp_core_ll_request_sleep();

View File

@ -73,6 +73,11 @@ __attribute__((__noreturn__)) void ulp_lp_core_halt(void);
*/
__attribute__((__noreturn__)) void ulp_lp_core_stop_lp_core(void);
/**
* @brief Abort LP core operation.
*/
void __attribute__((noreturn)) ulp_lp_core_abort(void);
/**
* @brief Enable the SW triggered interrupt from the PMU
*

View File

@ -11,6 +11,7 @@
#include "hal/lp_core_ll.h"
#include "riscv/rv_utils.h"
#include "riscv/rvruntime-frames.h"
#include "ulp_lp_core_utils.h"
#if SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR
/* Enable interrupt 30, which all external interrupts are routed to*/
@ -40,12 +41,12 @@ void ulp_lp_core_intr_disable(void)
void __attribute__((weak)) ulp_lp_core_panic_handler(RvExcFrame *frame, int exccause)
{
abort();
ulp_lp_core_abort();
}
static void ulp_lp_core_default_intr_handler(void)
{
abort();
ulp_lp_core_abort();
}
/* Default ISR handlers, intended to be overwritten by users */

View File

@ -0,0 +1,237 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_cpu.h"
#include "ulp_lp_core_print.h"
struct source_location {
const char *file_name;
uint32_t line;
uint32_t column;
};
struct type_descriptor {
uint16_t type_kind;
uint16_t type_info;
char type_name[];
};
struct type_mismatch_data {
struct source_location loc;
struct type_descriptor *type;
unsigned long alignment;
unsigned char type_check_kind;
};
struct type_mismatch_data_v1 {
struct source_location loc;
struct type_descriptor *type;
unsigned char log_alignment;
unsigned char type_check_kind;
};
struct overflow_data {
struct source_location loc;
struct type_descriptor *type;
};
struct shift_out_of_bounds_data {
struct source_location loc;
struct type_descriptor *lhs_type;
struct type_descriptor *rhs_type;
};
struct out_of_bounds_data {
struct source_location loc;
struct type_descriptor *array_type;
struct type_descriptor *index_type;
};
struct unreachable_data {
struct source_location loc;
};
struct vla_bound_data {
struct source_location loc;
struct type_descriptor *type;
};
struct invalid_value_data {
struct source_location loc;
struct type_descriptor *type;
};
struct nonnull_arg_data {
struct source_location loc;
};
struct nonnull_return_data {
struct source_location loc;
struct source_location attr_loc;
};
struct pointer_overflow_data {
struct source_location loc;
};
struct invalid_builtin_data {
struct source_location loc;
unsigned char kind;
};
static void __ubsan_maybe_debugbreak(void)
{
}
__attribute__((noreturn)) static void __ubsan_default_handler(struct source_location *loc, const char *func)
{
#if CONFIG_ULP_PANIC_OUTPUT_ENABLE
lp_core_printf("LP_CORE: Undefined behavior of type '%s' @\r\n"
"%s:%d\r\n", func, loc->file_name, loc->line);
#endif
abort();
}
void __ubsan_handle_type_mismatch(void *data_,
void *ptr_)
{
struct type_mismatch_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_type_mismatch_v1(void *data_,
void *ptr)
{
struct type_mismatch_data_v1 *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_add_overflow(void *data_,
void *lhs_,
void *rhs_)
{
struct overflow_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_sub_overflow(void *data_,
void *lhs_,
void *rhs_)
{
struct overflow_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_mul_overflow(void *data_,
void *lhs_,
void *rhs_)
{
struct overflow_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_negate_overflow(void *data_,
void *old_val_)
{
struct overflow_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_divrem_overflow(void *data_,
void *lhs_,
void *rhs_)
{
struct overflow_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_shift_out_of_bounds(void *data_,
void *lhs_,
void *rhs_)
{
struct shift_out_of_bounds_data *data = data_;
unsigned int rhs = (unsigned int)rhs_;
if (rhs == 32) {
return;
}
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_out_of_bounds(void *data_,
void *idx_)
{
struct out_of_bounds_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_missing_return(void *data_)
{
struct unreachable_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_vla_bound_not_positive(void *data_,
void *bound_)
{
struct vla_bound_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_load_invalid_value(void *data_,
void *val_)
{
struct invalid_value_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_nonnull_arg(void *data_)
{
struct nonnull_arg_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_nonnull_return(void *data_)
{
struct nonnull_return_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_builtin_unreachable(void *data_)
{
struct unreachable_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_pointer_overflow(void *data_,
void *base_,
void *result_)
{
struct pointer_overflow_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}
void __ubsan_handle_invalid_builtin(void *data_)
{
struct invalid_builtin_data *data = data_;
__ubsan_maybe_debugbreak();
__ubsan_default_handler(&data->loc, __func__);
}

View File

@ -27,6 +27,8 @@
#include "hal/lp_timer_ll.h"
#endif
#include "esp_cpu.h"
/* LP_FAST_CLK is not very accurate, for now use a rough estimate */
#define LP_CORE_CPU_FREQUENCY_HZ 16000000 // For P4 TRM says 20 MHz by default, but we tune it closer to 16 MHz
@ -137,6 +139,16 @@ void ulp_lp_core_stop_lp_core(void)
}
void __attribute__((noreturn)) abort(void)
{
// By calling abort users expect some panic message to be printed,
// so cause an exception like it is done in HP core's version of abort().
// If CONFIG_ULP_PANIC_OUTPUT_ENABLE is YES then panic handler will print smth
// If debugger is attached it will stop here and user can inspect the backtrace.
esp_cpu_dbgr_break();
while (1); // to make compiler happy about noreturn attr
}
void __attribute__((noreturn)) ulp_lp_core_abort(void)
{
/* Stop the LP Core */
ulp_lp_core_stop_lp_core();

View File

@ -279,6 +279,77 @@ When programming the LP-Core, it can sometimes be challenging to figure out why
python -m esp_idf_monitor --toolchain-prefix riscv32-esp-elf- --target {IDF_TARGET_NAME} --decode-panic backtrace PATH_TO_ULP_ELF_FILE
Debugging ULP LP-Core Applications with GDB and OpenOCD
-------------------------------------------------------
It is also possible to debug code running on LP core using GDB and OpenOCD as you usually do for HP cores, but it has some specifics and limitations.
Debugging Session
~~~~~~~~~~~~~~~~~
Run OpenOCD with special config file for LP core debugging support. And then run GDB with special ``gdbinit`` file.
.. code-block:: bash
openocd -f board/{IDF_TARGET_PATH_NAME}-lpcore-builtin.cfg
riscv32-esp-elf-gdb -x gdbinit <path to main program ELF>
``gdbinit`` file contents with inline comments is below. For more details see the next section.
.. code-block:: bash
# connect to target
target extended-remote :3333
# reset chip
mon reset halt
maintenance flush register-cache
# add symbols and debugging info for ULP program
add-symbol <path to ULP program ELF>
# temporary HW breakpoint to setup breakpoints
# if you need more than HW supports
thb main
commands
# set breakpoints here
# At this moment ULP program is loaded into RAM and when there are
# no free HW breakpoints slots available GDB will set SW ones
b func1
b func2
b func3
# resume execution
c
end
# start main program after reset
c
LP Core Debugging Specifics
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. list::
#. For convenient debugging you may need to add `-O0` compile option for ULP app in its CMakeLists.txt. See :example:`system/ulp/lp_core/debugging/` how to do this.
:not esp32p4: #. LP core supports limited set of HW exceptions, so, for example, writing at address `0x0` will not cause a panic as it would be for the code running on HP core. This can be overcome to some extent by enabling undefined behavior sanitizer for LP core application, so `ubsan` can help to catch some errors. But note that it will increase code size significantly and it can happen that application won't fit into RTC RAM. To enable `ubsan` for ULP app add `-fsanitize=undefined -fno-sanitize=shift-base` compile option to its CMakeLists.txt. See :example:`system/ulp/lp_core/debugging/` how to do this.
#. To be able to debug program running on LP core debug info and symbols need to be loaded to GDB. It can be done via GDB command line or in ``gdbinit`` file. See section above.
#. Upon startup LP core application is loaded into RAM, so all SW breakpoints set before that moment will get overwritten. The best moment to set breakpoints for LP core application is to do this when LP core program reaches `main` function.
#. When using IDEs it can be that it does not support breakpoint actions/commands configuration shown in ``gdbinit`` above, so in this case you have to preset all breakpoints before debug session start and disable all of them except for ``main``. When program is stopped at ``main`` manually enable remaining breakpoints and resume execution.
Limitations
~~~~~~~~~~~
#. Currently debugging is not supported when either HP or LP core enters any sleep mode. So it limits available debugging scenarios.
#. FreeRTOS support in OpenOCD is disabled when debugging LP core, so you won't be able to see tasks running in the system. Instead there will be several threads representing HP and LP cores:
.. code-block:: bash
(gdb) info thread
Id Target Id Frame
1 Thread 1 "{IDF_TARGET_PATH_NAME}.cpu0" (Name: {IDF_TARGET_PATH_NAME}.cpu0, state: debug-request) 0x40803772 in esp_cpu_wait_for_intr ()
at /home/user/projects/esp/esp-idf/components/esp_hw_support/cpu.c:64
* 2 Thread 2 "{IDF_TARGET_PATH_NAME}.cpu1" (Name: {IDF_TARGET_PATH_NAME}.cpu1, state: breakpoint) do_things (max=1000000000)
at /home/user/projects/esp/esp-idf/examples/system/ulp/lp_core/debugging/main/lp_core/main.c:21
#. When setting HW breakpoint in GDB it is set on both cores, so the number of available HW breakpoints is limited to the number of them supported by LP core ({IDF_TARGET_SOC_CPU_BREAKPOINTS_NUM} for {IDF_TARGET_NAME}).
#. OpenOCD flash support is disabled. It does not matter for LP core application because it is run completely from RAM and GDB can use SW breakpoints for it. But if you want to set a breakpoint on function from flash used by the code running on HP core (e.g. `app_main`) you should request to set HW breakpoint explicitly via ``hb`` / ``thb`` GDB commands.
#. Since main and ULP programs are linked as separate binaries it is possible for them to have global symbols (functions, variables) with the same name. When you set breakpoint for such a functions using its name GDB will set breakpoints for all of them. It could lead to the problems when one of the function is located in the flash because currently flash support is disabled in OpenOCD when debugging LP core. In that case you can use source line or address based breakpoints.
Application Examples
--------------------
@ -294,10 +365,10 @@ Application Examples
* :example:`system/ulp/lp_core/lp_uart/lp_uart_print` shows how to print various statements from a program running on the LP core.
* :example:`system/ulp/lp_core/interrupt` shows how to register an interrupt handler on the LP core to receive an interrupt triggered by the main CPU.
* :example:`system/ulp/lp_core/gpio_intr_pulse_counter` shows how to use GPIO interrupts to count pulses while the main CPU is in Deep-sleep mode.
* :example:`system/ulp/lp_core/build_system/` demonstrates how to include custom ``CMakeLists.txt`` file for the ULP app.
* :example:`system/ulp/lp_core/debugging` shows how to debug code running on LP core using GDB and OpenOCD.
API Reference
-------------

View File

@ -285,6 +285,12 @@ examples/system/ulp/lp_core/build_system:
depends_components:
- ulp
examples/system/ulp/lp_core/debugging:
enable:
- if: SOC_LP_CORE_SUPPORTED == 1
depends_components:
- ulp
examples/system/ulp/lp_core/gpio:
disable:
- if: SOC_DEEP_SLEEP_SUPPORTED != 1

View File

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

View File

@ -0,0 +1,77 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-P4 |
| ----------------- | -------- | -------- | -------- |
# LP Core Debugging Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## Overview
This example demonstrates how to debug application running on the LP core.
## How to use example
### Hardware Required
To run this example, you should have an ESP32-C6 based development board.
### Build and Flash
Enter `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Debugging Session
1) Run OpenOCD `openocd -f board/esp32c6-lpcore-builtin.cfg`.
2) Run GDB `riscv32-esp-elf-gdb -x gdbinit build/lp_debugging_example.elf`
3) `gdbinit` file will tell GDB to load debug info and symbols and set a number of breakpoints.
4) Type `c` upon hitting every breakpoint.
5) Finally LP core application should stop in `abort()`.
### LP Core Debugging Specifics
1) Add `-O0` compile option for ULP app in its CMakeLists.txt.
```
target_compile_options(${ULP_APP_NAME} PRIVATE -O0)
```
2) LP core supports limited set of HW exceptions, so, for example, writing at address `0x0` will not cause a panic as it would be for the code running on HP core. This can be overcome to some extent by enabling undefined behavior sanitizer for LP core application, so `ubsan` can help to catch some errors. But note that it will increase code size significantly and it can happen that application won't fit into RTC RAM. To enable `ubsan` for ULP app add `-fsanitize=undefined -fno-sanitize=shift-base` compile option to its CMakeLists.txt.
```
target_compile_options(${ULP_APP_NAME} PRIVATE -fsanitize=undefined -fno-sanitize=shift-base)
```
3) To be able to debug program running on LP core debug info and symbols need to be loaded to GDB. So there is special GDB command in `gdbinit`:
```
add-symbol build/esp-idf/main/ulp_debug_example/ulp_debug_example.elf
```
4) Upon startup LP core application is loaded into RAM, so all SW breakpoints set before that moment will get overwritten. The best moment to set breakpoints for LP core application is to do this when LP core program reaches `main` function. So `gdbinit` file used in this example sets temporary HW breakpoint on `main` and then set a bunch of other breakpoints when it hit.
```
thb main
commands
b main
b do_crash
b do_things
b ulp_lp_core_delay_us
c
end
```
## Limitations
1) Currently debugging is not supported when either HP or LP core enters any sleep mode. So this limits debugging scenarios.
2) FreeRTOS support in OpenOCD is disabled when debugging LP core, so you won't be able to see tasks running in the system. Instead there will be two threads representing HP ('esp32c6.cpu0') and LP ('esp32c6.cpu1') cores:
```
(gdb) info thread
Id Target Id Frame
1 Thread 1 "esp32c6.cpu0" (Name: esp32c6.cpu0, state: debug-request) 0x40803772 in esp_cpu_wait_for_intr ()
at /home/user/projects/esp/esp-idf/components/esp_hw_support/cpu.c:64
* 2 Thread 2 "esp32c6.cpu1" (Name: esp32c6.cpu1, state: breakpoint) do_things (max=1000000000)
at /home/user/projects/esp/esp-idf/examples/system/ulp/lp_core/debugging/main/lp_core/main.c:21
```
3) When setting HW breakpoint in GDB it is set on both cores, so the number of available HW breakpoints is limited to the number of them supported by LP core (2 for ESP32-C6).
4) OpenOCD flash support is disabled. It does not matter for LP core application because it is run completely from RAM and GDB can use SW breakpoints for it. But if you want to set a breakpoint on function from flash used by the code running on HP core (e.g. `app_main`) you should request to set HW breakpoint explicitly via `hb`/`thb` GDB commands.
## Troubleshooting
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View File

@ -0,0 +1,16 @@
set pagination off
target extended-remote :3333
mon reset halt
maintenance flush register-cache
add-symbol build/esp-idf/main/ulp_debug_example/ulp_debug_example.elf
thb main
commands
b do_crash
b do_things
b ulp_lp_core_delay_us
c
end
c

View File

@ -0,0 +1,8 @@
# Set usual component variables
set(app_sources "lp_debug_main.c")
idf_component_register(SRCS ${app_sources}
REQUIRES ulp
WHOLE_ARCHIVE)
ulp_add_project("ulp_debug_example" "${CMAKE_SOURCE_DIR}/main/ulp/")

View File

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "esp_sleep.h"
#include "esp_err.h"
#include "ulp_lp_core.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
extern const uint8_t ulp_build_debug_bin_start[] asm("_binary_ulp_debug_example_bin_start");
extern const uint8_t ulp_build_debug_bin_end[] asm("_binary_ulp_debug_example_bin_end");
static void lp_core_init(void)
{
/* Set LP core wakeup source as the HP CPU */
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,
};
/* Load LP core firmware */
ESP_ERROR_CHECK(ulp_lp_core_load_binary(ulp_build_debug_bin_start, (ulp_build_debug_bin_end - ulp_build_debug_bin_start)));
/* Run LP core */
ESP_ERROR_CHECK(ulp_lp_core_run(&cfg));
printf("LP core loaded with firmware and running successfully\n");
}
void app_main(void)
{
printf("Initializing LP core...\n");
/* Load LP Core binary and start the coprocessor */
lp_core_init();
printf("Do some work on HP core...\n");
while(1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

View File

@ -0,0 +1,31 @@
# This CMakelists.txt is included in the ULP project
# so we have access to the ULP target: ULP_APP_NAME
cmake_minimum_required(VERSION 3.16)
# Project/target name is passed from the main project to allow IDF to have a dependency on this target
# as well as embed the binary into the main app
project(${ULP_APP_NAME})
add_executable(${ULP_APP_NAME} main.c)
# Import the ULP project helper functions
include(IDFULPProject)
# Apply default compile options
ulp_apply_default_options(${ULP_APP_NAME})
# Apply default sources provided by the IDF ULP component
ulp_apply_default_sources(${ULP_APP_NAME})
# Add targets for building the binary, as well as the linkerscript which exports ULP shared variables to the main app
ulp_add_build_binary_targets(${ULP_APP_NAME})
# Set custom compile flags
# By default ULP sources are compiled with -Os which is set in toolchain file in IDF build system.
# These options will appear on command line after default ones effectively overriding them.
# Therefore '-Os' will be overridden with '-O0' for this example for convenient debugging.
target_compile_options(${ULP_APP_NAME} PRIVATE -O0 -fsanitize=undefined -fno-sanitize=shift-base)

View File

@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ulp_lp_core_utils.h"
void do_crash(void)
{
volatile int *p = (int *)0x0;
// if ubsan is enabled (-fsanitize=undefined) line below will cause ubsan check failure
// and finally app will be stopped in abort()
*p = 32;
// if ubsan is disabled app will be stopped in abort() call below
abort();
}
void do_things(int max)
{
while (1) {
for (int i = 0; i < max; i++) {
ulp_lp_core_delay_us(100000);
if (i > 0)
do_crash();
}
}
}
int main (void)
{
do_things(1000000000);
return 0;
}

View File

@ -0,0 +1,4 @@
# Enable LP Core
CONFIG_ULP_COPROC_ENABLED=y
CONFIG_ULP_COPROC_TYPE_LP_CORE=y
CONFIG_ULP_COPROC_RESERVE_MEM=14000