type
status
date
slug
summary
tags
category
icon
password
2024.1.10~2024.1.17
Steps
  1. 使用OpenOCD 下载代码
  1. 使用VSCode 对代码打断点调试
  1. 移植综合设计开发环境
  1. 配置PX4本地编译环境,编译PX4 固件
  1. 使用OpenOCD 调试PX4固件 (TODO)

01 · VSCode 开发STM32环境配置(macOS)

“优雅的嵌入式开发。”
一直以来IDE用的太多,代码编译等基本环节知识欠缺了不少,趁此机会仔细琢磨下。对于其他类unix系统,下文步骤中的包管理器和环境变量配置可能有些需要更改的地方。

开发环境

默认已经安装好Homebrew包管理器。使用brew安装的包默认都在/opt/homebrew/文件夹下,并且将自动创建符号链接至路径/opt/homebrew/bin下,不用手动配置环境变量。/opt是“可选项”(optional)的缩写,用于存放可选的、独立于操作系统提供的软件包的文件。
  • 研究一下类unix系统的文件构建体系
暂时无法在成电飞书文档外展示此内容

工具链

  • 安装交叉编译链 GNU Armmbedded Toolchain
    • More Versions:developer.arm.com
    • 打开terminal,输入
      • 这一行指令会安装arm-none-eabi-gccarm-none-eabi-gdb以及 arm-none-eabi-binutils的完整工具链。
    • 安装完毕后,输入 arm-none-eabi-gcc -varm-none-eabi-gdb -v 指令,如果出现版本信息即可
      • notion image
        notion image
  • 安装openOCD
    • 打开terminal,输入
    • 为什么安装openOCD时还显示在安装openCV和PCL之类的?
    • 看看版本openocd -v
    • notion image
  • 安装STLink
    • 打开terminal,输入
      • 使用st-info --probe查看STlink连接情况
        • notion image
    • 终端命令行测试
      • 在命令行里使用make与openocd指令对一demo进行测试,解决所有问题后编辑VScode里Workspcae的配置
        • 使用Cube32MX快速新建一个点灯的demo;Generate Code时选择“Makefile”选项
        • 编译
          • 终端返回(在当前目录新建了build目录) ...... arm-none-eabi-size build/TESTFOROpenOCD.elf text data bss dec hex filename 4264 20 1572 5856 16e0 build/TESTFOROpenOCD.elf arm-none-eabi-objcopy -O ihex build/TESTFOROpenOCD.elf build/TESTFOROpenOCD.hex arm-none-eabi-objcopy -O binary -S build/TESTFOROpenOCD.elf build/TESTFOROpenOCD.bin
          • 下载
              1. 两个.cfg文件:stlink.cfg 和 stm32f4x.cfg
                  • 可以在/OpenOCD/share/openocd/scripts中找到。
              终端返回:
              1. 板载小灯此时亮起,烧录成功。

      VSCode配置

      • 编译&下载:配置Task.json
        • 配置三个task:编译、烧录以及清除已编译的文件。这样一来,我们仅仅需要通过command+shift+B即可执行上面在命令行中输入的一长串指令。下面以烧录为例,其余两条指令只需要调整command以及args部分。
      • 调试:配置Launch.json
        • 创建Launch.json,添加如下:
        • 需要注意"svdFile"项:svd文件包含了寄存器等信息,是单步调试与查看寄存器信息的关键。该文件可以前往Keil5安装路径的Pack文件夹下查找,也可以前往下面这个网址下载:
          • https://github.com/modm-io/cmsis-svd-stm32
      随即可以开始单点调试
      notion image
      notion image
      至此,整个开发环境配置完成。

      参考

      https://lrl52.top/950/linux-build-embedded-env/
      https://blog.csdn.net/weixin_54911557/category_12167262.html
      https://zhuanlan.zhihu.com/p/145801160
      https://zhuanlan.zhihu.com/p/114311741
      https://zhuanlan.zhihu.com/p/376450754
      https://zhuanlan.zhihu.com/p/468568448

      问题

      • 遭遇报错:
        • notion image
        • 一篇详细的文章讲解高版本gcc对于#include_next的处理
          • https://www.jianshu.com/p/94faa8d32519
          • 临时解决方案:卸载13.2版本的arm-none-eabi-gcc,手动更换为 10.3.1 20210824 (release)版本。
          • TODO:macOS与Ubuntu的环境变量管理
            • 研究一下/etc/path.d/内的东西
      • 什么是SVD文件,作用是什么?
        • SVD文件是指System View Description文件,它是一种描述硬件设备寄存器映射和外设配置的文件格式。SVD文件通常用于嵌入式系统开发中,特别是在使用CMSIS(Cortex Microcontroller Software Interface Standard)的情况下。
          SVD文件的作用如下:
        • 描述寄存器映射:SVD文件定义了硬件设备的寄存器映射,包括每个寄存器的地址、大小、访问权限和位域的描述。它提供了一个结构化的方式来描述设备寄存器的布局和功能。
        • 自动生成驱动代码:基于SVD文件,可以使用自动化工具生成设备驱动代码。这些代码可以用于访问和配置设备寄存器,简化了驱动程序的编写和维护过程。
        • IDE集成和调试支持:一些集成开发环境(IDE)可以使用SVD文件提供硬件的可视化和调试支持。通过加载SVD文件,IDE可以了解设备的寄存器布局和功能,并在调试过程中显示寄存器的状态和值。
        • 硬件抽象和代码重用:SVD文件提供了一种硬件抽象的方式,使得应用程序可以与具体的硬件平台解耦。通过使用SVD文件,可以编写可移植的应用程序代码,并在不同的硬件设备上进行重用。
        • 总之,SVD文件是一种用于描述硬件设备寄存器映射和配置的文件格式,它在嵌入式系统开发中扮演着重要的角色,用于生成驱动代码、提供调试支持和实现硬件抽象等功能。
      • openOCD如何利用SVD进行调试工作?
        • OpenOCD(Open On-Chip Debugger)是一种开源的调试和编程工具,用于与嵌入式系统中的处理器和调试接口进行通信。OpenOCD可以与SVD文件相配合,以提供基于寄存器级别的调试和可视化支持。
          以下是OpenOCD与SVD文件相配合的主要步骤:
        • 获取SVD文件:首先,需要获取适用于目标设备的SVD文件。SVD文件通常由芯片厂商提供,可以在芯片或开发板的文档或支持页面上找到。确保选择与目标设备完全匹配的SVD文件。
        • 配置OpenOCD:接下来,需要配置OpenOCD以使用SVD文件。打开OpenOCD的配置文件(例如"openocd.cfg"),在配置文件中添加以下内容:
          • 启动OpenOCD:通过命令行或集成开发环境(IDE)启动OpenOCD。OpenOCD将根据配置文件加载SVD文件并初始化调试接口。
          • 调试和可视化:一旦OpenOCD启动,你可以使用适当的调试工具(例如GDB)连接到OpenOCD,以进行寄存器级别的调试。在调试过程中,OpenOCD将使用SVD文件提供寄存器的名称、位域的描述和当前值,以及其他相关信息。这使得调试过程更加直观和可视化,可以更方便地查看和修改寄存器的状态。
          • 通过将OpenOCD与SVD文件相配合,可以实现基于寄存器级别的调试和可视化支持,提供更好的开发体验。SVD文件的加载使得调试过程更具可读性和可理解性,帮助开发人员更好地理解和控制目标设备的寄存器状态。

        02 · 移植综设开发环境

        • 整理一下在ST的标准外设库函数开发环境下的项目架构。移植到Vscode下进行开发后,需要自己理清文件关系与编译命令,才能正确的编写Makefile
        暂时无法在成电飞书文档外展示此内容

        编译的过程

        在编写Makefile前,我们先复习一下编译技术,理清一下使用交叉编译器对ARM-CortexM4架构目标进行编译的过程,以便于我们写好系列Rules。在这里,我们自顶向下的分析一下。理清各种步骤后,可以通过指令arm-none-eabi-gcc --help来查看如何调用参数来实现目的需求。

        最终生成目标——链接系列.o文件

        • 在嵌入式开发过程中,最终有三种文件可以烧写到STM32的板子中执行:.elf .hex .bin
          • .elf 文件(Executable and Linkable Format):它是一种可执行文件和可链接文件的标准格式。.elf 文件包含了编译器和链接器生成的可执行代码、全局变量、符号表和其他调试信息。它是嵌入式应用程序的最终生成文件,可以用于调试、运行和部署。
          • .hex 文件(Intel Hexadecimal Format):它是一种用于存储二进制数据的文本文件格式。.hex 文件通常用于将程序烧录到目标设备的非易失性存储器(如闪存)中。烧录工具可以读取 .hex 文件并将其中的二进制数据按照特定的协议(如 Intel HEX)烧录到目标设备的存储器中。
          • .bin 文件(Binary Format):它是一种纯二进制文件,包含了编译器和链接器生成的可执行代码的二进制表示。.bin 文件通常用于将程序直接加载到目标设备的内存中,而不需要使用特定的烧录工具。.bin 文件可以通过串口、JTAG 等方式将程序加载到目标设备中运行。
        在开发过程中,我们更多选择烧录.elf文件到板子里去。 .hex .bin也是用.elf转换得来的(使用arm-none-eabi-objcopy )
        看了看珮泽师兄的Github仓库,是把一个.px4文件直接烧录到板子里去。GPT说 “.px4 文件通常是从 .elf 文件生成的,用于无人机飞控系统的固件文件,用于烧录到飞控硬件上实现飞行控制和导航功能。在开发过程中,开发者使用开发工具链(如 PX4 开发工具链)将源代码编译和链接生成 .elf 文件。然后,通过特定的构建和烧录过程,将 .elf 文件转换为 .px4 文件,以便将固件烧录到目标飞控硬件上。”
        暂时无法在成电飞书文档外展示此内容
        所以该如何生成呢?
        • .hex
          • O ihex:这是 arm-none-eabi-objcopy 工具的选项之一,用于指定输出文件的格式为 Intel HEX 格式。O 选项表示输出格式,ihex 是指定的输出格式名称。
          • build/HeiGuan.elf:这是输入文件的路径和名称,表示你要转换格式的 ELF 格式目标文件的路径和名称。
          • build/HeiGuan.hex:这是输出文件的路径和名称,表示转换后生成的 Intel HEX 格式文件的路径和名称。
        • .bin
          • O binary:同上,指定输出格式为binary
          • S:用于剥离(strip)目标文件中的符号信息。在转换过程中,只保留目标文件的原始二进制数据,而不包含符号表等调试信息。
          • build/HeiGuan.elf:输入文件的路径和名称
          • build/HeiGuan.bin:输出文件的路径和名称
        • .elf
          • 生成elf文件就需要用到链接器了。在交叉编译环节中,除了指定输入的系列.o文件,还需要指定系列目标平台的处理器架构、指令集等细节选项。在这里,需要查阅对应芯片的手册来确定一些关键选项:
          • xx_1.oxx_2.o:这是输入的目标文件,表示需要编译和链接的对象文件。这些文件可能是通过编译源代码而生成的。
          • mcpu=cortex-m4:用于指定目标处理器架构为 Cortex-M4。这将确保生成的代码在 Cortex-M4 处理器上正确运行。
          • mthumb:用于指定使用 Thumb 指令集。Thumb 是一种精简指令集,常用于嵌入式系统开发。
          • mfpu=fpv4-sp-d16:用于指定浮点运算单元(FPU)的类型。fpv4-sp-d16 表示使用单精度浮点运算(SP)和 16 位数据宽度。
          • mfloat-abi=hard:用于指定浮点运算的 ABI(Application Binary Interface)。hard 表示使用硬件浮点运算。
          • specs=nano.specs:用于指定链接时使用的规范文件nano.specs 是针对资源受限的嵌入式系统的规范文件。
          • TSTM32F401RETx_FLASH.ld:用于指定链接时使用的链接脚本文件。链接脚本定义了程序加载和内存布局的规则
          • lc -lm -lnosys:用于指定链接时需要使用的库文件lc 表示链接 C 标准库,lm 表示链接数学库,lnosys 表示链接无操作系统库。
          • Wl,-Map=build/HeiGuan.map,--cref用于指定链接器的参数Map=build/HeiGuan.map 表示生成链接地图文件,-cref 表示生成交叉引用信息。
          • Wl,--gc-sections:这是编译器选项,用于指定链接器对无用代码的剪裁。-gc-sections 表示剪裁无用的代码段,以减小生成的可执行文件的大小。
          • o build/HeiGuan.elf:这是编译器选项,用于指定输出文件的路径和名称。build/HeiGuan.elf 表示生成的可执行文件的路径和名称。

        中间文件.o的生成——分别编译.c和.s

        暂时无法在成电飞书文档外展示此内容
        我们需要使用gcc编译器将.s与.c文件编译为.o文件,系列.o文件将被用于生成.elf文件。除了.o文件,还有一些可以选择生成的.d和.lst文件。这两个文件是为了在编译过程中提供附加的信息和辅助功能。
        1. 生成 .d 文件(依赖关系文件): 1. .d 文件记录了源代码文件及其依赖项之间的依赖关系。这些依赖关系包括头文件的引用和其他源代码文件的引用。 2. 当一个源文件发生修改时,.d 文件可以被用来确定需要重新编译的文件,以及需要重新链接的目标文件。 3. 这对于大型项目和多文件项目非常有用,因为它可以避免不必要的重新编译,提高编译效率。 2. 生成 .lst 文件(汇编列表文件): 1. .lst 文件提供了对汇编代码的详细分析和解释。它包含了源代码的汇编表示,以及与之对应的机器指令和地址。 2. .lst 文件对于调试和代码优化非常有用。它可以帮助开发人员理解编译器生成的汇编代码,并进行针对性的优化和调试。 3. 通过查看 .lst 文件,可以了解编译器如何处理代码,如何分配寄存器和内存,并对代码执行路径进行分析。
        1. 1.
          1. 生成 .d 文件(依赖关系文件):
          2. 1.
            1. .d 文件记录了源代码文件及其依赖项之间的依赖关系。这些依赖关系包括头文件的引用和其他源代码文件的引用。
          3. 2.
            1. 当一个源文件发生修改时,.d 文件可以被用来确定需要重新编译的文件,以及需要重新链接的目标文件。
          4. 3.
            1. 这对于大型项目和多文件项目非常有用,因为它可以避免不必要的重新编译,提高编译效率。
        1. .d 文件记录了源代码文件及其依赖项之间的依赖关系。这些依赖关系包括头文件的引用和其他源代码文件的引用。
        1. 当一个源文件发生修改时,.d 文件可以被用来确定需要重新编译的文件,以及需要重新链接的目标文件。
        1. 这对于大型项目和多文件项目非常有用,因为它可以避免不必要的重新编译,提高编译效率。
        1. 2.
          1. 生成 .lst 文件(汇编列表文件):
          2. 1.
            1. .lst 文件提供了对汇编代码的详细分析和解释。它包含了源代码的汇编表示,以及与之对应的机器指令和地址。
          3. 2.
            1. .lst 文件对于调试和代码优化非常有用。它可以帮助开发人员理解编译器生成的汇编代码,并进行针对性的优化和调试。
          4. 3.
            1. 通过查看 .lst 文件,可以了解编译器如何处理代码,如何分配寄存器和内存,并对代码执行路径进行分析。
        1. .lst 文件提供了对汇编代码的详细分析和解释。它包含了源代码的汇编表示,以及与之对应的机器指令和地址。
        1. .lst 文件对于调试和代码优化非常有用。它可以帮助开发人员理解编译器生成的汇编代码,并进行针对性的优化和调试。
        1. 通过查看 .lst 文件,可以了解编译器如何处理代码,如何分配寄存器和内存,并对代码执行路径进行分析。
        • 从汇编文件生成.o文件
          • 这里有一个坑,前些日子一直报错,后来莫名其妙的解决了。昨天子为联系我说不同编译工具链的汇编文件语法不同,才恍然大悟。之前在Keil5中编写的.s都基于MDK工具链,而现在移植的环境是在gcc工具链。
          • 在这里仍然需要调用arm-none-eabi-gcc ,并如上文中生成.elf文件时指定处理器架构、指令集、浮点运算单元类型。除此之外,还需要额外指定:
          • x assembler-with-cpp:这是编译器选项,用于指定输入文件的类型为带有预处理指令的汇编源代码。这使得编译器能够识别并处理源文件中的预处理指令。
          • c:用于指定只进行编译操作,而不进行链接操作。这将生成一个目标文件,而不是可执行文件。
          • DUSE_STDPERIPH_DRIVERDSTM32F401xx定义宏
          • I./CORE/ -I./Hardware/ -I./Library/ -I./User/:用于指定头文件的搜索路径。I 选项后面跟着的路径表示头文件的目录路径。
          • Og:这是编译器选项,用于指定优化级别Og 表示进行调试级别的优化,以保留调试信息和原始代码的可读性。
          • Wall:这是编译器选项,用于启用所有警告信息。
          • fdata-sectionsffunction-sections:这是编译器选项,用于将数据和函数放置在单独的节(section)中。这有助于在链接时进行无用代码的剪裁。
          • g -gdwarf-2:这是编译器选项,用于生成调试信息g 表示生成调试信息,gdwarf-2 表示生成 DWARF 2 格式的调试信息。
          • MMD -MP -MF"build/startup_stm32f401xe.d":这是编译器选项,用于生成依赖关系文件MMD 表示生成依赖关系文件,MP 表示生成包含所有目标文件的规则,MF 指定依赖关系文件的名称和路径。
          • startup_stm32f401xe.s:这是输入的汇编源代码文件的路径和名称。
          • o build/startup_stm32f401xe.o:这是编译器选项,用于指定输出文件的路径和名称。build/startup_stm32f401xe.o 表示生成的目标文件的路径和名称。
        • 从源文件生成.o文件
          • 与上文从汇编文件生成并没有太多区别。值得注意的一点不同是:从.c文件生成.o文件时需要顺便生成.d和.lst两种文件 (汇编只用生成.d)。.lst文件是原代码的汇编表示,通过查看.lst文件可以分析编译器如何处理代码,如何分配寄存器等细节问题,便于进行深层次的DEBUG操作。
          • c:别忘了加上这个。在这里我们先只进行编译,不进行链接。
          • Wa,-a,-ad,-alms=build/main.lst:用于生成汇编代码的附加输出。Wa 后面跟着的参数用于指定附加输出的选项,a 表示生成汇编代码,ad 表示在汇编代码中包含所有指令的二进制表示,alms=build/main.lst 表示将汇编代码输出到名为 build/main.lst 的文件。
        这样,整个流程就顺下来了:
        暂时无法在成电飞书文档外展示此内容
        接下来就要考虑怎么写Makefile了。需要思考好Rule之间的关系,再构造足够多的变量用于保存命令中的那一大堆参数。

        Makefile编写

        https://lrl52.top/305/makefile/
        将上述
        notion image
        notion image
        • ./
          • Makefile
            • 在这里,我参照CubeMX生成的demo中的Makefile,对以下部分进行了修改:
              • 由于标准外设库函数的.c实在过多,此时选用了find命令来在当前目录和其子目录中递归搜索文件名匹配.c的所有文件
                • 之前的C_DEFS就是我们在Keil5中点小魔术棒中输入的宏定义。注意📢:根据gcc参数的规则,宏定义前需要加上D
                  • 这里配置头文件。需要注意的是,只需要将头文件所在目录丢给链接器即可,在书写这里的路径时不能具体到文件名xxxx.h
                    • 但是整个编译过程的几条Rules还没有理清楚,稍后下来仔细研究一下
                  • startup_stm32f401xe.s
                    • 一个普普通通的启动汇编文件,其中包含了系统初始化、中断服务和跳转到main函数的过程。但是直接复制粘贴Keil工程里的该文件会报错说找不到函数SystemInit和main函数的声明,此时我们需要在.global一行下添加:
                    • STM32F401RETx_FLASH.ld
                      • 一个链接脚本文件,用于在使用 STM32F401RETx 微控制器进行嵌入式软件开发时,定义了存储器布局和链接器的行为。 链接脚本文件是由链接器使用的配置文件,它指定了可执行程序在内存中的布局,包括代码、数据和其他部分的存放位置和大小。它还定义了链接器如何组织、分配和对齐代码和数据。
                    • ./Script
                      • 其中存储了F401RE的SVD文件
                    • ./CORE
                      • stm32f4xx.h
                      • core_cm4.h
                      • RTE_Components.h
                      • system_stm32f4xx.h
                      • system_stm32f4xx.c
                    • ./Hardware
                      • 放置自己写的系列硬件模块的驱动
                    • ./Library
                      • 放置标准外设库函数
                        • 注意📢,此处需要删除fsmc和fms外设的文件
                    • ./User
                      • 放置主函数、中断服务、Delay等函数的文件

                  03 · 配置PX4固件本地编译环境

                  克隆代码

                  开始编译

                  cd到PX4-Autopilot里去使用make hkust_nxt_bootloader来编译bootloader(make hkust_nxt-v1_bootloader用于编译develop_v1.14.x版本)使用make hkust_nxt来编译飞控固件(make hkust_nxt-v1用于编译develop_v1.14.x版本)
                  • 一种简单的方法,可以直接配置好所有需要依赖的包
                    但是由于此前电脑中已经安装了很多很多包,就打算直接硬make一发,按着报错来装pakage。
                    • 遭遇了几个报错
                      • CMake Version
                        • 电脑里安装的是3.28版本的cmake,感到非常奇怪,不知道为什么说cmake版本低于3.5。后来才发现是高于3.5版本的Cmake将不再与低于3.5版本的CmakeList兼容,但是这里的CMakeList兼容低于3.5版本的cmake;cmake在构建工程时就会面临一种版本箭筒问题的不确定性, 于是将CmakeList开篇的cmake_minimum_required(VERSION 3.2 FATAL_ERROR) 中的3.2改为3.5即可解决该问题。
                      • 提示策略CMP0148已被移除的warning
                        • 在CMake中,Policy(策略)是用来管理不同cmake版本之间行为和功能的变化的。策略定义了CMake的某个特定方面的行为规则。每个策略都有一个唯一的名称(CMPXXXX),其中XXXX是一个数字。通过设置相应的策略,你可以控制CMake的行为是否遵循新的规则或保持与旧版本的兼容性。
                        • 这个Warnning主要是对项目开发者看的,如果只是变一下来直接用,那使用 Wno-dev 指令即可让这条warnning不再出现;但为了彻底解决这个警告,我们需要使用cmake_policy指令来设置CMP0148的行为。
                      • 根据提示安装对应的包
                        • 需要注意empy的版本。最新的版本已经移除了.RAW_OPT属性,需要指定安装版本3.3.4
                      • 编译完后链接静态库失败:too many open files
                        • 没想到链接时除了问题,文件数过多,这时候需要修改一下系统的限制了。最后查出来是zsh把打开文件的最大数量限制到了256。遂改为65535,成功编译
                    notion image

                    参考

                    找到一个较为全面的PX4新手指南

                    问题

                    • NxtPX4上的TF卡是做什么的?如何指定PX4固件下载的地址与Bootloader下载的地址?
                    • PX4-Autopilot文件架构
                    • 没有在根目录的Makefile里找到hkust_nxt_bootloader的rule?

                    04 · 本地调试PX4固件

                    • 焊接上了,但是st-link移植检测不到设备😭
                    看看STM32H7的手册吧
                    似乎找到原因了,H7默认使用JTAG,要切换到SWD需要:
                    notion image
                    PX4·上手NxtPX4四轴 I——硬件子系统及PCB设计
                    Loading...