什么是分散加载
单片机和电脑一样具有,存储镜像和运行镜像。生成的bin文件下载到flash里面,然后根据连接脚本加载到指定的地方运行。通常情况下代码段都是放在rom中运行的,而数据段是放在ram中运行的。有时候为了提高效率或是其他目的,放在rom中的部分代码需要在ram中跑,下载的地址和运行的地址不同。这就是分散加载最常见的使用方式。
不只是代码段,分散加载机制可以将内存变量,定位于不同物理地址上。
将存储镜像里的代码,根据链接文件.scf加载到不同的地方,是由rom内置的代码来做的,不需要用户关心,只需要写好链接文件。cpu系统复位或上电之后,自己会做好。
分散加载知识
程序基本概念
code:程序代码段
ro-data:常量及只读类型数据
rw-data:已经初始化的静态变量,全局变量
zi-data:未初始化的静态变量
ROM size = code + ro-data + rw-data
RAM size = rw-data + zi-data
注:rw-data首先被下载到flash,之后需要加载到ram中运行,下载地址和运行地址不同,因此既占用flash空间,也占用ram空间。zi-data又叫bss段不同,它因为没有初始值,可以直接在ram中生成,不占用rom空间,也就是说存储镜像里没有bss段。
分散加载语法
- 第一个运行时域的基址必须与加载域基址相同
- 多flash的情况下,每个flash都定义一个加载域
语法:
- 目标文件过滤器,* 代表0个或多个字符,进行匹配时不区分大小写
- 属性选择器,+,如果指定一个模式以匹配输入段名称,前面需要+
- .ANY表示随意分配,大部分情况下可以代替*
stm32H7官方例子解析
stm32H753官方版的例子:外部flash128M,内部ram1M。
LR_IROM1 0x90000000 0x08000000 { ; load region size_region (128M)
ER_IROM1 0x90000000 0x08000000 { ; load address = execution address
*.o (RESET, +First) //首先加载中断向量表
*(InRoot$$Sections)
.ANY (+RO)//随意分配只读数据
}
RW_IRAM1 0x24000000 0x24080000{ ; RW data //第一块ram的运行域
.ANY (+RW +ZI)//任意分配变量
}
RW_IRAM2 0x38000000 0x00010000 { ; RW data//第二块ram的运行域
*(.RAM_D3)//将RAM_D3里的所有数据放到此处运行
}
}
注意这里就不可以将.ANY (+RW +ZI)换成*(+RW +ZI),因为这样会将所有的静态变量,全局变量拷贝到RW_IRAM1,这样不合适。
具体使用
keil的设置
- 首先去掉勾选linker-> use memory layout from target dialog,表示使用自己的*scf文件
如果这里勾选的话表示使用默认的连接脚本,这个文件是keil根据target 里面的配置自己生成的,目录obj下面的sct文件
配置结果的sct文件内容。
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00020000 { ; load region size_region
ER_IROM1 0x08000000 0x00020000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00020000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM2 0x24000000 0x00080000 {
.ANY (+RW +ZI)
}
}
- 选择算法
这里我们有几个flash那么这里就需要选择几个算法,根据不同型号的flash选择不同的算法。有的算法是没有的需要我们自己拷贝进去。具体放到mdk5安装路径下面的ARM->FLASH里面,然后选择就可以了。