How to use the GDB (Gnu Debugger) and OpenOCD for microcontroller debugging - from the terminal?
对ARM微控制器进行编程的标准(低成本)方法是使用带有插入的复杂工具链的Eclipse。 Eclipse绝对有其优点,但是我想脱离此IDE。我想发现在构建(编译-链接-刷新)软件以及运行调试会话时幕后发生的事情。为了获得更深入的了解,从命令行运行整个过程将是很棒的。
注意:我使用的是64位Windows10。但是,此处说明的大多数内容也适用于Linux系统。请打开具有管理员权限的所有命令终端。这样可以为您节省很多问题。
1.构建软件
第一个"任务"完成。现在,我可以通过命令行将软件编译并链接到二进制
您不再需要Eclipse!特别是如果您可以阅读(并理解)makefile并在项目进行时根据需要调整它。
请注意,在安装SW4STM32(STM32的系统工作台)之后,在以下文件夹中找到了GNU工具(编译器,链接器,make实用程序,GDB,...):
1 | C:\\Ac6\\SystemWorkbench\\plugins\\fr.ac6.mcu.externaltools.arm-none.win32_1.7.0.201602121829\\tools\\compiler\\ |
接下来,我在硬盘上创建了一个新文件夹,并将所有这些GNU工具复制到其中:
1 2 3 4 | C:\\Apps\\AC6GCC |-> arm-none-eabi |-> bin '-> lib |
然后将这些条目添加到"环境路径变量"中:
1 2 | - C:\\Apps\\AC6GCC\\bin - C:\\Apps\\AC6GCC\\lib\\gcc\\arm-none-eabi\\5.2.1 |
Huray,现在我已经在系统上启动并运行了所有GNU工具!我将以下
1 2 3 4 5 6 7 8 9 10 | @echo off echo. echo."--------------------------------" echo."- BUILD -" echo."--------------------------------" echo. make -j8 -f makefile all echo. |
运行此bat文件应该可以完成任务!如果一切顺利,则编译后将得到一个
2.刷新和调试固件
自然的后续步骤是将固件刷新到芯片上并开始调试会话。在Eclipse中,这只是一个"单击按钮"-至少在为您的微控制器正确配置了Eclipse的情况下。但是幕后发生了什么?
我已经阅读过OpenOCD开发人员Dominic Rath的硕士论文(部分)。您可以在这里找到它:http://openocd.net/。这是我学到的:
当您单击"调试"图标时,Eclipse将启动OpenOCD软件。 Eclipse还为OpenOCD提供了一些配置文件-这样OpenOCD知道如何连接到您的微控制器。"如何连接"不是一件小事。 OpenOCD需要找到正确的USB驱动程序以连接到JTAG适配器(例如STLink)。 JTAG适配器及其USB驱动程序通常由芯片制造商(例如STMicroelectronics)提供。 Eclipse还将配置文件移交给OpenOCD,该文件描述了微控制器的规格。一旦OpenOCD了解了所有这些信息,它就可以与目标设备建立可靠的JTAG连接。
OpenOCD启动两个服务器。第一个是TCP端口4444上的Telnet服务器。它可以访问OpenOCD CLI(命令行界面)。 Telnet客户端可以连接并向OpenOCD发送命令。这些命令可以是简单的"停止","运行","设置断点",...
这样的命令足以调试您的微控制器,但是许多人已经熟悉Gnu Debugger(GDB)。这就是OpenOCD还在TCP端口3333上启动GDB服务器的原因。GDB客户端可以连接到该端口,并开始调试微控制器!
Gnu调试器是命令行软件。许多人喜欢可视界面。这正是Eclipse所做的。 Eclipse启动了一个GDB客户端,该客户端连接到OpenOCD-但对用户而言,所有这些都隐藏了。 Eclipse提供了一个图形界面,可以在后台与GDB客户端进行交互。
我做了一个图来解释所有这些事情:
>>启动OpenOCD
我设法从命令行启动OpenOCD。我会解释如何。
打开命令终端,然后启动OpenOCD。您将需要给OpenOCD一些配置文件,以便它知道在哪里寻找您的微控制器。通常,您需要提供一个描述JTAG编程器的配置文件和一个定义您的微控制器的配置文件。在命令行中使用
1 | >"C:\\Apps\\OpenOCD-0.9.0-Win32\\bin\\openocd" -f"C:\\Apps\\OpenOCD-0.9.0-Win32\\share\\openocd\\scripts\\interface\\stlink-v2.cfg" -f"C:\\Apps\\OpenOCD-0.9.0-Win32\\share\\openocd\\scripts\\target\\stm32f7x.cfg" -s"C:\\Apps\\OpenOCD-0.9.0-Win32\\share\\openocd\\scripts" |
如果正确启动了OpenOCD(使用正确的参数),它将以以下消息启动:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Open On-Chip Debugger 0.9.0 (2015-08-15-12:41) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport"hla_swd". To override use 'transport select <transport>'. Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD adapter speed: 2000 kHz adapter_nsrst_delay: 100 srst_only separate srst_nogate srst_open_drain connect_deassert_srst Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : Unable to match requested speed 2000 kHz, using 1800 kHz Info : clock speed 1800 kHz Info : STLINK v2 JTAG v24 API v2 SWIM v4 VID 0x0483 PID 0x3748 Info : using stlink api v2 Info : Target voltage: 3.231496 Info : stm32f7x.cpu: hardware has 8 breakpoints, 4 watchpoints Info : accepting 'gdb' connection on tcp/3333 Info : flash size probed value 1024 |
请注意,您的终端窗口现已被阻止。您不能再键入命令。但这很正常。 OpenOCD在后台运行,它阻止了终端。现在,您有两个与OpenOCD交互的选项:在另一个终端上启动Telnet会话,然后登录到TCP端口
>>启动Telnet会话以与OpenOCD进行交互
这是启动Telnet会话以与正在运行的OpenOCD程序进行交互的方式:
1 2 3 | > dism /online /Enable-Feature /FeatureName:TelnetClient > telnet 127.0.0.1 4444 |
如果运行良好,您将在终端上收到以下消息:
1 2 | Open On-Chip Debugger > .. |
您已经准备好向OpenOCD发送命令!但是,现在我将切换到GDB会话,因为这是与OpenOCD进行交互的最方便的方法。
>>启动GDB客户端会话以与OpenOCD进行交互
打开另一个终端窗口,然后键入以下命令:
1 | >"C:\\Apps\\AC6GCC\\bin\\arm-none-eabi-gdb.exe" |
此命令仅启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20151217-cvs Copyright (C) 2015 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 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=i686-w64-mingw32 --target=arm-none-eabi". Type"show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type"help". Type"apropos word" to search for commands related to"word". (gdb).. |
现在,将此GDB客户端连接到OpenOCD内的GDB服务器:
1 | (gdb) target remote localhost:3333 |
现在您已连接到OpenOCD!提示:如果您想使用本机OpenOCD命令(就像在Telnet会话中一样),只需在命令前加上关键字
因此,现在是时候重置芯片,擦除并暂停它了:
1 2 3 4 5 6 7 8 9 10 11 12 13 | (gdb) monitor reset halt target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc (gdb) monitor halt (gdb) monitor flash erase_address 0x08000000 0x00100000 erased address 0x08000000 (length 1048576) in 8.899024s (115.069 KiB/s) (gdb) monitor reset halt target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc (gdb) monitor halt |
现在,该芯片已准备就绪,可以向我们获取一些说明。首先,我们将告诉芯片其闪存部分0至7(即我的1Mb芯片中的所有闪存部分)不应受到保护:
1 2 3 4 5 6 7 8 9 10 11 12 | (gdb) monitor flash protect 0 0 7 off (gdb) monitor flash info 0 #0 : stm32f7x at 0x08000000, size 0x00100000, buswidth 0, chipwidth 0 # 0: 0x00000000 (0x8000 32kB) not protected # 1: 0x00008000 (0x8000 32kB) not protected # 2: 0x00010000 (0x8000 32kB) not protected # 3: 0x00018000 (0x8000 32kB) not protected # 4: 0x00020000 (0x20000 128kB) not protected # 5: 0x00040000 (0x40000 256kB) not protected # 6: 0x00080000 (0x40000 256kB) not protected # 7: 0x000c0000 (0x40000 256kB) not protected |
接下来,我再次暂停芯片。只是要确定..
1 | (gdb) monitor halt |
最后,我将二进制
1 2 3 4 | (gdb) file C:\\\\..\\\\myProgram.elf A program is being debugged already. Are you sure you want to change the file? (y or n) y Reading symbols from C:\\..\\myProgram.elf ...done. |
现在是关键时刻。我要求GDB将二进制文件加载到芯片中。手指交叉:
1 2 3 4 5 6 7 8 | (gdb) load Loading section .isr_vector, size 0x1c8 lma 0x8000000 Loading section .text, size 0x39e0 lma 0x80001c8 Loading section .rodata, size 0x34 lma 0x8003ba8 Loading section .init_array, size 0x4 lma 0x8003bdc Loading section .fini_array, size 0x4 lma 0x8003be0 Loading section .data, size 0x38 lma 0x8003be4 Error finishing flash operation |
不幸的是,它没有成功。我在OpenOCD中收到以下消息:
1 2 | Error: error waiting for target flash write algorithm Error: error writing to flash at address 0x08000000 at offset 0x00000000 |
编辑:修复了硬件问题。
显然这是硬件问题。我从未想过我的芯片会出现故障,因为使用STLink Utility工具将二进制文件加载到芯片上可以正常工作。只有OpenOCD在抱怨并给出错误。因此,我自然地将责任归咎于OpenOCD-而不是芯片本身。有关更多详细信息,请参见下面的答案。
编辑:另一种优雅的方式来刷新芯片-使用makefile!
由于问题已解决,我现在将重点介绍执行闪存和芯片调试的另一种方法。我相信这对于社区真的很有趣!
您可能已经注意到,我使用Windows cmd命令执行所有必需的步骤。 这可以在批处理文件中自动执行。 但是,还有一种更优雅的方法:自动化makefile中的所有内容!
先生/女士 Othane为他/她的Cortex-M建议了以下makefile? 芯片。 我认为Cortex-M7芯片的过程非常相似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | ################################################# # MAKEFILE FOR BUILDING THE BINARY # # AND EVEN FLASHING THE CHIP! # # Author: Othane # ################################################# # setup compiler and flags for stm32f373 build SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) CROSS_COMPILE ?= arm-none-eabi- export CC = $(CROSS_COMPILE)gcc export AS = $(CROSS_COMPILE)gcc -x assembler-with-cpp export AR = $(CROSS_COMPILE)ar export LD = $(CROSS_COMPILE)ld export OD = $(CROSS_COMPILE)objdump export BIN = $(CROSS_COMPILE)objcopy -O ihex export SIZE = $(CROSS_COMPILE)size export GDB = $(CROSS_COMPILE)gdb MCU = cortex-m4 FPU = -mfloat-abi=hard -mfpu=fpv4-sp-d16 -D__FPU_USED=1 -D__FPU_PRESENT=1 -DARM_MATH_CM4 DEFS = -DUSE_STDPERIPH_DRIVER -DSTM32F37X -DRUN_FROM_FLASH=1 -DHSE_VALUE=8000000 OPT ?= -O0 MCFLAGS = -mthumb -mcpu=$(MCU) $(FPU) export ASFLAGS = $(MCFLAGS) $(OPT) -g -gdwarf-2 $(ADEFS) CPFLAGS += $(MCFLAGS) $(OPT) -gdwarf-2 -Wall -Wno-attributes -fverbose-asm CPFLAGS += -ffunction-sections -fdata-sections $(DEFS) export CPFLAGS export CFLAGS += $(CPFLAGS) export LDFLAGS = $(MCFLAGS) -nostartfiles -Wl,--cref,--gc-sections,--no-warn-mismatch $(LIBDIR) HINCDIR += ./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/CMSIS/Include/ \\ ./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/CMSIS/Device/ST/STM32F37x/Include/ \\ ./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/STM32F37x_StdPeriph_Driver/inc/ \\ ./ export INCDIR = $(patsubst %,$(SELF_DIR)%,$(HINCDIR)) # openocd variables and targets OPENOCD_PATH ?= /usr/local/share/openocd/ export OPENOCD_BIN = openocd export OPENOCD_INTERFACE = $(OPENOCD_PATH)/scripts/interface/stlink-v2.cfg export OPENOCD_TARGET = $(OPENOCD_PATH)/scripts/target/stm32f3x_stlink.cfg OPENOCD_FLASH_CMDS = '' OPENOCD_FLASH_CMDS += -c 'reset halt' OPENOCD_FLASH_CMDS += -c 'sleep 10' OPENOCD_FLASH_CMDS += -c 'stm32f1x unlock 0' OPENOCD_FLASH_CMDS += -c 'flash write_image erase $(PRJ_FULL) 0 ihex' OPENOCD_FLASH_CMDS += -c shutdown export OPENOCD_FLASH_CMDS OPENOCD_ERASE_CMDS = '' OPENOCD_ERASE_CMDS += -c 'reset halt' OPENOCD_ERASE_CMDS += -c 'sleep 10' OPENOCD_ERASE_CMDS += -c 'sleep 10' OPENOCD_ERASE_CMDS += -c 'stm32f1x mass_erase 0' OPENOCD_ERASE_CMDS += -c shutdown export OPENOCD_ERASE_CMDS OPENOCD_RUN_CMDS = '' OPENOCD_RUN_CMDS += -c 'reset halt' OPENOCD_RUN_CMDS += -c 'sleep 10' OPENOCD_RUN_CMDS += -c 'reset run' OPENOCD_RUN_CMDS += -c 'sleep 10' OPENOCD_RUN_CMDS += -c shutdown export OPENOCD_RUN_CMDS OPENOCD_DEBUG_CMDS = '' OPENOCD_DEBUG_CMDS += -c 'halt' OPENOCD_DEBUG_CMDS += -c 'sleep 10' .flash: $(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_FLASH_CMDS) .erase: $(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_ERASE_CMDS) .run: $(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_RUN_CMDS) .debug: $(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_DEBUG_CMDS) |
尊敬的先生/女士 Othane,您能否解释一下如何将此Makefile用于以下步骤:
我知道一些关于makefile的基础知识,但是您的makefile确实非常深入。 您似乎使用了GNU make实用程序的许多功能。 请给我们更多的解释,我将给您奖金;-)
------------------------------
好。
我记得它在直接加载命令上也遇到了一些麻烦,所以我切换到" flash write_image擦除my_project.hex 0 ihex" ..显然我正在使用十六进制文件,但看起来elf文件应该可以使用,请参见http: //openocd.org/doc/html/Flash-Commands.html ...关于此命令的好处是它还只擦除了确实方便的闪存部分,因此您不需要擦除
在运行上述命令之前,您将需要运行" stm32f1x unlock 0",以确保芯片已解锁并允许您连接至闪存...请参阅有关此数据表
另外,要开始使用该命令," stm32f1x mass_erase 0"将完全快速擦除芯片,因此最好确保以已知状态启动
我知道其中一些命令说它们适用于f1,但请相信我它们适用于f4系列
顺便说一句,这个文件包含了我用来刷新f4的大多数命令,因此它可能是一个很好的参考https://github.com/othane/mos/blob/master/hal/stm32f373/stm32f373.mk
我希望你能解开
乍一看,在gnutoolchains.com上的分发应该足够好。有许多构建脚本可以酿造您自己的版本。我确实包括ARM7TDMI。在Linux和FreeBSD上它可以正常工作,但是MinGW上次尝试它失败了:-(
关于OpenOCD,我建议在与GDB实例相同的目录中启动它,这样,如果您从GDB中调用它,二进制下载看起来是透明的(最简单的方法)。您还可以选择创建一个脚本来启动OpenOCD并加载代码,但是每次编译后都必须重新启动它。
这是一个简短但不是很好的stackoverflow样式,但是我会向您指出我的代码,在该代码中我为STM32F4和STM32F1(https://github.com/othane/mos)的" mos"库进行了设置。这是一个很重要的话题,所以我通过一个例子可能会更好
简而言之,我的项目是一棵Makefiles树,因为您可以在这里编译自己感兴趣的主要代码,请参见https://github.com/othane/mos/blob/master/hal/stm32f373/stm32f373.mk ...基本上,您需要openocd,然后我有一系列命令来擦除芯片,或者通过简单地键入make .erase或make .flash或make .debug来擦除和调试新代码等。
最后,如果您查看我的单元测试(这些基本上是示例程序),您会找到用于构建它的Makefile +像这样的gdbinit文件https://github.com/othane/mos/blob/master/utest/gpio/ debug_gpio_utest.gdbinit ...然后您只需在一个终端中执行" make && make .flash && make .debug",然后在其中调用交叉编译器gdb,例如" arm-none-eabi-gdb -x ./debug_gpio_utest.gdbinit"。另一个...这将在刷新代码后启动gdb,您可以使用gdb等中的常规break和list命令与代码进行交互(请注意,我如何在.gdbinit文件中定义了reset命令,请查看mon的帮助命令...基本上,它将使您可以通过gdb将命令直接发送到openocd,这确实很有用)
抱歉,答案很简短,有很多链接,但我希望它能帮助您前进。
现在,您只需调用" gdb"并将其连接到"远程服务器"(如果服务器和gdb在同一台计算机上运行,??则为localhost)。配置GDB,使其知道源代码的位置和ELF文件的位置。有大量的网站会介绍GDB的基本用法。
Windows似乎有一个GDB(http://www.equation.com/servlet/equation.cmd?fa=gdb)
GDB中的以下命令可以帮助您入门:
目标远程本地主机:3333
目录/ path / to / project
符号文件/path/to/project.elf
显然这是硬件问题。 我从未想过我的芯片会出现故障,因为使用STLink Utility工具将二进制文件加载到芯片上可以正常工作。 只有OpenOCD在抱怨并给出错误。 因此,我自然地将责任归咎于OpenOCD-而不是芯片本身。
今天,我在板上使用了新芯片,尝试了相同的步骤,现在可以正常工作!
发出
1 2 3 4 5 6 7 8 9 10 | (gdb) load Loading section .isr_vector, size 0x1c8 lma 0x8000000 Loading section .text, size 0x39e0 lma 0x80001c8 Loading section .rodata, size 0x34 lma 0x8003ba8 Loading section .init_array, size 0x4 lma 0x8003bdc Loading section .fini_array, size 0x4 lma 0x8003be0 Loading section .data, size 0x38 lma 0x8003be4 Start address 0x8003450, load size 15388 Transfer rate: 21 KB/sec, 2564 bytes/write. (gdb) |
感谢所有竭尽所能帮助我的人:-)