diff --git a/components/app_trace/CMakeLists.txt b/components/app_trace/CMakeLists.txt index 5fe8572319a..716d83bfab7 100644 --- a/components/app_trace/CMakeLists.txt +++ b/components/app_trace/CMakeLists.txt @@ -4,10 +4,26 @@ if(${target} STREQUAL "linux") return() # This component is not supported by the POSIX/Linux simulator endif() -set(srcs - "app_trace.c" - "app_trace_util.c" - "host_file_io.c") +if(CONFIG_APPTRACE_ENABLE) + set(srcs + "app_trace.c" + "app_trace_util.c" + "host_file_io.c" + ) + + if(NOT CONFIG_APPTRACE_DEST_UART) # JTAG or ALL + if(CONFIG_IDF_TARGET_ARCH_XTENSA) + list(APPEND srcs "port/xtensa/port_jtag.c") + elseif(CONFIG_IDF_TARGET_ARCH_RISCV) + list(APPEND srcs "port/riscv/port_jtag.c") + endif() + list(APPEND srcs "app_trace_membufs_proto.c") + endif() + + if(NOT CONFIG_APPTRACE_DEST_JTAG) # UART or ALL + list(APPEND srcs "port/port_uart.c") + endif() +endif() if(CONFIG_ESP_DEBUG_STUBS_ENABLE) list(APPEND srcs "debug_stubs.c") @@ -17,23 +33,6 @@ set(include_dirs "include") set(priv_include_dirs "private_include" "port/include") -if(CONFIG_APPTRACE_MEMBUFS_APPTRACE_PROTO_ENABLE) - list(APPEND srcs "app_trace_membufs_proto.c") -endif() - -if(CONFIG_APPTRACE_DEST_JTAG) - if(CONFIG_IDF_TARGET_ARCH_XTENSA) - list(APPEND srcs "port/xtensa/port_jtag.c") - endif() - if(CONFIG_IDF_TARGET_ARCH_RISCV) - list(APPEND srcs "port/riscv/port_jtag.c") - endif() -endif() - -if(CONFIG_APPTRACE_DEST_UART) - list(APPEND srcs "port/port_uart.c") -endif() - if(CONFIG_APPTRACE_SV_ENABLE) list(APPEND include_dirs sys_view/Config @@ -59,6 +58,6 @@ endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" PRIV_INCLUDE_DIRS "${priv_include_dirs}" - PRIV_REQUIRES esp_driver_gptimer esp_driver_gpio esp_driver_uart - REQUIRES esp_timer + PRIV_REQUIRES esp_driver_gptimer + REQUIRES esp_timer esp_driver_uart LDFRAGMENTS linker.lf) diff --git a/components/app_trace/Kconfig b/components/app_trace/Kconfig index f6147d023c2..3bf90245003 100644 --- a/components/app_trace/Kconfig +++ b/components/app_trace/Kconfig @@ -1,36 +1,50 @@ menu "Application Level Tracing" - choice APPTRACE_DESTINATION1 - prompt "Data Destination 1" - default APPTRACE_DEST_NONE + config APPTRACE_ENABLE + bool "Enable Application Level Tracing" + default n help - Select destination for application trace: JTAG or none (to disable). + Enables/disable application tracing module. + This must be enabled to use any tracing library. + + choice APPTRACE_DESTINATION + prompt "Data Destination" + default APPTRACE_DEST_JTAG if !PM_ENABLE + default APPTRACE_DEST_UART if PM_ENABLE + depends on APPTRACE_ENABLE + help + Select destination for application trace: JTAG or UART. + When SystemView is enabled, this also controls the SystemView destination. config APPTRACE_DEST_JTAG bool "JTAG" select APPTRACE_TRAX_ENABLE if IDF_TARGET_ARCH_XTENSA - select APPTRACE_MEMBUFS_APPTRACE_PROTO_ENABLE - select APPTRACE_ENABLE - - config APPTRACE_DEST_NONE - bool "None" - - endchoice - - choice APPTRACE_DESTINATION2 - prompt "Data Destination 2" - default APPTRACE_DEST_UART_NONE - help - Select destination for application trace: UART or none (to disable). + depends on !PM_ENABLE config APPTRACE_DEST_UART bool "UART" - select APPTRACE_ENABLE - config APPTRACE_DEST_UART_NONE - bool "None" + config APPTRACE_DEST_NONE + bool "None (runtime selection)" + help + Compile both JTAG and UART interfaces. Increases IRAM usage. + Allows runtime selection via esp_apptrace_get_user_params(). + + With this option, destination and configuration must be provided + at runtime. Default JTAG and UART settings are defined in + components/app_trace/include/esp_app_trace_config.h. + + Override these by implementing esp_apptrace_get_user_params() + in your application. endchoice + config APPTRACE_BUF_SIZE + int "Size of the apptrace buffer" + depends on APPTRACE_DEST_JTAG && !APPTRACE_TRAX_ENABLE + default 16384 + help + Size of the memory buffer for trace data in bytes. + config APPTRACE_DEST_UART_NUM int "UART port number" depends on APPTRACE_DEST_UART @@ -107,6 +121,7 @@ menu "Application Level Tracing" config APPTRACE_UART_TASK_PRIO int prompt "UART Task Priority" if APPTRACE_DEST_UART + depends on APPTRACE_DEST_UART default 1 range 1 32 help @@ -126,23 +141,13 @@ menu "Application Level Tracing" help Enables/disable TRAX tracing HW. - config APPTRACE_MEMBUFS_APPTRACE_PROTO_ENABLE - bool - default n - help - Enables/disable swapping memory buffers tracing protocol. - - config APPTRACE_ENABLE - bool - default n - help - Enables/disable application tracing module. - config APPTRACE_LOCK_ENABLE - bool - default !APPTRACE_SV_ENABLE + bool "Internal Sync Lock Enable" + depends on APPTRACE_ENABLE + default n help Enables/disable application tracing module internal sync lock. + Keep in mind this will slow down the trace data transfer to the host. config APPTRACE_ONPANIC_HOST_FLUSH_TMO int "Timeout for flushing last trace data to host on panic" @@ -162,13 +167,6 @@ menu "Application Level Tracing" Threshold for flushing last trace data to host on panic in post-mortem mode. This is minimal amount of data needed to perform flush. In bytes. - config APPTRACE_BUF_SIZE - int "Size of the apptrace buffer" - depends on APPTRACE_MEMBUFS_APPTRACE_PROTO_ENABLE && !APPTRACE_TRAX_ENABLE - default 16384 - help - Size of the memory buffer for trace data in bytes. - menu "FreeRTOS SystemView Tracing" depends on APPTRACE_ENABLE config APPTRACE_SV_ENABLE @@ -178,30 +176,9 @@ menu "Application Level Tracing" help Enables support for SEGGER SystemView tracing functionality. - choice APPTRACE_SV_DEST - prompt "SystemView destination" - depends on APPTRACE_SV_ENABLE - default APPTRACE_SV_DEST_JTAG - help - SystemView will transfer data through the defined interface. - - config APPTRACE_SV_DEST_JTAG - bool "Data destination JTAG" - depends on !PM_ENABLE && !APPTRACE_DEST_NONE - help - Send SEGGER SystemView events through JTAG interface. - - config APPTRACE_SV_DEST_UART - bool "Data destination UART" - depends on APPTRACE_DEST_UART - help - Send SEGGER SystemView events through UART interface. - - endchoice - choice APPTRACE_SV_CPU prompt "CPU to trace" - depends on APPTRACE_SV_DEST_UART && !ESP_SYSTEM_SINGLE_CORE_MODE + depends on APPTRACE_SV_ENABLE && APPTRACE_DEST_UART && !ESP_SYSTEM_SINGLE_CORE_MODE default APPTRACE_SV_DEST_CPU_0 help Define the CPU to trace by SystemView. @@ -218,7 +195,6 @@ menu "Application Level Tracing" endchoice - choice APPTRACE_SV_TS_SOURCE prompt "Timer to use as timestamp source" depends on APPTRACE_SV_ENABLE diff --git a/components/app_trace/app_trace.c b/components/app_trace/app_trace.c index d18e0427c8b..cb8bb2b49df 100644 --- a/components/app_trace/app_trace.c +++ b/components/app_trace/app_trace.c @@ -7,8 +7,10 @@ #include #include "esp_cpu.h" #include "esp_log.h" +#include "esp_rom_sys.h" #include "esp_app_trace.h" #include "esp_app_trace_port.h" +#include "esp_app_trace_types.h" #include "esp_private/startup_internal.h" #if CONFIG_ESP_CONSOLE_UART && CONFIG_APPTRACE_DEST_UART && (CONFIG_APPTRACE_DEST_UART_NUM == CONFIG_ESP_CONSOLE_UART_NUM) @@ -24,257 +26,205 @@ const static char *TAG = "esp_apptrace"; typedef struct { esp_apptrace_hw_t *hw; void *hw_data; + esp_apptrace_dest_t dest; } esp_apptrace_channel_t; -static esp_apptrace_channel_t s_trace_channels[ESP_APPTRACE_DEST_MAX]; -static bool s_inited; +static esp_apptrace_channel_t s_trace_ch; +static volatile int s_trace_ch_hw_initialized = 0; -esp_err_t esp_apptrace_init(void) +static esp_err_t esp_apptrace_init(const esp_apptrace_config_t *config) { __attribute__((unused)) void *hw_data = NULL; - // 'esp_apptrace_init()' is called on every core, so ensure to do main initialization only once if (esp_cpu_get_core_id() == 0) { - memset(&s_trace_channels, 0, sizeof(s_trace_channels)); #if CONFIG_APPTRACE_DEST_JTAG - s_trace_channels[ESP_APPTRACE_DEST_JTAG].hw = esp_apptrace_jtag_hw_get(&hw_data); - s_trace_channels[ESP_APPTRACE_DEST_JTAG].hw_data = hw_data; + s_trace_ch.hw = esp_apptrace_jtag_hw_get(&hw_data); + s_trace_ch.hw_data = hw_data; +#elif CONFIG_APPTRACE_DEST_UART + const esp_apptrace_uart_config_t *uart_config = &config->dest_cfg.uart; + s_trace_ch.hw = esp_apptrace_uart_hw_get(uart_config->uart_num, &hw_data); + s_trace_ch.hw_data = hw_data; +#else // CONFIG_APPTRACE_DEST_NONE allows runtime selection + if (config->dest == ESP_APPTRACE_DEST_JTAG) { + s_trace_ch.hw = esp_apptrace_jtag_hw_get(&hw_data); + s_trace_ch.hw_data = hw_data; + } else if (config->dest == ESP_APPTRACE_DEST_UART) { + const esp_apptrace_uart_config_t *uart_config = &config->dest_cfg.uart; + s_trace_ch.hw = esp_apptrace_uart_hw_get(uart_config->uart_num, &hw_data); + s_trace_ch.hw_data = hw_data; + } else { + s_trace_ch.hw = NULL; + s_trace_ch.hw_data = NULL; + ESP_APPTRACE_LOGE("Invalid destination type (%d)!", config->dest); + return ESP_ERR_INVALID_ARG; + } #endif -#if CONFIG_APPTRACE_DEST_UART - s_trace_channels[ESP_APPTRACE_DEST_UART].hw = esp_apptrace_uart_hw_get(CONFIG_APPTRACE_DEST_UART_NUM, &hw_data); - s_trace_channels[ESP_APPTRACE_DEST_UART].hw_data = hw_data; -#endif - s_inited = true; + s_trace_ch.dest = config->dest; + s_trace_ch_hw_initialized = 1; + } else { + // There is NO guarantee that system init functions will execute on core 0 first + // So we need to wait for core 0 to set up the hardware interface + while (!s_trace_ch_hw_initialized) { + esp_rom_delay_us(10); + } } - // esp_apptrace_init() is called on every core, so initialize trace channel on every core - for (int i = 0; i < sizeof(s_trace_channels) / sizeof(s_trace_channels[0]); i++) { - esp_apptrace_channel_t *ch = &s_trace_channels[i]; - if (ch->hw) { - int res = ch->hw->init(ch->hw_data); - if (res != ESP_OK) { - ESP_APPTRACE_LOGE("Failed to init trace channel HW interface (%d)!", res); - return res; - } + if (s_trace_ch.hw) { + int res = s_trace_ch.hw->init(s_trace_ch.hw_data, config); + if (res != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to init trace channel HW interface (%d)!", res); + return res; } } return ESP_OK; } -ESP_SYSTEM_INIT_FN(esp_apptrace_init, SECONDARY, ESP_SYSTEM_INIT_ALL_CORES, 115) +esp_err_t esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size) { - return esp_apptrace_init(); -} - -esp_err_t esp_apptrace_down_buffer_config(esp_apptrace_dest_t dest, uint8_t *buf, uint32_t size) -{ - esp_apptrace_channel_t *ch; - - if (dest >= ESP_APPTRACE_DEST_MAX) { + if (!buf || size == 0) { return ESP_ERR_INVALID_ARG; } - if (buf == NULL || size == 0) { - return ESP_ERR_INVALID_ARG; - } - if (!s_inited) { + if (!s_trace_ch.hw) { return ESP_ERR_INVALID_STATE; } - - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return ESP_FAIL; - } - if (ch->hw->down_buffer_config != NULL) { - ch->hw->down_buffer_config(ch->hw_data, buf, size); + if (s_trace_ch.hw->down_buffer_config) { + s_trace_ch.hw->down_buffer_config(s_trace_ch.hw_data, buf, size); } return ESP_OK; } -uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size, uint32_t user_tmo) +uint8_t *esp_apptrace_down_buffer_get(uint32_t *size, uint32_t user_tmo) { - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { + + if (!size || *size == 0) { return NULL; } - if (size == NULL || *size == 0) { + if (!s_trace_ch.hw) { return NULL; } - if (!s_inited) { - return NULL; - } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return NULL; - } - if (ch->hw->get_down_buffer == NULL) { + if (!s_trace_ch.hw->get_down_buffer) { return NULL; } + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, user_tmo); - return ch->hw->get_down_buffer(ch->hw_data, size, &tmo); + + return s_trace_ch.hw->get_down_buffer(s_trace_ch.hw_data, size, &tmo); } -esp_err_t esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t user_tmo) +esp_err_t esp_apptrace_down_buffer_put(uint8_t *ptr, uint32_t user_tmo) { - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { + + if (!ptr) { return ESP_ERR_INVALID_ARG; } - if (ptr == NULL) { - return ESP_ERR_INVALID_ARG; - } - if (!s_inited) { + if (!s_trace_ch.hw) { return ESP_ERR_INVALID_STATE; } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return ESP_ERR_NOT_SUPPORTED; - } - if (ch->hw->get_down_buffer == NULL) { + if (!s_trace_ch.hw->get_down_buffer) { return ESP_ERR_NOT_SUPPORTED; } + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, user_tmo); - return ch->hw->put_down_buffer(ch->hw_data, ptr, &tmo); + + return s_trace_ch.hw->put_down_buffer(s_trace_ch.hw_data, ptr, &tmo); } -esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *buf, uint32_t *size, uint32_t user_tmo) +esp_err_t esp_apptrace_read(void *buf, uint32_t *size, uint32_t user_tmo) { - int res = ESP_OK; - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { + + if (!buf || !size || *size == 0) { return ESP_ERR_INVALID_ARG; } - if (buf == NULL || size == NULL || *size == 0) { - return ESP_ERR_INVALID_ARG; - } - if (!s_inited) { + if (!s_trace_ch.hw) { return ESP_ERR_INVALID_STATE; } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return ESP_ERR_NOT_SUPPORTED; - } - if (ch->hw->get_down_buffer == NULL || ch->hw->put_down_buffer == NULL) { + if (!s_trace_ch.hw->get_down_buffer || !s_trace_ch.hw->put_down_buffer) { return ESP_ERR_NOT_SUPPORTED; } //TODO: callback system + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, user_tmo); + uint32_t act_sz = *size; *size = 0; - uint8_t *ptr = ch->hw->get_down_buffer(ch->hw_data, &act_sz, &tmo); + uint8_t *ptr = s_trace_ch.hw->get_down_buffer(s_trace_ch.hw_data, &act_sz, &tmo); if (ptr && act_sz > 0) { ESP_APPTRACE_LOGD("Read %" PRIu32 " bytes from host", act_sz); memcpy(buf, ptr, act_sz); - res = ch->hw->put_down_buffer(ch->hw_data, ptr, &tmo); *size = act_sz; - } else { - res = ESP_ERR_TIMEOUT; + return s_trace_ch.hw->put_down_buffer(s_trace_ch.hw_data, ptr, &tmo); } - return res; + return ESP_ERR_TIMEOUT; } -uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32_t user_tmo) +uint8_t *esp_apptrace_buffer_get(uint32_t size, uint32_t user_tmo) { - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { - return NULL; - } + if (size == 0) { return NULL; } - if (!s_inited) { + if (!s_trace_ch.hw) { return NULL; } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return NULL; - } - if (ch->hw->get_up_buffer == NULL) { + if (!s_trace_ch.hw->get_up_buffer) { return NULL; } + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, user_tmo); - return ch->hw->get_up_buffer(ch->hw_data, size, &tmo); + + return s_trace_ch.hw->get_up_buffer(s_trace_ch.hw_data, size, &tmo); } -esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t user_tmo) +esp_err_t esp_apptrace_buffer_put(uint8_t *ptr, uint32_t user_tmo) { - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { + + if (!ptr) { return ESP_ERR_INVALID_ARG; } - if (ptr == NULL) { - return ESP_ERR_INVALID_ARG; - } - if (!s_inited) { + if (!s_trace_ch.hw) { return ESP_ERR_INVALID_STATE; } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return ESP_ERR_NOT_SUPPORTED; - } - if (ch->hw->put_up_buffer == NULL) { + if (!s_trace_ch.hw->put_up_buffer) { return ESP_ERR_NOT_SUPPORTED; } + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, user_tmo); - return ch->hw->put_up_buffer(ch->hw_data, ptr, &tmo); + + return s_trace_ch.hw->put_up_buffer(s_trace_ch.hw_data, ptr, &tmo); } -esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_t size, uint32_t user_tmo) +esp_err_t esp_apptrace_write(const void *data, uint32_t size, uint32_t user_tmo) { - uint8_t *ptr = NULL; - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { + + if (!data || size == 0) { return ESP_ERR_INVALID_ARG; } - if (data == NULL || size == 0) { - return ESP_ERR_INVALID_ARG; - } - if (!s_inited) { + if (!s_trace_ch.hw) { return ESP_ERR_INVALID_STATE; } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return ESP_ERR_NOT_SUPPORTED; - } - if (ch->hw->get_up_buffer == NULL || ch->hw->put_up_buffer == NULL) { + if (!s_trace_ch.hw->get_up_buffer || !s_trace_ch.hw->put_up_buffer) { return ESP_ERR_NOT_SUPPORTED; } + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, user_tmo); - ptr = ch->hw->get_up_buffer(ch->hw_data, size, &tmo); - if (ptr == NULL) { + + uint8_t *ptr = s_trace_ch.hw->get_up_buffer(s_trace_ch.hw_data, size, &tmo); + if (!ptr) { return ESP_ERR_NO_MEM; } @@ -283,36 +233,29 @@ esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_ memcpy(ptr, data, size); // now indicate that this buffer is ready to be sent off to host - return ch->hw->put_up_buffer(ch->hw_data, ptr, &tmo); + return s_trace_ch.hw->put_up_buffer(s_trace_ch.hw_data, ptr, &tmo); } -int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const char *fmt, va_list ap) +int esp_apptrace_vprintf_to(uint32_t user_tmo, const char *fmt, va_list ap) { uint16_t nargs = 0; uint8_t *pout, *p = (uint8_t *)fmt; - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { + + if (!fmt) { return -1; } - if (fmt == NULL) { + if (!s_trace_ch.hw) { return -1; } - if (!s_inited) { - return -1; - } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return -1; - } - if (ch->hw->get_up_buffer == NULL || ch->hw->put_up_buffer == NULL) { + if (!s_trace_ch.hw->get_up_buffer || !s_trace_ch.hw->put_up_buffer) { return -1; } + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, user_tmo); + ESP_APPTRACE_LOGD("fmt %p", fmt); while ((p = (uint8_t *)strchr((char *)p, '%')) && nargs < ESP_APPTRACE_MAX_VPRINTF_ARGS) { p++; @@ -325,8 +268,8 @@ int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const c ESP_APPTRACE_LOGE("Failed to store all printf args!"); } - pout = ch->hw->get_up_buffer(ch->hw_data, 1 + sizeof(char *) + nargs * sizeof(uint32_t), &tmo); - if (pout == NULL) { + pout = s_trace_ch.hw->get_up_buffer(s_trace_ch.hw_data, 1 + sizeof(char *) + nargs * sizeof(uint32_t), &tmo); + if (!pout) { ESP_APPTRACE_LOGE("Failed to get buffer!"); return -1; } @@ -342,7 +285,7 @@ int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const c ESP_APPTRACE_LOGD("arg %" PRIx32, arg); } - int ret = ch->hw->put_up_buffer(ch->hw_data, p, &tmo); + int ret = s_trace_ch.hw->put_up_buffer(s_trace_ch.hw_data, p, &tmo); if (ret != ESP_OK) { ESP_APPTRACE_LOGE("Failed to put printf buf (%d)!", ret); return -1; @@ -353,78 +296,81 @@ int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const c int esp_apptrace_vprintf(const char *fmt, va_list ap) { - return esp_apptrace_vprintf_to(ESP_APPTRACE_DEST_JTAG, 0, fmt, ap); + return esp_apptrace_vprintf_to(0, fmt, ap); } -esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, uint32_t usr_tmo) +esp_err_t esp_apptrace_flush_nolock(uint32_t min_sz, uint32_t usr_tmo) { - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { - return ESP_ERR_INVALID_ARG; - } - if (!s_inited) { + + if (!s_trace_ch.hw) { return ESP_ERR_INVALID_STATE; } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return ESP_ERR_NOT_SUPPORTED; - } - if (ch->hw->flush_up_buffer_nolock == NULL) { + if (!s_trace_ch.hw->flush_up_buffer_nolock) { return ESP_ERR_NOT_SUPPORTED; } + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, usr_tmo); - return ch->hw->flush_up_buffer_nolock(ch->hw_data, min_sz, &tmo); + + return s_trace_ch.hw->flush_up_buffer_nolock(s_trace_ch.hw_data, min_sz, &tmo); } -esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t usr_tmo) +esp_err_t esp_apptrace_flush(uint32_t usr_tmo) { - esp_apptrace_tmo_t tmo; - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { - return ESP_ERR_INVALID_ARG; - } - if (!s_inited) { + + if (!s_trace_ch.hw) { return ESP_ERR_INVALID_STATE; } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return ESP_ERR_NOT_SUPPORTED; - } - if (ch->hw->flush_up_buffer == NULL) { + if (!s_trace_ch.hw->flush_up_buffer) { return ESP_ERR_NOT_SUPPORTED; } + esp_apptrace_tmo_t tmo; esp_apptrace_tmo_init(&tmo, usr_tmo); - return ch->hw->flush_up_buffer(ch->hw_data, &tmo); + + return s_trace_ch.hw->flush_up_buffer(s_trace_ch.hw_data, &tmo); } -bool esp_apptrace_host_is_connected(esp_apptrace_dest_t dest) +bool esp_apptrace_host_is_connected(void) { - esp_apptrace_channel_t *ch; - ESP_APPTRACE_LOGV("%s(): enter", __func__); - if (dest >= ESP_APPTRACE_DEST_MAX) { + + if (!s_trace_ch.hw) { return false; } - if (!s_inited) { - return false; - } - ch = &s_trace_channels[dest]; - if (ch->hw == NULL) { - ESP_APPTRACE_LOGE("Trace destination %d not supported!", dest); - return false; - } - if (ch->hw->host_is_connected == NULL) { + if (!s_trace_ch.hw->host_is_connected) { return false; } - return ch->hw->host_is_connected(ch->hw_data); + return s_trace_ch.hw->host_is_connected(s_trace_ch.hw_data); +} + +esp_apptrace_dest_t esp_apptrace_get_destination(void) +{ + return s_trace_ch.dest; +} + +esp_err_t esp_apptrace_set_header_size(esp_apptrace_header_size_t header_size) +{ + if (!s_trace_ch.hw) { + return ESP_ERR_INVALID_STATE; + } + if (s_trace_ch.hw->set_header_size) { + s_trace_ch.hw->set_header_size(s_trace_ch.hw_data, header_size); + } + return ESP_OK; +} + +esp_apptrace_config_t __attribute__((weak)) esp_apptrace_get_user_params(void) +{ + esp_apptrace_config_t default_config = APPTRACE_CONFIG_DEFAULT(); + return default_config; +} + +ESP_SYSTEM_INIT_FN(apptrace_early_init, SECONDARY, ESP_SYSTEM_INIT_ALL_CORES, 115) +{ + esp_apptrace_config_t config = esp_apptrace_get_user_params(); + return esp_apptrace_init(&config); } diff --git a/components/app_trace/app_trace_membufs_proto.c b/components/app_trace/app_trace_membufs_proto.c index cfebe971b3d..b535624ec6d 100644 --- a/components/app_trace/app_trace_membufs_proto.c +++ b/components/app_trace/app_trace_membufs_proto.c @@ -18,13 +18,16 @@ * In this case host SW will see that wr_sz < block_sz and will report error. */ typedef struct { -#if CONFIG_APPTRACE_SV_ENABLE - uint8_t block_sz; // size of allocated block for user data - uint8_t wr_sz; // size of actually written data -#else - uint16_t block_sz; // size of allocated block for user data - uint16_t wr_sz; // size of actually written data -#endif + union { + struct { + uint8_t block_sz_8; + uint8_t wr_sz_8; + }; + struct { + uint16_t block_sz_16; + uint16_t wr_sz_16; + }; + }; } esp_tracedata_hdr_t; /** TODO: docs @@ -33,31 +36,24 @@ typedef struct { uint16_t block_sz; // size of allocated block for user data } esp_hostdata_hdr_t; -#if CONFIG_APPTRACE_SV_ENABLE -#define ESP_APPTRACE_USR_BLOCK_CORE(_cid_) (0) -#define ESP_APPTRACE_USR_BLOCK_LEN(_v_) (_v_) -#define ESP_APPTRACE_USR_DATA_LEN_MAX(_hw_data_) 255UL -#else -#define ESP_APPTRACE_USR_BLOCK_CORE(_cid_) ((_cid_) << 15) -#define ESP_APPTRACE_USR_BLOCK_LEN(_v_) (~(1 << 15) & (_v_)) -#define ESP_APPTRACE_USR_DATA_LEN_MAX(_hw_data_) (ESP_APPTRACE_INBLOCK(_hw_data_)->sz - sizeof(esp_tracedata_hdr_t)) -#endif -#define ESP_APPTRACE_USR_BLOCK_RAW_SZ(_s_) ((_s_) + sizeof(esp_tracedata_hdr_t)) +#define ESP_APPTRACE_INBLOCK_MARKER(_hw_data_) \ + ((_hw_data_)->state.markers[(_hw_data_)->state.in_block % 2]) -#define ESP_APPTRACE_INBLOCK_MARKER(_hw_data_) ((_hw_data_)->state.markers[(_hw_data_)->state.in_block % 2]) -#define ESP_APPTRACE_INBLOCK_MARKER_UPD(_hw_data_, _v_) do {(_hw_data_)->state.markers[(_hw_data_)->state.in_block % 2] += (_v_);}while(0) -#define ESP_APPTRACE_INBLOCK(_hw_data_) (&(_hw_data_)->blocks[(_hw_data_)->state.in_block % 2]) +#define ESP_APPTRACE_INBLOCK(_hw_data_) \ + (&(_hw_data_)->blocks[(_hw_data_)->state.in_block % 2]) const static char *TAG = "esp_apptrace"; -static uint32_t esp_apptrace_membufs_down_buffer_write_nolock(esp_apptrace_membufs_proto_data_t *proto, uint8_t *data, uint32_t size); +static uint32_t esp_apptrace_membufs_down_buffer_write_nolock(esp_apptrace_membufs_proto_data_t *proto, + uint8_t *data, uint32_t size); -esp_err_t esp_apptrace_membufs_init(esp_apptrace_membufs_proto_data_t *proto, const esp_apptrace_mem_block_t blocks_cfg[2]) +esp_err_t esp_apptrace_membufs_init(esp_apptrace_membufs_proto_data_t *proto, + const esp_apptrace_mem_block_t blocks_cfg[2]) { // disabled by default esp_apptrace_rb_init(&proto->rb_down, NULL, 0); // membufs proto init - for (unsigned i = 0; i < 2; i++) { + for (unsigned int i = 0; i < 2; i++) { proto->blocks[i].start = blocks_cfg[i].start; proto->blocks[i].sz = blocks_cfg[i].sz; proto->state.markers[i] = 0; @@ -104,7 +100,8 @@ static esp_err_t esp_apptrace_membufs_swap(esp_apptrace_membufs_proto_data_t *pr *(p - 8), *(p - 7), *(p - 6), *(p - 5), *(p - 4), *(p - 3), *(p - 2), *(p - 1)); uint32_t sz = esp_apptrace_membufs_down_buffer_write_nolock(proto, (uint8_t *)(hdr + 1), hdr->block_sz); if (sz != hdr->block_sz) { - ESP_APPTRACE_LOGE("Failed to write %" PRIu32 " bytes to down buffer (%" PRIu16 " %" PRIu32 ")!", hdr->block_sz - sz, hdr->block_sz, sz); + ESP_APPTRACE_LOGE("Failed to write %" PRIu32 " bytes to down buffer (%" PRIu16 " %" PRIu32 ")!", + hdr->block_sz - sz, hdr->block_sz, sz); } hdr->block_sz = 0; } @@ -137,7 +134,8 @@ static esp_err_t esp_apptrace_membufs_swap_waitus(esp_apptrace_membufs_proto_dat return res; } -uint8_t *esp_apptrace_membufs_down_buffer_get(esp_apptrace_membufs_proto_data_t *proto, uint32_t *size, esp_apptrace_tmo_t *tmo) +uint8_t *esp_apptrace_membufs_down_buffer_get(esp_apptrace_membufs_proto_data_t *proto, + uint32_t *size, esp_apptrace_tmo_t *tmo) { uint8_t *ptr = NULL; @@ -170,13 +168,15 @@ uint8_t *esp_apptrace_membufs_down_buffer_get(esp_apptrace_membufs_proto_data_t return ptr; } -esp_err_t esp_apptrace_membufs_down_buffer_put(esp_apptrace_membufs_proto_data_t *proto, uint8_t *ptr, esp_apptrace_tmo_t *tmo) +esp_err_t esp_apptrace_membufs_down_buffer_put(esp_apptrace_membufs_proto_data_t *proto, + uint8_t *ptr, esp_apptrace_tmo_t *tmo) { /* nothing todo */ return ESP_OK; } -static uint32_t esp_apptrace_membufs_down_buffer_write_nolock(esp_apptrace_membufs_proto_data_t *proto, uint8_t *data, uint32_t size) +static uint32_t esp_apptrace_membufs_down_buffer_write_nolock(esp_apptrace_membufs_proto_data_t *proto, + uint8_t *data, uint32_t size) { uint32_t total_sz = 0; @@ -204,29 +204,21 @@ static uint32_t esp_apptrace_membufs_down_buffer_write_nolock(esp_apptrace_membu return total_sz; } -static inline uint8_t *esp_apptrace_membufs_pkt_start(uint8_t *ptr, uint16_t size) +static inline uint32_t esp_apptrace_membufs_usr_data_len_max(esp_apptrace_membufs_proto_data_t *proto) { - // it is safe to use esp_cpu_get_core_id() in macro call because arg is used only once inside it - ((esp_tracedata_hdr_t *)ptr)->block_sz = ESP_APPTRACE_USR_BLOCK_CORE(esp_cpu_get_core_id()) | size; - ((esp_tracedata_hdr_t *)ptr)->wr_sz = 0; - return ptr + sizeof(esp_tracedata_hdr_t); + return proto->header_size == ESP_APPTRACE_HEADER_SIZE_32 ? + ESP_APPTRACE_INBLOCK(proto)->sz - ESP_APPTRACE_HEADER_SIZE_32 : 255; } -static inline void esp_apptrace_membufs_pkt_end(uint8_t *ptr) +uint8_t *esp_apptrace_membufs_up_buffer_get(esp_apptrace_membufs_proto_data_t *proto, + uint32_t size, esp_apptrace_tmo_t *tmo) { - esp_tracedata_hdr_t *hdr = (esp_tracedata_hdr_t *)(ptr - sizeof(esp_tracedata_hdr_t)); - // update written size - hdr->wr_sz = hdr->block_sz; -} - -uint8_t *esp_apptrace_membufs_up_buffer_get(esp_apptrace_membufs_proto_data_t *proto, uint32_t size, esp_apptrace_tmo_t *tmo) -{ - if (size > ESP_APPTRACE_USR_DATA_LEN_MAX(proto)) { + if (size > esp_apptrace_membufs_usr_data_len_max(proto)) { ESP_APPTRACE_LOGE("Too large user data size %" PRIu32 "!", size); return NULL; } - if (ESP_APPTRACE_INBLOCK_MARKER(proto) + ESP_APPTRACE_USR_BLOCK_RAW_SZ(size) > ESP_APPTRACE_INBLOCK(proto)->sz) { + if (ESP_APPTRACE_INBLOCK_MARKER(proto) + size + proto->header_size > ESP_APPTRACE_INBLOCK(proto)->sz) { int res = esp_apptrace_membufs_swap_waitus(proto, tmo); if (res != ESP_OK) { return NULL; @@ -235,16 +227,32 @@ uint8_t *esp_apptrace_membufs_up_buffer_get(esp_apptrace_membufs_proto_data_t *p uint8_t *buf_ptr = ESP_APPTRACE_INBLOCK(proto)->start + ESP_APPTRACE_INBLOCK_MARKER(proto); // update cur block marker - ESP_APPTRACE_INBLOCK_MARKER_UPD(proto, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); - buf_ptr = esp_apptrace_membufs_pkt_start(buf_ptr, size); + proto->state.markers[proto->state.in_block % 2] += size + proto->header_size; + + // update header + esp_tracedata_hdr_t *hdr = (esp_tracedata_hdr_t *)buf_ptr; + if (proto->header_size == ESP_APPTRACE_HEADER_SIZE_32) { + hdr->block_sz_16 = (esp_cpu_get_core_id() << 15) | size; + hdr->wr_sz_16 = 0; + } else { + hdr->block_sz_8 = size; + hdr->wr_sz_8 = 0; + } ESP_APPTRACE_LOGD("Got %" PRIu32 " bytes from block", size); - return buf_ptr; + return buf_ptr + proto->header_size; } -esp_err_t esp_apptrace_membufs_up_buffer_put(esp_apptrace_membufs_proto_data_t *proto, uint8_t *ptr, esp_apptrace_tmo_t *tmo) +esp_err_t esp_apptrace_membufs_up_buffer_put(esp_apptrace_membufs_proto_data_t *proto, + uint8_t *ptr, esp_apptrace_tmo_t *tmo) { - esp_apptrace_membufs_pkt_end(ptr); + // update header + esp_tracedata_hdr_t *hdr = (esp_tracedata_hdr_t *)(ptr - proto->header_size); + if (proto->header_size == ESP_APPTRACE_HEADER_SIZE_32) { + hdr->wr_sz_16 = hdr->block_sz_16; + } else { + hdr->wr_sz_8 = hdr->block_sz_8; + } // TODO: mark block as busy in order not to reuse it for other tracing calls until it is completely written // TODO: avoid potential situation when all memory is consumed by low prio tasks which can not complete writing due to // higher prio tasks and the latter can not allocate buffers at all @@ -253,7 +261,8 @@ esp_err_t esp_apptrace_membufs_up_buffer_put(esp_apptrace_membufs_proto_data_t * return ESP_OK; } -esp_err_t esp_apptrace_membufs_flush_nolock(esp_apptrace_membufs_proto_data_t *proto, uint32_t min_sz, esp_apptrace_tmo_t *tmo) +esp_err_t esp_apptrace_membufs_flush_nolock(esp_apptrace_membufs_proto_data_t *proto, + uint32_t min_sz, esp_apptrace_tmo_t *tmo) { int res = ESP_OK; diff --git a/components/app_trace/app_trace_util.c b/components/app_trace/app_trace_util.c index c6cc1415663..b1a1c109bcf 100644 --- a/components/app_trace/app_trace_util.c +++ b/components/app_trace/app_trace_util.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -57,6 +57,12 @@ esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo) ///////////////////////////////// LOCK //////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// +void esp_apptrace_lock_init(esp_apptrace_lock_t *lock) +{ + portMUX_INITIALIZE(&lock->mux); + lock->int_state = 0; +} + esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *tmo) { esp_err_t ret; diff --git a/components/app_trace/heap_trace_tohost.c b/components/app_trace/heap_trace_tohost.c index 92922685294..8ee093b31b2 100644 --- a/components/app_trace/heap_trace_tohost.c +++ b/components/app_trace/heap_trace_tohost.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "sdkconfig.h" - +#include "freertos/FreeRTOS.h" #include "esp_heap_trace.h" #include "esp_heap_caps.h" #if CONFIG_APPTRACE_SV_ENABLE diff --git a/components/app_trace/host_file_io.c b/components/app_trace/host_file_io.c index 020000db1e7..6c0d2742ef6 100644 --- a/components/app_trace/host_file_io.c +++ b/components/app_trace/host_file_io.c @@ -17,8 +17,6 @@ #include #include "esp_app_trace.h" -#if CONFIG_APPTRACE_ENABLE - #include "esp_log.h" const static char *TAG = "esp_host_file_io"; @@ -79,13 +77,13 @@ typedef struct { void *file; } esp_apptrace_ftell_args_t; -static esp_err_t esp_apptrace_file_cmd_send(esp_apptrace_dest_t dest, uint8_t cmd, void (*prep_args)(uint8_t *, void *), void *args, uint32_t args_len) +static esp_err_t esp_apptrace_file_cmd_send(uint8_t cmd, void (*prep_args)(uint8_t *, void *), void *args, uint32_t args_len) { esp_err_t ret; esp_apptrace_fcmd_hdr_t *hdr; ESP_EARLY_LOGV(TAG, "%s %d", __func__, cmd); - uint8_t *ptr = esp_apptrace_buffer_get(dest, sizeof(*hdr) + args_len, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo + uint8_t *ptr = esp_apptrace_buffer_get(sizeof(*hdr) + args_len, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo if (ptr == NULL) { return ESP_ERR_NO_MEM; } @@ -97,13 +95,13 @@ static esp_err_t esp_apptrace_file_cmd_send(esp_apptrace_dest_t dest, uint8_t cm } // now indicate that this buffer is ready to be sent off to host - ret = esp_apptrace_buffer_put(dest, ptr, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo + ret = esp_apptrace_buffer_put(ptr, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to put apptrace buffer (%d)!", ret); return ret; } - ret = esp_apptrace_flush(dest, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo + ret = esp_apptrace_flush(ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to flush apptrace buffer (%d)!", ret); return ret; @@ -112,12 +110,12 @@ static esp_err_t esp_apptrace_file_cmd_send(esp_apptrace_dest_t dest, uint8_t cm return ESP_OK; } -static esp_err_t esp_apptrace_file_rsp_recv(esp_apptrace_dest_t dest, uint8_t *buf, uint32_t buf_len) +static esp_err_t esp_apptrace_file_rsp_recv(uint8_t *buf, uint32_t buf_len) { uint32_t tot_rd = 0; while (tot_rd < buf_len) { uint32_t rd_size = buf_len - tot_rd; - esp_err_t ret = esp_apptrace_read(dest, buf + tot_rd, &rd_size, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo + esp_err_t ret = esp_apptrace_read(buf + tot_rd, &rd_size, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read (%d)!", ret); return ret; @@ -137,7 +135,7 @@ static void esp_apptrace_fopen_args_prepare(uint8_t *buf, void *priv) memcpy(buf + args->path_len, args->mode, args->mode_len); } -void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char *mode) +void *esp_apptrace_fopen(const char *path, const char *mode) { esp_apptrace_fopen_args_t cmd_args; @@ -151,7 +149,7 @@ void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char cmd_args.mode = mode; cmd_args.mode_len = strlen(mode) + 1; - esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FOPEN, esp_apptrace_fopen_args_prepare, + esp_err_t ret = esp_apptrace_file_cmd_send(ESP_APPTRACE_FILE_CMD_FOPEN, esp_apptrace_fopen_args_prepare, &cmd_args, cmd_args.path_len + cmd_args.mode_len); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret); @@ -160,7 +158,7 @@ void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char // now read the answer void *resp; - ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp)); + ret = esp_apptrace_file_rsp_recv((uint8_t *)&resp, sizeof(resp)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret); return NULL; @@ -176,12 +174,12 @@ static void esp_apptrace_fclose_args_prepare(uint8_t *buf, void *priv) memcpy(buf, &args->file, sizeof(args->file)); } -int esp_apptrace_fclose(esp_apptrace_dest_t dest, void *stream) +int esp_apptrace_fclose(void *stream) { esp_apptrace_fclose_args_t cmd_args; cmd_args.file = stream; - esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FCLOSE, esp_apptrace_fclose_args_prepare, + esp_err_t ret = esp_apptrace_file_cmd_send(ESP_APPTRACE_FILE_CMD_FCLOSE, esp_apptrace_fclose_args_prepare, &cmd_args, sizeof(cmd_args)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret); @@ -190,7 +188,7 @@ int esp_apptrace_fclose(esp_apptrace_dest_t dest, void *stream) // now read the answer int resp; - ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp)); + ret = esp_apptrace_file_rsp_recv((uint8_t *)&resp, sizeof(resp)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret); return EOF; @@ -207,7 +205,7 @@ static void esp_apptrace_fwrite_args_prepare(uint8_t *buf, void *priv) memcpy(buf + sizeof(args->file), args->buf, args->size); } -size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t size, size_t nmemb, void *stream) +size_t esp_apptrace_fwrite(const void *ptr, size_t size, size_t nmemb, void *stream) { esp_apptrace_fwrite_args_t cmd_args; @@ -220,7 +218,7 @@ size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t siz cmd_args.buf = (void *)ptr; cmd_args.size = size * nmemb; cmd_args.file = stream; - esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FWRITE, esp_apptrace_fwrite_args_prepare, + esp_err_t ret = esp_apptrace_file_cmd_send(ESP_APPTRACE_FILE_CMD_FWRITE, esp_apptrace_fwrite_args_prepare, &cmd_args, sizeof(cmd_args.file) + cmd_args.size); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret); @@ -229,7 +227,7 @@ size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t siz // now read the answer size_t resp; - ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp)); + ret = esp_apptrace_file_rsp_recv((uint8_t *)&resp, sizeof(resp)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret); return 0; @@ -249,7 +247,7 @@ static void esp_apptrace_fread_args_prepare(uint8_t *buf, void *priv) memcpy(buf + sizeof(args->file), &args->size, sizeof(args->size)); } -size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size_t nmemb, void *stream) +size_t esp_apptrace_fread(void *ptr, size_t size, size_t nmemb, void *stream) { esp_apptrace_fread_args_t cmd_args; @@ -261,7 +259,7 @@ size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size cmd_args.size = size * nmemb; cmd_args.file = stream; - esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FREAD, esp_apptrace_fread_args_prepare, + esp_err_t ret = esp_apptrace_file_cmd_send(ESP_APPTRACE_FILE_CMD_FREAD, esp_apptrace_fread_args_prepare, &cmd_args, sizeof(cmd_args)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret); @@ -270,7 +268,7 @@ size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size // now read the answer size_t resp; - ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp)); + ret = esp_apptrace_file_rsp_recv((uint8_t *)&resp, sizeof(resp)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret); return 0; @@ -279,7 +277,7 @@ size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size return 0; } - ret = esp_apptrace_file_rsp_recv(dest, ptr, resp); + ret = esp_apptrace_file_rsp_recv(ptr, resp); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read file data (%d)!", ret); return 0; @@ -300,7 +298,7 @@ static void esp_apptrace_fseek_args_prepare(uint8_t *buf, void *priv) memcpy(buf + sizeof(args->file) + sizeof(args->offset), &args->whence, sizeof(args->whence)); } -int esp_apptrace_fseek(esp_apptrace_dest_t dest, void *stream, long offset, int whence) +int esp_apptrace_fseek(void *stream, long offset, int whence) { esp_apptrace_fseek_args_t cmd_args; @@ -309,7 +307,7 @@ int esp_apptrace_fseek(esp_apptrace_dest_t dest, void *stream, long offset, int cmd_args.file = stream; cmd_args.offset = offset; cmd_args.whence = whence; - esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FSEEK, esp_apptrace_fseek_args_prepare, + esp_err_t ret = esp_apptrace_file_cmd_send(ESP_APPTRACE_FILE_CMD_FSEEK, esp_apptrace_fseek_args_prepare, &cmd_args, sizeof(cmd_args)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret); @@ -318,7 +316,7 @@ int esp_apptrace_fseek(esp_apptrace_dest_t dest, void *stream, long offset, int // now read the answer int resp; - ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp)); + ret = esp_apptrace_file_rsp_recv((uint8_t *)&resp, sizeof(resp)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret); return -1; @@ -334,12 +332,12 @@ static void esp_apptrace_ftell_args_prepare(uint8_t *buf, void *priv) memcpy(buf, &args->file, sizeof(args->file)); } -int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream) +int esp_apptrace_ftell(void *stream) { esp_apptrace_ftell_args_t cmd_args; cmd_args.file = stream; - esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FTELL, esp_apptrace_ftell_args_prepare, + esp_err_t ret = esp_apptrace_file_cmd_send(ESP_APPTRACE_FILE_CMD_FTELL, esp_apptrace_ftell_args_prepare, &cmd_args, sizeof(cmd_args)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret); @@ -348,7 +346,7 @@ int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream) // now read the answer int resp; - ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp)); + ret = esp_apptrace_file_rsp_recv((uint8_t *)&resp, sizeof(resp)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret); return -1; @@ -357,10 +355,10 @@ int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream) return resp; } -int esp_apptrace_fstop(esp_apptrace_dest_t dest) +int esp_apptrace_fstop(void) { ESP_EARLY_LOGV(TAG, "%s", __func__); - esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_STOP, NULL, NULL, 0); + esp_err_t ret = esp_apptrace_file_cmd_send(ESP_APPTRACE_FILE_CMD_STOP, NULL, NULL, 0); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", ret); } @@ -374,12 +372,12 @@ static void esp_apptrace_feof_args_prepare(uint8_t *buf, void *priv) memcpy(buf, &args->file, sizeof(args->file)); } -int esp_apptrace_feof(esp_apptrace_dest_t dest, void *stream) +int esp_apptrace_feof(void *stream) { esp_apptrace_feof_args_t cmd_args; cmd_args.file = stream; - esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FEOF, esp_apptrace_feof_args_prepare, + esp_err_t ret = esp_apptrace_file_cmd_send(ESP_APPTRACE_FILE_CMD_FEOF, esp_apptrace_feof_args_prepare, &cmd_args, sizeof(cmd_args)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret); @@ -388,7 +386,7 @@ int esp_apptrace_feof(esp_apptrace_dest_t dest, void *stream) // now read the answer int resp; - ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp)); + ret = esp_apptrace_file_rsp_recv((uint8_t *)&resp, sizeof(resp)); if (ret != ESP_OK) { ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret); return EOF; @@ -396,5 +394,3 @@ int esp_apptrace_feof(esp_apptrace_dest_t dest, void *stream) return resp; } - -#endif diff --git a/components/app_trace/include/esp_app_trace.h b/components/app_trace/include/esp_app_trace.h index f43cf0ecb78..ea84866ee01 100644 --- a/components/app_trace/include/esp_app_trace.h +++ b/components/app_trace/include/esp_app_trace.h @@ -8,6 +8,7 @@ #include #include "esp_err.h" +#include "esp_app_trace_config.h" #include "esp_app_trace_util.h" // ESP_APPTRACE_TMO_INFINITE #ifdef __cplusplus @@ -15,83 +16,73 @@ extern "C" { #endif /** - * Application trace data destinations bits. - */ -typedef enum { - ESP_APPTRACE_DEST_JTAG, ///< JTAG destination - ESP_APPTRACE_DEST_UART, ///< UART destination - ESP_APPTRACE_DEST_MAX, -} esp_apptrace_dest_t; - -/** - * @brief Initializes application tracing module. + * @brief Get custom trace initialization parameters (optional callback) * - * @note Should be called before any esp_apptrace_xxx call. + * This is an optional callback function that user applications can implement to provide + * custom trace configuration. A weak default implementation exists in the app_trace component + * that returns menuconfig defaults (APPTRACE_CONFIG_DEFAULT()). User applications can override + * this by providing their own implementation. + * + * This function is called during early system initialization (before app_main) on all cores. * - * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_init(void); +esp_apptrace_config_t esp_apptrace_get_user_params(void); /** * @brief Configures down buffer. * @note Needs to be called before attempting to receive any data using esp_apptrace_down_buffer_get and esp_apptrace_read. * This function does not protect internal data by lock. * - * @param dest Indicates HW interface to configure. * @param buf Address of buffer to use for down channel (host to target) data. * @param size Size of the buffer. * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_down_buffer_config(esp_apptrace_dest_t dest, uint8_t *buf, uint32_t size); +esp_err_t esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size); /** * @brief Allocates buffer for trace data. * Once the data in the buffer is ready to be sent, esp_apptrace_buffer_put must be called to indicate it. * - * @param dest Indicates HW interface to send data. * @param size Size of data to write to trace buffer. * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return non-NULL on success, otherwise NULL. */ -uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32_t tmo); +uint8_t *esp_apptrace_buffer_get(uint32_t size, uint32_t tmo); /** * @brief Indicates that the data in the buffer is ready to be sent. * This function is a counterpart of and must be preceded by esp_apptrace_buffer_get. * - * @param dest Indicates HW interface to send data. Should be identical to the same parameter in call to esp_apptrace_buffer_get. * @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_buffer_get. * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t tmo); +esp_err_t esp_apptrace_buffer_put(uint8_t *ptr, uint32_t tmo); /** * @brief Writes data to trace buffer. * - * @param dest Indicates HW interface to send data. * @param data Address of data to write to trace buffer. * @param size Size of data to write to trace buffer. * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_t size, uint32_t tmo); +esp_err_t esp_apptrace_write(const void *data, uint32_t size, uint32_t tmo); /** * @brief vprintf-like function to send log messages to host via specified HW interface. * - * @param dest Indicates HW interface to send data. * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * @param fmt Address of format string. * @param ap List of arguments. * * @return Number of bytes written. */ -int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t tmo, const char *fmt, va_list ap); +int esp_apptrace_vprintf_to(uint32_t tmo, const char *fmt, va_list ap); /** * @brief vprintf-like function to send log messages to host. @@ -106,98 +97,104 @@ int esp_apptrace_vprintf(const char *fmt, va_list ap); /** * @brief Flushes remaining data in trace buffer to host. * - * @param dest Indicates HW interface to flush data on. * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t tmo); +esp_err_t esp_apptrace_flush(uint32_t tmo); /** * @brief Flushes remaining data in trace buffer to host without locking internal data. * This is a special version of esp_apptrace_flush which should be called from panic handler. * - * @param dest Indicates HW interface to flush data on. * @param min_sz Threshold for flushing data. If current filling level is above this value, data will be flushed. JTAG destinations only. * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, uint32_t tmo); +esp_err_t esp_apptrace_flush_nolock(uint32_t min_sz, uint32_t tmo); /** * @brief Reads host data from trace buffer. * - * @param dest Indicates HW interface to read the data on. * @param data Address of buffer to put data from trace buffer. * @param size Pointer to store size of read data. Before call to this function pointed memory must hold requested size of data * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *data, uint32_t *size, uint32_t tmo); +esp_err_t esp_apptrace_read(void *data, uint32_t *size, uint32_t tmo); /** * @brief Retrieves incoming data buffer if any. * Once data in the buffer is processed, esp_apptrace_down_buffer_put must be called to indicate it. * - * @param dest Indicates HW interface to receive data. * @param size Address to store size of available data in down buffer. Must be initialized with requested value. * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return non-NULL on success, otherwise NULL. */ -uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size, uint32_t tmo); +uint8_t *esp_apptrace_down_buffer_get(uint32_t *size, uint32_t tmo); /** * @brief Indicates that the data in the down buffer is processed. * This function is a counterpart of and must be preceded by esp_apptrace_down_buffer_get. * - * @param dest Indicates HW interface to receive data. Should be identical to the same parameter in call to esp_apptrace_down_buffer_get. * @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_down_buffer_get. * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return ESP_OK on success, otherwise see esp_err_t */ -esp_err_t esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t tmo); +esp_err_t esp_apptrace_down_buffer_put(uint8_t *ptr, uint32_t tmo); /** * @brief Checks whether host is connected. * - * @param dest Indicates HW interface to use. - * * @return true if host is connected, otherwise false */ -bool esp_apptrace_host_is_connected(esp_apptrace_dest_t dest); +bool esp_apptrace_host_is_connected(void); + +/** + * @brief Gets the destination of the application trace. + * + * @return The destination of the application trace. + */ +esp_apptrace_dest_t esp_apptrace_get_destination(void); + +/** + * @brief Sets the header size of the application trace packet. + * + * @param header_size The header size to set. + * + * @return ESP_OK on success, otherwise see esp_err_t + */ +esp_err_t esp_apptrace_set_header_size(esp_apptrace_header_size_t header_size); /** * @brief Opens file on host. * This function has the same semantic as 'fopen' except for the first argument. * - * @param dest Indicates HW interface to use. * @param path Path to file. * @param mode Mode string. See fopen for details. * * @return non zero file handle on success, otherwise 0 */ -void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char *mode); +void *esp_apptrace_fopen(const char *path, const char *mode); /** * @brief Closes file on host. * This function has the same semantic as 'fclose' except for the first argument. * - * @param dest Indicates HW interface to use. * @param stream File handle returned by esp_apptrace_fopen. * * @return Zero on success, otherwise non-zero. See fclose for details. */ -int esp_apptrace_fclose(esp_apptrace_dest_t dest, void *stream); +int esp_apptrace_fclose(void *stream); /** * @brief Writes to file on host. * This function has the same semantic as 'fwrite' except for the first argument. * - * @param dest Indicates HW interface to use. * @param ptr Address of data to write. * @param size Size of an item. * @param nmemb Number of items to write. @@ -205,13 +202,12 @@ int esp_apptrace_fclose(esp_apptrace_dest_t dest, void *stream); * * @return Number of written items. See fwrite for details. */ -size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t size, size_t nmemb, void *stream); +size_t esp_apptrace_fwrite(const void *ptr, size_t size, size_t nmemb, void *stream); /** * @brief Read file on host. * This function has the same semantic as 'fread' except for the first argument. * - * @param dest Indicates HW interface to use. * @param ptr Address to store read data. * @param size Size of an item. * @param nmemb Number of items to read. @@ -219,53 +215,82 @@ size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t siz * * @return Number of read items. See fread for details. */ -size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size_t nmemb, void *stream); +size_t esp_apptrace_fread(void *ptr, size_t size, size_t nmemb, void *stream); /** * @brief Set position indicator in file on host. * This function has the same semantic as 'fseek' except for the first argument. * - * @param dest Indicates HW interface to use. * @param stream File handle returned by esp_apptrace_fopen. * @param offset Offset. See fseek for details. * @param whence Position in file. See fseek for details. * * @return Zero on success, otherwise non-zero. See fseek for details. */ -int esp_apptrace_fseek(esp_apptrace_dest_t dest, void *stream, long offset, int whence); +int esp_apptrace_fseek(void *stream, long offset, int whence); /** * @brief Get current position indicator for file on host. * This function has the same semantic as 'ftell' except for the first argument. * - * @param dest Indicates HW interface to use. * @param stream File handle returned by esp_apptrace_fopen. * * @return Current position in file. See ftell for details. */ -int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream); +int esp_apptrace_ftell(void *stream); /** * @brief Indicates to the host that all file operations are complete. * This function should be called after all file operations are finished and * indicate to the host that it can perform cleanup operations (close open files etc.). * - * @param dest Indicates HW interface to use. - * * @return ESP_OK on success, otherwise see esp_err_t */ -int esp_apptrace_fstop(esp_apptrace_dest_t dest); +int esp_apptrace_fstop(void); /** * @brief Test end-of-file indicator on a stream. * This function has the same semantic as 'feof' except for the first argument. * - * @param dest Indicates HW interface to use. * @param stream File handle returned by esp_apptrace_fopen. * * @return Non-Zero if end-of-file indicator is set for stream. See feof for details. */ -int esp_apptrace_feof(esp_apptrace_dest_t dest, void *stream); +int esp_apptrace_feof(void *stream); + +#if !CONFIG_APPTRACE_DEST_UART // JTAG or NONE +#define APPTRACE_JTAG_CONFIG_DEFAULT() { \ + .dest = ESP_APPTRACE_DEST_JTAG, \ + .dest_cfg.jtag = {0}, \ + .panic_flush_tmo = CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO, \ + .panic_flush_thresh = CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, \ +} +#endif + +#if !CONFIG_APPTRACE_DEST_JTAG // UART or NONE +#define APPTRACE_UART_CONFIG_DEFAULT() { \ + .dest = ESP_APPTRACE_DEST_UART, \ + .dest_cfg.uart = { \ + .uart_num = CONFIG_APPTRACE_DEST_UART_NUM, \ + .tx_pin_num = CONFIG_APPTRACE_UART_TX_GPIO, \ + .rx_pin_num = CONFIG_APPTRACE_UART_RX_GPIO, \ + .baud_rate = CONFIG_APPTRACE_UART_BAUDRATE, \ + .rx_buff_size = CONFIG_APPTRACE_UART_RX_BUFF_SIZE, \ + .tx_buff_size = CONFIG_APPTRACE_UART_TX_BUFF_SIZE, \ + .tx_msg_size = CONFIG_APPTRACE_UART_TX_MSG_SIZE, \ + .task_prio = CONFIG_APPTRACE_UART_TASK_PRIO, \ + }, \ + .panic_flush_tmo = CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO, \ + .panic_flush_thresh = CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, \ +} +#endif + +// Default picks JTAG if available, otherwise UART +#if !CONFIG_APPTRACE_DEST_UART +#define APPTRACE_CONFIG_DEFAULT() APPTRACE_JTAG_CONFIG_DEFAULT() +#else +#define APPTRACE_CONFIG_DEFAULT() APPTRACE_UART_CONFIG_DEFAULT() +#endif #ifdef __cplusplus } diff --git a/components/app_trace/include/esp_app_trace_config.h b/components/app_trace/include/esp_app_trace_config.h new file mode 100644 index 00000000000..0f827da97f4 --- /dev/null +++ b/components/app_trace/include/esp_app_trace_config.h @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ESP_APP_TRACE_CONFIG_H_ +#define ESP_APP_TRACE_CONFIG_H_ + +#include "sdkconfig.h" + +/* Default configurations for runtime selection (CONFIG_APPTRACE_DEST_NONE) + * These values are used when CONFIG_APPTRACE_DEST_NONE is selected in menuconfig. + * To customize at runtime, implement esp_apptrace_get_user_params() + * in your application. See esp_app_trace.h for details. + */ + +#if !defined(CONFIG_APPTRACE_UART_TX_GPIO) || !defined(CONFIG_APPTRACE_UART_RX_GPIO) +#include "soc/uart_pins.h" +#endif + +#ifndef CONFIG_APPTRACE_BUF_SIZE +#define CONFIG_APPTRACE_BUF_SIZE 16384 +#endif + +#ifndef CONFIG_APPTRACE_UART_RX_BUFF_SIZE +#define CONFIG_APPTRACE_UART_RX_BUFF_SIZE 128 +#endif + +#ifndef CONFIG_APPTRACE_UART_TX_BUFF_SIZE +#define CONFIG_APPTRACE_UART_TX_BUFF_SIZE 4096 +#endif + +#ifndef CONFIG_APPTRACE_UART_TX_MSG_SIZE +#define CONFIG_APPTRACE_UART_TX_MSG_SIZE 128 +#endif + +#ifndef CONFIG_APPTRACE_UART_BAUDRATE +#define CONFIG_APPTRACE_UART_BAUDRATE 1000000 +#endif + +#ifndef CONFIG_APPTRACE_UART_TASK_PRIO +#define CONFIG_APPTRACE_UART_TASK_PRIO 1 +#endif + +#ifndef CONFIG_APPTRACE_UART_TX_GPIO +#define CONFIG_APPTRACE_UART_TX_GPIO U1TXD_GPIO_NUM +#endif + +#ifndef CONFIG_APPTRACE_UART_RX_GPIO +#define CONFIG_APPTRACE_UART_RX_GPIO U1RXD_GPIO_NUM +#endif + +#ifndef CONFIG_APPTRACE_DEST_UART_NUM +#define CONFIG_APPTRACE_DEST_UART_NUM 1 +#endif + +#ifndef CONFIG_APPTRACE_SV_DEST_CPU_0 +#define CONFIG_APPTRACE_SV_DEST_CPU_0 1 +#endif + +#endif /* ESP_APP_TRACE_CONFIG_H_ */ diff --git a/components/app_trace/include/esp_app_trace_types.h b/components/app_trace/include/esp_app_trace_types.h new file mode 100644 index 00000000000..ed48376bca6 --- /dev/null +++ b/components/app_trace/include/esp_app_trace_types.h @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ESP_APP_TRACE_TYPES_H_ +#define ESP_APP_TRACE_TYPES_H_ + +#include +#include "spinlock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Structure which holds data necessary for measuring time intervals. + * + * After initialization via esp_apptrace_tmo_init() user needs to call esp_apptrace_tmo_check() + * periodically to check timeout for expiration. + */ +typedef struct { + int64_t start; ///< time interval start (in us) + int64_t tmo; ///< timeout value (in us) + int64_t elapsed; ///< elapsed time (in us) +} esp_apptrace_tmo_t; + +/** Tracing module synchronization lock */ +typedef struct { + spinlock_t mux; + unsigned int_state; +} esp_apptrace_lock_t; + +/** Ring buffer control structure. + * + * @note For purposes of application tracing module if there is no enough space for user data and write pointer can be wrapped + * current ring buffer size can be temporarily shrunk in order to provide buffer with requested size. + */ +typedef struct { + uint8_t *data; ///< pointer to data storage + volatile uint32_t size; ///< size of data storage + volatile uint32_t cur_size; ///< current size of data storage + volatile uint32_t rd; ///< read pointer + volatile uint32_t wr; ///< write pointer +} esp_apptrace_rb_t; + +/** + * Application trace data destinations + */ +typedef enum { + ESP_APPTRACE_DEST_JTAG, + ESP_APPTRACE_DEST_UART, +} esp_apptrace_dest_t; + +/** + * Application trace configuration for UART destination + */ +typedef struct { + int uart_num; ///< Port number + int tx_pin_num; ///< TX pin number + int rx_pin_num; ///< RX pin number + int baud_rate; ///< Baud rate + uint32_t rx_buff_size; ///< RX ring buffer size + uint32_t tx_buff_size; ///< TX ring buffer size + uint32_t tx_msg_size; ///< Maximum size of the single message to transfer. + int task_prio; ///< Task priority +} esp_apptrace_uart_config_t; + +/** + * Application trace trace header size in bytes. It is 2 bytes for SEGGER SystemView + */ +typedef enum { + ESP_APPTRACE_HEADER_SIZE_16 = 2, + ESP_APPTRACE_HEADER_SIZE_32 = 4, +} esp_apptrace_header_size_t; + +/** + * Application trace configuration + */ +typedef struct { + esp_apptrace_dest_t dest; ///< Destination type (JTAG or UART) + + union { + esp_apptrace_uart_config_t uart; ///< UART configuration (when dest is ESP_APPTRACE_DEST_UART) + struct { ///< Reserved for JTAG (when dest is ESP_APPTRACE_DEST_JTAG) + uint8_t _unused; + } jtag; + } dest_cfg; ///< Destination-specific configuration + + uint32_t panic_flush_tmo; ///< Panic flush timeout in milliseconds + uint32_t panic_flush_thresh; ///< Panic flush threshold in bytes +} esp_apptrace_config_t; + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_APP_TRACE_TYPES_H_ */ diff --git a/components/app_trace/include/esp_app_trace_util.h b/components/app_trace/include/esp_app_trace_util.h index 264ae655bd8..927e37ac85a 100644 --- a/components/app_trace/include/esp_app_trace_util.h +++ b/components/app_trace/include/esp_app_trace_util.h @@ -10,24 +10,13 @@ extern "C" { #endif -#include "freertos/FreeRTOS.h" #include "esp_err.h" #include "esp_timer.h" +#include "esp_app_trace_types.h" /** Infinite waiting timeout */ #define ESP_APPTRACE_TMO_INFINITE ((uint32_t)-1) -/** Structure which holds data necessary for measuring time intervals. - * - * After initialization via esp_apptrace_tmo_init() user needs to call esp_apptrace_tmo_check() - * periodically to check timeout for expiration. - */ -typedef struct { - int64_t start; ///< time interval start (in us) - int64_t tmo; ///< timeout value (in us) - int64_t elapsed; ///< elapsed time (in us) -} esp_apptrace_tmo_t; - /** * @brief Initializes timeout structure. * @@ -55,22 +44,12 @@ static inline uint32_t esp_apptrace_tmo_remaining_us(esp_apptrace_tmo_t *tmo) return tmo->tmo != (int64_t) -1 ? (tmo->elapsed - tmo->tmo) : ESP_APPTRACE_TMO_INFINITE; } -/** Tracing module synchronization lock */ -typedef struct { - spinlock_t mux; - unsigned int_state; -} esp_apptrace_lock_t; - /** * @brief Initializes lock structure. * * @param lock Pointer to lock structure to be initialized. */ -static inline void esp_apptrace_lock_init(esp_apptrace_lock_t *lock) -{ - portMUX_INITIALIZE(&lock->mux); - lock->int_state = 0; -} +void esp_apptrace_lock_init(esp_apptrace_lock_t *lock); /** * @brief Tries to acquire lock in specified time period. @@ -91,19 +70,6 @@ esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t * */ esp_err_t esp_apptrace_lock_give(esp_apptrace_lock_t *lock); -/** Ring buffer control structure. - * - * @note For purposes of application tracing module if there is no enough space for user data and write pointer can be wrapped - * current ring buffer size can be temporarily shrunk in order to provide buffer with requested size. - */ -typedef struct { - uint8_t *data; ///< pointer to data storage - volatile uint32_t size; ///< size of data storage - volatile uint32_t cur_size; ///< current size of data storage - volatile uint32_t rd; ///< read pointer - volatile uint32_t wr; ///< write pointer -} esp_apptrace_rb_t; - /** * @brief Initializes ring buffer control structure. * diff --git a/components/app_trace/include/esp_sysview_trace.h b/components/app_trace/include/esp_sysview_trace.h index de9c8f753c0..98e2a9c908b 100644 --- a/components/app_trace/include/esp_sysview_trace.h +++ b/components/app_trace/include/esp_sysview_trace.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,7 +18,7 @@ extern "C" { /** * @brief Flushes remaining data in SystemView trace buffer to host. * - * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly. + * @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely. * * @return ESP_OK. */ diff --git a/components/app_trace/linker.lf b/components/app_trace/linker.lf index 6022f22427e..4223e486dea 100644 --- a/components/app_trace/linker.lf +++ b/components/app_trace/linker.lf @@ -1,14 +1,14 @@ [mapping:app_trace] archive: libapp_trace.a entries: - app_trace (noflash) - app_trace_util (noflash) - if APPTRACE_MEMBUFS_APPTRACE_PROTO_ENABLE: - app_trace_membufs_proto (noflash) - if APPTRACE_DEST_JTAG = y: - port_jtag (noflash) - if APPTRACE_DEST_UART = y: - port_uart (noflash) + if APPTRACE_ENABLE = y: + app_trace (noflash) + app_trace_util (noflash) + if APPTRACE_DEST_JTAG = y || APPTRACE_DEST_NONE = y: + port_jtag (noflash) + app_trace_membufs_proto (noflash) + if APPTRACE_DEST_UART = y || APPTRACE_DEST_NONE = y: + port_uart (noflash) if APPTRACE_SV_ENABLE = y: SEGGER_SYSVIEW (noflash) SEGGER_RTT_esp (noflash) @@ -19,6 +19,6 @@ entries: archive: libesp_driver_gptimer.a entries: if APPTRACE_SV_TS_SOURCE_GPTIMER = y: - gptimer: gptimer_get_raw_count (noflash) + gptimer: gptimer_get_raw_count (noflash) else: - * (default) + * (default) diff --git a/components/app_trace/port/include/esp_app_trace_port.h b/components/app_trace/port/include/esp_app_trace_port.h index f0be32eca44..bf1e7d25e8f 100644 --- a/components/app_trace/port/include/esp_app_trace_port.h +++ b/components/app_trace/port/include/esp_app_trace_port.h @@ -15,7 +15,7 @@ extern "C" { /** Apptrace HW interface. */ typedef struct { - esp_err_t (*init)(void *hw_data); + esp_err_t (*init)(void *hw_data, const esp_apptrace_config_t *config); uint8_t *(*get_up_buffer)(void *hw_data, uint32_t, esp_apptrace_tmo_t *); esp_err_t (*put_up_buffer)(void *hw_data, uint8_t *, esp_apptrace_tmo_t *); esp_err_t (*flush_up_buffer_nolock)(void *hw_data, uint32_t, esp_apptrace_tmo_t *); @@ -24,6 +24,7 @@ typedef struct { uint8_t *(*get_down_buffer)(void *hw_data, uint32_t *, esp_apptrace_tmo_t *); esp_err_t (*put_down_buffer)(void *hw_data, uint8_t *, esp_apptrace_tmo_t *); bool (*host_is_connected)(void *hw_data); + void (*set_header_size)(void *hw_data, esp_apptrace_header_size_t header_size); } esp_apptrace_hw_t; esp_apptrace_hw_t *esp_apptrace_jtag_hw_get(void **data); diff --git a/components/app_trace/port/port_uart.c b/components/app_trace/port/port_uart.c index d3d973e61d0..f76edc51f02 100644 --- a/components/app_trace/port/port_uart.c +++ b/components/app_trace/port/port_uart.c @@ -3,19 +3,16 @@ * * SPDX-License-Identifier: Apache-2.0 */ - #include #include "soc/soc.h" #include "esp_log.h" #include "esp_cpu.h" +#include "esp_app_trace_config.h" #include "esp_app_trace_port.h" #include "driver/uart.h" #include "hal/uart_ll.h" -#define APP_TRACE_MAX_TX_BUFF_UART CONFIG_APPTRACE_UART_TX_BUFF_SIZE -#define APP_TRACE_MAX_TX_MSG_UART CONFIG_APPTRACE_UART_TX_MSG_SIZE - /** UART HW transport data */ typedef struct { uint8_t inited; @@ -23,28 +20,34 @@ typedef struct { esp_apptrace_lock_t lock; // sync lock #endif uart_port_t port_num; -// TX data ring buffer + + /* TX data ring buffer */ uint8_t *tx_data_buff; + uint32_t tx_data_buff_size; int32_t tx_data_buff_in; int32_t tx_data_buff_out; -// TX message buffer + + /* TX message buffer */ uint8_t *tx_msg_buff; uint32_t tx_msg_buff_size; + uint32_t tx_pending_msg_size; -// RX message buffer + /* RX message buffer */ uint8_t *down_buffer; uint32_t down_buffer_size; -// Buffer overflow flags + + /* Buffer overflow flags */ bool message_buff_overflow; bool circular_buff_overflow; } esp_apptrace_uart_data_t; const static char *TAG = "esp_apptrace_uart"; -static esp_err_t esp_apptrace_uart_lock(esp_apptrace_uart_data_t *hw_data, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_uart_lock(void *hw_data, esp_apptrace_tmo_t *tmo) { #if CONFIG_APPTRACE_LOCK_ENABLE - esp_err_t ret = esp_apptrace_lock_take(&hw_data->lock, tmo); + esp_apptrace_uart_data_t *uart_data = hw_data; + esp_err_t ret = esp_apptrace_lock_take(&uart_data->lock, tmo); if (ret != ESP_OK) { return ESP_FAIL; } @@ -52,11 +55,12 @@ static esp_err_t esp_apptrace_uart_lock(esp_apptrace_uart_data_t *hw_data, esp_a return ESP_OK; } -static esp_err_t esp_apptrace_uart_unlock(esp_apptrace_uart_data_t *hw_data) +static esp_err_t esp_apptrace_uart_unlock(void *hw_data) { esp_err_t ret = ESP_OK; #if CONFIG_APPTRACE_LOCK_ENABLE - ret = esp_apptrace_lock_give(&hw_data->lock); + esp_apptrace_uart_data_t *uart_data = hw_data; + ret = esp_apptrace_lock_give(&uart_data->lock); #endif return ret; } @@ -70,58 +74,69 @@ static inline void esp_apptrace_uart_hw_init(void) /***************************** Apptrace HW iface *****************************************/ /*****************************************************************************************/ -static esp_err_t esp_apptrace_send_uart_data(esp_apptrace_uart_data_t *hw_data, const char *data, uint32_t size, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_send_uart_data(void *hw_data, const char *data, uint32_t size, esp_apptrace_tmo_t *tmo) { - esp_err_t res = esp_apptrace_uart_lock(hw_data, tmo); + esp_apptrace_uart_data_t *uart_data = hw_data; + esp_err_t res = esp_apptrace_uart_lock(uart_data, tmo); if (res != ESP_OK) { return res; } // We store current out position to handle it without lock - volatile int32_t out_position = hw_data->tx_data_buff_out; + volatile int32_t out_position = uart_data->tx_data_buff_out; - int len_free = APP_TRACE_MAX_TX_BUFF_UART - (hw_data->tx_data_buff_in - out_position); - if (out_position > hw_data->tx_data_buff_in) { - len_free = out_position - hw_data->tx_data_buff_in; + int len_free = uart_data->tx_data_buff_size - (uart_data->tx_data_buff_in - out_position); + if (out_position > uart_data->tx_data_buff_in) { + len_free = out_position - uart_data->tx_data_buff_in; } - int check_len = APP_TRACE_MAX_TX_BUFF_UART - hw_data->tx_data_buff_in; + int check_len = uart_data->tx_data_buff_size - uart_data->tx_data_buff_in; if (size <= len_free) { if (check_len >= size) { - memcpy(&hw_data->tx_data_buff[hw_data->tx_data_buff_in], data, size); - hw_data->tx_data_buff_in += size; + memcpy(&uart_data->tx_data_buff[uart_data->tx_data_buff_in], data, size); + uart_data->tx_data_buff_in += size; } else { - memcpy(&hw_data->tx_data_buff[hw_data->tx_data_buff_in], data, APP_TRACE_MAX_TX_BUFF_UART - hw_data->tx_data_buff_in); - memcpy(&hw_data->tx_data_buff[0], &data[APP_TRACE_MAX_TX_BUFF_UART - hw_data->tx_data_buff_in], size - (APP_TRACE_MAX_TX_BUFF_UART - hw_data->tx_data_buff_in)); - hw_data->tx_data_buff_in = size - (APP_TRACE_MAX_TX_BUFF_UART - hw_data->tx_data_buff_in); + memcpy(&uart_data->tx_data_buff[uart_data->tx_data_buff_in], + data, + uart_data->tx_data_buff_size - uart_data->tx_data_buff_in); + memcpy(&uart_data->tx_data_buff[0], + &data[uart_data->tx_data_buff_size - uart_data->tx_data_buff_in], + size - (uart_data->tx_data_buff_size - uart_data->tx_data_buff_in)); + uart_data->tx_data_buff_in = size - (uart_data->tx_data_buff_size - uart_data->tx_data_buff_in); } - if (hw_data->tx_data_buff_in >= APP_TRACE_MAX_TX_BUFF_UART) { - hw_data->tx_data_buff_in = 0; + if (uart_data->tx_data_buff_in >= uart_data->tx_data_buff_size) { + uart_data->tx_data_buff_in = 0; } } else { - hw_data->circular_buff_overflow = true; + uart_data->circular_buff_overflow = true; } - if (esp_apptrace_uart_unlock(hw_data) != ESP_OK) { + if (esp_apptrace_uart_unlock(uart_data) != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return ESP_OK; } -static void send_buff_data(esp_apptrace_uart_data_t *hw_data, esp_apptrace_tmo_t *tmo) +static void send_buff_data(void *hw_data, esp_apptrace_tmo_t *tmo) { - if (hw_data->tx_data_buff_in == hw_data->tx_data_buff_out) { + esp_apptrace_uart_data_t *uart_data = hw_data; + + if (uart_data->tx_data_buff_in == uart_data->tx_data_buff_out) { return; } // We store current in position to handle it without lock - volatile int32_t in_position = hw_data->tx_data_buff_in; - if (in_position > hw_data->tx_data_buff_out) { - int bytes_sent = uart_write_bytes(hw_data->port_num, &hw_data->tx_data_buff[hw_data->tx_data_buff_out], in_position - hw_data->tx_data_buff_out); - hw_data->tx_data_buff_out += bytes_sent; + volatile int32_t in_position = uart_data->tx_data_buff_in; + if (in_position > uart_data->tx_data_buff_out) { + int bytes_sent = uart_write_bytes(uart_data->port_num, + &uart_data->tx_data_buff[uart_data->tx_data_buff_out], + in_position - uart_data->tx_data_buff_out); + uart_data->tx_data_buff_out += bytes_sent; } else { - int bytes_sent = uart_write_bytes(hw_data->port_num, &hw_data->tx_data_buff[hw_data->tx_data_buff_out], APP_TRACE_MAX_TX_BUFF_UART - hw_data->tx_data_buff_out); - hw_data->tx_data_buff_out += bytes_sent; - if (hw_data->tx_data_buff_out >= APP_TRACE_MAX_TX_BUFF_UART) { - hw_data->tx_data_buff_out = 0; + int bytes_sent = uart_write_bytes(uart_data->port_num, + &uart_data->tx_data_buff[uart_data->tx_data_buff_out], + uart_data->tx_data_buff_size - uart_data->tx_data_buff_out); + uart_data->tx_data_buff_out += bytes_sent; + if (uart_data->tx_data_buff_out >= uart_data->tx_data_buff_size) { + uart_data->tx_data_buff_out = 0; } } } @@ -130,20 +145,21 @@ static void send_buff_data(esp_apptrace_uart_data_t *hw_data, esp_apptrace_tmo_t static void esp_apptrace_send_uart_tx_task(void *arg) { - esp_apptrace_uart_data_t *hw_data = (esp_apptrace_uart_data_t *)arg; + esp_apptrace_uart_data_t *uart_data = arg; esp_apptrace_tmo_t tmo; + esp_apptrace_tmo_init(&tmo, APP_TRACE_UART_STOP_WAIT_TMO); vTaskDelay(10); while (1) { - send_buff_data(hw_data, &tmo); + send_buff_data(uart_data, &tmo); vTaskDelay(10); - if (hw_data->circular_buff_overflow == true) { - hw_data->circular_buff_overflow = false; + if (uart_data->circular_buff_overflow == true) { + uart_data->circular_buff_overflow = false; ESP_LOGE(TAG, "Buffer overflow. Please increase UART baudrate, or increase UART TX ring buffer size in menuconfig."); } - if (hw_data->message_buff_overflow == true) { - hw_data->message_buff_overflow = false; + if (uart_data->message_buff_overflow == true) { + uart_data->message_buff_overflow = false; ESP_LOGE(TAG, "Message size more then message buffer!"); } } @@ -151,157 +167,181 @@ static void esp_apptrace_send_uart_tx_task(void *arg) static const int APP_TRACE_UART_RX_BUF_SIZE = 4024; -static esp_err_t esp_apptrace_uart_init(esp_apptrace_uart_data_t *hw_data) +static esp_err_t esp_apptrace_uart_init(void *hw_data, const esp_apptrace_config_t *config) { + esp_apptrace_uart_data_t *uart_data = hw_data; + const esp_apptrace_uart_config_t *apptrace_uart_config = &config->dest_cfg.uart; + + /* esp_apptrace_uart_init() is called on every core, so ensure to do main initialization only once */ int core_id = esp_cpu_get_core_id(); if (core_id == 0) { - hw_data->tx_data_buff = (uint8_t *)heap_caps_malloc(APP_TRACE_MAX_TX_BUFF_UART, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - if (hw_data->tx_data_buff == NULL) { + uart_data->tx_data_buff_size = apptrace_uart_config->tx_buff_size; + uart_data->tx_data_buff = heap_caps_malloc(uart_data->tx_data_buff_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if (uart_data->tx_data_buff == NULL) { return ESP_ERR_NO_MEM; } - hw_data->tx_data_buff_in = 0; - hw_data->tx_data_buff_out = 0; - hw_data->tx_msg_buff = (uint8_t *)heap_caps_malloc(APP_TRACE_MAX_TX_MSG_UART, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - if (hw_data->tx_msg_buff == NULL) { + uart_data->tx_data_buff_in = 0; + uart_data->tx_data_buff_out = 0; + uart_data->tx_msg_buff_size = apptrace_uart_config->tx_msg_size; + uart_data->tx_msg_buff = heap_caps_malloc(uart_data->tx_msg_buff_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if (uart_data->tx_msg_buff == NULL) { return ESP_ERR_NO_MEM; } - hw_data->tx_msg_buff_size = 0; - hw_data->down_buffer_size = 0; - hw_data->message_buff_overflow = false; - hw_data->circular_buff_overflow = false; + uart_data->tx_pending_msg_size = 0; + uart_data->down_buffer_size = 0; + uart_data->message_buff_overflow = false; + uart_data->circular_buff_overflow = false; - assert((hw_data->port_num <= SOC_UART_NUM) && "Not possible to configure UART. Please check selected UART port"); + assert((uart_data->port_num <= SOC_UART_NUM) && "Not possible to configure UART. Please check selected UART port"); int source_clk = UART_SCLK_DEFAULT; #if SOC_UART_LP_NUM > 0 - if (hw_data->port_num >= SOC_UART_HP_NUM) { + if (uart_data->port_num >= SOC_UART_HP_NUM) { source_clk = LP_UART_SCLK_DEFAULT; } #endif const uart_config_t uart_config = { - .baud_rate = CONFIG_APPTRACE_UART_BAUDRATE, + .baud_rate = apptrace_uart_config->baud_rate, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = source_clk, }; - ESP_LOGI(TAG, "UART baud rate: %i", CONFIG_APPTRACE_UART_BAUDRATE); + ESP_LOGI(TAG, "UART baud rate: %i", apptrace_uart_config->baud_rate); // We won't use a buffer for sending data. - esp_err_t err = uart_driver_install(hw_data->port_num, APP_TRACE_UART_RX_BUF_SIZE, APP_TRACE_UART_RX_BUF_SIZE, 0, NULL, 0); - assert((err == ESP_OK) && "Not possible to install UART. Please check and change menuconfig parameters!"); - err = uart_param_config(hw_data->port_num, &uart_config); - assert((err == ESP_OK) && "Not possible to configure UART. Please check and change menuconfig parameters!"); - err = uart_set_pin(hw_data->port_num, CONFIG_APPTRACE_UART_TX_GPIO, CONFIG_APPTRACE_UART_RX_GPIO, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - assert((err == ESP_OK) && "Not possible to configure UART RX/TX pins. Please check and change menuconfig parameters!"); + esp_err_t __attribute__((unused)) err = uart_driver_install(uart_data->port_num, + APP_TRACE_UART_RX_BUF_SIZE, + APP_TRACE_UART_RX_BUF_SIZE, + 0, + NULL, + 0); + assert((err == ESP_OK) && "Not possible to install UART. Please check and change uart parameters!"); + err = uart_param_config(uart_data->port_num, &uart_config); + assert((err == ESP_OK) && "Not possible to configure UART. Please check and change uart parameters!"); + err = uart_set_pin(uart_data->port_num, + apptrace_uart_config->tx_pin_num, + apptrace_uart_config->rx_pin_num, + UART_PIN_NO_CHANGE, + UART_PIN_NO_CHANGE); + assert((err == ESP_OK) && "Not possible to configure UART RX/TX pins. Please check and change the uart pins!"); - int uart_prio = CONFIG_APPTRACE_UART_TASK_PRIO; + int uart_prio = apptrace_uart_config->task_prio; if (uart_prio >= (configMAX_PRIORITIES - 1)) { uart_prio = configMAX_PRIORITIES - 1; } - err = xTaskCreate(esp_apptrace_send_uart_tx_task, "app_trace_uart_tx_task", 2500, hw_data, uart_prio, NULL); + err = xTaskCreate(esp_apptrace_send_uart_tx_task, "app_trace_uart_tx_task", 2500, uart_data, uart_prio, NULL); assert((err == pdPASS) && "Not possible to configure UART. Not possible to create task!"); #if CONFIG_APPTRACE_LOCK_ENABLE - esp_apptrace_lock_init(&hw_data->lock); + esp_apptrace_lock_init(&uart_data->lock); #endif } // init UART on this CPU esp_apptrace_uart_hw_init(); - hw_data->inited |= 1 << core_id; + uart_data->inited |= 1 << core_id; return ESP_OK; } -static uint8_t *esp_apptrace_uart_up_buffer_get(esp_apptrace_uart_data_t *hw_data, uint32_t size, esp_apptrace_tmo_t *tmo) +static uint8_t *esp_apptrace_uart_up_buffer_get(void *hw_data, uint32_t size, esp_apptrace_tmo_t *tmo) { - uint8_t *ptr; - if (size > APP_TRACE_MAX_TX_MSG_UART) { - hw_data->message_buff_overflow = true; + esp_apptrace_uart_data_t *uart_data = hw_data; + + if (size > uart_data->tx_msg_buff_size) { + uart_data->message_buff_overflow = true; return NULL; } - if (hw_data->tx_msg_buff_size != 0) { + if (uart_data->tx_pending_msg_size != 0) { // A previous message was not sent. return NULL; } - esp_err_t res = esp_apptrace_uart_lock(hw_data, tmo); + esp_err_t res = esp_apptrace_uart_lock(uart_data, tmo); if (res != ESP_OK) { return NULL; } - ptr = hw_data->tx_msg_buff; - hw_data->tx_msg_buff_size = size; + uint8_t *ptr = uart_data->tx_msg_buff; + + // Set the amount of data to send + uart_data->tx_pending_msg_size = size; // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data - if (esp_apptrace_uart_unlock(hw_data) != ESP_OK) { + if (esp_apptrace_uart_unlock(uart_data) != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return ptr; } -static esp_err_t esp_apptrace_uart_up_buffer_put(esp_apptrace_uart_data_t *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_uart_up_buffer_put(void *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) { - esp_err_t res = esp_apptrace_send_uart_data(hw_data, (const char *)ptr, hw_data->tx_msg_buff_size, tmo); + esp_apptrace_uart_data_t *uart_data = hw_data; + esp_err_t res = esp_apptrace_send_uart_data(uart_data, (const char *)ptr, uart_data->tx_pending_msg_size, tmo); // Clear size to indicate that we've sent data - hw_data->tx_msg_buff_size = 0; + uart_data->tx_pending_msg_size = 0; return res; } -static void esp_apptrace_uart_down_buffer_config(esp_apptrace_uart_data_t *hw_data, uint8_t *buf, uint32_t size) +static void esp_apptrace_uart_down_buffer_config(void *hw_data, uint8_t *buf, uint32_t size) { - hw_data->down_buffer = (uint8_t *)malloc(size); - if (hw_data->down_buffer == NULL) { + esp_apptrace_uart_data_t *uart_data = hw_data; + + uart_data->down_buffer = (uint8_t *)malloc(size); + if (uart_data->down_buffer == NULL) { assert(false && "Failed to allocate apptrace uart down buffer!"); } - hw_data->down_buffer_size = size; + uart_data->down_buffer_size = size; } -static uint8_t *esp_apptrace_uart_down_buffer_get(esp_apptrace_uart_data_t *hw_data, uint32_t *size, esp_apptrace_tmo_t *tmo) +static uint8_t *esp_apptrace_uart_down_buffer_get(void *hw_data, uint32_t *size, esp_apptrace_tmo_t *tmo) { + esp_apptrace_uart_data_t *uart_data = hw_data; uint8_t *ptr = NULL; - if (*size > hw_data->down_buffer_size) { + if (*size > uart_data->down_buffer_size) { return NULL; } - esp_err_t res = esp_apptrace_uart_lock(hw_data, tmo); + esp_err_t res = esp_apptrace_uart_lock(uart_data, tmo); if (res != ESP_OK) { return NULL; } size_t uart_fifolen = 0; - uart_get_buffered_data_len(hw_data->port_num, &uart_fifolen); + uart_get_buffered_data_len(uart_data->port_num, &uart_fifolen); if (uart_fifolen > 0) { if (*size < uart_fifolen) { uart_fifolen = *size; } *size = uart_fifolen; - ptr = hw_data->down_buffer; - *size = uart_read_bytes(hw_data->port_num, ptr, uart_fifolen, 0); + ptr = uart_data->down_buffer; + *size = uart_read_bytes(uart_data->port_num, ptr, uart_fifolen, 0); } - if (esp_apptrace_uart_unlock(hw_data) != ESP_OK) { + if (esp_apptrace_uart_unlock(uart_data) != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return ptr; } -static esp_err_t esp_apptrace_uart_down_buffer_put(esp_apptrace_uart_data_t *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_uart_down_buffer_put(void *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) { return ESP_OK; } -static bool esp_apptrace_uart_host_is_connected(esp_apptrace_uart_data_t *hw_data) +static bool esp_apptrace_uart_host_is_connected(void *hw_data) { - return hw_data->inited & 1; + esp_apptrace_uart_data_t *uart_data = hw_data; + + return uart_data->inited & 1; } -static esp_err_t esp_apptrace_uart_flush_nolock(esp_apptrace_uart_data_t *hw_data, uint32_t min_sz, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_uart_flush_nolock(void *hw_data, uint32_t min_sz, esp_apptrace_tmo_t *tmo) { return ESP_OK; } -static esp_err_t esp_apptrace_uart_flush(esp_apptrace_uart_data_t *hw_data, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_uart_flush(void *hw_data, esp_apptrace_tmo_t *tmo) { return ESP_OK; } @@ -312,15 +352,15 @@ esp_apptrace_hw_t *esp_apptrace_uart_hw_get(int num, void **data) static esp_apptrace_uart_data_t s_uart_hw_data; static esp_apptrace_hw_t s_uart_hw = { - .init = (esp_err_t (*)(void *))esp_apptrace_uart_init, - .get_up_buffer = (uint8_t *(*)(void *, uint32_t, esp_apptrace_tmo_t *))esp_apptrace_uart_up_buffer_get, - .put_up_buffer = (esp_err_t (*)(void *, uint8_t *, esp_apptrace_tmo_t *))esp_apptrace_uart_up_buffer_put, - .flush_up_buffer_nolock = (esp_err_t (*)(void *, uint32_t, esp_apptrace_tmo_t *))esp_apptrace_uart_flush_nolock, - .flush_up_buffer = (esp_err_t (*)(void *, esp_apptrace_tmo_t *))esp_apptrace_uart_flush, - .down_buffer_config = (void (*)(void *, uint8_t *, uint32_t))esp_apptrace_uart_down_buffer_config, - .get_down_buffer = (uint8_t *(*)(void *, uint32_t *, esp_apptrace_tmo_t *))esp_apptrace_uart_down_buffer_get, - .put_down_buffer = (esp_err_t (*)(void *, uint8_t *, esp_apptrace_tmo_t *))esp_apptrace_uart_down_buffer_put, - .host_is_connected = (bool (*)(void *))esp_apptrace_uart_host_is_connected, + .init = esp_apptrace_uart_init, + .get_up_buffer = esp_apptrace_uart_up_buffer_get, + .put_up_buffer = esp_apptrace_uart_up_buffer_put, + .flush_up_buffer_nolock = esp_apptrace_uart_flush_nolock, + .flush_up_buffer = esp_apptrace_uart_flush, + .down_buffer_config = esp_apptrace_uart_down_buffer_config, + .get_down_buffer = esp_apptrace_uart_down_buffer_get, + .put_down_buffer = esp_apptrace_uart_down_buffer_put, + .host_is_connected = esp_apptrace_uart_host_is_connected, }; s_uart_hw_data.port_num = num; *data = &s_uart_hw_data; diff --git a/components/app_trace/port/riscv/port_jtag.c b/components/app_trace/port/riscv/port_jtag.c index c98d3edf634..03b72826949 100644 --- a/components/app_trace/port/riscv/port_jtag.c +++ b/components/app_trace/port/riscv/port_jtag.c @@ -7,6 +7,7 @@ #include "sdkconfig.h" #include "esp_cpu.h" #include "esp_log.h" +#include "esp_app_trace_config.h" #include "esp_app_trace_membufs_proto.h" #include "esp_app_trace_port.h" #include "riscv/semihosting.h" @@ -74,10 +75,11 @@ __attribute__((weak)) void esp_apptrace_get_up_buffers(esp_apptrace_mem_block_t mem_blocks_cfg[1].sz = CONFIG_APPTRACE_BUF_SIZE; } -static esp_err_t esp_apptrace_riscv_lock(esp_apptrace_riscv_data_t *hw_data, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_riscv_lock(void *hw_data, esp_apptrace_tmo_t *tmo) { #if CONFIG_APPTRACE_LOCK_ENABLE - esp_err_t ret = esp_apptrace_lock_take(&hw_data->lock, tmo); + esp_apptrace_riscv_data_t *riscv_data = hw_data; + esp_err_t ret = esp_apptrace_lock_take(&riscv_data->lock, tmo); if (ret != ESP_OK) { return ESP_FAIL; } @@ -85,11 +87,12 @@ static esp_err_t esp_apptrace_riscv_lock(esp_apptrace_riscv_data_t *hw_data, esp return ESP_OK; } -static esp_err_t esp_apptrace_riscv_unlock(esp_apptrace_riscv_data_t *hw_data) +static esp_err_t esp_apptrace_riscv_unlock(void *hw_data) { esp_err_t ret = ESP_OK; #if CONFIG_APPTRACE_LOCK_ENABLE - ret = esp_apptrace_lock_give(&hw_data->lock); + esp_apptrace_riscv_data_t *riscv_data = hw_data; + ret = esp_apptrace_lock_give(&riscv_data->lock); #endif return ret; } @@ -98,89 +101,96 @@ static esp_err_t esp_apptrace_riscv_unlock(esp_apptrace_riscv_data_t *hw_data) /***************************** Apptrace HW iface *****************************************/ /*****************************************************************************************/ -static esp_err_t esp_apptrace_riscv_init(esp_apptrace_riscv_data_t *hw_data) +static esp_err_t esp_apptrace_riscv_init(void *hw_data, const esp_apptrace_config_t *config) { - int core_id = esp_cpu_get_core_id(); + esp_apptrace_riscv_data_t *riscv_data = hw_data; - if (hw_data->inited == 0) { + /* esp_apptrace_riscv_init() is called on every core, so ensure to do main initialization only once */ + int core_id = esp_cpu_get_core_id(); + if (core_id == 0) { esp_apptrace_mem_block_t mem_blocks_cfg[2]; esp_apptrace_get_up_buffers(mem_blocks_cfg); - esp_err_t res = esp_apptrace_membufs_init(&hw_data->membufs, mem_blocks_cfg); + riscv_data->membufs.header_size = ESP_APPTRACE_HEADER_SIZE_32; + esp_err_t res = esp_apptrace_membufs_init(&riscv_data->membufs, mem_blocks_cfg); if (res != ESP_OK) { ESP_APPTRACE_LOGE("Failed to init membufs proto (%d)!", res); return res; } #if CONFIG_APPTRACE_LOCK_ENABLE - esp_apptrace_lock_init(&hw_data->lock); + esp_apptrace_lock_init(&riscv_data->lock); #endif } - hw_data->inited |= 1 << core_id; + riscv_data->inited |= 1 << core_id; ESP_APPTRACE_LOGI("Apptrace initialized on CPU%d. Tracing control block @ %p.", core_id, &s_tracing_ctrl[core_id]); - s_tracing_ctrl[core_id].mem_blocks = hw_data->membufs.blocks; + s_tracing_ctrl[core_id].mem_blocks = riscv_data->membufs.blocks; for (int i = 0; i < 2; i++) { ESP_APPTRACE_LOGD("Mem buf[%d] %" PRIu32 " bytes @ %p (%p/%p)", i, s_tracing_ctrl[core_id].mem_blocks[i].sz, s_tracing_ctrl[core_id].mem_blocks[i].start, &(s_tracing_ctrl[core_id].mem_blocks[i].start), &(s_tracing_ctrl[core_id].mem_blocks[i].sz)); } // notify host about control block address - int res = esp_apptrace_advertise_ctrl_block(&s_tracing_ctrl[core_id]); + int __attribute__((unused)) res = esp_apptrace_advertise_ctrl_block(&s_tracing_ctrl[core_id]); assert(res == 0 && "Failed to send config to host!"); return ESP_OK; } -static uint8_t *esp_apptrace_riscv_up_buffer_get(esp_apptrace_riscv_data_t *hw_data, uint32_t size, esp_apptrace_tmo_t *tmo) +static uint8_t *esp_apptrace_riscv_up_buffer_get(void *hw_data, uint32_t size, esp_apptrace_tmo_t *tmo) { - uint8_t *ptr; + esp_apptrace_riscv_data_t *riscv_data = hw_data; - if (!ESP_APPTRACE_RISCV_INITED(hw_data)) { + if (!ESP_APPTRACE_RISCV_INITED(riscv_data)) { return NULL; } - esp_err_t res = esp_apptrace_riscv_lock(hw_data, tmo); + esp_err_t res = esp_apptrace_riscv_lock(riscv_data, tmo); if (res != ESP_OK) { return NULL; } - ptr = esp_apptrace_membufs_up_buffer_get(&hw_data->membufs, size, tmo); + uint8_t *ptr = esp_apptrace_membufs_up_buffer_get(&riscv_data->membufs, size, tmo); // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data - if (esp_apptrace_riscv_unlock(hw_data) != ESP_OK) { + if (esp_apptrace_riscv_unlock(riscv_data) != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return ptr; } -static esp_err_t esp_apptrace_riscv_up_buffer_put(esp_apptrace_riscv_data_t *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_riscv_up_buffer_put(void *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) { - if (!ESP_APPTRACE_RISCV_INITED(hw_data)) { + esp_apptrace_riscv_data_t *riscv_data = hw_data; + + if (!ESP_APPTRACE_RISCV_INITED(riscv_data)) { return ESP_ERR_INVALID_STATE; } // Can avoid locking because esp_apptrace_membufs_up_buffer_put() just modifies buffer's header - esp_err_t res = esp_apptrace_membufs_up_buffer_put(&hw_data->membufs, ptr, tmo); + esp_err_t res = esp_apptrace_membufs_up_buffer_put(&riscv_data->membufs, ptr, tmo); return res; } -static void esp_apptrace_riscv_down_buffer_config(esp_apptrace_riscv_data_t *hw_data, uint8_t *buf, uint32_t size) +static void esp_apptrace_riscv_down_buffer_config(void *hw_data, uint8_t *buf, uint32_t size) { - if (!ESP_APPTRACE_RISCV_INITED(hw_data)) { + esp_apptrace_riscv_data_t *riscv_data = hw_data; + + if (!ESP_APPTRACE_RISCV_INITED(riscv_data)) { return; } - esp_apptrace_membufs_down_buffer_config(&hw_data->membufs, buf, size); + esp_apptrace_membufs_down_buffer_config(&riscv_data->membufs, buf, size); } -static uint8_t *esp_apptrace_riscv_down_buffer_get(esp_apptrace_riscv_data_t *hw_data, uint32_t *size, esp_apptrace_tmo_t *tmo) +static uint8_t *esp_apptrace_riscv_down_buffer_get(void *hw_data, uint32_t *size, esp_apptrace_tmo_t *tmo) { - uint8_t *ptr; + esp_apptrace_riscv_data_t *riscv_data = hw_data; - if (!ESP_APPTRACE_RISCV_INITED(hw_data)) { + if (!ESP_APPTRACE_RISCV_INITED(riscv_data)) { return NULL; } - esp_err_t res = esp_apptrace_riscv_lock(hw_data, tmo); + esp_err_t res = esp_apptrace_riscv_lock(riscv_data, tmo); if (res != ESP_OK) { return NULL; } - ptr = esp_apptrace_membufs_down_buffer_get(&hw_data->membufs, size, tmo); + uint8_t *ptr = esp_apptrace_membufs_down_buffer_get(&riscv_data->membufs, size, tmo); // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data if (esp_apptrace_riscv_unlock(hw_data) != ESP_OK) { @@ -189,9 +199,11 @@ static uint8_t *esp_apptrace_riscv_down_buffer_get(esp_apptrace_riscv_data_t *hw return ptr; } -static esp_err_t esp_apptrace_riscv_down_buffer_put(esp_apptrace_riscv_data_t *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_riscv_down_buffer_put(void *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) { - if (!ESP_APPTRACE_RISCV_INITED(hw_data)) { + esp_apptrace_riscv_data_t *riscv_data = hw_data; + + if (!ESP_APPTRACE_RISCV_INITED(riscv_data)) { return ESP_ERR_INVALID_STATE; } // Can avoid locking because esp_apptrace_membufs_down_buffer_put() does nothing @@ -200,7 +212,7 @@ static esp_err_t esp_apptrace_riscv_down_buffer_put(esp_apptrace_riscv_data_t *h return res; }*/ - esp_err_t res = esp_apptrace_membufs_down_buffer_put(&hw_data->membufs, ptr, tmo); + esp_err_t res = esp_apptrace_membufs_down_buffer_put(&riscv_data->membufs, ptr, tmo); // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data /*if (esp_apptrace_riscv_unlock(hw_data) != ESP_OK) { @@ -209,36 +221,42 @@ static esp_err_t esp_apptrace_riscv_down_buffer_put(esp_apptrace_riscv_data_t *h return res; } -static bool esp_apptrace_riscv_host_is_connected(esp_apptrace_riscv_data_t *hw_data) +static bool esp_apptrace_riscv_host_is_connected(void *hw_data) { - if (!ESP_APPTRACE_RISCV_INITED(hw_data)) { + esp_apptrace_riscv_data_t *riscv_data = hw_data; + + if (!ESP_APPTRACE_RISCV_INITED(riscv_data)) { return false; } return s_tracing_ctrl[esp_cpu_get_core_id()].ctrl & ESP_APPTRACE_RISCV_HOST_CONNECT ? true : false; } -static esp_err_t esp_apptrace_riscv_flush_nolock(esp_apptrace_riscv_data_t *hw_data, uint32_t min_sz, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_riscv_flush_nolock(void *hw_data, uint32_t min_sz, esp_apptrace_tmo_t *tmo) { - if (!ESP_APPTRACE_RISCV_INITED(hw_data)) { + esp_apptrace_riscv_data_t *riscv_data = hw_data; + + if (!ESP_APPTRACE_RISCV_INITED(riscv_data)) { return ESP_ERR_INVALID_STATE; } - return esp_apptrace_membufs_flush_nolock(&hw_data->membufs, min_sz, tmo); + return esp_apptrace_membufs_flush_nolock(&riscv_data->membufs, min_sz, tmo); } -static esp_err_t esp_apptrace_riscv_flush(esp_apptrace_riscv_data_t *hw_data, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_riscv_flush(void *hw_data, esp_apptrace_tmo_t *tmo) { - if (!ESP_APPTRACE_RISCV_INITED(hw_data)) { + esp_apptrace_riscv_data_t *riscv_data = hw_data; + + if (!ESP_APPTRACE_RISCV_INITED(riscv_data)) { return ESP_ERR_INVALID_STATE; } - esp_err_t res = esp_apptrace_riscv_lock(hw_data, tmo); + esp_err_t res = esp_apptrace_riscv_lock(riscv_data, tmo); if (res != ESP_OK) { return res; } - res = esp_apptrace_membufs_flush_nolock(&hw_data->membufs, 0, tmo); + res = esp_apptrace_membufs_flush_nolock(&riscv_data->membufs, 0, tmo); // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data - if (esp_apptrace_riscv_unlock(hw_data) != ESP_OK) { + if (esp_apptrace_riscv_unlock(riscv_data) != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return res; @@ -319,6 +337,12 @@ static bool esp_apptrace_riscv_host_data_pending(void) return (ctrl_reg & ESP_APPTRACE_RISCV_HOST_DATA) ? true : false; } +static void esp_apptrace_riscv_set_header_size(void *hw_data, esp_apptrace_header_size_t header_size) +{ + esp_apptrace_riscv_data_t *riscv_data = hw_data; + riscv_data->membufs.header_size = header_size; +} + esp_apptrace_hw_t *esp_apptrace_jtag_hw_get(void **data) { static esp_apptrace_membufs_proto_hw_t s_trace_proto_hw = { @@ -333,15 +357,16 @@ esp_apptrace_hw_t *esp_apptrace_jtag_hw_get(void **data) }, }; static esp_apptrace_hw_t s_trace_hw = { - .init = (esp_err_t (*)(void *))esp_apptrace_riscv_init, - .get_up_buffer = (uint8_t *(*)(void *, uint32_t, esp_apptrace_tmo_t *))esp_apptrace_riscv_up_buffer_get, - .put_up_buffer = (esp_err_t (*)(void *, uint8_t *, esp_apptrace_tmo_t *))esp_apptrace_riscv_up_buffer_put, - .flush_up_buffer_nolock = (esp_err_t (*)(void *, uint32_t, esp_apptrace_tmo_t *))esp_apptrace_riscv_flush_nolock, - .flush_up_buffer = (esp_err_t (*)(void *, esp_apptrace_tmo_t *))esp_apptrace_riscv_flush, - .down_buffer_config = (void (*)(void *, uint8_t *, uint32_t))esp_apptrace_riscv_down_buffer_config, - .get_down_buffer = (uint8_t *(*)(void *, uint32_t *, esp_apptrace_tmo_t *))esp_apptrace_riscv_down_buffer_get, - .put_down_buffer = (esp_err_t (*)(void *, uint8_t *, esp_apptrace_tmo_t *))esp_apptrace_riscv_down_buffer_put, - .host_is_connected = (bool (*)(void *))esp_apptrace_riscv_host_is_connected, + .init = esp_apptrace_riscv_init, + .get_up_buffer = esp_apptrace_riscv_up_buffer_get, + .put_up_buffer = esp_apptrace_riscv_up_buffer_put, + .flush_up_buffer_nolock = esp_apptrace_riscv_flush_nolock, + .flush_up_buffer = esp_apptrace_riscv_flush, + .down_buffer_config = esp_apptrace_riscv_down_buffer_config, + .get_down_buffer = esp_apptrace_riscv_down_buffer_get, + .put_down_buffer = esp_apptrace_riscv_down_buffer_put, + .host_is_connected = esp_apptrace_riscv_host_is_connected, + .set_header_size = esp_apptrace_riscv_set_header_size, }; *data = &s_trace_hw_data; return &s_trace_hw; diff --git a/components/app_trace/port/xtensa/port_jtag.c b/components/app_trace/port/xtensa/port_jtag.c index f4002388c2a..c1aa842cdd3 100644 --- a/components/app_trace/port/xtensa/port_jtag.c +++ b/components/app_trace/port/xtensa/port_jtag.c @@ -195,10 +195,11 @@ static uint8_t * const s_trax_blocks[] = { (uint8_t *)TRACEMEM_BLK1_ADDR }; -static esp_err_t esp_apptrace_trax_lock(esp_apptrace_trax_data_t *hw_data, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_trax_lock(void *hw_data, esp_apptrace_tmo_t *tmo) { #if CONFIG_APPTRACE_LOCK_ENABLE - esp_err_t ret = esp_apptrace_lock_take(&hw_data->lock, tmo); + esp_apptrace_trax_data_t *trax_data = hw_data; + esp_err_t ret = esp_apptrace_lock_take(&trax_data->lock, tmo); if (ret != ESP_OK) { return ESP_FAIL; } @@ -206,11 +207,12 @@ static esp_err_t esp_apptrace_trax_lock(esp_apptrace_trax_data_t *hw_data, esp_a return ESP_OK; } -static esp_err_t esp_apptrace_trax_unlock(esp_apptrace_trax_data_t *hw_data) +static esp_err_t esp_apptrace_trax_unlock(void *hw_data) { esp_err_t ret = ESP_OK; #if CONFIG_APPTRACE_LOCK_ENABLE - ret = esp_apptrace_lock_give(&hw_data->lock); + esp_apptrace_trax_data_t *trax_data = hw_data; + ret = esp_apptrace_lock_give(&trax_data->lock); #endif return ret; } @@ -262,11 +264,12 @@ static inline void esp_apptrace_trax_memory_enable(void) /***************************** Apptrace HW iface *****************************************/ /*****************************************************************************************/ -static esp_err_t esp_apptrace_trax_init(esp_apptrace_trax_data_t *hw_data) +static esp_err_t esp_apptrace_trax_init(void *hw_data, const esp_apptrace_config_t *config) { - int core_id = esp_cpu_get_core_id(); + esp_apptrace_trax_data_t *trax_data = hw_data; // 'esp_apptrace_trax_init()' is called on every core, so ensure to do main initialization only once + int core_id = esp_cpu_get_core_id(); if (core_id == 0) { esp_apptrace_mem_block_t mem_blocks_cfg[2] = { { @@ -278,87 +281,94 @@ static esp_err_t esp_apptrace_trax_init(esp_apptrace_trax_data_t *hw_data) .sz = ESP_APPTRACE_TRAX_BLOCK_SIZE }, }; - esp_err_t res = esp_apptrace_membufs_init(&hw_data->membufs, mem_blocks_cfg); + trax_data->membufs.header_size = ESP_APPTRACE_HEADER_SIZE_32; + esp_err_t res = esp_apptrace_membufs_init(&trax_data->membufs, mem_blocks_cfg); if (res != ESP_OK) { ESP_APPTRACE_LOGE("Failed to init membufs proto (%d)!", res); return res; } #if CONFIG_APPTRACE_LOCK_ENABLE - esp_apptrace_lock_init(&hw_data->lock); + esp_apptrace_lock_init(&trax_data->lock); #endif esp_apptrace_trax_memory_enable(); esp_apptrace_trax_select_memory_block(0); } // init TRAX on this CPU esp_apptrace_trax_hw_init(); - hw_data->inited |= 1 << core_id; + trax_data->inited |= 1 << core_id; return ESP_OK; } -static uint8_t *esp_apptrace_trax_up_buffer_get(esp_apptrace_trax_data_t *hw_data, uint32_t size, esp_apptrace_tmo_t *tmo) +static uint8_t *esp_apptrace_trax_up_buffer_get(void *hw_data, uint32_t size, esp_apptrace_tmo_t *tmo) { - uint8_t *ptr; + esp_apptrace_trax_data_t *trax_data = hw_data; - if (!ESP_APPTRACE_TRAX_INITED(hw_data)) { + if (!ESP_APPTRACE_TRAX_INITED(trax_data)) { return NULL; } - esp_err_t res = esp_apptrace_trax_lock(hw_data, tmo); + esp_err_t res = esp_apptrace_trax_lock(trax_data, tmo); if (res != ESP_OK) { return NULL; } - ptr = esp_apptrace_membufs_up_buffer_get(&hw_data->membufs, size, tmo); + uint8_t *ptr = esp_apptrace_membufs_up_buffer_get(&trax_data->membufs, size, tmo); // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data - if (esp_apptrace_trax_unlock(hw_data) != ESP_OK) { + if (esp_apptrace_trax_unlock(trax_data) != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return ptr; } -static esp_err_t esp_apptrace_trax_up_buffer_put(esp_apptrace_trax_data_t *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_trax_up_buffer_put(void *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) { - if (!ESP_APPTRACE_TRAX_INITED(hw_data)) { + esp_apptrace_trax_data_t *trax_data = hw_data; + + if (!ESP_APPTRACE_TRAX_INITED(trax_data)) { return ESP_ERR_INVALID_STATE; } // Can avoid locking because esp_apptrace_membufs_up_buffer_put() just modifies buffer's header - esp_err_t res = esp_apptrace_membufs_up_buffer_put(&hw_data->membufs, ptr, tmo); + esp_err_t res = esp_apptrace_membufs_up_buffer_put(&trax_data->membufs, ptr, tmo); return res; } -static void esp_apptrace_trax_down_buffer_config(esp_apptrace_trax_data_t *hw_data, uint8_t *buf, uint32_t size) +static void esp_apptrace_trax_down_buffer_config(void *hw_data, uint8_t *buf, uint32_t size) { - if (!ESP_APPTRACE_TRAX_INITED(hw_data)) { + esp_apptrace_trax_data_t *trax_data = hw_data; + + if (!ESP_APPTRACE_TRAX_INITED(trax_data)) { return; } - esp_apptrace_membufs_down_buffer_config(&hw_data->membufs, buf, size); + esp_apptrace_membufs_down_buffer_config(&trax_data->membufs, buf, size); } -static uint8_t *esp_apptrace_trax_down_buffer_get(esp_apptrace_trax_data_t *hw_data, uint32_t *size, esp_apptrace_tmo_t *tmo) +static uint8_t *esp_apptrace_trax_down_buffer_get(void *hw_data, uint32_t *size, esp_apptrace_tmo_t *tmo) { - uint8_t *ptr; + esp_apptrace_trax_data_t *trax_data = hw_data; - if (!ESP_APPTRACE_TRAX_INITED(hw_data)) { + if (!ESP_APPTRACE_TRAX_INITED(trax_data)) { return NULL; } - esp_err_t res = esp_apptrace_trax_lock(hw_data, tmo); + esp_err_t res = esp_apptrace_trax_lock(trax_data, tmo); if (res != ESP_OK) { return NULL; } - ptr = esp_apptrace_membufs_down_buffer_get(&hw_data->membufs, size, tmo); + uint8_t *ptr = esp_apptrace_membufs_down_buffer_get(&trax_data->membufs, size, tmo); // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data - if (esp_apptrace_trax_unlock(hw_data) != ESP_OK) { + if (esp_apptrace_trax_unlock(trax_data) != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return ptr; } -static esp_err_t esp_apptrace_trax_down_buffer_put(esp_apptrace_trax_data_t *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_trax_down_buffer_put(void *hw_data, uint8_t *ptr, esp_apptrace_tmo_t *tmo) { - if (!ESP_APPTRACE_TRAX_INITED(hw_data)) { + esp_apptrace_trax_data_t *trax_data = hw_data; + + if (!ESP_APPTRACE_TRAX_INITED(trax_data)) { return ESP_ERR_INVALID_STATE; } // Can avoid locking because esp_apptrace_membufs_down_buffer_put() does nothing @@ -367,7 +377,7 @@ static esp_err_t esp_apptrace_trax_down_buffer_put(esp_apptrace_trax_data_t *hw_ return res; }*/ - esp_err_t res = esp_apptrace_membufs_down_buffer_put(&hw_data->membufs, ptr, tmo); + esp_err_t res = esp_apptrace_membufs_down_buffer_put(&trax_data->membufs, ptr, tmo); // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data /*if (esp_apptrace_trax_unlock(hw_data) != ESP_OK) { @@ -376,36 +386,42 @@ static esp_err_t esp_apptrace_trax_down_buffer_put(esp_apptrace_trax_data_t *hw_ return res; } -static bool esp_apptrace_trax_host_is_connected(esp_apptrace_trax_data_t *hw_data) +static bool esp_apptrace_trax_host_is_connected(void *hw_data) { - if (!ESP_APPTRACE_TRAX_INITED(hw_data)) { + esp_apptrace_trax_data_t *trax_data = hw_data; + + if (!ESP_APPTRACE_TRAX_INITED(trax_data)) { return false; } return eri_read(ESP_APPTRACE_TRAX_CTRL_REG) & ESP_APPTRACE_TRAX_HOST_CONNECT ? true : false; } -static esp_err_t esp_apptrace_trax_flush_nolock(esp_apptrace_trax_data_t *hw_data, uint32_t min_sz, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_trax_flush_nolock(void *hw_data, uint32_t min_sz, esp_apptrace_tmo_t *tmo) { - if (!ESP_APPTRACE_TRAX_INITED(hw_data)) { + esp_apptrace_trax_data_t *trax_data = hw_data; + + if (!ESP_APPTRACE_TRAX_INITED(trax_data)) { return ESP_ERR_INVALID_STATE; } - return esp_apptrace_membufs_flush_nolock(&hw_data->membufs, min_sz, tmo); + return esp_apptrace_membufs_flush_nolock(&trax_data->membufs, min_sz, tmo); } -static esp_err_t esp_apptrace_trax_flush(esp_apptrace_trax_data_t *hw_data, esp_apptrace_tmo_t *tmo) +static esp_err_t esp_apptrace_trax_flush(void *hw_data, esp_apptrace_tmo_t *tmo) { - if (!ESP_APPTRACE_TRAX_INITED(hw_data)) { + esp_apptrace_trax_data_t *trax_data = hw_data; + + if (!ESP_APPTRACE_TRAX_INITED(trax_data)) { return ESP_ERR_INVALID_STATE; } - esp_err_t res = esp_apptrace_trax_lock(hw_data, tmo); + esp_err_t res = esp_apptrace_trax_lock(trax_data, tmo); if (res != ESP_OK) { return res; } - res = esp_apptrace_membufs_flush_nolock(&hw_data->membufs, 0, tmo); + res = esp_apptrace_membufs_flush_nolock(&trax_data->membufs, 0, tmo); // now we can safely unlock apptrace to allow other tasks/ISRs to get other buffers and write their data - if (esp_apptrace_trax_unlock(hw_data) != ESP_OK) { + if (esp_apptrace_trax_unlock(trax_data) != ESP_OK) { assert(false && "Failed to unlock apptrace data!"); } return res; @@ -494,6 +510,12 @@ static bool esp_apptrace_trax_host_data_pending(void) return (ctrl_reg & ESP_APPTRACE_TRAX_HOST_DATA) ? true : false; } +static void esp_apptrace_trax_set_header_size(void *hw_data, esp_apptrace_header_size_t header_size) +{ + esp_apptrace_trax_data_t *trax_data = hw_data; + trax_data->membufs.header_size = header_size; +} + esp_apptrace_hw_t *esp_apptrace_jtag_hw_get(void **data) { static esp_apptrace_membufs_proto_hw_t s_trax_proto_hw = { @@ -508,15 +530,16 @@ esp_apptrace_hw_t *esp_apptrace_jtag_hw_get(void **data) }, }; static esp_apptrace_hw_t s_trax_hw = { - .init = (esp_err_t (*)(void *))esp_apptrace_trax_init, - .get_up_buffer = (uint8_t *(*)(void *, uint32_t, esp_apptrace_tmo_t *))esp_apptrace_trax_up_buffer_get, - .put_up_buffer = (esp_err_t (*)(void *, uint8_t *, esp_apptrace_tmo_t *))esp_apptrace_trax_up_buffer_put, - .flush_up_buffer_nolock = (esp_err_t (*)(void *, uint32_t, esp_apptrace_tmo_t *))esp_apptrace_trax_flush_nolock, - .flush_up_buffer = (esp_err_t (*)(void *, esp_apptrace_tmo_t *))esp_apptrace_trax_flush, - .down_buffer_config = (void (*)(void *, uint8_t *, uint32_t))esp_apptrace_trax_down_buffer_config, - .get_down_buffer = (uint8_t *(*)(void *, uint32_t *, esp_apptrace_tmo_t *))esp_apptrace_trax_down_buffer_get, - .put_down_buffer = (esp_err_t (*)(void *, uint8_t *, esp_apptrace_tmo_t *))esp_apptrace_trax_down_buffer_put, - .host_is_connected = (bool (*)(void *))esp_apptrace_trax_host_is_connected, + .init = esp_apptrace_trax_init, + .get_up_buffer = esp_apptrace_trax_up_buffer_get, + .put_up_buffer = esp_apptrace_trax_up_buffer_put, + .flush_up_buffer_nolock = esp_apptrace_trax_flush_nolock, + .flush_up_buffer = esp_apptrace_trax_flush, + .down_buffer_config = esp_apptrace_trax_down_buffer_config, + .get_down_buffer = esp_apptrace_trax_down_buffer_get, + .put_down_buffer = esp_apptrace_trax_down_buffer_put, + .host_is_connected = esp_apptrace_trax_host_is_connected, + .set_header_size = esp_apptrace_trax_set_header_size, }; *data = &s_trax_hw_data; return &s_trax_hw; diff --git a/components/app_trace/private_include/esp_app_trace_membufs_proto.h b/components/app_trace/private_include/esp_app_trace_membufs_proto.h index a48fb5f4bc9..17237c1e99c 100644 --- a/components/app_trace/private_include/esp_app_trace_membufs_proto.h +++ b/components/app_trace/private_include/esp_app_trace_membufs_proto.h @@ -40,6 +40,7 @@ typedef struct { esp_apptrace_mem_block_t blocks[2]; // memory blocks // ring buffer control struct for data from host (down buffer) esp_apptrace_rb_t rb_down; + int header_size; ///< Size of the trace header (2 or 4 bytes) } esp_apptrace_membufs_proto_data_t; esp_err_t esp_apptrace_membufs_init(esp_apptrace_membufs_proto_data_t *proto, const esp_apptrace_mem_block_t blocks_cfg[2]); diff --git a/components/app_trace/sdkconfig.rename b/components/app_trace/sdkconfig.rename index 27c3aceee3b..6b61ac0c221 100644 --- a/components/app_trace/sdkconfig.rename +++ b/components/app_trace/sdkconfig.rename @@ -2,7 +2,6 @@ # CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION CONFIG_ESP32_APPTRACE_DESTINATION CONFIG_APPTRACE_DESTINATION -CONFIG_ESP32_APPTRACE_DEST_NONE CONFIG_APPTRACE_DEST_NONE CONFIG_ESP32_APPTRACE_DEST_TRAX CONFIG_APPTRACE_DEST_JTAG CONFIG_ESP32_APPTRACE_ENABLE CONFIG_APPTRACE_ENABLE CONFIG_ESP32_APPTRACE_LOCK_ENABLE CONFIG_APPTRACE_LOCK_ENABLE diff --git a/components/app_trace/sys_view/esp/SEGGER_RTT_esp.c b/components/app_trace/sys_view/esp/SEGGER_RTT_esp.c index b9ac957d5c4..e6ab35f13d5 100644 --- a/components/app_trace/sys_view/esp/SEGGER_RTT_esp.c +++ b/components/app_trace/sys_view/esp/SEGGER_RTT_esp.c @@ -32,19 +32,12 @@ static uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ]; static uint16_t s_events_buf_filled; static uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE]; -#if CONFIG_APPTRACE_SV_DEST_UART - -#define ESP_APPTRACE_DEST_SYSVIEW ESP_APPTRACE_DEST_UART #if CONFIG_APPTRACE_SV_DEST_CPU_0 || CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE #define APPTRACE_SV_DEST_CPU 0 #else #define APPTRACE_SV_DEST_CPU 1 #endif // CONFIG_APPTRACE_SV_DEST_CPU_0 -#elif CONFIG_APPTRACE_SV_DEST_JTAG || (CONFIG_APPTRACE_ENABLE && CONFIG_APPTRACE_DEST_UART_NONE) -#define ESP_APPTRACE_DEST_SYSVIEW ESP_APPTRACE_DEST_JTAG -#endif - /********************************************************************* * * Public code @@ -70,13 +63,13 @@ void SEGGER_RTT_ESP_FlushNoLock(unsigned long min_sz, unsigned long tmo) { esp_err_t res; if (s_events_buf_filled > 0) { - res = esp_apptrace_write(ESP_APPTRACE_DEST_SYSVIEW, s_events_buf, s_events_buf_filled, tmo); + res = esp_apptrace_write(s_events_buf, s_events_buf_filled, tmo); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to flush buffered events (%d)!", res); } } // flush even if we failed to write buffered events, because no new events will be sent after STOP - res = esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_SYSVIEW, min_sz, tmo); + res = esp_apptrace_flush_nolock(min_sz, tmo); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to flush apptrace data (%d)!", res); } @@ -124,7 +117,7 @@ void SEGGER_RTT_ESP_Flush(unsigned long min_sz, unsigned long tmo) unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) { uint32_t size = BufferSize; - esp_err_t res = esp_apptrace_read(ESP_APPTRACE_DEST_SYSVIEW, pData, &size, 0); + esp_err_t res = esp_apptrace_read(pData, &size, 0); if (res != ESP_OK) { return 0; } @@ -159,70 +152,70 @@ unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, u { uint8_t *pbuf = (uint8_t *)pBuffer; uint8_t event_id = *pbuf; -#if CONFIG_APPTRACE_SV_DEST_UART - if ( - (APPTRACE_SV_DEST_CPU != esp_cpu_get_core_id()) && - ( - (event_id == SYSVIEW_EVTID_ISR_ENTER) || - (event_id == SYSVIEW_EVTID_ISR_EXIT) || - (event_id == SYSVIEW_EVTID_TASK_START_EXEC) || - (event_id == SYSVIEW_EVTID_TASK_STOP_EXEC) || - (event_id == SYSVIEW_EVTID_TASK_START_READY) || - (event_id == SYSVIEW_EVTID_TASK_STOP_READY) || - (event_id == SYSVIEW_EVTID_MARK_START) || - (event_id == SYSVIEW_EVTID_MARK_STOP) || - (event_id == SYSVIEW_EVTID_TIMER_ENTER) || - (event_id == SYSVIEW_EVTID_TIMER_EXIT) || - (event_id == SYSVIEW_EVTID_STACK_INFO) || - (event_id == SYSVIEW_EVTID_MODULEDESC) - ) - ) { - return NumBytes; - } -// This is workaround for SystemView! -// Without this line SystemView will hangs on when heap tracing enabled. - if (event_id == SYSVIEW_EVTID_MODULEDESC) { - return NumBytes; + if (esp_apptrace_get_destination() == ESP_APPTRACE_DEST_UART) { + if ( + (APPTRACE_SV_DEST_CPU != esp_cpu_get_core_id()) && + ( + (event_id == SYSVIEW_EVTID_ISR_ENTER) || + (event_id == SYSVIEW_EVTID_ISR_EXIT) || + (event_id == SYSVIEW_EVTID_TASK_START_EXEC) || + (event_id == SYSVIEW_EVTID_TASK_STOP_EXEC) || + (event_id == SYSVIEW_EVTID_TASK_START_READY) || + (event_id == SYSVIEW_EVTID_TASK_STOP_READY) || + (event_id == SYSVIEW_EVTID_MARK_START) || + (event_id == SYSVIEW_EVTID_MARK_STOP) || + (event_id == SYSVIEW_EVTID_TIMER_ENTER) || + (event_id == SYSVIEW_EVTID_TIMER_EXIT) || + (event_id == SYSVIEW_EVTID_STACK_INFO) || + (event_id == SYSVIEW_EVTID_MODULEDESC) + ) + ) { + return NumBytes; + } + + // This is workaround for SystemView! + // Without this line SystemView will hangs on when heap tracing enabled. + if (event_id == SYSVIEW_EVTID_MODULEDESC) { + return NumBytes; + } } -#endif // CONFIG_APPTRACE_SV_DEST_UART if (NumBytes > SYSVIEW_EVENTS_BUF_SZ) { ESP_LOGE(TAG, "Too large event %u bytes!", NumBytes); return 0; } -#if CONFIG_APPTRACE_SV_DEST_JTAG - if (esp_cpu_get_core_id()) { // dual core specific code - // use the highest - 1 bit of event ID to indicate core ID - // the highest bit can not be used due to event ID encoding method - // this reduces supported ID range to [0..63] (for 1 byte IDs) plus [128..16383] (for 2 bytes IDs) - if (*pbuf & 0x80) { // 2 bytes ID - *(pbuf + 1) |= (1 << 6); - } else if (NumBytes != 10 || *pbuf != 0) { // ignore sync sequence - *pbuf |= (1 << 6); + if (esp_apptrace_get_destination() == ESP_APPTRACE_DEST_JTAG) { + if (esp_cpu_get_core_id()) { // dual core specific code + // use the highest - 1 bit of event ID to indicate core ID + // the highest bit can not be used due to event ID encoding method + // this reduces supported ID range to [0..63] (for 1 byte IDs) plus [128..16383] (for 2 bytes IDs) + if (*pbuf & 0x80) { // 2 bytes ID + *(pbuf + 1) |= (1 << 6); + } else if (NumBytes != 10 || *pbuf != 0) { // ignore sync sequence + *pbuf |= (1 << 6); + } + } + + if (s_events_buf_filled + NumBytes > SYSVIEW_EVENTS_BUF_SZ) { + + esp_err_t res = esp_apptrace_write(s_events_buf, s_events_buf_filled, SEGGER_HOST_WAIT_TMO); + if (res != ESP_OK) { + return 0; // skip current data buffer only, accumulated events are kept + } + s_events_buf_filled = 0; } } -#endif // CONFIG_APPTRACE_SV_DEST_JTAG -#if CONFIG_APPTRACE_SV_DEST_JTAG - if (s_events_buf_filled + NumBytes > SYSVIEW_EVENTS_BUF_SZ) { + memcpy(&s_events_buf[s_events_buf_filled], pBuffer, NumBytes); + s_events_buf_filled += NumBytes; - esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_SYSVIEW, s_events_buf, s_events_buf_filled, SEGGER_HOST_WAIT_TMO); + if (esp_apptrace_get_destination() == ESP_APPTRACE_DEST_UART) { + esp_err_t res = esp_apptrace_write(pBuffer, NumBytes, SEGGER_HOST_WAIT_TMO); if (res != ESP_OK) { return 0; // skip current data buffer only, accumulated events are kept } s_events_buf_filled = 0; } -#endif - memcpy(&s_events_buf[s_events_buf_filled], pBuffer, NumBytes); - s_events_buf_filled += NumBytes; - -#if CONFIG_APPTRACE_SV_DEST_UART - esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_SYSVIEW, pBuffer, NumBytes, SEGGER_HOST_WAIT_TMO); - if (res != ESP_OK) { - return 0; // skip current data buffer only, accumulated events are kept - } - s_events_buf_filled = 0; -#endif if (event_id == SYSVIEW_EVTID_TRACE_STOP) { SEGGER_RTT_ESP_FlushNoLock(0, SEGGER_STOP_WAIT_TMO); @@ -288,19 +281,20 @@ int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBu */ int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { - return esp_apptrace_down_buffer_config(ESP_APPTRACE_DEST_SYSVIEW, s_down_buf, sizeof(s_down_buf)); + return esp_apptrace_down_buffer_config(s_down_buf, sizeof(s_down_buf)); } /*************************** Init hook **************************** * - * This init function is placed here because this port file will be - * linked whenever SystemView is used. + * This init function is placed here because this port file will be linked whenever SystemView is used. + * It is used to initialize SystemView and app trace configuration by the init hook function. + * Otherwise, SystemView and app trace initialization needs to be done later in the app_main. */ - -ESP_SYSTEM_INIT_FN(sysview_init, SECONDARY, BIT(0), 120) +ESP_SYSTEM_INIT_FN(sysview_early_init, SECONDARY, BIT(0), 120) { + esp_apptrace_set_header_size(ESP_APPTRACE_HEADER_SIZE_16); SEGGER_SYSVIEW_Conf(); + return ESP_OK; } - /*************************** End of file ****************************/ diff --git a/components/app_trace/test_apps/.build-test-rules.yml b/components/app_trace/test_apps/.build-test-rules.yml index 3762c8660dd..fbbd2d55b1d 100644 --- a/components/app_trace/test_apps/.build-test-rules.yml +++ b/components/app_trace/test_apps/.build-test-rules.yml @@ -9,6 +9,6 @@ components/app_trace/test_apps: - esp_driver_uart - esp_driver_gptimer disable: - - if: IDF_TARGET in ["esp32c5", "esp32c61", "esp32h21", "esp32h4"] + - if: IDF_TARGET in ["esp32h21", "esp32h4"] temporary: true - reason: not support yet # TODO: [ESP32C5] IDF-8705, [ESP32C61] IDF-9306, [ESP32H21] IDF-11539 [ESP32H4] IDF-12325 + reason: not support yet # TODO: [ESP32H21] IDF-11539 [ESP32H4] IDF-12325 diff --git a/components/app_trace/test_apps/README.md b/components/app_trace/test_apps/README.md index 061305f61a5..ecca19c3a70 100644 --- a/components/app_trace/test_apps/README.md +++ b/components/app_trace/test_apps/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # app_trace test diff --git a/components/app_trace/test_apps/main/test_trace.c b/components/app_trace/test_apps/main/test_trace.c index d2740c3381a..c4d4fcf2004 100644 --- a/components/app_trace/test_apps/main/test_trace.c +++ b/components/app_trace/test_apps/main/test_trace.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,16 +17,15 @@ #include "freertos/semphr.h" #include "freertos/task.h" +#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE +#include "esp_log.h" #include "esp_app_trace.h" -#include "esp_app_trace_util.h" #define ESP_APPTRACE_TEST_USE_PRINT_LOCK 0 #define ESP_APPTRACE_TEST_PRN_WRERR_MAX 5 #define ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH 100 #define ESP_APPTRACE_TEST_BLOCK_SIZE 1024 -#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE -#include "esp_log.h" const static char *TAG = "esp_apptrace_test"; #if ESP_APPTRACE_TEST_USE_PRINT_LOCK == 1 @@ -67,9 +66,9 @@ const static char *TAG = "esp_apptrace_test"; #define ESP_APPTRACE_TEST_LOGO( format, ... ) ESP_APPTRACE_TEST_LOG_LEVEL(E, ESP_LOG_NONE, format, ##__VA_ARGS__) #if CONFIG_APPTRACE_SV_ENABLE == 0 -#define ESP_APPTRACE_TEST_WRITE(_b_, _s_) esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, _b_, _s_, ESP_APPTRACE_TMO_INFINITE) -#define ESP_APPTRACE_TEST_WRITE_FROM_ISR(_b_, _s_) esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, _b_, _s_, 0UL) -#define ESP_APPTRACE_TEST_WRITE_NOWAIT(_b_, _s_) esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, _b_, _s_, 0) +#define ESP_APPTRACE_TEST_WRITE(_b_, _s_) esp_apptrace_write(_b_, _s_, ESP_APPTRACE_TMO_INFINITE) +#define ESP_APPTRACE_TEST_WRITE_FROM_ISR(_b_, _s_) esp_apptrace_write(_b_, _s_, 0UL) +#define ESP_APPTRACE_TEST_WRITE_NOWAIT(_b_, _s_) esp_apptrace_write(_b_, _s_, 0) typedef struct { uint8_t *buf; @@ -625,7 +624,7 @@ static int esp_logtrace_printf(const char *fmt, ...) va_start(ap, fmt); - int ret = esp_apptrace_vprintf_to(ESP_APPTRACE_DEST_JTAG, ESP_APPTRACE_TMO_INFINITE, fmt, ap); + int ret = esp_apptrace_vprintf_to(ESP_APPTRACE_TMO_INFINITE, fmt, ap); va_end(ap); @@ -657,7 +656,7 @@ static void esp_logtrace_task(void *p) break; } } - esp_err_t ret = esp_apptrace_flush(ESP_APPTRACE_DEST_JTAG, ESP_APPTRACE_TMO_INFINITE); + esp_err_t ret = esp_apptrace_flush(ESP_APPTRACE_TMO_INFINITE); if (ret != ESP_OK) { ESP_APPTRACE_TEST_LOGE("Failed to flush printf buf (%d)!", ret); } diff --git a/components/app_trace/test_apps/sdkconfig.defaults b/components/app_trace/test_apps/sdkconfig.defaults index 5e62fe2487f..2931bc40520 100644 --- a/components/app_trace/test_apps/sdkconfig.defaults +++ b/components/app_trace/test_apps/sdkconfig.defaults @@ -1,2 +1,3 @@ CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n +CONFIG_APPTRACE_ENABLE=y CONFIG_APPTRACE_DEST_JTAG=y diff --git a/components/esp_system/panic.c b/components/esp_system/panic.c index 19a5d8344b6..660459b5eb5 100644 --- a/components/esp_system/panic.c +++ b/components/esp_system/panic.c @@ -371,8 +371,7 @@ void esp_panic_handler(panic_info_t *info) #if CONFIG_APPTRACE_SV_ENABLE SEGGER_RTT_ESP_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); #else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_JTAG, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); + esp_apptrace_flush_nolock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); #endif #endif @@ -414,8 +413,7 @@ void esp_panic_handler(panic_info_t *info) #if CONFIG_APPTRACE_SV_ENABLE SEGGER_RTT_ESP_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); #else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_JTAG, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); + esp_apptrace_flush_nolock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); #endif #endif // CONFIG_APPTRACE_ENABLE @@ -485,8 +483,7 @@ void __attribute__((noreturn, no_sanitize_undefined)) panic_abort(const char *de #if CONFIG_APPTRACE_SV_ENABLE SEGGER_RTT_ESP_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); #else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_JTAG, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); + esp_apptrace_flush_nolock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); #endif #endif diff --git a/components/esp_system/system_init_fn.txt b/components/esp_system/system_init_fn.txt index 837e6a21e1c..fd665d90d4c 100644 --- a/components/esp_system/system_init_fn.txt +++ b/components/esp_system/system_init_fn.txt @@ -92,8 +92,8 @@ SECONDARY: 107: sleep_sys_periph_startup_init in components/esp_hw_support/sleep SECONDARY: 108: sleep_mmu_startup_init in components/esp_hw_support/lowpower/port/esp32c5/sleep_mmu.c on BIT(0) # app_trace has to be initialized before systemview -SECONDARY: 115: esp_apptrace_init in components/app_trace/app_trace.c on ESP_SYSTEM_INIT_ALL_CORES -SECONDARY: 120: sysview_init in components/app_trace/sys_view/esp/SEGGER_RTT_esp.c on BIT(0) +SECONDARY: 115: apptrace_early_init in components/app_trace/app_trace.c on ESP_SYSTEM_INIT_ALL_CORES +SECONDARY: 120: sysview_early_init in components/app_trace/sys_view/esp/SEGGER_RTT_esp.c on BIT(0) # coredump doesn't have init dependencies SECONDARY: 130: init_coredump in components/espcoredump/src/core_dump_init.c on BIT(0) diff --git a/docs/en/api-guides/app_trace.rst b/docs/en/api-guides/app_trace.rst index 3476c901af8..1733f0952e8 100644 --- a/docs/en/api-guides/app_trace.rst +++ b/docs/en/api-guides/app_trace.rst @@ -41,27 +41,31 @@ Using of this feature depends on two components: 1. **Host side:** Application tracing is done over JTAG, so it needs OpenOCD to be set up and running on host machine. For instructions on how to set it up, please see :doc:`JTAG Debugging <../api-guides/jtag-debugging/index>` for details. -2. **Target side:** Application tracing functionality can be enabled in menuconfig. Please go to ``Component config`` > ``Application Level Tracing`` menu, which allows selecting destination for the trace data (hardware interface for transport: JTAG or/and UART). Choosing any of the destinations automatically enables the ``CONFIG_APPTRACE_ENABLE`` option. For UART interfaces, users have to define port number, baud rate, TX and RX pins numbers, and additional UART-related parameters. +2. **Target side:** Application tracing functionality can be enabled in menuconfig. **Important:** You must first enable application tracing by going to ``Component config`` > ``Application Level Tracing`` > ``Enable Application Level Tracing`` (:ref:`CONFIG_APPTRACE_ENABLE`). After enabling this option, you can configure the destination for the trace data. For UART interfaces, users have to define port number, baud rate, TX and RX pins numbers, and additional UART-related parameters. When FreeRTOS SystemView Tracing is enabled, selected destination will be used for systemview tracing as well. .. note:: In order to achieve higher data rates and minimize the number of dropped packets, it is recommended to optimize the setting of JTAG clock frequency, so that it is at maximum and still provides stable operation of JTAG. See :ref:`jtag-debugging-tip-optimize-jtag-speed`. -There are two additional menuconfig options not mentioned above: +There are some additional menuconfig options not mentioned above: 1. *Threshold for flushing last trace data to host on panic* (:ref:`CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH`). This option is necessary due to the nature of working over JTAG. In this mode, trace data is exposed to the host in 16 KB blocks. In post-mortem mode, when one block is filled, it is exposed to the host and the previous one becomes unavailable. In other words, the trace data is overwritten in 16 KB granularity. On panic, the latest data from the current input block is exposed to the host and the host can read them for post-analysis. System panic may occur when a very small amount of data are not exposed to the host yet. In this case, the previous 16 KB of collected data will be lost and the host will see the latest, but very small piece of the trace. It can be insufficient to diagnose the problem. This menuconfig option allows avoiding such situations. It controls the threshold for flushing data in case of apanic. For example, users can decide that it needs no less than 512 bytes of the recent trace data, so if there is less then 512 bytes of pending data at the moment of panic, they will not be flushed and will not overwrite the previous 16 KB. The option is only meaningful in post-mortem mode and when working over JTAG. 2. *Timeout for flushing last trace data to host on panic* (:ref:`CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO`). The option is only meaningful in streaming mode and it controls the maximum time that the tracing module will wait for the host to read the last data in case of panic. -3. *UART RX/TX ring buffer size* (:ref:`CONFIG_APPTRACE_UART_TX_BUFF_SIZE`). The size of the buffer depends on the amount of data transferred through the UART. +3. *Internal Sync Lock* (:ref:`CONFIG_APPTRACE_LOCK_ENABLE`). Enable this option to protect trace buffer writes with locks, preventing data corruption when multiple tasks generate trace data concurrently. -4. *UART TX message size* (:ref:`CONFIG_APPTRACE_UART_TX_MSG_SIZE`). The maximum size of the single message to transfer. +4. *UART RX/TX ring buffer size* (:ref:`CONFIG_APPTRACE_UART_TX_BUFF_SIZE`). The size of the buffer depends on the amount of data transferred through the UART. + +5. *UART TX message size* (:ref:`CONFIG_APPTRACE_UART_TX_MSG_SIZE`). The maximum size of the single message to transfer. How to Use This Library ----------------------- -This library provides APIs for transferring arbitrary data between the host and {IDF_TARGET_NAME}. When enabled in menuconfig, the target application tracing module is initialized automatically at the system startup, so all what the user needs to do is to call corresponding APIs to send, receive or flush the data. +This library provides APIs for transferring arbitrary data between the host and {IDF_TARGET_NAME}. When enabled in menuconfig, the application tracing module is automatically initialized during system startup using configuration from menuconfig. Users can then call corresponding APIs to send, receive, or flush the data. + +Optionally, users can override the default configuration by implementing the weak callback function :cpp:func:`esp_apptrace_get_user_params()`. .. _app_trace-application-specific-tracing: @@ -71,14 +75,36 @@ Application Specific Tracing In general, users should decide what type of data should be transferred in every direction and how these data must be interpreted (processed). The following steps must be performed to transfer data between the target and the host: -1. On the target side, users should implement algorithms for writing trace data to the host. Piece of code below shows an example on how to do this. +1. **Configuration:** Application tracing is automatically initialized during system startup using configuration from menuconfig. If you need to override the default configuration at runtime (e.g., to use custom UART pins), implement the :cpp:func:`esp_apptrace_get_user_params()` callback: + + .. code-block:: c + + #include "esp_app_trace.h" + + esp_apptrace_config_t *esp_apptrace_get_user_params(void) + { + esp_apptrace_config_t config = APPTRACE_CONFIG_DEFAULT(); + + // Customize configuration if needed + // For example, to use different UART pins: + config.dest_cfg.uart.tx_pin_num = GPIO_NUM_17; + config.dest_cfg.uart.rx_pin_num = GPIO_NUM_16; + + return config; + } + + .. note:: + + This callback is optional. Only implement it if you need to override menuconfig settings. For most use cases, configuring through menuconfig is sufficient. + +2. On the target side, users should implement algorithms for writing trace data to the host. Piece of code below shows an example on how to do this. .. code-block:: c #include "esp_app_trace.h" ... char buf[] = "Hello World!"; - esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, buf, strlen(buf), ESP_APPTRACE_TMO_INFINITE); + esp_err_t res = esp_apptrace_write(buf, strlen(buf), ESP_APPTRACE_TMO_INFINITE); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to write data to host!"); return res; @@ -91,13 +117,13 @@ In general, users should decide what type of data should be transferred in every #include "esp_app_trace.h" ... int number = 10; - char *ptr = (char *)esp_apptrace_buffer_get(ESP_APPTRACE_DEST_JTAG, 32, 100/*tmo in us*/); + char *ptr = (char *)esp_apptrace_buffer_get(32, 100/*tmo in us*/); if (ptr == NULL) { ESP_LOGE(TAG, "Failed to get buffer!"); return ESP_FAIL; } sprintf(ptr, "Here is the number %d", number); - esp_err_t res = esp_apptrace_buffer_put(ESP_APPTRACE_DEST_JTAG, ptr, 100/*tmo in us*/); + esp_err_t res = esp_apptrace_buffer_put(ptr, 100/*tmo in us*/); if (res != ESP_OK) { /* in case of error host tracing tool (e.g., OpenOCD) will report incomplete user buffer */ ESP_LOGE(TAG, "Failed to put buffer!"); @@ -115,13 +141,13 @@ In general, users should decide what type of data should be transferred in every size_t sz = sizeof(buf); /* config down buffer */ - esp_err_t res = esp_apptrace_down_buffer_config(ESP_APPTRACE_DEST_JTAG, down_buf, sizeof(down_buf)); + esp_err_t res = esp_apptrace_down_buffer_config(down_buf, sizeof(down_buf)); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to config down buffer!"); return res; } /* check for incoming data and read them if any */ - res = esp_apptrace_read(ESP_APPTRACE_DEST_JTAG, buf, &sz, 0/*do not wait*/); + res = esp_apptrace_read(buf, &sz, 0/*do not wait*/); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to read data from host!"); return res; @@ -142,12 +168,12 @@ In general, users should decide what type of data should be transferred in every size_t sz = 32; /* config down buffer */ - esp_err_t res = esp_apptrace_down_buffer_config(ESP_APPTRACE_DEST_JTAG, down_buf, sizeof(down_buf)); + esp_err_t res = esp_apptrace_down_buffer_config(down_buf, sizeof(down_buf)); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to config down buffer!"); return res; } - char *ptr = (char *)esp_apptrace_down_buffer_get(ESP_APPTRACE_DEST_JTAG, &sz, 100/*tmo in us*/); + char *ptr = (char *)esp_apptrace_down_buffer_get(&sz, 100/*tmo in us*/); if (ptr == NULL) { ESP_LOGE(TAG, "Failed to get buffer!"); return ESP_FAIL; @@ -158,22 +184,22 @@ In general, users should decide what type of data should be transferred in every } else { printf("No data"); } - res = esp_apptrace_down_buffer_put(ESP_APPTRACE_DEST_JTAG, ptr, 100/*tmo in us*/); + res = esp_apptrace_down_buffer_put(ptr, 100/*tmo in us*/); if (res != ESP_OK) { /* in case of error host tracing tool (e.g., OpenOCD) will report incomplete user buffer */ ESP_LOGE(TAG, "Failed to put buffer!"); return res; } -2. The next step is to build the program image and download it to the target as described in the :ref:`Getting Started Guide `. +3. The next step is to build the program image and download it to the target as described in the :ref:`Getting Started Guide `. -3. Run OpenOCD (see :doc:`JTAG Debugging <../api-guides/jtag-debugging/index>`). +4. Run OpenOCD (see :doc:`JTAG Debugging <../api-guides/jtag-debugging/index>`). -4. Connect to OpenOCD telnet server. It can be done using the following command in terminal ``telnet 4444``. If telnet session is opened on the same machine which runs OpenOCD, you can use ``localhost`` as ```` in the command above. +5. Connect to OpenOCD telnet server. It can be done using the following command in terminal ``telnet 4444``. If telnet session is opened on the same machine which runs OpenOCD, you can use ``localhost`` as ```` in the command above. -5. Start trace data collection using special OpenOCD command. This command will transfer tracing data and redirect them to the specified file or socket (currently only files are supported as trace data destination). For description of the corresponding commands, see `OpenOCD Application Level Tracing Commands`_. +6. Start trace data collection using special OpenOCD command. This command will transfer tracing data and redirect them to the specified file or socket (currently only files are supported as trace data destination). For description of the corresponding commands, see `OpenOCD Application Level Tracing Commands`_. -6. The final step is to process received data. Since the format of data is defined by users, the processing stage is out of the scope of this document. Good starting points for data processor are python scripts in ``$IDF_PATH/tools/esp_app_trace``: ``apptrace_proc.py`` (used for feature tests) and ``logtrace_proc.py`` (see more details in section `Logging to Host`_). +7. The final step is to process received data. Since the format of data is defined by users, the processing stage is out of the scope of this document. Good starting points for data processor are python scripts in ``$IDF_PATH/tools/esp_app_trace``: ``apptrace_proc.py`` (used for feature tests) and ``logtrace_proc.py`` (see more details in section `Logging to Host`_). OpenOCD Application Level Tracing Commands @@ -302,9 +328,10 @@ How To Use It In order to use logging via trace module, users need to perform the following steps: -1. On the target side, the special vprintf-like function :cpp:func:`esp_apptrace_vprintf` needs to be installed. It sends log data to the host. An example is ``esp_log_set_vprintf(esp_apptrace_vprintf);``. To send log data to UART again, use ``esp_log_set_vprintf(vprintf);``. -2. Follow instructions in items 2-5 in `Application Specific Tracing`_. -3. To print out collected log records, run the following command in terminal: ``$IDF_PATH/tools/esp_app_trace/logtrace_proc.py /path/to/trace/file /path/to/program/elf/file``. +1. Enable application tracing in menuconfig (``Component config`` > ``Application Level Tracing`` > ``Enable Application Level Tracing``). +2. On the target side, the special vprintf-like function :cpp:func:`esp_apptrace_vprintf` needs to be installed. It sends log data to the host. An example is ``esp_log_set_vprintf(esp_apptrace_vprintf);``. To send log data to UART again, use ``esp_log_set_vprintf(vprintf);``. +3. Follow instructions in items 4-6 in `Application Specific Tracing`_ (OpenOCD setup and trace collection). +4. To print out collected log records, run the following command in terminal: ``$IDF_PATH/tools/esp_app_trace/logtrace_proc.py /path/to/trace/file /path/to/program/elf/file``. Log Trace Processor Command Options @@ -342,11 +369,9 @@ How To Use It Support for this feature is enabled by ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` (:ref:`CONFIG_APPTRACE_SV_ENABLE`) menuconfig option. There are several other options enabled under the same menu: -1. SytemView destination. Select the destination interface: JTAG or UART. In case of UART, it will be possible to connect SystemView application to the {IDF_TARGET_NAME} directly and receive data in real-time. +1. {IDF_TARGET_NAME} timer to use as SystemView timestamp source: (:ref:`CONFIG_APPTRACE_SV_TS_SOURCE`) selects the source of timestamps for SystemView events. In the single core mode, timestamps are generated using {IDF_TARGET_NAME} internal cycle counter running at maximum frequency. (:ref:`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ`) In the dual-core mode, external timer is used to generate timestamps. It's frequency is 1/2 of the CPU frequency. -2. {IDF_TARGET_NAME} timer to use as SystemView timestamp source: (:ref:`CONFIG_APPTRACE_SV_TS_SOURCE`) selects the source of timestamps for SystemView events. In the single core mode, timestamps are generated using {IDF_TARGET_NAME} internal cycle counter running at maximum 240 Mhz (about 4 ns granularity). In the dual-core mode, external timer working at 40 Mhz is used, so the timestamp granularity is 25 ns. - -3. Individually enabled or disabled collection of SystemView events (``CONFIG_APPTRACE_SV_EVT_XXX``): +2. Individually enabled or disabled collection of SystemView events (``CONFIG_APPTRACE_SV_EVT_XXX``): - Trace Buffer Overflow Event - ISR Enter Event @@ -362,10 +387,9 @@ Support for this feature is enabled by ``Component config`` > ``Application Leve - Timer Enter Event - Timer Exit Event -ESP-IDF has all the code required to produce SystemView compatible traces, so users can just configure necessary project options (see above), build, download the image to target, and use OpenOCD to collect data as described in the previous sections. - -4. Select Pro or App CPU in menuconfig options ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` to trace over the UART interface in real-time. +ESP-IDF has all the code required to produce SystemView compatible traces. +3. Select Pro or App CPU in menuconfig options ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` to trace over the UART interface in real-time. OpenOCD SystemView Tracing Command Options """""""""""""""""""""""""""""""""""""""""" diff --git a/docs/en/api-reference/system/heap_debug.rst b/docs/en/api-reference/system/heap_debug.rst index 491dd013c0c..069a7245da1 100644 --- a/docs/en/api-reference/system/heap_debug.rst +++ b/docs/en/api-reference/system/heap_debug.rst @@ -571,7 +571,7 @@ Host-Based Mode Once you have identified the code which you think is leaking: - In the project configuration menu, navigate to ``Component config`` > ``Heap Memory Debugging`` > :ref:`CONFIG_HEAP_TRACING_DEST` and select ``Host-Based``. -- In the project configuration menu, navigate to ``Component config`` > ``Application Level Tracing`` > :ref:`CONFIG_APPTRACE_DESTINATION1` and select ``Trace memory``. +- In the project configuration menu, navigate to ``Component config`` > ``Application Level Tracing`` > ``Enable Application Level Tracing`` > ``Data Destination`` :ref:`CONFIG_APPTRACE_DESTINATION` and select ``JTAG``. - In the project configuration menu, navigate to ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` and enable :ref:`CONFIG_APPTRACE_SV_ENABLE`. - Call the function :cpp:func:`heap_trace_init_tohost` early in the program, to initialize the JTAG heap tracing module. - Call the function :cpp:func:`heap_trace_start` to begin recording all memory allocation and free calls in the system. Call this immediately before the piece of code which you suspect is leaking memory. diff --git a/docs/en/migration-guides/release-6.x/6.0/system.rst b/docs/en/migration-guides/release-6.x/6.0/system.rst index f57ef9f92f9..bbf3652aacd 100644 --- a/docs/en/migration-guides/release-6.x/6.0/system.rst +++ b/docs/en/migration-guides/release-6.x/6.0/system.rst @@ -70,27 +70,64 @@ The deprecated ``STATUS`` type has been removed from ``ets_sys.h`` ROM header fi App Trace ---------- -Removed extra data buffering option. `CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX` is no longer supported. +Configuration Changes +^^^^^^^^^^^^^^^^^^^^^ -Removed deprecated `ESP_APPTRACE_DEST_TRAX` enum value. Use `ESP_APPTRACE_DEST_JTAG` instead. +Previously, application tracing was automatically enabled when a destination was configured. Now you must explicitly enable application tracing through ``CONFIG_APPTRACE_ENABLE``` option before configuring any destination. -The :cpp:func:`esp_apptrace_down_buffer_config` function now requires a destination parameter and returns an error code for proper error handling. +To enable application tracing, go to "Component config" → "Application Level Tracing" → "Enable Application Level Tracing" in menuconfig. + +Removed extra data buffering option. ``CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX`` is no longer supported. + +Removed deprecated ``ESP_APPTRACE_DEST_TRAX`` enum value. Use ``ESP_APPTRACE_DEST_JTAG`` instead. + +Initialization Flow Changes +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you need to override the default configuration at runtime, you can implement the ``esp_apptrace_get_user_params()`` callback function. A weak default implementation exists that returns menuconfig defaults (``APPTRACE_CONFIG_DEFAULT()``). Your application can override this by providing its own configuration. + + .. code-block:: c + + esp_apptrace_config_t esp_apptrace_get_user_params(void) + { + esp_apptrace_config_t config = APPTRACE_CONFIG_DEFAULT(); + + // Override with custom values (example for UART) + config.dest_cfg.uart.uart_num = UART_NUM_0; + config.dest_cfg.uart.baud_rate = 921600; + config.dest_cfg.uart.tx_pin_num = GPIO_NUM_17; + config.dest_cfg.uart.rx_pin_num = GPIO_NUM_16; + + return config; + } + + **Important:** + + - Do **not** add ``__attribute__((weak))`` to your implementation + - You can also use destination-specific macros: ``APPTRACE_JTAG_CONFIG_DEFAULT()`` or ``APPTRACE_UART_CONFIG_DEFAULT()`` + +API Changes +^^^^^^^^^^^ + +The destination parameter has been removed from all apptrace APIs. Old Version: .. code-block:: c - esp_apptrace_down_buffer_config(down_buf, sizeof(down_buf)); + esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, data, size, timeout); + esp_apptrace_read(ESP_APPTRACE_DEST_UART, buffer, &size, timeout); + esp_apptrace_flush(ESP_APPTRACE_DEST_JTAG, min_sz, timeout); Update to: .. code-block:: c - esp_err_t res = esp_apptrace_down_buffer_config(ESP_APPTRACE_DEST_JTAG, down_buf, sizeof(down_buf)); - if (res != ESP_OK) { - ESP_LOGE(TAG, "Failed to config down buffer!"); - return res; - } + esp_apptrace_write(data, size, timeout); + esp_apptrace_read(buffer, &size, timeout); + esp_apptrace_flush(min_sz, timeout); + +The destination is now configured in menuconfig under "Application Level Tracing" → "Data Destination". The UART destination configuration has been simplified: @@ -114,10 +151,18 @@ New configuration: CONFIG_APPTRACE_DEST_UART=y CONFIG_APPTRACE_DEST_UART_NUM=0 # or 1, 2 depending on target +SystemView Destination +^^^^^^^^^^^^^^^^^^^^^^ + +The SystemView destination is now controlled by the same configuration as the application trace destination. When SystemView is enabled, it will use the destination configured under "Application Level Tracing" → "Data Destination". + +This means that if you have both application tracing and SystemView enabled, they will share the same destination (JTAG or UART) as configured in the menuconfig. SystemView will not have its own destination configuration. + FreeRTOS -------- -**Removed Functions** +Removed Functions +^^^^^^^^^^^^^^^^^ The following deprecated FreeRTOS functions have been removed in ESP-IDF v6.0: @@ -128,21 +173,24 @@ The following deprecated FreeRTOS functions have been removed in ESP-IDF v6.0: The following compatibility functions have been removed in ESP-IDF v6.0. These functions were maintained for backward compatibility with previous ESP-IDF versions as they were changed to either macros or separate functions in FreeRTOS. This compatibility has been removed. - :cpp:func:`xQueueGenericReceive` - Use :cpp:func:`xQueueReceive`, :cpp:func:`xQueuePeek`, or :cpp:func:`xQueueSemaphoreTake` instead, depending on your use case. -- :cpp:func:`vTaskDelayUntil` - Use :cpp:func:`xTaskDelayUntil` instead -- :cpp:func:`ulTaskNotifyTake` - Use the macro ``ulTaskNotifyTake`` instead -- :cpp:func:`xTaskNotifyWait` - Use the macro ``xTaskNotifyWait`` instead +- :cpp:func:`vTaskDelayUntil` - Use :cpp:func:`xTaskDelayUntil` instead. +- :cpp:func:`ulTaskNotifyTake` - Use the macro ``ulTaskNotifyTake`` instead. +- :cpp:func:`xTaskNotifyWait` - Use the macro ``xTaskNotifyWait`` instead. -**Deprecated Functions** +Deprecated Functions +^^^^^^^^^^^^^^^^^^^^ The function :cpp:func:`pxTaskGetStackStart` has been deprecated. Use :cpp:func:`xTaskGetStackStart` instead for improved type safety. -**API Added** +API Added +^^^^^^^^^ Task snapshot APIs have been made public to support external frameworks like ESP Insights. These APIs are now provided through ``freertos/freertos_debug.h`` instead of the deprecated ``freertos/task_snapshot.h``. For safe use while the scheduler is running, use ``vTaskSuspendAll()`` before calling snapshot functions, and ``xTaskResumeAll()`` afterward. -**Memory Placement** +Memory Placement +^^^^^^^^^^^^^^^^ - To reduce IRAM usage, the default placement for most FreeRTOS functions has been changed from IRAM to flash. Consequently, the ``CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH`` option has been removed. This change saves a significant amount of IRAM but may have a slight performance impact. For performance-critical applications, you can restore the previous behavior by enabling the new :ref:`CONFIG_FREERTOS_IN_IRAM` option. - Before enabling ``CONFIG_FREERTOS_IN_IRAM``, it is recommended to run performance tests to measure the actual impact on your specific use case. The performance difference between flash and IRAM configurations depends on factors such as flash cache efficiency, API usage patterns, and system load. @@ -150,7 +198,8 @@ For safe use while the scheduler is running, use ``vTaskSuspendAll()`` before ca - Task snapshot functions are automatically placed in IRAM when ``CONFIG_ESP_PANIC_HANDLER_IRAM`` is enabled, ensuring they remain accessible during panic handling. - ``vTaskGetSnapshot`` is kept in IRAM unless ``CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH`` is enabled, as it is used by the Task Watchdog interrupt handler. -**Removed Configuration Options** +Removed Configuration Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following hidden (and always true) configuration options have been removed: @@ -160,21 +209,24 @@ The following hidden (and always true) configuration options have been removed: Ring Buffer ----------- -**Memory Placement** +Memory Placement +^^^^^^^^^^^^^^^^ To reduce IRAM usage, the default placement for `esp_ringbuf` functions has been changed from IRAM to Flash. Consequently, the ``CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH`` option has been removed. This change saves a significant amount of IRAM but may have a slight performance impact. For performance-critical applications, the previous behavior can be restored by enabling the new :ref:`CONFIG_RINGBUF_IN_IRAM` option. Log --- -**Removed Functions** +Removed Functions +^^^^^^^^^^^^^^^^^ The following deprecated Log functions have been removed in ESP-IDF v6.0: - :cpp:func:`esp_log_buffer_hex` - Use :cpp:func:`ESP_LOG_BUFFER_HEX` instead. - :cpp:func:`esp_log_buffer_char` - Use :cpp:func:`ESP_LOG_BUFFER_CHAR` instead. -**Removed Headers** +Removed Headers +^^^^^^^^^^^^^^^ - ``esp_log_internal.h`` - Use ``esp_log_buffer.h`` instead. @@ -199,7 +251,8 @@ The partial download functionality in ESP HTTPS OTA has been moved under a confi To use partial download features in your OTA applications, you need to enable the component-level configuration :ref:`CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD` in menuconfig (``Component config`` → ``ESP HTTPS OTA`` → ``Enable partial HTTP download for OTA``). -**Removed Deprecated APIs** +Removed Deprecated APIs +^^^^^^^^^^^^^^^^^^^^^^^ The following deprecated functions have been removed from the ``app_update`` component: @@ -213,7 +266,8 @@ Gcov The gcov component has been moved to a separate repository. `esp_gcov `_ is now a managed component. -**Component Dependency** +Component Dependency +^^^^^^^^^^^^^^^^^^^^ Projects using gcov functionality must now add the esp_gcov component as a dependency in their ``idf_component.yml`` manifest file: @@ -222,13 +276,15 @@ Projects using gcov functionality must now add the esp_gcov component as a depen dependencies: espressif/esp_gcov: ^1 -**Configuration Changes** +Configuration Changes +^^^^^^^^^^^^^^^^^^^^^ The gcov configuration options have moved from the Application Level Tracing menu to a dedicated ``GNU Code Coverage`` menu section. The ``CONFIG_APPTRACE_GCOV_ENABLE`` option has been renamed to ``CONFIG_ESP_GCOV_ENABLE``. -**Header File Changes** +Header File Changes +^^^^^^^^^^^^^^^^^^^ For the gcov functionality, include the ``esp_gcov.h`` header file instead of ``esp_app_trace.h``. diff --git a/docs/zh_CN/api-guides/app_trace.rst b/docs/zh_CN/api-guides/app_trace.rst index eedeeae4132..48b763d0d7c 100644 --- a/docs/zh_CN/api-guides/app_trace.rst +++ b/docs/zh_CN/api-guides/app_trace.rst @@ -41,27 +41,31 @@ ESP-IDF 中提供了应用层跟踪功能,用于分析应用程序的行为。 1. **主机端:** 应用程序跟踪通过 JTAG 来完成,因此需要在主机上安装并运行 OpenOCD。详细信息请参阅 :doc:`JTAG 调试 <../api-guides/jtag-debugging/index>`。 -2. **目标端:** 在 menuconfig 中开启应用程序跟踪功能。前往 ``Component config`` > ``Application Level Tracing`` 菜单,选择跟踪数据的传输目标(具体用于传输的硬件接口:JTAG 和/或 UART),选择任一非 None 的目标都会自动开启 ``CONFIG_APPTRACE_ENABLE`` 这个选项。对于 UART 接口,用户需要定义端口号、波特率、TX 和 RX 管脚及其他相关参数。 +2. **目标端:** 在 menuconfig 中开启应用程序跟踪功能。**重要提示:** 您必须首先通过 ``Component config`` > ``Application Level Tracing`` > ``Enable Application Level Tracing`` (:ref:`CONFIG_APPTRACE_ENABLE`) 启用应用程序跟踪。启用此选项后,您可以配置跟踪数据的传输目标。对于 UART 接口,用户需要定义端口号、波特率、TX 和 RX 管脚及其他相关参数。当启用 FreeRTOS SystemView 跟踪功能时,所选目标也将被用于 SystemView 跟踪。 .. note:: 为了实现更高的数据速率并降低丢包率,建议优化 JTAG 的时钟频率,使其达到能够稳定运行的最大值。详细信息请参阅 :ref:`jtag-debugging-tip-optimize-jtag-speed`。 -以下为前述未提及的另外两个 menuconfig 选项: +以下为前述未提及的另外几个 menuconfig 选项: 1. *Threshold for flushing last trace data to host on panic* (:ref:`CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH`)。使用 JTAG 接口时,此选项是必选项。在该模式下,跟踪数据以 16 KB 数据块的形式暴露给主机。在后验模式中,一个块被填充后会被暴露给主机,同时之前的块不再可用。也就是说,跟踪数据以 16 KB 的粒度进行覆盖。发生 Panic 时,当前输入块的最新数据将会被暴露给主机,主机可以读取数据以进行后续分析。如果系统发生 Panic 时,仍有少量数据还没来得及暴露给主机,那么之前收集的 16 KB 数据将丢失,主机只能获取少部分的最新跟踪数据,从而可能无法诊断问题。此 menuconfig 选项有助于避免此类情况,它可以控制发生 Panic 时刷新数据的阈值。例如,用户可以设置需要不少于 512 字节的最新跟踪数据,如果在发生 Panic 时待处理的数据少于 512 字节,则数据不会被刷新,也不会覆盖之前的 16 KB 数据。该选项仅在后验模式和使用 JTAG 工作时可发挥作用。 2. *Timeout for flushing last trace data to host on panic* (:ref:`CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO`)。该选项仅在流模式下才可发挥作用,它可用于控制跟踪模块在发生 Panic 时等待主机读取最新数据的最长时间。 -3. *UART RX/TX ring buffer size* (:ref:`CONFIG_APPTRACE_UART_TX_BUFF_SIZE`)。缓冲区的大小取决于通过 UART 传输的数据量。 +3. *Internal Sync Lock* (:ref:`CONFIG_APPTRACE_LOCK_ENABLE`)。启用此选项可使用锁保护跟踪缓冲区写入操作,防止多个任务并发生成跟踪数据时发生数据损坏。 -4. *UART TX message size* (:ref:`CONFIG_APPTRACE_UART_TX_MSG_size`)。要传输的单条消息的最大尺寸。 +4. *UART RX/TX ring buffer size* (:ref:`CONFIG_APPTRACE_UART_TX_BUFF_SIZE`)。缓冲区的大小取决于通过 UART 传输的数据量。 + +5. *UART TX message size* (:ref:`CONFIG_APPTRACE_UART_TX_MSG_size`)。要传输的单条消息的最大尺寸。 如何使用此库 -------------- -该库提供了用于在主机和 {IDF_TARGET_NAME} 之间传输任意数据的 API。在 menuconfig 中启用该库后,目标应用程序的跟踪模块会在系统启动时自动初始化。因此,用户需要做的就是调用相应的 API 来发送、接收或者刷新数据。 +该库提供了用于在主机和 {IDF_TARGET_NAME} 之间传输任意数据的 API。在 menuconfig 中启用该库后,应用程序跟踪模块会在系统启动期间使用 menuconfig 配置自动初始化。然后用户可以调用相应的 API 来发送、接收或者刷新数据。 + +用户可以通过实现弱回调函数 :cpp:func:`esp_apptrace_get_user_params()` 来覆盖默认配置(可选)。 .. _app_trace-application-specific-tracing: @@ -71,18 +75,40 @@ ESP-IDF 中提供了应用层跟踪功能,用于分析应用程序的行为。 通常,用户需要决定在每个方向上待传输数据的类型以及如何解析(处理)这些数据。要想在目标和主机之间传输数据,则需执行以下几个步骤: -1. 在目标端,用户需要实现将跟踪数据写入主机的算法。下面的代码片段展示了如何执行此操作。 +1. **配置:** 应用程序跟踪会在系统启动期间使用 menuconfig 配置自动初始化。如需在运行时覆盖默认配置(例如使用自定义的 UART 引脚),可实现 :cpp:func:`esp_apptrace_get_user_params()` 回调函数: + + .. code-block:: c + + #include "esp_app_trace.h" + + esp_apptrace_config_t *esp_apptrace_get_user_params(void) + { + esp_apptrace_config_t config = APPTRACE_CONFIG_DEFAULT(); + + // Customize configuration if needed + // For example, to use different UART pins: + config.dest_cfg.uart.tx_pin_num = GPIO_NUM_17; + config.dest_cfg.uart.rx_pin_num = GPIO_NUM_16; + + return config; + } + + .. note:: + + 此回调函数为可选项。仅当需要覆盖 menuconfig 设置时才需实现。对于大多数使用场景,通过 menuconfig 配置即可满足需求。 + +2. 在目标设备端,用户需实现将跟踪数据写入主机的算法。下方代码片段展示了实现示例。 .. code-block:: c - #include "esp_app_trace.h" - ... - char buf[] = "Hello World!"; - esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, buf, strlen(buf), ESP_APPTRACE_TMO_INFINITE); - if (res != ESP_OK) { - ESP_LOGE(TAG, "Failed to write data to host!"); - return res; - } + #include "esp_app_trace.h" + ... + char buf[] = "Hello World!"; + esp_err_t res = esp_apptrace_write(buf, strlen(buf), ESP_APPTRACE_TMO_INFINITE); + if (res != ESP_OK) { + ESP_LOGE(TAG, "Failed to write data to host!"); + return res; + } ``esp_apptrace_write()`` 函数使用 memcpy 把用户数据复制到内部缓存中。在某些情况下,使用 ``esp_apptrace_buffer_get()`` 和 ``esp_apptrace_buffer_put()`` 函数会更加理想,它们允许开发人员自行分配缓冲区并填充。下面的代码片段展示了如何执行此操作。 @@ -91,13 +117,13 @@ ESP-IDF 中提供了应用层跟踪功能,用于分析应用程序的行为。 #include "esp_app_trace.h" ... int number = 10; - char *ptr = (char *)esp_apptrace_buffer_get(ESP_APPTRACE_DEST_JTAG, 32, 100/*tmo in us*/); + char *ptr = (char *)esp_apptrace_buffer_get(32, 100/*tmo in us*/); if (ptr == NULL) { ESP_LOGE(TAG, "Failed to get buffer!"); return ESP_FAIL; } sprintf(ptr, "Here is the number %d", number); - esp_err_t res = esp_apptrace_buffer_put(ESP_APPTRACE_DEST_JTAG, ptr, 100/*tmo in us*/); + esp_err_t res = esp_apptrace_buffer_put(ptr, 100/*tmo in us*/); if (res != ESP_OK) { /* in case of error host tracing tool (e.g. OpenOCD) will report incomplete user buffer */ ESP_LOGE(TAG, "Failed to put buffer!"); @@ -115,13 +141,13 @@ ESP-IDF 中提供了应用层跟踪功能,用于分析应用程序的行为。 size_t sz = sizeof(buf); /* config down buffer */ - esp_err_t res = esp_apptrace_down_buffer_config(ESP_APPTRACE_DEST_JTAG, down_buf, sizeof(down_buf)); + esp_err_t res = esp_apptrace_down_buffer_config(down_buf, sizeof(down_buf)); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to config down buffer!"); return res; } /* check for incoming data and read them if any */ - res = esp_apptrace_read(ESP_APPTRACE_DEST_JTAG, buf, &sz, 0/*do not wait*/); + res = esp_apptrace_read(buf, &sz, 0/*do not wait*/); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to read data from host!"); return res; @@ -142,12 +168,12 @@ ESP-IDF 中提供了应用层跟踪功能,用于分析应用程序的行为。 size_t sz = 32; /* config down buffer */ - esp_err_t res = esp_apptrace_down_buffer_config(ESP_APPTRACE_DEST_JTAG, down_buf, sizeof(down_buf)); + esp_err_t res = esp_apptrace_down_buffer_config(down_buf, sizeof(down_buf)); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to config down buffer!"); return res; } - char *ptr = (char *)esp_apptrace_down_buffer_get(ESP_APPTRACE_DEST_JTAG, &sz, 100/*tmo in us*/); + char *ptr = (char *)esp_apptrace_down_buffer_get(&sz, 100/*tmo in us*/); if (ptr == NULL) { ESP_LOGE(TAG, "Failed to get buffer!"); return ESP_FAIL; @@ -158,22 +184,22 @@ ESP-IDF 中提供了应用层跟踪功能,用于分析应用程序的行为。 } else { printf("No data"); } - res = esp_apptrace_down_buffer_put(ESP_APPTRACE_DEST_JTAG, ptr, 100/*tmo in us*/); + res = esp_apptrace_down_buffer_put(ptr, 100/*tmo in us*/); if (res != ESP_OK) { /* in case of error host tracing tool (e.g. OpenOCD) will report incomplete user buffer */ ESP_LOGE(TAG, "Failed to put buffer!"); return res; } -2. 下一步是编译应用程序的镜像,并将其下载到目标板上。这一步可以参考文档 :ref:`构建并烧写 `。 +3. 下一步是编译应用程序的镜像,并将其下载到目标板上。这一步可以参考文档 :ref:`构建并烧写 `。 -3. 运行 OpenOCD(参见 :doc:`JTAG 调试 <../api-guides/jtag-debugging/index>`)。 +4. 运行 OpenOCD(参见 :doc:`JTAG 调试 <../api-guides/jtag-debugging/index>`)。 -4. 连接到 OpenOCD 的 telnet 服务器。用户可在终端执行命令 ``telnet 4444``。如果用户是在运行 OpenOCD 的同一台机器上打开 telnet 会话,可以使用 ``localhost`` 替换上面命令中的 ````。 +5. 连接到 OpenOCD 的 telnet 服务器。用户可在终端执行命令 ``telnet 4444``。如果用户是在运行 OpenOCD 的同一台机器上打开 telnet 会话,可以使用 ``localhost`` 替换上面命令中的 ````。 -5. 使用特殊的 OpenOCD 命令开始收集待跟踪的命令。此命令将传输跟踪数据并将其重定向到指定的文件或套接字(当前仅支持文件作为跟踪数据目标)。相关命令的说明,请参阅 :ref:`jtag-debugging-launching-debugger`。 +6. 使用特殊的 OpenOCD 命令开始收集待跟踪的命令。此命令将传输跟踪数据并将其重定向到指定的文件或套接字(当前仅支持文件作为跟踪数据目标)。相关命令的说明,请参阅 :ref:`jtag-debugging-launching-debugger`。 -6. 最后,处理接收到的数据。由于数据格式由用户自己定义,本文档中省略数据处理的具体流程。数据处理的范例可以参考位于 ``$IDF_PATH/tools/esp_app_trace`` 下的 Python 脚本 ``apptrace_proc.py`` (用于功能测试)和 ``logtrace_proc.py`` (请参阅 :ref:`app_trace-logging-to-host` 章节中的详细信息)。 +7. 最后,处理接收到的数据。由于数据格式由用户自己定义,本文档中省略数据处理的具体流程。数据处理的范例可以参考位于 ``$IDF_PATH/tools/esp_app_trace`` 下的 Python 脚本 ``apptrace_proc.py`` (用于功能测试)和 ``logtrace_proc.py`` (请参阅 :ref:`app_trace-logging-to-host` 章节中的详细信息)。 OpenOCD 应用程序跟踪命令 @@ -302,9 +328,10 @@ ESP-IDF 的日志库会默认使用类 vprintf 的函数将格式化的字符串 为了使用跟踪模块来记录日志,用户需要执行以下步骤: -1. 在目标端,需要安装特殊的类 vprintf 函数 :cpp:func:`esp_apptrace_vprintf`,该函数负责将日志数据发送给主机,使用方法为 ``esp_log_set_vprintf(esp_apptrace_vprintf);``。如需将日志数据再次重定向给 UART,请使用 ``esp_log_set_vprintf(vprintf);``。 -2. 按照 :ref:`app_trace-application-specific-tracing` 章节中的第 2-5 步进行操作。 -3. 打印接收到的日志记录,请在终端运行以下命令:``$IDF_PATH/tools/esp_app_trace/logtrace_proc.py /path/to/trace/file /path/to/program/elf/file``。 +1. 在 menuconfig 中启用应用程序跟踪功能(路径为 ``Component config`` > ``Application Level Tracing`` > ``Enable Application Level Tracing``)。 +2. 在目标端,需要安装特殊的类 vprintf 函数 :cpp:func:`esp_apptrace_vprintf`,该函数负责将日志数据发送给主机,使用方法为 ``esp_log_set_vprintf(esp_apptrace_vprintf);``。如需将日志数据再次重定向给 UART,请使用 ``esp_log_set_vprintf(vprintf);``。 +3. 按照 :ref:`app_trace-application-specific-tracing` 章节中的第 1-5 步进行操作。 +4. 打印接收到的日志记录,请在终端运行以下命令:``$IDF_PATH/tools/esp_app_trace/logtrace_proc.py /path/to/trace/file /path/to/program/elf/file``。 Log Trace Processor 命令选项 @@ -342,11 +369,9 @@ ESP-IDF 中另一个基于应用层跟踪库的实用功能是系统级跟踪, 若需使用这个功能,需要在 menuconfig 中开启 :ref:`CONFIG_APPTRACE_SV_ENABLE` 选项,具体路径为 ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing``。同一菜单栏下还开启了其它几个选项: -1. *SytemView destination*。选择需要使用的接口:JTAG 或 UART。使用 UART 接口时,可以将 SystemView 应用程序直接连接到 {IDF_TARGET_NAME} 并实时接收数据。 +1. {IDF_TARGET_NAME} 用作 SystemView 时间戳源的定时器选择:(:ref:`CONFIG_APPTRACE_SV_TS_SOURCE`)用于选择 SystemView 事件的时间戳源。在单核模式下,时间戳由以最大频率运行的 {IDF_TARGET_NAME} 内部周期计数器生成。(:ref:`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ`)在双核模式下,使用外部定时器生成时间戳,其频率为 CPU 频率的 1/2。 -2. *{IDF_TARGET_NAME} timer to use as SystemView timestamp source* (:ref:`CONFIG_APPTRACE_SV_TS_SOURCE`)。选择 SystemView 事件使用的时间戳来源。在单核模式下,使用 {IDF_TARGET_NAME} 内部的循环计数器生成时间戳,其最大的工作频率是 240 MHz(时间戳粒度大约为 4 ns)。在双核模式下,使用工作在 40 MHz 的外部定时器,因此时间戳粒度为 25 ns。 - -3. 可以单独启用或禁用的 SystemView 事件集合 (``CONFIG_APPTRACE_SV_EVT_XXX``): +2. 可以单独启用或禁用的 SystemView 事件集合 (``CONFIG_APPTRACE_SV_EVT_XXX``): - Trace Buffer Overflow Event - ISR Enter Event @@ -362,10 +387,9 @@ ESP-IDF 中另一个基于应用层跟踪库的实用功能是系统级跟踪, - Timer Enter Event - Timer Exit Event -ESP-IDF 中已经包含了所有用于生成兼容 SystemView 跟踪信息的代码,用户只需配置必要的项目选项(如上所示),然后构建、烧写映像到目标板,接着参照前面的介绍,使用 OpenOCD 收集数据。 - -4. 想要通过 UART 接口进行实时跟踪,请在菜单配置选项 ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` 中选择 Pro 或 App CPU。 +ESP-IDF 中已经包含了所有用于生成兼容 SystemView 跟踪信息的代码。 +3. 想要通过 UART 接口进行实时跟踪,请在菜单配置选项 ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` 中选择 Pro 或 App CPU。 OpenOCD SystemView 跟踪命令选项 """"""""""""""""""""""""""""""" @@ -430,7 +454,7 @@ Start 子命令语法: .. only:: SOC_HP_CPU_HAS_MULTIPLE_CORES - 遗憾的是,SystemView 不支持从多个核心进行跟踪。所以当使用 JTAG 追踪双核模式下的 {IDF_TARGET_NAME} 时会生成两个文件:一个用于 PRO CPU,另一个用于 APP CPU。用户可以将每个文件加载到工具中单独分析。使用 UART 进行追踪时,用户可以在 menuconfig Pro 或 App 中点击 ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` 并选择要追踪的 CPU。 + 遗憾的是,SystemView 不支持从多个核心进行跟踪。所以当使用 JTAG 跟踪双核模式下的 {IDF_TARGET_NAME} 时会生成两个文件:一个用于 PRO CPU,另一个用于 APP CPU。用户可以将每个文件加载到工具中单独分析。使用 UART 进行跟踪时,用户可以在 menuconfig Pro 或 App 中点击 ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` 并选择要跟踪的 CPU。 在工具中单独分析每个核的跟踪数据是比较棘手的,但是 Eclipse 提供了 *Impulse* 插件,该插件可以加载多个跟踪文件,并且可以在同一视图中检查来自两个内核的事件。此外,与免费版的 SystemView 相比,此插件没有 1,000,000 个事件的限制。 diff --git a/docs/zh_CN/api-reference/system/heap_debug.rst b/docs/zh_CN/api-reference/system/heap_debug.rst index fe959ef5df8..c932b8049f2 100644 --- a/docs/zh_CN/api-reference/system/heap_debug.rst +++ b/docs/zh_CN/api-reference/system/heap_debug.rst @@ -571,7 +571,7 @@ ESP-IDF 集成了用于请求 :ref:`堆内存信息 `、:ref:` 确定存在泄漏的代码后,请执行以下步骤: - 在项目配置菜单中,前往 ``Component config`` > ``Heap Memory Debugging`` > :ref:`CONFIG_HEAP_TRACING_DEST` 并选择 ``Host-Based``。 -- 在项目配置菜单中,前往 ``Component config`` > ``Application Level Tracing`` > :ref:`CONFIG_APPTRACE_DESTINATION1` 并选择 ``Trace memory``。 +- 在项目配置菜单中,前往 ``Component config`` > ``Application Level Tracing`` > ``Enable Application Level Tracing`` > ``Data Destination`` :ref:`CONFIG_APPTRACE_DESTINATION` 并选择 ``JTAG``。 - 在项目配置菜单中,前往 ``Component config`` > ``Application Level Tracing`` > ``FreeRTOS SystemView Tracing`` 并启用 :ref:`CONFIG_APPTRACE_SV_ENABLE`。 - 在程序早期,调用函数 :cpp:func:`heap_trace_init_tohost`,初始化 JTAG 堆内存跟踪模块。 - 在有内存泄漏之嫌的代码块前,调用函数 :cpp:func:`heap_trace_start` 开始记录系统中的内存分配和释放操作。 diff --git a/docs/zh_CN/migration-guides/release-6.x/6.0/system.rst b/docs/zh_CN/migration-guides/release-6.x/6.0/system.rst index f2864d25945..8678610fa16 100644 --- a/docs/zh_CN/migration-guides/release-6.x/6.0/system.rst +++ b/docs/zh_CN/migration-guides/release-6.x/6.0/system.rst @@ -70,27 +70,64 @@ ROM 头文件 App 追踪 ---------- -已移除额外数据缓冲选项。不再支持 `CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX` 配置项。 +配置更改 +^^^^^^^^^^ -已移除弃用的 `ESP_APPTRACE_DEST_TRAX` 枚举值。请改用 `ESP_APPTRACE_DEST_JTAG`。 +此前,当配置传输目标时,应用程序跟踪会自动启用。现在必须在配置任何目标前,通过 ``CONFIG_APPTRACE_ENABLE`` 选项显式启用应用程序跟踪功能。 -函数 :cpp:func:`esp_apptrace_down_buffer_config` 现在需要一个目标参数,并返回一个错误代码以便进行适当的错误处理。 +如需启用应用程序跟踪,请在 menuconfig 中依次进入 "Component config" → "Application Level Tracing" → "Enable Application Level Tracing" 进行设置。 -旧代码: +已移除额外数据缓冲选项。不再支持 ``CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX`` 配置项。 + +已移除弃用的 ``ESP_APPTRACE_DEST_TRAX`` 枚举值。请改用 ``ESP_APPTRACE_DEST_JTAG``。 + +初始化流程更改 +^^^^^^^^^^^^^^^^^^^ + +如需在运行时覆盖默认配置,可以实现 ``esp_apptrace_get_user_params()`` 回调函数。系统提供了一个弱默认实现,返回 menuconfig 的默认配置(``APPTRACE_CONFIG_DEFAULT()``)。您的应用程序可以通过提供自己的配置来覆盖此默认实现。 + + .. code-block:: c + + esp_apptrace_config_t esp_apptrace_get_user_params(void) + { + esp_apptrace_config_t config = APPTRACE_CONFIG_DEFAULT(); + + // 使用自定义值覆盖(UART 示例) + config.dest_cfg.uart.uart_num = UART_NUM_0; + config.dest_cfg.uart.baud_rate = 921600; + config.dest_cfg.uart.tx_pin_num = GPIO_NUM_17; + config.dest_cfg.uart.rx_pin_num = GPIO_NUM_16; + + return config; + } + + **重要提示:** + + - 请 **勿** 在您的实现中添加 ``__attribute__((weak))`` + - 您也可以使用特定目标的宏:``APPTRACE_JTAG_CONFIG_DEFAULT()`` 或 ``APPTRACE_UART_CONFIG_DEFAULT()`` + +API 更改 +^^^^^^^^^^^ + +所有 apptrace API 中的目标参数已被移除。 + +旧版本: .. code-block:: c - esp_apptrace_down_buffer_config(down_buf, sizeof(down_buf)); + esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, data, size, timeout); + esp_apptrace_read(ESP_APPTRACE_DEST_UART, buffer, &size, timeout); + esp_apptrace_flush(ESP_APPTRACE_DEST_JTAG, min_sz, timeout); -现在需要修改成: +更新为: .. code-block:: c - esp_err_t res = esp_apptrace_down_buffer_config(ESP_APPTRACE_DEST_JTAG, down_buf, sizeof(down_buf)); - if (res != ESP_OK) { - ESP_LOGE(TAG, "Failed to config down buffer!"); - return res; - } + esp_apptrace_write(data, size, timeout); + esp_apptrace_read(buffer, &size, timeout); + esp_apptrace_flush(min_sz, timeout); + +目标现在在 menuconfig 中的 "Application Level Tracing" → "Data Destination" 下全局配置。 UART 目标配置已简化: @@ -114,10 +151,18 @@ UART 目标配置已简化: CONFIG_APPTRACE_DEST_UART=y CONFIG_APPTRACE_DEST_UART_NUM=0 # 或 1、2,具体取决于目标芯片 +SystemView 的传输目标 +^^^^^^^^^^^^^^^^^^^^^^^ + +SystemView 的传输目标现在由与应用程序跟踪目标相同的配置控制。启用 SystemView 后,它将使用在 "Application Level Tracing" → "Data Destination" 下配置的目标传输方式。 + +这意味着如果同时启用了应用程序跟踪和 SystemView,它们将共享在 menuconfig 中配置的相同目标传输方式(JTAG 或 UART)。SystemView 将不再拥有独立的传输目标配置。 + FreeRTOS -------- -**已移除的函数** +已移除的函数 +^^^^^^^^^^^^^^ 以下已弃用的 FreeRTOS 函数已在 ESP-IDF v6.0 中移除: @@ -127,22 +172,25 @@ FreeRTOS 以下兼容性函数已在 ESP-IDF v6.0 中移除。这些函数原本是为了向后兼容旧版本 ESP-IDF 而维护的,因为它们在 FreeRTOS 中已被更改为宏或独立函数。现已移除此兼容性支持。 -- :cpp:func:`xQueueGenericReceive` - 请根据具体使用场景选择 :cpp:func:`xQueueReceive`、:cpp:func:`xQueuePeek` 或 :cpp:func:`xQueueSemaphoreTake` 替代 -- :cpp:func:`vTaskDelayUntil` - 请使用 :cpp:func:`xTaskDelayUntil` 替代 -- :cpp:func:`ulTaskNotifyTake` - 请使用宏 ``ulTaskNotifyTake`` 替代 -- :cpp:func:`xTaskNotifyWait` - 请使用宏 ``xTaskNotifyWait`` 替代 +- :cpp:func:`xQueueGenericReceive` - 请根据具体使用场景选择 :cpp:func:`xQueueReceive`、:cpp:func:`xQueuePeek` 或 :cpp:func:`xQueueSemaphoreTake` 替代。 +- :cpp:func:`vTaskDelayUntil` - 请使用 :cpp:func:`xTaskDelayUntil` 替代。 +- :cpp:func:`ulTaskNotifyTake` - 请使用宏 ``ulTaskNotifyTake`` 替代。 +- :cpp:func:`xTaskNotifyWait` - 请使用宏 ``xTaskNotifyWait`` 替代。 -**已弃用的函数** +已弃用的函数 +^^^^^^^^^^^^^^ 函数 :cpp:func:`pxTaskGetStackStart` 已弃用。请使用 :cpp:func:`xTaskGetStackStart` 替代以提高类型安全性。 -**新增 API** +新增 API +^^^^^^^^^ 任务快照 API 已对外公开,以支持 ESP Insights 等外部框架。这些 API 现通过 ``freertos/freertos_debug.h`` 头文件提供,不再使用已弃用的 ``freertos/task_snapshot.h``。 在调度程序运行时安全使用的方案是:调用快照函数前先执行 ``vTaskSuspendAll()`` 暂停所有任务,完成后调用 ``xTaskResumeAll()`` 恢复运行。 -**内存布局** +内存布局 +^^^^^^^^^^^^ - 为了减少 IRAM 的使用,大多数 FreeRTOS 函数的默认存储位置已从 IRAM 更改为 flash。因此,``CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH`` 选项已被移除。这项变更可显著节省 IRAM 空间,但可能会对性能造成轻微影响。如果应用对性能有严苛要求,可通过启用新选项 :ref:`CONFIG_FREERTOS_IN_IRAM` 恢复原先配置。 - 启用 ``CONFIG_FREERTOS_IN_IRAM`` 前,建议进行性能测试以评估对具体应用场景的实际影响。flash 和 IRAM 配置的性能差异取决于 flash 缓存效率、API 调用模式和系统负载等因素。 @@ -150,7 +198,8 @@ FreeRTOS - 当启用 ``CONFIG_ESP_PANIC_HANDLER_IRAM`` 时,任务快照函数会自动存入 IRAM,确保在系统崩溃处理期间仍可调用。 - 除非启用 ``CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH``,否则 ``vTaskGetSnapshot`` 将始终保留在 IRAM 中,因为该函数被任务看门狗中断处理程序所调用。 -**已移除的配置选项** +已移除的配置选项 +^^^^^^^^^^^^^^^^^^ 以下隐藏(且始终启用)的配置选项已被移除: @@ -160,21 +209,24 @@ FreeRTOS 环形缓冲区 ---------- -**内存布局** +内存布局 +^^^^^^^^^^ -为了减少 IRAM 的使用,`esp_ringbuf` 函数的默认位置已从 IRAM 更改为 Flash。因此,``CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH`` 选项已被移除。此举可节省大量 IRAM,但可能会对性能造成轻微影响。对于性能要求严苛的应用程序,可通过启用新增的 :ref:`CONFIG_RINGBUF_IN_IRAM` 选项来恢复之前的行为。 +为了减少 IRAM 的使用,`esp_ringbuf` 函数的默认位置已从 IRAM 更改为 flash。因此,``CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH`` 选项已被移除。此举可节省大量 IRAM,但可能会对性能造成轻微影响。对于性能要求严苛的应用程序,可通过启用新增的 :ref:`CONFIG_RINGBUF_IN_IRAM` 选项来恢复之前的行为。 Log --- -**已移除的函数** +已移除的函数 +^^^^^^^^^^^^^^ 以下已弃用的 Log 函数已在 ESP-IDF v6.0 中移除: - :cpp:func:`esp_log_buffer_hex` – 请使用 :cpp:func:`ESP_LOG_BUFFER_HEX` 替代。 - :cpp:func:`esp_log_buffer_char` – 请使用 :cpp:func:`ESP_LOG_BUFFER_CHAR` 替代。 -**已移除的头文件** +已移除的头文件 +^^^^^^^^^^^^^^^ - ``esp_log_internal.h`` – 请使用 ``esp_log_buffer.h`` 替代。 @@ -199,7 +251,8 @@ ESP HTTPS OTA 的分段下载功能已移至配置选项下,以便在未使用 如果要在 OTA 应用中使用分段下载功能,需要在 menuconfig 中启用组件级配置 :ref:`CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD` (``Component config`` → ``ESP HTTPS OTA`` → ``Enable partial HTTP download for OTA``)。 -**已移除的废弃 API** +已移除的废弃 API +^^^^^^^^^^^^^^^^^^^^ 以下废弃函数已从 ``app_update`` 组件中移除: @@ -213,7 +266,8 @@ Gcov gcov 组件已移至独立仓库。`esp_gcov `_ 现为托管组件。 -**组件依赖** +组件依赖 +^^^^^^^^^^^ 使用 gcov 功能的项目现在必须在 ``idf_component.yml`` 清单文件中添加 esp_gcov 组件作为依赖项: @@ -222,13 +276,15 @@ gcov 组件已移至独立仓库。`esp_gcov None: search_strings = ['Targets connected.', 'Disconnect targets...'] with open(openocd.log_file, encoding='utf-8') as oocd_log: # pylint: disable=protected-access cores = 1 if dut.app.sdkconfig.get('ESP_SYSTEM_SINGLE_CORE_MODE') is True else 2 - search_strings.append('App trace params: from {} cores,'.format(cores)) + search_strings.append(f'App trace params: from {cores} cores,') for search_str in search_strings: found = False oocd_log.seek(0) @@ -35,26 +37,51 @@ def _test_examples_app_trace_basic(openocd_dut: 'OpenOCD', dut: IdfDut) -> None: raise RuntimeError(f'"{search_str}" could not be found in {openocd.log_file}') # pylint: disable=protected-access with open('apptrace.log', encoding='utf-8') as apptrace_log: + content = apptrace_log.read() for sample_num in range(1, 51): - log_str = 'Apptrace test data[{}]:{}'.format(sample_num, sample_num * sample_num) - found = False - for line in apptrace_log: - if log_str in line: - found = True - break - if found is not True: + log_str = f'Apptrace test data[{sample_num}]:{sample_num * sample_num}' + if log_str not in content: raise RuntimeError('"{}" could not be found in {}'.format(log_str, 'apptrace.log')) @pytest.mark.jtag +@idf_parametrize('config', ['apptrace_jtag'], indirect=['config']) @idf_parametrize('target', ['esp32', 'esp32c2', 'esp32s2'], indirect=['target']) def test_examples_app_trace_basic(openocd_dut: 'OpenOCD', dut: IdfDut) -> None: _test_examples_app_trace_basic(openocd_dut, dut) @pytest.mark.usb_serial_jtag +@idf_parametrize('config', ['apptrace_jtag'], indirect=['config']) @idf_parametrize( 'target', ['esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32c61', 'esp32h2', 'esp32p4'], indirect=['target'] ) def test_examples_app_trace_basic_usj(openocd_dut: 'OpenOCD', dut: IdfDut) -> None: _test_examples_app_trace_basic(openocd_dut, dut) + + +@pytest.mark.generic +@idf_parametrize('config', ['apptrace_uart'], indirect=['config']) +@idf_parametrize('target', ['supported_targets'], indirect=['target']) +def test_examples_app_trace_basic_uart(dut: IdfDut) -> None: + dut.serial.close() + with serial.Serial(dut.serial.port, baudrate=1000000, timeout=10) as ser: + apptrace_log = os.path.join(dut.logdir, 'apptrace_log_uart.txt') # pylint: disable=protected-access + with open(apptrace_log, 'w+b') as f: + start_time = time.time() + while True: + try: + if ser.in_waiting: + data = ser.read(100) + f.write(data) + if time.time() - start_time > 5: + break + except serial.SerialTimeoutException: + assert False, 'Timeout reached while reading from serial port, exiting...' + + f.seek(0) + content = f.read().decode('utf-8', errors='ignore') + for sample_num in range(1, 51): + log_str = f'Apptrace test data[{sample_num}]:{sample_num * sample_num}' + if log_str not in content: + raise RuntimeError('"{}" could not be found in {}'.format(log_str, 'apptrace_log_uart.txt')) diff --git a/examples/system/app_trace_basic/sdkconfig.ci.apptrace_jtag b/examples/system/app_trace_basic/sdkconfig.ci.apptrace_jtag new file mode 100644 index 00000000000..772bddde156 --- /dev/null +++ b/examples/system/app_trace_basic/sdkconfig.ci.apptrace_jtag @@ -0,0 +1 @@ +CONFIG_APPTRACE_DEST_JTAG=y diff --git a/examples/system/app_trace_basic/sdkconfig.ci.apptrace_uart b/examples/system/app_trace_basic/sdkconfig.ci.apptrace_uart new file mode 100644 index 00000000000..e2a7c255a3b --- /dev/null +++ b/examples/system/app_trace_basic/sdkconfig.ci.apptrace_uart @@ -0,0 +1,3 @@ +CONFIG_ESP_CONSOLE_NONE=y +# Destination selection on runtime +CONFIG_APPTRACE_DEST_NONE=y diff --git a/examples/system/app_trace_basic/sdkconfig.defaults b/examples/system/app_trace_basic/sdkconfig.defaults index e7028aee834..376f789f619 100644 --- a/examples/system/app_trace_basic/sdkconfig.defaults +++ b/examples/system/app_trace_basic/sdkconfig.defaults @@ -1,3 +1,2 @@ # Enable application tracing by default -CONFIG_APPTRACE_DEST_JTAG=y CONFIG_APPTRACE_ENABLE=y diff --git a/examples/system/app_trace_to_plot/main/app_trace_to_plot.c b/examples/system/app_trace_to_plot/main/app_trace_to_plot.c index d9d9789c05d..db686a10859 100644 --- a/examples/system/app_trace_to_plot/main/app_trace_to_plot.c +++ b/examples/system/app_trace_to_plot/main/app_trace_to_plot.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -56,7 +56,7 @@ typedef struct { int16_t get_engine_temperature(int cnt) { - /* A healhty engine should work between 90 to 105 degree Celcius */ + /* A healhty engine should work between 90 to 105 degree Celsius */ const int32_t temp_arr[] = {1, 1, 2, 3, 4, 6, 8, 10, 13, 16, 19, 24, 29, 34, 40, 47, 53, 60, 68, 75, 82, 88, 94, 99, 103, 105, 107, 107, 106, 104, 101, 96, 91, 85, 78, 71, 64, 57, 50, 43, 37, 31, 26, 21, 17, 14, 11, 9, 7, 5, 4, 3}; @@ -65,7 +65,7 @@ int16_t get_engine_temperature(int cnt) int8_t get_outside_temperature(int cnt) { - /* Recorded hightest temperature was around 57 degree and lowest was -89 degree Celcius */ + /* Recorded highest temperature was around 57 degree and lowest was -89 degree Celsius */ return (rand() % 146) - 89; } @@ -84,7 +84,7 @@ int32_t get_pressure(int cnt) void app_main(void) { ESP_LOGI(TAG, "Waiting for OpenOCD connection"); - while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_JTAG)) { + while (!esp_apptrace_host_is_connected()) { vTaskDelay(1); } @@ -98,7 +98,7 @@ void app_main(void) memcpy(buf, (uint8_t *)&STX, STX_LENGTH); - while (esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_JTAG)) { + while (esp_apptrace_host_is_connected()) { sensor.header.id = 1; sensor.header.timestamp = esp_log_timestamp(); sensor.value = get_outside_temperature(cnt); @@ -106,7 +106,7 @@ void app_main(void) buf[STX_LENGTH] = sizeof(sensor); memcpy(buf + STX_LENGTH + 1, (uint8_t *)&sensor, sizeof(sensor)); buf[STX_LENGTH + 1 + sizeof(sensor)] = ETX; - esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, buf, sizeof(sensor) + STX_LENGTH + 1/*sensor pkt len*/ + 1/*ETX len*/, ESP_APPTRACE_TMO_INFINITE); + esp_err_t res = esp_apptrace_write(buf, sizeof(sensor) + STX_LENGTH + 1/*sensor pkt len*/ + 1/*ETX len*/, ESP_APPTRACE_TMO_INFINITE); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to write data to host [0x%x] (%s)", res, esp_err_to_name(res)); break; @@ -121,7 +121,7 @@ void app_main(void) buf[STX_LENGTH] = sizeof(sensor2); memcpy(buf + STX_LENGTH + 1, (uint8_t *)&sensor2, sizeof(sensor2)); buf[STX_LENGTH + 1 + sizeof(sensor2)] = ETX; - res = esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, buf, sizeof(sensor2) + STX_LENGTH + 1/*sensor pkt len*/ + 1/*ETX len*/, ESP_APPTRACE_TMO_INFINITE); + res = esp_apptrace_write(buf, sizeof(sensor2) + STX_LENGTH + 1/*sensor pkt len*/ + 1/*ETX len*/, ESP_APPTRACE_TMO_INFINITE); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to write data to host [0x%x] (%s)", res, esp_err_to_name(res)); break; @@ -136,7 +136,7 @@ void app_main(void) buf[STX_LENGTH] = sizeof(sensor3); memcpy(buf + STX_LENGTH + 1, (uint8_t *)&sensor3, sizeof(sensor3)); buf[STX_LENGTH + 1 + sizeof(sensor3)] = ETX; - res = esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, buf, sizeof(sensor3) + STX_LENGTH + 1/*sensor pkt len*/ + 1/*ETX len*/, ESP_APPTRACE_TMO_INFINITE); + res = esp_apptrace_write(buf, sizeof(sensor3) + STX_LENGTH + 1/*sensor pkt len*/ + 1/*ETX len*/, ESP_APPTRACE_TMO_INFINITE); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to write data to host [0x%x] (%s)", res, esp_err_to_name(res)); break; @@ -151,14 +151,14 @@ void app_main(void) buf[STX_LENGTH] = sizeof(sensor4); memcpy(buf + STX_LENGTH + 1, (uint8_t *)&sensor4, sizeof(sensor4)); buf[STX_LENGTH + 1 + sizeof(sensor4)] = ETX; - res = esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, buf, sizeof(sensor4) + STX_LENGTH + 1/*sensor pkt len*/ + 1/*ETX len*/, ESP_APPTRACE_TMO_INFINITE); + res = esp_apptrace_write(buf, sizeof(sensor4) + STX_LENGTH + 1/*sensor pkt len*/ + 1/*ETX len*/, ESP_APPTRACE_TMO_INFINITE); if (res != ESP_OK) { ESP_LOGE(TAG, "Failed to write data to host [0x%x] (%s)", res, esp_err_to_name(res)); break; } vTaskDelay(10 / portTICK_PERIOD_MS); - esp_apptrace_flush(ESP_APPTRACE_DEST_JTAG, 1000); + esp_apptrace_flush(1000); cnt = (cnt + 1) % CYCLE_PERIOD; } ESP_LOGE(TAG, "Apptrace connection lost"); diff --git a/examples/system/app_trace_to_plot/sdkconfig.defaults b/examples/system/app_trace_to_plot/sdkconfig.defaults index e7028aee834..bcec5bd2f04 100644 --- a/examples/system/app_trace_to_plot/sdkconfig.defaults +++ b/examples/system/app_trace_to_plot/sdkconfig.defaults @@ -1,3 +1,3 @@ # Enable application tracing by default -CONFIG_APPTRACE_DEST_JTAG=y CONFIG_APPTRACE_ENABLE=y +CONFIG_APPTRACE_DEST_JTAG=y diff --git a/examples/system/gcov/sdkconfig.defaults b/examples/system/gcov/sdkconfig.defaults index b144d1fbf25..4d64a379004 100644 --- a/examples/system/gcov/sdkconfig.defaults +++ b/examples/system/gcov/sdkconfig.defaults @@ -1,5 +1,4 @@ CONFIG_APPTRACE_DEST_JTAG=y -# CONFIG_APPTRACE_DEST_NONE is not set CONFIG_APPTRACE_ENABLE=y CONFIG_APPTRACE_LOCK_ENABLE=y CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO=-1 diff --git a/examples/system/sysview_tracing/main/sysview_tracing.c b/examples/system/sysview_tracing/main/sysview_tracing.c index 48adab2bb0c..0d62a122177 100644 --- a/examples/system/sysview_tracing/main/sysview_tracing.c +++ b/examples/system/sysview_tracing/main/sysview_tracing.c @@ -7,12 +7,14 @@ CONDITIONS OF ANY KIND, either express or implied. */ +#include "esp_err.h" #include "sdkconfig.h" #include #include #include #include #include "esp_log.h" +#include "esp_app_trace.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gptimer.h" diff --git a/examples/system/sysview_tracing/pytest_sysview_tracing.py b/examples/system/sysview_tracing/pytest_sysview_tracing.py index 674a11ecf7a..8c0d2899903 100644 --- a/examples/system/sysview_tracing/pytest_sysview_tracing.py +++ b/examples/system/sysview_tracing/pytest_sysview_tracing.py @@ -15,6 +15,20 @@ if typing.TYPE_CHECKING: from conftest import OpenOCD +def _validate_trace_data(trace_log: list[str], target: str) -> None: + """Validate SysView trace data in log file(s). + + Args: + trace_log: List of trace log paths + target: Target chip name (e.g., 'esp32', 'esp32s3') + """ + for idx, log in enumerate(trace_log): + with open(log, 'rb') as f: + content = f.read() + search_str = f'N=FreeRTOS Application,D={target},C=core{idx},O=FreeRTOS'.encode() + assert search_str in content, f'SysView trace data not found in {log}' + + def _test_sysview_tracing_jtag(openocd_dut: 'OpenOCD', dut: IdfDut) -> None: # Construct trace log paths trace_log = [ @@ -58,6 +72,8 @@ def _test_sysview_tracing_jtag(openocd_dut: 'OpenOCD', dut: IdfDut) -> None: time.sleep(3) openocd.write('esp sysview stop') + _validate_trace_data(trace_log, dut.target) + @pytest.mark.jtag @idf_parametrize('config', ['sysview_jtag'], indirect=['config']) @@ -79,10 +95,10 @@ def _test_sysview_tracing_uart(dut: IdfDut) -> None: dut.serial.close() time.sleep(2) # Wait for the DUT to reboot with serial.Serial(dut.serial.port, baudrate=dut.app.sdkconfig.get('APPTRACE_UART_BAUDRATE'), timeout=10) as ser: - trace_log = os.path.join(dut.logdir, 'sys_log_uart.svdat') # pylint: disable=protected-access + trace_log = [os.path.join(dut.logdir, 'sys_log_uart.svdat')] # pylint: disable=protected-access # Send Start command to start SysView tracing ser.write(b'\x01') - with open(trace_log, 'w+b') as f: + with open(trace_log[0], 'w+b') as f: start_time = time.time() while True: try: @@ -97,10 +113,7 @@ def _test_sysview_tracing_uart(dut: IdfDut) -> None: # Send Stop command ser.write(b'\x02') - f.seek(0) - content = f.read() - search_str = f'N=FreeRTOS Application,D={dut.target},C=core0,O=FreeRTOS'.encode() - assert search_str in content, 'SysView trace data not found in the log file' + _validate_trace_data(trace_log, dut.target) @pytest.mark.generic diff --git a/examples/system/sysview_tracing/sdkconfig.ci.sysview_uart b/examples/system/sysview_tracing/sdkconfig.ci.sysview_uart index 73b99d42676..9d16ef2ee1a 100644 --- a/examples/system/sysview_tracing/sdkconfig.ci.sysview_uart +++ b/examples/system/sysview_tracing/sdkconfig.ci.sysview_uart @@ -1,5 +1,4 @@ CONFIG_ESP_CONSOLE_NONE=y -CONFIG_ESP_CONSOLE_SECONDARY_NONE=y CONFIG_APPTRACE_DEST_UART=y CONFIG_APPTRACE_DEST_UART_NUM=0 -CONFIG_APPTRACE_SV_DEST_UART=y +CONFIG_USE_CUSTOM_EVENT_ID=y diff --git a/examples/system/sysview_tracing/sdkconfig.ci.sysview_uart_esp32c2_26Mhz b/examples/system/sysview_tracing/sdkconfig.ci.sysview_uart_esp32c2_26Mhz index 442044d5730..1efa43fecec 100644 --- a/examples/system/sysview_tracing/sdkconfig.ci.sysview_uart_esp32c2_26Mhz +++ b/examples/system/sysview_tracing/sdkconfig.ci.sysview_uart_esp32c2_26Mhz @@ -1,8 +1,6 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_ESP_CONSOLE_NONE=y -CONFIG_ESP_CONSOLE_SECONDARY_NONE=y CONFIG_APPTRACE_DEST_UART=y CONFIG_APPTRACE_DEST_UART_NUM=0 -CONFIG_APPTRACE_SV_DEST_UART=y CONFIG_APPTRACE_UART_BAUDRATE=74880 CONFIG_XTAL_FREQ_26=y diff --git a/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c b/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c index aecf041da5b..455d013ad2e 100644 --- a/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c +++ b/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c @@ -9,6 +9,8 @@ #include "sdkconfig.h" #include +#include "esp_err.h" +#include "esp_app_trace.h" #include "esp_sysview_trace.h" #include "esp_heap_trace.h" #include "esp_log.h" diff --git a/examples/system/sysview_tracing_heap_log/sdkconfig.defaults b/examples/system/sysview_tracing_heap_log/sdkconfig.defaults index 0d2f661c0ee..97521d048e8 100644 --- a/examples/system/sysview_tracing_heap_log/sdkconfig.defaults +++ b/examples/system/sysview_tracing_heap_log/sdkconfig.defaults @@ -2,7 +2,6 @@ CONFIG_FREERTOS_HZ=1000 # Enable application tracing by default CONFIG_APPTRACE_DEST_JTAG=y -CONFIG_APPTRACE_MEMBUFS_APPTRACE_PROTO_ENABLE=y CONFIG_APPTRACE_ENABLE=y # Enable FreeRTOS SystemView Tracing by default CONFIG_APPTRACE_SV_ENABLE=y