diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8a662bd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,3 @@ +if(ESP_PLATFORM) + include(${CMAKE_CURRENT_LIST_DIR}/kernelports/ESP-IDF_FreeRTOS/esp.cmake) +endif() \ No newline at end of file diff --git a/Kconfig b/Kconfig index 84ac7af..e2bf8d6 100644 --- a/Kconfig +++ b/Kconfig @@ -1,30 +1,36 @@ # Copyright (c) 2021 Percepio AB # SPDX-License-Identifier: Apache-2.0 -menu "Trace Recorder" -choice PERCEPIO_TRC_CFG_RECORDER_RTOS - prompt "Recorder RTOS" - default PERCEPIO_TRC_CFG_RECORDER_RTOS_FREERTOS +if !IDF_CMAKE + menu "Trace Recorder" + choice PERCEPIO_TRC_CFG_RECORDER_RTOS + prompt "Recorder RTOS" + default PERCEPIO_TRC_CFG_RECORDER_RTOS_FREERTOS -config PERCEPIO_TRC_CFG_RECORDER_RTOS_FREERTOS - bool "FreeRTOS" - -config PERCEPIO_TRC_CFG_RECORDER_RTOS_THREADX - bool "ThreadX" - -config PERCEPIO_TRC_CFG_RECORDER_RTOS_ZEPHYR - bool "Zephyr" -endchoice + config PERCEPIO_TRC_CFG_RECORDER_RTOS_FREERTOS + bool "FreeRTOS" + + config PERCEPIO_TRC_CFG_RECORDER_RTOS_THREADX + bool "ThreadX" + + config PERCEPIO_TRC_CFG_RECORDER_RTOS_ZEPHYR + bool "Zephyr" + endchoice -if PERCEPIO_TRC_CFG_RECORDER_RTOS_FREERTOS -rsource "kernelports/FreeRTOS/config/Kconfig" -endif # PERCEPIO_TRC_CFG_RECORDER_RTOS_FREERTOS + if PERCEPIO_TRC_CFG_RECORDER_RTOS_FREERTOS + # rsource "kernelports/FreeRTOS/config/Kconfig" + endif # PERCEPIO_TRC_CFG_RECORDER_RTOS_FREERTOS -if PERCEPIO_TRC_CFG_RECORDER_RTOS_THREADX -rsource "kernelports/ThreadX/config/Kconfig" -endif # PERCEPIO_TRC_CFG_RECORDER_RTOS_THREADX + if PERCEPIO_TRC_CFG_RECORDER_RTOS_THREADX + # rsource "kernelports/ThreadX/config/Kconfig" + endif # PERCEPIO_TRC_CFG_RECORDER_RTOS_THREADX -if PERCEPIO_TRC_CFG_RECORDER_RTOS_ZEPHYR -rsource "kernelports/Zephyr/config/Kconfig" -endif # PERCEPIO_TRC_CFG_RECORDER_RTOS_ZEPHYR -endmenu # "Trace Recorder" + if PERCEPIO_TRC_CFG_RECORDER_RTOS_ZEPHYR + # rsource "kernelports/Zephyr/config/Kconfig" + endif # PERCEPIO_TRC_CFG_RECORDER_RTOS_ZEPHYR + endmenu # "Trace Recorder" +endif + +if IDF_CMAKE +rsource "kernelports/ESP-IDF_FreeRTOS/Kconfig.projbuild" +endif diff --git a/examples/ESP-IDF/tracing/CMakeLists.txt b/examples/ESP-IDF/tracing/CMakeLists.txt new file mode 100644 index 0000000..4b70923 --- /dev/null +++ b/examples/ESP-IDF/tracing/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD OFF) +project(tracealyzer) diff --git a/examples/ESP-IDF/tracing/README.md b/examples/ESP-IDF/tracing/README.md new file mode 100644 index 0000000..17009f9 --- /dev/null +++ b/examples/ESP-IDF/tracing/README.md @@ -0,0 +1,148 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | +# Example: Application Level Tracing - Percepio Tracealyzer Traces (tracealyzer) + +This test code shows how to perform system-wide behavioral analysis of the program using [Percepio Tracealyzer tool](https://www.segger.com/products/development-tools/systemview/). + +For description of [SystemView tracing](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#system-behaviour-analysis-with-segger-systemview) please refer to **ESP32 Programming Guide**, section **Application Level Tracing library**. The following example provides practical implementation of this functionality. + + +## Use Case + +To find the reason of program's misbehaviour it is often necessary to have the whole picture of interacting components (scheduler, IRQs, tasks, semaphores etc.) in the system. In such cases tools which allow to trace the behaviour of the system as a whole can be very useful. +Consider the following situation. User program have a timer and a task. Upon every tick the timer sends an event to the task. When task receives event it prints a message. Timer should notify the task 10 times. +There can be a problem which causes the task to lose some events. +Below is the timer's ISR code: + +``` +static void example_timer_isr(void *arg) +{ + example_event_data_t *tim_arg = (example_event_data_t *)arg; + + if (tim_arg->thnd != NULL) { + if (tim_arg->count++ < 10) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + if (xTaskNotifyFromISR(tim_arg->thnd, tim_arg->count, eSetValueWithOverwrite, &xHigherPriorityTaskWoken) != pdPASS) { + ESP_EARLY_LOGE(TAG, "Failed to notify task %p", tim_arg->thnd); + } else { + if (xHigherPriorityTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } + } + } + } + // re-start timer + example_timer_rearm(tim_arg->group, tim_arg->timer); +} +``` + +Below is the task's code: + +``` +static void example_task(void *p) +{ + example_event_data_t *arg = (example_event_data_t *) p; + timer_isr_handle_t inth; + + ESP_LOGI(TAG, "%p: run task", xTaskGetCurrentTaskHandle()); + + esp_err_t res = timer_isr_register(arg->group, arg->timer, example_timer_isr, arg, 0, &inth); + if (res != ESP_OK) { + ESP_LOGE(TAG, "%p: failed to register timer ISR", xTaskGetCurrentTaskHandle()); + } + else { + res = timer_start(arg->group, arg->timer); + if (res != ESP_OK) { + ESP_LOGE(TAG, "%p: failed to start timer", xTaskGetCurrentTaskHandle()); + } + } + + while (1) { + uint32_t event_val; + xTaskNotifyWait(0, 0, &event_val, portMAX_DELAY); + ESP_LOGI(TAG, "Task[%p]: received event %d", xTaskGetCurrentTaskHandle(), event_val); + } +} +``` + +Potential problem can arise in such program because task and timer has no any mechanism to acknowledge the events transfer. Task needs some time to process an event before waiting for the next one. In this case call to `ESP_LOGI` will be the most time consuming part of event processing. Therefore when timer's ISR is called at some rate it can happen that `xTaskNotifyFromISR` gets called several times before task calls `xTaskNotifyWait`. In these conditions some events will be lost. Possible solution for this is to increase timer's tick period or to use some events acknowledgement mechanism. + +Check the full example code [sysview_tracing](main/sysview_tracing.c) that when compiled in dual core mode reproduces the described problem on both cores. Below is the output of example compiled in single core mode. It shows that task misses several events: + +``` +I (295) example: 0x3ffb6c10: run task +I (297) example: Task[0x3ffb6c10]: received event 1 +I (300) example: Task[0x3ffb6c10]: received event 2 +I (306) example: Task[0x3ffb6c10]: received event 5 +I (311) example: Task[0x3ffb6c10]: received event 8 +I (317) example: Task[0x3ffb6c10]: received event 10 +``` + + +## Detecting The Reason Of The Problem + +Besides built-in functionality to trace FreeRTOS internal operations SystemView also provides user with means to define its own trace messages and transfer problem-specific data to the host. In this example we extend SystemView with user-defined tracing module in order to +make the root cause of the problem more clear in the gathered trace. + +There are two ways to send user-defined info to SystemView: +1. Using built-in SystemView messages. This method uses `SEGGER_SYSVIEW_OnUserStart` and `SEGGER_SYSVIEW_OnUserStop` API to indicate that some user event started or stopped. Disadvantge of this way is that those API do not carry any other data except for user event ID. Advantage is that you do not need to write any additional code to use these functions. In SystemView messages sent by means of that API will be shown as `User Start` or `User Stop` with user event ID as only parameter: 0 - for timer and 1 - for task in this example. +2. Using custom SystemView messages. This is more flexible way. It implies extending SystemView with user module having its own set of events with any number of parameters (data) in each. For more details on extending see [code of this example](main/sysview_tracing.c) and [SystemView User Manual](https://www.segger.com/downloads/jlink/UM08027). + +To run the example and find out the reason of the problem: + +1. Connect JTAG interface to ESP32 board, power up both JTAG and ESP32. For details how to setup JTAG interface see [JTAG Debugging](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html). + +2. [Run OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#run-openocd). If you are using the [binary distribution of OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#jtag-debugging-setup-openocd) and one of versions of [ESP-WROVER-KIT](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html#esp-wrover-kit-v3), respective command line will look as follows: + + ``` + cd ~/esp/openocd-esp32 + bin/openocd -s share/openocd/scripts -f board/esp32-wrover-kit-3.3v.cfg + ``` +NOTE: In order to run this example you need OpenOCD version `v0.10.0-esp32-20181105` or later. + +3. Compile and load the example. Note to enable application tracing in menuconfig by going to `Component config > Application Level Tracing` and selecting `(X) Trace memory`. Also in order to generate SystemView trace data you need to enable this in `Component config > Application Level Tracing > FreeRTOS SystemView Tracing` by checking `(X) SystemView Tracing Enable`. Also ensure that all SystemView events are enabled there. + +4. If you are going to use custom events enable them by checking `Example Configuration > Use custom SystemView event IDs`. By default SystemView shows only numeric values of IDs and parameters for custom messages in `Events` view. To make them pretty-looking you need to define for them parsing templates in `SYSVIEW_FreeRTOS.txt` which is resided in SystemView installation directory. For this example you can use `SYSVIEW_FreeRTOS.txt` from the project's root directory. + +5. It is useful to use GDB to start and/or stop tracing automatically. To do this you need to prepare special `gdbinit` file: + + ``` + target remote :3333 + mon reset halt + b app_main + commands + mon esp sysview start file:///tmp/sysview_example.svdat + # For dual-core mode uncomment the line below and comment the line above + # mon esp sysview start file:///tmp/sysview_example0.svdat file:///tmp/sysview_example1.svdat + c + end + c + ``` + + Using this file GDB will connect to the target, reset it, and start tracing when it hit breakpoint at `app_main`. Trace data will be saved to `/tmp/sysview_example.svdat`. + +6. Run GDB using the following command from the project root directory: + + ``` + xtensa-esp32-elf-gdb -x gdbinit build/sysview_tracing.elf + ``` + + **Note:** Replace `xtensa-esp32-elf-gdb` with the related gdb tool (e.g. `xtensa-esp32s2-elf-gdb`, `xtensa-esp32s3-elf-gdb` or `riscv32-esp-elf-gdb`) if running the example on different chip. + +7. When program prints the last message, interrupt its execution (e.g. by pressing `CTRL+C`) and type the following command in GDB console to stop tracing: + + ``` + mon esp sysview stop + ``` + + You can also use another breakpoint to stop tracing and add respective lines to `gdbinit` at step 5. + +8. Open trace data file in SystemView tool. + +9. Right-click on any event in `Events` view and select: + + - `Show User Events only` if you compiled example to use only built-in event. + - `Show APIs only` if you compiled example to use custom events. + +10. Now you can navigate over user-defined messages and see when timer `TG1_T0_LEVEL` sends events (`SYSVIEW_EXAMPLE_SEND_EVENT_START/STOP` or `User Start/Stop(0)`) and when task `svtrace0` reads them (`SYSVIEW_EXAMPLE_WAIT_EVENT_START/STOP` or `User Start/Stop(1)`). + If you compiled example to use custom events you will also be able to see the values sent by timer and ones actually received by tasks. diff --git a/examples/ESP-IDF/tracing/gdbinit b/examples/ESP-IDF/tracing/gdbinit new file mode 100644 index 0000000..2ba09f8 --- /dev/null +++ b/examples/ESP-IDF/tracing/gdbinit @@ -0,0 +1,13 @@ +set pagination off +target remote :3333 + +mon reset halt +maintenance flush register-cache + +b app_main +commands +mon esp apptrace start "file:///tmp/tracealyzer_example.psf" 0 -1 -1 0 0 +c +end + +c diff --git a/examples/ESP-IDF/tracing/main/CMakeLists.txt b/examples/ESP-IDF/tracing/main/CMakeLists.txt new file mode 100644 index 0000000..aab6ceb --- /dev/null +++ b/examples/ESP-IDF/tracing/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "tracealyzer.c" + PRIV_REQUIRES esp_driver_gptimer app_trace + INCLUDE_DIRS ".") diff --git a/examples/ESP-IDF/tracing/main/idf_component.yml b/examples/ESP-IDF/tracing/main/idf_component.yml new file mode 100644 index 0000000..f3a2f88 --- /dev/null +++ b/examples/ESP-IDF/tracing/main/idf_component.yml @@ -0,0 +1,7 @@ +## IDF Component Manager Manifest File +dependencies: + ## Required IDF version + idf: + version: ">=4.2.0" + percepio/tracerecorder: + version: "*" diff --git a/examples/ESP-IDF/tracing/main/tracealyzer.c b/examples/ESP-IDF/tracing/main/tracealyzer.c new file mode 100644 index 0000000..33cc897 --- /dev/null +++ b/examples/ESP-IDF/tracing/main/tracealyzer.c @@ -0,0 +1,102 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Application Trace to Host Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include "sdkconfig.h" +#include +#include +#include +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gptimer.h" + +static const char *TAG = "example"; + +typedef struct { + gptimer_handle_t gptimer; + int count; + TaskHandle_t thnd; + uint64_t period; + char task_name[32]; +} example_event_data_t; + +static bool example_timer_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx) +{ + example_event_data_t *tim_arg = (example_event_data_t *)user_ctx; + bool need_yield = false; + + if (tim_arg->thnd != NULL) { + if (tim_arg->count++ < 10000) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + if (xTaskNotifyFromISR(tim_arg->thnd, tim_arg->count, eSetValueWithOverwrite, &xHigherPriorityTaskWoken) != pdPASS) { + ESP_EARLY_LOGE(TAG, "Failed to notify task %p", tim_arg->thnd); + } else { + if (xHigherPriorityTaskWoken == pdTRUE) { + need_yield = true; + } + } + } + } + return need_yield; +} + +static void example_task(void *p) +{ + uint32_t event_val; + example_event_data_t *arg = (example_event_data_t *) p; + ESP_LOGI(TAG, "%p: run task", xTaskGetCurrentTaskHandle()); + gptimer_alarm_config_t alarm_config = { + .reload_count = 0, + .alarm_count = arg->period, + .flags.auto_reload_on_alarm = true, + }; + // This task is pinned to a specific core, to the interrupt will also be install to that core + gptimer_event_callbacks_t cbs = { + .on_alarm = example_timer_alarm_cb, + }; + + traceString MyChannel = xTraceRegisterString(xPortGetCoreID() == 0 ? "DataCh0" : "DataCh1"); + + ESP_ERROR_CHECK(gptimer_register_event_callbacks(arg->gptimer, &cbs, arg)); + ESP_ERROR_CHECK(gptimer_set_alarm_action(arg->gptimer, &alarm_config)); + ESP_ERROR_CHECK(gptimer_enable(arg->gptimer)); + ESP_ERROR_CHECK(gptimer_start(arg->gptimer)); + while (1) { + xTaskNotifyWait(0, 0, &event_val, portMAX_DELAY); + ESP_LOGI(TAG, "Task[%p]: received event %"PRIu32, xTaskGetCurrentTaskHandle(), event_val); + vTracePrintF(MyChannel, "Sensor Data = %d", event_val); + } +} + +void app_main(void) +{ + static example_event_data_t event_data[CONFIG_FREERTOS_NUMBER_OF_CORES]; + + for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) { + gptimer_config_t timer_config = { + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = 1000000, + }; + ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &event_data[i].gptimer)); + event_data[i].period = 100000 * (i + 1); + } + + for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) { + sprintf(event_data->task_name, "trace%d", i); + xTaskCreatePinnedToCore(example_task, event_data->task_name, 4096, &event_data[i], 3, &event_data[i].thnd, i); + ESP_LOGI(TAG, "Created task %p", event_data[i].thnd); + } +} diff --git a/examples/ESP-IDF/tracing/sdkconfig.defaults b/examples/ESP-IDF/tracing/sdkconfig.defaults new file mode 100644 index 0000000..a3451e0 --- /dev/null +++ b/examples/ESP-IDF/tracing/sdkconfig.defaults @@ -0,0 +1,38 @@ +# Enable application tracing by default +CONFIG_APPTRACE_DEST_JTAG=y +CONFIG_APPTRACE_ENABLE=y + +# Enable Percepio TraceRecorder +CONFIG_PERCEPIO_RECORDER_TRC_RECORDER_MODE_STREAMING=y +CONFIG_PERCEPIO_TRACERECORDER_ENABLED=y +CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START_FROM_HOST=y +# CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START is not set +# CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START_AWAIT_HOST is not set +CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ESP_IDF_APPTRACE=y +# CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RINGBUFFER is not set +# CONFIG_PERCEPIO_RECORDER_CFG_TRAX_MODE_BLOCK_IF_FIFO_FULL is not set +CONFIG_PERCEPIO_RECORDER_CFG_TRAX_MODE_NO_BLOCK_SKIP=y +# CONFIG_PERCEPIO_RECORDER_CFG_SCHEDULING_ONLY is not set +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_MEMMANG_EVENTS=y +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_USER_EVENTS=y +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_ISR_TRACING=y +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_READY_EVENTS=y +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_OSTICK_EVENTS=y +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_EVENT_GROUP_EVENTS=y +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_TIMER_EVENTS=y +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS=y +CONFIG_PERCEPIO_RECORDER_CFG_INCLUDE_STREAM_BUFFER_EVENTS=y +CONFIG_PERCEPIO_RECORDER_CFG_ENABLE_STACK_MONITOR=y +CONFIG_PERCEPIO_RECORDER_CFG_STACK_MONITOR_MAX_TASKS=15 +CONFIG_PERCEPIO_RECORDER_CFG_STACK_MONITOR_MAX_REPORTS=1 +CONFIG_PERCEPIO_RECORDER_CFG_CTRL_TASK_PRIORITY=1 +CONFIG_PERCEPIO_RECORDER_CFG_CTRL_TASK_DELAY=10 +CONFIG_PERCEPIO_RECORDER_CFG_CTRL_TASK_STACK_SIZE=1024 +CONFIG_PERCEPIO_RECORDER_TRC_RECORDER_BUFFER_ALLOCATION_STATIC=y +# CONFIG_PERCEPIO_RECORDER_TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC is not set +# CONFIG_PERCEPIO_RECORDER_TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM is not set +CONFIG_PERCEPIO_RECORDER_CFG_MAX_ISR_NESTING=8 +CONFIG_PERCEPIO_RECORDER_TRC_CFG_ENTRY_TABLE_SLOTS=40 +CONFIG_PERCEPIO_RECORDER_TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH=25 +# CONFIG_PERCEPIO_RECORDER_TRC_STREAM_PORT_USE_INTERNAL_BUFFER is not set +CONFIG_PERCEPIO_RECORDER_TRC_CFG_ISR_TAILCHAINING_THRESHOLD_STREAMING=0 diff --git a/idf_component.yml b/idf_component.yml new file mode 100644 index 0000000..71e5c30 --- /dev/null +++ b/idf_component.yml @@ -0,0 +1,20 @@ +version: "4.10.3" +description: "This is a Percepio TraceRecorder component" +url: "https://github.com/percepio/TraceRecorderSource" +license: "Apache" + +files: + exclude: + # Exclude code for other RTOSes + - "kernelports/BareMetal/**/*" + - "kernelports/FreeRTOS/**/*" + - "kernelports/ThreadX/**/*" + - "kernelports/Zephyr/**/*" + # Exclude code for unsuported streamports + - "streamports/ARM_ITM/**/*" + - "streamports/File/**/*" + - "streamports/STM32_USB_CDC/**/*" + - "streamports/TCPIP/**/*" + - "streamports/TCPIP_Win32/**/*" + - "streamports/UDP/**/*" + - "streamports/XMOS_xScope/**/*" diff --git a/kernelports/ESP-IDF_FreeRTOS/CMakeLists.txt b/kernelports/ESP-IDF_FreeRTOS/CMakeLists.txt index 1f3c197..b096b90 100644 --- a/kernelports/ESP-IDF_FreeRTOS/CMakeLists.txt +++ b/kernelports/ESP-IDF_FreeRTOS/CMakeLists.txt @@ -1,31 +1,5 @@ -# Only add the source/header files if the Tracerecorder is enables. By doing -# this we avoid having a lot of conditional checks for configuration -# options in the configuration files that use parameters from the KConfig, -# parameters that are missing when the Tracerecorder is disabled. -if(CONFIG_PERCEPIO_TRACERECORDER_ENABLED) - if(CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RINGBUFFER) - set(src_dirs ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/../../streamports/RingBuffer" ${CMAKE_CURRENT_LIST_DIR}/../../) - set(inc_dirs "${CMAKE_CURRENT_LIST_DIR}/config" "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_CURRENT_LIST_DIR}/../../streamports/RingBuffer/include" "${CMAKE_CURRENT_LIST_DIR}/streamports/RingBuffer/config" ${CMAKE_CURRENT_LIST_DIR}/../../include) - endif() - if(CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RTT) - set(src_dirs ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/../../streamports/Jlink_RTT" ${CMAKE_CURRENT_LIST_DIR}/../../) - set(inc_dirs "${CMAKE_CURRENT_LIST_DIR}/config" "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_CURRENT_LIST_DIR}/../../streamports/Jlink_RTT/include" "${CMAKE_CURRENT_LIST_DIR}/streamports/Jlink_RTT/config" ${CMAKE_CURRENT_LIST_DIR}/../../include) - endif() - if(CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ESP_IDF_APPTRACE) - set(src_dirs ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/streamports/ESP_IDF_APPTRACE" ${CMAKE_CURRENT_LIST_DIR}/../../) - set(inc_dirs "${CMAKE_CURRENT_LIST_DIR}/config" "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_CURRENT_LIST_DIR}/streamports/ESP_IDF_APPTRACE/include" ${CMAKE_CURRENT_LIST_DIR}/../../include) - endif() -else() - set(src_dirs "") - set(inc_dirs "") -endif() -idf_component_register(SRC_DIRS "${src_dirs}" - INCLUDE_DIRS "${inc_dirs}" - LDFRAGMENTS "lifra.fr" - PRIV_REQUIRES - app_trace - ) +include(${CMAKE_CURRENT_LIST_DIR}/esp.cmake) # Since we inject Trace Recorder in the ESP-IDF we must expose the includes to ESP-IDF. if(CONFIG_PERCEPIO_TRACERECORDER_ENABLED) @@ -43,4 +17,4 @@ if(CONFIG_PERCEPIO_TRACERECORDER_ENABLED) if(CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ESP_IDF_APPTRACE) idf_build_set_property(INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/streamports/ESP_IDF_APPTRACE/include APPEND) endif() -endif() \ No newline at end of file +endif() diff --git a/kernelports/ESP-IDF_FreeRTOS/config/trcConfig.h b/kernelports/ESP-IDF_FreeRTOS/config/trcConfig.h index 2bead9e..3f808ae 100644 --- a/kernelports/ESP-IDF_FreeRTOS/config/trcConfig.h +++ b/kernelports/ESP-IDF_FreeRTOS/config/trcConfig.h @@ -323,6 +323,11 @@ extern "C" { #define TRC_CFG_CORE_COUNT 2 #endif +/** + * Force usage of GCC statement expressions. Avoid `-Werror=unused-value`. + */ +#define TRC_CFG_USE_GCC_STATEMENT_EXPR 1 + #ifdef __cplusplus } #endif diff --git a/kernelports/ESP-IDF_FreeRTOS/esp.cmake b/kernelports/ESP-IDF_FreeRTOS/esp.cmake new file mode 100644 index 0000000..62ad0ba --- /dev/null +++ b/kernelports/ESP-IDF_FreeRTOS/esp.cmake @@ -0,0 +1,28 @@ +# Only add the source/header files if the Tracerecorder is enables. By doing +# this we avoid having a lot of conditional checks for configuration +# options in the configuration files that use parameters from the KConfig, +# parameters that are missing when the Tracerecorder is disabled. +if(CONFIG_PERCEPIO_TRACERECORDER_ENABLED) + if(CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RINGBUFFER) + set(src_dirs ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/../../streamports/RingBuffer" ${CMAKE_CURRENT_LIST_DIR}/../../) + set(inc_dirs "${CMAKE_CURRENT_LIST_DIR}/config" "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_CURRENT_LIST_DIR}/../../streamports/RingBuffer/include" "${CMAKE_CURRENT_LIST_DIR}/streamports/RingBuffer/config" ${CMAKE_CURRENT_LIST_DIR}/../../include) + endif() + if(CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_RTT) + set(src_dirs ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/../../streamports/Jlink_RTT" ${CMAKE_CURRENT_LIST_DIR}/../../) + set(inc_dirs "${CMAKE_CURRENT_LIST_DIR}/config" "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_CURRENT_LIST_DIR}/../../streamports/Jlink_RTT/include" "${CMAKE_CURRENT_LIST_DIR}/streamports/Jlink_RTT/config" ${CMAKE_CURRENT_LIST_DIR}/../../include) + endif() + if(CONFIG_PERCEPIO_TRC_CFG_STREAM_PORT_ESP_IDF_APPTRACE) + set(src_dirs ${CMAKE_CURRENT_LIST_DIR} "${CMAKE_CURRENT_LIST_DIR}/streamports/ESP_IDF_APPTRACE" ${CMAKE_CURRENT_LIST_DIR}/../../) + set(inc_dirs "${CMAKE_CURRENT_LIST_DIR}/config" "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_CURRENT_LIST_DIR}/streamports/ESP_IDF_APPTRACE/include" ${CMAKE_CURRENT_LIST_DIR}/../../include) + endif() +else() + set(src_dirs "") + set(inc_dirs "") +endif() + +idf_component_register(SRC_DIRS "${src_dirs}" + INCLUDE_DIRS "${inc_dirs}" + LDFRAGMENTS "${CMAKE_CURRENT_LIST_DIR}/lifra.fr" + PRIV_REQUIRES + app_trace + ) diff --git a/kernelports/ESP-IDF_FreeRTOS/include/trcKernelPort.h b/kernelports/ESP-IDF_FreeRTOS/include/trcKernelPort.h index 62ea4f4..731d112 100644 --- a/kernelports/ESP-IDF_FreeRTOS/include/trcKernelPort.h +++ b/kernelports/ESP-IDF_FreeRTOS/include/trcKernelPort.h @@ -27,34 +27,21 @@ extern "C" { #endif /*** FreeRTOS version codes **************************************************/ -#define TRC_ESP_IDF_VERSION_NOT_SET 0 -#define TRC_ESP_IDF_VERSION_4_2_0 420 -#define TRC_ESP_IDF_VERSION_4_3_0 430 -#define TRC_ESP_IDF_VERSION_4_4_0 440 -#define TRC_ESP_IDF_VERSION_4_5_0 450 -#define TRC_ESP_IDF_VERSION_5_0_0 500 -#define TRC_ESP_IDF_VERSION_5_1_0 510 -#define TRC_ESP_IDF_VERSION_5_2_0 520 - -#if ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 0 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_4_0_0 -#elif ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 1 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_4_1_0 -#elif ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 2 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_4_2_0 -#elif ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 3 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_4_3_0 -#elif ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 4 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_4_4_0 -#elif ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 5 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_4_5_0 -#elif ESP_IDF_VERSION_MAJOR == 5 && ESP_IDF_VERSION_MINOR == 0 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_5_0_0 -#elif ESP_IDF_VERSION_MAJOR == 5 && ESP_IDF_VERSION_MINOR == 1 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_5_1_0 -#elif ESP_IDF_VERSION_MAJOR == 5 && ESP_IDF_VERSION_MINOR == 2 -#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_5_2_0 -#else +#define TRC_ESP_IDF_VERSION_MAKE(_maj_, _min_) ((_maj_)*100+(_min_)*10) +#define TRC_ESP_IDF_VERSION_NOT_SET TRC_ESP_IDF_VERSION_MAKE(0,0) +#define TRC_ESP_IDF_VERSION_4_2_0 TRC_ESP_IDF_VERSION_MAKE(4,2) +#define TRC_ESP_IDF_VERSION_4_3_0 TRC_ESP_IDF_VERSION_MAKE(4,3) +#define TRC_ESP_IDF_VERSION_4_4_0 TRC_ESP_IDF_VERSION_MAKE(4,4) +#define TRC_ESP_IDF_VERSION_4_5_0 TRC_ESP_IDF_VERSION_MAKE(4,5) +#define TRC_ESP_IDF_VERSION_5_0_0 TRC_ESP_IDF_VERSION_MAKE(5,0) +#define TRC_ESP_IDF_VERSION_5_1_0 TRC_ESP_IDF_VERSION_MAKE(5,1) +#define TRC_ESP_IDF_VERSION_5_2_0 TRC_ESP_IDF_VERSION_MAKE(5,2) + +#define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_MAKE(ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR) + +/* Sanity check that current IDF version is supported. */ +#if TRC_CFG_ESP_IDF_VERSION < TRC_ESP_IDF_VERSION_MAKE(4, 0) || \ + TRC_CFG_ESP_IDF_VERSION > TRC_ESP_IDF_VERSION_MAKE(5, 5) #define TRC_CFG_ESP_IDF_VERSION TRC_ESP_IDF_VERSION_NOT_SET #endif @@ -64,6 +51,12 @@ extern "C" { #define prvGetStreamBufferType(x) 0 #endif +#if (TRC_CFG_ESP_IDF_VERSION < TRC_ESP_IDF_VERSION_MAKE(5,3)) +#define TRC_KERNEL_PORT_SYSTEM_INIT_FN(f, c, priority) ESP_SYSTEM_INIT_FN(f, c, priority) +#else +#define TRC_KERNEL_PORT_SYSTEM_INIT_FN(f, c, priority) ESP_SYSTEM_INIT_FN(f, SECONDARY, c, priority) +#endif + #define STRING_CAST(x) x #define TraceKernelPortTickType_t TickType_t #define TraceKernelPortTaskHandle_t TaskHandle_t @@ -73,6 +66,10 @@ extern "C" { #define TRC_CFG_GET_CURRENT_CORE() (xPortGetCoreID()) #endif +#if !CONFIG_FREERTOS_SMP +#define pxCurrentTCB pxCurrentTCBs +#endif + #if !CONFIG_FREERTOS_UNICORE extern portMUX_TYPE xTraceMutex; diff --git a/kernelports/ESP-IDF_FreeRTOS/lifra.fr b/kernelports/ESP-IDF_FreeRTOS/lifra.fr index 2e1a0b6..7b3821f 100644 --- a/kernelports/ESP-IDF_FreeRTOS/lifra.fr +++ b/kernelports/ESP-IDF_FreeRTOS/lifra.fr @@ -1,4 +1,4 @@ -[mapping:TraceRecorder] -archive: libESP-IDF_FreeRTOS.a +[mapping:percepio_tracerecorder] +archive: libpercepio_tracerecorder.a entries: * (noflash) \ No newline at end of file diff --git a/kernelports/ESP-IDF_FreeRTOS/trcKernelPort.c b/kernelports/ESP-IDF_FreeRTOS/trcKernelPort.c index a946a7c..781c955 100644 --- a/kernelports/ESP-IDF_FreeRTOS/trcKernelPort.c +++ b/kernelports/ESP-IDF_FreeRTOS/trcKernelPort.c @@ -333,12 +333,12 @@ esp_err_t xTraceEspKernelPortEnable() #include -ESP_SYSTEM_INIT_FN(xTraceEspKernelPortInitialize, ESP_SYSTEM_INIT_ALL_CORES, 102) +TRC_KERNEL_PORT_SYSTEM_INIT_FN(xTraceEspKernelPortInitialize, ESP_SYSTEM_INIT_ALL_CORES, 102) { return xTraceEspKernelPortInitialize(); } -ESP_SYSTEM_INIT_FN(xTraceEspKernelPortEnable, ESP_SYSTEM_INIT_ALL_CORES, 240) +TRC_KERNEL_PORT_SYSTEM_INIT_FN(xTraceEspKernelPortEnable, ESP_SYSTEM_INIT_ALL_CORES, 240) { return xTraceEspKernelPortEnable(); }