diff --git a/docs/_static/jtag-debugging-overview_zh.jpg b/docs/_static/jtag-debugging-overview_zh.jpg new file mode 100644 index 0000000000..6a50e6a950 Binary files /dev/null and b/docs/_static/jtag-debugging-overview_zh.jpg differ diff --git a/docs/en/api-guides/jtag-debugging/index.rst b/docs/en/api-guides/jtag-debugging/index.rst index 42bcc84eb0..37be58364d 100644 --- a/docs/en/api-guides/jtag-debugging/index.rst +++ b/docs/en/api-guides/jtag-debugging/index.rst @@ -17,7 +17,7 @@ GDB. The document is structured as follows: :ref:`jtag-debugging-launching-debugger` Steps to start up a debug session with GDB from :ref:`jtag-debugging-using-debugger-eclipse` and from :ref:`jtag-debugging-using-debugger-command-line`. :ref:`jtag-debugging-examples` - If you are not familiar with GDB, check this section for debugging examples provided from from :ref:`jtag-debugging-examples-eclipse` as well as from :ref:`jtag-debugging-examples-command-line`. + If you are not familiar with GDB, check this section for debugging examples provided from :ref:`jtag-debugging-examples-eclipse` as well as from :ref:`jtag-debugging-examples-command-line`. :ref:`jtag-debugging-building-openocd` Procedure to build OpenOCD from sources for :doc:`Windows `, :doc:`Linux ` and :doc:`MacOS ` operating systems. :ref:`jtag-debugging-tips-and-quirks` diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index 2c2eae64f9..43e933483d 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -16,7 +16,7 @@ API 指南 FreeRTOS SMP Changes Thread Local Storage High Level Interrupts - JTAG Debugging + JTAG 调试 Bootloader 分区表 Secure Boot <../security/secure-boot> diff --git a/docs/zh_CN/api-guides/jtag-debugging/building-openocd-linux.rst b/docs/zh_CN/api-guides/jtag-debugging/building-openocd-linux.rst index 36c4701ad8..5eb951d080 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/building-openocd-linux.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/building-openocd-linux.rst @@ -1 +1,75 @@ -.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-linux.rst \ No newline at end of file +****************************** +Linux 环境下从源码编译 OpenOCD +****************************** + +除了从 `Espressif 官方 `_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-linux` 章节查阅。 + + +.. highlight:: bash + +下载 OpenOCD 源码 +================= + +支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码:: + + cd ~/esp + git clone --recursive https://github.com/espressif/openocd-esp32.git + +克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。 + + +安装依赖的软件包 +================ + +安装编译 OpenOCD 所需的软件包。 + +.. note:: + + 依次安装以下软件包,检查安装是否成功,然后继续下一个软件包的安装。在进行下一步操作之前,要先解决当前报告的问题。 + +:: + + sudo apt-get install make + sudo apt-get install libtool + sudo apt-get install pkg-config + sudo apt-get install autoconf + sudo apt-get install automake + sudo apt-get install texinfo + sudo apt-get install libusb-1.0 + +.. note:: + + * pkg-config 应为 0.2.3 或以上的版本。 + * autoconf 应为 2.6.4 或以上的版本。 + * automake 应为 1.9 或以上的版本。 + * 当使用 USB-Blaster,ASIX Presto,OpenJTAG 和 FT2232 作为适配器时,需要下载安装 libFTDI 和 FTD2XX 的驱动。 + * 当使用 CMSIS-DAP 时,需要安装 HIDAPI。 + + +构建 OpenOCD +============ + +配置和构建 OpenOCD 的流程如下:: + + cd ~/esp/openocd-esp32 + ./bootstrap + ./configure + make + +你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD,请跳过这个步骤,因为它可能会覆盖掉原来的 OpenOCD。 + +.. note:: + + * 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。 + * 如果 OpenOCD 存在子模块问题,请 ``cd`` 到 ``openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。 + * 如果 ``./configure`` 成功运行,JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。 + * 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。 + * 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README``。 + +一旦 ``make`` 过程成功结束,OpenOCD 的可执行文件会被保存到 ``~/openocd-esp32/bin`` 目录中。 + + +下一步 +====== + +想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。 diff --git a/docs/zh_CN/api-guides/jtag-debugging/building-openocd-macos.rst b/docs/zh_CN/api-guides/jtag-debugging/building-openocd-macos.rst index 70481a7bf3..c95bb69aff 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/building-openocd-macos.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/building-openocd-macos.rst @@ -1 +1,53 @@ -.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-macos.rst \ No newline at end of file +****************************** +MacOS 环境下从源码编译 OpenOCD +****************************** + +除了从 `Espressif 官方 `_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-macos` 章节查阅。 + +.. highlight:: bash + +下载 OpenOCD 源码 +================= + +支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码:: + + cd ~/esp + git clone --recursive https://github.com/espressif/openocd-esp32.git + +克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。 + + +安装依赖的软件包 +================ + +使用 Homebrew 安装编译 OpenOCD 所需的软件包:: + + brew install automake libtool libusb wget gcc@4.9 pkg-config + +构建 OpenOCD +============= + +配置和构建 OpenOCD 的流程如下:: + + cd ~/esp/openocd-esp32 + ./bootstrap + ./configure + make + +你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD,请跳过这个步骤,因为它可能会覆盖掉原来的 OpenOCD。 + +.. note:: + + * 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。 + * 如果 OpenOCD 存在子模块问题,请 ``cd`` 到 ``openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。 + * 如果 ``./configure`` 成功运行,JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。 + * 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。 + * 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README.OSX``。 + +一旦 ``make`` 过程成功结束,OpenOCD 的可执行文件会被保存到 ``~/esp/openocd-esp32/src/openocd`` 目录中。 + +下一步 +====== + +想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。 + \ No newline at end of file diff --git a/docs/zh_CN/api-guides/jtag-debugging/building-openocd-windows.rst b/docs/zh_CN/api-guides/jtag-debugging/building-openocd-windows.rst index 34cef1021f..1aebc9b5b2 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/building-openocd-windows.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/building-openocd-windows.rst @@ -1 +1,74 @@ -.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-windows.rst \ No newline at end of file +******************************** +Windows 环境下从源码编译 OpenOCD +******************************** + +除了从 `Espressif 官方 `_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-windows` 章节查阅。 + + +.. highlight:: bash + +下载 OpenOCD 源码 +================= + +支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码:: + + cd ~/esp + git clone --recursive https://github.com/espressif/openocd-esp32.git + +克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。 + + +安装依赖的软件包 +================ + +安装编译 OpenOCD 所需的软件包。 + +.. note:: + + 依次安装以下软件包,检查安装是否成功,然后继续下一个软件包的安装。在进行下一步操作之前,要先解决当前报告的问题。 + +:: + + pacman -S libtool + pacman -S autoconf + pacman -S automake + pacman -S texinfo + pacman -S mingw-w64-i686-libusb-compat-git + pacman -S pkg-config + +.. note:: + + 安装 ``pkg-config`` 会破坏 esp-idf 的工具链,因而在 OpenOCD 构建完成后,应将其卸载。详见文末进一步说明。如果想要再次构建 OpenOCD,你需要再次运行 ``pacman -S pkg-config``。此步骤安装的其他软件包(在 ``pkg-config`` 之前)并不会出现这一问题。 + + +构建 OpenOCD +============ + +配置和构建 OpenOCD 的流程如下:: + + cd ~/esp/openocd-esp32 + ./bootstrap + ./configure + make + +你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD,请跳过这个步骤,因为它可能会覆盖掉原来的 OpenOCD。 + +.. note:: + + * 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。 + * 如果 OpenOCD 存在子模块问题,请 ``cd`` 到 ``openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。 + * 如果 ``./configure`` 成功运行,JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。 + * 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。 + * 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README.Windows``。 + +一旦 ``make`` 过程成功完成,OpenOCD 的可执行文件会被保存到 ``~/esp/openocd-esp32/src/openocd`` 目录中。 + +如安装依赖步骤所述,最后还需要移除 ``pkg-config`` 软件包:: + + pacman -Rs pkg-config + + +下一步 +====== + +想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。 diff --git a/docs/zh_CN/api-guides/jtag-debugging/configure-other-jtag.rst b/docs/zh_CN/api-guides/jtag-debugging/configure-other-jtag.rst index 720df4b505..147e2d6988 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/configure-other-jtag.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/configure-other-jtag.rst @@ -1 +1,45 @@ -.. include:: ../../../en/api-guides/jtag-debugging/configure-other-jtag.rst \ No newline at end of file +配置其它 JTAG 接口 +================== + +关于适配 OpenOCD 和 ESP32 的 JTAG 接口选择问题,请参考 :ref:`jtag-debugging-selecting-jtag-adapter` 章节,确保 JTAG 适配器能够与 OpenOCD 和 ESP32 一同工作。然后按照以下三个步骤进行设置,使其正常工作。 + + +配置硬件 +^^^^^^^^ + +1. 找到 JTAG 接口和 ESP32 板上需要相互连接并建立通信的引脚/信号。 + + +---+---------------+-----------+ + | | ESP32 引脚 | JTAG 信号 | + +===+===============+===========+ + | 1 | CHIP_PU | TRST_N | + +---+---------------+-----------+ + | 2 | MTDO / GPIO15 | TDO | + +---+---------------+-----------+ + | 3 | MTDI / GPIO12 | TDI | + +---+---------------+-----------+ + | 4 | MTCK / GPIO13 | TCK | + +---+---------------+-----------+ + | 5 | MTMS / GPIO14 | TMS | + +---+---------------+-----------+ + | 6 | GND | GND | + +---+---------------+-----------+ + +2. 检查 ESP32 上用于 JTAG 通信的的引脚是否被连接到了其它硬件上,这可能会影响 JTAG 的工作。 + +3. 连接 ESP32 和 JTAG 接口上的引脚/信号。 + + +配置驱动 +^^^^^^^^ +你可能还需要安装软件驱动,才能使 JTAG 在计算机上正常工作,请参阅你所使用的 JTAG 适配器的有关文档,获取相关详细信息。 + + +连接 +^^^^ + +将 JTAG 接口连接到计算机,打开 ESP32 和 JTAG 接口板上的电源,然后检查计算机是否可以识别到 JTAG 接口。 + + +要继续设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。 + diff --git a/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst b/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst index d79518837d..0b73bbbd3e 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst @@ -1 +1,197 @@ -.. include:: ../../../en/api-guides/jtag-debugging/configure-wrover.rst \ No newline at end of file +配置 WROVER 上的 JTAG 接口 +========================== + +所有版本的 ESP-WROVER-KIT 板子都内置了 JTAG 调试功能,要使其正常工作,还需要设置相关跳帽来启用 JTAG 功能,设置 SPI 闪存电压和配置 USB 驱动程序。具体步骤请参考以下说明。 + + +配置硬件 +^^^^^^^^ + +1. 根据 :doc:`../../get-started/get-started-wrover-kit` 文档中 :ref:`get-started-esp-wrover-kit-setup-options` 章节所描述的信息,设置 JP8 便可以启用 JTAG 功能。 + +2. 检查 ESP32 上用于 JTAG 通信的引脚是否被接到了其它硬件上,这可能会影响 JTAG 的工作。 + + +---+---------------+-----------+ + | | ESP32 引脚 | JTAG 信号 | + +===+===============+===========+ + | 1 | CHIP_PU | TRST_N | + +---+---------------+-----------+ + | 2 | MTDO / GPIO15 | TDO | + +---+---------------+-----------+ + | 3 | MTDI / GPIO12 | TDI | + +---+---------------+-----------+ + | 4 | MTCK / GPIO13 | TCK | + +---+---------------+-----------+ + | 5 | MTMS / GPIO14 | TMS | + +---+---------------+-----------+ + + +配置 USB 驱动 +^^^^^^^^^^^^^ + +安装和配置 USB 驱动,这样 OpenOCD 才能够与 ESP-WROVER-KIT 板上的 JTAG 接口通信,并且使用 UART 接口上传待烧写的镜像文件。请根据你的操作系统按照以下步骤进行安装配置。 + +.. note:: ESP-WROVER-KIT 使用了 FT2232 芯片实现了 JTAG 适配器,所以以下说明同样适用于其他基于 FT2232 的 JTAG 适配器。 + + +Windows +""""""" + +1. 使用标准 USB A / micro USB B 线将 ESP-WROVER-KIT 与计算机相连接,并打开板子的电源。 + +2. 等待 Windows 识别出 ESP-WROVER-KIT 并且为其安装驱动。如果驱动没有被自动安装,请前往 `官网 `_ 下载并手动安装。 + +3. 从 `Zadig 官网 `_ 下载 Zadig 工具(Zadig_X.X.exe)并运行。 + +4. 在 Zadig 工具中,进入 “Options” 菜单中选中 “List All Devices”。 + +5. 检查设备列表,其中应该包含两条与 ESP-WROVER-KIT 相关的条目:“Dual RS232-HS (Interface 0)” 和 “Dual RS232-HS (Interface 1)”。驱动的名字应该是 “FTDIBUS (vxxxx)” 并且 USB ID 为:0403 6010。 + + .. figure:: ../../../_static/jtag-usb-configuration-zadig.jpg + :align: center + :alt: Configuration of JTAG USB driver in Zadig tool + :figclass: align-center + + 在 Zadig 工具中配置 JTAG USB 驱动 + +6. 第一个设备 “Dual RS232-HS(Interface 0)” 连接到了 ESP32 的 JTAG 端口,此设备原来的 “FTDIBUS (vxxxx)” 驱动需要替换成 "WinUSB (v6xxxxx)"。为此,请选择 “Dual RS232-HS (Interface 0)” 并将驱动重新安装为 “WinUSB (v6xxxxx)”,具体可以参考上图。 + +.. note:: + + 请勿更改第二个设备 “Dual RS232-HS(Interface 1)” 的驱动,它被连接到 ESP32 的串口(UART),用于上传应用程序映像给 ESP32 进行烧写。 + +现在,ESP-WROVER-KIT 的 JTAG 接口应该可以被 OpenOCD 使用了,想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。 + + +Linux +""""" + +1. 使用标准 USB A / micro USB B 线将 ESP-WROVER-KIT 与计算机相连接,并打开板子的电源。 + +.. highlight:: none + +2. 打开终端,输入 ``ls -l /dev/ttyUSB*`` 命令检查操作系统是否能够识别板子的 USB 端口。类似识别结果如下: + + :: + + user-name@computer-name:~/esp$ ls -l /dev/ttyUSB* + crw-rw---- 1 root dialout 188, 0 Jul 10 19:04 /dev/ttyUSB0 + crw-rw---- 1 root dialout 188, 1 Jul 10 19:04 /dev/ttyUSB1 + + +3. 根据 `OpenOCD README 文档 `_ 中 “Permissions delegation” 小节的介绍,设置这两个 USB 端口的访问权限。 + +4. 注销并重新登录 Linux 系统,然后重新插拔板子的电源使之前的改动生效。在终端再次输入 ``ls -l /dev/ttyUSB*`` 命令进行验证,查看这两个设备的组所有者是否已经从 ``dialout`` 更改为 ``plugdev``: + + :: + + user-name@computer-name:~/esp$ ls -l /dev/ttyUSB* + crw-rw-r-- 1 root plugdev 188, 0 Jul 10 19:07 /dev/ttyUSB0 + crw-rw-r-- 1 root plugdev 188, 1 Jul 10 19:07 /dev/ttyUSB1 + + 如果看到类似的输出结果,并且你也是 ``plugdev`` 组的成员, 那么设置工作就完成了。 + + 具有较低编号的 ``/dev/ttyUSBn`` 接口用于 JTAG 通信,另一路接口被连接到 ESP32 的串口(UART),用于上传应用程序映像给 ESP32 进行烧写。 + +现在,ESP-WROVER-KIT 的 JTAG 接口应该可以被 OpenOCD 使用了,想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。 + + +MacOS +""""" + +在 macOS 上,同时使用 FT2232 的 JTAG 接口和串口还需另外进行其它操作。当操作系统加载 FTDI 串口驱动的时候,它会对 FT2232 芯片的两个通道做相同的操作。但是,这两个通道中只有一个是被用作串口,而另一个用于 JTAG,如果操作系统已经为用于 JTAG 的通道加载了 FTDI 串口驱动的话,OpenOCD 将无法连接到芯片。有两个方法可以解决这个问题: + +1. 在启动 OpenOCD 之前手动卸载 FTDI 串口驱动程序,然后启动 OpenOCD,再加载串口驱动程序。 + +2. 修改 FTDI 驱动程序的配置,使其不会为 FT2232 芯片的通道 B 进行自我加载,该通道用于 ESP-WROVER-KIT 板上的 JTAG 通道。 + +手动卸载驱动程序 +................ + +1. 从 `FTDI 官网 `_ 安装驱动。 + +2. 使用 USB 线连接 ESP-WROVER-KIT。 + +3. 卸载串口驱动 :: + + sudo kextunload -b com.FTDI.driver.FTDIUSBSerialDriver + + 有时,您可能还需要卸载苹果的 FTDI 驱动:: + + sudo kextunload -b com.apple.driver.AppleUSBFTDI + +4. 运行 OpenOCD(以下路径为 Github 上可供下载的预编译后的 OpenOCD):: + + bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg + + 如果 OpenOCD 是从源码编译得到的,那么路径需要做相应修改:: + + src/openocd -s tcl -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg + +5. 在另一个终端窗口,再一次加载 FTDI 串口驱动:: + + sudo kextload -b com.FTDI.driver.FTDIUSBSerialDriver + +.. include:: ./windows-openocd-note.rst + +.. note:: + + 如果你需要重启 OpenOCD,则无需再次卸载 FTDI 驱动程序,只需停止 OpenOCD 并再次启动它。只有在重新连接 ESP-WROVER-KIT 或者切换了电源的情况下才需要再次卸载驱动。 + +你也可以根据自身需求,将此过程包装进 shell 脚本中。 + +修改 FTDI 驱动 +.............. + +简而言之,这种方法需要修改 FTDI 驱动程序的配置文件,这样可以防止为 FT2232H 的通道 B 自动加载串口驱动。 + +.. note:: 其他板子可能将通道 A 用于 JTAG,因此请谨慎使用此选项。 + +.. warning:: 此方法还需要操作系统禁止对驱动进行签名验证,因此可能无法被所有的用户所接受。 + + +1. 使用文本编辑器打开 FTDI 驱动的配置文件(注意 ``sudo``):: + + sudo nano /Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist + +2. 找到并删除以下几行:: + + FT2232H_B + + CFBundleIdentifier + com.FTDI.driver.FTDIUSBSerialDriver + IOClass + FTDIUSBSerialDriver + IOProviderClass + IOUSBInterface + bConfigurationValue + 1 + bInterfaceNumber + 1 + bcdDevice + 1792 + idProduct + 24592 + idVendor + 1027 + + +3. 保存并关闭文件 + +4. 禁用驱动的签名认证: + + 1. 点击苹果的 logo,选择 “Restart...” + + 2. 重启后当听到响铃时,立即按下键盘上的 CMD+R 组合键 + + 3. 进入恢复模式后,打开终端 + + 4. 运行命令:: + + csrutil enable --without kext + + 5. 再一次重启系统 + +完成这些步骤后,可以同时使用串口和 JTAG 接口了。 + +想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。 diff --git a/docs/zh_CN/api-guides/jtag-debugging/debugging-examples.rst b/docs/zh_CN/api-guides/jtag-debugging/debugging-examples.rst index ee8c9594c0..b11f358dc9 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/debugging-examples.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/debugging-examples.rst @@ -1 +1,654 @@ -.. include:: ../../../en/api-guides/jtag-debugging/debugging-examples.rst \ No newline at end of file +调试示例 +======== + +本节将介绍如何在 :ref:`Eclipse ` 和 :ref:`命令行 ` 中使用 GDB 进行调试的示例。 + +.. highlight:: none + +.. _jtag-debugging-examples-eclipse: + +使用 Eclipse 的调试示例 +----------------------- + +请检查目标板是否已经准备好,并加载了 :example:`get-started/blink` 示例代码,然后按照 :ref:`jtag-debugging-using-debugger-eclipse` 中介绍的步骤配置和启动调试器,最后选择让应用程序在 ``app_main()`` 建立的断点处停止。 + +.. figure:: ../../../_static/debug-perspective.jpg + :align: center + :alt: Debug Perspective in Eclipse + :figclass: align-center + + Eclipse 中的 Debug 视图 + + +本小节的示例 +^^^^^^^^^^^^ + +1. :ref:`jtag-debugging-examples-eclipse-01` +2. :ref:`jtag-debugging-examples-eclipse-02` +3. :ref:`jtag-debugging-examples-eclipse-03` +4. :ref:`jtag-debugging-examples-eclipse-04` +5. :ref:`jtag-debugging-examples-eclipse-05` +6. :ref:`jtag-debugging-examples-eclipse-06` +7. :ref:`jtag-debugging-examples-eclipse-07` + + +.. _jtag-debugging-examples-eclipse-01: + +浏览代码,查看堆栈和线程 +^^^^^^^^^^^^^^^^^^^^^^^^ + +当目标暂停时,调试器会在 “Debug” 窗口中显示线程的列表,程序暂停的代码行在下面的另一个窗口中被高亮显示,如下图所示。此时板子上的 LED 停止了闪烁。 + +.. figure:: ../../../_static/debugging-target-halted.jpg + :align: center + :alt: Target halted during debugging + :figclass: align-center + + 调试时目标停止 + +暂停的程序所在线程也会被展开,显示函数调用的堆栈,它表示直到目标暂停所在代码行(下图高亮处)为止的相关函数的调用关系。1 号线程下函数调用堆栈的第一行包含了最后一个调用的函数 ``app_main()``,根据下一行显示,它又是在函数 ``main_task()`` 中被调用的。堆栈的每一行还包含调用函数的文件名和行号。通过单击每个堆栈的条目,在下面的窗口中,你将看到此文件的内容。 + +通过展开线程,你可以浏览整个应用程序。展开 5 号线程,它包含了更长的函数调用堆栈,你可以看到函数调用旁边的数字,比如 ``0x4000000c``,它们代表未以源码形式提供的二进制代码所在的内存地址。 + +.. figure:: ../../../_static/debugging-navigate-through-the-stack.jpg + :align: center + :alt: Navigate through the call stack + :figclass: align-center + + 浏览函数调用堆栈 + +无论项目是以源代码还是仅以二进制形式提供,在右边一个窗口中,都可以看到反汇编后的机器代码。 + +回到 1 号线程中的 ``app_main()`` 函数所在的 ``blink.c`` 源码文件,下面的示例将会以该文件为例介绍调试的常用功能。调试器可以轻松浏览整个应用程序的代码,这给单步调试代码和设置断点带来了很大的便利,下面将一一展开讨论。 + + +.. _jtag-debugging-examples-eclipse-02: + +设置和清除断点 +^^^^^^^^^^^^^^ + +在调试时,我们希望能够在关键的代码行停止应用程序,然后检查特定的变量、内存、寄存器和外设的状态。为此我们需要使用断点,以便在特定某行代码处快速访问和停止应用程序。 + +我们在控制 LED 状态发生变化的两处代码行分别设置一个断点。基于以上代码列表,这两处分别为第 33 和 36 代码行。按住键盘上的 “Control” 键,双击 blink.c 文件中的行号 33,并在弹出的对话框中点击 “OK” 按钮进行确定。如果你不想看到此对话框,双击行号即可。执行同样操作,在第 36 行设置另外一个断点。 + +.. figure:: ../../../_static/debugging-setting-breakpoint.jpg + :align: center + :alt: Setting a breakpoint + :figclass: align-center + + 设置断点 + +断点的数量和位置信息会显示在右上角的“断点”窗口中。单击 “Show Breakpoints Supported by Selected Target” 图标可以刷新此列表。除了刚才设置的两个断点外,列表中可能还包含在调试器启动时设置在 ``app_main()`` 函数处的临时断点。由于最多只允许设置两个断点(详细信息请参阅 :ref:`jtag-debugging-tip-breakpoints`),你需要将其删除,否则调试会失败。 + +.. figure:: ../../../_static/debugging-three-breakpoints-set.jpg + :align: center + :alt: Three breakpoints are set / maximum two are allowed + :figclass: align-center + + 设置了三个断点 / 最多允许两个断点 + +单击 “Resume”(如果 “Resume” 按钮是灰色的,请先单击 8 号线程的 ``blink_task()`` 函数)后处理器将开始继续运行,并在断点处停止。再一次单击 “Resume” 按钮,使程序再次运行,然后停在第二个断点处,依次类推。 + +每次单击 “Resume” 按钮恢复程序运行后,都会看到 LED 切换状态。 + +更多关于断点的信息,请参阅 :ref:`jtag-debugging-tip-breakpoints` 和 :ref:`jtag-debugging-tip-where-breakpoints`。 + + +.. _jtag-debugging-examples-eclipse-03: + +手动暂停目标 +^^^^^^^^^^^^ + +在调试时,你可以恢复程序运行并输入代码等待某个事件发生或者保持无限循环而不设置任何断点。后者,如果想要返回调试模式,可以通过单击 “Suspend” 按钮来手动中断程序的运行。 + +在此之前,请删除所有的断点,然后单击 “Resume” 按钮。接着单击 “Suspend” 按钮,应用程序会停止在某个随机的位置,此时 LED 也将停止闪烁。调试器将展开线程并高亮显示停止的代码行。 + +.. figure:: ../../../_static/debugging-target-halted-manually.jpg + :align: center + :alt: Target halted manually + :figclass: align-center + + 手动暂停目标 + +在上图所示的情况中,应用程序已经在 ``freertos_hooks.c`` 文件的第 52 行暂停运行,现在你可以通过单击 “Resume” 按钮再次将其恢复运行或者进行下面要介绍的调试工作。 + + +.. _jtag-debugging-examples-eclipse-04: + +单步执行代码 +^^^^^^^^^^^^ + +我们还可以使用 “Step Into (F5)” 和 “Step Over (F6)” 命令单步执行代码, 这两者之间的区别是执行 “Step Into (F5)” 命令会进入调用的子程序,而执行 “Step Over (F6)” 命令则会直接将子程序看成单个源码行,单步就能将其运行结束。 + +在继续演示此功能之前,请参照上文所述确保目前只在 ``blink.c`` 文件的第 36 行设置了一个断点。 + +按下 F8 键让程序继续运行然后在断点处停止运行,多次按下 “Step Over (F6)” 按钮,观察调试器是如何单步执行一行代码的。 + +.. figure:: ../../../_static/debugging-step-over.jpg + :align: center + :alt: Stepping through the code with "Step Over (F6)" + :figclass: align-center + + 使用 “Step Over (F6)” 单步执行代码 + +如果你改用 "Step Into (F5)",那么调试器将会进入调用的子程序内部。 + +.. figure:: ../../../_static/debugging-step-into.jpg + :align: center + :alt: Stepping through the code with "Step Into (F5)" + :figclass: align-center + + 使用 “Step Into (F5)” 单步执行代码 + +在上述例子中,调试器进入 ``gpio_set_level(BLINK_GPIO, 0)`` 代码内部,同时代码窗口快速切换到 ``gpio.c`` 驱动文件。 + +请参阅 :ref:`jtag-debugging-tip-why-next-works-as-step` 文档以了解 ``next`` 命令的潜在局限。 + + +.. _jtag-debugging-examples-eclipse-05: + +查看并设置内存 +^^^^^^^^^^^^^^ + +要显示或者设置内存的内容,请使用“调试”视图中位于底部的 “Memory” 选项卡。 + +在 “Memory” 选项卡下,我们将在内存地址 ``0x3FF44004`` 处读取和写入内容。该地址也是 ``GPIO_OUT_REG`` 寄存器的地址,可以用来控制(设置或者清除)某个 GPIO 的电平。关于该寄存器的更多详细信息,请参阅 `ESP32 技术参考手册 `_ 中的 IO_MUX 和 GPIO Matrix 章节。 + +同样在 ``blink.c`` 项目文件中,在两个 ``gpio_set_level`` 语句的后面各设置一个断点,单击 “Memory” 选项卡,然后单击 “Add Memory Monitor” 按钮,在弹出的对话框中输入 ``0x3FF44004``。 + +按下 F8 按键恢复程序运行,并观察 “Monitor” 选项卡。 + +.. figure:: ../../../_static/debugging-memory-location-on.jpg + :align: center + :alt: Observing memory location 0x3FF44004 changing one bit to ON" + :figclass: align-center + + 观察内存地址 0x3FF44004 处的某个比特被置高 + +每按一下 F8,你就会看到在内存 ``0x3FF44004`` 地址处的一个比特位被翻转(并且 LED 会改变状态)。 + +.. figure:: ../../../_static/debugging-memory-location-off.jpg + :align: center + :alt: Observing memory location 0x3FF44004 changing one bit to ON" + :figclass: align-center + + 观察内存地址 0x3FF44004 处的某个比特被置低 + +要修改内存的数值,请在 “Monitor” 选项卡中找到待修改的内存地址,如前面观察的结果一样,输入特定比特翻转后的值。当按下回车键后,将立即看到 LED 的状态发生了改变。 + +.. _jtag-debugging-examples-eclipse-06: + +观察和设置程序变量 +^^^^^^^^^^^^^^^^^^ + +常见的调试任务是在程序运行期间检查程序中某个变量的值,为了演示这个功能,更新 ``blink.c`` 文件,在 ``blink_task`` 函数的上面添加一个全局变量的声明 ``int i``,然后在 ``while(1)`` 里添加 ``i++``,这样每次 LED 改变状态的时候,变量 ``i`` 都会增加 1。 + +退出调试器,这样就不会与新代码混淆,然后重新构建并烧写代码到 ESP32 中,接着重启调试器。注意,这里不需要我们重启 OpenOCD。 + +一旦程序停止运行,在代码 ``i++`` 处添加一个断点。 + +下一步,在 “Breakpoints” 所在的窗口中,选择 “Expressions” 选项卡。如果该选项卡不存在,请在顶部菜单栏的 Window > Show View > Expressions 中添加这一选项卡。然后在该选项卡中单击 “Add new expression”,并输入 ``i``。 + +按下 F8 继续运行程序,每次程序停止时,都会看到变量 ``i`` 的值在递增。 + +.. figure:: ../../../_static/debugging-watch-variable.jpg + :align: center + :alt: Watching program variable "i" + :figclass: align-center + + 观察程序变量 “i” + + +如想更改 ``i`` 的值,可以在 “Value” 一栏中输入新的数值。按下 “Resume (F8)” 后,程序将从新输入的数字开始递增 ``i``。 + + +.. _jtag-debugging-examples-eclipse-07: + +设置条件断点 +^^^^^^^^^^^^ + +接下来的内容更为有趣,你可能想在一定条件满足的情况下设置断点,然后让程序停止运行。右击断点打开上下文菜单,选择 “Breakpoint Properties”,将 “Type:” 改选为 “Hardware” 然后在 “Condition:” 一栏中输入条件表达式,例如 ``i == 2``。 + +.. figure:: ../../../_static/debugging-setting-conditional-breakpoint.jpg + :align: center + :alt: Setting a conditional breakpoint + :figclass: align-center + + 设置条件断点 + +如果当前 ``i`` 的值小于 ``2`` (如果有需要也可以更改这个阈值)并且程序被恢复运行,那么 LED 就会循环闪烁,直到 ``i == 2`` 条件成立,最后程序停止在该处。 + + +.. _jtag-debugging-examples-command-line: + +使用命令行的调试示例 +-------------------- + +请检查您的目标板是否已经准备好,并加载了 :example:`get-started/blink` 示例代码,然后按照 :ref:`jtag-debugging-using-debugger-command-line` 中介绍的步骤配置和启动调试器,最后选择让应用程序在 ``app_main()`` 建立的断点处停止运行 :: + + Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43 + 43 xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL); + (gdb) + + + +本小节的示例 +^^^^^^^^^^^^ + +1. :ref:`jtag-debugging-examples-command-line-01` +2. :ref:`jtag-debugging-examples-command-line-02` +3. :ref:`jtag-debugging-examples-command-line-03` +4. :ref:`jtag-debugging-examples-command-line-04` +5. :ref:`jtag-debugging-examples-command-line-05` +6. :ref:`jtag-debugging-examples-command-line-06` +7. :ref:`jtag-debugging-examples-command-line-07` + + +.. _jtag-debugging-examples-command-line-01: + +浏览代码,查看堆栈和线程 +^^^^^^^^^^^^^^^^^^^^^^^^ + +当看到 ``(gdb)`` 提示符的时候,应用程序已停止运行,LED 也停止闪烁。 + +要找到代码暂停的位置,输入 ``l`` 或者 ``list`` 命令,调试器会打印出停止点(``blink.c`` 代码文件的第 43 行)附近的几行代码 :: + + (gdb) l + 38 } + 39 } + 40 + 41 void app_main() + 42 { + 43 xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL); + 44 } + (gdb) + + +也可以通过输入 ``l 30, 40`` 等命令来查看特定行号范围内的代码。 + +使用 ``bt`` 或者 ``backtrace`` 来查看哪些函数最终导致了此代码被调用:: + + (gdb) bt + #0 app_main () at /home/user-name/esp/blink/main/./blink.c:43 + #1 0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339 + (gdb) + +输出的第 0 行表示应用程序暂停之前调用的最后一个函数,即我们之前列出的 ``app_main ()``。``app_main ()`` 又被位于 ``cpu_start.c`` 文件第 339 行的 ``main_task`` 函数调用。 + +想查看 ``cpu_start.c`` 文件中 ``main_task`` 函数的上下文,需要输入 ``frame N``,其中 N = 1,因为根据前面的输出,``main_task`` 位于 #1 下:: + + (gdb) frame 1 + #1 0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339 + 339 app_main(); + (gdb) + +输入 ``l`` 将显示一段名为 ``app_main()`` 的代码(在第 339 行):: + + (gdb) l + 334 ; + 335 } + 336 #endif + 337 //Enable allocation in region where the startup stacks were located. + 338 heap_caps_enable_nonos_stack_heaps(); + 339 app_main(); + 340 vTaskDelete(NULL); + 341 } + 342 + (gdb) + +通过打印前面的一些行,你会看到我们一直在寻找的 ``main_task`` 函数:: + + (gdb) l 326, 341 + 326 static void main_task(void* args) + 327 { + 328 // Now that the application is about to start, disable boot watchdogs + 329 REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S); + 330 REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); + 331 #if !CONFIG_FREERTOS_UNICORE + 332 // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack + 333 while (port_xSchedulerRunning[1] == 0) { + 334 ; + 335 } + 336 #endif + 337 //Enable allocation in region where the startup stacks were located. + 338 heap_caps_enable_nonos_stack_heaps(); + 339 app_main(); + 340 vTaskDelete(NULL); + 341 } + (gdb) + +如果要查看其他代码,可以输入 ``i threads`` 命令,则会输出目标板上运行的线程列表:: + + (gdb) i threads + Id Target Id Frame + 8 Thread 1073411336 (dport) 0x400d0848 in dport_access_init_core (arg=) + at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:170 + 7 Thread 1073408744 (ipc0) xQueueGenericReceive (xQueue=0x3ffae694, pvBuffer=0x0, xTicksToWait=1644638200, + xJustPeeking=0) at /home/user-name/esp/esp-idf/components/freertos/./queue.c:1452 + 6 Thread 1073431096 (Tmr Svc) prvTimerTask (pvParameters=0x0) + at /home/user-name/esp/esp-idf/components/freertos/./timers.c:445 + 5 Thread 1073410208 (ipc1 : Running) 0x4000bfea in ?? () + 4 Thread 1073432224 (dport) dport_access_init_core (arg=0x0) + at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:150 + 3 Thread 1073413156 (IDLE) prvIdleTask (pvParameters=0x0) + at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282 + 2 Thread 1073413512 (IDLE) prvIdleTask (pvParameters=0x0) + at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282 + * 1 Thread 1073411772 (main : Running) app_main () at /home/user-name/esp/blink/main/./blink.c:43 + (gdb) + +线程列表显示了每个线程最后一个被调用的函数以及所在的 C 源文件名(如果存在的话)。 + +您可以通过输入 ``thread N`` 进入特定的线程,其中 ``N`` 是线程 ID。我们进入 5 号线程来看一下它是如何工作的:: + + (gdb) thread 5 + [Switching to thread 5 (Thread 1073410208)] + #0 0x4000bfea in ?? () + (gdb) + +然后查看回溯:: + + (gdb) bt + #0 0x4000bfea in ?? () + #1 0x40083a85 in vPortCPUReleaseMutex (mux=) at /home/user-name/esp/esp-idf/components/freertos/./port.c:415 + #2 0x40083fc8 in vTaskSwitchContext () at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:2846 + #3 0x4008532b in _frxt_dispatch () + #4 0x4008395c in xPortStartScheduler () at /home/user-name/esp/esp-idf/components/freertos/./port.c:222 + #5 0x4000000c in ?? () + #6 0x4000000c in ?? () + #7 0x4000000c in ?? () + #8 0x4000000c in ?? () + (gdb) + +如上所示,回溯可能会包含多个条目,方便查看直至目标停止运行的函数调用顺序。如果找不到某个函数的源码文件,将会使用问号 ``??`` 替代,这表示该函数是以二进制格式提供的。像 ``0x4000bfea`` 这样的值是被调用函数所在的内存地址。 + +使用诸如 ``bt``, ``i threads``, ``thread N`` 和 ``list`` 命令可以浏览整个应用程序的代码。这给单步调试代码和设置断点带来很大的便利,下面将一一展开来讨论。 + + +.. _jtag-debugging-examples-command-line-02: + +设置和清除断点 +^^^^^^^^^^^^^^ + +在调试时,我们希望能够在关键的代码行停止应用程序,然后检查特定的变量、内存、寄存器和外设的状态。为此我们需要使用断点,以便在特定某行代码处快速访问和停止应用程序。 + +我们在控制 LED 状态发生变化的两处代码行分别设置一个断点。基于以上代码列表,这两处分别为第 33 和 36 代码行。使用命令 ``break M`` 设置断点,其中 M 是具体的代码行:: + + (gdb) break 33 + Breakpoint 2 at 0x400db6f6: file /home/user-name/esp/blink/main/./blink.c, line 33. + (gdb) break 36 + Breakpoint 3 at 0x400db704: file /home/user-name/esp/blink/main/./blink.c, line 36. + +输入命令 ``c``,处理器将运行并在断点处停止。再次输入 ``c`` 将使其再次运行,并在第二个断点处停止,依此类推:: + + (gdb) c + Continuing. + Target halted. PRO_CPU: PC=0x400DB6F6 (active) APP_CPU: PC=0x400D10D8 + + Breakpoint 2, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:33 + 33 gpio_set_level(BLINK_GPIO, 0); + (gdb) c + Continuing. + Target halted. PRO_CPU: PC=0x400DB6F8 (active) APP_CPU: PC=0x400D10D8 + Target halted. PRO_CPU: PC=0x400DB704 (active) APP_CPU: PC=0x400D10D8 + + Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:36 + 36 gpio_set_level(BLINK_GPIO, 1); + (gdb) + +只有在输入命令 ``c`` 恢复程序运行后才能看到 LED 改变状态。 + +查看已设置断点的数量和位置,请使用命令 ``info break``:: + + (gdb) info break + Num Type Disp Enb Address What + 2 breakpoint keep y 0x400db6f6 in blink_task at /home/user-name/esp/blink/main/./blink.c:33 + breakpoint already hit 1 time + 3 breakpoint keep y 0x400db704 in blink_task at /home/user-name/esp/blink/main/./blink.c:36 + breakpoint already hit 1 time + (gdb) + +请注意,断点序号(在 ``Num`` 栏列出)从 2 开始,这是因为在调试器启动时执行 ``thb app_main`` 命令已经在 ``app_main()`` 函数处建立了第一个断点。由于它是一个临时断点,已经被自动删除,所以没有被列出。 + +要删除一个断点,请输入 ``delete N`` 命令(或者简写成 ``d N``),其中 ``N`` 代表断点序号:: + + (gdb) delete 1 + No breakpoint number 1. + (gdb) delete 2 + (gdb) + +更多关于断点的信息,请参阅 :ref:`jtag-debugging-tip-breakpoints` 和 :ref:`jtag-debugging-tip-where-breakpoints`。 + + +.. _jtag-debugging-examples-command-line-03: + +暂停和恢复应用程序的运行 +^^^^^^^^^^^^^^^^^^^^^^^^ + +在调试时,可以恢复程序运行并输入代码等待某个事件发生或者保持无限循环而不设置任何断点。对于后者,想要返回调试模式,可以通过输入 Ctrl+C 手动中断程序的运行。 + +在此之前,请删除所有的断点,然后输入 ``c`` 恢复程序运行。接着输入 Ctrl+C,应用程序会停止在某个随机的位置,此时 LED 也将停止闪烁。调试器会打印如下信息:: + + (gdb) c + Continuing. + ^CTarget halted. PRO_CPU: PC=0x400D0C00 APP_CPU: PC=0x400D0C00 (active) + [New Thread 1073433352] + + Program received signal SIGINT, Interrupt. + [Switching to Thread 1073413512] + 0x400d0c00 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52 + 52 asm("waiti 0"); + (gdb) + +在上图所示的情况下,应用程序已经在 ``freertos_hooks.c`` 文件的第 52 行暂停运行,现在您可以通过输入 ``c`` 再次将其恢复运行或者进行如下所述的一些调试工作。 + +.. note:: + + 在 MSYS2 的 shell 中输入 Ctrl+C 并不会暂停目标的运行,而是会退出调试器。解决这个问题的方法可以通过 :ref:`使用 Eclipse 来调试 ` 或者参考 http://www.mingw.org/wiki/Workaround_for_GDB_Ctrl_C_Interrupt 里的解决方案。 + + +.. _jtag-debugging-examples-command-line-04: + +单步执行代码 +^^^^^^^^^^^^ + +我们还可以使用 ``step`` 和 ``next`` 命令(可以简写成 ``s`` 和 ``n``)单步执行代码, 这两者之间的区别是执行 “step” 命令会进入调用的子程序内部,而执行 “next” 命令则会直接将子程序看成单个源码行,单步就能将其运行结束。 + +在继续演示此功能之前,请使用前面介绍的 ``break`` 和 ``delete`` 命令,确保目前只在 ``blink.c`` 文件的第 36 行设置了一个断点:: + + (gdb) info break + Num Type Disp Enb Address What + 3 breakpoint keep y 0x400db704 in blink_task at /home/user-name/esp/blink/main/./blink.c:36 + breakpoint already hit 1 time + (gdb) + +输入 ``c`` 恢复程序运行然后等它在断点处停止运行:: + + (gdb) c + Continuing. + Target halted. PRO_CPU: PC=0x400DB754 (active) APP_CPU: PC=0x400D1128 + + Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:36 + 36 gpio_set_level(BLINK_GPIO, 1); + (gdb) + +然后输入 ``n`` 多次,观察调试器是如何单步执行一行代码的:: + + (gdb) n + Target halted. PRO_CPU: PC=0x400DB756 (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DB758 (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DC04C (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DB75B (active) APP_CPU: PC=0x400D1128 + 37 vTaskDelay(1000 / portTICK_PERIOD_MS); + (gdb) n + Target halted. PRO_CPU: PC=0x400DB75E (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400846FC (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DB761 (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DB746 (active) APP_CPU: PC=0x400D1128 + 33 gpio_set_level(BLINK_GPIO, 0); + (gdb) + +如果你输入 ``s``,那么调试器将进入子程序:: + + (gdb) s + Target halted. PRO_CPU: PC=0x400DB748 (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DB74B (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DC04C (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DC04F (active) APP_CPU: PC=0x400D1128 + gpio_set_level (gpio_num=GPIO_NUM_4, level=0) at /home/user-name/esp/esp-idf/components/driver/./gpio.c:183 + 183 GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG); + (gdb) + +上述例子中,调试器进入 ``gpio_set_level(BLINK_GPIO, 0)`` 代码内部,同时代码窗口快速切换到 ``gpio.c`` 驱动文件。 + +请参阅 :ref:`jtag-debugging-tip-why-next-works-as-step` 文档以了解 ``next`` 命令的潜在局限。 + + +.. _jtag-debugging-examples-command-line-05: + +查看并设置内存 +^^^^^^^^^^^^^^ + +使用命令 ``x`` 可以显示内存的内容,配合其余参数还可以调整所显示内存位置的格式和数量。运行 ``help x`` 可以查看更多相关细节。与 ``x`` 命令配合使用的命令是 ``set``,它允许你将值写入内存。 + +为了演示 ``x`` 和 ``set`` 的使用,我们将在内存地址 ``0x3FF44004`` 处读取和写入内容。该地址也是 ``GPIO_OUT_REG`` 寄存器的地址,可以用来控制(设置或者清除)某个 GPIO 的电平。关于该寄存器的更多详细信息,请参阅 `ESP32 技术参考手册 `_ 中的 IO_MUX 和 GPIO Matrix章节。 + +同样在 ``blink.c`` 项目文件中,在两个 ``gpio_set_level`` 语句的后面各设置一个断点。输入两次 ``c`` 命令后停止在断点处,然后输入 ``x /1wx 0x3FF44004`` 来显示 ``GPIO_OUT_REG`` 寄存器的值:: + + (gdb) c + Continuing. + Target halted. PRO_CPU: PC=0x400DB75E (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DB74E (active) APP_CPU: PC=0x400D1128 + + Breakpoint 2, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:34 + 34 vTaskDelay(1000 / portTICK_PERIOD_MS); + (gdb) x /1wx 0x3FF44004 + 0x3ff44004: 0x00000000 + (gdb) c + Continuing. + Target halted. PRO_CPU: PC=0x400DB751 (active) APP_CPU: PC=0x400D1128 + Target halted. PRO_CPU: PC=0x400DB75B (active) APP_CPU: PC=0x400D1128 + + Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:37 + 37 vTaskDelay(1000 / portTICK_PERIOD_MS); + (gdb) x /1wx 0x3FF44004 + 0x3ff44004: 0x00000010 + (gdb) + +如果闪烁的 LED 连接到了 GPIO4,那么每次 LED 改变状态时你会看到第 4 比特被翻转:: + + 0x3ff44004: 0x00000000 + ... + 0x3ff44004: 0x00000010 + +现在,当 LED 熄灭时,与之对应地会显示 ``0x3ff44004: 0x00000000``,尝试使用 ``set`` 命令向相同的内存地址写入 ``0x00000010`` 来将该比特置高:: + + (gdb) x /1wx 0x3FF44004 + 0x3ff44004: 0x00000000 + (gdb) set {unsigned int}0x3FF44004=0x000010 + +在输入 ``set {unsigned int}0x3FF44004=0x000010`` 命令后,你会立即看到 LED 亮起。 + + +.. _jtag-debugging-examples-command-line-06: + +观察和设置程序变量 +^^^^^^^^^^^^^^^^^^ + +常见的调试任务是在程序运行期间检查程序中某个变量的值,为了能够演示这个功能,更新 ``blink.c`` 文件,在 ``blink_task`` 函数的上面添加一个全局变量的声明 ``int i``,然后在 ``while(1)`` 里添加 ``i++``,这样每次 LED 改变状态的时候,变量 ``i`` 都会增加 1。 + +退出调试器,这样就不会与新代码混淆,然后重新构建并烧写代码到 ESP32 中,接着重启调试器。注意,这里不需要我们重启 OpenOCD。 + +一旦程序停止运行,输入命令 ``watch i``:: + + (gdb) watch i + Hardware watchpoint 2: i + (gdb) + +这会在所有变量 ``i`` 发生改变的代码处插入所谓的“观察点”。现在输入 ``continue`` 命令来恢复应用程序的运行并观察它停止:: + + (gdb) c + Continuing. + Target halted. PRO_CPU: PC=0x400DB751 (active) APP_CPU: PC=0x400D0811 + [New Thread 1073432196] + + Program received signal SIGTRAP, Trace/breakpoint trap. + [Switching to Thread 1073432196] + 0x400db751 in blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:33 + 33 i++; + (gdb) + +多次恢复程序运行后,变量 ``i`` 的值会增加,现在你可以输入 ``print i`` (简写 ``p i``)来查看当前 ``i`` 的值:: + + (gdb) p i + $1 = 3 + (gdb) + +要修改 ``i`` 的值,请使用 ``set`` 命令,如下所示(可以将其打印输出来查看是否确已修改):: + + (gdb) set var i = 0 + (gdb) p i + $3 = 0 + (gdb) + +最多可以使用两个观察点,详细信息请参阅 :ref:`jtag-debugging-tip-breakpoints`。 + + +.. _jtag-debugging-examples-command-line-07: + +设置条件断点 +^^^^^^^^^^^^ + +接下来的内容更为有趣,你可能想在一定条件满足的情况下设置断点。请先删除已有的断点,然后尝试如下命令:: + + (gdb) break blink.c:34 if (i == 2) + Breakpoint 3 at 0x400db753: file /home/user-name/esp/blink/main/./blink.c, line 34. + (gdb) + +以上命令在 ``blink.c`` 文件的 ``34`` 处设置了一个条件断点,当 ``i==2`` 条件满足时,程序会停止运行。 + +如果当前 ``i`` 的值小于 ``2`` 并且程序被恢复运行,那么 LED 就会循环闪烁,直到 ``i == 2`` 条件成立,最后程序停止在该处:: + + (gdb) set var i = 0 + (gdb) c + Continuing. + Target halted. PRO_CPU: PC=0x400DB755 (active) APP_CPU: PC=0x400D112C + Target halted. PRO_CPU: PC=0x400DB753 (active) APP_CPU: PC=0x400D112C + Target halted. PRO_CPU: PC=0x400DB755 (active) APP_CPU: PC=0x400D112C + Target halted. PRO_CPU: PC=0x400DB753 (active) APP_CPU: PC=0x400D112C + + Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:34 + 34 gpio_set_level(BLINK_GPIO, 0); + (gdb) + + +获得命令的帮助信息 +^^^^^^^^^^^^^^^^^^ + +目前所介绍的都是些非常基础的命令,目的在于让您快速上手 JTAG 调试。如果想获得特定命令的语法和功能相关的信息,请在 ``(gdb)`` 提示符下输入 ``help`` 和命令名:: + + (gdb) help next + Step program, proceeding through subroutine calls. + Usage: next [N] + Unlike "step", if the current source line calls a subroutine, + this command does not enter the subroutine, but instead steps over + the call, in effect treating it as a single source line. + (gdb) + +只需输入 ``help`` 命令,即可获得高级命令列表,帮助你了解更多详细信息。此外,还可以参考一些 GDB 命令速查表,比如 http://darkdust.net/files/GDB%20Cheat%20Sheet.pdf。虽然不是所有命令都适用于嵌入式环境,但还是会有所裨益。 + + +结束调试会话 +^^^^^^^^^^^^ + +输入命令 ``q`` 可以退出调试器:: + + (gdb) q + A debugging session is active. + + Inferior 1 [Remote target] will be detached. + + Quit anyway? (y or n) y + Detaching from program: /home/user-name/esp/blink/build/blink.elf, Remote target + Ending remote debugging. + user-name@computer-name:~/esp/blink$ diff --git a/docs/zh_CN/api-guides/jtag-debugging/index.rst b/docs/zh_CN/api-guides/jtag-debugging/index.rst index 8a42b5678f..d1c8ef59e0 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/index.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/index.rst @@ -1 +1,307 @@ -.. include:: ../../../en/api-guides/jtag-debugging/index.rst \ No newline at end of file +JTAG 调试 +========= + +本文将指导安装 ESP32 的 OpenOCD 调试环境,并介绍如何使用 GDB 来调试 ESP32 的应用程序。本文的组织结构如下: + +:ref:`jtag-debugging-introduction` + 介绍本指南主旨。 +:ref:`jtag-debugging-how-it-works` + 介绍 ESP32,JTAG(Joint Test Action Group)接口,OpenOCD 和 GDB 是如何相互连接从而实现 ESP32 的调试功能。 +:ref:`jtag-debugging-selecting-jtag-adapter` + 介绍有关 JTAG 硬件适配器的选择及参照标准。 +:ref:`jtag-debugging-setup-openocd` + 介绍如何在 :doc:`Windows `,:doc:`Linux ` 和 :doc:`MacOS ` 操作系统上安装预编译好的 OpenOCD 软件包。 +:ref:`jtag-debugging-configuring-esp32-target` + 介绍如何设置 OpenOCD 软件并安装 JTAG 硬件适配器,这两者共同组成最终的调试目标。 +:ref:`jtag-debugging-launching-debugger` + 介绍如何从 :ref:`Eclipse 集成开发环境 ` 和 :ref:`命令行终端 ` 启动 GDB 调试会话。 +:ref:`jtag-debugging-examples` + 如果你对 GDB 不太熟悉,本小节会分别针对 :ref:`Eclipse 集成开发环境 ` 和 :ref:`命令行终端 ` 来讲解调试的范例。 +:ref:`jtag-debugging-building-openocd` + 介绍如何在 :doc:`Windows `,:doc:`Linux ` 和 :doc:`MacOS ` 操作系统上从源码构建 OpenOCD。 +:ref:`jtag-debugging-tips-and-quirks` + 介绍使用 OpenOCD 和 GDB 通过 JTAG 接口调试 ESP32 时的注意事项和补充内容。 + +.. _jtag-debugging-introduction: + +引言 +---- + +ESP32 具有两个强大的 Xtensa 内核,支持多种程序架构。ESP-IDF 自带的 FreeRTOS 操作系统具有多核抢占式多线程的功能,它允许用户以更加直观的方式编写软件。 + +与此相对地,简便的编程方式会给程序的调试带来困难(如果没有合适的工具),比如找出由两个线程引起的错误,并且这两个线程在单独的 CPU 核上同时运行,仅凭 ``printf`` 语句会花费很长的时间来定位到该错误。在大多数情况下,调试此类问题更快的方法是使用调试器,连接到处理器的调试端口。 + +乐鑫已经为 ESP32 处理器和多核 FreeRTOS 架构移植好了 OpenOCD,它将成为大多数 ESP32 应用程序的基础。此外,乐鑫还提供了一些 OpenOCD 本身并不支持的工具来进一步丰富调试的功能。 + +本文将指导如何在 Linux,Windows 和 MacOS 环境下为 ESP32 安装 OpenOCD,并使用 GDB 进行软件调试。除了个别操作系统的安装过程有所差别以外,软件用户界面和使用流程都是一样的。 + +.. note:: + 本文使用的图片素材来自于 Ubuntu 16.04 LTE 上 Eclipse Neon 3 软件的截图,不同的操作系统(Windows, MacOS 或者 Linux)和 Eclipse 软件版本在用户界面上可能会有细微的差别。 + +.. _jtag-debugging-how-it-works: + +工作原理 +-------- + +通过 JTAG(Joint Test Action Group)接口使用 OpenOCD 调试 ESP32 时所需要的一些关键的软件和硬件包括 **xtensa-esp32-elf-gdb +调试器**,**OpenOCD 片上调试器** 和连接到 **ESP32** 目标的 **JTAG 适配器**。 + +.. figure:: ../../../_static/jtag-debugging-overview_zh.jpg + :align: center + :alt: JTAG debugging - overview diagram + :figclass: align-center + + JTAG 调试 - 概述图 + +在 “Application Loading and Monitoring” 下还有另外一组软件和硬件,它们用来编译、构建和烧写应用程序到 ESP32 上,以及监视来自 ESP32 的运行诊断信息。 + +`Eclipse `__ 环境集成了 JTAG 调试和应用程序加载、监视的功能,它使得软件从编写、编译、加载到调试的迭代过程变得更加快速而简单。所有的软件均适用于 Windows,Linux 和 MacOS 平台。 + +如果你使用的是 :doc:`ESP-WROVER-KIT 开发板 <../../hw-reference/modules-and-boards>`,得益于板载的 FT232H 芯片,PC 和 ESP32 的连接仅仅需要一根 USB 线即可完成。FT232H 提供了两路 USB 通道,一路连接到 JTAG,另一路连接到 UART。 + +根据用户的喜好,除了使用 Eclipse 集成开发环境,上述的调试工具和构建工具还可以直接在命令行终端运行。 + +.. _jtag-debugging-selecting-jtag-adapter: + +选择 JTAG 适配器 +---------------- + +上手 JTAG 最快速便捷的方式是使用 :doc:`ESP-WROVER-KIT 开发板 <../../hw-reference/modules-and-boards>`,因为它板载了 JTAG 调试接口,无需使用外部的 JTAG 硬件适配器和额外的线缆来连接 JTAG 与 ESP32。ESP-WROVER-KIT 采用 FT2232H 提供的 JTAG 接口,可以稳定运行在 20 MHz 的时钟频率,外接的适配器很难达到这个速度。 + +如果你想使用单独的 JTAG 适配器,请确保其与 ESP32 的电平电压和 OpenOCD 软件都兼容。ESP32 使用的是业界标准的 JTAG 接口,它省略了(实际上也并不需要)TRST 信号脚。JTAG 使用的 IO 引脚由 VDD_3P3_RTC 电源引脚供电(通常连接到外部 3.3 V 的电源轨),因此 JTAG 硬件适配器的引脚需要能够在该电压范围内正常工作。 + +在软件方面,OpenOCD 支持相当多数量的 JTAG 适配器,可以参阅 `OpenOCD 支持的适配器列表 `_ (尽管上面显示的器件不太完整),这个页面还列出了兼容 SWD 接口的适配器,但是请注意,ESP32 目前并不支持 SWD。此外那些被硬编码为只支持特定产品线的 JTAG 适配器也不能在 ESP32 上工作,比如用于 STM32 产品家族的 ST-LINK 适配器。 + +JTAG 正常工作至少需要连接的信号线有:TDI,TDO,TCK,TMS 和 GND。某些 JTAG 适配器还需要 ESP32 提供一路电源到适配器的某个引脚上(比如 Vtar)用以设置适配器的工作电压。SRST 信号线是可选的,它可以连接到 ESP32 的 CH_PD 引脚上,尽管目前 OpenOCD 对该信号线的支持还非常有限。 + + +.. _jtag-debugging-setup-openocd: + +安装 OpenOCD +------------ + +本节会介绍 OpenOCD 软件包的安装,如果你想从源码构建 OpenOCD,请参阅 :ref:`jtag-debugging-building-openocd`。默认所有 OpenOCD 相关的文件都会被存放到 ``~/esp/openocd-esp32`` 目录下,你也可以选择任何其它的目录,但相应地,你也需要调整本文档示例中使用的相对路径。 + +.. toctree:: + :hidden: + + Windows + Linux + MacOS + +从下面选择你使用的操作系统,并按照提示进一步设置 OpenOCD。 + ++-------------------+-------------------+-------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-------------------+-------------------+-------------------+ +| `Windows`_ | `Linux`_ | `Mac OS`_ | ++-------------------+-------------------+-------------------+ + +.. |windows-logo| image:: ../../../_static/windows-logo.png + :target: ../jtag-debugging/setup-openocd-windows.html + +.. |linux-logo| image:: ../../../_static/linux-logo.png + :target: ../jtag-debugging/setup-openocd-linux.html + +.. |macos-logo| image:: ../../../_static/macos-logo.png + :target: ../jtag-debugging/setup-openocd-macos.html + +.. _Windows: setup-openocd-windows.html +.. _Linux: setup-openocd-linux.html +.. _Mac OS: setup-openocd-macos.html + +安装完成后,请熟悉一下 ``openocd-esp32`` 安装路径下的两个关键目录: + +- ``bin`` 目录下包含了 OpenOCD 的可执行文件 +- ``share\openocd\scripts`` 目录下包含了一些配置文件,它们会作为命令行参数与 OpenOCD 一同被调用 + +.. note:: + + 上面的目录名称和结构特定于 OpenOCD 的二进制发行版,它们会被用在本指南中的 OpenOCD 示例中。从源码构建得到的 OpenOCD 存放的目录可能会不一样,所以调用 OpenOCD 的方式也会略有不同。更多详细信息请参阅 :ref:`jtag-debugging-building-openocd`。 + + +.. _jtag-debugging-configuring-esp32-target: + +配置 ESP32 目标板 +----------------- + +安装好 OpenOCD 之后就可以配置 ESP32 目标(即带 JTAG 接口的 ESP32 板),具体可以通过以下三个步骤进行: + +- 配置并连接 JTAG 接口 +- 运行 OpenOCD +- 上传待调试的应用程序 + + +配置并连接 JTAG 接口 +~~~~~~~~~~~~~~~~~~~~ + +此步骤取决于您使用的 JTAG 和 ESP32 板,请参考以下两种情况。 + +.. toctree:: + :maxdepth: 1 + + configure-wrover + configure-other-jtag + + +.. _jtag-debugging-run-openocd: + +运行 OpenOCD +~~~~~~~~~~~~ + +配置完目标并将其连接到电脑后,即可启动 OpenOCD。 + +.. highlight:: bash + +打开终端,进入安装目录并启动 OpenOCD:: + + cd ~/esp/openocd-esp32 + bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg + +.. note:: + + 如上所示,``-f`` 后面的文件是特定于板载 :ref:`ESP-WROOM-32 ` 模组的 ESP-WROVER-KIT 开发板的。您可能需要根据具体使用的硬件而提供不同的配置文件,相关指导请参阅 :ref:`jtag-debugging-tip-openocd-configure-target`。 + +.. include:: ./windows-openocd-note.rst + +.. highlight:: none + +现在应该可以看到类似下面的输出(此日志来自 ESP-WROVER-KIT):: + + user-name@computer-name:~/esp/openocd-esp32$ bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg + Open On-Chip Debugger 0.10.0-dev-ged7b1a9 (2017-07-10-07:16) + Licensed under GNU GPL v2 + For bug reports, read + http://openocd.org/doc/doxygen/bugs.html + none separate + adapter speed: 20000 kHz + force hard breakpoints + Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi_tdo_sample_edge falling" + Info : clock speed 20000 kHz + Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1) + Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1) + Info : esp32: Debug controller was reset (pwrstat=0x5F, after clear 0x0F). + Info : esp32: Core was reset (pwrstat=0x5F, after clear 0x0F). + +- 如果出现指示权限问题的错误,请参阅 ``~/esp/openocd-esp32`` 目录下 OpenOCD README 文件中关于 “Permissions delegation” 的说明。 +- 如果发现配置文件有错误,例如 ``Can't find interface/ftdi/esp32_devkitj_v1.cfg``,请检查 ``-s`` 后面的路径,OpenOCD 会根据此路径来查找 ``-f`` 指定的文件。此外,还需要检查配置文件是否确实位于该路径下。 +- 如果看到 JTAG 错误(输出全是 1 或者全是 0),请检查硬件连接,除了 ESP32 的引脚之外是否还有其他信号连接到了 JTAG,并查看是否所有器件都已经上电。 + + +.. _jtag-upload-app-debug: + +上传待调试的应用程序 +~~~~~~~~~~~~~~~~~~~~ + +您可以像往常一样构建并上传 ESP32 应用程序,具体请参阅 :ref:`get-started-build-flash` 章节。 + +除此以外,还支持使用 OpenOCD 通过 JTAG 接口将应用程序镜像烧写到闪存中,命令如下:: + + cd ~/esp/openocd-esp32 + bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg -c "program_esp32 filename.bin 0x10000 verify exit" + +.. include:: ./windows-openocd-note.rst + +其中 OpenOCD 的烧写命令 ``program_esp32`` 具有以下格式: + +``program_esp32 [verify] [reset] [exit]`` + + - ``image_file`` - 程序镜像文件存放的路径 + - ``offset`` - 镜像烧写到闪存中的偏移地址 + - ``verify`` - 烧写完成后校验闪存中的内容(可选) + - ``reset`` - 烧写完成后重启目标(可选) + - ``exit`` - 烧写完成后退出 OpenOCD(可选) + +现在可以进行应用程序的调试了,请按照以下章节中讲解的步骤进行操作。 + + +.. _jtag-debugging-launching-debugger: + +启动调试器 +---------- + +ESP32 的工具链中带有 GNU 调试器(简称 GDB) ``xtensa-esp32-elf-gdb``,它和其它工具链软件存放在同一个 bin 目录下。除了直接在命令行终端中调用并操作 GDB 外,还可以在 IDE (例如 Eclipse,Visual Studio Code 等)中调用它,在图形用户界面的帮助下间接操作 GDB,无需在终端中输入任何命令。 + +关于以上两种调试器的使用方法,详见以下链接。 + +* :ref:`jtag-debugging-using-debugger-eclipse` +* :ref:`jtag-debugging-using-debugger-command-line` + +建议首先检查调试器是否能在 :ref:`命令行终端 ` 下正常工作,然后再转到使用 Eclipse 等 :ref:`集成开发环境 ` 下进行调试工作。 + + +.. _jtag-debugging-examples: + +调试范例 +-------- + +本节适用于不熟悉 GDB 的用户,将使用 :example:`get-started/blink` 下简单的应用程序来演示 :ref:`调试会话的工作流程 `,同时会介绍以下常用的调试操作: + +1. :ref:`jtag-debugging-examples-eclipse-01` +2. :ref:`jtag-debugging-examples-eclipse-02` +3. :ref:`jtag-debugging-examples-eclipse-03` +4. :ref:`jtag-debugging-examples-eclipse-04` +5. :ref:`jtag-debugging-examples-eclipse-05` +6. :ref:`jtag-debugging-examples-eclipse-06` +7. :ref:`jtag-debugging-examples-eclipse-07` + +此外还会提供 :ref:`在命令行终端进行调试 ` 的案例。 + +在演示之前,请设置好 ESP32 目标板并加载 :example:`get-started/blink` 至 ESP32 中。 + + +.. _jtag-debugging-building-openocd: + +从源码构建 OpenOCD +------------------ + +请参阅以下文档,它们分别介绍了在各大操作系统平台上从源码构建 OpenOCD 的流程。 + +.. toctree:: + :maxdepth: 1 + + Windows + Linux + MacOS + +.. note:: + + 本文档演示所使用的 OpenOCD 是 :ref:`jtag-debugging-setup-openocd` 章节中介绍的预编译好的二进制发行版,如果要使用本地从源代码构建得到的 OpenOCD 程序,需要将相应可执行文件的路径修改为 ``src/openocd``,并将配置文件的路径修改为 ``-s tcl``。 + + 具体使用示例如下:: + + src/openocd -s tcl -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg + + +.. _jtag-debugging-tips-and-quirks: + +注意事项和补充内容 +-------------------- + +本节列出了本指南中提到的所有注意事项和补充内容的链接。 + +* :ref:`jtag-debugging-tip-breakpoints` +* :ref:`jtag-debugging-tip-where-breakpoints` +* :ref:`jtag-debugging-tip-flash-mappings` +* :ref:`jtag-debugging-tip-why-next-works-as-step` +* :ref:`jtag-debugging-tip-code-options` +* :ref:`jtag-debugging-tip-freertos-support` +* :ref:`jtag-debugging-tip-code-flash-voltage` +* :ref:`jtag-debugging-tip-optimize-jtag-speed` +* :ref:`jtag-debugging-tip-debugger-startup-commands` +* :ref:`jtag-debugging-tip-openocd-configure-target` +* :ref:`jtag-debugging-tip-reset-by-debugger` +* :ref:`jtag-debugging-tip-jtag-pins-reconfigured` +* :ref:`jtag-debugging-tip-reporting-issues` + + +相关文档 +-------- + +.. toctree:: + :maxdepth: 1 + + using-debugger + debugging-examples + tips-and-quirks + ../app_trace diff --git a/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-linux.rst b/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-linux.rst index 16059fc9c5..15154c8c1d 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-linux.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-linux.rst @@ -1 +1,34 @@ -.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-linux.rst \ No newline at end of file +*************************** +在 Linux 环境下安装 OpenOCD +*************************** + + +安装 OpenOCD +============ + +64 位 Linux 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载: + +https://github.com/espressif/openocd-esp32/releases + +下载文件名称包含 `linux64` 字样的最新发布的归档文件,例如 `openocd-esp32-linux64-0.10.0-esp32-20180418.tar.gz`。 + +将该文件解压缩到 ``~/esp/`` 目录下:: + + cd ~/esp + tar -xzf ~/Downloads/openocd-esp32-linux64-.tar.gz + + +下一步 +====== + +进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。 + + +相关文档 +======== + +.. toctree:: + :maxdepth: 1 + + building-openocd-linux + diff --git a/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-macos.rst b/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-macos.rst index fd8f49ba61..0b1d76bf8f 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-macos.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-macos.rst @@ -1 +1,39 @@ -.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-macos.rst \ No newline at end of file +*************************** +在 MacOS 环境下安装 OpenOCD +*************************** + + +安装 libusb +=========== + +使用 `Homebrew `_ 或者 `Macports `_ 来安装 `libusb` 软件包。 + +安装 OpenOCD +============ + +MacOS 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载: + +https://github.com/espressif/openocd-esp32/releases + +下载文件名包含 `macos` 字样的最新发布的归档文件,例如 `openocd-esp32-macos-0.10.0-esp32-20180418.tar.gz`。 + +将该文件解压缩到 ``~/esp/`` 目录下:: + + cd ~/esp + tar -xzf ~/Downloads/openocd-esp32-macos-.tar.gz + + +下一步 +====== + +进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。 + + +相关文档 +======== + +.. toctree:: + :maxdepth: 1 + + building-openocd-macos + diff --git a/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst b/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst index cb3368c6ae..5531c04421 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst @@ -1 +1,38 @@ -.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-windows.rst \ No newline at end of file +***************************** +在 Windows 环境下安装 OpenOCD +***************************** + +IDF 工具安装程序 +================ + +如果您正在使用 CMake 构建系统,并遵循 :doc:`/get-started-cmake/windows-setup` 章节的指导使用了 ``ESP-IDF Tools Installer`` 的 V1.2 及其以上版本,那么默认情况下您已经安装好了 ``OpenOCD`` 软件。 + +``ESP-IDF Tools Installer`` 会将 ``OpenOCD`` 添加到环境变量 ``PATH`` 中,这样你就可以在任何目录运行它。 + +安装 OpenOCD +============ + +Windows 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载: + +https://github.com/espressif/openocd-esp32/releases + +下载文件名包含 `win32` 字样的最新发布的归档文件,例如 `openocd-esp32-macos-0.10.0-win32-20180418.zip`。 + +将该文件解压缩到 ``~/esp/`` 目录下:: + + cd ~/esp + unzip /c/Users//Downloads/openocd-esp32-win32-.zip + +下一步 +====== + +进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。 + + +相关文档 +======== + +.. toctree:: + :maxdepth: 1 + + building-openocd-windows diff --git a/docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst b/docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst index aaf7dfadfd..f20af93fde 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst @@ -1 +1,281 @@ -.. include:: ../../../en/api-guides/jtag-debugging/tips-and-quirks.rst \ No newline at end of file +注意事项和补充内容 +------------------ + +本节提供了本指南中各部分提到的一些注意事项和补充内容。 + +.. _jtag-debugging-tip-breakpoints: + +可用的断点和观察点 +^^^^^^^^^^^^^^^^^^ + +ESP32 调试器支持 2 个硬件断点和 64 个软件断点。硬件断点是由 ESP32 芯片内部的逻辑电路实现的,能够设置在代码的任何位置:闪存或者 IRAM 的代码区域。除此以外,OpenOCD 实现了两种软件断点:闪存断点(最多 32 个)和 IRAM 断点(最多 32 个)。目前 GDB 无法在闪存中设置软件断点,因此除非解决此限制,否则这些断点只能由 OpenOCD 模拟为硬件断点。(详细信息可以参阅 :ref:`下面 `)。ESP32 还支持 2 个观察点,所以可以观察两个变量的变化或者通过 GDB 命令 ``watch myVariable`` 来读取变量的值。请注意 menuconfig 中的 :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 选项会使用第二个观察点,如果你想在 OpenOCD 或者 GDB 中再次尝试使用这个观察点,可能不会得到预期的结果。详情请查看 menuconfig 中的帮助文档。 + + +.. _jtag-debugging-tip-where-breakpoints: + +关于断点的补充知识 +^^^^^^^^^^^^^^^^^^ + +使用软件闪存模拟部分硬件断点的意思就是当使用 GDB 命令 ``hb myFunction`` 给某个函数设置硬件断点时,如果该函数位于闪存中,并且此时还有可用的硬件断点,那调试器就会使用硬件断点,否则就使用 32 个软件闪存断点中的一个来模拟。这个规则同样适用于 ``b myFunction`` 之类的命令,在这种情况下,GDB 会自己决定该使用哪种类型的断点。如果 ``myFunction`` 位于可写区域(IRAM),那就会使用软件 IRAM 断点,否则就会像处理 ``hb`` 命令一样使用硬件断点或者软件闪存断点。 + + +.. _jtag-debugging-tip-flash-mappings: + +闪存映射 vs 软件闪存断点 +^^^^^^^^^^^^^^^^^^^^^^^^ + +为了在闪存中设置或者清除软件断点,OpenOCD 需要知道它们在闪存中的地址。为了完成从 ESP32 的地址空间到闪存地址的转换,OpenOCD 使用闪存中程序代码区域的映射。这些映射被保存在程序映像的头部,位于二进制数据(代码段和数据段)之前,并且特定于写入闪存的每一个应用程序的映像。因此,为了支持软件闪存断点,OpenOCD 需要知道待调试的应用程序映像在闪存中的位置。默认情况下,OpenOCD 会在 0x8000 处读取分区表并使用第一个找到的应用程序映像的映射,但是也可能会存在无法工作的情况,比如分区表不在标准的闪存位置,甚至可能有多个映像:一个出厂映像和两个 OTA 映像,你可能想要调试其中的任意一个。为了涵盖所有可能的调试情况,OpenOCD 支持特殊的命令,用于指定待调试的应用程序映像在闪存中的具体位置。该命令具有以下格式: + +``esp32 appimage_offset `` + +偏移量应为十六进制格式,如果要恢复默认行为,可以将偏移地址设置为 ``-1`` 。 + +.. note:: + + 由于 GDB 在连接 OpenOCD 时仅仅请求一次内存映射,所以可以在 TCL 配置文件中指定该命令,或者通过命令行传递给 OpenOCD。对于后者,命令行示例如下: + + ``bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg -c "init; halt; esp32 appimage_offset 0x210000"`` + + 另外还可以通过 OpenOCD 的 telnet 会话执行该命令,然后再连接 GDB, 不过这种方式似乎没有那么便捷。 + +.. _jtag-debugging-tip-why-next-works-as-step: + +“next” 命令无法跳过子程序的原因 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +当使用 ``next`` 命令单步执行代码时, GDB 会在子程序的前面设置一个断点(两个中可用的一个),这样就可以跳过进入子程序内部的细节。如果这两个断点已经用在代码的其它位置,那么 ``next`` 命令将不起作用。在这种情况下,请删掉一个断点以使其中一个变得可用。当两个断点都已经被使用时,``next`` 命令会像 ``step`` 命令一样工作,调试器就会进入子程序内部。 + + +.. _jtag-debugging-tip-code-options: + +OpenOCD 支持的编译时的选项 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ESP-IDF 有一些针对 OpenOCD 调试功能的选项可以在编译时进行设置: + +* :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` 默认会被使能。如果程序抛出了不可修复或者未处理的异常,并且此时已经连接上了 JTAG 调试器(即 OpenOCD 正在运行),那么 ESP-IDF 将会进入调试器工作模式。 +* :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 默认没有使能。在所有任务堆栈的末尾设置观察点,从 1 号开始索引。这是调试任务堆栈溢出的最准确的方式。 + +更多有关设置编译时的选项的信息,请参阅 :ref:`make menuconfig `。 + +.. _jtag-debugging-tip-freertos-support: + +支持FreeRTOS +^^^^^^^^^^^^ + +OpenOCD 完全支持 ESP-IDF 自带的 FreeRTOS 操作系统,GDB 会将 FreeRTOS 中的任务当做线程。使用 GDB 命令 ``i threads`` 可以查看所有的线程,使用命令 ``thread n`` 可以切换到某个具体任务的堆栈,其中 ``n`` 是线程的编号。检测 FreeRTOS 的功能可以在配置目标时被禁用。更多详细信息,请参阅 :ref:`jtag-debugging-tip-openocd-configure-target`. + + +.. _jtag-debugging-tip-code-flash-voltage: + +在 OpenOCD 的配置文件中设置 SPI 闪存的工作电压 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ESP32 的 MTDI 引脚是用于 JTAG 通信的四个引脚之一,同时也是 ESP32 的 bootstrapping 引脚。上电时,ESP32 会在 MTDI 引脚上采样二进制电平,据此来设置内部的稳压器,用于给外部的 SPI 闪存芯片供电。如果上电时 MTDI 引脚上的二进制电平为低电平,则稳压器会被设置为 3.3 V;如果 MTDI 引脚为高电平,则稳压器会被设置为 1.8 V。MTDI 引脚通常需要一个上拉电阻或者直接使能内部的弱下拉电阻(详见 `ESP32 系列芯片技术规格书 `_ ),具体取决于所使用的 SPI 芯片的类型。但是一旦连接上 JTAG 后,原来用于实现 bootstrapping 功能的上拉或者下拉电阻都会被覆盖掉。 + +为了解决这个问题,OpenOCD 的板级配置文件(例如 ESP32-WROOM-32 模组的 ``boards\esp-wroom-32.cfg``)提供了 ``ESP32_FLASH_VOLTAGE`` 参数来设置 ``TDO`` 信号线在空闲状态下的二进制电平,这样就可以减少由于闪存电压不正确而导致的应用程序启动不良的几率。 + +查看 JTAG 连接的 ESP32 模组的规格书,检查其 SPI 闪存芯片的供电电压值,然后再相应的设置 ``ESP32_FLASH_VOLTAGE``。大多数的 WROOM 模组使用 3.3 V 的闪存芯片,但是 WROVER 模组使用 1.8 V 的闪存芯片。 + + +.. _jtag-debugging-tip-optimize-jtag-speed: + +优化 JTAG 的速度 +^^^^^^^^^^^^^^^^ + +为了实现更高的数据通信速率同时最小化丢包数,建议优化 JTAG 时钟频率的设置,使其达到 JTAG 能稳定运行的最大值。为此,请参考以下建议。 + +1. 如果 CPU 以 80 MHz 运行,则 JTAG 时钟频率的上限为 20 MHz;如果 CPU 以 160 MHz 或者 240 MHz 运行,则上限为 26 MHz。 +2. 根据特定的 JTAG 适配器和连接线缆的长度,你可能需要将 JTAG 的工作频率降低至 20 / 26 MHz 以下。 +3. 在某些特殊情况下,如果你看到 DSR/DIR 错误(并且它并不是由 OpenOCD 试图从一个没有物理存储器映射的地址空间读取数据而导致的),请降低 JTAG 的工作频率。 +4. ESP-WROVER-KIT 能够稳定运行在 20 / 26 MHz 频率下。 + + +.. _jtag-debugging-tip-debugger-startup-commands: + +调试器的启动命令的含义 +^^^^^^^^^^^^^^^^^^^^^^ + +在启动时,调试器发出一系列命令来复位芯片并使其在特定的代码行停止运行。这个命令序列(如下所示)支持自定义,用户可以选择在最方便合适的代码行开始调试工作。 + +* ``set remote hardware-watchpoint-limit 2`` — 限制 GDB 仅使用 ESP32 支持的两个硬件观察点。更多详细信息,请查阅 `GDB 配置远程目标 `_ 。 +* ``mon reset halt`` — 复位芯片并使 CPU 停止运行。 +* ``flushregs`` — monitor (``mon``) 命令无法通知 GDB 目标状态已经更改,GDB 会假设在 ``mon reset halt`` 之前所有的任务堆栈仍然有效。实际上,复位后目标状态将发生变化。执行 ``flushregs`` 是一种强制 GDB 从目标获取最新状态的方法。 +* ``thb app_main`` — 在 ``app_main`` 处插入一个临时的硬件断点,如果有需要,可以将其替换为其他函数名。 +* ``c`` — 恢复程序运行,它将会在 ``app_main`` 的断点处停止运行。 + + +.. _jtag-debugging-tip-openocd-configure-target: + +针对特定目标的 OpenOCD 配置 +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +OpenOCD 需要知道当前使用的 JTAG 适配器的类型,以及其连接的目标板和处理器的类型。为此,请使用位于 OpenOCD 安装目录下 ``share/openocd/scripts/interface`` 和 ``share/openocd/scripts/board`` 文件夹中现有的配置文件。 + +例如,如果使用板载 ESP-WROOM-32 模组的 ESP-WROVER-KIT 开发板(详见 :ref:`esp-modules-and-boards-esp-wrover-kit-v1`),请使用以下配置文件: + +* ``interface/ftdi/esp32_devkitj_v1.cfg`` +* ``board/esp-wroom-32.cfg`` + +当然也可以使用自定义的配置文件,建议在已有配置文件的基础上进行修改,以匹配你的硬件。下面列举一些常用的板级配置参数。 + + +.. highlight:: none + +适配器的时钟速度 +"""""""""""""""" + +:: + + adapter_khz 20000 + +请参阅 :ref:`jtag-debugging-tip-optimize-jtag-speed` 以获取有关如何设置此值的指导。 + + +单核调试 +"""""""" + +:: + + set ESP32_ONLYCPU 1 + +如果是双核调试,请注释掉这一行。 + + +禁用 RTOS 支持 +"""""""""""""" + +:: + + set ESP32_RTOS none + +如果要支持 RTOS, 请注释掉这一行。 + + +ESP32 的 SPI 闪存芯片的电源电压 +""""""""""""""""""""""""""""""" + +:: + + set ESP32_FLASH_VOLTAGE 1.8 + +如果 SPI 闪存芯片的电源电压为 3.3 V, 请注释掉这一行,更多信息请参阅: :ref:`jtag-debugging-tip-code-flash-voltage`。 + + +ESP32 的目标配置文件 +"""""""""""""""""""" + +:: + + source [find target/esp32.cfg] + +.. note:: + + 除非你熟悉 OpenOCD 内部的工作原理,否则请不要更改 ``source [find target/esp32.cfg]`` 这一行。 + +目前 ``target/esp32.cfg`` 仍然是 ESP32 目标(esp108 和 esp32)的唯一配置文件。支持的配置矩阵如下所示: + + +---------------+---------------+---------------+ + | Dual/single | RTOS | Target used | + +===============+===============+===============+ + | dual | FreeRTOS | esp32 | + +---------------+---------------+---------------+ + | single | FreeRTOS | esp108 (*) | + +---------------+---------------+---------------+ + | dual | none | esp108 | + +---------------+---------------+---------------+ + | single | none | esp108 | + +---------------+---------------+---------------+ + + (*) — 我们计划修复此问题,并在后续提交中添加对 esp32 目标的单核调试的支持。 + +更多信息,请查看 ``board/esp-wroom-32.cfg`` 配置文件的注释部分。 + + +.. _jtag-debugging-tip-reset-by-debugger: + +复位 ESP32 +^^^^^^^^^^ + +通过在 GDB 中输入 ``mon reset`` 或者 ``mon reset halt`` 来复位板子。 + + +.. _jtag-debugging-tip-jtag-pins-reconfigured: + +不要将 JTAG 引脚用于其他功能 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +如果除了 ESP32 模组和 JTAG 适配器之外的其他硬件也连接到了 JTAG 引脚,那么 JTAG 的操作可能会受到干扰。ESP32 JTAG 使用以下引脚: + + +---+----------------+-------------+ + | | ESP32 JTAG Pin | JTAG Signal | + +===+================+=============+ + | 1 | MTDO / GPIO15 | TDO | + +---+----------------+-------------+ + | 2 | MTDI / GPIO12 | TDI | + +---+----------------+-------------+ + | 3 | MTCK / GPIO13 | TCK | + +---+----------------+-------------+ + | 4 | MTMS / GPIO14 | TMS | + +---+----------------+-------------+ + +如果用户应用程序更改了 JTAG 引脚的配置,JTAG 通信可能会失败。如果 OpenOCD 正确初始化(检测到两个 Tensilica 内核),但在程序运行期间失去了同步并报出大量 DTR/DIR 错误,则应用程序可能将 JTAG 引脚重新配置为其他功能或者用户忘记将 Vtar 连接到 JTAG 适配器。 + +.. highlight:: none + +下面是 GDB 在应用程序进入重新配置 MTDO/GPIO15 作为输入代码后报告的一系列错误摘录:: + + cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates target still busy! + cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an exception! + cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an overrun! + cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates target still busy! + cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an exception! + cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an overrun! + + +.. _jtag-debugging-tip-reporting-issues: + +报告 OpenOCD / GDB 的问题 +^^^^^^^^^^^^^^^^^^^^^^^^^ + +如果你遇到 OpenOCD 或者 GDB 程序本身的问题,并且在网上没有找到可用的解决方案,请前往 https://github.com/espressif/openocd-esp32/issues 新建一个议题。 + +1. 请在问题报告中提供你使用的配置的详细信息: + + a. JTAG 适配器类型。 + b. 用于编译和加载正在调试的应用程序的 ESP-IDF 版本号。 + c. 用于调试的操作系统的详细信息。 + d. 操作系统是在本地计算机运行还是在虚拟机上运行? + +2. 创建一个能够演示问题的简单示例工程,描述复现该问题的步骤。且这个调试示例不能受到 Wi-Fi 协议栈引入的非确定性行为的影响,因而再次遇到同样问题时,更容易复现。 + +.. highlight:: bash + +3. 在启动命令中添加额外的参数来输出调试日志。 + + OpenOCD 端: + + :: + + bin/openocd -l openocd_log.txt -d 3 -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg + + 这种方式会将日志输出到文件,但是它会阻止调试信息打印在终端上。当有大量信息需要输出的时候(比如调试等级提高到 ``-d 3``)这是个不错的选择。如果你仍然希望在屏幕上看到调试日志,请改用以下命令: + + :: + + bin/openocd -d 3 -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg 2>&1 | tee openocd.log + + .. note:: + + 如果运行的 OpenOCD 是从源码自行编译的,命令的格式会有些许不同,具体请参阅: :ref:`jtag-debugging-building-openocd`。 + + Debugger 端: + + :: + + xtensa-esp32-elf-gdb -ex "set remotelogfile gdb_log.txt" + + 也可以将命令 ``remotelogfile gdb_log.txt`` 添加到 ``gdbinit`` 文件中。 + + +4. 请将 ``openocd_log.txt`` 和 ``gdb_log.txt`` 文件附在你的问题报告中。 diff --git a/docs/zh_CN/api-guides/jtag-debugging/using-debugger.rst b/docs/zh_CN/api-guides/jtag-debugging/using-debugger.rst index e34bc09731..a1bd8707e0 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/using-debugger.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/using-debugger.rst @@ -1 +1,189 @@ -.. include:: ../../../en/api-guides/jtag-debugging/using-debugger.rst \ No newline at end of file +使用调试器 +---------- + +本节会在 :ref:`Eclipse ` 和 :ref:`命令行 ` 中分别介绍配置和运行调试器的方法。我们建议你首先通过 :ref:`命令行 ` 检查调试器是否正常工作,然后再转到使用 :ref:`Eclipse ` 平台。 + + +.. _jtag-debugging-using-debugger-eclipse: + +在 Eclipse 中使用 GDB +^^^^^^^^^^^^^^^^^^^^^ + +标准的 Eclipse 安装流程默认安装调试功能,另外我们还可以使用插件来调试,比如 “GDB Hardware Debugging”。这个插件用起来非常方便,本指南会详细介绍该插件的使用方法。 + +首先,通过打开 Eclipse 并转到 “Help” > “Install New Software” 来安装 “GDB Hardware Debugging” 插件。 + +安装完成后,按照以下步骤配置调试会话。请注意,一些配置参数是通用的,有些则针对特定项目。我们会通过配置 "blink" 示例项目的调试环境来进行展示,请先按照 :doc:`使用 Eclipse IDE 编译和烧写 <../../get-started/eclipse-setup>` 文章介绍的方法将该示例项目添加到 Eclipse 的工作空间。示例项目 :example:`get-started/blink` 的源代码可以在 ESP-IDF 仓库的 :idf:`examples` 目录下找到。 + +1. 在 Eclipse 中,进入 `Run` > `Debug Configuration`,会出现一个新的窗口。在窗口的左侧窗格中,双击 “GDB Hardware Debugging” (或者选择 “GDB Hardware Debugging” 然后按下 “New” 按钮)来新建一个配置。 + +2. 在右边显示的表单中,“Name:” 一栏中输入配置的名称,例如: “Blink checking”。 + +3. 在下面的 “Main” 选项卡中, 点击 “Project:” 边上的 “Browse” 按钮,然后选择当前的 “blink” 项目。 + +4. 在下一行的 “C/C++ Application:” 中,点击 “Browse” 按钮,选择 “blink.elf” 文件。如果 “blink.elf” 文件不存在,那么很有可能该项目还没有编译,请参考 :doc:`使用 Eclipse IDE 编辑和烧写 <../../get-started/eclipse-setup>` 指南中的介绍。 + +5. 最后,在 “Build (if required) before launching” 下面点击 “Disable auto build”。 + + 上述步骤 1 - 5 的示例输入如下图所示。 + + .. figure:: ../../../_static/hw-debugging-main-tab.jpg + :align: center + :alt: Configuration of GDB Hardware Debugging - Main tab + :figclass: align-center + + GDB 硬件调试的配置 - Main 选项卡 + +6. 点击 “Debugger” 选项卡,在 “GDB Command” 栏中输入 ``xtensa-esp32-elf-gdb`` 来调用调试器。 + +7. 更改 “Remote host” 的默认配置,在 “Port number” 下面输入 ``3333``。 + + 上述步骤 6 - 7 的示例输入如下图所示。 + + .. figure:: ../../../_static/hw-debugging-debugger-tab.jpg + :align: center + :alt: Configuration of GDB Hardware Debugging - Debugger tab + :figclass: align-center + + GDB 硬件调试的配置 - Debugger 选项卡 + +8. 最后一个需要更改默认配置的选项卡是 “Startup” 选项卡。在 “Initialization Commands” 下,取消选中 “Reset and Delay (seconds)” 和 “Halt”,然后在下面一栏中输入以下命令: + + :: + + mon reset halt + flushregs + set remote hardware-watchpoint-limit 2 + + .. note:: + 如果你想在启动新的调试会话之前自动更新闪存中的镜像,请在 “Initialization Commands” 文本框的开头添加以下命令行:: + + mon reset halt + mon program_esp32 ${workspace_loc:blink/build/blink.bin} 0x10000 verify + + + 有关 ``program_esp32`` 命令的说明请参考 :ref:`jtag-upload-app-debug` 章节。 + +9. 在 “Load Image and Symbols” 下,取消选中 “Load image” 选项。 + +10. 在同一个选项卡中继续往下浏览,建立一个初始断点用来在调试器复位后暂停 CPU。插件会根据 “Set break point at:” 一栏中输入的函数名,在该函数的开头设置断点。选中这一选项,并在相应的字段中输入 ``app_main``。 + +11. 选中 “Resume” 选项,这会使得程序在每次调用步骤 8 中的 ``mon reset halt`` 之后恢复,然后在 ``app_main`` 的断点处停止。 + + 上述步骤 8 - 11 的示例输入如下图所示。 + + .. figure:: ../../../_static/hw-debugging-startup-tab.jpg + :align: center + :alt: Configuration of GDB Hardware Debugging - Startup tab + :figclass: align-center + + GDB 硬件调试的配置 - Startup 选项卡 + + 上面的启动序列看起来有些复杂,如果你对其中的初始化命令不太熟悉,请查阅 :ref:`jtag-debugging-tip-debugger-startup-commands` 章节获取更多说明。 + +12. 如果你前面已经完成 :ref:`jtag-debugging-configuring-esp32-target` 中介绍的步骤,那么目标正在运行并准备与调试器进行对话。按下 “Debug” 按钮就可以直接调试。否则请按下 “Apply” 按钮保存配置,返回 :ref:`jtag-debugging-configuring-esp32-target` 章节进行配置,最后再回到这里开始调试。 + +一旦所有 1 - 12 的配置步骤都已经完成,Eclipse 就会打开 “Debug” 视图,如下图所示。 + +.. figure:: ../../../_static/debug-perspective.jpg + :align: center + :alt: Debug Perspective in Eclipse + :figclass: align-center + + Eclipse 中的调试视图 + +如果你不太了解 GDB 的常用方法,请查阅 :ref:`jtag-debugging-examples-eclipse` 文章中的调试示例章节 :ref:`jtag-debugging-examples`。 + + +.. _jtag-debugging-using-debugger-command-line: + +在命令行中使用 GDB +^^^^^^^^^^^^^^^^^^ + +1. 为了能够启动调试会话,需要先启动并运行目标,如果还没有完成,请按照 :ref:`jtag-debugging-configuring-esp32-target` 中的介绍进行操作。 + +.. highlight:: bash + +2. 打开一个新的终端会话并前往待调试的项目目录,比如: + + :: + + cd ~/esp/blink + +.. highlight:: none + +3. 当启动调试器时,通常需要提供几个配置参数和命令,为了避免每次都在命令行中逐行输入这些命令,我们可以新建一个配置文件,并将其命名为 ``gdbinit``: + + :: + + target remote :3333 + set remote hardware-watchpoint-limit 2 + mon reset halt + flushregs + thb app_main + c + + 将此文件保存在当前目录中。 + + 有关 ``gdbinit`` 文件内部的更多详细信息,请参阅 :ref:`jtag-debugging-tip-debugger-startup-commands` 章节。 + +.. highlight:: bash + +4. 准备好启动 GDB,请在终端中输入以下内容: + + :: + + xtensa-esp32-elf-gdb -x gdbinit build/blink.elf + +.. highlight:: none + +5. 如果前面的步骤已经正确完成,你会看到如下所示的输出日志,在日志的最后会出现 ``(gdb)`` 提示符: + + :: + + user-name@computer-name:~/esp/blink$ xtensa-esp32-elf-gdb -x gdbinit build/blink.elf + GNU gdb (crosstool-NG crosstool-ng-1.22.0-61-gab8375a) 7.10 + Copyright (C) 2015 Free Software Foundation, Inc. + License GPLv3+: GNU GPL version 3 or later + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. Type "show copying" + and "show warranty" for details. + This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=xtensa-esp32-elf". + Type "show configuration" for configuration details. + For bug reporting instructions, please see: + . + Find the GDB manual and other documentation resources online at: + . + For help, type "help". + Type "apropos word" to search for commands related to "word"... + Reading symbols from build/blink.elf...done. + 0x400d10d8 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52 + 52 asm("waiti 0"); + JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1) + JTAG tap: esp32.slave tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1) + esp32: Debug controller was reset (pwrstat=0x5F, after clear 0x0F). + esp32: Core was reset (pwrstat=0x5F, after clear 0x0F). + Target halted. PRO_CPU: PC=0x5000004B (active) APP_CPU: PC=0x00000000 + esp32: target state: halted + esp32: Core was reset (pwrstat=0x1F, after clear 0x0F). + Target halted. PRO_CPU: PC=0x40000400 (active) APP_CPU: PC=0x40000400 + esp32: target state: halted + Hardware assisted breakpoint 1 at 0x400db717: file /home/user-name/esp/blink/main/./blink.c, line 43. + 0x0: 0x00000000 + Target halted. PRO_CPU: PC=0x400DB717 (active) APP_CPU: PC=0x400D10D8 + [New Thread 1073428656] + [New Thread 1073413708] + [New Thread 1073431316] + [New Thread 1073410672] + [New Thread 1073408876] + [New Thread 1073432196] + [New Thread 1073411552] + [Switching to Thread 1073411996] + + Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43 + 43 xTaskCreate(&blink_task, "blink_task", 512, NULL, 5, NULL); + (gdb) + +注意上面日志的倒数第三行显示了调试器已经在 ``app_main()`` 函数的断点处停止,该断点在 ``gdbinit`` 文件中设定。由于处理器已经暂停运行,LED 也不会闪烁。如果这也是你看到的现象,你可以开始调试了。 + +如果你不太了解 GDB 的常用方法,请查阅 :ref:`jtag-debugging-examples-command-line` 文章中的调试示例章节 :ref:`jtag-debugging-examples`。 diff --git a/docs/zh_CN/api-guides/jtag-debugging/windows-openocd-note.rst b/docs/zh_CN/api-guides/jtag-debugging/windows-openocd-note.rst index f81ed5ca65..1fe3676cc4 100644 --- a/docs/zh_CN/api-guides/jtag-debugging/windows-openocd-note.rst +++ b/docs/zh_CN/api-guides/jtag-debugging/windows-openocd-note.rst @@ -1 +1,3 @@ -.. include:: ../../../en/api-guides/jtag-debugging/windows-openocd-note.rst +.. note:: + + 如果您在 Windows 上使用 ``ESP-IDF Tools Installer`` 安装的 OpenOCD,则无需切换目录即可运行 ``openocd -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg`` ,也无需使用 ``-s share/openocd/scripts`` 参数指定脚本文件的搜索路径。