关于协议栈XDATA,内存溢出的小结

 

【第二部分的内容仅供参考,自己不是十分确定】
**************************************************************
**************************************************************
**************************************************************

一、

1、单片机的存储器分为数据存储器(RAM)和程序存储器(ROM/FLASH):
RAM:用来存取各种动态的输入输出数据,中间计算结果以及与外部存储器交换的数据和暂存数据。设备掉电后,数据就会丢失。
ROM:通常用来固化存储一些用户写入程序或数据,用于启动设备和控制设备工作方式。设备掉电后可保存数据。
FLASH:通常也是用来固化存储一些用户写入程序或数据。设备掉电后不会丢失数据,同时可以快速读取数据。U盘、MP3多用这种存储器。

RAM包括:
(1)静态RAM(SRAM):速度非常快,是目前读写最快的存储设备。
(2)动态RAM(DRAM):保留数据时间短,但速度比ROM快,计算机内存多为DRAM。DRAM包括:EDORAM;DDR RAM;RDRAM;SGRAM;WRAM…

ROM包括:
(1)PROM:可编程,一次性
(2)EPROM:可擦除可编程,通过紫外线擦除
(3)EEPROM:擦除可编程,通过电子擦除

FLASH包括:(具体参见http://wjf88223.blog.163.com/blog/static/35168001201092685333808/)
(1)NOR FLASH
(2)NAND FLASH

2、存储类型与存储区关系(单片机)
     data       --->     可寻址片内ram
     bdata     --->     可位寻址的片内ram
     idata      --->     可寻址片内ram,允许访问全部内部ram
     pdata     --->     分页寻址片外ram (MOVX @R0) (256 BYTE/页)
     xdata     --->     可寻址片外ram (64k 地址范围FFFFH)
     code      --->     程序存储区 (64k 地址范围),对应MOVC @DPTR

3、一个C语言程序占用的内存分为以下几个部分:
(1)栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结
构中的栈。
(2)堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收。
(3)全局区(静态区):全局变量和静态变量的存储位置是在一起的。初始化的全局变量和静态变量在同一块区 
域,而未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统自动释放。
(4)文字常量区:这一区域用于存放常量字符串,程序结束后由系统释放。
(5)程序代码区:这一区域用于存放函数体的二进制代码(ROM/FLASH)。

4、堆(heap)和栈(stack)的申请方式
stack:由系统自动分配。比如,声明在函数中的一个局部变量 int b;系统自动在栈中为b开辟空间。
heap:需要程序员自己申请,并指明大小。
在C中malloc函数;如:p1=(char *)mqlloc(10);
在C++中用new运算符;如:p2=new char[20];
注:p1,p2本身是在栈中的。

5、例子:
//main.cpp  
int a = 0; //全局初始化区 
char *p1; //全局未初始化区 
main()  
{   
int b; //栈  
char s[ ] = "abc"; //栈  
char *p2; //栈   
char *p3 = "123456"; //123456在常量区,p3在栈上。 
static int c =0; //全局(静态)初始化区  
//分配得来得10和20字节的区域就在堆区。
p1 = (char *)malloc(10);  
p2 = (char *)malloc(20);  
}  
strcpy(p1, "123456"); 
//123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方


6、变量的存储类型和存储方式
存储类型:

关于协议栈XDATA溢出的小结 - 小峰 - Babapig~ -.O!

存储方式:

关于协议栈XDATA溢出的小结 - 小峰 - Babapig~ -.O!


静态存储变量通常是在变量定义时就分配一定的存储空间并一直保持不变,直至整个程序结束。
动态存储变量是在程序执行过程中,使用它时才分配存储单元,使用完毕立即释放。
静态存储变量是一直存在的,而动态存储变量则时而存在时而消失。

全局变量:作用域为整个源程序,即所有源文件;
静态全局变量:作用域为定义该变量的源文件;
把全局变量改变为静态全局变量后改变了它的作用域,而生存期不变;

局部变量:生存期为定义它的函数或复合语句;
静态局部变量:生存期为整个源程序;
把局部变量改变为静态局部变量后改变了它的生存期,而作用域不变;
**************************************************************
**************************************************************
**************************************************************

二、
对《SimpleApp中Controller/Switch绑定小实验》中出现的以下XDATA溢出错误,记录下个人的一点理解.

关于协议栈XDATA溢出的小结 - 小峰 - Babapig~ -.O!

**************************************************************

《SimpleApp中Controller/Switch绑定小实验》中整个工程编译后的内存占用如下:
123 - 小峰 - Babapig~ -.O!
【图1】

那在函数zb_ReceiveDataIndication()中添加下面语句:

123 - 小峰 - Babapig~ -.O!

编译后的内存占用如下:

 123 - 小峰 - Babapig~ -.O!

与图1相比XDATA多了6字节,个人认为这6个字节是:H E L L O
buf这个数组应该属于自动变量,属于动态存储方式,只有在使用它,即当buf被调用时才给它分配内存单元,开始它的生存期,调用结束,释放存储单元,结束生存期。

那在zb_ReceiveDataIndication()中这样添加(typedef  __code const uint8  CCUINT8;,):
 123 - 小峰 - Babapig~ -.O!

编译后的内存占用如下:
 123 - 小峰 - Babapig~ -.O!

与图1相比可以发现这里字符串并没有占用XDATA,而是占用CODE。
若没有static声明为静态变量,则出现以下错误:
Error[Be009]: memory attributes not allowed on auto variables or parameters

当然,把它声明为全局变量(?常量)也可行,在SimpleController.c开头定义全局变量(?常量):
CCUINT8 buf[ ]="HELLO";
编译后的内存占用如下:
 
123 - 小峰 - Babapig~ -.O!

两种方式所占内存一样,全局变量与静态变量的存储方式都是静态存储,存储空间是在编译完成后就分配的,并且在程序运行的全部过程中都不会撤销。
至于出现错误Error[Be009]的原因,和实验室的人讨论也没有得出一个很明确的答案。

typedef  __code const uint8  CCUINT8;
CCUINT8 buf[ ]="HELLO";

按理说应该是把HELLO放在常量区(???),编译后就分配内存,程序运行中只能读取不能改写
(1)把CCUINT8 buf[ ]="HELLO";放在SimpleController.c开头声明为全局变量(?常量),这种存储方式应该是符合的;
(2)把static CCUINT8 buf[ ]="HELLO";放在zb_ReceiveDataIndication()中声明为静态局部变量(?常量),这
种存储方式也应该是符合的;
(3)把CCUINT8 buf[ ]="HELLO";放在zb_ReceiveDataIndication()中,按我个人理解,编译器会认为它是一个自动变量,因为关键字“auto”可以省略,auto不写则隐含确定为“自动存储类别”,属于动态存储方式,即只有在使用它时才给它分配存储单元,开始它的生存期,使用结束后,释放单元,结束生存期。这种存储方
式不符合。
 对于typedef  __code const uint8  CCUINT8;,我是看到协议栈中hal_adc.c定义过这么个数组:

static __code const uint16 HalAdcVddLimit[] =
{
    …………
};

以及在Font.c定义过这么个数组:
__code const INT8U Font8X8[] =
{
    ………………
}

然后拿过来看看能否解决把字符串定义到CODE中而不占用XDATA,具体很详细的语法意思不知道,总之最终可行。

如果把这个数组定义过大,比如在SimpleController.c开头定义:
CCUINT8 buff[4000];
在zb_ReceiveDataIndication()中:
HalUARTWrite ( 0, (uint8 *)buff, sizeof(buff) );
则编译会出现以下错误:
 123 - 小峰 - Babapig~ -.O!

还缺少0x219字节,即537字节,那我这样定义:CCUINT8 buff[3463];编译没有问题:
 123 - 小峰 - Babapig~ -.O!

那我再加1字节:CCUINT8 buff[3464];出现这错误:
 123 - 小峰 - Babapig~ -.O!

即多了0x01字节。O了~

另一种方法,自己申请一个堆
最初工程内存占用为:

 123 - 小峰 - Babapig~ -.O!

那我在zb_ReceiveDataIndication()中这样添加:
 123 - 小峰 - Babapig~ -.O!

编译后的内存占用如下:
 关于协议栈XDATA溢出的小结 - 小峰 - Babapig~ -.O!

与图1相比发现这样定义不占用XDATA。但个人总感觉如果废话多点,这样把字符一个一个赋进去十分麻烦,可是不知道如何快捷地把一串字符赋给动态开辟的堆……
我这样添加:

 123 - 小峰 - Babapig~ -.O!

与图1相比可以看到编译后的内存占用XDATA还是多了6字节:
 123 - 小峰 - Babapig~ -.O!

我这样添加:
 123 - 小峰 - Babapig~ -.O!

与图1相比可以看到编译后的内存占用XDATA一样还是多了6字节:
 123 - 小峰 - Babapig~ -.O!

……还是不知道怎么赋…= . =''关于协议栈XDATA溢出的小结 - 小峰 - Babapig~ -.O!
****************************************
小结[我不敢百分百确定,大家自己可以实验下]:
1、不占用XDATA,对于字符串:
(1) typedef  __code const uint8  CCUINT8; 通过CCUINT8定义到CODE中;//char也OK
(2)通过osal_mem_alloc()函数动态开辟堆空间,把字符一个一个赋进去;用完后调用osal_mem_free()进行内存释放!

2、不占用XDATA,对于一堆需要用数组存储的数据:
  通过osal_mem_alloc()函数动态开辟堆空间,把数据一个一个赋进去;用完后调用osal_mem_free()进行内存释放!
3、对XDATA溢出,我还没有试验过是否可以通过修改配置文件中的-D_XDATA_END来解决,但看了下貌似不可以,已经达到最大值8K了;
********************
// These settings are used for devices that don't use PM2/PM3
-D_IXDATA_START=E000           // The internal IXDATA block is 8K,
-D_IXDATA_END=FEFF             // End of IXDATA if PM2/PM3 are not used
//
// These settings must be used for devices that use PM2/PM3.
// Note that the IXDATA_START allows the XSTACK to grow down into the non-persistent RAM, but
// checks in HAL Sleep insure that the stack is back into persistent RAM before entering PM2/PM3.
//-D_IXDATA_START=EE00         // The internal IXDATA block is 4K+,
//-D_IXDATA_END=FD55           // FD56-FEFF is used for saving the CC2430 registers before sleep.低功耗时这部分用于存储寄存器值
//
// FF00-FFFF is mapped to IDATA.
//
//
//    XDATA
//
-D_XDATA_START=_IXDATA_START   // The IXDATA is used as XDATA.
-D_XDATA_END=_IXDATA_END
********************

4、若CODE溢出: (1)减小程序;(2)把配置文件f8w2430.xcl/f8w2430pm.xcl中的-D_CODE_END改大点:
********************
f8w2430.xcl:
//    CODE
//
// These settings determine the size/location of the ROOT segment.
// Increase _CODE_END to increase ROOT memory, i.e. for constants.
-D_CODE_START=0x0000           // Code size = 128k for CC2430-F128
-D_CODE_END=0x4000             // Last address for ROOT bank
********************
f8w2430pm.xcl:
//    CODE
//
// These settings determine the size/location of the ROOT segment.
// Increase _CODE_END to increase ROOT memory, i.e. for constants.
-D_CODE_START=0x0000           // Code size = 128k for CC2430-F128
-D_CODE_END=0x29FF             //(原0x28FF) Last address for ROOT bank 这里我修改增大过的。
********************

**************************************************************
**************************************************************
**************************************************************

说明:
1、本文为个人学习笔记,仅供参考.
2、错误之处还请指出,随时更新.
2、欢迎交流,转载请注明出处,谢谢!

    更新:2010.12.13                                      ~XF    2010.12.07



原文地址:https://www.cnblogs.com/Zoran-/p/5819308.html