【正点原子MP157连载】第八章 STM32CubeIDE工程模板分析-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发指南

1)实验平台:正点原子STM32MP157开发板
2)购买链接:https://item.taobao.com/item.htm?&id=629270721801
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-318813-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子STM32MP157技术交流群:691905614
在这里插入图片描述

第八章 STM32CubeIDE工程模板分析

在第四章的操作中,我们通过第一个工程实验熟悉了STM32CubeIDE的基本使用方法,在第六和第七章我们分析了STM32CubeIDE下载的STM32CubeMP1固件包以及固件包中的HAL库,对HAL库有了基本的认识。本章节,我们以第一个工程为模板,分析一下工程的结构,了解工程中有哪些文件,他们的关系是什么,有什么作用。通过对工程的分析,我们可以了解工程和STM32CubeMP1固件包有着怎样密切的关系。
本章将分为如下几个小节:
8.1、STM32CubeIDE工程模板框架;
8.2、CA7文件夹分析;
8.3、CM4文件夹分析;
8.4、章节小结
8.1 STM32CubeIDE工程模板框架
我们打开前面第一个工程HAL_LED的保存目录,并对比STM32CubeIDE软件上的工程浏览窗口,他们的目录对应关系如下:
在这里插入图片描述

图8.1. 1 CubeIDE工程目录
HAL_LED工程根目录下的文件和文件夹描述如下:
在这里插入图片描述

表8.1. 1 HAL_LED工程根目录下的文件夹
Common文件夹下是system_stm32mp1xx.c文件,此文件我们在6.3.4小节有分析。
Drivers文件夹下包含的是STM32CubeMP1固件包中的Device文件夹和Include文件夹。其中,Device文件夹下是具体芯片直接相关的文件,里边是ST官方的STM32MP1xx器件专用的头文件、启动代码文件和专用系统文件。Include文件夹下是符合CMSIS标准的内核头文件,主要是核内外设文件。这些文件我们已经在前面的6.3小节有讲解,如果没有印象了还可以回过头看看,温故而知新。
.mxproject文件是STM32CubeIDE的配置文件,此文件是在创建工程以后生成的,在STM32CubeMX插件界面修改工程配置并保存,重新生成工程代码以后,此文件就会被更新。文件主要记录一些配置信息,如宏定义以及工程中要生成什么文件,例如在STM32CubeMX插件配置界面配置了GPIO,那么此文件中将会记录在CM4工程对应目录下添加gpio.h和gpio.c文件。
在这里插入图片描述

图8.1. 2 CubeIDE的配置文件
下面,我们分析CA7和CM4工程目录下有哪些文件。
8.2 CA7文件夹分析
CA7文件夹存放的是工程生成的设备树源文件。
在这里插入图片描述

图8.2. 1 CA7工程
其中tf-a里的设备树是uboot启动前加载到内存中的配置信息,类似于FSBL,它的作用主要是为硬件提供一个安全环境。u-boot下存放的是uboot启动阶段要用的设备树源文件,kernel下存放的是内核启动阶段用到的设备树源文件。打开其中一个设备树大概浏览一下,可以根据文件中给出的WIKI网址https://wiki.st.com/stm32mpu/wiki/Category:Device_tree_configuration去了解更多有关设备树的详细配置信息。关于设备树,正点原子的《STM32MP1嵌入式Linux驱动开发指南V1.0》文档有专门的讲解,设备树在Linux中是非常重要的,大家在学习Linux部分的知识点的时候会接触到这部分内容。
在这里插入图片描述

图8.2. 2工程中有用的注释
8.3 CM4文件夹分析
CM4里的文件就比较多了,它们是M4工程文件,下面我们逐个来说明这些文件的作用。
在这里插入图片描述

图8.3. 1M4工程
下表中是对CM4工程文件的一个汇总:
在这里插入图片描述

表8.3. 1 CM4工程列表
在生成工程的时候,STM32CubeIDE会从STM32CubeMP1固件包中拷贝必要的文件。其中在工程的根目录下,Common文件夹拷贝的是固件包中的system_stm32mp1xx.c文件,Drivers文件夹下拷贝的是固件包中的HAL库文件(包括头文件和源文件)。而CM4工程的Common文件夹和Drivers文件夹里的文件其实也是拷贝了STM32CubeMP1固件包中的源文件(没有拷贝头文件),其中,CM4工程的源文件会引用工程根目录下Drivers文件夹里的头文件。
在这里插入图片描述

图8.3. 2 工程文件和固件包文件的关系
怎么知道CM4工程引用的了工程根目录下Drivers文件夹里的头文件?打开CM4工程的Includes目录就知道了:
在这里插入图片描述

图8.3. 3 CM4工程和工程根目录文件的关系
工程目录是这样的结构,其实这跟我们创建工程时的配置有关,一开始我们创建工程的时候,Code Generator Options配置默认选择:Copy only the necessary library files,固件包默认在C盘下:
在这里插入图片描述

图8.3. 4创建工程时的配置
如果我们重新创建一个工程,工程名字命名为FOR_TEST(笔者随意命名的),然后在下面的Code Generator Options选项选择配置为Add necessary library files as reference in the toolchain project configuration file(一般不建议采用这种方式,下面会解释原因),然后固件包保存在另一个路径下,例如笔者选择保存在E:\STM32CubeIDE_Project\TEST目录下:
在这里插入图片描述

图8.3. 5更改创建工程的默认配置
点击Finish,系统开始在线下载固件包到E:\STM32CubeIDE_Project\TEST目录下:
在这里插入图片描述

图8.3. 6在线下载固件包
待工程创建完成,我们可以打开固件包的位置,看到固件包已经自动下载并自动解压好了。
在这里插入图片描述

图8.3. 7下载好的固件包
回到工程界面,对比一下新创建的FOR_TEST工程和之前的HAL_LED工程有什么不同,可以看到新建的FOR_TEST工程根目录下没有了Drivers文件夹,CM4工程直接引用固件包里Drivers文件的头文件。不过一般不建议采用FOR_TEST工程的这种创建方式,因为可能会不小心修改固件包里的头文件,毕竟上面的头文件是直接引用了固件包里的。新创建的工程结构,如下图所示:
在这里插入图片描述

图8.3. 8新创建的工程结构

  1. Binaries
    Binaries下有HAL_LED_CM4.elf文件,它是指向Debug目录下生成的.elf文件,我们编译完以后可以直接看Binaries下有没有.elf文件,有的话编译成功。可以在工程中选中HAL_LED_CM4.elf文件然后右键查看Properties属性。
    在这里插入图片描述

图8.3. 9工程中Binaries文件夹
2. Common文件夹
Common文件夹下有一个system_stm32mp1xx.c文件,此文件和工程根目录下的Common文件夹中的system_stm32mp1xx.c文件一模一样,这个文件其实也就是我们第6.3.4小节分析的STM32CubeMP1固件包中的system_stm32mp1xx.c文件。在生成工程的时候,STM32CubeIDE会从之前下载的STM32CubeMP1固件包中拷贝这些文件到工程对应目录中。
system_stm32mp1xx.c文件提供SystemInit函数、SystemCoreClockUpdate函数和SystemCoreClock变量。SystemCoreClockUpdate函数的作用就是,根据时钟寄存器的值来更新SystemCoreClock变量,SystemCoreClock变量包含系统时钟频率,用户应用程序可以使用它来设置SysTick定时器或配置其他参数。系统复位以后,在跳到main函数之前,SystemInit函数被startup_stm32mp1xx.s启动文件调用,SystemInit函数中主要是初始化FPU设置、配置SRAM中的向量表和禁用所有中断和事件。关于system_stm32mp1xx.c文件的详细细节,可以回头看看第6.3.4小节的介绍。
3. Core文件夹
Core文件夹下主要是STM32CubeIDE自动生成的操作外设要用到的API函数文件和main函数文件。其中Inc下主要是API的头文件,Src下主要是API的源文件,实验中我们操作的是GPIO,所以会看到有关GPIO的API函数gpio.c和gpio.h,如果此时在工程中配置UART,那么就会多出uart.c和uart.h文件。我们分析一下这些文件:
gpio.c文件是GPIO引脚配置的代码,例如GPIO的时钟使能和GPIO的模式配置代码。
main.c文件,毋庸置疑,就是主函数文件。
stm32mp1xx_hal_msp.c文件
stm32mp1xx_hal_msp.c文件是STM32CubeIDE自动生成的,官方的例程模板里有这个文件。MSP,全称为 MCU support package,翻译过来就是MCU的特定封装,是什么封装呢,我们先打开看看文件里有什么。文件中的注释说明此文件提供用于MSP初始化的代码和取消初始化代码,文件的主要内容如下:
#include “main.h”

void HAL_MspInit(void)
{
__HAL_RCC_HSEM_CLK_ENABLE();

}
HAL_MspInit函数中调用了stm32mp1xx_hal_rcc.h.文件中的__HAL_RCC_HSEM_CLK_ENABLE函数,此函数内容是:
#define __HAL_RCC_HSEM_CLK_ENABLE() (RCC->MC_AHB3ENSETR = RCC_MC_AHB3ENSETR_HSEMEN)
HSEM是集成在STM32中的硬件信号量,用于管理一些共享资源的访问权限和同步,保护GPIO和外部中断EXTI配置免受并发访问。RCC->MC_AHB3ENSETR 表示RCC_MC_AHB3ENSETR这个寄存器,根据参考手册的说明,RCC_MC_AHB3ENSETR寄存器的第11位HSEMEN,对HSEMEN写’1’表示使能HSEM外设时钟,对HSEMEN读取到’1’意味着HSEMEN外设时钟已经被使能:
在这里插入图片描述

图8.3. 10参考手册HSEMEN寄存器说明
RCC_MC_AHB3ENSETR_HSEMEN在stm32mp157dxx_cm4.h中有定义,B(11)表示将RCC->MC_AHB3ENSETR第11位置1,第11位刚好就是HSEMEN,即开启HSEMEN外设时钟:
/* 此寄存器用于将相应外设的外设时钟启用位设置为1。它给单片机分配一个外围设备 */

#define RCC_MC_AHB3ENSETR_DCMIEN              B(0)
#define RCC_MC_AHB3ENSETR_HASH2EN             B(5)
#define RCC_MC_AHB3ENSETR_RNG2EN              B(6)
#define RCC_MC_AHB3ENSETR_CRC2EN              B(7)
#define RCC_MC_AHB3ENSETR_HSEMEN              B(11)
#define RCC_MC_AHB3ENSETR_IPCCEN              B(12):
那么__HAL_RCC_HSEM_CLK_ENABLE函数就是开启HSEMEN外设时钟的(并不是GPIO外设时钟,GPIO挂载AHB4上,不是AHB3),表示开启HSEM。不过,对于本实验,即使删掉该函数也没事。HAL_MspInit 函数我们称之为回调函数(在第7.4.1小节有介绍),HAL_MspInit回调函数被stm32mp1xx_hal.c 文件中的HAL_Init 函数调用,HAL_MspInit回调函数在已经在stm32mp1xx_hal.c文件里面做了弱定义(只是弱定义一个函数,函数并没有什么内容,是个空函数)。弱就表示用户可以在其它地方重新定义这个函数,在编译的时候编译器就默认编译用户自定义的那个函数。
__weak void HAL_MspInit(void)

{
/* 注意:这个函数不应该修改,当需要回调时,HAL_MspInit可以在用户文件中实现* /
}
至此我们明白了,stm32mp1xx_hal_msp.c文件中对HAL_MspInit回调函数进行了重定义,文件包含用户应用程序中会用到的外围设备的MSP初始化和取消初始化代码(主例程和回调)。而回调函数可以被用户在其它地方重新定义,即使用户没有重新定义,系统也会默认编译带了weak定义的弱函数,这样说明,stm32mp1xx_hal_msp.c文件并不是必须的,即使删掉以后重新编译,工程也不会报错。毕竟stm32mp1xx_hal_msp.c文件是STM32CubeIDE自动生成的,我们就不删除了,以后我们也可以此文件中添加我们重新定义的回调函数。
stm32mp1xx_it.c文件
stm32mp1xx_it.c文件是STM32CubeIDE自动生成的,官方的例程模板里有这个文件。
在这里插入图片描述

图8.3. 11 ST官方模板文件
stm32mp1xx_it.c文件包含异常处理程序和外设中断服务程序,文件中有调用HAL_IncTick函数来保证Systick每隔1ms产生一次中断(我们在7.4.2的第1小节有分析)。中断服务函数也可以编写在其他文件中,比如各个硬件的驱动文件里面,既然STM32CubeIDE生成了此文件,那我们就利用此文件好了,在以后的项目开发中,我们的中断服务函数都可以在此文件中添加。
syscalls.c文件
syscalls 翻译过来是系统调用的意思。syscalls.c是MCU最小系统调用文件,由STM32CubeIDE 自动生成。打开文件,文件调用了一些C函数库,例如标准输入输出函数stdio.h,还有返回错误事件错误码的errno.h函数等,这些函数的具体实现,可以参考Newlib 或者libc说明手册。
注:
Newlib和libc是一个开源的、面向嵌入式系统的C运行库,可以将这些库移植到我们工程代码中,详细信息可以参考官网链接:
http://www.gnu.org/software/libc/
https://sourceware.org/newlib/
syscalls.c文件中还有getpid(取得进程识别码)函数,例如_write函数和_read函数,如果我们做串口实验会遇到printf的重定向问题,printf的调用流程是先调用_write函数,再调用__io_putchar或__io_getchar函数,那么我们可以直接调用syscalls.c文件,然后根据需要可以修改里边的内容。
sysmem.c文件
sysmem.c文件,翻译过来就是和系统内存有关的文件,此文件是STM32CubeIDE系统内存调用文件,文件中调用了_sbrk函数,将内存分配给newlib堆,并由malloc使用。其实也是C库函数,可以参考Newlib 或者libc说明手册进一步了解,此函数不是重点介绍内容。
4. Startup文件夹
Startup下是启动文件startup_stm32mp157daax.s,此启动文件和我们之前6.3.5小节讲解的CMSIS文件夹中的startup_stm32mp15xx.s文件是一样的,它是是系统上电后第一个运行的程序,主要用于:
①设置栈指针SP;
②设置初始PC= Reset_Handler;
③设置中断向量表入口地址,并初始化向量表;
④初始化.data 和 .bss 段;
⑤跳转到C库中的main
关于此文件的详细内容,可以再返回到6.3.5小节进行了解。
5. Drivers文件夹
Drivers文件夹下就是HAL库了,里边的文件是STM32CubeIDE从之前下载的STM32CubeMP1固件包中拷贝的。记得我们之前在创建工程的时候采用默认配置,或者在4.1.2的第4小节操作中,在STM32CubeMX插件中配置了Copy only the necessary library files选项,意思就是,生成工程时,会从STM32CubeMP1固件包中拷贝需要用到的HAL库文件,没用到的不会拷贝,这样生成的工程就比较精简和小巧。
在这里插入图片描述

图8.3. 12工程的Drivers文件夹
在这里插入图片描述

图8.3. 13 CubeMX的配置
6. Debug文件夹
Debug文件夹下就是编译生成的文件。Common、Core和Drivers文件夹下有编译生成的中间文件。Debug文件夹根目录下有编译生成的可执行.elf文件和bin格式文件,这些格式的文件可以通过配置STM32CubeIDE来生成,我们在4.2.4小节有讲解怎么配置。.map文件是地图文件,.list文件是反汇编文件,makefile文件是控制工程编译规则的文件,这些文件我们在6.3.6小节有讲解。
在这里插入图片描述

图8.3. 14 Debug文件夹
7. Release文件夹
对应Release发行版编译生成的文件,我们有在4.2.5小节介绍过。
8.4 章节小结
本章节,我们主要分析了第四章STM32CubeIDE第一个工程的结构,结合前面第六和第七章中对STM32CubeMP1固件包中重要文件的分析,我们将工程中的文件关系用下一张简图来描述(图中省略了部分.c文件和.h文件):

图8.4. 1 CubeIDE工程文件关系
在STM32CubeIDE工程中的文件,主要分为三个部分,分别为CMSIS核心层、设备驱动层和用户程序文件,我们将其用一个表格来说明:
在这里插入图片描述

表8.4. 1 CubeIDE工程描述
关于HAL库中其它文件,我们通过后面的实验来熟悉它们,下面开始我们的实践之旅吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值