esp-idf/examples/system/app_trace_to_plot
..
main
CMakeLists.txt
README.md
data.json
read_trace.py
sdkconfig.defaults

README.md

Supported Targets ESP32 ESP32-C2 ESP32-C3 ESP32-C5 ESP32-C6 ESP32-H2 ESP32-P4 ESP32-S2 ESP32-S3

Application Level Tracing Example (Plotting)

(See the README.md file in the upper level 'examples' directory for more information about examples.)

This example demonstrates how to use the Application Level Tracing Library (henceforth referred to as App Trace) to send and plot dummy sensor data to a host via JTAG instead of the normal method of logging via UART.

UART logs are time consuming and can significantly slow down the function that calls it. Therefore, it is generally a bad idea to use UART logs in time-critical functions. Logging to host via JTAG is significantly faster and can be used in time-critical functions. For more details regarding logging to host via JTAG, refer to the Logging to Host Documentation.

Hardware Required

To run this example, you need a supported target dev board connected to a JTAG adapter, which can come in the following forms:

  • For ESP32-C3 or ESP32-S3, any board with the built-in USB interface (USB_SERIAL_JTAG).

This example will assume that an ESP-WROVER-KIT is used.

Connections:

  1. Connect the JTAG interface to the target board. For details about how to set up JTAG interface, please see JTAG Debugging. Power up both the JTAG debugger and target board.

  2. To start the tcp socket server, you need to run read_trace.py tool under the esp-idf/examples/system/app_trace_to_plot path.

  3. After connecting JTAG interface and starting the tcp socket server, you need to Run OpenOCD.

Configure the project

idf.py menuconfig
  • To enable application tracing, select the (X) Trace memory option under Component config > Application Level Tracing. This option should have been selected by default.

Build, Flash, and Run

Build the project and flash it to the board, then run monitor tool to view serial output:

idf.py -p PORT flash monitor

(Replace PORT with the name of the serial port to use.)

Run Plotting Tool To plot data and open TCP socket, there is a tool named read_trace.py under the examples/system/app_trace_to_plot path. Run this tool in the terminal session with configured IDF development environment by entering the command below. This command opens a TCP socket and plots the given data when OpenOCD triggered to start App Trace. If you are running tool at first time, you need to install dash with pip install dash in the same terminal session after running configuring IDF development environment.

python read_trace.py --plot-config data.json --source tcp://localhost:53535 --output-file data.log

Start App Trace: Start OpenOCD and App Trace on the target by entering the command below. This command will start OpenOCD and collect all of the bytes from JTAG log data and send them to the tcp socket tcp://localhost:53535 (note tcp:// depends on which IP address and port number opened). Assuming that OpenOCD was started in this example's directory, data.log will be saved here as well.

After running the plotting tool and starting apptrace with OpenOCD separately, you need access plotting on related socket address. Default address is http://127.0.0.1:8055/ and also address can be seen from read_trace.py output. You can see the plotting result by accessing the address from browser.

idf.py openocd --openocd-commands 'reset;esp apptrace start tcp://localhost:53535 0 -1 5'

Note: data.json file is an example for plot config file. It can be changed or modified.

Note: For more details on OpenOCD commands regarding App Trace, refer to the OpenOCD Application Level Tracing Commands

(To exit the serial monitor, type Ctrl-].)

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

Configuration file and data format

General format of json file is:

"Subplot Name": {
    "data_streams"
        "Name of the sensor": {
            "id": int
            "x_axis_data_size": int
            "x_axis_timestamp": bool
            "y_axis_data_size": int
            "data_type": "string"
            ["precision": int]
            ["type": "string"]
            ["mode": "string"]
            ["any_plot_config": Type defined in plotly]
        }
    }
    "xaxis_title": "string",
    "yaxis_title": "string"
}

Explanations of JSON keys are:

JSON Keys Explanation
id ID value of the incoming packet (e.g. 1, 2, 3)
x_axis_data_size Data size of x axis of the incoming packet in bytes (e.g 2, 4, 8)
x_axis_timestamp Will x axis data be timestamp value (e.g. true, false)
y_axis_data_size Data size of y axis of the incoming packet in bytes (e.g 2, 4, 8)
data_type Data type of y axis of the incoming packet (e.g. "int", "float", "double")
precision Optional. If y axis data of the incoming packet is a floating point number, you need to send it in integer form by multiplying a power of 10 and adjust this field (e.g. 1, 2, 3)
type Optional. Determines the plotting type of the graph (e.g. "scatter", "bar"). Default is "scatter"
mode Optional. Determines how values will look like (e.g. "lines", "markers", "lines+markers"). Default is "lines"
xaxis_title Title of x axis in the plot (e.g "time")
yaxis_title Title of y axis in the plot (e.g "values", "sensor data")

Note: Plotting works with plotly subplot feature. id, timestamp_flag, data_size and data_type are the mandatory elements. In addition to these elements, you can config your plot with properties are passed to the constructor of the specified trace type. Data transferring is in {'x': ..., 'y': ..., ...} format. Graph types like Pie or Scatter3D won't work. Scatter, histogram, box, line and similar graph types are working.

Data format in microcontroller side is:

struct format {
    char STX[5] = "esp32",
	uint32_t id,
	any_size y_axis_value,
	any_size x_axis_value
    char EXT = 0x03,
}

Note STX and EXT fields are mandatory and constant to check data validity in visualizer side. You cannot change or remove these fields.

Note y_axis_value and x_axis_value could be in any value and different sizes like long, short, and int. The only thing to do is enter the correct data size in the config file.

Note: If you want to send a floating point number, send it in integer form by multiplying a power of 10 and filling the precision field in the config file.

Troubleshooting

Unable to flash when OpenOCD is connected to the target

On ESP32 boards, one likely cause would be an incorrect SPI flash voltage when starting OpenOCD. Suppose a target board/module with a 3.3 V powered SPI flash is being used, but the configuration file (ex. board/esp32-wrover.cfg for ESP32) is selected when starting OpenOCD which can set the SPI flash voltage to 1.8 V. In this situation, the SPI flash will not work after OpenOCD connects to the target as OpenOCD has changed the SPI flash voltage. Therefore, you might not be able to flash to the target when OpenOCD is connected.

To work around this issue, users are suggested to use board/esp32-wrover.cfg for ESP32 boards/modules operating with an SPI flash voltage of 1.8 V, and board/esp-wroom-32.cfg for 3.3 V. Refer to ESP32 Modules and Boards and Set SPI Flash Voltage for more details.

(For any technical queries, please open an issue on GitHub. We will get back to you as soon as possible.)