历史上的今天
今天是:2024年10月28日(星期一)
2021年10月28日 | C51和MDK的ROM大小及变量绝对地址初始化
2021-10-28 来源:eefocus
#1. C51的ROM大小
Keil编译完之后,显示的Program Size: data=9.0 xdata=8 const=15 code=180,则
The Total ROM(const + code + code-gap + const-gap) is 199BYTE
实际生成的bin文件大小:

在.MAP中的C O D E M E M O R Y 中

code-gap为0,cosnt-gap为4,则const + code + const-gap=15 + 180 + 4 = 199,刚好和实际生成的bin文件大小一致。
#2. C51的ROM大小优化
如果实际编译显示的const + code远小于实际的Bin文件,表明有非常大的空隙,需要优化。
优化空间,有几个查找方向:
.A51文件中的代码段起始地址CSEG AT 0xXX是否与Off-chip Code Memory设置的起始位置一致,如果不一致可能导致GAP。
函数及变量指定的绝对地址超出Off-chip Code Memory设置的范围。
interrupt vectors at adress: 0xXX设置的中断向量地址是否超出Off-chip Code Memory设置的范围。interrupt vectors at adress必须设置,因为Keil C51默认的是0x03,可能不在Off-chip Code Memory设置的范围内,导致GAP。
打开.MAP文件,搜索GAP,如果存在一些GAP,则可能是多个指定的绝对地址之间有GAP导致的,可以将绝对地址调整对齐。
因为xdata + const + code将占用整个Off-chip(1581为58KB),所以可以将一些const,code类型的变量转换成xdata。总之,根据这三者根据实际情况进行一个调整,总大小不超过58KB即可。有时ROM存放在EEPROM上,所以适当减少const+code的大小,一些变量转换成Xdata是一种方法。
#3. C51变量绝对地址定位及初始化
##3.1. 关键字_at_
int xdata nValA _at_ 0x1114;
int xdata nValA = 0x2222; // nValA绝对地址定位于x:0x1114,初始化值为0x2222
char code nValD _at_ 0xD2;
char code nValD = 0x22; // 此句无效,nValD绝对地址定位于c:0xD2,初始值为0
##3.2. LX51 Locate
当勾选Use Extended liker(LX51) instead of BL51时,即使用LX51 Locate。
LX 51 Locate->User Segments->?CO?MAIN(C:0xD2), ?XD?MAIN(x:0x1114)
LX51 Misc->use linker control file->edit->SEGMENTS (?CO?MAIN(C:0xD2), ?XD?MAIN(x:0x1114))
以上两种设置均可,推荐用前面一种更方便,且还能够添加REMOVEUNUSED等编译关键字。
?CO?MAIN和?XD?MAIN作为segment name,是以变量类型缩写+文件名大写组合而成,对此不熟练,可以打开生成的.MAP文件,查看MEMORY MAP OF MODULE区域的描述也可以找到
当指定了当前文件Segment所在,那么当前文件所有的全局变量,均会在指定的绝对地址之后顺序排列,并且可以对变量进行初始化。
int xdata nValA = 0x2222; // nValA绝对地址定位于x:0x1114,初始化值为0x2222
int xdata nValB = 0x1111; // nValB绝对地址定位于x:0x1116,初始化值为0x1111
char code nValD = 0x22; // nValD绝对地址定位于c:0xD2,初始值为x22
char code nValD = 0x11; // nValD绝对地址定位于c:0xD2,初始值为x11
##3.3. BL51 Locate
当不勾选Use Extended liker(LX51) instead of BL51时,即使用BX51 Locate。
BL 51 Locate->code->?CO?MAIN(0xD2)
BL 51 Locate->Xdata->?XD?MAIN(0x1114)
BL1 Misc->use linker control file->edit->CODE( 0X0000-0X0FFF , ?CO?MAIN(0XD2) ) XDATA( 0X1000-0X2FFF , ?XD?MAIN(0x1002) )
以上两种设置均可,推荐使用LX51,这是新的链接器,性能更好。
#4. MDK的ROM大小
此处主要是针对M0而言。Keil编译之后,在.MAP文件结尾会显示:
Code (inc. data) RO Data RW Data ZI Data Debug
26864 2124 1284 2040 26632 118060 Grand Totals
26864 2124 1284 72 26632 118060 ELF Image Totals (compressed)
26864 2124 1284 72 0 0 ROM Totals
===================================================================
Total RO Size (Code + RO Data) 28148 ( 27.49kB)
Total RW Size (RW Data + ZI Data) 28672 ( 28.00kB)
Total ROM Size (Code + RO Data + RW Data) 28220 ( 27.56kB)
Code,不仅包括生成的代码,还包括inline data, literal pools, and short strings。
RO Data,Read Only data,用const修饰的变量,或是地址定位到RO Data的变量。
ZI Data,Zero Initialie data,编译器进行0初始化的数据。所有未显示初始化,或是显式初始化为0的变量均是ZI Data(包括栈变量和堆变量)。
RW Data,Read Write Data,显式初始化为非0的全局变量。
Total Rom Size即是生成的bin文件大小。ROM Size所包含的RW Data为28220-28148=72,而不是2040。
实际的代码:
int nArr[500] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
nArr作为RW Data,实际大小有2000B,那么为什么通过ROM计算出的RW Data只有72B呢?
首先,RW Data为什么要记录在ROM中呢?这是因为RW Data的初始化值是编译期生成的,所以这些初始化值要记录在ROM中,这样一上电就能够初始化。正因为只记录初始化的值,所以上面的nArr只初始化了10个值,其他未初始化的其实都没有放进ROM中。所以这才导致了两者的不同。
Total RW Size即运行时存放变量的RAM的大小。
#5. MDK的ROM优化
打开.MAP文件,找到Memory Map of the image处,搜查看是否有PAD,如果存在一些PAD,则可能是多个指定的绝对地址之间有GAP导致的,可以将绝对地址调整对齐PAD的大小然后编译再查看.MAP文件的PAD。
因为Code + RO Data + RW Data + ZI Data将占用整个SRAM(5081为60KB),Code一般不易修改,所以可以动态调整RO Data、RW Data以及ZI Data的分布,只要总的大小不超过60KB即可,来优化ROM的大小。有时ROM存放在EEPROM上,所以适当减少ROM的大小,一些变量转换成ZI Data是一种方法。
#6. MDK的变量绝对地址定位及初始化
##3.1. 关键字__attribute__((at(address)))
const int MAX_LUN_CNT __at(0x2000E000) = 10; // IROM1
const int MY_COLOR[4] __at(0x2000E004) = {1, 2, 3, 4}; // IROM1
int g_Val __at(0x2000E004); // 正确 // IROM1
int g_Val1 __at(0x2000E200); // 正确 // IRAM1
// 错误.This is fixed with ARM Compiler V5.06u2, released in combination with MDK-ARM V5.20.
int g_Val __at(0x2000E200) = 10; // Keil 4编译错误,Keil 5.20编译通过
下一篇:51单片机学习笔记之中断
史海拾趣
|
1.概述 也许您曾经想过无线网络的应用,但是您听到的说法让您犹豫再三。您的同事告诉您,无线应用不但复杂而且昂贵。您的老板提到可靠性和升级的问题。或者,在您最后一次参加的技术会议上,与会者提到了太多太多的安全风险问题。 虽然各种形 ...… 查看全部问答> |
|
大家好,现在实验中要对模拟信号精确处理,模拟信号Vo为电流传感器输出,经过隔离芯片后为Vin,然后送到跟随器,由于隔离芯片有误差,导致Vin高于Vo,差值为0.02v,为固定值,请问如何才能才能使用模拟电路抵消0.02v的差值?(见附件) [ 本帖最后 ...… 查看全部问答> |
|
昨天,一应用程序员反问了这个问题 在写向flash写数据的时候,突然断电,下次再启动的时候。这个文件变成不可读写了,说是写保护了。 请问大家是否遇到这种情况了? 我看了两个类似的帖子。 http://topic.eeworld.net/u/20080616/11/C34E5388-9 ...… 查看全部问答> |
|
我最近在看《自己动手写操作系统》那本书,已经看到了保护模式,但尚有一问,第一章时,BootSector的代码的最后两个字节是0x55aa 但是我后来改成了0xaa55 也可以正常引导,请问这到底是怎么回事呢?… 查看全部问答> |
|
用制作LED16*16单行点阵屏通过RS232串口接收数据问题 本人用89C51做了一个LED16*16点阵单行显示屏,带RS232串行口,现在本人写的程序可显示4个中文汉字左或右、上或下循环显示,我懂用计时器0、方式1 设置9600波特率通过串口助手发十六进制01 、02控制带串口的LED单灯左循环的启停,现在有几点请教大家 ...… 查看全部问答> |
|
S3C2416开发板ARM9EJ内核 完美替代S3C2440 一、S3C2416简介 S3C2416是低功耗、高性能、低成本的SAMSUNG ARM9(ARM926EJ)处理器,最具性价比优势的芯片,S3C2440最完美的替代者。 UT-S3C2416开发板是一款以S3C2416处理器为核心的高 ...… 查看全部问答> |
|
本人现在有一款omap3530嵌入式开发板devkit8000,当初心血来潮买的,因为种种原因买了之后就没用过了,算是全新的。关于该开发板的信息可以看这里http://www.timll.com/products/Devkit8000.asp这里http://elinux.org/DevKit8000和这里http://item. ...… 查看全部问答> |




