【GD32】分散加载文件.sct
.sct
文件是什么?
.sct
文件(Scatter-Loading Description File,分散加载描述文件)是 ARM 编译器(特别是 ARM Compiler 5/6 和 Keil MDK-ARM) 中使用的一种链接脚本文件。它的核心作用是精确控制程序代码(Code)和数据(Data)在目标微控制器(MCU)物理内存(如 Flash、RAM)中的存放位置和加载行为。
为什么需要 .sct
文件?
- 非单一连续内存块:现代 MCU(包括 GD32)通常具有复杂的存储器结构:
- 多个 Flash 块:主程序 Flash、选项字节区域、信息块、可能还有独立的 Bootloader Flash。
- 多种 RAM 块:主 SRAM、可能还有 CCM RAM(内核耦合存储器,通常只能由 CPU 直接访问,DMA 不可达)、备份 SRAM(在待机模式下保持数据)。
- 外设寄存器区域:内存映射的寄存器地址空间。
- 特殊需求:
- 将关键代码(如中断向量表、启动代码)放在特定地址(如 Flash 起始地址)。
- 将高频访问的数据(如堆栈、DMA 缓冲区)放在速度更快的 RAM(如 CCM RAM)中。
- 将需要在低功耗模式下保持的数据放在备份 RAM 中。
- 实现自定义的 Bootloader 和 Application 分区。
- 处理不同速度或特性的内存区域。
- 定义堆(Heap)和栈(Stack)的精确位置和大小。
- 默认行为不足:链接器有默认的链接规则(通常假设一个连续的 Flash 和一个连续的 RAM),但在面对上述复杂或不连续的内存布局时,默认规则无法满足需求。
.sct
文件的结构(ARM Compiler 5/6 / Keil MDK-ARM)
一个典型的 .sct
文件包含以下几个主要部分:
-
加载区 (Load Region):
- 定义程序在上电或复位后初始存放的位置(通常是 Flash)。
- 指定该区域的起始地址 (
base
)、大小 (size
) 和类型 (属性
,如PI
表示物理初始加载地址)。 - 可以有多个加载区(例如,主程序 Flash 和 信息块 Flash)。
LR_IROM1 0x08000000 0x00080000 { ; 加载区名称 LR_IROM1, 起始地址 0x08000000, 大小 0x80000 (512KB)... ; 执行区定义放在这里 }
-
执行区 (Execution Region):
- 定义程序在运行时代码和数据实际存放和执行的位置。
- 每个执行区必须属于一个加载区。
- 指定该执行区的起始地址 (
base
)、大小 (size
)、访问属性 (属性
,如RW
可读可写,ZI
初始化为零,PI
与加载地址相同,RELOC
需要重定位等)。 - 可以有多个执行区(例如,
.text
在 Flash,.data
在 RAM,.ccmram
在 CCM RAM)。
ER_IROM1 0x08000000 0x00080000 { ; 执行区名称 ER_IROM1, 起始地址 0x08000000, 大小 0x80000... ; 模块和段选择放在这里 } RW_IRAM1 0x20000000 0x00020000 { ; 执行区名称 RW_IRAM1, 起始地址 0x20000000 (主RAM), 大小 0x20000 (128KB)... ; 模块和段选择放在这里 } RW_IRAM2 0x10000000 0x00010000 { ; 执行区名称 RW_IRAM2, 起始地址 0x10000000 (CCM RAM), 大小 0x10000 (64KB)... ; 模块和段选择放在这里 }
-
模块选择器和段选择器 (Module Selector and Section Selector):
- 在执行区内部,使用
*.o
(目标文件) 或特定目标文件名 +(+RO)
,(+RW)
,(+ZI)
等选择器来指定哪些代码段或数据段应该放置在该执行区。 +RO
:只读部分(代码.text
,常量.rodata
,初始化数据表的只读部分)。+RW
:可读写数据(已初始化的全局/静态变量.data
)。+ZI
:零初始化数据(未初始化或显式初始化为0的全局/静态变量.bss
)。*
是通配符,匹配所有目标文件。
ER_IROM1 0x08000000 0x00080000 {*.o (RESET, +First) ; 将 RESET 段(包含向量表)放在这个区域的起始位置(+First)*(InRoot$$Sections) ; ARM 库的特殊段(如 C/C++ 库初始化代码).ANY (+RO) ; 将所有其他只读段(代码和常量)放在这里 } RW_IRAM1 0x20000000 0x00020000 {.ANY (+RW +ZI) ; 将所有的 RW 和 ZI 数据默认放在主 RAM } RW_IRAM2 0x10000000 0x00010000 {my_speed_critical.o (+RW +ZI) ; 将特定文件的数据放在 CCM RAMmy_dma_buffer.o (+RW) ; 将另一个文件的 RW 数据也放在 CCM RAM }
- 在执行区内部,使用
-
特殊符号定义:
- 定义堆栈位置:
ARM_LIB_STACK 0x20020000 EMPTY -0x00004000 {} ; 栈顶在 0x20020000, 向下生长 16KB (0x4000) ARM_LIB_HEAP 0x2001C000 EMPTY 0x00004000 {} ; 堆起始 0x2001C000, 大小 16KB (0x4000)
EMPTY
属性表示该区域在链接时不填充任何输入段的内容,而是预留一块空间(用于堆或栈)。
- 定义堆栈位置:
.sct
文件在 GD32 开发中的关键点
- 匹配具体型号的存储器映射:必须根据你使用的 具体 GD32 型号的数据手册 来编写
.sct
文件。不同型号的 Flash 起始地址、大小、RAM 地址和大小(包括是否有 CCM RAM)都不同。 - 向量表位置:中断向量表必须放在 Flash 的起始地址(通常是
0x08000000
)。.sct
文件确保RESET
段(包含向量表)位于+First
。 - 初始化过程:链接器根据
.sct
文件生成代码。这些代码在main()
函数之前执行(通常由startup_*.s
汇编启动文件调用),负责:- 将初始化数据(
.data
)从 Flash 中的加载地址复制到 RAM 中的执行地址。 - 将零初始化数据区(
.bss
)在 RAM 中清零。
- 将初始化数据(
- 优化性能:通过将关键代码(如中断服务程序)或高频访问数据放在更快的存储器(如 CCM RAM)中,可以显著提升性能。
- Bootloader 支持:如果使用 Bootloader,
.sct
文件需要将 Application 的起始地址偏移到 Bootloader 占用的空间之后(例如0x0800C000
),并可能调整向量表偏移寄存器 (VTOR
)。
如何创建和使用 .sct
文件 (Keil MDK-ARM)
- 默认生成:在 Keil 中新建 GD32 工程时,IDE 通常会根据你选择的芯片型号自动生成一个基本的
.sct
文件(如GD32F30x.sct
)。 - 手动编辑:
- 在 Project 窗口中找到该文件(通常在
Target
目录下)。 - 右键点击 ->
Open
或Edit
。 - 根据项目需求修改加载区、执行区定义和段分配。
- 在 Project 窗口中找到该文件(通常在
- 指定文件:在 Keil 的
Options for Target
->Linker
选项卡中:- 确保
Use Memory Layout from Target Dialog
未选中。 - 在
Scatter File
框中,选择或输入你的.sct
文件路径。
- 确保
- 查看效果:编译链接后,查看生成的
.map
文件。这个文件详细列出了所有段、符号的最终地址和大小,是验证.sct
文件是否按预期工作的关键依据。
.sct
文件与其他工具链
- GCC (ARM-none-eabi-gcc):GCC 工具链使用
*.ld
(Linker Script)文件来实现与.sct
相同的功能。语法完全不同(基于MEMORY
和SECTIONS
命令),但目的和作用是等价的。如果你使用基于 GCC 的 IDE(如 STM32CubeIDE、PlatformIO、VSCode + Cortex-Debug),你需要编辑的是.ld
文件。 - IAR Embedded Workbench:IAR 使用
*.icf
(IAR Configuration File)文件作为其链接脚本。
总结
.sct
文件是 ARM 编译器(Keil MDK)中控制 GD32 程序内存布局的核心配置文件。它精确地定义了代码和数据在 Flash 和不同类型 RAM(如主 RAM、CCM RAM)中的加载地址、执行地址以及初始化过程。理解并正确配置 .sct
文件对于:
- 确保程序正确运行(向量表位置正确、数据正确初始化)。
- 充分利用芯片的存储器资源(划分 Flash/RAM、使用特殊 RAM)。
- 优化性能(将关键部分放入更快的内存)。
- 实现复杂功能(如 Bootloader/Application 分区、在低功耗模式下保持数据)。