keil c代码空间怎么指定分配,栈检测,常量代码数组指定存放地址?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了keil c代码空间怎么指定分配,栈检测,常量代码数组指定存放地址?相关的知识,希望对你有一定的参考价值。

1、keil c怎么检测栈的合法性?
我看了一下startup.a51,里面的spi是从0x21开始的,在data区,最大的空间地址不能超过0x80,因为0x80是SFR地址了。
所以我想看一下我的栈用了多少?怎么样查看?

2、代码空间分配。
假如我写了一段代码
void fun1()

....

我想指定fun1存在0x2000开始的地方,应该怎么样来指定呢?

3、我要限定一组函数必须存在0x2000 - 0x3000区间里面,如果编译出来的代码超过这个空间,就报错,没有就放在这里面!
4、我写一个数组
unsigned char code buff[N] = "code";
我想这个放在0x2000L地址上,怎么样来处理?

哪里位高手告诉我一下。谢谢!

参考技术A 在定义之后增加关键字 _at_ ,例如:
unsigned char code buf[]="a123456" _at_ 0x2000;
zhu注意空格追问

_at_ 的绝对变量 是不能够初始化的。

Keil编译过程及程序在Flash和SRAM的空间分配

1. keil编译介绍

  当使用keil进行单片机的开发时,运行一段程序后,在output输出框会看到如下图的结果。技术图片

图1 keil 的output框

  其中,Compiler编译器,使用的版本是 V5.06,程序会先经过编译、后链接linking生成可执行的代码,如果要下载单片机的Flash上,还需要转换成二进制(bin)或者十六进制(hex)的文件。具体过程如下:

技术图片

 

图2 keil的编译过程

  值得注意的是,经过编译后,并不会给变量赋地址生(.o文件),只有经过链接器链接后变量才有地址,链接的作用可以看做是便于管理。经链接后代码分为Code、RO-data、RW-data、ZI-data四部分。接下来是老生常谈的问题,每个区都是干嘛的呢?

 

  • CODE:代码区,指程序中代码即函数体的大小,注意程序中未使用的函数也会算在CODE中,也即会占用FLASH空间,因此不用的函数最好删除掉,以免占用过多FLASH空间;
  • RO-DATA:RO就是只读的意思,程序中只读的变量(也就是带Const的)和已初始化的字符串等;
  • RW-DATA:特指已初始化的可读可写全局/静态变量;
  • ZI-DATA:未初始化的可读可写全局/静态变量,注意初始化为0也算做未初始化,用到的堆空间和栈空间也会被算入这里面;

  之前我一直在想的一个问题是我的局部变量存放在哪里,其实是这样的,局部变量只有在程序运行的过程中才会生成,当程序不运行,即将关闭单片机的电源后,是没有局部变量的。所以这就要涉及到程序的两种状态存储态和运行态。

技术图片

图3 程序的存储态和运行态

 

存储态:向Flash中下载程序时,其实仅仅下载的是CODE+RO-data+RW-data的内容,意思就是说,在掉电情况下,Flash里面的内存仅包含CODE+RO-data+RW-data这三块。

运行态:当上电后,程序运行时,首先程序会从特定的地址进行启动,启动时会将RW-data的数据加载到SRAM中(启用文件中有一段代码是干这件事的,keil已经帮你做完了这件事),单片机的 RO区域不需要加载到 SRAM,内核直接从 FLASH 读取指令运行。那ZI-data的数据怎么办呢?对于初始值为0全局变量来说,因为要在Code区要调用该全局变量,所以肯定要对其进行描述,程序运行时就知道了,原来你是初始值为0的全局变量呀,然后就在SRAM区给你分配了一段固定区域的地址;对于局部变量来说, 会自动分配大小,不用我们管。不禁要问了,ZI-data啥用也没有呀,它其实是有统计作用的,并且SRAM中一段特定的区域是运行ZI-data数据,RW-DATA+ZI-DATA就是程序运行总共会占用SRAM的长度,生成局部变量的栈空间包含在ZI-data区的范围

技术图片

 

图4 程序的组成

  计算机系统的应用程序运行过程很类似,不过计算机系统的程序在存储状态时位于硬盘,执行的时候甚至会把上述的 RO 区域(代码、只读数据)加载到内存,加快运行速度,还有虚拟内存管理单元(MMU)辅助加载数据,使得可以运行比物理内存还大的应用程序,因为单片中 没有MMU,所以无法支持 Linux Windows 系统,这里我说的单片是指M系列的单片机,但是可以跑ucos或FreeRTOS系统。

2. Flash和Sram的理解

  存储器是计算机结构的重要组成部分,存储器是用来存储程序代码和数据的部件,有了存储器计算机才具有记忆功能。按照存储介质的特性,可以分“易失性存储器”和“非易失性存储器”两类,易失和非易失是指存储器断电后,里面存储的内容是否会丢失,另一边的速度而言呢,易失性存储器的速度要快于非易失性存储器。

 技术图片

 

 

2.1 易失性存储器

  按照RAM的物理存储机制,可以分为DRAM(Dynamic)和SRAM(Static)两类。首先,说一下目前所用的DRAM,其通讯时序是利用时钟进行同步通讯,所以起名为Synchronous DRAM,那么,后期为了进一步提高SDRAM的通讯速度,人们设计了DDR SDRAM存储器(Double Data Rate SDRAM),随后又发展出二、三、四代SDRAM,现在很多PC机上的内存条是DDRIII SDRAM存储器。另外,静态随机存储器SRAM的存储单元以锁存器来存储数据,结构比DRAM要复杂很多,所以生产相同容量的存储器,DRAM的成本要更低,且集成度更高。
技术图片

 

 

2.2 非易失性存储器

  半导体类的非易失性存储器有ROM和FLASH,感觉现在ROM使用的比较少了,貌似很多都被flash代替了。之前学单片机的时候,用的外接EEPROM算是一种ROM,不作过多介绍。FLASH的容量一般比EEPROM大得多,且在擦除时,一般以多个字节为单位。如有的FLASH存储器以4096个字节为扇区,最小的擦除单位为一个扇区。根据存储单元电路的不同,FLASH存储器又分为NOR FLASH和NAND FLASH。
技术图片

  NOR与NAND的共性是在数据写入前都需要有擦除操作,而擦除操作一般是以“扇区/块”为单位,而NOR与NAND特性的差别,主要是其内部“地址/数据线”是否分开导致的。

  • 由于NOR的地址线和数据线分开,它可以按“字节”读写数据,符合CPU的指令译码执行要求,所以假如NOR上存储了代码指令,CPU给NOR一个地址,NOR就能向CPU返回一个数据让CPU执行,中间不需要额外的处理操作。所以,在功能上可以认为NOR是一种断电后数据不丢失的RAM,但它的擦除单位与RAM有区别,且读写速度比RAM要慢得多。
  • 由于NAND的数据和地址线共用,只能按“块”来读写数据,假如NAND上存储了代码指令,CPU给NAND地址后,它无法直接返回该地址的数据,所以不符合指令译码要求。若代码存储在NAND上,可以把它先加载到RAM存储器上,再由CPU执行。

  目前,单片机SOC内部普遍使用的是SRAM和NorFlash。

 

  Flash,SRAM寄存器和输入输出端口被组织在同一个4GB的线性地址空间内,可访问的存储器空间被分成8个主要块,每个块为512MB。存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射,如果给存储器再分配一个地址就叫存储器重映射。NRF52832的内存映射如下图所示,

技术图片

  在nordic芯片中FLASH存储编译后下载的程序,SRAM是存储在程序运行中的临时创建数据(ARMv7,哈弗结构),故只要你不外扩存储器,写完的程序中只要在芯片上运行起来,所有数据也就会出现在这两个存储器中。Flsah或者Ram内部又会根据不同的功能把他们分为多个模块。

  在网上看到一张图,感觉很有意思。这张图是STM32程序下载到Flash上的存储结构。如果你知道了这些具体地址,及地址块的作用,就可以做BootLoader以便产品后期升级。

技术图片

参考网址:https://www.cnblogs.com/amanlikethis/p/3719529.html

 

以上是关于keil c代码空间怎么指定分配,栈检测,常量代码数组指定存放地址?的主要内容,如果未能解决你的问题,请参考以下文章

码海拾遗:内存四区

程序内存地址的分配

c程序hex文件在用keil2编译生成新的hex文件怎么不一样了

new/delete

new/delete

详解栈区堆区全局区文字常量区程序代码区