【STM32】sct 分散加载文件的格式与应用

本文围绕STM32的分散加载文件(sct)展开,介绍了其格式,包括加载区和执行域描述、输入节区用法。还说明了通过MDK配置选项和手动两种方式修改sct文件的方法,并给出自动分配变量到指定SRAM空间、优先使用内部SRAM并分配堆区到指定空间的实例。

简介

当工程按默认配置构建时,MDK 会根据我们选择的芯片型号,获知芯片的内部FLASH 及内部 SRAM 存储器概况,自动生成一个以工程名命名的后缀为*.sct 的分散加载文件(Linker Control File,scatter loading),链接器根据该文件的配置分配各个节区地址,生成分散加载代码,因此我们通过修改该文件可以定制具体节区的存储位置

一般情况下,不需要编写分散加载文件,由编译器自动生成,将某些数据放到默认位置。但是在某些场合,希望将某些数据放在指定的位置。

例如可以设置源文件中定义的所有变量自动按地址分配到外部 SRAM,这样就不需要再使用关键字“attribute”按具体地址来指定了;

复杂内存映射:如果必须将代码和数据放在多个不同的内存区域中,则需要使用详细指令指定将哪些数据放在哪个内存空间中。

不同类型的内存:许多系统都包含多种不同的物理内存设备,如闪存、 ROM、 SDRAM 和快速 SRAM。分散加载描述可以将代码和数据与最适合的内存类型相匹配。例如,可以将中断代码放在快速 SRAM 中以缩短中断等待时间,而将不经常使用的配置信息放在较慢的闪存中。

位于固定位置的函数:可以将函数放在内存中的固定位置,即使已修改并重新编译周围的应用程序。

使用符号标识堆和堆栈:链接应用程序时,可以为堆和堆栈位置定义一些符号。

利用它还可以控制代码的加载区与执行区的位置,例如可以把程序代码存储到单位容量价格便宜的 NAND-FLASH 中,但在NAND-FLASH 中的代码是不能像内部 FLASH 的代码那样直接提供给内核运行的,这时可通过修改分散加载文件,把代码加载区设定为 NAND-FLASH 的程序位置,而程序的执行区设定为 SRAM 中的位置,这样链接器就会生成一个配套的分散加载代码,该代码会把NAND-FLASH 中的代码加载到 SRAM 中,内核再从 SRAM 中运行主体代码,大部分运行Linux 系统的代码都是这样加载的

sct文件的格式

在这里插入图片描述
在默认的 sct 文件配置中仅分配了 Code、RO-data、RW-data 及 ZI-data 这些大区域的地址,链接时各个节区(函数、变量等)直接根据属性排列到具体的地址空间。

sct 文件中主要包含描述加载域及执行域的部分,一个文件中可包含有多个加载域,而一个加载域可由多个部分的执行域组成。同等级的域之间使用花括号“{}”分隔开,最外层的是加载域第二层“{}”内的是执行域

在这里插入图片描述
在这里插入图片描述

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
 
LR_IROM1 0x08000000 0x00020000  {
   
       
	//定义一个加载域,域地址0x08000000,域大小为0x00020000
    //load region size_region 所有代码需要下载到0x08000000 开始的区域中,且这个区域大小只有0x00020000 
  ER_IROM1 0x08000000 0x00020000  {
   
     
	//load address = execution address 第一个运行时域必须和加载域起始地址相同,其大小一般也相同
    //只能是只读的代码段和只读数据段
   *.o (RESET, +First)        //启动代码的首次执行地址,RO执行域名称为ER_IROM1, 
    //将 RESET 段最先加载到本域的起始地址外
    //首次执行的地址为RESET标号所表示的地址,RESET 存储的是向量表
    //对应启动文件中的AREA    RESET, CODE, READONLY
   *(InRoot$$Sections)     //稍后文件中会单独讲到
   .ANY (+RO) //加载所有匹配目标文件的只读属性数据,包含:Code、 RW-Code、 RO-Data。
  }
  RW_IRAM1 0x20000000 0x00005000  {
   
     
    //再定义一个运行时域,域基址0x20000000 
	//RW data 执行域是以0x20000000 开始的长度为0x00004000  一段区域
   .ANY (+RW +ZI)    //其中包括的是哪些文件
  }
}

加载区描述

加载域名 (基地址 | ("+" 地址偏移)) [属性列表] [最大容量]
{
   
   
	执行区域描述
}
LR_IROM1 0x08000000 0x00080000  {
   
       ; load region size_region
......
}

加载域名:名称,在 map 文件中的描述会使用该名称来标识空间。如本例中只有一个加载域,该域名为 LR_IROM1。
基地址+地址偏移:这部分说明了本加载域的基地址,可以使用+号连接一个地址偏移,算进基地址中,整个加载域以它们的结果为基地址。如本例中的加载域基地址为 0x08000000,刚好是 STM32 内部 FLASH 的基地址。
属性列表:属性列表说明了加载域的是否为绝对地址、N 字节对齐等属性,该配置是可选的。本例中没有描述加载域的属性。
最大容量:最大容量说明了这个加载域可使用的最大空间,该配置也是可选的,如果加上这个配置后,当链接器发现工程要分配到该区域的空间比容量还大,它会在工程构建过程给出提示。本例中的加载域最大容量为 0x00080000,即 512KB,正是本型号 STM32 内部 FLASH 的空间大小。

执行域

执行域名 (基地址 | "+" 地址偏移) [属性列表] [最大容量 ]
{
   
   
///输入节区描述
}

执行域的格式与加载域是类似的,区别只是输入节区的描述有所不同

输入节区描述 .o .ANY (+RO)等的用法

配合加载域及执行域的配置,在相应的域配置“输入节区描述”即可控制该节区存储到域中

 //除模块选择样式部分外,其余部分都可选选填
 模块选择样式"("输入节区样式","
本文档是关于GD32H7xx系列微控制器在Keil环境中使用分散加载(Scatter Loading)技术的应用笔记。文档详细介绍了如何通过手动编写的sct文件将全局变量、函数、数组和.c文件加载到指定的存储器位置,包括内部SRAM和外部SDRAM。具体步骤包括修改sct文件、配置链接器选项、定义特殊属性的变量和函数,以及调试验证。此外,还特别强调了在使用SDRAM时需要配置MPU以确保代码执行的安全性和正确性。 适合人群:嵌入式系统开发人员,特别是那些对GD32H7xx系列微控制器有一定了解并希望深入了解其内存管理和优化技术的人群。 使用场景及目标:①通过修改sct文件,实现代码段、数据段等在不同存储器区域的精确放置; 2.2 全局变量加载到指定位置 通过在.sct文件中添加特定代码,可以将全局变量加载到指定的存储区域。例如,将变量testValue_RAM加载到SRAM地址0x24020000。 2.3 函数加载到指定位置 文章展示了如何将函数分配到特定的存储区域,例如将delay函数加载到FLASH地址0x08020000,将fill_TX_Data函数加载到SRAM地址0x24040000。 2.4 数组加载到指定位置 未初始化数组:通过在.sct文件中添加代码,可以将未初始化数组加载到指定的SRAM地址。 常量数组:通过在数组定义后添加__attribute__((section(".ARM.__at_xxxxxxxx"))),可以将常量数组加载到指定的FLASH地址。 全局初始化数组:通过在.sct文件中添加代码,可以将全局初始化数组加载到指定的SRAM地址。 2.5 .c文件加载到指定位置 通过在.sct文件中添加代码,可以将整个.c文件加载到指定的存储区域。 3. SDRAM分散加载实现 文章介绍了如何将代码和数据加载到SDRAM的指定位置。
在MDK中,会生成一个以工程名命名的后缀为 *.sct分散加载文件(Linker Control File,scatter loading),链接器根据该文件的配置分配各个节区地址,生成分散加载代码,通过修改该文件能够定制具体节区的存储位置[^1]。 ### 使用 分散加载文件能解决一些特殊的存储需求。例如,像LPC2378芯片具有多个不连续的SRAM,通用的RAM不够用时,可通过SCATTER文件把某个.C中的RW数据放在USB的SRAM中,对于STM32F427,若有类似多区域存储需求,也可借助分散加载文件实现[^3]。 ### 配置 以下是一个简单的分散加载文件示例: ```plaintext LR_IROM1 0x08000000 0x00080000 { ; load region size_region ER_IROM1 0x08000000 0x00080000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00010000 { ; RW data .ANY (+RW +ZI) } } ``` 在这个示例中: - `LR_IROM1` 是加载区域,`0x08000000` 是加载区域的起始地址,`0x00080000` 是加载区域的大小。 - `ER_IROM1` 是执行区域,这里加载地址和执行地址相同。`*.o (RESET, +First)` 表示将RESET段放在最开始;`*(InRoot$$Sections)` 包含根节区;`.ANY (+RO)` 表示所有的只读(RO)段都放在这里。 - `RW_IRAM1` 是读写数据区域,`0x20000000` 是起始地址,`0x00010000` 是大小,`.ANY (+RW +ZI)` 表示所有的读写(RW)和零初始化(ZI)段都放在这里。 ### 相关说明 - **RESET段**:RESET段存在FLASH(0x08000000 - 0x08080000)中,并且是FLASH的最开头。结合CORTEX - M3的特性,其上电后根据启动引脚来决定PC位置,若启动设置为FLASH启动,则启动后PC跳到0x08000000 [^4]。 - **内存大小计算**:RO Size = Code + RO Data;RW Size = RW Data + ZI Data;ROM Size = Code + RO Data + RW Data [^2]。 - **microlib使用**:若使用了microlib,只需将__initial_sp,__heap_base,__heap_limit三个变量定义成全局变量,这三个变量可被C库引用,在库中会使用它们对堆栈进行初始化 [^5]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值