EDN首页   博客首页

最新日志

发表于:2008-7-21 9:49:07
标签:data2mem  .bmm  .mem  

1

data2mem技术

i want to use Data2mem tool for my rom updating. i have rom that has size of 64kb
 with data bus of 8 bits.i used this tool for 4kb and it worked fine but some how
  for 64 kb its not working at all.
normally for this tool bmm is used. so i used and for 64kb there are 32 ramb16
 location that i have seen in place and route editor so i enter these location
  in bmm file.
here is the bmm file that i have used.
ADDRESS_SPACE i_mc8051_rom RAMB16 [0x0000:0xffff]
///////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
i_mc8051_rom/B6 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B9 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B12 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B15 [7:0];
END_BUS_BLOCK;
///////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
i_mc8051_rom/B64 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B67 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B70 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B73 [7:0];
END_BUS_BLOCK;

///////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
i_mc8051_rom/B122 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B125 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B128 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B131 [7:0];
END_BUS_BLOCK;

//////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
i_mc8051_rom/B180 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B183 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B186 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B189 [7:0];
END_BUS_BLOCK;

///////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
i_mc8051_rom/B238 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B241 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B244 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B247 [7:0];
END_BUS_BLOCK;

///////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
i_mc8051_rom/B296 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B299 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B302 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B305 [7:0];
END_BUS_BLOCK;

///////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
i_mc8051_rom/B354 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B357 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B360 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B363 [7:0];
END_BUS_BLOCK;

///////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
i_mc8051_rom/B412 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B415 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B418 [7:0];
END_BUS_BLOCK;

BUS_BLOCK
i_mc8051_rom/B421 [7:0];
END_BUS_BLOCK;

///////////////////////////////////////////////////////////////////////////////
END_ADDRESS_SPACE;

The thing i want to know is how to enter values on these bram location. i have
8 bit data bus.ramb16 means one location has to be 2kb.and i have 32 locations.
so how this 2kb per location will work.guide me out.i have seen xilinx data2mem
pdf file but no help in this matter.
waiting for responce.

 

next thing is i have hex file i can also use .coe format.but how to generate from hex file a coe file.

waiting for the responces.

thanks
-----------------------------------------------------------------------------
Muhammad,

 

This is how I do. Don't know if this is the right way but it works.

 

1. First, prepare .bmm file. One thing I would like to note is that use fixed primitive for coregen.

(2k x 8) Otherwise, I saw Coregen use 9-bit parity for data bit which can mess up the data2mem.

Here is my example for 32-bit ROM. (ROM.bmm)

 

//--------------------------------------------------------------------------------------------------

// myTop can be any name. I don't think PPC405 also matters.

//--------------------------------------------------------------------------------------------------

ADDRESS_MAP myTop PPC405 0

 

    ADDRESS_SPACE BOOTROM_0 RAMB32 [0x00000000:0x00003FFF]

         BUS_BLOCK

            top/rom/rom0/u0_R1O4096X32M16P32A_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [7:0] ;

            top/rom/rom0/u0_R1O4096X32M16P32A_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[1].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [15:8] ;

            top/rom/rom0/u0_R1O4096X32M16P32A_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[2].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [23:16] ;

            top/rom/rom0/u0_R1O4096X32M16P32A_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[3].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [31:24] ;

        END_BUS_BLOCK;

    END_ADDRESS_SPACE;

 

    ADDRESS_SPACE BOOTROM_1 RAMB32 [0x00004000:0x00007FFF]

        BUS_BLOCK

            top/rom/rom1/u0_R1O4096X32M16P32B_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [7:0] ;

            top/rom/rom1/u0_R1O4096X32M16P32B_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[1].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [15:8] ;

            top/rom/rom1/u0_R1O4096X32M16P32B_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[2].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [23:16] ;

            top/rom/rom1/u0_R1O4096X32M16P32B_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[3].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [31:24] ;

        END_BUS_BLOCK;

    END_ADDRESS_SPACE;

 

END_ADDRESS_MAP;

 

You need to know the exact path of block memory. I use planAhead and I think any other tool which can read .ngc or .edn should work.

 

2.  Run Map/PAR with .bmm file. Just add ROM.bmm file during ISE run. At the end of bitgen, ISE will create ROM_bd.bmm

which contains the physical location of each ROM as shown below.

 

ADDRESS_MAP myTop PPC405 0

 

 

    ADDRESS_SPACE BOOTROM_0 RAMB32 [0x00000000:0x00003FFF]

        BUS_BLOCK

            top/rom/rom0/u0_R1O4096X32M16P32A_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [7:0] PLACED = X4Y12;

            top/rom/rom0/u0_R1O4096X32M16P32A_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[1].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [15:8] PLACED = X4Y22;

            top/rom/rom0/u0_R1O4096X32M16P32A_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[2].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [23:16] PLACED = X4Y30;

            top/rom/rom0/u0_R1O4096X32M16P32A_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[3].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [31:24] PLACED = X4Y17;

        END_BUS_BLOCK;

    END_ADDRESS_SPACE;

 

 

    ///////////////////////////////////////////////////////////////////////////////

    //

    // Processor 'mb_uC' address space 'BOOTROM_1' 0x00004000:0x3300007FFF (16 KB).

    //

    ///////////////////////////////////////////////////////////////////////////////

 

    ADDRESS_SPACE BOOTROM_1 RAMB32 [0x00004000:0x00007FFF]

        BUS_BLOCK

            top/rom/rom1/u0_R1O4096X32M16P32B_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [7:0] PLACED = X4Y9;

            top/rom/rom1/u0_R1O4096X32M16P32B_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[1].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [15:8] PLACED = X4Y23;

            top/rom/rom1/u0_R1O4096X32M16P32B_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[2].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [23:16] PLACED = X2Y37;

            top/rom/rom1/u0_R1O4096X32M16P32B_fpga/BU2/U0/blk_mem_generator/valid.cstr/ramloop[3].ram.r/v5_init.ram/SP.SINGLE_PRIM36.SP [31:24] PLACED = X4Y18;

        END_BUS_BLOCK;

    END_ADDRESS_SPACE;

 

To run data2mem, the tool should know where it can find BRAM to replace the contents.

If you didn't run with .bmm, you can manually create .bmm file using planAhead or FPGA editor for geometry.

I recommend using planAhead to read .ncd since it is much faster.

 

3. Prepare .mem file for new data. Refer data2mem manual for exact format. But basically it is just list of data with starting address.

You can jump to next address without filling every address. "0" will be inserted for any address that are not covered.

You may want to create very simple script to convert .hex to .mem (or .coe to .mem).

Let's call this file as "newROM.mem"

 

@0000

0e0000ea

18f09fe5

18f09fe5

18f09fe5

18f09fe5

18f09fe5

18f09fe5

18f09fe5

40000000

@3FFF

0f000000

 

4. Ready to run data2mem.

If your original bitstream is Top.bit, you can create new bitstream "newTop.bit"

with data2mem.

 

data2mem -bm ROM_bd.bmm -bd  newROM.bmm -bt Top.bit -o b newTop.bit

 

If you would like to verify the new data in new bitstream, dump bitstream into text file

might be useful.

 

data2mem -bm ROM_bd.bmm -bt newTop.bit > newTop.dump.txt

 

Hope this helps. I love data2mem. This is the fastest way to create new bitstream

with new ROM data without running long long ISE processes.

 

- Jay Moon

以下为我的个人小结:

1. data2mem工具认为地址空间是字节地址空间,对于做32位SOC的朋友或16位DSP的朋友需要进行4倍或2倍的处理

2. BUS_BLOCK与END_BUS_BLOCK之间的位宽要根据用户自己的实际位宽来组合

3. 注意格式,注意多个blockram初始化可以统一写在同一个.bmm里即多个ADDRESS_SPACE ...END_ADDRESS_SPACE;也可以分步法,逐步生成中间的.bit

4. 很有意思的RAM32可以用,虽然实际上我们使用的还是RAMB36(不过不用4位PARITY的)

 5. *.mem注意是使用intel格式(我们项目中用字地址),注意字地址和字节地址的关系转换,否则不正确

 

总之data2mem确实很不错很wonderful

点击此处查看原文 >>

系统分类: CPLD/FPGA   |    用户分类:    |    来源: 整理

评论(0) | 阅读(139)
发表于:2008-7-15 19:40:34
标签:VCCcore/GND,VCCIO/GND的选取方法参考  

1

VCCcore/GND,VCCIO/GND的选取方法参考

大家讨论下pad的问题吧

现在有一个项目,有很多pad,有analog 的,digit的
digit里又有clk的,又有平常普通的
还有很多Power pad,

我们要考虑IR drop, EM, 功耗,core的电流等问题

大家碰到这样一个项目,一般都是怎么考虑摆放的。。。。

一般考虑的步骤有哪几步的?

哪个大侠给点经验啊~~~~~
 
------------------------------------------------------------------------------------------
 
1)analog 的pad无论信号还是电源,都依照使用说明
2)数字IO按照性能和设计要求选择晶振,时钟,输入,输出,上拉,下拉,施密特触发等不同IO
3)按照IO的功耗,SSO(取大的)决定IO power IO的个数
4)按照core功耗,IR drop(取大的)决定core power IO 的个数
5)其他特殊要求的IO,(参考手册)
 
 
(1)和(2)或其他一些板级方面的要求是由analog或前端,PCB系统方面的的人提供的吧
(3)和(4)可以说的详细点吗?
       (3)   如果我们已知
               IO Type 2mA 4mA 8mA 12mA  16mA 24mA
                              DF Value 0.02 0.03 0.09 0.18     0.3    0.56   
                              然后该怎么确定IO power IO 的个数呢?
       (4)   譬如我们设定VSS+VDD的IR drop为5%,然后整个chip的功耗为1w,怎么确定core power IO的个数?
(5)pad处的EM呢?是到后面如果发现问题了,再手动加吗?

谢谢
---------------------------------------------------------------------------------
(3.1) 算出所有数字IO的总功耗, 除以每个IO power IO的最大供电限度,就是最少需要的IO power IO个数,最好再多加20%

(3.2) 按照下面的方法计算SSO.
比如你有20个4mA IO, 50个8mA IO, 那么SDF=20x0.03+50x0.09=5.1
到IO使用说明上的找SDF与要求IO power IO个数的系数,比如ground 是1.0, power 是1.1
那么需要ground IO 个数= SDFx1.0 = 5.1 --> 6个
power IO个数= SDFx1.1 = 5.1x1.1 = 5.6 --> 6个

比较(3.1)和(3.2)的结果,取大的就是(3)的结果

(4.1)整个chip的功耗除以每个core power IO的最大供电限度,就是最少需要的core power IO个数,最好再多加10%

(4.2)把上面算出的core power IO个数均匀地摆放,借助工具检查IR drop,如果不理想的话,再调整,最后得到需要的core power IO个数

比较(4.1)和(4.2)的结果,取大的就是(4)的结果

(1) (2) (5)的答案正确
 
--------------------------------------------------------------------------------------------
首先非常谢谢,受益非浅啊~~~

学着去试试,看具体还有什么问题的再问


对了,突然有个很白痴的问题想问:
只要放pad处有空间,core power IO我尽量多的加,这样的话IR drop可以尽量小了,我想只是最后bonding的时候把它们bond在一起就ok了啊

请问这样有什么问题的.....
 
------------------------------------------------------------------------------------
To:陈涛
(3.2)为什么出来的SDF还要乘以系数的?
            还有定义的DF值怎么来确定的?我想一些specific cell同时跳变的数量和具体的chip有关的,工艺厂怎么得到这个数据的?

To:skyscar
    "摆放的方式也很重要。"这个对EM和IR drop都有很大的影响吧,还是指其他意思的?

点击此处查看原文 >>

系统分类: 嵌入式   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(131)
发表于:2008-7-15 19:34:06
标签:C语言内存分配问题  

1

C语言内存分配问题

#1 楼主:C语言内存分配问题 精华帖

贴子发表于:2008-7-14 13:36:00

C语言内存分配问题

1、C中内存分为四个区
栈:用来存放函数的形参和函数内的局部变量。由编译器分配空间,在函数执行完后由编译器自动释放。
堆:用来存放由动态分配函数(如malloc)分配的空间。是由程序员自己手动分配的,并且必须由程序员使用free释放。如果忘记用free释放,会导致所分配的空间一直占着不放,导致内存泄露。
全局局:用来存放全局变量和静态变量。存在于程序的整个运行期间,是由编译器分配和释放的。
文字常量区:例如char *c = “123456”;则”123456”为文字常量,存放于文字常量区。也由编译器控制分配和释放。
程序代码区:用来存放程序的二进制代码。
例子(一)
int a = 0; //全局区
void main()
{
int b; //栈
char s[] = abc; //s在栈,abc在文字常量区
char *p1,*p2; //栈
char *p3 = 123456; //123456在常量区,p3在栈上
static int c =0; //全局区
p1 = (char *)malloc(10); //p1在栈,分配的10字节在堆
p2 = (char *)malloc(20); //p2在栈,分配的20字节在堆
strcpy(p1, 123456); //123456放在常量区
}
例子(二)
//返回char型指针
char *f()
{
//s数组存放于栈上
char s[4] = {'1','2','3','0'};
return s; //返回s数组的地址,但程序运行完s数组就被释放了
}
void main()
{
char *s;
s = f();
printf (%s, s); //打印出来乱码。因为s所指向地址已经没有数据
}
2、动态分配释放内存
用malloc动态分配内存后一定要判断一下分配是否成功,判断指针的值是否为NULL。
内存分配成功后要对内存单元进行初始化。
内存分配成功且初始化后使用时别越界了。
内存使用完后要用free(p)释放,注意,释放后,p的值是不会变的,仍然是一个地址值,仍然指向那块内存区,只是这块内存区的值变成垃圾了。为了防止后面继续使用这块内存,应在free(p)后,立即p=NULL,这样后面如果要使用,判断p是否为NULL时就会判断出来。


NO.1
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str,hello world);
printf(str);
}
请问运行Test函数后会是什么样的结果?
NO.2
char *GetMemory(void)
{
char p[] = hello world;
retrun p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
问题同NO.1
NO.3
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str,100);
strcpy(str,hello);
printf(str);
}
问题同NO.1
NO.4
void Test(void)
{
char *str = (char *)malloc(100);
strcpy(str,hello);
free(str);
if(str != NULL)
{
strcpy(str,world);
printf(str);
}
}
问题同NO.1
我对以上问题的分析:
NO.1:程序首先申请一个char类型的指针str,并把str指向NULL(即str里存的是NULL的地址,*str为NULL中的值为0),调用函数的过程中做了如下动作:1申请一个char 类型的指针p,2把str的内容copy到了p里(这是参数传递过程中系统所做的),3为p指针申请了100个空间,4返回Test函数.最后程序把字符串hello world拷贝到str指向的内存空间里.到这里错误出现了!str的空间始终为NULL而并没有实际的空间.深刻理解函数调用的第2步,将不难发现问题所在!(建议:画图理解)
NO.2:程序首先申请一个char类型的指针str,并把str指向NULL.调用函数的过程中做了如下动作:1申请一数组p[]并将其赋值为hello world(数组的空间大小为12),2返回数组名p付给str指针(即返回了数组的首地址).那么这样就可以打印出字符串"hello world"了么?当然是不能的!因为在函数调用的时候漏掉了最后一步.也就是在第2步return数组名后,函数调用还要进行一步操作,也就是释放内存空间.当一个函数被调用结束后它会释放掉它里面所有的变量所占用的空间.所以数组空间被释放掉了,也就是说str所指向的内容将不确定是什么东西.
NO.3:正确答案为可以打印出hello.但内存泄漏了!
NO.4:申请空间,拷贝字符串,释放空间.前三步操作都没有任何问题.到if语句里的判断条件开始出错了,因为一个指针被释放之后其内容并不是NULL,而是一个不确定的值.所以if语句永远都不能被执行.这也是著名的"野"指针问题.所以我们在编写程序释放一个指针之后一定要人为的将指针付成NULL.这样就会避免出现"野"指针的出现.有人说"野"指针很可怕,会带来意想不到的错误.

点击此处查看原文 >>

系统分类: 软件开发   |    用户分类:    |    来源: 转贴

评论(1) | 阅读(169)
发表于:2008-7-8 9:39:34
标签:ISE  Virtex-5使用  

1

Virtex-5 FPGA调试的一些记录

1.     在FPGA调试前,先做好把xilinx替换掉IC RTL的相关部分,并详细做好仿真,否则马上在FPGA上调试,效果效率都很糟糕

2.     注意`timescale的以致,一些生成的IP往往和自己设计的RTL不一致,modelsim发现仿真结果与期望不一,原因是`timescale的不一致导致

3.     针对xilinx的*.mif的生成:*.out   -->elf2hex -Mx *.mif-->ALT+C 再按住shift ,最前面memory_initialization_radix=2;memory_initialization_vector= ...然后","后面";"文件名改成*.coe-->coregenerator生成*.v *.ngc *.mif;[*.mif和*.coe的交叉处理,*.mif可用于软件仿真,*mif和*.ngc用于FPGA实现]

4.    Xilinx的Tcl研究,process run "",很好用,所有GUI的各个process均可以,只要按其名字写入即可

5.    Partition技术研究,默认是routing(保存的数据最多从synthesis--routed)和inherit(针对child module而言)

 

点击此处查看原文 >>

系统分类: CPLD/FPGA   |    用户分类:    |    来源: 原创

评论(0) | 阅读(116)
发表于:2008-6-20 16:51:29
标签:无标签

0

单片机系统的低功耗设计策略


单片机系统的低功耗设计策略
作者: 清华大学 陈萌萌 邵贝贝


摘要 嵌入式系统的低功耗设计需要全面分析各方面因素,统筹规划。在设计之初,各个因素往往是相互制约、相互影响的,一个降低系统功耗的措
施有时会带来其他方面的“负效应”。因此,降低系统整体功耗,需要仔细分析和计算。本文从硬件和应用软件设计两个方面,阐述一个以单片机为核
心的嵌入式系统低功耗设计时所需考虑的一些问题。


关键词 低功耗设计 硬件设计 应用软件设计 低功耗模式


  在嵌入式应用中,系统的功耗越来越受到人们的重视,这一点对于需要电池供电的便携式系统尤其明显。降低系统功耗,延长电池的寿命,就
是降低系统的运行成本。对于以单片机为核心的嵌入式应用,系统功耗的最小化需要从软、硬件设计两方面入手。
  随着越来越多的嵌入式应用使用了实时操作系统,如何在操作系统层面上降低系统功耗也成为一个值得关注的问题。限于篇幅,本文仅从硬件
设计和应用软件设计两个方面讨论。
1 硬件设计
  选用具有低功耗特性的单片机可以大大降低系统功耗。可以从供电电压、单片机内部结构设计、系统时钟设计和低功耗模式等几方面考察一款
单片机的低功耗特性。
1.1 选用尽量简单的CPU内核
  在选择CPU内核时切忌一味追求性能。8位机够用,就没有必要选用16位机,选择的原则应该是“够用就好”。现在单片机的运行速度越来越快,但
性能的提升往往带来功耗的增加。一个复杂的CPU集成度高、功能强,但片内晶体管多,总漏电流大,即使进入STOP状态,漏电流也变得不可忽
视;而简单的CPU内核不仅功耗低,成本也低。
1.2 选择低电压供电的系统
  降低单片机的供电电压可以有效地降低其功耗。当前,单片机从与TTL兼容的5 V供电降低到3.3 V、3 V、2 V乃至1.8 V供电。供电电压降下来,要
归功于半导体工艺的发展。从原来的3 μm工艺到现在的0.25、0.18、0.13 μm工艺, CMOS电路的门限电平阈值不断降低。低电压供电可以大大降低系
统的工作电流,但是由于晶体管的尺寸不断减小,管子的漏电流有增大的趋势,这也是对降低功耗不利的一个方面。
  目前,单片机系统的电源电压仍以5 V为主,而过去5年中,3 V供电的单片机系统数量增加了1倍,2 V供电的系统也在不断增加。再过五年,低电
压供电的单片机数量可能会超过5 V电压供电的单片机。如此看来,供电电压降低将是未来单片机发展的一个重要趋势。
1.3 选择带有低功耗模式的系统
  低功耗模式指的是系统的等待和停止模式。处于这类模式下的单片机功耗将大大小于运行模式下的功耗。过去传统的单片机,在运行模式下有
wait和stop两条指令,可以使单片机进入等待或停止状态,以达到省电的目的。
  等待模式下,CPU停止工作,但系统时钟并不停止,单片机的外围I/O模块也不停止工作;系统功耗一般降低有限,相当于工作模式的50%~
70%。

  停止模式下,系统时钟也将停止,由外部事件中断重新启动时钟系统时钟,进而唤醒CPU继续工作,CPU消耗电流可降到μA级。在停止模式
下,CPU本身实际上已经不消耗什么电流,要想进一步减小系统功耗,就要尽量将单片机的各个I/O模块关掉。随着I/O模块的逐个关闭,系统的功耗
越来越小,进入停止模式的深度也越来越深。进入深度停止模式无异于关机,这时的单片机耗电可以小于20 nA。其中特别要提示的是,片内RAM停
止供电后,RAM中存储的数据会丢失,也就是说,唤醒CPU后要重新对系统作初始化。因此在让系统进入深度停止状态前,要将重要系统参数保存在
非易失性存储器中,如EEPROM中。深度停止模式关掉了所有的I/O,可能的唤醒方式也很有限,一般只能是复位或IRQ中断等。
  保留的I/O模块越多,系统允许的唤醒中断源也就越多。单片机的功耗将根据保留唤醒方式的不同,降至1μA至几十μA之间。例如,用户可以保
留外部键盘中断,保留异步串行口(SCI)接收数据中断等来唤醒CPU。保留的唤醒方式越多,系统耗电也就会多一些。其他可能的唤醒方式还有实
时钟唤醒、看门狗唤醒等。停机状态较浅的情况下,外部晶振电路还是工作的。
  图1以Freescale的HCS08单片机为例,给出不同运行模式下的系统功耗。HCS08是8位单片机,有多个系列,各系列I/O模块数目有所不同,但低功
耗模式下的电流消耗大致相同。
图1 HCS08单片机各模式下的耗电
  以R系列单片机为例:在室温(25℃)下,不包括I/O口的负载,以2 V供电,将可编程锁相环时钟设为16 MHz(总线时钟8 MHz),典型电流值为
2.6 mA,当温度升高到85℃时,供电电流也升高到3.6 mA;而采用3 V供电,这一组数据升高至3.8 mA和4.8 mA。用2 V供电,直接使用外部晶振2 MHz
(总线时钟1 MHz)时,典型运行电流降至450 μA。在等待状态下,因时钟并没有停止,耗电情况和时钟频率有很大关系,节省的功耗有限;而进入
轻度停止(stop3),以外部中断唤醒,电流消耗在0. 5 μA左右。在中度停止态(stop2),功耗可进一步降低。使用内部1 kHz的时钟,保持1个运行的
时钟,周期性唤醒CPU,所增加的电流约为0.3 μA。在深度停止态(stop1),RAM的数据也不再保留,只能通过外部复位重启系统,此时的电流消耗
可降到20 nA。以上数据都是在室温下测量所得。当环境温度升高到85℃时,电流消耗可能增加3~5倍。
1.4 选择合适的时钟方案
  时钟的选择对于系统功耗相当敏感,设计者需要注意两个方面的问题:
  第一是系统总线频率应当尽量低。单片机内部的总电流消耗可分为两部分——运行电流和漏电流。理想的CMOS开关电路,在保持输出状态不变
时,是不消耗功率的。例如,典型的CMOS反相器电路,如图2所示,当输入端为零时,输出端为1,P晶体管导通,N晶体管截止,没有电流流过。而
实际上,由于N晶体管存在一定漏电流,且随集成度提高,管基越薄,漏电流会加大。温度升高,CMOS翻转阈电压会降低,而漏电流则随环境温度
的增高变大。在单片机运行时,开关电路不断由“1”变“0”、由“0”变“1”,消耗的功率是由单片机运行引起的,我们称之为“运行电流”。如图2所示,在两
只晶体管互相变换导通、截止状态时,由于两只管子的开关延迟时间不可能完全一致,在某一瞬间会有两只管子同时导通的情况,此时电源到地之
间会有一个瞬间较大的电流,这是单片机运行电流的主要来源。可以看出,运行电流几乎是和单片机的时钟频率成正比的,因此尽量降低系统时钟
的运行频率可以有效地降低系统功耗。

图2 典型的CMOS反相器
  第二是时钟方案,也就是是否使用锁相环、使用外部晶振还是内部晶振等问题。新一代的单片机,如飞思卡尔的HCS08系列单片机,片内带有内
部晶振,可以直接作为时钟源。使用片内晶振的优点是可以省掉片外晶振,降低系统的硬件成本;缺点是片内晶振的精度不高(误差一般在25%左
右,即使校准之后也可能有2%的相对误差),而且会增加系统的功耗。   现代单片机普遍采用锁相环技术,使单片机的时钟频率可由程序控制。
锁相环允许用户在片外使用频率较低的晶振,可以很大地减小板级噪声;而且,由于时钟频率可由程序控制,系统时钟可以在一个很宽的范围内调
整,总线频率往往能升得很高。但是,使用锁相环也会带来额外的功率消耗。
  单就时钟方案来讲,使用外部晶振且不使用锁相环是功率消耗最小的一种。
2 应用软件方面的考虑
  之所以使用“应用软件”的说法,是为了区分于“系统软件”或者“实时操作系统”。软件对于一个低功耗系统的重要性常常被人们忽略。一个重要的原
因是,软件上的缺陷并不像硬件那样容易发现,同时也没有一个严格的标准来判断一个软件的低功耗特性。尽管如此,设计者仍需尽量将应用的低
功耗特性反映在软件中,以避免那些“看不见”的功耗损失。
2.1 用“中断”代替“查询”
  一个程序使用中断方式还是查询方式对于一些简单的应用并不那么重要,但在其低功耗特性上却相去甚远。使用中断方式,CPU可以什么都不
做,甚至可以进入等待模式或停止模式;而查询方式下,CPU必须不停地访问I/O寄存器,这会带来很多额外的功耗。
2.2 用“宏”代替“子程序”
  程序员必须清楚,读RAM会比读Flash带来更大的功耗。正是因为如此,低功耗性能突出的ARM在CPU设计上仅允许一次子程序调用。因为CPU进
入子程序时,会首先将当前CPU寄存器推入堆栈(RAM),在离开时又将CPU寄存器弹出堆栈,这样至少带来两次对RAM的操作。因此,程序员可以
考虑用宏定义来代替子程序调用。对于程序员,调用一个子程序还是一个宏在程序写法上并没有什么不同,但宏会在编译时展开,CPU只是顺序执行
指令,避免了调用子程序。唯一的问题似乎是代码量的增加。目前,单片机的片内Flash越来越大,对于一些不在乎程序代码量大一些的应用,这种
做法无疑会降低系统的功耗。
2.3 尽量减少CPU的运算量
  减少CPU运算的工作可以从很多方面入手:将一些运算的结果预先算好,放在Flash中,用查表的方法替代实时的计算,减少CPU的运算工作量,
可以有效地降低CPU的功耗(很多单片机都有快速有效的查表指令和寻址方式,用以优化查表算法);不可避免的实时计算,算到精度够了就结束,
避免“过度”的计算;尽量使用短的数据类型,例如,尽量使用字符型的8位数据替代16位的整型数据,尽量使用分数运算而避免浮点数运算等。
2.4 让I/O模块间歇运行
  不用的I/O模块或间歇使用的I/O模块要及时关掉,以节省电能。RS232的驱动需要相当的功率,可以用单片机的一个I/O引脚来控制,在不需要通信
时,将驱动关掉。不用的I/O引脚要设置成输出或设置成输入,用上拉电阻拉高。因为如果引脚没有初始化,可能会增大单片机的漏电流。特别要注
意有些简单封装的单片机没有把个别I/O引脚引出来,对这些看不见的I/O引脚也不应忘记初始化。
3 结论
  一个成功的低功耗设计应该是硬件设计和软件设计的结合。从硬件设计开始,就应该充分意识到一个低功耗应用的特性,选择一款合适的单片
机,通过对其特性的了解,设计系统方案;在软件设计上,要考虑到低功耗编程的特殊性,并尽量使用单片机的低功耗模式。   限于篇幅,仅仅
讨论了低功耗设计中的一些常见问题,更多的问题只能靠设计者去实际分析和解决了。
参考文献

1 刘慧银,等. Motorola微控制器MC68HC08原理及其嵌入式应用,北京:清华大学出版社,2001
2 邵贝贝. 单片机嵌入式应用的在线开发方法. 北京:清华大学出版社,2004
3 Donnie Garcia, Scott Pape. MC9S08GB/GT Low?Power Modes. Freescale Semiconductor, Rev2. 2004
4 MC9S08GB/GT Data Sheet. Freescale Semiconductor, Rev.2.2, 2004
5 HCS08 Family Reference Manual. Freescale Semiconductor, 2003
6 Scott Pape. HC08 to HCS08 Transition. Freescale Semiconductor, 2004
7 Bill Lucas, Scott Pape. Configuring the System and Peripheral Clocks in the MC9S08GB/GT. Freescale Semiconductor, 2003
8 Scott Pape. S08 in Low Power Devices. Freescale Technology Forum, 2005
(收稿日期:2005-09-26)
[返回上页] [关闭本页] [打印本页]
CopyRight ? 2006 《单片机与嵌入式系统应用》杂志社 webmaster@mesnet.com.cn
编辑部:(010)82338009 广告部:(010)82313656/82317029 网络部:(010)82317043 传真:(010)82317043
投稿专用: paper@mesnet.com.cn 广告专用: adv@mesnet.com.cn
每月1日出版 国际标准16开本 每期定价:8元 国内统一刊号CN 11-4530/V 国际标准刊号ISSN 1009-623X 邮发代号:2-765
pdf

点击此处查看原文 >>

系统分类: 嵌入式   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(114)
发表于:2008-6-20 16:23:57
标签:上电复位  

1

80C51上电复位和复位延时的时序分析


80C51上电复位和复位延时的时序分析
作者:河北通信职业技术学院 李学海   机械科学研究院 刘治山
            师慧公司 宋庆国
  80C51单片机的上电复位POR(Power On Reset)实质上就是上电延时复位,也就是在上电延时期间把单片机锁定在复位状态上。为什么在每次单
片机接通电源时,都需要加入一定的延迟时间呢?分析如下。
1 上电复位时序
  在单片机及其应用电路每次上电的过程中,由于电源回路中通常存在一些容量大小不等的滤波电容,使得单片机芯片在其电源引脚VCC和VSS之
间所感受到的电源电压值VDD,是从低到高逐渐上升的。该过程所持续的时间一般为1~100 ms(记作taddrise)。上电延时taddrise的定义是电源电压从
10% VDD上升到90% VDD所需的时间,如图1所示。
图1 上电延时taddrise和起振延时tosc实测结果
  在单片机电源电压上升到适合内部振荡电路运行的范围并且稳定下来之后,时钟振荡器开始了启动过程(具体包括偏置、起振、锁定和稳定几
个过程)。该过程所持续的时间一般为1~50 ms(记作tosc)。起振延时tosc的定义是时钟振荡器输出信号的高电平达到Vih1所需的时间。从图1所示的
实际测量图中也可以看得很清楚。这里的Vih1是单片机电气特性中的一个普通参数,代表XTAL1和RST引脚上的输入逻辑高电平。例如,对于常见的单
片机型号AT89C51和AT89S51,厂家给出的Vih1值为0.7VDD~VDD+0.5 V。
  从理论上讲,单片机每次上电复位所需的最短延时应该不小于treset。这里,treset等于上电延时taddrise与起振延时tosc之和,如图1所示。从实际
上讲,延迟一个treset往往还不够,不能够保障单片机有一个良好的工作开端。
  在单片机每次初始加电时,首先投入工作的功能部件是复位电路。复位电路把单片机锁定在复位状态上并且维持一个延时(记作TRST),以便
给予电源电压从上升到稳定的一个等待时间;在电源电压稳定之后,再插入一个延时,给予时钟振荡器从起振到稳定的一个等待时间;在单片机开
始进入运行状态之前,还要至少推迟2个机器周期的延时,如图2所示。

图2 复位信号释放的时机
2 上电复位电路3款
  上述一系列的延时,都是利用在单片机RST引脚上外接一个RC支路的充电时间而形成的。典型复位电路如图3(a)所示,其中的阻容值是原始手
册中提供的。在经历了一系列延时之后,单片机才开始按照时钟源的工作频率,进入到正常的程序运行状态。从图2所示的实测曲线中可以同时看到
4条曲线: VDD、Vrst、XTAL2和ALE。在电源电压以及振荡器输出信号稳定之后,又等待了一段较长的延时才释放RST信号,使得CPU脱离复位锁定状
态;而RST信号一旦被释放,立刻在ALE引脚上就可检测到持续的脉冲信号。
图3 上电复位延时电路
  由于标准80C51的复位逻辑相对简单,复位源只有RST一个(相对新型单片机来说,复位源比较单一),因此各种原因所导致的复位活动以及复
位状态的进入,都要依靠在外接引脚RST上施加一定时间宽度的高电平信号来实现。
  标准80C51不仅复位源比较单一,而且还没有设计内部上电复位的延时功能,因此必须借助于外接阻容支路来增加延时环节,如图3(a)所示。其
实,外接电阻R还是可以省略的,理由是一些CMOS单片机芯片内部存在一个现成的下拉电阻Rrst。例如,AT89系列的Rrst阻值约为50~200 kΩ;
P89V51Rx2系列的Rrst阻值约为40~225 kΩ,如图4所示。因此,在图3(a)基础上,上电复位延时电路还可以精简为图3(b)所示的简化电路(其中电容C的
容量也相应减小了)。
图4 复位引脚RST内部电路
  在每次单片机断电之后,须使延时电容C上的电荷立刻放掉,以便为随后可能在很短的时间内再次加电作好准备。否则,在断电后C还没有充分
放电的情况下,如果很快又加电,那么RC支路就失去了它应有的延迟功能。因此,在图3(a)的基础上添加一个放电二极管D,上电复位延时电路就变

成了如图3(c)所示的改进电路。也就是说,只有RC支路的充电过程对电路是有用的,放电过程不仅无用,而且会带来潜在的危害。于是附加一个放电
二极管D来大力缩短放电持续时间,以便消除隐患。二极管D只有在单片机断电的瞬间(即VCC趋近于0 V,可以看作VCC对地短路)正向导通,平时
一直处于反偏截止状态。
3 上电复位失败的2种案例分析
  假如上电复位延迟时间不够或者根本没有延时过程,则单片机可能面临以下2种危险,从而导致CPU开始执行程序时没有一个良好的初始化,甚
至陷入错乱状态。
① 在时钟振荡器输出的时钟脉冲还没有稳定,甚至还没有起振之前,就因释放RST信号的锁定状态而放纵CPU开始执行程序。这将会导致程序计数器
PC中首次抓取的地址码很可能是0000H之外的随机值,进而引导CPU陷入混乱状态。参考图5所示的实测信号曲线。
图5 在时钟未稳定前释放RST的情况
② 在电源电压还没有上升到合适范围之前(自然也是时钟尚未稳定之前),就释放RST信号的锁定状态,将会使单片机永远感受不到复位信号、经
历不到复位过程、包含PC在内的各个SFR内容没有被初始化而保留了随机值,从而导致CPU从一个随机地址开始执行程序,进而也陷入混乱状态。参
考图6所示的实测信号曲线。
图6 在电源和时钟均未稳定前释放RST的情况
4 外接监控器MAX810x
  为了提高单片机应用系统的稳定性,以及保障单片机应用系统的可靠复位,许多世界著名的半导体公司,陆续推出了种类繁多、功能各异、封
装微小的专用集成电路。本文仅以带有电源电压跌落复位和上电延迟复位功能的3脚芯片MAX810x为例,简单说明。
  MAX810x(x = L、M、J、T、S或R)是美国Maxim公司研制的一组CMOS电源监控电路,能够为低功耗微控制器MCU(或μC)、微处理器MPU(或μP)
或数字系统监视3~5 V的电源电压。在电源上电、断电和跌落期间产生脉宽不低于140 ms的复位脉冲。与采用分立元件或通用芯片构成的欠压检测电
路相比,将电压检测和复位延时等功能集成到一片3引脚封装的小芯片内,大大降低了系统电路的复杂性,减少了元器件的数量,显著提高了系统可
靠性和精确度。应用电路如图7所示。

图7 外接带延时功能的电压检测复位电路
  MAX810x系列产品提供高电平复位信号,并且还能提供6种固定的检测门限(4.63 V、4.38 V、4.00 V、3.08 V、2.93 V和2.63 V)。例如,MAX810M的检测
门限电压就是4.38 V,回差电压约为0.16 V。
  对于MAX810,在电源上电、断电或跌落期间,只要VCC还高于1.1 V,就能保证RESET引脚输出高电压。在VCC上升期间RESET维持高电平,直到
电源电压升至复位门限以上。在超过此门限后,内部定时器大约再维持240 ms后释放RESET,使其返回低电平。无论何时只要电源电压降低到复位门
限以下(即电源跌落),RESET引脚就会立刻变高。
  关于MAX810芯片的更多信息,可以参考该器件的产品手册。
参考文献
[1] 李学海. PIC单片机实用教程——基础篇/扩展篇. 北京: 北京航空航天大学出版社,2002.
[2] 李学海. EM78单片机实用教程——基础篇/扩展篇. 北京: 电子工业出版社,2003.
[3] 李学海. 凌阳8位单片机——基础篇/提高篇. 北京: 北京航空航天大学出版社,2005.
[4] 李学海. PIC单片机原理. 北京: 北京航空航天大学出版社,2004.
[5] 李学海. PIC单片机实践. 北京: 北京航空航天大学出版社,2004.
(收稿日期:2006-08-21)
[返回上页] [关闭本页] [打印本页]
CopyRight ? 2006 《单片机与嵌入式系统应用》杂志社 webmaster@mesnet.com.cn
编辑部:(010)82338009 广告部:(010)82313656/82317029 网络部:(010)82317043 传真:(010)82317043
投稿专用: paper@mesnet.com.cn 广告专用: adv@mesnet.com.cn
每月1日出版 国际标准16开本 每期定价:8元 国内统一刊号CN 11-4530/V 国际标准刊号ISSN 1009-623X 邮发代号:2-765
http://www.mesnet.com.cn/htm/magazine_view.asp?id=2109(第 4/4 页)2008-6-20 16:15:23pdf

点击此处查看原文 >>

系统分类: ARM   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(189)
发表于:2008-6-13 9:20:14
标签:存储器  

1

ROM、RAM、DRAM、SRAM、FLASH的区别?

ROMRAM指的都是半导体存储器,ROM是Read Only Memory的缩写,RAM是Random Access Memory的缩写。ROM在系统停止供电
的时候仍然可以保持数据,而RAM通常都是在掉电之后就丢失数据,典型的RAM就是计算机的内存。


RAM有两大类,一种称为静态RAM(Static RAM/SRAM),SRAM速度非常快,是目前读写最快的存储设备了,但是它也非常昂贵,所以只在要求很苛刻的地方使用,譬如CPU的一级缓冲,二级缓冲。另一种称为动态RAM(Dynamic RAM/DRAM),DRAM保留数据的时间很短,速度也比SRAM慢,不过它还是比任何的ROM都要快,但从价格上来说DRAM相比SRAM要便宜很多,计算机内存就是DRAM的。

DRAM分为很多种,常见的主要有FPRAM/FastPage、EDORAM、SDRAM、DDR RAM、RDRAM、SGRAM以及WRAM等,这里介绍其中的一种DDR RAM。DDR RAM(Date-Rate RAM)也称作DDR SDRAM,这种改进型的RAM和SDRAM是基本一样的,不同之处在于它可以在一个时钟读写两次数据,这样就使得数据传输速度加倍了。这是目前电脑中用得最多的内存,而且它有着成本优势,事实上击败了Intel的另外一种内存标准-Rambus DRAM。在很多高端的显卡上,也配备了高速DDR RAM来提高带宽,这可以大幅度提高3D加速卡的像素渲染能力。

ROM也有很多种,PROM是可编程的ROM,PROM和EPROM(可擦除可编程ROM)两者区别是,PROM是一次性的,也就是软件灌入后,就无法修改了,这种是早期的产品,现在已经不可能使用了,而EPROM是通过紫外光的照射擦出原先的程序,是一种通用的存储器。另外一种EEPROM是通过电子擦出,价格很高,写入时间很长,写入很慢。

举个例子,手机软件一般放在EEPROM中,我们打电话,有些最后拨打的号码,暂时是存在SRAM中的,不是马上写入通过记录(通话记录保存在EEPROM中),因为当时有很重要工作(通话)要做,如果写入,漫长的等待是让用户忍无可忍的。FLASH存储器又称闪存,它结合了ROM和RAM的长处,不仅具备电子可擦出可编程(EEPROM)的性能,还不会断电丢失数据同时可以快速读取数据(NVRAM的优势),U盘和MP3里用的就是这种存储器。在过去的20年里,嵌入式系统一直使用ROM(EPROM)作为它们的存储设备,然而近年来Flash全面代替了ROM(EPROM)在嵌入式系统中的地位,用作存储bootloader以及操作系统或者程序代码或者直接当硬盘使用(U盘)。

目前Flash主要有两种NOR Flash和NADN Flash。NOR Flash的读取和我们常见的SDRAM的读取是一样,用户可以直接运行装载在NOR FLASH里面的代码,这样可以减少SRAM的容量从而节约了成本。NAND Flash没有采取内存的随机读取技术,它的读取是以一次读取一快的形式来进行的,通常是一次读取512个字节,采用这种技术的Flash比较廉价。用户不能直接运行NAND Flash上的代码,因此好多使用NAND Flash的开发板除了使用NAND Flah以外,还作上了一块小的NOR Flash来运行启动代码。

一般小容量的用NOR Flash,因为其读取速度快,多用来存储操作系统等重要信息,而大容量的用NAND FLASH,最常见的NAND FLASH应用是嵌入式系统采用的DOC(Disk On Chip)和我们通常用的“闪盘”,可以在线擦除。目前市面上的FLASH 主要来自Intel,AMD,Fujitsu和Toshiba,而生产NAND Flash的主要厂家有Samsung和Toshiba。

点击此处查看原文 >>

系统分类: 嵌入式   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(174)
发表于:2008-5-21 13:45:17
标签:C语言  内存使用  

1

正确使用内存

一般来说,内存的分配方式有三种:
  
  1.从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整
个运行期间都存在。例如全局变量,static变量。
  
  2.在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数
执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很
高,但是分配的内存容量有限。

  3.从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的
内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使
用非常灵活,但问题也最多。
  
  以上三种分配方式,我们要注意内存生命期的问题:
  
  1.静态分配的区域的生命期是整个软件运行期,就是说从软件运行开始到软件终止退
出。只有软件终止运行后,这块内存才会被系统回收 
  
  2.在栈中分配的空间的生命期与这个变量所在的函数和类相关。如果是函数中定义的
局部变量,那么它的生命期就是函数被调用时,如果函数运行结束,那么这块内存就会被回
收。如果是类中的成员变量,则它的生命期与类实例的生命期相同
  
  3.在堆上分配的内存,生命期是从调用new或者malloc开始,到调用delete或者free结
束。如果不掉用delete或者free。则这块空间必须到软件运行结束后才能被系统回收。

  下面我们再看看,在使用内存的过程中,我们经常发生一些什么样的错误。以及我们应
该采取哪些对策。
    
  发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序运行
时才能捕捉到。而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。有时用户
怒气冲冲地把你找来,程序却没有发生任何问题,你一走,错误又发作了。
  
  常见的内存错误及其对策如下:
  
  1 内存分配未成功,却使用了它。
  
  编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在
使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用
assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if
(p!=NULL)进行防错处理。
  
  2 内存分配虽然成功,但是尚未初始化就引用它。
  
  犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为
零,导致引用初值错误(例如数组)。
  
  内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无
不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,
不要嫌麻烦。
  
  3 内存分配成功并且已经初始化,但操作越过了内存的边界。
  
  例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句
中,循环次数很容易搞错,导致数组操作越界。
  
  4 忘记了释放内存,造成内存泄露。
  
  含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不
到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。
  
  动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯
定有错误(new/delete同理)。
  
  5 释放了内存却继续使用它。
  
  有三种情况:
  
  (1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了
内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。
  
  (2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引
用”,因为该内存在函数体结束时被自动销毁。

点击此处查看原文 >>

系统分类: 软件开发   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(170)
总共 , 当前 /