18

我正在寻求有关正确 GDB / OpenOCD 初始化和运行命令(外部工具)的帮助,以在 Eclipse 中用于闪存和 RAM 调试,以及需要合并到用于闪存与 RAM 构建的 makefile 中的正确修改或添加对于这个 MCU,如果这当然重要的话。

单片机:STM32F103VET6

我正在使用带有 Zylin Embedded CDT、Yagarto 工具和 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 调试以及擦除闪存的初始化和命令。

我通读了几个教程,并搜索了网络,但无法找到该处理器的任何特定内容。我对此并不陌生,因此我可能无法识别等效产品的示例。

4

3 回答 3

32

我正在使用相同的工具链来编程和调试 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调试配置对话框完成。在Zylin Embedded debug (Native)部分下,我创建了一个新配置,为其命名、项目(可选)和我想要编程的二进制文件的绝对路径。在 Debugger 选项卡下,我将调试器设置为Embedded GDB,指向 Yagarto GDB 二进制路径,不要设置 GDB 命令文件,将 GDB 命令集设置为Standard,并将协议设置为mi


命令选项卡 - 将 GDB 连接到 OpenOCD

所以下一个选项卡是命令选项卡,这就是问题的关键所在。您有两个空格InitializeRun。除了猜测它们发生在 GDB 调用之前和之后,不知道究竟有什么区别。无论哪种方式,我都没有注意到我的命令运行方式有什么不同。

但无论如何,按照我在网上找到的示例,我用以下命令填充了初始化框:

set remote hardware-breakpoint limit 6
set remote hardware-watchoint-limit 4
target remote localhost:3333
monitor halt
monitor poll

前两行告诉 GDB 你有多少断点和观察点。打开 OCD 手册第 20.3 节说 GDB 无法查询该信息,所以我自己告诉它。下一行命令 GDB 通过 3333 端口连接到 localhost 上的远程目标。最后一行是一个监视命令,它告诉 GDB 将命令传递给目标,而无需自行执行任何操作。在这种情况下,目标是 OpenOCD,我给它的命令是halt。之后我告诉 OpenOCD 切换到异步操作模式。由于以下某些操作需要一段时间,因此不要让 OpenOCD 阻塞并等待每个操作。

旁注#1:如果您对 GDB 或 OpenOCD 的状态有疑问,那么您可以在调用此调试配置后使用 Eclipse 调试控制台将命令发送到 GDB 或 OpenOCD(通过 GDB 监视器命令)。


命令选项卡 - 设置用户闪存

接下来是我在运行命令部分给出的命令:

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_SR:PGERR 位 (0x4002200c) 在编程过程中被设置,那么你就知道你还没有擦除那块内存。

旁注#5:擦除闪存中的位意味着将其设置为 1。

编程你的二进制文件

擦除后的下两行将二进制映像写入闪存并重新启用写保护。PM0075 没有涵盖更多内容。基本上,当您发出flash write_image时发生的任何错误都可能与未禁用 flash 保护有关。它可能不是OpenOCD,但如果您好奇,您可以启用调试输出并遵循它的功能。

GDB 调试

所以最后在编程之后,我将 GDB 与远程连接断开,然后将其重新连接到目标,进行软重置,我的 GDB 现在可以调试了。最后一部分是我昨晚才弄清楚的,因为我试图弄清楚为什么在编程之后,GDB 在重置后不会正确地停止在 main() 处。它不断地进入杂草并炸毁。

我目前的想法以及我在 OpenOCD 和 GDB 手册中阅读的内容是,远程连接首先是要在 GDB 和已经配置和运行的目标之间使用。好吧,我在运行之前使用 GDB 进行配置,所以我认为符号表或其他一些重要信息在编程过程中会变得混乱。OpenOCD 手册说,当 GDB 连接时,服务器会自动报告内存和符号,但是当芯片被编程时,所有这些信息可能会变得无效。断开连接并重新连接我认为刷新 GDB 需要正确调试的信息。所以这导致我创建了另一个调试配置,这个只是连接并重置目标,因为我不一定需要在每次我想使用 GDB 时对芯片进行编程。


哇!完毕!有点长,但这花了我 3 个周末才弄清楚,所以我认为这并不算太糟糕......

最后的旁注:在我调试期间,我发现 OpenOCD 调试输出对于我理解 OpenOCD 在幕后所做的事情非常宝贵。要对 STM32x 芯片进行编程,您需要解锁闪存寄存器,翻转正确的位,并且一次只能写入一个半字。有一段时间我一直在质疑 OpenOCD 是否正确执行此操作,但在查看 OpenOCD 调试输出并将其与 PM0075 指令进行比较后,我能够确认它确实遵循了正确的步骤来执行每个操作。我还发现我正在重复 OpenOCD 已经在执行的步骤,因此我能够删除没有帮助的指令!故事的寓意:调试输出是你的朋友!

于 2011-10-29T18:59:38.113 回答
3

我努力让 JLink 与 STM3240XX 一起工作,并在 JLink GDB 服务器文档中找到了一条声明,说加载闪存后,您必须发出“目标重置”:

“在闪存中调试时,当目标在闪存下载后重置时,堆栈指针和 PC 会自动设置。下载后不重置,堆栈指针和 PC 需要正确初始化,通常在 .gdbinit 文件中。”

当我在 Eclipse 的调试器设置的运行框中添加“目标重置”时,突然一切正常。Kinetis K60 没有这个问题。

该文档还解释了如果您不想发出重置,如何直接手动设置堆栈指针和 pc。解决问题的可能不是断开/连接,而是重置。

于 2013-03-30T16:40:16.480 回答
2

我在 Comannd 选项卡中的最后一句之后使用的 - “运行”命令是:

symbol-file STM3210CTest/test_rom.elf
thbreak main
continue

thbreak main句话是让 gdb 停在 main 上的原因。

于 2012-09-03T20:35:09.440 回答