我们平时都是用缺省的分散加载文件,但有时候需要用到自己编写的分散加载文件,比如远程升级程序等场合。
STM32 开发中分散加载文件(通常是.sct后缀)的具体应用场合,也就是在哪些开发场景下需要用它替代编译器默认的内存分配规则来精准控制存储布局。
分散加载文件是 ARM 编译器(Keil MDK、STM32CubeIDE 等)的核心配置文件,用于定义程序的加载域(Load Region) 和执行域(Execution Region) ,把代码段(.text)、数据段(.data)、未初始化段(.bss)等精准映射到 Flash、RAM、CCM RAM、片外 SDRAM 等不同存储介质。默认的内存分配仅能满足简单场景,以下是必须使用分散加载文件的核心场景:
一、核心应用场景(附代码示例)
场景 1:多类型 / 多区域存储介质的分配(最常用)
STM32 芯片包含多种特性不同的存储资源(片内 Flash、CCM RAM、片外 SPI Flash/SDRAM 等),分散加载文件可将不同数据 / 代码匹配到最优存储区:
-
CCM RAM(核心耦合内存):速度快但 DMA 不可访问,适合高频访问的变量;
-
片外 SPI Flash:容量大但速度慢,适合静态大数据(如字库、固件备份);
-
片内普通 RAM:DMA 可访问,适合缓冲区、普通变量。
示例(STM32F429 分散加载文件):
cpp
; LR_IROM1:加载域(代码最终存储的位置,通常是Flash)
LR_IROM1 0x08000000 0x00100000 ; 片内Flash,起始0x08000000,大小1MB
{
; ER_IROM1:执行域(代码运行的位置,这里和加载域一致)
ER_IROM1 0x08000000 0x00100000
{
*.o (RESET, +First) ; 复位向量表优先存放
*(InRoot$$Sections)
.ANY (+RO) ; 只读代码/常量(如const变量)
}
; RW_IRAM1:普通RAM(DMA可访问)
RW_IRAM1 0x20000000 0x00020000 ; 0x20000000-0x2001FFFF(128KB)
{
.ANY (+RW +ZI) ; 普通读写数据/未初始化数据
}
; RW_CCMRAM:CCM RAM(高速,无总线冲突)
RW_CCMRAM 0x10000000 0x00010000 ; 0x10000000-0x1000FFFF(64KB)
{
*.o (CCM_DATA, +RW +ZI) ; 标记为CCM_DATA的变量存这里
}
}
代码中使用 CCM RAM
cpp
// 给变量加段属性,自动映射到CCM RAM
__attribute__((section("CCM_DATA"))) uint32_t high_speed_var[1024];
场景 2:OTA(空中升级)/ 双固件分区管理
STM32 做 OTA 时,必须划分 Bootloader、App1(主固件)、App2(备份固件)、参数区等独立分区,避免地址重叠,分散加载文件是实现分区的核心:
-
Bootloader:占前 64KB Flash(0x08000000-0x0800FFFF);
-
App1:占后续 512KB(0x08010000-0x0808FFFF);
-
App2:占另一 512KB(0x08090000-0x0810FFFF);
-
参数区:占最后 32KB(0x08100000-0x08107FFF)。
示例(App1 的分散加载文件)
cpp
LR_IROM1 0x08010000 0x00080000 ; App1加载域:起始0x08010000,大小512KB
{
ER_IROM1 0x08010000 0x00080000 ; App1执行域(代码/常量)
{
*.o (RESET, +First) ; 中断向量表重定位到App1起始地址
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00040000 ; 片内RAM(128KB)
{
.ANY (+RW +ZI)
}
}
关键作用:将 App1 的中断向量表重定位到 0x08010000,确保 App1 能绕过 Bootloader 正常启动。
场景 3:特殊代码 / 数据的精准定位
需将特定代码 / 数据固定到指定地址时,必须用分散加载文件:
-
中断向量表重定位(如 App 不在 Flash 起始地址启动);
-
校准数据 / 密钥固定地址(方便量产烧录、加密保护);
-
临界代码放到 RAM 执行(RAM 访问速度远快于 Flash)。
示例:将高频函数放到 RAM 执行:
cpp
; 新增RAM执行域
ER_IRAM2 0x20008000 0x00008000 ; RAM执行域:0x20008000开始,32KB
{
ram_functions.o (+RO) ; ram_functions.c中的代码放这里
}
代码中定义 RAM 执行函数
场景 4:内存优化与 DMA 兼容性
STM32 的 DMA 控制器无法访问 CCM RAM(如 F4/H7 系列),分散加载文件可强制 DMA 缓冲区到普通 RAM;片内 RAM 不足时,可将大数组放到片外 SDRAM:
示例:
cpp
LR_IROM1 0x08000000 0x00200000
{
ER_IROM1 0x08000000 0x00200000
{
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00040000 ; 普通RAM(DMA可访问)
{
*.o (DMA_BUFFER, +RW) ; DMA缓冲区强制放这里
.ANY (+RW +ZI)
}
RW_SDRAM 0xC0000000 0x04000000 ; 片外SDRAM(100MB)
{
*.o (LARGE_ARRAY, +RW) ; 大数组放片外SDRAM
}
}
代码中使用
cpp
// DMA缓冲区(避免放到CCM RAM导致传输失败)
__attribute__((section("DMA_BUFFER"))) uint8_t uart_dma_buf[4096];
// 大数组(释放片内RAM)
__attribute__((section("LARGE_ARRAY"))) uint32_t image_buffer[1024*1024];
场景 5:多核心系统(如 STM32H7 双核心)
STM32H7 的 Cortex-M7 和 M4 双核心需分配独立的 Flash/RAM 空间,避免资源冲突,可通过各自的分散加载文件定义:
-
M7 核心:Flash(0x08000000-0x081FFFFF)、RAM(0x24000000-0x240FFFFF);
-
M4 核心:Flash(0x08200000-0x083FFFFF)、RAM(0x20000000-0x200FFFFF)。
总结
-
分散加载文件的核心作用是突破默认内存分配规则,精准控制代码 / 数据的存储位置,是 STM32 定制化存储布局的核心工具;
-
核心应用场景:多类型存储介质分配、OTA 双分区管理、特殊代码 / 数据精准定位、DMA 兼容 / 内存优化、多核心资源隔离;
-
本质是将代码 / 数据的 "段(Section)" 映射到指定的 "存储域(Region)",满足性能、分区、兼容性等定制化需求。