STM32固件库移植出错解决方法:No section matches selector – no section to be FIRST/LAST

1 问题描述

最近项目上需要用到STM32F103VET6芯片。之前一直使用的是8年前的库,决定更新为最新版的固件库。在建立新工程编译时出现了以下错误:“…\OBJ\NH3N STM32.sct(7): error: L6236E: No section matches selector – no section to be FIRST/LAST.”

2 问题分析

2.1 问题定位

双击出错信息,Keil跳转到如下窗口:

错误出现在“xxxx.sct”文件,sct文件,全名scatter file,中文名分散加载文件,是ARM程序链接时的输入参数。默认设置下,Keil会自动生成.sct文件。出错的的“NH3N STM32.sct”文件就是keil自动生成的。

2.2 分散加载机制(sct文件)

分散加载机制允许为链接器指定映像的存储器映射信息,可实现对映像组件分组和布局的全面控制。分散加载区域分两类:

加载区:该映像文件开始运行前存放的区域,即当系统启动或加载时应用程序存放的区域。

执行区:映像文件运行时的区域,即系统启动后,应用程序进行执行和数据访问的存储器区域。

2.3 本工程sct文件分析

对于本工程生成的.sct文件来说。

6  ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address

加载区,指定了程序映像在存储区存放的起始地址:0x08000000,总共的大小为0x00080000。这与图3中的存放代码的Flash区域地址一致。上电后,从此地址处加载代码。

11  RW_IRAM1 0x20000000 0x00010000  {  ; RW data

执行区,指定了运行时临时存放代码的地方。起始地址:0x20000000,总共的大小:0x00010000。这与图3中的SRAM区域地址一致。上电后,程序在此区域内运行。

上边说了Keil在编译工程时会自动生成.sct文件。那么Keil是怎样知道加载区(ROM)起始地址以及执行区(RAM)起始地址的呢?

其实我们新建工程时第一步就是选择芯片的具体型号,Keil会根据我们设置的芯片型号加载默认的ROM、RAM起始地址和存储区大小。

在“Options for Target…”的“Target”选项卡可以看到默认的设置。下图即是我的工程keil的默认设置。从图中可知IROM1就是程序映像存储区参数,IRAM1就是运行时临时代码存放区参数。两个名称前边都加了“I”,代表内部存储区的意思,对应图标“on-chip”。如果系统有外部扩展的ROM和RAM,还需要在“off-chip”对应的区域设置存储区起始地址和大小。“Startup”单选框用于选择系统启动起始区域。通过和生成的.scf文件对比,此默认设置和.sct文件中的代码表述一致。

另外,可以设置多个IROM、ROM、IRAM和RAM区,这和.sct文件支持多个不连续的加载区和运行区相对应。但是启动加载区只能选择一个。

报错的代码行是:

7   *.o (RESET, +First)

这一行代码指定了启动代码的首次执行地址。RESET标号表示的地址就是启动地址。其中First属性符表示把RESET代表的代码放在最开始处,也就是指定RESET代表的地址为启动地址。

2.4 报错原因

报错信息中的“no section to be FIRST/LAST”也就是说没有找到FIRST或者LAST对应的区域,也就是说没有找到RESET标号对应的代码。RESET标号对应的代码也就是单片机复位之后执行的代码。因此可以判断keil没有找到STM32的启动文件。

3 问题解决

3.1 启动文件存放位置

通过以上的分析,找到STM32的启动文件,并加载到工程中就可以解决问题了。
在官方库文件中可以找到启动文件,文件存放路径:STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm。在此路径下总共有8个启动文件。

3.2 启动文件适用环境

这8个启动文件分别适用于什么场合?对于本工程应该选择哪一个启动文件?

仔细查看可知这8个文件的文件名都是startup_stm32f10x_xx.s 格式的。这些启动文件分别适用于不同类型及flash大小的器件。

3.3 STM32 内部Flash容量等级划分规则

那么STM32内部Flash是按照什么样的标准划分大、小、中容量的?

每种系列的器件的划分标准是不太一样的。可能从芯片数据手册中找到划分标准。对于STM32F103xx系列的划分标准如下图所示。

3.4 找到合适的启动文件

由数据手册中的选型部分可知STM32F103VET6的Flash大小为512Kbytes,属于大容量系列,因此应该选择启动文件:startup_stm32f10x_hd.s 。

使用notepad++打开此启动文件,启动文件采用汇编语言编写,主要完成系统底层初始化并找到程序main函数执行入口。在启动文件中可以找到如下代码:

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

可以看到这就是.scf文件要找的RESET标号对应的代码。

3.5 往工程中添加启动文件

(以下操作以我自己的工程为例)

把启动文件startup_stm32f10x_hd.s拷贝到工程文件里的CMSIS文件夹里。然后在keil工程树中右击“CMSIS”,在弹出菜单中选择“Manage Project Items”,在弹出的“Manage Project Items”窗口中,在“CMSIS”group中点击“Add Files…”添加刚才的拷贝的启动文件。

3.6 编译验证

启动文件添加好后,重新编译工程,编译顺利通过。

【参考】
1、Keil sct分散加载文件 http://blog.csdn.net/kobesdu/article/details/38258449
2、关于arm启动代码的启动流程 https://www.cnblogs.com/blackeyes/articles/4742264.html
3、STM32F10x 启动代码文件选择 https://wenku.baidu.com/view/263f7f5c0066f5335b81215f.html

案例2

今天用STM32CubeMX创建一个简单的工程,就配置了一个LED,编译的时候发现如下错误:
error: L6236E: No section matches selector – no section to be FIRST/LAST.
很纳闷,这么简单的工程都能配错吗?看了一遍配置确定没问题,突然发现工程路径包含中文,应该就是这里的问题,于是改变路径重新生成,就没问题了。

解决方法:

1.修改工程保存位置

2.再新建一个工程,复制粘贴。

下图为我原来的工程保存路径,因为含有中文所以出错。

参考:https://blog.csdn.net/qq_62018762/article/details/127595972

物联沃分享整理
物联沃-IOTWORD物联网 » STM32固件库移植出错解决方法:No section matches selector – no section to be FIRST/LAST

发表评论