第八章 新建HAL版本MDK工程
8.2 下载验证
这里我们继续使用DAP仿真器下载,在MDK主界面,点击:file:///C:/Users/ALIENTEK/AppData/Local/Temp/msohtmlclip1/01/clip_image002.png(下载按钮,也可以按键盘快捷键:F8),就可以将代码下载到开发板,如图8.2.1所示:
图8.2.1 下载成功
上图提示:Application running…,则表示代码下载成功,且开始运行。此时,看到RGB的红、蓝、绿三种灯轮流亮,类跑马灯。如果有朋友没能下载成功,请看第四章寻找问题,或者直接对照我们提供的实验0-3,新建工程实验-HAL库版本工程设置。
8.3 分散加载文件简介
ARM芯片用于在链接时指定存储器分配方案的文件,称之为分散加载文件(.sct),它可以将不同的代码(.o文件)放在不同的存储空间。关于分散加载的详细介绍,请参考:A盘à8,STM32参考资料à4,分散加载à分散加载文件浅释.pdf,这是周立功公司的一份文档资料,详细介绍了.sct文件的基础概念、语法及应用实例说明,对学习分散加载非常有帮助,请大家务必先学习一下这个文档。
本节,我们仅对.sct文件进行一个简介,方便大家学习。
首先明确一个概念:MDK编译任何STM32工程,都会需要用到分散加载文件。分散加载文件的来源有两种方式:
通过MDK自己生成;
2,通过用户指定(用户自己编写);
首先,我们来看MDK自己生成的.sct文件。
选择本章新建工程àMDK的魔术棒àLinker选项卡里面,进行如图8.3.1所示的设置:
图8.3.1 勾选Use Memory Layout from Target Dialog选项
勾选Use Memory Layout from Target Dialog选项后,MDK就会根据Target选项卡里面的相关设置来决定存储器分配,如图8.3.2所示:
图8.2.2 MDK默认的存储器分配
标号①,是MDK的只读存储区域(ROM)和可读写存储区域(RAM)的配置区域。
标号②处,说明默认将所有的代码(Code + RO Data + RW Data)都存放到IROM1指定的地址范围上。其起始地址为:0X0800 0000,大小为:0X20000。
标号③处,说明默认将所有的变量及堆栈(RW Data + ZI Data)都存放在IRAM1和IRAM2指定的地址范围上。IRAM1的起始地址为:0X2000 0000,大小为:0X20000;IRAM2的起始地址为:0X2400 0000,大小为:0X80000;变量的具体位置由编译器自动分配。
在完成以上两步操作以后,对MDK进行一次编译,在编译成功后,MDK会自动生成一个以工程名命名的.sct文件,存放在Output文件夹里面,如图8.2.3所示:
图8.2.3 MDK自动生成的分散加载文件
打开上图中的test.sct文件,其内容如下
- ; *************************************************************
- ; *** Scatter-Loading Description File generated by uVision ***
- ; *************************************************************
- LR_IROM1 0x08000000 0x00020000 { ; load region size_region
- ER_IROM1 0x08000000 0x00020000 { ; load address = execution address
- *.o (RESET, +First)
- *(InRoot$Sections)
- .ANY (+RO)
- .ANY (+XO)
- }
- RW_IRAM1 0x20000000 0x00020000 { ; RW data
- .ANY (+RW +ZI)
- }
- RW_IRAM2 0x24000000 0x00080000 {
- .ANY (+RW +ZI)
- }
- }
复制代码LR_IROM1是一个加载域,起始地址为:0X0800 0000,大小为:0X0002 0000。它包含三个运行域分别是:
ER_IROM1运行域,起始地址为:0X0800 0000,大小为:0X0002 0000。
RW_IRAM1运行域,起始地址为:0X2000 0000,大小为:0X0002 0000。
RW_IRAM2运行域,起始地址为:0X2400 0000,大小为:0X0008 0000。
其中:
ER_IROM1为ROM区域,存放:Code + RO Data + RW Data等只读数据,由:.ANY (+RO)指定,即所有只读数据,都存放在这个区域。
RW_IRAM1和RW_IRAM2为RAM区域,存放:RW Data + ZI Data等可读写数据,由:.ANY (+RW +ZI)指定,即所有的可读写数据,都存放在这两个区域,具体存放位置由MDK编译器自动分配。
*.o (RESET, +First):表示优先(+FIRST)将RESET(即中断向量表)段放这个域的起始位置,实际上就是把中断向量表拷贝到最开始的位置。
* (InRoot$$Sections):表示将所有用到的库段放到root区,如:__main.o、__scatter*.o和__dc*.o等。
以上,就是MDK自动生成的.sct文件简介。
接下来,我们看用户指定.sct文件的实现方式。选择本章新建工程àMDK的魔术棒àLinker选项卡里面,进行如图8.3.4所示的设置:
图8.2.4 取消Use Memory Layout from Target Dialog选项
标号①,取消Use Memory Layout from Target Dialog选项,使用用户自定义分散加载文件。
标号②,新建工程时,已选择SCRIPT\qspi_code_scf.scf分散加载文件。
标号③,点击Edit按钮,即可在MDK里面打开qspi_code_scf.scf分散加载文件。
qspi_code.scf的内容如下:
#! armcc -E
;#! armclang -E --target=arm-arm-none-eabi -mcpu=cortex-m7 -xc
/* 使用说明
! armclang -E --target=arm-arm-none-eabi -mcpu=cortex-m7 -xc, 用于AC6编译报错(L6709E错误)时,请使用此设置
!armcc -E, 用于AC5编译报错(L6709E错误)时,请使用此设置
注意,设置必须放本文件第一行!否则还是报错!请注意调整顺序!
- */
- /**
- **********************************************************************************************
- * [url=home.php?mod=space&uid=175224]@file[/url] main.c
- * [url=home.php?mod=space&uid=90321]@Author[/url] 正点原子团队(ALIENTEK)
- * @version V1.0
- * @date 2020-03-13
- * @brief STM32H750分散加载文件(.scf文件)
- * [url=home.php?mod=space&uid=292586]@license[/url] Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
- **********************************************************************************************
- * @attention
- *
- * 实验平台:正点原子 Mini Pro H750开发板
- * 在线视频:www.yuanzige.com
- * 技术论坛:www.openedv.com
- * 公司网址:www.alientek.com
- * 购买地址:openedv.taobao.com
- *
- **********************************************************************************************
- */
- #define m_stmflash_start 0X08000000 /* m_stmflash(STM32内部FLASH)域起始地址 */
- #define m_stmflash_size 0X20000 /* m_stmflash(STM32内部FLASH)大小,H750是128KB */
- #define m_qspiflash_start 0X90000000 /* m_qspiflash(外扩QSPI FLASH)域起始地址 */
- #define m_qspiflash_size 0X800000 /* m_qspiflash(外扩QSPI FLASH)大小,W25Q64是8MB */
- #define m_stmsram_start 0X24000000 /* m_stmsram(STM32内部RAM)域起始地址,定义在D1,AXI SRAM */
- #define m_stmsram_size 0X80000 /* m_stmsram(STM32内部RAM)大小,AXI SRAM共512KB */
- LR_m_stmflash m_stmflash_start m_stmflash_size /* LR_m_stmflash加载域 */
- {
- /* ER_m_stmfalsh运行域,起始地址为:m_stmflash_start,大小为:m_stmflash_size */
- ER_m_stmflash m_stmflash_start m_stmflash_size {
- /* 优先(+FIRST)将RESET(中断向量表)段放这个域,实际上就是把中断向量表拷贝到m_stmflash_start */
- /* RESET是一个段名,表示中断向量表(在.s文件定义);+FIRST表示时第一个要加载的. */
- *.o (RESET, +First)
- /* 将所有的库段(C/C++标准库)放在root region.如__main.o,__scatter*.o等 */
- * (InRoot$Sections)
- * (Veneer$Code)
- libinit.o
- libinit2.o
- libshutdown.o
- libshutdown2.o
- __rtentry.o
- __rtentry2.o
- __rtentry4.o
- rtexit.o
- rtexit2.o
- use_no_semi_2.o
- heapauxi.o
- use_no_semi.o
- sys_stackheap_outer.o
- exit.o
- libspace.o
- fpinit.o
- lludivv7m.o
- startup_stm32h750xx.o
- rt_locale_intlibspace.o
- lc_numeric_c.o
- lc_ctype_c.o
- main.o
- sys.o
- usart.o
- delay.o
- pwr.o
- /* H7的QSPI接口不支持读时写,因此必须把以下3个文件放到内部FLASH,以保证可以
- 对QSPI FLASH的写入 */
- qspi.o
- norflash.o
- norflash_ex.o
- /* 针对HAL库驱动添加到内部的文件 */
- system_stm32h7xx.o
- stm32h7xx_hal.o
- stm32h7xx_hal_cortex.o
- stm32h7xx_hal_rcc.o
- stm32h7xx_hal_rcc_ex.o
- stm32h7xx_hal_gpio.o
- stm32h7xx_hal_dma.o
- stm32h7xx_hal_dma_ex.o
- stm32h7xx_hal_qspi.o
- stm32h7xx_hal_pwr.o
- stm32h7xx_hal_pwr_ex.o
- }
- /* RW_m_stmsram运行域,起始地址为:m_stmsram_start,大小为:m_stmsram_size. */
- RW_m_stmsram m_stmsram_start m_stmsram_size {
- .ANY (+RW + ZI) /* 将所有用到的RAM都放在这个区域 */
- }
- }
- LR_m_qspiflash m_qspiflash_start m_qspiflash_size /* LR_m_qspiflash加载域 */
- {
- /* ER_m_qspiflash加载域,起始地址为:m_qspiflash_start,大小为:m_qspiflash_size */
- ER_m_qspiflash m_qspiflash_start m_qspiflash_size {
- .ANY (+RO) /* 将只读数据(+RO)放这个域,任意分配.相当于程序就是存放在这个域的 */
- }
- }
复制代码相比于MDK自己生成的分散加载文件,我们自己编写的相对复杂一些,qspi_code.scf分散加载文件包含2个加载域,3个运行域,分别是:
LR_m_stmflash加载域,起始地址为:m_stmflash_start(宏定义,实际值:0X0800 0000),大小为:m_stmflash_size(宏定义,实际值:0X20000)。它包含二个运行域分别是:
ER_m_stmflash运行域,起始地址为:m_stmflash_start(宏定义,实际值:0X0800 0000),大小为:m_stmflash_size(宏定义,实际值:0X20000)。
RW_m_stmsram运行域,起始地址为:m_stmsram_start(宏定义,实际值:0X2400 0000)大小为:m_stmsram_size(宏定义,实际值:0X80000)。
LR_m_qspiflash加载域,起始地址为:m_qspiflash_start(宏定义,实际值:0X9000 0000)大小为:m_qspiflash_size(宏定义,实际值:0X80000)。它包含一个运行域:
ER_m_qspiflash运行域,起始地址为:m_qspiflash_start(宏定义,实际值:0X9000 0000)大小为:m_qspiflash_size(宏定义,实际值:0X80000)。
具体的存储器分配情况为:
ER_m_stmflash运行域,包含:*.o (RESET, +First)开始到delay.o结束的相关代码,这些代码运行在内部FLASH,可以得到最佳的性能。需要注意的是:这些代码大部分都是必须放到内部FLASH,否则无法正常运行!!
ER_m_qspiflash运行域,所有没有在ER_m_stmflash运行域指定的代码,都被放在这个运行域,这些代码运行在外部SPI FLASH,速度比内部FLASH慢一些。
RW_m_stmsram运行域,所有变量及堆栈(RW Data + ZI Data)都存放在这个运行域。
以上分散加载文件,由正点原子编写,为了方便大家使用,不用频繁修改.sct文件,特意将.ANY ROM区域放在外部SPI FLASH,这样大家在新增.c参与编译时,默认就是存放在外部SPI FLASH的,这样使用起来就更方便。
注意事项:
1、如果你新增的代码,对速度有要求,可以将其对应的.o添加到内部FLASH,即放在:ER_m_stmflash运行域。
2、如果添加新代码后,程序无法正常运行(通常表现为黑屏/不启动),可以尝试将新增的.o放到ER_m_stmflash运行域后(重新编译)再尝试。如果还不行,可以尝试将所有代码都放到ER_m_stmflash运行域后再尝试。
至此,分散加载文件就给大家介绍完了。