11. 新建工程—库函数版

了解STM32的HAL库文件之后,我们就可以使用它来建立工程了,因为用库新建工程的步骤较多, 我们一般是使用库建立一个空的工程,作为工程模板。以后直接复制一份工程模板,在它之上进行开发。

11.1. 新建工程

版本说明:MDK5.23(MDK即KEIL软件)

版本号可从MDK软件的“Help–>About uVision”选项中查询到。

11.1.1. 新建本地工程文件夹

为了工程目录更加清晰,我们在本地电脑上新建一个“工程模板”文件夹,在它之下再新建6个文件夹,具体如下:

工程目录文件夹清单 工程文件夹目录

在本地新建好文件夹后,把准备好的库文件添加到相应的文件夹下:

工程目录文件夹内容清单

11.1.2. 新建工程

打开KEIL5,新建一个工程,工程名根据喜好命名,我这里取LED-LIB,保存在ProjectRVMDK(uv5)文件夹下。

在KEIL5中新建工程

11.1.2.1. 选择CPU型号

这个根据你开发板使用的CPU具体的型号来选择,M7挑战者选STM32H750XBH6型号。 如果这里没有出现你想要的CPU型号,或者一个型号都没有,那么肯定是你的KEIL5没有添加device库, KEIL5不像KEIL4那样自带了很多MCU的型号,KEIL5需要自己添加,关于如何添加请参考《如何安装KEIL5》这一章。

选择具体的CPU型号

11.1.2.2. 在线添加库文件

等下我们手动添加库文件,这里我们点击关掉。

库文件管理

11.1.2.3. 添加组文件夹

在新建的工程中添加5个组文件夹,用来存放各种不同的文件,文件从本地建好的工程文件夹下获取, 双击组文件夹就会出现添加文件的路径,然后选择文件即可。

工程内组文件夹内容清单 如何在工程中添加文件夹

11.1.2.4. 添加文件

先把上面提到的文件从ST标准库中复制到工程模版对应文件夹的目录下,然后在新建的工程中添加这些文件, 双击组文件夹就会出现添加文件的路径,然后选择文件即可。

如何在工程中添加文件

11.1.2.5. 设置文件是否加入编译

STM32H750外设比较丰富,它的库文件比较庞大,在添加外设文件时,为了减少编译时间。 我们把外设库的所有文件都添加进工程,使用下面的方法把暂时没有用到的库文件,设置为不加入编译, 这样就不会对特定文件进行编译。这种设置在开发时也很常用,暂时不把文件加进编译,方便调试,加快开发进度。

设置文件是否加入编译

11.1.2.6. 配置魔术棒选项卡

这一步的配置工作很重要,很多人串口用不了printf函数,编译有问题,下载有问题,都是这个步骤的配置出了错。

(1) Target中选中微库“ Use MicroLib”,为的是在日后编写串口驱动的时候可以使用printf函数。 而且有些应用中如果用了STM32的浮点运算单元FPU,一定要同时开微库,不然有时会出现各种奇怪的现象。 FPU的开关选项在微库配置选项下方的“Use double Precision”中,默认是开的。

添加微库

(2) 在Output选项卡中把输出文件夹定位到我们工程目录下的“output”文件夹, 如果想在编译的过程中生成hex文件,那么那Create HEX File选项勾上。

配置 Output 选项卡

(3) 在Listing选项卡中把输出文件夹定位到我们工程目录下的“Listing”文件夹。

配置 Listing 选项卡

(4) 在C/C++选项卡中添加处理宏及编译器编译的时候查找的头文件路径。

配置 C/C++ 选项卡

在这个选项中添加宏,就相当于我们在文件中使用“#define”语句定义宏一样。在编译器中添加宏的好处就是, 只要用了这个模版,就不用源文件中修改代码。

  • STM32H750xx宏:为了告诉STM32 HAL库,我们使用的芯片是,STM32H750型号,使STM32 HAL库根据我们选定的芯片型号来配置。

  • USE_HAL_DRIVER宏:为了让stm32h7xx.h包含stm32h7xx_hal_conf.h这个头文件。

“Include Paths ”这里添加的是头文件的路径,如果编译的时候提示说找不到头文件,一般就是这里配置出了问题。 你把头文件放到了哪个文件夹,就把该文件夹添加到这里即可。(请使用图中的方法用文件浏览器去添加路径, 不要直接手打路径,容易出错)

11.1.2.7. 下载器配置

Debug选项配置

Debug中选择 CMSIS-DAP Debugger

Utilities选项配置

Utilities选择 Use Debug Driver

Debug Settings选项配置

Settings选项配置

11.1.2.8. 选择CPU型号

这一步的配置也不是配置一次之后完事,常常会因为各种原因需要重新选择,当你下载的时候, 提示说找不到Device的时候,请确保该配置是否正确。有时候下载程序之后,不会自动运行,要手动复位的时候, 也回来看看这里的“Reset and Run”配置是否失效。H750Pro用的STM32的内部FLASH大小是128KB, 所以这里选择128KB的容量,如果使用的是其他型号和FLASH大小的,要根据实际情况选择。

选择芯片型号

11.2. 下载程序

如果前面步骤都成功了,接下来就可以把编译好的程序下载到开发板上运行。下载程序不需要其他额外的软件,直接点击KEIL中的LOAD按钮即可。

下载程序

程序下载后,Build Output选项卡如果打印出 Application running…则表示程序下载成功。如果没有出现实验现象, 按复位键试试。当然,这只是一个工程模版,我们还没写程序,开发板不会有任何现象。

至此,一个基于固件库的新的工程模版新建完毕。

11.3. 各种版本的工程模版

根据前面的操作,我们已经建立了一个可用的工程模版,但我们可以更进一步,提供多种版本的配置。 例如上面的工程是把程序下载到内部FLASH存储器并执行的,但如果程序比较大,此时内部FLASH的大小已无法容纳, 我们就希望把程序下载到外部FLASH中,这样能开发一些代码量较大的程序。

为适应不同的应用场景,我们建立了工程“新建工程-固件库版本\2-进阶版本”, 相对来说这个版本的工程模版更加实用且功能丰富,因而在后续章节中我们一般都以它为模版。不过, 该工程建立的过程和原理涉及众多知识,所以我们不太推荐大家亲自创建该工程, 只要了解它的特性能在不同场合下正确使用即可。

11.3.1. STM32H750系统包含的存储器

要了解该工程,首先要了解本系统中主要使用的存储器,在本开发板中主要使用板载的QSPI NOR FLASH存储器存放代码, 以板载SDRAM作为大内存,而在STM32H750芯片中包含有ITCM、DTCM和系统RAM存储器, 这些存储器的特性具体见表 系统主要使用的存储器特性

系统主要使用的存储器特性

通过该表可以了解到这些存储器中只有QSPI NOR FLASH是ROM类型的,即只有它在掉电的情况下能正常保存内容, 其它都是RAM类型的,其保存的内容在掉电时会丢失;又由于存储器类型或访问方式的区别, 内核访问它们的速度有快有慢,而且它们的容量也不同。

11.3.2. 代码存储的位置与执行的位置

根据不同的应用场景,我们会根据存储器的特性调整代码的存储位置和执行位置。

  1. 代码存储在FLASH中并执行

STM32H750系统比较常见的运行方式具体见图 从FLASH中加载代码并执行,在这种方式下代码保存在QSPI NOR FLASH中, 内核通过QSPI外设从QSPI NOR FLASH中加载代码并执行,而DTCM、系统RAM和SDRAM存储器则用于存储C语言的堆栈、 以及显存等内容,即内核从这些位置加载运行的数据。

从FLASH中加载代码并执行

由于QSPI NOR FLASH掉电后能正常保存内容,所以在下一次上电后,系统仍然能正常执行NOR FLASH中保存的程序, 所以在发布应用的时候通常采用把代码保存到NOR FLASH的这种方式。

  1. 代码存储在FLASH中,在RAM中执行

为了综合FLASH和RAM存储器的优点,该系统对代码的存储和执行还有更复杂的处理方式,具体见图 代码存储在FLASH在RAM中执行

代码存储在FLASH在RAM中执行

使用这种方式时,系统平时把代码存储在NOR FLASH,这能保证掉电后也能正常存储,在上电后把代码从NOR FLASH复制到ITCM、 系统RAM或SDRAM中,在正式运行时,内核直接从这些RAM内加载代码并执行,由于内核对RAM的访问速度更快, 所以这能提高代码的执行速度,尤其是与内核联系紧密、使用64位线宽的ITCM,它是专门设计需要高速执行代码的。

11.3.3. 不同工程版本及其特性

本教程提供的进阶版工程模版,它包含了把代码存储放在不同区域的工程,工程的具体特性见表格 各个工程版本的不同特性

各个工程版本的不同特性

在本章教程一开始建立的工程模版,就属于“Fire_H7_InFlash”类型的工程, 它的代码存储位置和执行位置都是芯片内部的FLASH,而C语言的堆栈位置在AXI SRAM。

以上两种工程版本,应用时需要根据代码量、外部资源存储方式和存储器的特性来选择。

本工程模版中的代码都是大粒度的配置,整个代码都是全部统一存储在某个存储器或统一在某个存储器中执行代码, 在实际的应用中会更精细地进行存储器分配,如同一个工程中, 它的大部分代码或数据仍然使用NOR FLASH或SDRAM等大容量的存储器,而有高速需求的代码或数据另外存放至内部FLASH和TCM, 关于这些内容需要掌握如何配置“分散加载文件”,在本工程模版的基础上作进一步配置。

11.3.4. 增加不同工程版本的方法

下面说明一下使用Keil创建以上不同工程版本的流程:

  1. 使用前面建立的工程模版为基础,即在 “新建工程—固件库版本>入门版本”工程的基础上,打开system_stm32h7xx.c文件,找到第231行代码,把其中的“FLASH_BANK1_BASE”改为“APPLICATION_ADDRESS”,具体见图 修改system_stm32h7xx.c 和图 修改后的效果

修改system_stm32h7xx.c 修改后的效果
  1. 点击“File Extensions”按钮,在弹出的项目管理界面下把原工程名“Fire_H7”改为“Fire_H7_InFlash”以便区分,具体见图 在项目管理界面修改工程名

在项目管理界面修改工程名
  1. 点击“Project Targets”栏的“New”按钮,然后创建其它两个版本的工程,具体见图 创建其它版本的工程

创建其它版本的工程

创建完成后的效果见图 创建其它版本工程后的效果

创建其它版本工程后的效果
  1. 点击魔术棒选项卡,在Taget一栏中,将只读储存区更改为外部ROM并设置起始地址和大小。具体见图 只读存储区更改

只读存储区更改
  1. 最后,还需要为不同的工程添加对应的下载算法。在“Debug Settings”弹出的“FLASH Download”选项卡中选择目标存储器下载算法,具体要根据工程设置以及板子上使用的FLASH型号和大小来决定。

以“Fire_H7_ExtFlash_Single”为例,删除针对内部FLASH的下载算法,具体见图 删除原目标存储器

删除原目标存储器

删除默认存储器后,添加野火STM32H750 Pro系列开发板配套的单片32MB FLASH存储器下载算法“embedFire-H750V-W25Q256.FLM”, 具体见图 添加野火开发板配套的下载算法,若在列表框中找不到该项目,请参考《3.5放置下载算法》章节补充说明。

添加野火开发板配套的下载算法

由于本下载算法相比默认的需要更大的空间,所以还要在配置界面中增大算法空间,见图 设置下载算法空间

设置下载算法空间

11.3.5. 各个版本工程的配置差异

  1. 各个版本工程的关系

当项目中存在多个版本的工程时,可以通过Load按钮旁边的下拉框选择进行切换,具体见图 切换不同版本的工程。 不同版本的工程共用相同的文件,即共用源代码,只是配置不同,例如魔术棒处定制的各项配置在不同的版本间是独立的, 修改当前的配置不会影响其它版本。

切换不同版本的工程
  1. 根据版本定制不同的配置

按照前面步骤操作得到的各个版本工程相当于是对“Fire_H750V”版本的复制版,即到目前为止各个版本都是完全一样的。 下面对各个版本的差异进行讲解,除以下提到的差异外,工程的其它内容完全一致,在实际操作时请注意切换版本后进行配置。

  • Output及Listing输出路径的差异

不同版本的工程编译后有不同的输出,为进行区分,我们在工程目录创建与工程名相同的文件夹用于存放Output及Listing的输出, 在各个工程中选择输各文件夹中对应的Objects及Listings文件夹内即可,如图 各个工程选择对应的输出文件夹 所示。

各个工程选择对应的输出文件夹
  • C/C++选项配置的差异

在C/C++选项配置中的部分宏和代码优化等级是不一样的,其中代码优化等级通常根据自身的需要调整, 此处不进行整理。具体见下图和表格。

表各工程版本C/C++选项配置的差异 图各版本工程中C/C++选项配置的差异