62

对 ARM 微控制器进行编程的标准(低成本)方法是使用 Eclipse,并在其中插入一个复杂的工具链。Eclipse 肯定有它的优点,但我想感觉独立于这个 IDE。我想了解当我构建(编译-链接-刷新)我的软件以及运行调试会话时幕后发生了什么。要获得如此深入的了解,最好从命令行运行整个过程。

注意:我使用的是 64 位 Windows 10。但这里解释的大多数内容也适用于 Linux 系统。请以管理员权限打开所有命令终端。这可以为您节省很多问题。

1. 构建软件

第一个“任务”完成了。我现在可以通过命令行将我的软件编译并链接成二进制文件.bin和图像。.elf成功的关键是找出 Eclipse 将其生成文件放在特定项目的位置。一旦你知道它们在哪里,你所要做的就是打开一个命令终端,然后输入GNU make命令。

在此处输入图像描述

您不再需要 Eclipse!特别是如果您可以阅读(并理解)makefile 并在项目进展时根据您的需要对其进行调整。

请注意,在安装 SW4STM32(STM32 的系统工作台)后,我在以下文件夹中找到了 GNU 工具(编译器、链接器、make 实用程序、GDB...):

C:\Ac6\SystemWorkbench\plugins\fr.ac6.mcu.externaltools.arm-none.win32_1.7.0.201602121829\tools\compiler\

接下来,我在硬盘上创建了一个新文件夹,并将所有这些 GNU 工具复制到其中:

C:\Apps\AC6GCC
           |-> arm-none-eabi
           |-> bin
           '-> lib

我将这些条目添加到“环境路径变量”中:

 - C:\Apps\AC6GCC\bin
 - C:\Apps\AC6GCC\lib\gcc\arm-none-eabi\5.2.1

Huray,现在我已经在我的系统上启动并运行了所有 GNU 工具!我将以下build.bat文件放在与以下文件相同的文件夹中makefile

@echo off
echo.
echo."--------------------------------"
echo."-           BUILD              -"
echo."--------------------------------"
echo.

make -j8 -f makefile all

echo.

运行这个 bat 文件应该可以完成这项工作!如果一切顺利,您将得到一个.bin和一个.elf二进制文件作为编译的结果。

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 调试器 (GDB)。这就是为什么 OpenOCD 还在 TCP 端口 3333 上启动 GDB 服务器的原因。GDB 客户端可以连接到该端口,并开始调试微控制器!

  • Gnu Debugger 是一个命令行软件。许多人更喜欢可视化界面。这正是 Eclipse 所做的。Eclipse 启动了一个连接到 OpenOCD 的 GDB 客户端——但这对用户来说都是隐藏的。Eclipse 提供了一个图形界面,可以在后台与 GDB 客户端进行交互。

我做了一个图来解释所有这些事情:

在此处输入图像描述

>> 启动 OpenOCD

我设法从命令行启动了 OpenOCD。我会解释如何。

  1. 首先确保您的 STLink-V2 JTAG 编程器已正确安装。您可以使用 STMicroelectronics 的“STLink Utility 工具”测试安装。它有一个不错的 GUI,您只需单击连接按钮。 在此处输入图像描述
  2. 接下来从该网站下载 OpenOCD 软件可执行文件:http: //gnutoolchains.com/arm-eabi/openocd/。安装它,并将其放在硬盘上的文件夹中,例如“C:\Apps\”。
  3. 打开命令终端,然后启动 OpenOCD。您需要为 OpenOCD 提供一些配置文件,以便它知道在哪里寻找您的微控制器。通常您需要提供一个描述 JTAG 编程器的配置文件和一个定义您的微控制器的配置文件。-f使用命令行中的参数将这些文件传递给 OpenOCD 。您还需要scripts通过传递参数来授予 OpenOCD 对文件夹的访问权限-s。这就是我使用命令行在我的计算机上启动 OpenOCD 的方式:

    > "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"
    
  4. 如果您正确启动了 OpenOCD(使用正确的参数),它将启动并显示以下消息:

    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
    
  5. 请注意,您的终端窗口现在已被阻止。您不能再键入命令。但这是正常的。OpenOCD 在后台运行,它会阻塞终端。现在您有两个与 OpenOCD 交互的选项:您在另一个终端中启动 Telnet 会话,然后登录到 TCP 端口localhost:4444,这样您就可以向 OpenOCD 发出命令并接收反馈。或者您启动一个 GDB 客户端会话,并将其连接到 TCP 端口localhost:3333

>> 启动 Telnet 会话以与 OpenOCD 交互

这是您启动 Telnet 会话以与正在运行的 OpenOCD 程序交互的方式:

> dism /online /Enable-Feature /FeatureName:TelnetClient

> telnet 127.0.0.1 4444

如果运行良好,您将在终端上收到以下消息:

Open On-Chip Debugger
> ..

你已经准备好向 OpenOCD 发送命令了!但我现在将切换到 GDB 会话,因为这是与 OpenOCD 交互的最方便的方式。

>> 启动 GDB 客户端会话以与 OpenOCD 交互

打开另一个终端窗口,然后键入以下命令:

> "C:\Apps\AC6GCC\bin\arm-none-eabi-gdb.exe"

该命令只是启动arm-none-eabi-gdb.exeGDB 客户端。如果一切顺利,GDB 会启动并显示以下消息:

    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 服务器:

    (gdb) target remote localhost:3333

现在您已连接到 OpenOCD!很高兴知道:如果您想使用本机 OpenOCD 命令(就像您在 Telnet 会话中所做的那样),只需在命令前加上关键字monitor. 这样,OpenOCD 内部的 GDB 服务器将不会自己处理命令,而是将其传递给本地 OpenOCD 守护进程。

所以,现在是时候重置芯片、擦除它并停止它了:

    (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 芯片中的所有闪存部分)不应受到保护:

    (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

接下来我再次停止芯片。只是要确定..

    (gdb) monitor halt

最后我将二进制.elf文件交给 GDB:

    (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 将这个二进制文件加载到芯片中。手指交叉:

    (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 中收到以下消息:

    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 芯片的过程非常相似:

            #################################################
            #        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 真的很深入。您似乎使用了 GNU make 实用程序的一些功能。请给我们更多的解释,我会给你奖金;-)

------------------------------

4

5 回答 5

8

我记得我在使用直接加载命令时也遇到了一些问题,所以我切换到“flash write_image erase my_project.hex 0 ihex”.. 显然我使用的是 hex 文件,但看起来 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

我希望这能让你摆脱困境

于 2016-07-17T05:45:17.847 回答
2

乍一看,gnutoolchains.com 上的发行版应该已经足够好了。有许多构建脚本可以酿造您自己的版本。我确实有我的包括 ARM7TDMI。它在 Linux 和 FreeBSD 下运行良好,但我上次尝试时 MinGW 失败了 :-(

关于 OpenOCD,我建议在与 GDB 实例相同的目录中启动它,以便从 GDB 中调用它时二进制下载看起来是透明的(最简单的方法)。您还可以选择创建一个脚本来启动 OpenOCD 并加载代码,但是您必须在每次编译后重新启动它。

于 2016-07-03T13:36:27.610 回答
2

这有点简短,而且不是很好的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”,然后像这样“arm-none-eabi-gdb -x ./debug_gpio_utest.gdbinit”调用您的交叉编译器gdb另一个...这将在刷新代码后启动 gdb,您可以使用 gdb 等中的正常 break 和 list 命令与代码交互(注意我如何在 .gdbinit 文件中定义重置命令,查看 mon 的帮助command ... 基本上它会让你通过 gdb 直接向 openocd 发送命令,非常有用)

抱歉,答案很简短,链接很多,但我希望它能让你继续前进。

于 2016-06-30T09:35:05.220 回答
1

您现在只需调用“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

于 2016-06-28T02:01:12.393 回答
0

显然这是一个硬件问题。我从没想过我的芯片会有缺陷,因为使用 STLink Utility 工具将二进制文件加载到芯片上没有问题。只有 OpenOCD 抱怨并给出错误。所以我很自然地责怪 OpenOCD——而不是芯片本身。

今天我用板上的新芯片尝试了相同的程序,现在它可以工作了!

load发出命令时,我在 GDB 中得到以下输出:

    (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)

感谢所有竭尽全力帮助我的人:-)

于 2016-07-20T10:09:43.970 回答