esp_trace es un nuevo componente de ESP-IDF que separa el tracing de aplicación en encoders y transports enchufables. Agregar una nueva librería de trazado ya no implica parchear el kernel. Este post da un recorrido general y muestra el ejemplo que demuestra la integración.

¿Tracing o logging?

Tracing y logging son herramientas distintas. El logging guarda mensajes discretos que el código decide emitir; se leen cuando algo sale mal. El tracing registra una stream continua de eventos: cambios de tarea, interrupciones y actividad de las colas del kernel, además de cualquier evento personalizado de la aplicación. Una herramienta del host convierte esa stream en una línea de tiempo navegable, aunque los formatos de trace más simples se pueden leer directamente en un monitor serial.

Se recurre al tracing cuando algo es lento o se comporta de forma inesperada y los logs por sí solos no alcanzan a explicar el porqué.

¿Qué resuelve esp_trace?

ESP-IDF tiene ahora un componente llamado esp_trace. Es un núcleo pequeño que controla el estado de trace en runtime (start/stop, sesión activa, locking) y delega el resto del trabajo a dos partes enchufables: un encoder que define el formato del trace, y un transport que mueve esos bytes fuera del chip. Ambas partes se resuelven en un registro al arranque por nombre, de modo que se pueden combinar libremente sin cambios de integración.

Espressif lo construyó por dos motivos. Primero, cada nueva librería de trazado necesitaba su propio mecanismo para engancharse a los eventos de FreeRTOS, y sin un punto de extensión genérico los integradores se veían forzados a modificar FreeRTOSConfig.h directamente. Segundo, el formato de trace estaba acoplado a un transport específico, así que enviar los mismos datos por un enlace distinto (USB-Serial-JTAG en vez de JTAG, por ejemplo) implicaba reescribir la integración.

esp_trace ataca ambos problemas: un punto de extensión bien definido para que herramientas de terceros se publiquen como componentes ESP-IDF normales sin parches al kernel, y una separación limpia encoder/transport para que los mismos datos viajen por cualquier enlace soportado.

Arquitectura

El código de aplicación interactúa con una única API pública. El núcleo despacha cada llamada a través de un vtable de encoder y un vtable de transport. Los encoders y transports se registran en tiempo de link y el núcleo los resuelve por nombre. El layer de transport es opcional: si la librería de trazado ya mueve bytes fuera del chip por su propio canal (streaming sobre TCP, UDP, o escribir a memoria), se puede saltar el adaptador de transport y hacer que el encoder escriba directamente. Seleccionando CONFIG_ESP_TRACE_TRANSPORT_NONE=y en sdkconfig se habilita ese camino.

¿Cómo se enganchan los hooks de FreeRTOS?

FreeRTOS expone macros trace*() (traceTASK_SWITCHED_IN, traceISR_ENTER, traceQUEUE_SEND, etc.) que el kernel invoca en puntos de instrumentación. Esas macros se resuelven en tiempo de compilación, no en runtime, así que no pueden pasar por el vtable del encoder.

esp_trace las maneja en un camino aparte: su header público se incluye desde FreeRTOSConfig.h, y cuando una librería externa está habilitada, esta trae un esp_trace_freertos_impl.h desde tu componente. Ese header es donde se mapean las macros trace*() a las implementaciones de los hooks.

Encoders disponibles hoy

El componente viene de fábrica con un encoder de producción y un encoder de ejemplo:

  • SEGGER SystemView, disponible como el componente gestionado esp_sysview. Es el camino recomendado si se quiere un visualizador completo del lado del host.
  • Un encoder de referencia pequeño que viene con el ejemplo. Emite texto plano, una línea por evento de FreeRTOS, lo que permite leer el trace directamente en cualquier terminal serial.

La arquitectura es abierta: un encoder CTF está en el roadmap, y los mismos puntos de extensión permiten que cualquiera publique su propio encoder o transport como un componente gestionado. Desde el punto de vista de la aplicación todos lucen iguales; solo cambia la selección en Kconfig.

Ejemplo de integración

examples/system/esp_trace es un proyecto mínimo que ejercita cada parte del contrato encoder/hook FreeRTOS. Registra un encoder externo, corre una tarea productora y otra consumidora en distintos cores, y emite una línea legible por humanos por evento FreeRTOS sobre USB-Serial-JTAG.

Ejemplo de salida de trace en un monitor serial
Ejemplo de salida de trace en un monitor serial

El número inicial son los microsegundos transcurridos desde el evento anterior. No se requiere decoder del host ni tooling especial: basta con abrir el endpoint USB-Serial-JTAG en cualquier monitor serial.

El app_main.c del ejemplo usa solo la API genérica. Llama a esp_trace_start(), deja que las tareas corran brevemente, luego llama a esp_trace_stop() y esp_trace_flush(). El código de la aplicación nunca referencia el encoder o el transport por nombre; esos bindings se resuelven desde la configuración.

Conclusiones de Espressif

La conclusión que destaca el equipo: las herramientas de trazado de terceros ya no necesitan parchear ESP-IDF. Para quien mantiene un tracer, la integración pasa a ser un componente gestionado autocontenido construido alrededor de dos contratos pequeños (encoder y transport). SystemView es la opción out-of-the-box recomendada hoy, el ejemplo muestra el port viable más pequeño, y el encoder CTF está en el roadmap.

¿Dónde están las referencias técnicas?