KEIL下分散加载文件

本文详细介绍了Keil中SCATTER文件的使用方法及注意事项,通过实例解析了如何利用SCATTER文件精确控制代码和数据的加载与运行地址,特别适用于需要定制化内存布局的应用场景。
AI助手已提取文章相关产品:

在keil中编译的程序通过了,但是debug的时候会出现一些错误:

*** error 65: access violation at 0x4C000018 : no 'write' permission

*** error 65: access violation at 0x00000000 : no 'execute/read' permission (ram.sct的时候)

我发现当我工程设置中linker中选择了runinram.sct和runinflash.sct或者自动生成的sct文件的时候就出现上面的错误。应该就是地址的问题。但是具体怎么修改才能解决这个错误,还没弄明白。弄明白了再发。

 

下面是找了一篇值得参考的文章:

原文地址:

http://hi.baidu.com/pengjj0807/blog/item/ef73e287a212453cc65cc3be.html

KEIL下分散加载文件的使用

*************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00004000 ; load region size_region 第一个加载域,起始地址0x08000000{ 大小0x00004000

ER_IROM1 0x08000000 0x00004000 ; load address = execution address第一个运行时域,

{ 起始0x08000000,大小0x00004000

*.o (RESET, +First) IAP第一阶段还是在FLASH中运行
*(InRoot$$Sections)
startup_stm32f10x_md.o
}
ER_IROM2 0x20008000 0x00004000 ; load address = execution address第二个运行时域,

{ 起始0x20008000,大小0x00004000

.ANY (+RO) IAP第二阶段加载到SDRAM中运行
}
RW_IRAM1 0x20000000 0x00008000 ; RW data
 把可读写的数据和初始化为0的数据放在内存SDRAM的开头

{

.ANY (+RW +ZI)
}
}

让MDK自己分配--选linker-usexxx


 

对于分散加载的概念,在《ARM体系结构与编程》书中第11章有明确介绍。

分散加载文件(即scatter file 后缀为.scf)是一个文本文件,通过编写一个分散加载文件来指定
ARM连接器在生成映像文件时如何分配RO,RW,ZI等数据的存放地址。如果不用SCATTER文件指定,那么
ARM连接器会按照默认的方式来生成映像文件,一般情况下我们是不需要使用分散加载文件的。

但在某些场合,我们希望把某些数据放在指定的地址处,那么这时候SCATTER文件就发挥了非常大的作用
而且SCATTER文件用起来非常简单好用。

举个例子:比如像LPC2378芯片具有多个不连续的SRAM,通用的RAM是32KB,可是32KB不够用,我想把
某个.C中的RW数据放在USB的SRAM中,那么就可以通过SCATTER文件来完成这个功能。
下面是就这个例子作的说明:


这是一个标准的常用的分散加载文件,现在加注释于后,方便以后查阅:
;******************************************************************************
;
; SCATTER LOADING DEION
; ARM
; KEIL's uVision3
; (RealView Microprocessor Developer Kit)
;
; Filename : LPC2378_Flash.scat
;******************************************************************************

LR_IROM1 0x00000000 0x00080000 ;; 第一个加载域,名字为LR_IROM1,起始
{                  ;;地址为0x0,大小为0x80000
ER_IROM1 0x00000000 0x00080000 ;;加载域中的运行时域,名字为ER_IROM1
{ ;; 起始地址为0x0,大小为0x80000
vectors.o (VECT, +First) ;;将vectors.c编译后生成的文件vectors.o中的代码
init.o (INIT) ;;以及init.o中的代码
* (+RO) ;;以及所有编译生成的RO属性的代码全部存放在
} ;;运行时域ER_IROM1指定的地址范围内,存放方式:顺序存放

RW_IRAM1 0x40000000 0x0000e800  ;;这是第二个运行时域,功能同上
{ ;;其中 *是代表具有()里面指定的属性的全部数据
*(+RW,+ZI) ;;与*功能相似的有.ANY,后面说明
} ;; The following declarations select the "two region model" ;

;; A default __user_initial_stackheap() will be used ;
ARM_LIB_HEAP 0x40007000 EMPTY 0x00000100 {} ;;指定堆栈地址
ARM_LIB_STACK 0x40008000 EMPTY -0x00000E00 {}
}


下面是针对LPC2378的USB SRAM作数据RAM使用的配置:

;******************************************************************************
;
; SCATTER LOADING DEION
; ARM
; KEIL's uVision3
; (RealView Microprocessor Developer Kit)
;
; Filename : LPC2378_Flash.scat
;******************************************************************************

LR_IROM1 0x00000000 0x00080000 ;; 第一个加载域,名字为LR_IROM1,起始
{                  ;;地址为0x0,大小为0x80000
ER_IROM1 0x00000000 0x00080000 ;;加载域中的运行时域,名字为ER_IROM1
{ ;; 起始地址为0x0,大小为0x80000
vectors.o (VECT, +First)
init.o (INIT)
* (+RO)
}

RW_IRAM1 0x40000000 0x0000e800
{
.ANY(+RW,+ZI)     ;; 此处.ANY替换原来的*,是因为下面的一个执行域对指定的模块中的RW,ZI数据指定了存放地址
;;用.ANY就可以把已经被指定的具有RW,ZI属性的数据排除
} ;; The following declarations select the "two region model" ;

找了3个分散加载文件来分析:

1、7x256的flash.sct分散加载文件:

Load_region 0x100000 0x40000 {//ro起始地址为0x100000,大小为0x40000

Fixed_region 0x100000 0x40000 {
*(cstartup +First)
.ANY (+RO)
}

Relocate_region 0x200000 {//rw和zi段的地址为0x200000

*.o (VECTOR, +First)
.ANY (+RW +ZI)
}

ARM_LIB_HEAP 0x20E000 EMPTY 0x1000 {
}

ARM_LIB_STACK 0x210000 EMPTY -0x1000 {
}
}

2、sram.sct文件

Load_region 0x200000 0x10000 {

Fixed_region 0x200000 {
*.o (VECTOR, +First)
.ANY (+RO)
}

Relocate_region +0 {
*(cstartup +First)
.ANY (+RW +ZI)
}

ScatterAssert((ImageLength(Fixed_region) + ImageLength(Relocate_region)) < 0xE000)

ARM_LIB_HEAP 0x20E000 EMPTY 0x1000 {
}

ARM_LIB_STACK 0x210000 EMPTY -0x1000 {
}
}

3、自定义的sram.sct

LR_IROM1 0x00200000 0x00008000 { ; load region size_region
ER_IROM1 0x00200000 0x00008000 { ; load address = execution address//加载域等于运行域
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x00208000 UNINIT 0x00008000 { ; RW data//rw和zi段
.ANY (+RW +ZI)
}
}

什么是分散加载文件这里就不赘述了。

前面两个分散加载文件是从别的地方拷过来的,用在自己的程序中可能会有问题,因为如果不修改它的话它就固定了加载地址和运行地址,如果程序简单又比较小的话可能不会有问题,但是如果程序代码比较大,超出了那两个加载文件的定义大小可能就会出问题,解决办法也很简单,直接修改.sct文件直到适合你的代码。

更好的办法是自己定义一个分散加载文件,在keil中勾选Use Memory Layout from Target Dialog,那么加载文件就是从你定义irom和iram等地址得到的,如果不勾选的话就是通过你自己指定的加载文件来加载。

如果分散加载文件不对的话,可能出现的问题就是明明是在sram中调试程序,但是却能神奇的通过flash downloader下载到flash中去,刚开始也是不解,后来才发现是分散加载文件有错误,我使用了一个指定的flash.sct分散加载文件,这样的话我设置的irom和iram都无效了,编译器直接根据我指定的flash.sct来分布代码和加载代码,又查看了一下flash.sct文件是加代码加载到flash地址空间的,这就是为什么在jlink-sram工程中也能通过flash downloader工具烧写代码到flash中去的原因

您可能感兴趣的与本文相关内容

<think>嗯,用户的问题是关于如何在Keil中自动生成分散加载文件。首先,我需要回忆一下分散加载文件的作用,它主要用于指定代码和数据的存储位置,这在嵌入式开发中非常重要,尤其是在处理不同内存区域时。用户可能正在开发STM32或者其他基于ARM的项目,需要配置内存布局,可能遇到了手动配置分散加载文件的麻烦,所以想知道如何让Keil自动生成。 根据用户提供的引用内容,特别是引用[1]中提到,Keil默认情况下会根据Target配置生成分散加载文件,当取消勾选第一个选项时,可以编辑分散加载文件。所以,自动生成的关键可能在于正确配置Target选项,让Keil根据这些配置自动处理。 接下来,我需要整理步骤。首先,用户需要打开工程配置,进入Target设置,确认内存地址和大小是否正确,比如STM32的Flash起始地址0x08000000和大小0x00040000。然后,在Linker选项中,确保Use Memory Layout from Target Dialog被勾选,这样Keil就会根据Target的配置生成分散加载文件,而不需要手动编辑。这可能就是自动生成的关键步骤。 另外,引用[2]提到分散加载文件和映像文件的关系,说明自动生成的文件结构可能包括加载域和执行域,如LR_IROM1和ER_IROM1。用户可能需要检查生成的文件内容是否符合预期,例如是否包含了正确的ROM和RAM配置。 可能用户遇到的问题是没有正确配置Target中的ROM和RAM地址,导致分散加载文件生成不正确。需要提醒用户检查这些地址是否与芯片手册一致。此外,如果用户需要更复杂的配置,可能需要手动修改分散加载文件,这时候就需要取消勾选自动生成的选项,但用户当前的需求是自动生成,所以重点应放在正确配置Target选项上。 还需要考虑用户是否了解如何找到生成的文件,引用[1]中提到可以通过Edit或白色框中的目录找到默认生成的文件。因此,在教程步骤中,应该指导用户如何访问这个文件,确认其内容是否正确。 总结步骤应该是:打开工程配置,配置Target中的内存地址,确保Linker选项中启用自动生成,最后编译工程并检查生成的文件。可能还需要提醒用户关于依赖库和启动文件的位置是否需要特别处理,但根据引用内容,这部分可能由Keil自动处理。 另外,用户提供的引用[3]中关于Keil工程的建立过程,可能用户是新手,所以在教程中需要详细说明每个步骤的位置,比如如何进入Target和Linker设置,如何勾选选项等,避免用户找不到相关菜单。 最后,生成的问题部分需要考虑用户可能的后续疑问,比如优化内存分配、处理多区域内存、错误排查等,这些都与分散加载文件相关,可以作为相关问题提出,帮助用户进一步学习。</think>### Keil自动生成分散加载文件教程 在Keil MDK中,分散加载文件(Scatter File)的自动生成主要依赖工程配置中的 **Target选项** 和 **Linker配置**。以下是具体操作步骤: --- #### **步骤1:配置Target选项** 1. 打开工程配置:右键点击工程名 → 选择`Options for Target` 2. 进入`Target`选项卡: - **ROM配置**:定义Flash起始地址和大小,例如STM32F1系列通常为: ``` Start: 0x08000000 Size: 0x00040000 ``` - **RAM配置**:定义内存起始地址和大小,例如: ``` Start: 0x20000000 Size: 0x00008000 ``` - 此配置直接影响自动生成的分散加载文件中的加载域(Load Region)和执行域(Execution Region)[^1]。 --- #### **步骤2:启用Linker自动生成** 1. 在工程配置中进入`Linker`选项卡: - 确保勾选 **`Use Memory Layout from Target Dialog`** ![Linker配置示意图](https://example.com/linker-settings.png) - 若勾选此选项,Linker会根据`Target`选项卡中的ROM/RAM配置自动生成分散加载文件[^1]。 --- #### **步骤3:编译工程生成文件** 1. 执行编译操作(点击`Build`按钮) 2. 生成的分散加载文件默认路径为: ``` 工程目录\Objects\工程名.sct ``` 3. 文件内容示例: ```scatter LR_IROM1 0x08000000 0x00040000 { ; 加载域:Flash起始地址和大小 ER_IROM1 0x08000000 0x00040000 { ; 执行域:代码段 *.o (RESET, +First) ; 中断向量表 * (InRoot$$Sections) ; ARM运行时库依赖 .ANY (+RO) ; 只读数据(代码、常量) } RW_IRAM1 0x20000000 0x00008000 { ; 可读写数据(RAM) .ANY (+RW +ZI) ; 全局变量、堆栈等 } } ``` --- #### **验证与调试** 1. **查看MAP文件**:编译后生成的`.map`文件会详细列出各段地址分配。 2. **修改规则**:若需自定义代码/数据分区,需手动编辑`.sct`文件并取消勾选`Use Memory Layout from Target Dialog`[^2]。 --- #### **注意事项** 1. 自动生成适用于 **单存储区域** 的简单工程,多区域存储需手动编写分散加载文件。 2. 启动文件(如`startup_stm32f10x.s`)中的堆栈初始化需与分散加载文件中的RAM定义匹配[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值