ESP-IDF

This section covers the information necessary for using the FreeRTOS trace recorder using Espressif’s ESP-IDF framework and ESP32/ESP32-S2 targets.

Integration ESP-IDF V4.3

The following sections cover the integration of the Percepio trace recorder with ESP-IDF V4.3.

  1. Open startup.c located in the “componentsesp_system” directory of ESP-IDF and locate static void do_core_init(void).

  2. At the start of the do_core_init(void) function add a call to vTraceInitialize();.

  3. Add the following code after esp_newlib_time_init();

    #if CONFIG_PERCEPIO_TRACERECORDER_ENABLED
        #if CONFIG_PERCEPIO_RECORDER_TRC_RECORDER_MODE_STREAMING
            esp_err_t trc_err;
            trc_err = esp_apptrace_init();
            assert(trc_err == ESP_OK && "Failed to init apptrace module on PRO CPU!");
        #endif
    
        #if CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START == 1
            vTraceEnable(TRC_START);
        #elif CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START_AWAIT_HOST == 1
            vTraceEnable(TRC_START_AWAIT_HOST);
        #else
            vTraceEnable(TRC_INIT);
        #endif
    #endif /*CONFIG_PERCEPIO_TRACERECORDER_ENABLED*/
    
  4. Open FreeRTOS.h located in the “componentsfreertosincludefreertos” directory of ESP-IDF.

  5. Insert the following code after #include "freertos/FreeRTOSConfig.h"

    /* Trace recorder FreeRTOS hooks */
    #ifdef CONFIG_PERCEPIO_TRACERECORDER_ENABLED
        #include "trcRecorder.h"
    #endif
    

Integration ESP-IDF V4.2 (ESP32)

Follow the steps below to integrate Trace Recorder with ESP-IDF V4.2 for an ESP32 target.

  1. Open cpu_start.c located in the “componentsesp32” directory of ESP-IDF, locate void start_cpu0_default(void) and change it from:

    void start_cpu0_default(void)
    {
        esp_err_t err;
        esp_setup_syscall_table();
    
        if (s_spiram_okay) {
    #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
            esp_err_t r=esp_spiram_add_to_heapalloc();
            if (r != ESP_OK) {
                ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
                abort();
            }
    #if CONFIG_SPIRAM_USE_MALLOC
            heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
    #endif
    #endif
        }
    
    //Enable trace memory and immediately start trace.
    #if CONFIG_ESP32_TRAX
    #if CONFIG_ESP32_TRAX_TWOBANKS
        trax_enable(TRAX_ENA_PRO_APP);
    #else
        trax_enable(TRAX_ENA_PRO);
    #endif
        trax_start_trace(TRAX_DOWNCOUNT_WORDS);
    #endif
        esp_clk_init();
        esp_perip_clk_init();
        intr_matrix_clear();
    
    #ifndef CONFIG_ESP_CONSOLE_UART_NONE
    #ifdef CONFIG_PM_ENABLE
        const int uart_clk_freq = REF_CLK_FREQ;
        /* When DFS is enabled, use REFTICK as UART clock source */
        CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON);
    #else
        const int uart_clk_freq = APB_CLK_FREQ;
    #endif // CONFIG_PM_DFS_ENABLE
        uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE);
    #endif // CONFIG_ESP_CONSOLE_UART_NONE
    

    into

    void start_cpu0_default(void)
    {
        esp_err_t err;
        esp_setup_syscall_table();
    
        if (s_spiram_okay) {
    #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
            esp_err_t r=esp_spiram_add_to_heapalloc();
            if (r != ESP_OK) {
                ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
                abort();
            }
    #if CONFIG_SPIRAM_USE_MALLOC
    heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
    #endif
    #endif
        }
    
    //Enable trace memory and immediately start trace.
    #if CONFIG_ESP32_TRAX
    #if CONFIG_ESP32_TRAX_TWOBANKS
        trax_enable(TRAX_ENA_PRO_APP);
    #else
        trax_enable(TRAX_ENA_PRO);
    #endif
        trax_start_trace(TRAX_DOWNCOUNT_WORDS);
    #endif
        esp_clk_init();
        esp_perip_clk_init();
        intr_matrix_clear();
    
    #if CONFIG_PERCEPIO_TRACERECORDER_ENABLED
    #if CONFIG_PERCEPIO_RECORDER_TRC_RECORDER_MODE_STREAMING
        esp_err_t trc_err;
        trc_err = esp_apptrace_init();
        assert(trc_err == ESP_OK && "Failed to init apptrace module on PRO CPU!");
    #endif
    #if CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START == 1
        vTraceEnable(TRC_START);
    #elif CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START_AWAIT_HOST == 1
        vTraceEnable(TRC_START_AWAIT_HOST);
    #else
        vTraceEnable(TRC_INIT);
    #endif
    #endif /*CONFIG_PERCEPIO_TRACERECORDER_ENABLED*/
    
    #ifndef CONFIG_ESP_CONSOLE_UART_NONE
    #ifdef CONFIG_PM_ENABLE
        const int uart_clk_freq = REF_CLK_FREQ;
        /* When DFS is enabled, use REFTICK as UART clock source */
        CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON);
    #else
        const int uart_clk_freq = APB_CLK_FREQ;
    #endif // CONFIG_PM_DFS_ENABLE
        uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE);
    #endif // CONFIG_ESP_CONSOLE_UART_NONE
    
  2. Open FreeRTOS.h located in the “componentsfreertosincludefreertos” directory of ESP-IDF and insert the following code after #include "freertos/FreeRTOSConfig.h"

    /* Trace recorder FreeRTOS hooks */
    #ifdef CONFIG_PERCEPIO_TRACERECORDER_ENABLED
        #include "trcRecorder.h"
    #endif
    

Integration ESP-IDF V4.2 (ESP32-S2)

Follow the steps below to integrate Trace Recorder with ESP-IDF V4.2 for an ESP32-S2 target.

  1. Open cpu_start.c located in the “componentsesp32s2” directory of ESP-IDF, locate void start_cpu0_default(void) and change it from:

    void start_cpu0_default(void)
    {
        esp_err_t err;
        esp_setup_syscall_table();
    
        if (s_spiram_okay) {
    #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
            esp_err_t r = esp_spiram_add_to_heapalloc();
            if (r != ESP_OK) {
                ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
                abort();
            }
    #if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
            r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
            if (r != ESP_OK) {
                ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool!");
                abort();
            }
    #endif
    #if CONFIG_SPIRAM_USE_MALLOC
            heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
    #endif
    #endif
        }
    
    //Enable trace memory and immediately start trace.
    #if CONFIG_ESP32S2_TRAX
        trax_enable(TRAX_ENA_PRO);
        trax_start_trace(TRAX_DOWNCOUNT_WORDS);
    #endif
        esp_clk_init();
        esp_perip_clk_init();
        intr_matrix_clear();
    
    #ifndef CONFIG_ESP_CONSOLE_UART_NONE
    #ifdef CONFIG_PM_ENABLE
        const int uart_clk_freq = REF_CLK_FREQ;
        /* When DFS is enabled, use REFTICK as UART clock source */
        CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON);
    #else
        const int uart_clk_freq = APB_CLK_FREQ;
    #endif // CONFIG_PM_DFS_ENABLE
        uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE);
    #endif // CONFIG_ESP_CONSOLE_UART_NONE
    

    into

    void start_cpu0_default(void)
    {
        esp_err_t err;
        esp_setup_syscall_table();
    
        if (s_spiram_okay) {
    #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
            esp_err_t r = esp_spiram_add_to_heapalloc();
            if (r != ESP_OK) {
                ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!");
                abort();
            }
    #if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
            r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
            if (r != ESP_OK) {
                ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool!");
                abort();
            }
    #endif
    #if CONFIG_SPIRAM_USE_MALLOC
            heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
    #endif
    #endif
        }
    
    //Enable trace memory and immediately start trace.
    #if CONFIG_ESP32S2_TRAX
        trax_enable(TRAX_ENA_PRO);
        trax_start_trace(TRAX_DOWNCOUNT_WORDS);
    #endif
        esp_clk_init();
        esp_perip_clk_init();
        intr_matrix_clear();
    
    #if CONFIG_PERCEPIO_TRACERECORDER_ENABLED
    #if CONFIG_PERCEPIO_RECORDER_TRC_RECORDER_MODE_STREAMING
        esp_err_t trc_err;
        trc_err = esp_apptrace_init();
        assert(trc_err == ESP_OK && "Failed to init apptrace module on PRO CPU!");
    #endif
    #if CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START == 1
        vTraceEnable(TRC_START);
    #elif CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START_AWAIT_HOST == 1
        vTraceEnable(TRC_START_AWAIT_HOST);
    #else
        vTraceEnable(TRC_INIT);
    #endif
    #endif /*CONFIG_PERCEPIO_TRACERECORDER_ENABLED*/
    
    #ifndef CONFIG_ESP_CONSOLE_UART_NONE
    #ifdef CONFIG_PM_ENABLE
        const int uart_clk_freq = REF_CLK_FREQ;
        /* When DFS is enabled, use REFTICK as UART clock source */
        CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON);
    #else
        const int uart_clk_freq = APB_CLK_FREQ;
    #endif // CONFIG_PM_DFS_ENABLE
        uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE);
    #endif // CONFIG_ESP_CONSOLE_UART_NONE
    
  2. Open FreeRTOS.h located in the “componentsfreertosincludefreertos” directory of ESP-IDF and insert the following code after #include "freertos/FreeRTOSConfig.h"

    /* Trace recorder FreeRTOS hooks */
    #ifdef CONFIG_PERCEPIO_TRACERECORDER_ENABLED
        #include "trcRecorder.h"
    #endif
    

Getting Started with Tracealyzer for ESP-IDF FreeRTOS - Snapshot Mode (Eclipse)

Follow the steps below to integrate the trace recorder in an existing project. In snapshot mode, the data is stored in a ring-buffer in Target RAM, from which you may read a “snapshot” at any time, as long as the target system is halted. Learn more in the Snapshot Mode section of the Tracealyzer User Manual.

  1. Get Tracealyzer from https://percepio.com/downloadform. In the registration form, make sure to select FreeRTOS as “Target Platform”. The download link is emailed to you and usually arrives within 1 minute. Evaluation licenses are sent in a separate email and may take a few minutes to arrive.

  2. Install Tracealyzer and select “Help” -> “FreeRTOS Trace Recorder” to locate the Trace Recorder ESP-IDF component in the installation directory.

  3. Copy the “TraceRecorder” folder into your project components folder. Please note that there needs to be a folder named components in the project where the TraceRecorder is placed for the sdkconfig to be able to find the component.

  4. Open trcConfig.h and make sure that TRC_CFG_ESP_IDF_VERSION matches your version of ESP-IDF.

  5. Open sdkconfig and ensure “Run FreeRTOS only on first core” is checked.

  6. Navigate to “Component config” and enter the “Application Level Tracing” menu and select the “Trace memory” option for “Data Destination”.

  7. Navigate to the “Percepio Trace Recorder” component and enable “Tracealyzer Tracing Enabled” and set Tracing Mode to “Snapshot recorder mode”.

  8. Scroll down and make sure that the settings Number of Tasks, ISR, Queues, Semaphores etc. are large enough to accommodate the number of tasks, queues, semaphores etc. in your system. If not sure, use large values. You can optimize these settings later, once a trace has been recorded.

  9. Test it. Build the project, let the system run for a while, then halt the execution.

Getting Started with Tracealyzer for ESP-IDF FreeRTOS - Snapshot Mode (Visual Studio Code)

Follow the steps below to integrate the trace recorder in an existing project. In snapshot mode, the data is stored in a ring-buffer in Target RAM, from which you may read a “snapshot” at any time, as long as the target system is halted. Learn more in the Snapshot Mode section of the Tracealyzer User Manual.

  1. Get Tracealyzer from https://percepio.com/downloadform In the registration form, make sure to select FreeRTOS as “Target Platform”. The download link is emailed to you and usually arrives within 1 minute. Evaluation licenses are sent in a separate email and may take a few minutes to arrive.

  2. Install Tracealyzer and select “Help” -> “FreeRTOS Trace Recorder” to locate the Trace Recorder ESP-IDF component in the installation directory.

  3. Copy the TraceRecorder folder into your project components folder. Please note that there needs to be a folder named components in the project where the “TraceRecorder” is placed for the menuconfig to be able to find the component.

  4. Open trcConfig.h and make sure that TRC_CFG_ESP_IDF_VERSION matches your version of ESP-IDF.

  5. Run menuconfig and ensure “Run FreeRTOS only on first core” is checked.

  6. Navigate to “Component config” and enter the “Application Level Tracing” menu and select the “Trace memory” option for “Data Destination”.

  7. Navigate to the “Percepio Trace Recorder” component and enable “Tracealyzer Tracing Enabled” and set Tracing Mode to “Snapshot recorder mode”.

  8. Scroll down and make sure that the settings Number of Tasks, ISR, Queues, Semaphores etc. are large enough to accommodate the number of tasks, queues, semaphores etc. in your system. If not sure, use large values. You can optimize these settings later, once a trace has been recorded.

#. Test it. Build the project, let the system run for a while, then halt the execution. Done!

To access the trace data, you need to upload the trace data from the target RAM and save it in a file on the host computer, which is then opened in Tracealyzer. This can be automated in several ways but can also be accomplished in Visual Studio Code PlatformIO by entering the following command in the “DEBUG CONSOLE”

mon dump_image <filename> RecorderDataPtr <size>

Getting Started with Tracealyzer for ESP-IDF FreeRTOS - Streaming Mode (Recorder Setup)

Assuming you have followed the recommended steps for basic integration, the following additional steps are needed to enable streaming.

  1. Select Tracing Mode: Streaming Recorder Mode (CONFIG_PERCEPIO_RECORDER_TRC_RECORDER_MODE_STREAMING)

  2. Select Recorder Start Mode: Start Await Host (CONFIG_PERCEPIO_RECORDER_CFG_START_MODE_START_AWAIT_HOST)

  3. Select Stream Blocking Mode: Block if FIFO Full (CONFIG_PERCEPIO_RECORDER_CFG_TRAX_MODE_BLOCK_IF_FIFO_FULL)

Save the configuration, recompile the project, and continue with the next section.

Getting Started with Tracealyzer for ESP-IDF FreeRTOS - Streaming Mode (Tracealyzer Setup)

ESP-IDF features an application level tracing library apptrace, which allows for the transfer of trace data from target to host using a JTAG adapter and OpenOCD. To configure Tracealyzer to interface with the apptrace system via GDB use the following steps:

  1. First of all an instance of OpenOCD needs to be running. OpenOCD will handle the communication btween the target and Tracealyzer. Here are documentation on how to setup and run OpenOCD, when you see the expected output shown under “Run OpenOCD” you can continoue to the next step.

  2. In Tracealyzer, open settings, navigate to PSF-Streaming Settings, and choose Target Connection: GDB.

  3. Navigate to GDB Settings

  4. Set Path to GDB to the GDB executable provided by Espressif (xtensa-esp32-elf-gdb.exe).

  5. Set Path to Image to your projects .elf file.

  6. Configure Commands to Initialize as follows:

    target remote localhost:3333
    !tz wait 1000
    set mem inaccessible-by-default off
    mon reset halt
    flushregs
    set remote hardware-watchpoint-limit 2
    
  7. Configure Commands to Start Stream as follows:

    mon reset halt
    thb initTrax
    c
    mon esp apptrace start "file://$(TZ_OUT)" 0 -1 -1 0 0
    mon resume
    
  8. Configure Commands to End Stream as follows:

    mon esp apptrace stop
    mon halt
    
  9. Set Trace Data is Received by to GDB Writes Data to Output Specified by $(TZ_OUT).