mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
Merge branch 'tracing_test_fixes_v6.1' into 'release/v6.1'
Tracing test fixes (v6.1) See merge request espressif/esp-idf!52327
This commit is contained in:
@@ -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.22)
|
||||
|
||||
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 ON)
|
||||
project(sysview_tracing)
|
||||
@@ -0,0 +1,146 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | --------- |
|
||||
# Example: Application Level Tracing - SystemView Tracing (sysview_tracing)
|
||||
|
||||
This test code shows how to perform system-wide behavioral analysis of the program using [SEGGER SystemView 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/tracing/sysview.html) 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-dev-kits/en/latest/esp32/esp-wrover-kit/index.html), 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_mcore start file:///tmp/sysview_example.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`. The `esp sysview_mcore` command uses the SEGGER SystemView multi-core format, so a single file holds the trace for both single- and dual-core targets.
|
||||
|
||||
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_mcore 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. The multi-core format produced by `esp sysview_mcore` requires SEGGER SystemView v3.60 or later.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,108 @@
|
||||
128 vTaskAllocateMPURegions xTask=%t pxRegions=%u
|
||||
33 vTaskDelete xTaskToDelete=%t
|
||||
34 vTaskDelay xTicksToDelay=%u
|
||||
35 vTaskDelayUntil
|
||||
129 uxTaskPriorityGet xTask=%t
|
||||
56 uxTaskPriorityGetFromISR xTask=%t
|
||||
130 eTaskGetState xTask=%t
|
||||
55 vTaskPrioritySet xTask=%t uxNewPriority=%u
|
||||
36 vTaskSuspend xTaskToSuspend=%t
|
||||
40 vTaskResume xTaskToResume=%t
|
||||
43 xTaskResumeFromISR xTaskToResume=%t
|
||||
131 vTaskStartScheduler
|
||||
132 vTaskEndScheduler
|
||||
133 vTaskSuspendAll
|
||||
134 xTaskResumeAll
|
||||
135 xTaskGetTickCount
|
||||
57 xTaskGetTickCountFromISR
|
||||
136 uxTaskGetNumberOfTasks
|
||||
137 pcTaskGetName xTaskToQuery=%t
|
||||
138 uxTaskGetStackHighWaterMark xTask=%t
|
||||
139 vTaskSetApplicationTaskTag xTask=%t pxHookFunction=%u
|
||||
140 xTaskGetApplicationTaskTag xTask=%t
|
||||
141 vTaskSetThreadLocalStoragePointer xTaskToSet=%T xIndex=%u pvValue=%u
|
||||
142 pvTaskGetThreadLocalStoragePointer xTaskToQuery=%T xIndex=%u
|
||||
143 xTaskCallApplicationTaskHook xTask=%T pvParameter=%u
|
||||
144 xTaskGetIdleTaskHandle
|
||||
145 uxTaskGetSystemState pxTaskStatusArray=%u uxArraySize=%u pulTotalRunTime=%u
|
||||
146 vTaskList pcWriteBuffer=%u
|
||||
147 vTaskGetRunTimeStats pcWriteBuffer=%u
|
||||
44 xTaskGenericNotify xTaskToNotify=%t ulValue=%u eAction=%u pulPreviousNotificationValue=%u
|
||||
45 xTaskGenericNotifyFromISR xTaskToNotify=%t ulValue=%u eAction=%u pulPreviousNotificationValue=%u pxHigherPriorityTaskWoken=%u
|
||||
46 xTaskNotifyWait ulBitsToClearOnEntry=%u ulBitsToClearOnExit=%u pulNotificationValue=%u xTicksToWait=%u
|
||||
38 vTaskNotifyGiveFromISR xTaskToNotify=%t pxHigherPriorityTaskWoken=%u
|
||||
37 ulTaskNotifyTake xClearCountOnExit=%u xTicksToWait=%u
|
||||
148 xTaskNotifyStateClear xTask=%t
|
||||
149 xTaskGetCurrentTaskHandle
|
||||
150 vTaskSetTimeOutState pxTimeOut=%u
|
||||
151 xTaskCheckForTimeOut pxTimeOut=%u pxTicksToWait=%u
|
||||
152 vTaskMissedYield
|
||||
153 xTaskGetSchedulerState
|
||||
39 vTaskPriorityInherit pxMutexHolder=%p
|
||||
42 xTaskPriorityDisinherit pxMutexHolder=%p
|
||||
154 xTaskGenericCreate pxTaskCode=%u pcName=%u usStackDepth=%u pvParameters=%u uxPriority=%u pxCreatedTask=%u puxStackBuffer=%u xRegions=%u
|
||||
155 uxTaskGetTaskNumber xTask=%u
|
||||
156 vTaskSetTaskNumber xTask=%u uxHandle=%u
|
||||
41 vTaskStepTick xTicksToJump=%u
|
||||
157 eTaskConfirmSleepModeStatus
|
||||
158 xTimerCreate pcTimerName=%u xTimerPeriodInTicks=%u uxAutoReload=%u pvTimerID=%u pxCallbackFunction=%u
|
||||
159 pvTimerGetTimerID xTimer=%u
|
||||
160 vTimerSetTimerID xTimer=%u pvNewID=%u
|
||||
161 xTimerIsTimerActive xTimer=%u
|
||||
162 xTimerGetTimerDaemonTaskHandle
|
||||
163 xTimerPendFunctionCallFromISR xFunctionToPend=%u pvParameter1=%u ulParameter2=%u pxHigherPriorityTaskWoken=%u
|
||||
164 xTimerPendFunctionCall xFunctionToPend=%u pvParameter1=%u ulParameter2=%u xTicksToWait=%u
|
||||
165 pcTimerGetName xTimer=%u
|
||||
166 xTimerCreateTimerTask
|
||||
167 xTimerGenericCommand xTimer=%u xCommandID=%u xOptionalValue=%u pxHigherPriorityTaskWoken=%u xTicksToWait=%u
|
||||
53 xQueueGenericSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u xCopyPosition=%u
|
||||
50 xQueuePeekFromISR xQueue=%I pvBuffer=%p
|
||||
49 xQueueGenericReceive xQueue=%I pvBuffer=%p xTicksToWait=%u xJustPeek=%u
|
||||
168 uxQueueMessagesWaiting xQueue=%I
|
||||
169 uxQueueSpacesAvailable xQueue=%I
|
||||
48 vQueueDelete xQueue=%I
|
||||
54 xQueueGenericSendFromISR xQueue=%I pvItemToQueue=%p pxHigherPriorityTaskWoken=%u xCopyPosition=%u
|
||||
61 xQueueGiveFromISR xQueue=%I pxHigherPriorityTaskWoken=%u
|
||||
51 xQueueReceiveFromISR xQueue=%I pvBuffer=%p pxHigherPriorityTaskWoken=%u
|
||||
62 xQueueIsQueueEmptyFromISR xQueue=%I
|
||||
63 xQueueIsQueueFullFromISR xQueue=%I
|
||||
170 uxQueueMessagesWaitingFromISR xQueue=%I
|
||||
171 xQueueAltGenericSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u xCopyPosition=%u
|
||||
172 xQueueAltGenericReceive xQueue=%I pvBuffer=%p xTicksToWait=%u xJustPeeking=%u
|
||||
173 xQueueCRSendFromISR xQueue=%I pvItemToQueue=%p xCoRoutinePreviouslyWoken=%u
|
||||
174 xQueueCRReceiveFromISR xQueue=%I pvBuffer=%p pxTaskWoken=%u
|
||||
175 xQueueCRSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u
|
||||
176 xQueueCRReceive xQueue=%I pvBuffer=%p xTicksToWait=%u
|
||||
177 xQueueCreateMutex ucQueueType=%u
|
||||
178 xQueueCreateCountingSemaphore uxMaxCount=%u uxInitialCount=%u
|
||||
179 xQueueGetMutexHolder xSemaphore=%u
|
||||
180 xQueueTakeMutexRecursive xMutex=%u xTicksToWait=%u
|
||||
181 xQueueGiveMutexRecursive pxMutex=%u
|
||||
52 vQueueAddToRegistry xQueue=%I pcName=%u
|
||||
182 vQueueUnregisterQueue xQueue=%I
|
||||
47 xQueueGenericCreate uxQueueLength=%u uxItemSize=%u ucQueueType=%u
|
||||
183 xQueueCreateSet uxEventQueueLength=%u
|
||||
184 xQueueAddToSet xQueueOrSemaphore=%u xQueueSet=%u
|
||||
185 xQueueRemoveFromSet xQueueOrSemaphore=%u xQueueSet=%u
|
||||
186 xQueueSelectFromSet xQueueSet=%u xTicksToWait=%u
|
||||
187 xQueueSelectFromSetFromISR xQueueSet=%u
|
||||
188 xQueueGenericReset xQueue=%I xNewQueue=%u
|
||||
189 vListInitialise pxList=%u
|
||||
190 vListInitialiseItem pxItem=%u
|
||||
191 vListInsert pxList=%u pxNewListItem=%u
|
||||
192 vListInsertEnd pxList=%u pxNewListItem=%u
|
||||
193 uxListRemove pxItemToRemove=%u
|
||||
194 xEventGroupCreate
|
||||
195 xEventGroupWaitBits xEventGroup=%u uxBitsToWaitFor=%u xClearOnExit=%u xWaitForAllBits=%u xTicksToWait=%u
|
||||
196 xEventGroupClearBits xEventGroup=%u uxBitsToClear=%u
|
||||
58 xEventGroupClearBitsFromISR xEventGroup=%u uxBitsToSet=%u
|
||||
197 xEventGroupSetBits xEventGroup=%u uxBitsToSet=%u
|
||||
59 xEventGroupSetBitsFromISR xEventGroup=%u uxBitsToSet=%u pxHigherPriorityTaskWoken=%u
|
||||
198 xEventGroupSync xEventGroup=%u uxBitsToSet=%u uxBitsToWaitFor=%u xTicksToWait=%u
|
||||
60 xEventGroupGetBitsFromISR xEventGroup=%u
|
||||
199 vEventGroupDelete xEventGroup=%u
|
||||
200 uxEventGroupGetNumber xEventGroup=%u
|
||||
512 SYSVIEW_EXAMPLE_SEND_EVENT_START
|
||||
513 SYSVIEW_EXAMPLE_SEND_EVENT_END evt_val=%u
|
||||
514 SYSVIEW_EXAMPLE_WAIT_EVENT_START
|
||||
515 SYSVIEW_EXAMPLE_WAIT_EVENT_END evt_val=%u
|
||||
@@ -0,0 +1,13 @@
|
||||
set pagination off
|
||||
target remote :3333
|
||||
|
||||
mon reset halt
|
||||
maintenance flush register-cache
|
||||
|
||||
b app_main
|
||||
commands
|
||||
mon esp sysview_mcore start file:///tmp/sysview_example.svdat
|
||||
c
|
||||
end
|
||||
|
||||
c
|
||||
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "sysview_tracing.c"
|
||||
PRIV_REQUIRES esp_driver_gptimer
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,12 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config USE_CUSTOM_EVENT_ID
|
||||
bool "Use custom SystemView event IDs"
|
||||
default "n"
|
||||
help
|
||||
Use custom IDs for user events. If it is enabled, replace `SYSVIEW_FreeRTOS.txt` in SystemView
|
||||
installation directory with the version from example's root directory.
|
||||
|
||||
By default SYSVIEW_EVTID_MARK_START/STOP are used for tracing purposes of the example.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,7 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf:
|
||||
version: '>=6.0'
|
||||
# # Put list of dependencies here
|
||||
espressif/esp_sysview: ^1
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_trace.h"
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
#if !CONFIG_USE_CUSTOM_EVENT_ID
|
||||
|
||||
#define SYSVIEW_EXAMPLE_SEND_EVENT_ID 0
|
||||
#define SYSVIEW_EXAMPLE_WAIT_EVENT_ID 1
|
||||
|
||||
#define SYSVIEW_EXAMPLE_SEND_EVENT_START() SEGGER_SYSVIEW_OnUserStart(SYSVIEW_EXAMPLE_SEND_EVENT_ID)
|
||||
#define SYSVIEW_EXAMPLE_SEND_EVENT_END(_val_) SEGGER_SYSVIEW_OnUserStop(SYSVIEW_EXAMPLE_SEND_EVENT_ID)
|
||||
#define SYSVIEW_EXAMPLE_WAIT_EVENT_START() SEGGER_SYSVIEW_OnUserStart(SYSVIEW_EXAMPLE_WAIT_EVENT_ID)
|
||||
#define SYSVIEW_EXAMPLE_WAIT_EVENT_END(_val_) SEGGER_SYSVIEW_OnUserStop(SYSVIEW_EXAMPLE_WAIT_EVENT_ID)
|
||||
|
||||
#else
|
||||
|
||||
#define SYSVIEW_EXAMPLE_SEND_EVENT_START_ID 0
|
||||
#define SYSVIEW_EXAMPLE_SEND_EVENT_END_ID 1
|
||||
#define SYSVIEW_EXAMPLE_WAIT_EVENT_START_ID 2
|
||||
#define SYSVIEW_EXAMPLE_WAIT_EVENT_END_ID 3
|
||||
#define SYSVIEW_EXAMPLE_EVENT_MAX 4
|
||||
|
||||
#define SYSVIEW_EXAMPLE_SEND_EVENT_START() example_sysview_event_send(SYSVIEW_EXAMPLE_SEND_EVENT_START_ID, 0)
|
||||
#define SYSVIEW_EXAMPLE_SEND_EVENT_END(_val_) example_sysview_event_send(SYSVIEW_EXAMPLE_SEND_EVENT_END_ID, _val_)
|
||||
#define SYSVIEW_EXAMPLE_WAIT_EVENT_START() example_sysview_event_send(SYSVIEW_EXAMPLE_WAIT_EVENT_START_ID, 0)
|
||||
#define SYSVIEW_EXAMPLE_WAIT_EVENT_END(_val_) example_sysview_event_send(SYSVIEW_EXAMPLE_WAIT_EVENT_END_ID, _val_)
|
||||
|
||||
static SEGGER_SYSVIEW_MODULE s_example_sysview_module = {
|
||||
.sModule = "M=Example SystemView User Module",
|
||||
.NumEvents = SYSVIEW_EXAMPLE_EVENT_MAX,
|
||||
};
|
||||
|
||||
static void example_sysview_event_send(uint32_t id, uint32_t val)
|
||||
{
|
||||
U8 aPacket[SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32];
|
||||
|
||||
U8 *pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, val); // Add the parameter to the packet
|
||||
SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_example_sysview_module.EventOffset + id);
|
||||
}
|
||||
|
||||
#endif // !CONFIG_USE_CUSTOM_EVENT_ID
|
||||
|
||||
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++ < 10) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
SYSVIEW_EXAMPLE_SEND_EVENT_START();
|
||||
if (xTaskNotifyFromISR(tim_arg->thnd, tim_arg->count, eSetValueWithOverwrite, &xHigherPriorityTaskWoken) != pdPASS) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to notify task %p", tim_arg->thnd);
|
||||
} else {
|
||||
SYSVIEW_EXAMPLE_SEND_EVENT_END(tim_arg->count);
|
||||
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,
|
||||
};
|
||||
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) {
|
||||
SYSVIEW_EXAMPLE_WAIT_EVENT_START();
|
||||
xTaskNotifyWait(0, 0, &event_val, portMAX_DELAY);
|
||||
SYSVIEW_EXAMPLE_WAIT_EVENT_END(event_val);
|
||||
ESP_LOGI(TAG, "Task[%p]: received event %"PRIu32, xTaskGetCurrentTaskHandle(), event_val);
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_TRACE_TRANSPORT_APPTRACE
|
||||
#include "soc/uart_pins.h"
|
||||
#include "esp_app_trace.h"
|
||||
esp_trace_open_params_t esp_trace_get_user_params(void)
|
||||
{
|
||||
static esp_apptrace_config_t app_trace_config = APPTRACE_CONFIG_DEFAULT();
|
||||
#if CONFIG_APPTRACE_DEST_UART
|
||||
/* Override default values to use console pins as a uart channel */
|
||||
app_trace_config.dest_cfg.uart.tx_pin_num = U0TXD_GPIO_NUM;
|
||||
app_trace_config.dest_cfg.uart.rx_pin_num = U0RXD_GPIO_NUM;
|
||||
#endif
|
||||
|
||||
esp_trace_open_params_t trace_params = {
|
||||
.core_cfg = NULL,
|
||||
.encoder_name = "sysview",
|
||||
.encoder_cfg = NULL,
|
||||
.transport_name = "apptrace",
|
||||
.transport_cfg = &app_trace_config,
|
||||
};
|
||||
return trace_params;
|
||||
}
|
||||
#elif CONFIG_ESP_TRACE_TRANSPORT_USB_SERIAL_JTAG
|
||||
esp_trace_open_params_t esp_trace_get_user_params(void)
|
||||
{
|
||||
esp_trace_open_params_t trace_params = {
|
||||
.core_cfg = NULL,
|
||||
.encoder_name = "sysview",
|
||||
.encoder_cfg = NULL,
|
||||
.transport_name = "usb_serial_jtag",
|
||||
.transport_cfg = NULL,
|
||||
};
|
||||
return trace_params;
|
||||
}
|
||||
#endif
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Hello from sysview_tracing example!");
|
||||
|
||||
static example_event_data_t event_data[CONFIG_FREERTOS_NUMBER_OF_CORES];
|
||||
|
||||
#if CONFIG_USE_CUSTOM_EVENT_ID
|
||||
// Currently OpenOCD does not support requesting module info from target. So do the following...
|
||||
// Wait until SystemView module receives START command from host,
|
||||
// after that data can be sent to the host using onboard API,
|
||||
// so user module description does not need to be requested by OpenOCD itself.
|
||||
while (!SEGGER_SYSVIEW_Started()) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
SEGGER_SYSVIEW_RegisterModule(&s_example_sysview_module);
|
||||
#endif
|
||||
|
||||
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 = 1000000 * (i + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) {
|
||||
sprintf(event_data->task_name, "svtrace%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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import os.path
|
||||
import re
|
||||
import time
|
||||
import typing
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
import serial
|
||||
from pytest_embedded_idf import IdfDut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
from pytest_embedded_idf.utils import soc_filtered_targets
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from conftest import OpenOCD
|
||||
|
||||
|
||||
STOP_EVENT_ID = 0x0B # SYSVIEW_EVTID_TRACE_STOP
|
||||
|
||||
|
||||
def _assert_has_stop_record(segment: bytes, label: str) -> None:
|
||||
"""Assert a SysView data segment ends with a TRACE_STOP record.
|
||||
|
||||
A STOP record is the STOP event ID followed by a variable-length timestamp
|
||||
delta. Walk back over the trailing continuation bytes (0x80 bit set) to find
|
||||
the event ID, since its offset is not fixed.
|
||||
"""
|
||||
size = len(segment)
|
||||
assert size >= 2, f'{label}: segment too small to contain STOP record'
|
||||
i = size - 2
|
||||
while i >= 0 and (segment[i] & 0x80):
|
||||
i -= 1
|
||||
assert i >= 0 and segment[i] == STOP_EVENT_ID, f'{label}: does not end with a TRACE_STOP record'
|
||||
|
||||
|
||||
def _split_mcore_file(content: bytes) -> list[bytes]:
|
||||
"""Split an ``esp sysview_mcore`` combined file into per-core data segments.
|
||||
|
||||
Layout is an ASCII comment header followed by core0 data then core1 data::
|
||||
|
||||
; ...
|
||||
; Offset Core0 0
|
||||
; Offset Core1 <size of core0 data in bytes>
|
||||
;
|
||||
<core0 data><core1 data>
|
||||
|
||||
The header ends at the first line that does not start with ';', (the data
|
||||
begins with the all-zero sync sequence).
|
||||
"""
|
||||
header = re.match(rb'(?:;[^\n]*\n)*', content)
|
||||
assert header is not None
|
||||
pos = header.end()
|
||||
m = re.search(rb';\s*Offset\s+Core1\s+(\d+)', content[:pos])
|
||||
assert m is not None, 'mcore file header missing "Offset Core1"'
|
||||
offset_core1 = int(m.group(1))
|
||||
core0 = content[pos : pos + offset_core1]
|
||||
core1 = content[pos + offset_core1 :]
|
||||
return [core0, core1]
|
||||
|
||||
|
||||
def _validate_trace_data(trace_log: str, target: str, dual_core: bool = False, is_uart: bool = False) -> None:
|
||||
"""Validate SysView trace data in a single trace log file.
|
||||
|
||||
Args:
|
||||
trace_log: Path to the trace log file
|
||||
target: Target chip name (e.g., 'esp32', 'esp32s3')
|
||||
dual_core: If True, this is an 'esp sysview_mcore' combined file that
|
||||
embeds core0 and core1 data segments (see '_split_mcore_file');
|
||||
each segment is validated separately.
|
||||
is_uart: If True, also validate STOP record at end of file
|
||||
"""
|
||||
with open(trace_log, 'rb') as f:
|
||||
content = f.read()
|
||||
|
||||
for idx in range(2 if dual_core else 1):
|
||||
search_str = f'N=FreeRTOS Application,D={target},C=core{idx},O=FreeRTOS'.encode()
|
||||
assert search_str in content, f'SysView core{idx} trace data not found in {trace_log}'
|
||||
|
||||
if dual_core:
|
||||
# Seek to each core's segment via the header offset
|
||||
# and require each to end with its own TRACE_STOP record.
|
||||
for idx, segment in enumerate(_split_mcore_file(content)):
|
||||
_assert_has_stop_record(segment, f'core{idx}')
|
||||
else:
|
||||
_assert_has_stop_record(content, 'trace')
|
||||
|
||||
|
||||
def _capture_sysview_trace(ser: serial.Serial, trace_log_path: str) -> None:
|
||||
"""Capture SysView trace data from serial port.
|
||||
|
||||
Args:
|
||||
ser: Serial port instance
|
||||
trace_log_path: Path to save the trace log
|
||||
"""
|
||||
START_CMD = b'\x01'
|
||||
STOP_CMD = b'\x02'
|
||||
STOP_EVENT_ID = 0x0B # SYSVIEW_EVTID_TRACE_STOP
|
||||
|
||||
ser.reset_input_buffer()
|
||||
# Send Start command to start SysView tracing
|
||||
ser.write(START_CMD)
|
||||
|
||||
data = bytearray()
|
||||
|
||||
# Capture for 3 seconds
|
||||
end_time = time.time() + 3.0
|
||||
while time.time() < end_time:
|
||||
try:
|
||||
if ser.in_waiting:
|
||||
data += ser.read(ser.in_waiting)
|
||||
except serial.SerialTimeoutException:
|
||||
assert False, 'Timeout reached while reading from serial port, exiting...'
|
||||
|
||||
# Give pending trace data a short window to reach the host before requesting STOP.
|
||||
time.sleep(0.2)
|
||||
|
||||
# Send Stop command
|
||||
ser.write(STOP_CMD)
|
||||
|
||||
# Capture the final data produced by STOP and the transport flush.
|
||||
end_time = time.time() + 3.0
|
||||
last_data_time = time.time()
|
||||
while time.time() < end_time and (time.time() - last_data_time) <= 1.0:
|
||||
try:
|
||||
if ser.in_waiting:
|
||||
data += ser.read(ser.in_waiting)
|
||||
last_data_time = time.time()
|
||||
except serial.SerialTimeoutException:
|
||||
assert False, 'Timeout reached while reading from serial port, exiting...'
|
||||
|
||||
# Drop anything after the TRACE_STOP record (e.g. the ROM boot banner printed
|
||||
# on the shared UART when pytest-embedded resets the DUT after the test).
|
||||
stop_pos = data.rfind(STOP_EVENT_ID)
|
||||
if stop_pos != -1:
|
||||
end = stop_pos + 1
|
||||
# Consume the timestamp delta: continuation bytes have the 0x80 bit set,
|
||||
# terminated by a single byte with 0x80 clear.
|
||||
while end < len(data) and (data[end] & 0x80):
|
||||
end += 1
|
||||
if end < len(data):
|
||||
end += 1
|
||||
data = data[:end]
|
||||
|
||||
with open(trace_log_path, 'w+b') as f:
|
||||
f.write(data)
|
||||
|
||||
|
||||
def _test_sysview_tracing_jtag(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
|
||||
# Single multi-core capture file (esp sysview_mcore): one file is enough for
|
||||
# both single- and dual-core targets.
|
||||
trace_log = os.path.join(dut.logdir, 'sys_log.svdat') # pylint: disable=protected-access
|
||||
dual_core = not dut.app.sdkconfig.get('ESP_SYSTEM_SINGLE_CORE_MODE') or dut.target == 'esp32s3'
|
||||
|
||||
# Prepare gdbinit file pointing at this run's capture file
|
||||
gdb_logfile = os.path.join(dut.logdir, 'gdb.txt')
|
||||
gdbinit_orig = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'gdbinit')
|
||||
gdbinit = os.path.join(dut.logdir, 'gdbinit')
|
||||
with open(gdbinit_orig) as f_r, open(gdbinit, 'w') as f_w:
|
||||
for line in f_r:
|
||||
if line.startswith('mon esp sysview_mcore start'):
|
||||
f_w.write(f'mon esp sysview_mcore start file://{trace_log}\n')
|
||||
else:
|
||||
f_w.write(line)
|
||||
|
||||
def dut_expect_task_event() -> None:
|
||||
dut.expect(re.compile(rb'example: Task\[0x[0-9A-Fa-f]+\]: received event \d+'), timeout=30)
|
||||
|
||||
time.sleep(1) # Wait for the USJ port to be ready
|
||||
dut.expect_exact('example: Hello from sysview_tracing example!', timeout=5)
|
||||
with (
|
||||
openocd_dut.run() as openocd,
|
||||
open(gdb_logfile, 'w') as gdb_log,
|
||||
pexpect.spawn(
|
||||
f'idf.py -B {dut.app.binary_path} gdb --batch -x {gdbinit}',
|
||||
timeout=60,
|
||||
logfile=gdb_log,
|
||||
encoding='utf-8',
|
||||
codec_errors='ignore',
|
||||
) as p,
|
||||
):
|
||||
p.expect_exact('hit Breakpoint 1, app_main ()')
|
||||
dut.expect('example: Created task') # dut has been restarted by gdb since the last dut.expect()
|
||||
dut_expect_task_event()
|
||||
|
||||
# Capture sysview samples and keep reading telnet so OpenOCD's blocking log writes don't stall its
|
||||
# main loop and leave the 'stop' below unserviced.
|
||||
openocd.consume_output(3)
|
||||
openocd.write('esp sysview_mcore stop')
|
||||
openocd.apptrace_wait_stop()
|
||||
|
||||
_validate_trace_data(trace_log, dut.target, dual_core=dual_core)
|
||||
|
||||
|
||||
@pytest.mark.jtag
|
||||
@idf_parametrize('config', ['sysview_jtag'], indirect=['config'])
|
||||
@idf_parametrize('target', ['esp32', 'esp32c2', 'esp32s2'], indirect=['target'])
|
||||
def test_sysview_tracing_jtag(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
|
||||
_test_sysview_tracing_jtag(openocd_dut, dut)
|
||||
|
||||
|
||||
@pytest.mark.usb_serial_jtag
|
||||
@idf_parametrize('config', ['sysview_jtag'], indirect=['config'])
|
||||
@idf_parametrize(
|
||||
'target',
|
||||
soc_filtered_targets('SOC_USB_SERIAL_JTAG_SUPPORTED == 1'),
|
||||
indirect=['target'],
|
||||
)
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='lack of runner # TODO: IDFCI-10703')
|
||||
@idf_parametrize('port', ['/dev/serial_ports/ttyUSB-esp32'], indirect=['port'])
|
||||
def test_sysview_tracing_usj(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
|
||||
_test_sysview_tracing_jtag(openocd_dut, dut)
|
||||
|
||||
|
||||
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=3) as ser:
|
||||
trace_log = os.path.join(dut.logdir, 'sys_log_uart.svdat') # pylint: disable=protected-access
|
||||
_capture_sysview_trace(ser, trace_log)
|
||||
_validate_trace_data(trace_log, dut.target, is_uart=True)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('config', ['sysview_uart'], indirect=['config'])
|
||||
@idf_parametrize('target', ['supported_targets'], indirect=['target'])
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='lack of runner # TODO: IDFCI-10703')
|
||||
def test_sysview_tracing_uart(dut: IdfDut) -> None:
|
||||
_test_sysview_tracing_uart(dut)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.xtal_26mhz
|
||||
@idf_parametrize('config', ['sysview_uart_esp32c2_26Mhz'], indirect=['config'])
|
||||
@idf_parametrize('target', ['esp32c2'], indirect=['target'])
|
||||
def test_sysview_tracing_uart_c2(dut: IdfDut) -> None:
|
||||
_test_sysview_tracing_uart(dut)
|
||||
|
||||
|
||||
@pytest.mark.usb_serial_jtag
|
||||
@idf_parametrize('target', soc_filtered_targets('SOC_USB_SERIAL_JTAG_SUPPORTED == 1'), indirect=['target'])
|
||||
@pytest.mark.parametrize('config', [pytest.param('sysview_usj')], indirect=True)
|
||||
@idf_parametrize('port', ['/dev/serial_ports/ttyUSB-esp32'], indirect=['port'])
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='lack of runner # TODO: IDFCI-10703')
|
||||
def test_sysview_tracing_usj_serial(dut: IdfDut) -> None:
|
||||
time.sleep(1) # wait for USJ port to be ready
|
||||
usj_port = '/dev/serial_ports/ttyACM-esp32'
|
||||
trace_log = os.path.join(dut.logdir, 'sys_log_usj.svdat') # pylint: disable=protected-access
|
||||
with serial.Serial(usj_port, baudrate=1000000, timeout=10) as ser:
|
||||
_capture_sysview_trace(ser, trace_log)
|
||||
_validate_trace_data(trace_log, dut.target, is_uart=True)
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_ESP_TRACE_TRANSPORT_APPTRACE=y
|
||||
CONFIG_APPTRACE_DEST_JTAG=y
|
||||
@@ -0,0 +1,6 @@
|
||||
CONFIG_ESP_CONSOLE_NONE=y
|
||||
CONFIG_ESP_TRACE_TRANSPORT_APPTRACE=y
|
||||
CONFIG_APPTRACE_DEST_UART=y
|
||||
CONFIG_APPTRACE_DEST_UART_NUM=0
|
||||
CONFIG_APPTRACE_UART_BAUDRATE=1000000
|
||||
CONFIG_USE_CUSTOM_EVENT_ID=y
|
||||
@@ -0,0 +1,6 @@
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_ESP_CONSOLE_NONE=y
|
||||
CONFIG_ESP_TRACE_TRANSPORT_APPTRACE=y
|
||||
CONFIG_APPTRACE_DEST_UART=y
|
||||
CONFIG_APPTRACE_UART_BAUDRATE=74880
|
||||
CONFIG_XTAL_FREQ_26=y
|
||||
@@ -0,0 +1,4 @@
|
||||
CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
|
||||
CONFIG_ESP_TRACE_TRANSPORT_USB_SERIAL_JTAG=y
|
||||
CONFIG_USE_CUSTOM_EVENT_ID=y
|
||||
CONFIG_ESP_TRACE_USJ_TX_BUFFER_SIZE=16384
|
||||
@@ -0,0 +1,19 @@
|
||||
# 1ms tick period
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
# Enable FreeRTOS SystemView Tracing by default
|
||||
CONFIG_ESP_TRACE_ENABLE=y
|
||||
CONFIG_ESP_TRACE_LIB_EXTERNAL=y
|
||||
CONFIG_ESP_TRACE_TS_SOURCE_ESP_TIMER=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_OVERFLOW_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_ISR_ENTER_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_ISR_EXIT_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_ISR_TO_SCHED_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_TASK_START_EXEC_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_TASK_STOP_EXEC_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_TASK_START_READY_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_TASK_STOP_READY_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_TASK_CREATE_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_TASK_TERMINATE_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_IDLE_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_TIMER_ENTER_ENABLE=y
|
||||
CONFIG_SEGGER_SYSVIEW_EVT_TIMER_EXIT_ENABLE=y
|
||||
Reference in New Issue
Block a user