用于 Flash 和 Ram 调试的 STM32 GDB/OpenOCD 命令和初始化
Posted
技术标签:
【中文标题】用于 Flash 和 Ram 调试的 STM32 GDB/OpenOCD 命令和初始化【英文标题】:STM32 GDB/OpenOCD Commands and Initialization for Flash and Ram Debugging 【发布时间】:2011-07-28 22:51:09 【问题描述】:我正在寻求有关正确 GDB/OpenOCD 初始化和运行命令(外部工具)的帮助,以在 Eclipse 中用于闪存和 RAM 调试,以及需要合并到闪存生成文件中的正确修改或添加与此 MCU 的 RAM 构建相比,如果这当然重要的话。
MCU:STM32F103VET6
我正在使用带有 Zylin Embedded CDT、Yagarto Tools 和 Bins、OpenOCD 0.4 的 Eclipse Helios,并且有一个 Olimex ARM-USB-OCD JTAG 适配器。
我已经配置了 ARM-USB-OCD 并将其添加为 Eclipse 中的外部工具。为了初始化 OpenOCD,我在 Eclipse 中使用了以下命令。板子配置文件引用stm32 MCU:
openocd -f interface/olimex-arm-usb-ocd-h.cfg -f board/stm32f10x_128k_eval.cfg
当我在 Eclipse 中运行它时,一切似乎都在工作(GDB 接口、OpenOCD 找到 MCU 等)。我还可以远程登录到 OpenOCD 并运行命令。 所以,我被困在下一部分;用于闪存和 RAM 调试以及擦除闪存的初始化和命令。
我阅读了几个教程,并在网上搜索,但无法找到该处理器的任何特别之处。我对此并不陌生,因此我可能无法识别出一个同等产品的例子。
【问题讨论】:
【参考方案1】:我正在使用相同的工具链来编程和调试 STM32F107 板。以下是我在此工具链下对 STM32Fxxx 芯片进行编程和调试的观察。
初始起点
因此,此时您已经建立了一个有效的 OpenOCD 到 ARM-USB-OCD 的连接,因此您应该为此做好准备。现在的工作是让 Eclipse/Zylin/Yagarto GDB 组合通过 OpenOCD/Olimex 连接正确地与 STM32Fxxx 通信。要记住的一件事是,要发出的所有 OpenOCD 命令都是 运行模式 命令。调用 OpenOCD 服务器的配置脚本和命令行选项是 配置模式 命令。一旦你发出 init 命令,服务器就会进入运行模式,这会打开你接下来需要的命令集。您可能已经在其他地方完成了它,但是当我像这样调用 OpenOCD 服务器时,我添加了一个 '-c "init"' 选项:
openocd -f /path to scripts/olimex-arm-usb-ocd-h.cfg -f /path to targets/stm32f107.cfg -c "init"
我接下来发出的以下命令由 Eclipse Debug Configurations 对话框完成。在 Zylin Embedded debug (Native) 部分下,我创建了一个新配置,为其命名、项目(可选)和我想要编程的二进制文件的绝对路径。在 Debugger 选项卡下,我将调试器设置为 Embedded GDB,指向 Yagarto GDB 二进制路径,不要 设置 GDB 命令文件,将 GDB 命令设置为 标准,以及mi的协议。
命令选项卡 - 将 GDB 连接到 OpenOCD
所以下一个选项卡是 Commands 选项卡,这就是问题的关键所在。你有两个空格Initialize和Run。除了猜测它们发生在 GDB 调用之前和之后,不知道究竟有什么区别。无论哪种方式,我都没有注意到我的命令运行方式有什么不同。
但无论如何,按照我在网上找到的示例,我用以下命令填充了 Initialize 框:
set remote hardware-breakpoint limit 6
set remote hardware-watchoint-limit 4
target remote localhost:3333
monitor halt
monitor poll
前两行告诉 GDB 你有多少个断点和观察点。 Open OCD Manual Section 20.3 说 GDB 无法查询该信息,所以我自己告诉它。下一行命令 GDB 通过端口 3333 连接到 localhost 上的远程目标。最后一行是 monitor 命令,它告诉 GDB 将命令传递给目标,而无需自行执行任何操作。在这种情况下,目标是 OpenOCD,我给它的命令是 halt。之后我告诉 OpenOCD 切换到异步操作模式。由于以下某些操作需要一段时间,因此不要让 OpenOCD 阻塞并等待每个操作。
旁注#1:如果您对 GDB 或 OpenOCD 的状态有疑问,那么您可以使用 Eclipse 调试控制台向 GDB 或 OpenOCD 发送命令(通过 GDB 监视器命令)调用此调试配置。
命令选项卡 - 设置用户 Flash
接下来是我在运行命令部分给出的命令:
monitor flash probe 0
monitor flash protect 0 0 127 off
monitor reset halt
monitor stm32x mass_erase 0
monitor flash write_image STM3210CTest/test_rom.elf
monitor flash protect 0 0 127 on
disconnect
target remote localhost:3333
monitor soft_reset_halt
将在以下部分中解释...
设置对用户闪存的访问
首先我发出一个 OpenOCD 查询,看看它是否可以找到闪存模块并报告正确的地址。如果它响应它在地址 0x08000000 处找到闪存,那么我们很好。末尾的 0 指定获取关于 flash bank 0 的信息。
旁注#2: STM32Fxxx 部件特定数据表在第 4 节中有一个内存映射。在您使用该芯片时随身携带非常有用。此外,由于所有内容都作为内存地址进行访问,因此经过一点编程时间,您就会对这种布局了如指掌!
因此,在确认闪存已正确配置后,我们调用命令来关闭对闪存组的写保护。 PM0075 描述了您需要了解的有关对闪存进行编程的所有信息。对于这个命令,你需要知道的是 flash bank、起始扇区、结束扇区,以及是否启用或禁用写保护。闪存库是在您传递给 OpenOCD 的配置文件中定义的,并由前面的命令确认。因为我想禁用对整个闪存空间的保护,所以我指定扇区 0 到 127。PM0075 解释了我是如何得到这个数字的,因为它指的是闪存是如何为我的(和你的)设备组织成 2KB 页面的。我的设备有 256KB 的闪存,这意味着我有 128 页。您的设备有 512KB 的闪存,因此您将拥有 256 页。要确认您的设备的写保护已被正确禁用,您可以使用 OpenOCD 命令检查地址 0x40022020 的 FLASH_WRPR 寄存器:
monitor mdw 0x40022020
它打印的结果字将是 0xffffffff,这意味着所有页面都禁用了写保护。 0x00000000 表示所有页面都启用了写保护。
旁注#3:关于内存命令的主题,我在地址 0x1ffff800 开始的块处弄乱了选项字节时,我把芯片变砖了两次。第一次我在闪存上设置了读保护(如果你这样做,很难弄清楚你在做什么),第二次我设置了硬件看门狗,这阻止了我之后做任何事情,因为看门狗一直在触发!通过使用 OpenOCD 内存访问命令修复它。故事的寓意是:权力越大,责任越大……。 或者另一种看法是,如果我在脚上开枪,我仍然可以通过 JTAG 修复问题。
旁注#4:如果您尝试写入受保护的闪存,将会发生的一件事是 FLASH_SR:WRPRTERR 位将被设置。 OpenOCD 将报告更用户友好的错误消息。
擦除 Flash
所以在禁用写保护之后,我们需要擦除你想要编程的内存。我进行了一次批量擦除,它会擦除所有内容,您还可以选择按扇区或地址擦除(我认为)。无论哪种方式,您都需要在编程之前先擦除,因为硬件会在允许写入之前先检查擦除。如果 FLASH_SR:PGERR 位 (0x4002200c) 在编程过程中被设置,那么你就知道你还没有擦除那块内存。
旁注#5:擦除闪存中的位意味着将其设置为 1。
编写二进制文件
擦除后的下两行将二进制映像写入闪存并重新启用写保护。 PM0075 没有涵盖更多内容。基本上,当您发出 flash write_image 时发生的任何错误都可能与未禁用闪存保护有关。它可能不是 OpenOCD,但如果您好奇,您可以启用调试输出并按照它的作用进行操作。
GDB 调试
所以最后在编程之后,我将 GDB 与远程连接断开,然后将其重新连接到目标,进行软重置,我的 GDB 现在可以调试了。最后一部分是我昨晚才弄清楚的,因为我试图弄清楚为什么在编程之后,GDB 在重置后不会正确地停止在 main() 处。它不断进入杂草并炸毁。
我目前的想法以及我在 OpenOCD 和 GDB 手册中阅读的内容是,远程连接首先是要在 GDB 和已经配置并运行的目标之间使用。好吧,我在运行之前使用 GDB 进行配置,所以我认为符号表或其他一些重要信息在编程过程中会变得混乱。 OpenOCD 手册说,当 GDB 连接时,服务器会自动报告内存和符号,但是当芯片被编程时,所有这些信息可能会变得无效。断开连接并重新连接我认为刷新 GDB 需要正确调试的信息。所以这导致我创建了另一个调试配置,这个配置只是连接并重置目标,因为我不一定需要每次使用 GDB 时都对芯片进行编程。
哇!完毕!有点长,但这花了我 3 个周末才弄明白,所以我认为这并不算太糟糕......
最后的旁注:在我调试期间,我发现 OpenOCD 调试输出对于我理解 OpenOCD 在幕后所做的事情非常宝贵。要对 STM32x 芯片进行编程,您需要解锁闪存寄存器,翻转正确的位,并且一次只能写入一个半字。有一段时间我一直在质疑 OpenOCD 是否正确执行此操作,但在查看 OpenOCD 调试输出并将其与 PM0075 指令进行比较后,我能够确认它确实遵循了正确的步骤来执行每个操作。我还发现我正在重复 OpenOCD 已经在执行的步骤,因此我能够删除没有帮助的指令! 故事的寓意:调试输出是您的朋友!
【讨论】:
很好的答案!不幸的是,大多数 OpenOCD 教程只解释了如何安装它。顺便说一句,您引用了 OpenOCD 手册第 20.3 节,但现在是 21.3。对于不使用 Eclipse 的人来说,使用gdb -ex "commands here"
编写 gdb 命令脚本很容易
亲爱的@spade78,我可以看出你对 OpenOCD 有很深的了解。请看看我的问题:***.com/questions/38033130/…。它有一个开放的赏金。希望你能帮助我。【参考方案2】:
我在 Comannd 选项卡的最后一句之后使用的 - '运行' 命令是:
symbol-file STM3210CTest/test_rom.elf
thbreak main
continue
thbreak main
语句是让 gdb 在 main 处停止的原因。
【讨论】:
【参考方案3】:我很难让 JLink 与 STM3240XX 一起工作,并在 JLink GDB 服务器文档中找到了一条声明,说加载闪存后必须发出“目标重置”:
"在闪存中调试时,在闪存下载后重置目标时,堆栈指针和 PC 会自动设置。下载后不重置,堆栈指针和 PC 需要正确初始化,通常在 .gdbinit 文件中。”
当我在 Eclipse 的调试器设置的运行框中添加“目标重置”时,突然一切正常。我的 Kinetis K60 没有这个问题。
该文档还解释了如果您不想发出重置,如何直接手动设置堆栈指针和 pc。解决问题的可能不是断开/连接,而是重置。
【讨论】:
以上是关于用于 Flash 和 Ram 调试的 STM32 GDB/OpenOCD 命令和初始化的主要内容,如果未能解决你的问题,请参考以下文章
stm32转成ram调试方式,设置后,下载失败,提示芯片被锁,但用flash下载正常,jlink解锁后仍无效,求教
STM32 KEIL C如何在RAM中调试FREERTOS?
关于STM32 KEIL MDK环境下,程序在RAM中调试的问题