正点原子 发表于 2022-7-28 10:11:16

《STM32MP1 M4裸机CubeIDE开发指南 V1.5.2》第八章 STM32CubeIDE工程模块

1)实验平台:正点原子STM32MP157开发板
2) 章节摘自【正点原子】STM32MP1 M4裸机CubeIDE开发指南 V1.5.2
3)购买链接:https://detail.tmall.com/item.htm?id=631745687288
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/arm-linux/zdyzmp157.html1.0.0 文档
5)正点原子官方B站:https://space.bilibili.com/394620890
6)STM32MP157技术交流QQ群:703341432




第八章 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. BinariesBinaries下有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文件。我们分析一下这些文件:l gpio.c文件是GPIO引脚配置的代码,例如GPIO的时钟使能和GPIO的模式配置代码。l main.c文件,毋庸置疑,就是主函数文件。l 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自动生成的,我们就不删除了,以后我们也可以此文件中添加我们重新定义的回调函数。l stm32mp1xx_it.c文件stm32mp1xx_it.c文件是STM32CubeIDE自动生成的,官方的例程模板里有这个文件。图8.3. 11 ST官方模板文件stm32mp1xx_it.c文件包含异常处理程序和外设中断服务程序,文件中有调用HAL_IncTick函数来保证Systick每隔1ms产生一次中断(我们在7.4.2的第1小节有分析)。中断服务函数也可以编写在其他文件中,比如各个硬件的驱动文件里面,既然STM32CubeIDE生成了此文件,那我们就利用此文件好了,在以后的项目开发中,我们的中断服务函数都可以在此文件中添加。l 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文件,然后根据需要可以修改里边的内容。l 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库中其它文件,我们通过后面的实验来熟悉它们,下面开始我们的实践之旅吧。

页: [1]
查看完整版本: 《STM32MP1 M4裸机CubeIDE开发指南 V1.5.2》第八章 STM32CubeIDE工程模块