CubeMX+VSCode+Ozone的STM32开发工作流(一)背景知识介绍

news2024/11/28 18:57:43

neozng1@hnu.edu.cn

TODO:
1. 添加一键编译+启用ozone调试/一键编译+下载的脚本,使得整个进一步流程自动化
2. 增加更多的背景知识介绍
3. 增加VSCode下RTT viewer的支持和一键下载(不进入调试)的支持

前言

了解过嵌入式开发的你一定接触过Keil,这款20世纪风格UI的IDE伴随很多人度过了学习单片机的岁月。然而由于其缺少代码补全、高亮和静态检查的支持,以及为人诟病的一系列逆天的设置、极慢的编译速度(特别是在开发HAL库时),很多开发者开始转向其他IDE。

IAR、CubeIDE等都是广为使用的“其他”IDE,但是他们也有各自的缺点,不能让笔者满意。作为IDE界的艺术家,JetBrains推出的Clion也在相当程度上完善了对嵌入式开发的支持。不过,在体验过多款IDE后,还是VSCode这款高度定制化的编辑器最让人满意。强大的补全和snippet以及代码高亮、定义跳转甩KEIL十条街。

而Ozone则是SEGGER(做jilnk的)推出的调试应用,支持变量实时更新,变量曲线可视化,SEGGER RTT日志,DBG虚拟串口等功能,大大扩展了调试的功能。很多人习惯使用串口进行可视化调试,如vofa,串口调试助手等。然而通过这些方式进行调试,都是对内核有侵入性的,会占有内核资源并且导致定时器的时间错乱。由于DBG有单独连接到FLASH和CPU寄存器的高速总线(类似于DMA),可以在不影响程序正常运行的情况下以极高的频率直接获取变量值。

下面,将从工具链介绍、环境配置以及调试工作流三个方面介绍以VSCode为编辑器,Ozone为调试接口的开发环境。

开发的大致流程为:

本教程不仅希望教会你如何配置环境,同样会告诉你每一步究竟是在做什么,而不是简单的复制黏贴邯郸学步。

前置知识

  1. 计算机速成课:Crash Course Computer Science
  2. 从零到一打造一台计算机:
    编程前你最好了解的基本硬件和计算机基础知识(模拟电路)
    编程前你最好了解的基本硬件和计算机基础知识(数字电路)
    从0到1设计一台计算机
  3. C语言基础:程序设计入门——C语言

务必学完以上课程再开始本教程的学习。

如果有可能,还应该学习: 哈佛大学公开课:计算机科学cs50。你将会对单片机和计算机有不同的理解。

预备知识

  1. 软件安装
  2. C语言从源代码到.bin和.hex等机器代码的编译和链接过程
  3. C语言的内存模型
  4. C语言标准,动态链接库和静态编译的区别,一些编译器的常用选项
  5. STM32F4系列的DBG外设工作原理
  6. GDB调试器、硬件调试器和DBG的关系

编译全过程

C语言代码由固定的词汇(关键字)按照固定的格式(语法)组织起来,简单直观,程序员容易识别和理解,但是CPU只能识别二进制形式的指令,并且这些指令是和硬件相关的(感兴趣的同学可以搜索指令集相关内容)。这就需要一个工具,将C语言代码转换成CPU能够识别的二进制指令,对于我们的x86平台windows下的程序就是.exe后缀的文件;对于单片机,一般来说是.bin或.hex等格式的文件(调试文件包括axf和elf)。

能够完成这个转化过程的工具是一个特殊的软件,叫做编译器(Compiler)。常见的编译器包括开源的GNU GCC,windows下微软开发的visual C++,以及apple主导的llvm/clang。编译器能够识别代码中的关键字、表达式以及各种特定的格式,并将他们转换成特定的符号,也就是汇编语言(再次注意汇编语言是平台特定的),这个过程称为编译(Compile)

对于单个.c文件,从C语言开始到单片机可识别的.bin文件,一般要经历以下几步:

不知道图源哪里,侵删

首先是编译预处理Preprocessing,这一步会展开宏并删除注释,将多余的空格去除。预处理之后会生成.i文件。

然后,开始编译Compilation的工作。编译器会将源代码进行语法分析、词法分析、语义分析等,根据编译设置进行性能优化,然后生成汇编代码.s文件。汇编代码仍然是以助记符的形式记录的文本,比如将某个地址的数据加载到CPU寄存器等,还需要进一步翻译成二进制代码。

下一步就是进行汇编Assemble,编译器会根据汇编助记符和机器代码的查找表将所有符号进行替换,生成.o .obj等文件。但请注意,这些文件并不能直接使用(烧录),我们在编写代码的时候,都会包含一些,因此编译结果应当有多个.o文件。我们还需要一种方法将这些目标文件缝合在一起,使得在遇到函数调用的时候,程序可以正确地跳转到对应的地方执行。

最后一步就由链接器Linker(也称LD)完成,称为链接Linking。比如你编写了一个motor.c文件和.h文件,并在main.c中包含了motor.h,使用了后者提供的MotorControl()函数。那么,链接器会根据编译器生成.obj文件时留下的函数入口地址,将main.o里的调用映射到生成的motor.o中。链接完成后,就生成了单片机可以识别的可执行文件,通过支持的串口或下载器烧录,便可以运行。

另外,上图可以看到左侧的 静态库,包括 .lib .a,比如我们在STM32中使用的DSP运算库就是这种文件。他在本质上和.o文件相同,只要你在你编写的源文件中包含了这些库的头文件,链接器就可以根据映射关系找到头文件中声明的函数在库文件的地址。(直接提供库而不是.c文件,就可以防止源代码泄露,因此一些不开源的程序会提供函数调用的头文件和接口具体实现的库;你也可以编写自己的库,感兴趣自行搜索)

链接之后,实际上还要进行不同代码片段的重组、地址重映射,详细的内容请参看:C/C++语言编译链接过程,这篇教程还提供了以GCC为例的代码编译示例。

C语言内存模型

好像图源CSDN,侵删

以上是C语言常见的内存模型,即C语言的代码块以及运行时使用的内存(包括函数、变量等)的组织方式。

有些平台的图与此相反,栈在最下面(内存低地址),其他区域都倒置,不影响我们理解

代码段即我们编写的代码,也就是前面说的编译和链接之后最终生成的可执行文件占据的空间。一些常量,包括字符串和使用const关键字修饰的变量被放在常量存储区。static修饰的静态变量(包括函数静态变量和文件静态变量)以及全局变量放在常量区上面一点的全局区(也称静态区)。

然后就是最重要的。在一个代码块内定义的变量会被放在栈区,一旦离开作用域(出了它被定义的{}的区域),就会立刻被销毁。在调用函数或进入一个用户自定义的{}块,都会在栈上开辟一块新的空间,空间的大小和内存分配由操作系统或C库自动管理。一般来说,直接通过变量访问栈内存,速度最快(对于单片机)。而堆则是存储程序员自行分配的变量的地方,即使用malloc(),realloc() ,new等方法获取的空间,都被分配在这里。

在CubeMX初始化的时候,Project mananger标签页下有一个Linker Setting的选项,这里是设置最小堆内存和栈内存的地方。如果你的程序里写了大规模的数组,或使用 malloc()等分配了大量的空间,可能出现栈溢出或堆挤占栈空间的情况。需要根据MCU的资源大小,设置合适的stack size和heap size。

RTOS创建任务的时候也会为每个任务分配一定的栈空间,它会替代MCU的硬件裸机进行内存的分配。可以在CubeMX中设置。如果一个任务里定义了大量的变量,可能导致实时系统运行异常,请增大栈空间。

开发板C型使用F407IG芯片,片上RAM的大小为1MB。

C language标准和编译器

不同的C语言标准(一般以年份作代号)支持的语法特性和关键字不同,拥有的功能也不同。一般来说语言标准都是向前兼容的,在更新之后仍然会保存前代的基本功能支持(legacy support)。不过,为了程序能够正常运行,我们还需要一些硬件或平台支持的组件。比如malloc()这个函数,在linux平台和windows平台上的具体实现就相去甚远,跟单片机更是差了不止一点。前两者一般和对应的操作系统有关,后者在裸机上则是直接通过硬件或ST公司提供的硬件抽象层代码实现。

然而,不同编译器提供的代码实现也不尽相同,比如使用clang和gcc这两种c语言编译器,他们对于一些标准库(也称C库,包括stdio,stdlib,string等在内的实现)的函数的实现就不太一样。再如__packed是arm-cc提供的一个字节不对齐关键字,在一些其他编译器中就不支持这种实现。

以前大家常用的KEIL使用的是ARM提供的arm-cc工具链(非常蛋疼,甚至不支持uint8_t=0b00001111这种二进制定义法),而该教程选用的是开源的Arm GNU Toolchain。在非目标机且和目标机平台不同的平台上进行开发被成为跨平台开发,进行的编译也被成为交叉编译(在一个平台上生成另一个平台上的 可执行代码)。

工具链包含了编译器,链接器以及调试器等开发常用组件。我们使用的Arm GNU toolchain中,编译器是 arm-none-eabi-gcc.exe,链接器是 arm-none-eabi-ld.exe,调试器则是 arm-none-eabi-gdb.exe。通过跨平台调试器和j-link/st-link/dap-link,我们就可以在自己的电脑上对异构平台(即单片机)的运行进行调试了。

Debug外设工作原理

来自STM32F407IG的datasheet

DBG支持模块(红框标注部分,也可以看作一个外设)通过一条专用的AHB-AP总线和调试接口相连(Jtag或swd),并且有与数据外设总线直接相连的桥接器。它还同时连接了中断嵌套管理器(因此同样可以捕获中断并进行debug)和ITM、DWT、FPB这些调试支持模块。因此DBG可以直接获取内存或片上外设内的数据而不需要占用CPU的资源,并将这些数据通过专用外设总线发送给调试器,进而在上位机中读取。

FPB是flash patch breakpoint闪存指令断点的缩写,用于提供代码断点插入的支持,当CPU的指令寄存器读取到某一条指令时,FPB会监测到它的动作,并通知TPIU暂停CPU进行现场保护。

DWT是data watch trace数据观察与追踪单元的缩写,用于比较debug变量的大小,并追踪变量值的变化。当你设定了比较断点规则(当某个数据大于/小于某个值时暂停程序)或将变量加入watch进行查看,DWT就会开始工作。DWT还提供了一个额外的计时器,即所有可见的TIM资源之外的另一个硬件计时器(因为调试其他硬件定时器的计时由于时钟变化可能定时不准,而DWT定时器是始终正常运行的)。它用于给自身和其他调试器模块产生的信息打上时间戳。我们的bsp中也封装了dwt计时器,你可以使用它来计时。

ITM是instrument trace macrocell指令追踪宏单元的缩写,它用于提供非阻塞式的日志发送支持(相当于大家常用的串口调试),SEGGER RTT就可以利用这个模块,向上位机发送日志和信息。这个硬件还可以追踪CPU执行的所有指令,这也被称作trace(跟踪),并将执行过的指令全部通过调试器发送给上位机。当debug无法定位bug所在的时候,逐条查看cpu执行的指令是一个绝佳的办法,特别是你有大量的中断或开启了实时系统时。

以上三个模块都需要通过TPIU(trace port interface unit)和外部调试器(j-link等)进行连接,TPIU会将三个模块发来的数据进行封装并通过DWT记录时间,发送给上位机。

GDB调试MCU原理

图源博客园某博客,找不到具体出处了,侵删

不论使用MDK(KEIL)还是VSCode还是Ozone,实际上背后的流程相同。首先GDB会建立TCP/IP端口并提供接口,调试服务器(Server)作为硬件调试器和GDB软件的桥梁,将硬件调试器的相关功能(也就是DBG外设支持的那些功能)映射到GDB的接口上(通过连接到GDB建立的端口)。之后启动调试,将可执行文件下载到目标MCU上,然后从main开始执行

当然你也可以选择从其他启动点开始执行,调试器开始执行的位置叫做 entry point。同样,在MCU已经正在运行程序的时候,可以 attach到程序上开始监控(attach=附加,贴上;很形象了)。
而对于直接运行在电脑上的程序(.exe),就不需要GDBserver和物理调试器,GDB程序可以直接访问电脑上运行的程序和CPU的寄存器等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]java毕业设计校园求职与招聘系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

单克隆抗体WuT9/甘草次酸-氟尿嘧啶偶联顺铂/RGD肽修饰聚谷氨酸-顺铂复合物的制备

小编下面整理了单克隆抗体WuT9/甘草次酸-氟尿嘧啶偶联顺铂/RGD肽修饰聚谷氨酸-顺铂复合物的制备,来看! RGD肽修饰聚谷氨酸-顺铂复合物制备: 以改性聚谷氨酸侧链羧基与顺铂稳定配位,再与RGD肽进行化学偶联,得到修饰后的药物复合物,对复合物的…

【Java基础】HashMap扩容 | CopyOnWriteArrayList 的底层原理 | 字节码 | Java 异常体系

1. HashMap的扩容机制 JDK 1.7 扩容是针对数组进行扩容,链表是不需要进行扩容的。扩容时先生成原来数组两倍大小的新数组,在把原来老数组上的链表上的元素转移过去。具体在转移链表中元素的步骤是:取每个元素的 key,基于新数组长…

Java反射学习笔记--使用示例

简介 反射是Java编程语言中的一个特性。它允许执行的Java程序 检查 或 操作 自身,并操作程序的内部属性。例如,Java类可以获取其所有成员的名称并显示它们。 反射的一个具体用途是在JavaBeans中,软件组件可以通过一个构建工具进行可视化操作…

specCPU 2006 备忘

前言 首先 specCPU是收费的,好像是800还是1000$,缴费了才有软件分发给你,但是个人或者国内某些项目测试都是百度或者找整机,CPU或者操作系统厂家给。 specCPU和其他性能测试工具类似,基本上都是在被测试机器现场编译测试程序&am…

C++11主要新增使用语法介绍

目录 1. C11简介 2. 统一的列表初始化 2.1 {}初始化 2.2 std::initializer_list 3. 声明 3.1 auto 3.2 decltype 3.3 nullptr 4. STL中一些变化 5. 右值引用和移动构造/赋值 5. 1 左值引用和右值引用 5.2 右值引用使用场景和意义 5.3 完美转发…

map底层实现原理

目录一、map数据结构二、bucket数据结构三、哈希冲突四、负载因子五、渐进式扩容1.扩容的前提条件2.增量扩容3.等量扩容六、查找过程七、插入过程八、Map的value赋值九、Map的遍历赋值一、map数据结构 Golang的map使用哈希表作为底层实现,一个哈希表里可以有多个哈…

2022-11-20 C++并发编程( 四十四 ) -- 通讯顺序进程 CSP 范型

C并发编程 -- 四十四 前言一、通讯顺序进程 CSP 范型1. 细节分解1. lambda 封装类成员函数和 std::function< > 函数封装器2. 模板和 dynamic_cast< >类型转换二、ATM 示例总结前言 并发编程除了常规的使用锁, 或无锁结构实现某些并发计算, 还有没有其它实现形式?…

controller-informer

推翻了自己的三次理论&#xff0c;最终确定informer流程。自己梳理&#xff0c;有错请提示&#xff0c;以便及时改正 一、流程图 图1为整体流程&#xff0c;图2位细节流程 二、主要组件 Reflector-负责与API-Server进行绑定Delta FIFO-增量先进先出队列Indexer-本地缓存Resour…

Linux--系统基础磁盘管理相关知识详解笔记

1.磁盘知识体系结构 第一个层次&#xff1a;磁盘相关物理知识 内部结构 外部结构 读写数据原理 第二个层次&#xff1a;磁盘阵列知识 磁盘弹性扩展知识 ​ 阵列&#xff1a;将多块磁盘整合为一块 ​ &#xff08;1&#xff09;可以存储更大容量数据 ​ &#xff08;2&#…

[附源码]java毕业设计心理问题咨询预约系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

docker启动mysql实例之后,docker ps命令查询不到

1.首先拉取mysql,创建并启动实例 #docker pull mysql:5.7 # docker run -p 3306:3306 --name mysql \ -v /mydata/mysql/log:/var/log/mysql \ -v /mydata/mysql/data:/var/lib/mysql \ -v /mydata/mysql/conf:/etc/mysql \ -e MYSQL_ROOT_PASSWORDroot \ -d mysql:5.7…

Softing DTS.monaco 9.03新版发布,带有远程接口、并行诊断和动态VCI处理功能

2022年10月24日&#xff0c;Softing推出了“诊断工具集&#xff08;DTS&#xff09;”的新版本——Softing DTS.monaco 9.03。9.03版的诊断测试仪Softing DTS.monaco包含了很多新功能&#xff0c;将使您的工作变得更加简单。由于集成了一个新的连接插件&#xff08;动态VCI处理…

XCZU19EG_FFVC1760芯片的封装和管脚

首先写这篇文章是因为我有接触到这款芯片&#xff0c;但是在做接口约束时&#xff0c;有许多地方并不是很清楚&#xff0c;因此在这里对官方文档(ug1075)进行了通读&#xff0c;只翻译了我觉得我需要用到和需要了解的地方&#xff0c;具体是什么还需要大家去自己阅读官方文档。…

LeetCode 319 周赛

纪念本狗第三次AK&#xff01;&#xff01;&#xff01; 2469. 温度转换 给你一个四舍五入到两位小数的非负浮点数 celsius 来表示温度&#xff0c;以 摄氏度&#xff08;Celsius&#xff09;为单位。 你需要将摄氏度转换为 开氏度&#xff08;Kelvin&#xff09;和 华氏度&a…

RK3568平台开发系列讲解(图像篇)JPEG图像处理

🚀返回专栏总目录 文章目录 一、JPEG文件格式和libjpeg编译二、libjpeg接口函数三、JPEG文件解析沉淀、分享、成长,让自己和他人都能有所收获!😄 📢我们今天来讲解JPEG图像处理。 一、JPEG文件格式和libjpeg编译 JPEG的后缀名为.jpg的图像文件。对于图像内容和信息相同…

Windows安装docker踩坑

安装过程中出现一下问题&#xff0c;步骤如下 菜鸟教程安装windows docker https://www.runoob.com/docker/windows-docker-install.html 启动后报错wsl2错误&#xff0c;因为本机运行的是wsl1&#xff0c;进行解决 wsl -l -v查看运行的虚-了拟机的版本以及状态 因为默认运…

一文带你学习,动态规划算法

一文带你学习&#xff0c;动态规划算法1.什么是动态规划&#xff08;DP&#xff09;2.青蛙跳台阶问题暴力递归解法自顶向下的递归解法自底向上的动态规划解法3.动态规划的解题套路穷举分析确定边界确定最优子结构写出状态转移方程4.经典线性DP&#xff1a;数字三角形5.01背包&a…

金鸡奖提名电影《巴林塔娜》,主题曲和腾格尔合作是未卜先知吗

在刚刚结束的第三十五届金鸡奖上&#xff0c;由十月天传媒推送的电影《巴林塔娜》&#xff0c;获得了最佳提名奖的荣誉。根据资料显示&#xff0c;十月天传媒是来自北京的一家公司&#xff0c;也是国内最具专业的综合性文化产业运营机构。 话说十月天传媒的董事长袁熙伯先生&am…

Qt OpenGL(二十四)——Qt OpenGL 核心模式-实现彩色三角形

Qt OpenGL(二十四)——Qt OpenGL 核心模式-实现彩色三角形 我们之前在Qt OpenGL 核心模式版本中,看到了Qt关于OpenGL的例程,是一个旋转的彩色三角形,本篇文章我们就使用OpenGL核心模式,实现这个彩色三角形。 图1 旋转的三角形 一、彩色三角形 上一篇文章(Qt OpenGL 核心…