Keil MDK的.sct加载文件

Keil MDK(MicroVision Development Kit)中的 sct 文件(Scatter-Loading Description File) 是链接器(ARM Linker)用于精确控制代码和数据在嵌入式设备内存中布局的关键配置文件。它取代了传统的启动代码内存初始化,允许开发者灵活定义内存分区、地址分配和段(section)的加载/执行位置。


sct 文件的核心作用

  1. 内存映射管理
    定义物理存储设备(如 Flash、RAM、外部存储器)的地址范围、大小和属性(如 RO(只读)、RW(读写)、ZI(零初始化))。
  2. 代码/数据定位
    指定目标文件(.o)中的各个段(如代码、常量、变量、堆栈)应放置到哪个存储区域。
  3. 执行域控制
    分离加载地址(Load Address,程序存储的位置)和执行地址(Execution Address,程序运行的位置),常用于支持 XIP(eXecute In Place)或数据从 Flash 加载到 RAM 中运行。
  4. 多区域分配
    支持复杂存储架构(如多块 RAM、外部 SDRAM、QSPI Flash)。
  5. 优化启动速度
    减少不必要的拷贝操作(如只拷贝需要初始化的数据段)。

sct 文件基本结构

; 注释格式:分号开头

; 1. 定义存储区域(Memory Regions)
ROM_LOAD  0x08000000  0x00100000  { ; 加载域:起始地址 + 大小
    ; 2. 定义执行域(Execution Regions)
    ROM_EXEC 0x08000000 0x00100000  { ; 执行域地址(常与加载域相同)
        *.o (RESET, +First)          ; 向量表必须放在开头
        * (InRoot$$Sections)         ; 内核和库的关键段(如初始化代码__main函数)
        .ANY (+RO)                   ; 所有只读段(代码+常量)
    }

    RAM 0x20000000 0x00030000 {      ; RAM 执行域
        .ANY (+RW, +ZI)              ; 所有读写数据 + 零初始化数据
    }

    ; 特殊段(如堆栈)
    ARM_LIB_HEAP 0x20030000 EMPTY 0x00004000 { } ; 堆区域(未初始化)
    ARM_LIB_STACK 0x20034000 EMPTY -0x00001000 { } ; 栈(向下生长)
}

关键语法解析

  1. 加载域(Load Region)

    • 定义程序烧录位置(通常是 Flash)。
    • 格式:区域名 起始地址 大小 { 执行域列表 }
    FLASH 0x80000000 0x00200000 { ... } ; 2MB Flash
    
  2. 执行域(Execution Region)

    • 定义代码/数据的运行位置(可能与加载域不同)。
    • 可包含属性:ABSOLUTE(绝对地址)、RELOC(重定位)、EMPTY(预分配空区域)等。
    SRAM 0x20000000 0x00010000 { ... }  ; 64KB RAM 运行域
    
  3. 段分配规则

    • * : 匹配所有目标文件(.o
    • .ANY : 按需分配未被显式指定的段
    • file.o(.section) : 精确指定文件及段
    • +属性:如 +RO+RW+ZI
    • 特殊段:
      • RESET:中断向量表(必须 +First 置于开头)
      • InRoot$$Sections:编译器/库关键段(如 __main.o, __scatter*.o
  4. 地址偏移与对齐

    • offset:偏移量(如 ROM_EXEC +0x1000
    • ALIGN n:按 n 字节对齐
    CUSTOM_RAM 0x20008000 ALIGN 32 { ... } ; 32字节对齐
    

典型场景示例

1. 从 Flash 执行代码(XIP)
LR_FLASH 0x08000000 0x00100000 {   ; 1MB Flash (加载域)
    ER_FLASH 0x08000000 0x00100000 { ; 执行域 = 加载域
        *.o (RESET, +First)         ; 向量表在 Flash 开头
        * (InRoot$$Sections)        ; 库初始化代码
        .ANY (+RO)                  ; 所有代码和常量
    }
    
    ER_RAM 0x20000000 0x00030000 { ; 192KB RAM
        .ANY (+RW, +ZI)            ; 变量和堆栈
    }
}
2. 代码从 Flash 拷贝到 RAM 运行(加速)
LR_FLASH 0x08000000 0x00100000 {
    ER_FLASH 0x08000000 0x00100000 {
        *.o (RESET, +First)
        * (InRoot$$Sections)
        .ANY (+RO)                 ; RO 段保留在 Flash
    }

    ; 定义代码在 RAM 中的执行位置
    ER_FASTCODE 0x20000000 0x00008000 { ; 32KB RAM
        fast_code.o (+RO)           ; 指定需要加速的文件
    }
    
    ER_RAM 0x20008000 0x00028000 { ; 剩余 RAM
        .ANY (+RW, +ZI)
    }
}

需配合初始化代码(由 __main 自动处理或手动实现)。

3. 外部存储器 + 多区域管理
LR_QSPI 0x90000000 0x01000000 {     ; 16MB QSPI Flash
    ER_QSPI_EXEC 0x90000000 0x01000000 {
        .ANY (+RO)                  ; 只读数据/代码
    }
}

LR_SDRAM 0xC0000000 0x02000000 {    ; 32MB SDRAM
    ER_SDRAM_RW 0xC0000000 0x01000000 {
        .ANY (+RW, +ZI)             ; 全局变量
    }
    ER_HEAP 0xC1000000 EMPTY 0x00400000 { } ; 堆区(4MB)
    ER_STACK 0xC1400000 EMPTY -0x00010000 { } ; 栈区(64KB)
}

调试与验证

  1. 生成映射文件
    在 Keil 的 Linker 配置中启用 --map 选项,编译后查看生成的 .map 文件,确认各段地址是否符合预期。

  2. 检查链接错误

    • 地址溢出Execution region xxx size overflow → 增大区域或优化代码。
    • 未分配段Section .data cannot be assigned → 添加 .ANY(+RW)
  3. 使用 __attribute__ 强制指定段
    在代码中通过编译器扩展将变量/函数放入自定义段:

    __attribute__((section(".my_section"))) int fast_var;
    

    在 sct 文件中分配:

    ER_RAM 0x20000000 {
         *.o (.my_section)   ; 分配到 RAM
    }
    

最佳实践

  • 向量表固定地址RESET 必须位于设备指定的起始地址(如 0x08000000)。
  • 库段处理务必包含 * (InRoot$$Sections),避免初始化代码缺失。
  • 使用 .ANY 简化:避免手动枚举所有 .o 文件。
  • 空区域管理:堆栈推荐用 EMPTY(不占用 bin 文件体积)。
  • 版本控制:sct 文件应与工程代码一同纳入版本管理(如 Git)。

通过掌握 sct 文件的配置,开发者能彻底控制嵌入式系统的内存布局,应对复杂存储架构、性能优化与资源受限挑战。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值