mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'apptrace_pytest' into 'master'
Generic apptrace example with pytest support Closes IDF-5620 See merge request espressif/esp-idf!22195
This commit is contained in:
commit
a3df4d5386
@ -106,6 +106,17 @@ example_test_pytest_esp32s2_generic:
|
||||
tags: [ esp32s2, generic ]
|
||||
parallel: 3
|
||||
|
||||
example_test_pytest_esp32s2_jtag:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
- .rules:test:example_test-esp32s2
|
||||
needs:
|
||||
- build_pytest_examples_jtag
|
||||
tags: [ esp32s2, jtag ]
|
||||
variables:
|
||||
SETUP_TOOLS: "1" # need gdb openocd
|
||||
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
|
||||
|
||||
example_test_pytest_esp32s3_generic:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
@ -115,6 +126,17 @@ example_test_pytest_esp32s3_generic:
|
||||
tags: [ esp32s3, generic ]
|
||||
parallel: 3
|
||||
|
||||
example_test_pytest_esp32s3_usb_serial_jtag:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
- .rules:test:example_test-esp32s3
|
||||
needs:
|
||||
- build_pytest_examples_jtag
|
||||
tags: [ esp32s3, usb_serial_jtag ]
|
||||
variables:
|
||||
SETUP_TOOLS: "1" # need gdb openocd
|
||||
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
|
||||
|
||||
example_test_pytest_esp32s3_f4r8:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
@ -132,6 +154,17 @@ example_test_pytest_esp32c2_generic:
|
||||
tags: [ esp32c2, generic, xtal_40mhz ]
|
||||
parallel: 3
|
||||
|
||||
example_test_pytest_esp32c2_jtag:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
- .rules:test:example_test-esp32c2
|
||||
needs:
|
||||
- build_pytest_examples_jtag
|
||||
tags: [ esp32c2, jtag ]
|
||||
variables:
|
||||
SETUP_TOOLS: "1" # need gdb openocd
|
||||
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
|
||||
|
||||
example_test_pytest_esp32c3_generic:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
@ -141,6 +174,17 @@ example_test_pytest_esp32c3_generic:
|
||||
tags: [ esp32c3, generic ]
|
||||
parallel: 3
|
||||
|
||||
example_test_pytest_esp32c3_usb_serial_jtag:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
- .rules:test:example_test-esp32c3
|
||||
needs:
|
||||
- build_pytest_examples_jtag
|
||||
tags: [ esp32c3, usb_serial_jtag ]
|
||||
variables:
|
||||
SETUP_TOOLS: "1" # need gdb openocd
|
||||
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
|
||||
|
||||
example_test_pytest_esp32c3_flash_suspend:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
|
@ -114,6 +114,7 @@ ENV_MARKERS = {
|
||||
'MSPI_F4R8': 'runner with Quad Flash and Octal PSRAM',
|
||||
'MSPI_F4R4': 'runner with Quad Flash and Quad PSRAM',
|
||||
'jtag': 'runner where the chip is accessible through JTAG as well',
|
||||
'usb_serial_jtag': 'runner where the chip is accessible through builtin JTAG as well',
|
||||
'adc': 'ADC related tests should run on adc runners',
|
||||
'xtal32k': 'Runner with external 32k crystal connected',
|
||||
'no32kXtal': 'Runner with no external 32k crystal connected',
|
||||
|
@ -292,7 +292,7 @@ How To Use It
|
||||
|
||||
In order to use logging via trace module, users need to perform the following steps:
|
||||
|
||||
1. On the target side, the special vprintf-like function ``esp_apptrace_vprintf`` needs to be installed. It sends log data to the host. Example code is provided in :example:`system/app_trace_to_host`.
|
||||
1. On the target side, the special vprintf-like function :cpp:func:`esp_apptrace_vprintf` needs to be installed. It sends log data to the host. An example is ``esp_log_set_vprintf(esp_apptrace_vprintf);``. To send log data to UART again, use ``esp_log_set_vprintf(vprintf);``.
|
||||
2. Follow instructions in items 2-5 in `Application Specific Tracing`_.
|
||||
3. To print out collected log records, run the following command in terminal: ``$IDF_PATH/tools/esp_app_trace/logtrace_proc.py /path/to/trace/file /path/to/program/elf/file``.
|
||||
|
||||
|
@ -292,7 +292,7 @@ ESP-IDF 的日志库会默认使用类 vprintf 的函数将格式化的字符串
|
||||
|
||||
为了使用跟踪模块来记录日志,用户需要执行以下步骤:
|
||||
|
||||
1. 在目标端,需要安装特殊的类 vprintf 函数 ``esp_apptrace_vprintf``,该函数负责将日志数据发送给主机。示例代码参见 :example:`system/app_trace_to_host` 。
|
||||
1. 在目标端,需要安装特殊的类 vprintf 函数 :cpp:func:`esp_apptrace_vprintf`,该函数负责将日志数据发送给主机,使用方法为 ``esp_log_set_vprintf(esp_apptrace_vprintf);``。如需将日志数据再次重定向给 UART,请使用 ``esp_log_set_vprintf(vprintf);``。
|
||||
2. 按照 :ref:`app_trace-application-specific-tracing` 章节中的第 2-5 步进行操作。
|
||||
3. 打印接收到的日志记录,请在终端运行以下命令:``$IDF_PATH/tools/esp_app_trace/logtrace_proc.py /path/to/trace/file /path/to/program/elf/file``。
|
||||
|
||||
|
@ -1,14 +1,10 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
examples/system/app_trace_to_host:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32", "esp32s2"]
|
||||
examples/system/app_trace_basic:
|
||||
disable:
|
||||
- if: IDF_TARGET == "esp32c6" or IDF_TARGET == "esp32h2"
|
||||
temporary: true
|
||||
reason: the other targets are not tested yet
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32s2"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
reason: target esp32c6, esp32h2 is not supported yet
|
||||
|
||||
examples/system/base_mac_address:
|
||||
disable_test:
|
||||
|
@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(app_trace_to_host)
|
||||
project(app_trace_basic)
|
73
examples/system/app_trace_basic/README.md
Normal file
73
examples/system/app_trace_basic/README.md
Normal file
@ -0,0 +1,73 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Application Level Tracing Example (Basic)
|
||||
|
||||
(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](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#) (henceforth referred to as **App Trace**) to log messages 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](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#app-trace-logging-to-host).
|
||||
|
||||
### 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:
|
||||
|
||||
* [ESP-WROVER-KIT](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html#esp-wrover-kit-v4-1) which integrates an on-board JTAG adapter. Ensure that the [required jumpers to enable JTAG are connected](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/get-started-wrover-kit.html#setup-options) on the WROVER-KIT.
|
||||
* ESP32, ESP32-S2 or ESP32-C2 core board (e.g. ESP32-DevKitC, [ESP32-S2-Saola-1](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html)) can also work as long as you connect it to an external JTAG adapter (e.g. FT2232H, J-LINK).
|
||||
|
||||
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](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html). Power up both the JTAG debugger and target board.
|
||||
|
||||
2. After connecting JTAG interface, you need to [Run OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#run-openocd).
|
||||
|
||||
3. Open a separate terminal window and run telnet by entering the command below. The telnet terminal window is used to feed commands to OpenOCD:
|
||||
|
||||
```bash
|
||||
telnet localhost 4444
|
||||
```
|
||||
|
||||
### 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.)
|
||||
|
||||
**Start App Trace:** In the telnet session window, trigger OpenOCD to start App Trace on the target by entering the command below. This command will collect 9000 bytes of JTAG log data and save them to the file `file://apptrace.log` (note `file://` depends on
|
||||
where OpenOCD was started). Assuming that OpenOCD was started in this example's directory, `apptrace.log` will be saved here as well.
|
||||
|
||||
|
||||
```bash
|
||||
esp apptrace start file://apptrace.log 0 2000 3 0 0
|
||||
```
|
||||
|
||||
**Note:** For more details on OpenOCD commands regarding App Trace, refer to the [OpenOCD Application Level Tracing Commands](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#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.
|
||||
|
||||
## 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](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html) and [Set SPI Flash Voltage](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/tips-and-quirks.html#why-to-set-spi-flash-voltage-in-openocd-configuration) for more details.
|
||||
|
||||
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)
|
2
examples/system/app_trace_basic/main/CMakeLists.txt
Normal file
2
examples/system/app_trace_basic/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "app_trace_basic_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* Application Trace Basic Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Waiting for OpenOCD connection");
|
||||
|
||||
while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_JTAG)) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Sending example data to the host...");
|
||||
|
||||
for (unsigned int cnt = 1; cnt < 51; ++cnt) {
|
||||
char buf[32] = {0};
|
||||
snprintf(buf, sizeof(buf), "Apptrace test data[%d]:%d\n", cnt, cnt * cnt);
|
||||
esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_JTAG, buf, strlen(buf), ESP_APPTRACE_TMO_INFINITE);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write data to host [0x%x] (%s)", res, esp_err_to_name(res));
|
||||
}
|
||||
esp_apptrace_flush(ESP_APPTRACE_DEST_JTAG, 1000);
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Done!");
|
||||
}
|
73
examples/system/app_trace_basic/pytest_app_trace_basic.py
Normal file
73
examples/system/app_trace_basic/pytest_app_trace_basic.py
Normal file
@ -0,0 +1,73 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import time
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
from pytest_embedded_idf import IdfDut
|
||||
from pytest_embedded_jtag import OpenOcd
|
||||
|
||||
|
||||
def apptrace_wait_stop(openocd: OpenOcd, timeout: int = 30) -> None:
|
||||
stopped = False
|
||||
end_before = time.time() + timeout
|
||||
while not stopped:
|
||||
cmd_out = openocd.write('esp apptrace status')
|
||||
for line in cmd_out.splitlines():
|
||||
if line.startswith('Tracing is STOPPED.'):
|
||||
stopped = True
|
||||
break
|
||||
if not stopped and time.time() > end_before:
|
||||
raise pexpect.TIMEOUT('Failed to wait for apptrace stop!')
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'embedded_services, no_gdb',
|
||||
[
|
||||
('esp,idf,jtag', 'y'),
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
'port, openocd_cli_args', [
|
||||
pytest.param(None, None, marks=[pytest.mark.esp32, pytest.mark.jtag]),
|
||||
pytest.param(None, '-f board/esp32s2-kaluga-1.cfg', marks=[pytest.mark.esp32s2, pytest.mark.jtag]),
|
||||
pytest.param(None, '-f board/esp32c2-ftdi.cfg', marks=[pytest.mark.esp32c2, pytest.mark.jtag]),
|
||||
pytest.param('/dev/ttyACM0', '-f board/esp32s3-builtin.cfg', marks=[pytest.mark.esp32s3, pytest.mark.usb_serial_jtag]),
|
||||
pytest.param('/dev/ttyACM0', '-f board/esp32c3-builtin.cfg', marks=[pytest.mark.esp32c3, pytest.mark.usb_serial_jtag]),
|
||||
],
|
||||
indirect=True
|
||||
)
|
||||
def test_examples_app_trace_basic(dut: IdfDut, openocd: OpenOcd) -> None:
|
||||
dut.openocd.write('reset')
|
||||
dut.expect_exact('example: Waiting for OpenOCD connection', timeout=5)
|
||||
assert 'Targets connected.' in dut.openocd.write('esp apptrace start file://apptrace.log 0 2000 3 0 0')
|
||||
apptrace_wait_stop(dut.openocd)
|
||||
|
||||
with open(openocd._logfile) as oocd_log: # pylint: disable=protected-access
|
||||
cores = 1 if dut.app.sdkconfig.get('FREERTOS_UNICORE') is True else 2
|
||||
params_str = 'App trace params: from {} cores,'.format(cores)
|
||||
found = False
|
||||
for line in oocd_log:
|
||||
if params_str in line:
|
||||
found = True
|
||||
break
|
||||
if found is not True:
|
||||
raise RuntimeError(
|
||||
'"{}" could not be found in {}'.format(params_str, openocd._logfile) # pylint: disable=protected-access
|
||||
)
|
||||
|
||||
with open('apptrace.log') as apptrace_log:
|
||||
for sample_num in range(1, 51):
|
||||
log_str = 'Apptrace test data[{}]:{}'.format(sample_num, sample_num * sample_num)
|
||||
found = False
|
||||
for line in apptrace_log:
|
||||
if log_str in line:
|
||||
found = True
|
||||
break
|
||||
if found is not True:
|
||||
raise RuntimeError(
|
||||
'"{}" could not be found in {}'.format(log_str, 'apptrace.log')
|
||||
)
|
@ -1,5 +1,3 @@
|
||||
# Enable application tracing by default
|
||||
CONFIG_APPTRACE_DEST_JTAG=y
|
||||
CONFIG_APPTRACE_ENABLE=y
|
||||
# Disable WiFi stack by default
|
||||
CONFIG_WIFI_ENABLED=n
|
@ -1,221 +0,0 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 |
|
||||
| ----------------- | ----- | -------- |
|
||||
|
||||
# Application Level Tracing Example (Logging to Host)
|
||||
|
||||
(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](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#) (henceforth referred to as **App Trace**) to log messages 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](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#app-trace-logging-to-host).
|
||||
|
||||
This example demonstrates JTAG logging to host in the context of polling for a [zero crossing](https://en.wikipedia.org/wiki/Zero_crossing). The example app will continuously sample a 130 Hz sinusoidal signal (using the ADC) and log the sampled values (via JTAG). Due to the higher speed of JTAG logging, the polling rate of the ADC should be high enough to detect a zero crossing.
|
||||
|
||||
This example utilizes the following ESP-IDF features:
|
||||
* [DAC driver](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/dac.html) to generate the 130 Hz sinusoidal signal.
|
||||
* [ADC driver](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html) to sample the sinusoidal signal.
|
||||
* [Application Level Tracing Library](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#) to log ADC samples to host.
|
||||
* [OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#setup-of-openocd) to interface with the target and receive the log output over JTAG.
|
||||
|
||||
## How to use example
|
||||
|
||||
### 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:
|
||||
|
||||
* [ESP-WROVER-KIT](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html#esp-wrover-kit-v4-1) which integrates an on-board JTAG adapter. Ensure that the [required jumpers to enable JTAG are connected](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/get-started-wrover-kit.html#setup-options) on the WROVER-KIT.
|
||||
* ESP32 or ESP32-S2 core board (e.g. ESP32-DevKitC, [ESP32-S2-Saola-1](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html)) can also work as long as you connect it to an external JTAG adapter (e.g. FT2232H, J-LINK).
|
||||
|
||||
This example will assume that that an ESP-WROVER-KIT is used.
|
||||
|
||||
#### Pin Assignment:
|
||||
|
||||
The sinusoidal signal ranging from 0 V ~ 3.1 V should be input into `ADC1_CHANNEL_6`. Users may provide this signal themselves, or use the example-generated signal in `DAC_CHAN_0`. Listed below are the corresponding DAC/ADC channel pins for supported targets.
|
||||
|
||||
| Target | DAC Output | ADC Input |
|
||||
| ------------------ | ------------------ | ------------------ |
|
||||
| ESP32 | Channel 0 (GPIO25) | Channel 6 (GPIO34) |
|
||||
| ESP32S2 | Channel 0 (GPIO17) | Channel 6 (GPIO7) |
|
||||
|
||||
#### Extra Connections:
|
||||
|
||||
1. Connect the JTAG interface to the target board. For details about how to set up JTAG interface, please see [JTAG Debugging](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html). Power up both the JTAG debugger and target board.
|
||||
|
||||
2. After connecting JTAG interface, you need to [Run OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#run-openocd).
|
||||
|
||||
3. Open a separate terminal window and run telnet by entering the command below. The telnet terminal window is used to feed commands to OpenOCD:
|
||||
|
||||
```bash
|
||||
telnet localhost 4444
|
||||
```
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* By default, the DAC will generate about 130 Hz signal ranging from 0 V ~ 3.1 V. Note that to generate a 130 Hz signal, the RTC 8 MHz clock will need to use a non-standard divider.
|
||||
|
||||
* 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.)
|
||||
|
||||
**Start App Trace:** In the telnet session window, trigger OpenOCD to start App Trace on the target by entering the command below. This command will collect 9000 bytes of JTAG log data and save them to the file `file://adc.log` (note `file://` depends on
|
||||
where OpenOCD was started). Assuming that OpenOCD was started in this example's directory, `adc.log` will be saved here as well.
|
||||
|
||||
|
||||
```bash
|
||||
esp apptrace start file://adc.log 0 9000 5 0 0
|
||||
```
|
||||
|
||||
**Note:** For more details on OpenOCD commands regarding App Trace, refer to the [OpenOCD Application Level Tracing Commands](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#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.
|
||||
|
||||
## Example Output
|
||||
|
||||
The example will continuously sample the ADC for 2 ms per iteration, and will alternate between JTAG and UART logging per iteration. However, the JTAG logs should be captured by OpenOCD, thus will not appear in the monitor's output. Therefore, the monitor should only display the iterations where UART logging was used (i.e. every alternate iteration) such as the following:
|
||||
|
||||
```
|
||||
I (4289) example: Sampling ADC and sending data to the host...
|
||||
I (4309) example: Collected 427 samples in 2 ms.
|
||||
|
||||
I (4309) example: Sampling ADC and sending data to the UART...
|
||||
I (4309) example: Sample:1, Value:2224
|
||||
I (4309) example: Sample:2, Value:840
|
||||
I (4309) example: Sample:3, Value:3503
|
||||
I (4319) example: Sample:4, Value:27
|
||||
I (4319) example: Sample:5, Value:4095
|
||||
I (4329) example: Collected 5 samples in 2 ms.
|
||||
```
|
||||
|
||||
**Note:** The UART log above was produced with the CPU running at 240 MHz.
|
||||
|
||||
To access the JTAG logs, the `adc.log` file should be decoded. This can be done by using the `logtrace_proc.py` script as such:
|
||||
|
||||
```bash
|
||||
$IDF_PATH/tools/esp_app_trace/logtrace_proc.py adc.log build/app_trace_to_host.elf
|
||||
```
|
||||
|
||||
The `logtrace_proc.py` script should produce the following output when decoding:
|
||||
|
||||
```
|
||||
Parse trace file '/user-home/esp/openocd-esp32/adc.log'...
|
||||
Unprocessed 7 bytes of log record args!
|
||||
Parsing completed.
|
||||
====================================================================
|
||||
I (59369) example: Sample:1, Value:3717
|
||||
I (59369) example: Sample:2, Value:3647
|
||||
I (59369) example: Sample:3, Value:3575
|
||||
I (59369) example: Sample:4, Value:3491
|
||||
...
|
||||
|
||||
I (59379) example: Sample:398, Value:78
|
||||
I (59379) example: Sample:399, Value:58
|
||||
I (59379) example: Sample:400, Value:22
|
||||
I (59379) example: Sample:401, Value:14
|
||||
I (59379) example: Sample:402, Value:0
|
||||
I (59379) example: Sample:403, Value:0
|
||||
I (59379) example: Sample:404, Value:0
|
||||
I (59379) example: Sample:405, Value:0
|
||||
I (59379) example: Sample:406, Value:0
|
||||
I (59379) example: Sample:407, Value:0
|
||||
I (59379) example: Sample:408, Value:0
|
||||
I (59379) example: Sample:409, Value:0
|
||||
I (59379) example: Sample:410, Value:0
|
||||
I (59379) example: Sample:411, Value:0
|
||||
I (59379) example: Sample:412, Value:0
|
||||
I (59379) example: Sample:413, Value:0
|
||||
I (59379) example: Sample:414, Value:16
|
||||
I (59379) example: Sample:415, Value:32
|
||||
I (59379) example: Sample:416, Value:40
|
||||
I (59379) example: Sample:417, Value:74
|
||||
I (59379) example: Sample:418, Value:89
|
||||
I (59379) example: Sample:419, Value:113
|
||||
I (59379) example: Sample:420, Value:160
|
||||
I (59379) example: Sample:421, Value:192
|
||||
I (59379) example: Sample:422, Value:221
|
||||
I (59379) example: Sample:423, Value:256
|
||||
I (59379) example: Sample:424, Value:298
|
||||
I (59379) example: Sample:425, Value:345
|
||||
I (59379) example: Sample:426, Value:386
|
||||
I (59379) example: Sample:427, Value:432
|
||||
I (61409) example: Sample:1, Value:2653
|
||||
|
||||
====================================================================
|
||||
|
||||
Log records count: 428
|
||||
```
|
||||
|
||||
## 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](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html) and [Set SPI Flash Voltage](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/tips-and-quirks.html#why-to-set-spi-flash-voltage-in-openocd-configuration) for more details.
|
||||
|
||||
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)
|
||||
|
||||
The log should be identical to those printed via UART (complete with timestamps), but almost two orders of magnitude faster.
|
||||
|
||||
## Example Breakdown
|
||||
|
||||
The following code snippet demonstrates a loop of the sampling and logging the ADC over a 2 ms period in order to capture one full period of a 130 Hz signal.
|
||||
|
||||
```c
|
||||
int sampling_period = 2;
|
||||
int i = 0;
|
||||
uint32_t sampling_start = esp_log_timestamp(); //this clock counts milliseconds
|
||||
do {
|
||||
int adc_raw = 0;
|
||||
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHANNEL, &adc_raw));
|
||||
ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc_raw);
|
||||
} while (esp_log_timestamp() - sampling_start < sampling_period);
|
||||
```
|
||||
|
||||
If `ESP_LOGI()` is routed via UART (occurs by default), the log output produced will likely resemble the output shown below. Notice that due to UART logging is time consuming, thus the ADC is only sampled five times, which is too infrequent to consistently detect a zero crossing (where the zero crossing is `4096/2 = 2048` i.e., the mid point of the 12-bit ADC).
|
||||
|
||||
```bash
|
||||
I (4309) example: Sample:1, Value:2224
|
||||
I (4309) example: Sample:2, Value:840
|
||||
I (4309) example: Sample:3, Value:3503
|
||||
I (4319) example: Sample:4, Value:27
|
||||
I (4319) example: Sample:5, Value:4095
|
||||
I (4329) example: Collected 5 samples in 2 ms.
|
||||
```
|
||||
|
||||
However, by logging via JTAG, the logging is much quicker hence allows a much higher sampling frequency (over 400 times) as shown the the log output below thus would be able to detect a zero crossing more consistently.
|
||||
|
||||
```c
|
||||
esp_log_set_vprintf(esp_apptrace_vprintf);
|
||||
```
|
||||
|
||||
```bash
|
||||
...
|
||||
|
||||
I (59379) example: Sample:423, Value:256
|
||||
I (59379) example: Sample:424, Value:298
|
||||
I (59379) example: Sample:425, Value:345
|
||||
I (59379) example: Sample:426, Value:386
|
||||
I (59379) example: Sample:427, Value:432
|
||||
I (61409) example: Sample:1, Value:2653
|
||||
|
||||
====================================================================
|
||||
|
||||
Log records count: 428
|
||||
|
||||
```
|
||||
|
||||
This example has demonstrated powerful functionality of logging to host via JTAG interface. With standard UART communication at a baud rate of 115200, printing out a single line log message takes approximately 4 ms. This also means that logged tasks cannot run more frequently than every 4 ms. By providing the same logging over JTAG, logging performance is improved 80 fold.
|
@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "app_trace_to_host_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
@ -1,118 +0,0 @@
|
||||
/* Application Trace to Host Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "driver/dac_cosine.h"
|
||||
#include "soc/adc_channel.h"
|
||||
#include "soc/dac_channel.h"
|
||||
|
||||
#define ADC1_TEST_CHANNEL (ADC_CHANNEL_6)
|
||||
#define EXAMPLE_DAC_CHENNEL DAC_CHAN_0
|
||||
|
||||
#define TEST_SAMPLING_PERIOD 20
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
/*
|
||||
* Enable cosine waveform generator (CW)
|
||||
* on DAC channel 0 to provide sinusoidal signal
|
||||
* It can be used instead of a live signal for testing
|
||||
* of speed of logging to the host
|
||||
* sequentially with data retrieval from ADC
|
||||
*/
|
||||
static void enable_cosine_generator(void)
|
||||
{
|
||||
dac_cosine_handle_t dac_handle;
|
||||
dac_cosine_config_t cos_cfg = {
|
||||
.chan_id = EXAMPLE_DAC_CHENNEL,
|
||||
.freq_hz = 130,
|
||||
.clk_src = DAC_COSINE_CLK_SRC_DEFAULT,
|
||||
.offset = 0,
|
||||
.phase = DAC_COSINE_PHASE_0,
|
||||
.atten = DAC_COSINE_ATTEN_DEFAULT,
|
||||
.flags.force_set_freq = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(dac_cosine_new_channel(&cos_cfg, &dac_handle));
|
||||
ESP_ERROR_CHECK(dac_cosine_start(dac_handle));
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample data an ADC1 channel 6
|
||||
* over specific 'sampling_period' in milliseconds.
|
||||
* Print out sampling result using standard ESP_LOGI() function.
|
||||
* Return the number of samples collected.
|
||||
*/
|
||||
static int adc1_sample_and_show(adc_oneshot_unit_handle_t adc1_handle, int sampling_period)
|
||||
{
|
||||
int i = 0;
|
||||
uint32_t sampling_start = esp_log_timestamp();
|
||||
do {
|
||||
int adc_raw = 0;
|
||||
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHANNEL, &adc_raw));
|
||||
ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc_raw);
|
||||
} while (esp_log_timestamp() - sampling_start < sampling_period);
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main program loop that is sampling data on ADC
|
||||
* and logging results with application tracing to the host
|
||||
* as well as for comparison printing out sampling result to UART
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Enabling ADC1 on channel 6 / GPIO%d.", ADC1_CHANNEL_6_GPIO_NUM);
|
||||
|
||||
//-------------ADC1 Init---------------//
|
||||
adc_oneshot_unit_handle_t adc1_handle;
|
||||
adc_oneshot_unit_init_cfg_t init_config1 = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
|
||||
|
||||
//-------------ADC1 Channel Config---------------//
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.atten = ADC_ATTEN_DB_11,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC1_TEST_CHANNEL, &config));
|
||||
|
||||
ESP_LOGI(TAG, "Enabling CW generator on DAC channel 0 / GPIO%d.", DAC_CHAN0_GPIO_NUM);
|
||||
enable_cosine_generator();
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Logging with the Application Trace
|
||||
*/
|
||||
ESP_LOGI(TAG, "Sampling ADC and sending data to the host...");
|
||||
// Route LOGx() to the host
|
||||
esp_log_set_vprintf(esp_apptrace_vprintf);
|
||||
int samples_collected = adc1_sample_and_show(adc1_handle, TEST_SAMPLING_PERIOD);
|
||||
// Route LOGx() back to UART
|
||||
esp_log_set_vprintf(vprintf);
|
||||
// Flush collected data to the host
|
||||
esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, 100000);
|
||||
ESP_LOGI(TAG, "Collected %d samples in %d ms.\n", samples_collected, TEST_SAMPLING_PERIOD);
|
||||
|
||||
/*
|
||||
* Logging to UART
|
||||
*/
|
||||
ESP_LOGI(TAG, "Sampling ADC and sending data to the UART...");
|
||||
samples_collected = adc1_sample_and_show(adc1_handle, TEST_SAMPLING_PERIOD);
|
||||
ESP_LOGI(TAG, "Collected %d samples in %d ms.\n", samples_collected, TEST_SAMPLING_PERIOD);
|
||||
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle));
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
from pytest_embedded.log import DuplicateStdoutPopen, MessageQueue
|
||||
from pytest_embedded_idf import IdfDut
|
||||
from pytest_embedded_jtag import OpenOcd
|
||||
|
||||
|
||||
def apptrace_wait_stop(openocd: OpenOcd, timeout: int = 30) -> None:
|
||||
stopped = False
|
||||
end_before = time.time() + timeout
|
||||
while not stopped:
|
||||
cmd_out = openocd.write('esp apptrace status')
|
||||
for line in cmd_out.splitlines():
|
||||
if line.startswith('Tracing is STOPPED.'):
|
||||
stopped = True
|
||||
break
|
||||
if not stopped and time.time() > end_before:
|
||||
raise pexpect.TIMEOUT('Failed to wait for apptrace stop!')
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.jtag
|
||||
@pytest.mark.parametrize(
|
||||
'embedded_services, no_gdb',
|
||||
[
|
||||
('esp,idf,jtag', 'y'),
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_examples_app_trace_to_host(msg_queue: MessageQueue, dut: IdfDut, openocd: OpenOcd, idf_path: str) -> None:
|
||||
dut.expect_exact('example: Enabling ADC1 on channel 6 / GPIO34.')
|
||||
dut.expect_exact('example: Enabling CW generator on DAC channel 0 / GPIO25')
|
||||
dut.expect_exact('example: Sampling ADC and sending data to the host...')
|
||||
dut.expect(r'example: Collected \d+ samples in 20 ms.')
|
||||
dut.expect_exact('example: Sampling ADC and sending data to the UART...')
|
||||
dut.expect(r'example: Sample:\d, Value:\d+')
|
||||
dut.expect(r'example: Collected \d+ samples in 20 ms.')
|
||||
|
||||
assert 'Targets connected.' in dut.openocd.write('esp apptrace start file://adc.log 0 9000 5 0 0')
|
||||
apptrace_wait_stop(dut.openocd)
|
||||
|
||||
with open(openocd._logfile) as oocd_log: # pylint: disable=protected-access
|
||||
cores = 1 if dut.app.sdkconfig.get('CONFIG_FREERTOS_UNICORE') == 'y' else 2
|
||||
params_str = 'App trace params: from {} cores'.format(cores)
|
||||
for line in oocd_log:
|
||||
if params_str in line:
|
||||
break
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'"{}" could not be found in {}'.format(params_str, openocd._logfile) # pylint: disable=protected-access
|
||||
)
|
||||
|
||||
DuplicateStdoutPopen(
|
||||
msg_queue,
|
||||
[
|
||||
os.path.join(idf_path, 'tools', 'esp_app_trace', 'logtrace_proc.py'),
|
||||
'adc.log',
|
||||
os.path.join(dut.app.elf_file),
|
||||
],
|
||||
)
|
||||
|
||||
dut.expect_exact('Parse trace file')
|
||||
dut.expect_exact('Parsing completed.')
|
||||
dut.expect_exact('====================================================================')
|
||||
dut.expect(re.compile(rb'example: Sample:\d+, Value:\d+'))
|
||||
dut.expect_exact('====================================================================')
|
||||
dut.expect(re.compile(rb'Log records count: \d+'))
|
@ -1557,8 +1557,6 @@ examples/storage/spiffsgen/example_test.py
|
||||
examples/storage/spiffsgen/main/spiffsgen_example_main.c
|
||||
examples/storage/wear_levelling/main/wear_levelling_example_main.c
|
||||
examples/storage/wear_levelling/wear_levelling_example_test.py
|
||||
examples/system/app_trace_to_host/example_test.py
|
||||
examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c
|
||||
examples/system/base_mac_address/example_test.py
|
||||
examples/system/base_mac_address/main/base_mac_address_example_main.c
|
||||
examples/system/console/advanced/components/cmd_nvs/cmd_nvs.c
|
||||
|
@ -109,7 +109,6 @@ examples/storage/semihost_vfs/semihost_vfs_example_test.py
|
||||
examples/storage/spiffs/spiffs_example_test.py
|
||||
examples/storage/spiffsgen/example_test.py
|
||||
examples/storage/wear_levelling/wear_levelling_example_test.py
|
||||
examples/system/app_trace_to_host/example_test.py
|
||||
examples/system/base_mac_address/example_test.py
|
||||
examples/system/console/example_test.py
|
||||
examples/system/deep_sleep/example_test.py
|
||||
|
Loading…
x
Reference in New Issue
Block a user