Integrating a Custom Trace Library
The esp_trace component lets a third-party trace recorder plug into ESP-IDF without patching the framework. External encoders, such as SEGGER SystemView, use this path. For the high-level design, see Tracing Architecture.
An external component provides:
An encoder adapter, registered via
ESP_TRACE_REGISTER_ENCODER(), which formats trace data into the recorder's protocol.An
esp_trace_freertos_impl.hheader that defines the FreeRTOS trace hooks needed by the recorder.
The encoder is independent from the host link. It can use any registered transport, such as apptrace over JTAG/UART, USB Serial JTAG, or a custom transport.
Encoder Port
An encoder implements esp_trace_encoder_vtable_t.
initandwriteare the only required callbacks.start/stop/flushare dispatched fromesp_trace_start(),esp_trace_stop(), andesp_trace_flush().panic_handleris called from the panic path so the adapter can flush without taking normal locks.take_lock/give_lockprovide the encoder's cross-core serialization; the core adds no locking of its own.
The encoder instance (esp_trace_encoder) holds its function table, the transport bound for the active trace session, and any encoder-specific state. See the struct reference for the exact fields.
If the encoder needs transport-specific settings, configure its bound transport from init using typed configuration keys, for example ESP_TRACE_TRANSPORT_CFG_HEADER_SIZE to set the transport header size.
Register the encoder at link time; the core looks it up by the configured name:
ESP_TRACE_REGISTER_ENCODER("sysview", &s_sysview_vt);
Transport Port
A transport implements esp_trace_transport_vtable_t.
Register it with ESP_TRACE_REGISTER_TRANSPORT("name", &vtable). Most projects only need a custom encoder and can use an existing transport. Implement a transport only when you need a new host link. See Application Level Tracing Transport (apptrace) for the apptrace transport.
Locking and Reentrancy
Runtime callbacks such as write, flush / flush_nolock, read, take_lock / give_lock, and panic_handler can run from FreeRTOS trace hooks. Some of them can also run from ISR context, and some are called while the encoder lock is held.
Warning
Do not call FreeRTOS or IDF APIs that themselves emit trace hooks from these callbacks. Anything that triggers a trace*() macro re-enters the tracing path and can recurse into your encoder, deadlock on the encoder's non-recursive spinlock, or call a task-only API from ISR context.
Specifically avoid these APIs from runtime callbacks:
Task APIs that yield (
vTaskDelay,vTaskSuspend,xTaskNotify*)Queue / semaphore / mutex APIs (
xQueueSend/xQueueReceive,xSemaphoreTake/xSemaphoreGive)Stream and message buffer APIs
Heap allocations that may take an internal mutex
Use lock-free or spinlock-only primitives (esp_trace_lock_*, esp_trace_rb_*), low-level register access, atomics, and esp_rom_* helpers in runtime callbacks. Do heavier work, such as FreeRTOS API calls or allocations, only in init() before tracing starts.
For transports that need a complex driver or network stack, keep the runtime callback as a producer only. Copy the trace data into a preallocated, trace-safe buffer, such as an esp_trace_rb_* ring buffer, and return quickly. A worker task created during init() consumes that buffer and calls APIs such as SPI master, sockets, StreamBuffer, or other FreeRTOS facilities outside the trace callback path and outside the encoder lock. Because the callback must not block or wake a task through yielding APIs, have the worker poll the buffer (or wake on a transport-level event) and drop data when the buffer is full rather than pushing backpressure onto the callback.
FreeRTOS Trace Hooks
To capture FreeRTOS events, the external component implementing a trace encoder should provide an esp_trace_freertos_impl.h header, defining the desired trace macros (traceTASK_SWITCHED_IN(), traceISR_ENTER(), and so on). esp_trace includes this header when CONFIG_ESP_TRACE_LIB_EXTERNAL is enabled.
Application Example
system/esp_trace_custom_library is a minimal template that wires up an external encoder, demonstrates the FreeRTOS trace-hook include chain, and shows cross-core serialization through the encoder lock.