这些问题,都起源于最近在用STM32f103RBT6做了几次FFT后,需定义多个很大的数组,导致报错,显示No Space类似的错误... 百度后有说用如下方法。
法1:魔术棒—>C/C++—>Optimization,这个好像是可以优化代码,级数越高优化的越厉害。试了试有一定作用,但是不持久。
法2:更改此处的IROM1和IRAM1,可是咱也不懂咋改呀,也不敢随便乱改呀。
没达到效果。然后开始深度百度...
片内Flash与片内RAM,RAM相当于内存,Flash相当于硬盘。
①code:代码段,存放程序的所有代码
②RO:只读数据段,存放程序中定义的常量
③RW:读写数据段,存放初始化为非0值的全局变量
④ZI:零数据段,存放未初始化的全局变量,以及初始化为0的变量。
FLASH=Code + RO-data + RW-data =(14588+428+32)/1024=14.70KB
RAM=RW-data + ZI-data =32+20264=20.296KB
FLASH=Code + RO-data + RW-data =(14588+428+32)/1024=14.70KB
RAM=RW-data + ZI-data =32+20264=20.296KB
FLASH=Code + RO-data + RW-data =(14588+428+32)/1024=14.70KB
RAM=RW-data + ZI-data =32+20264=20.296KB
然后再看STM32f103RBT6的flash和SRAM,flash没问题,但是已经超了SRAM。
ROM:0x8000000+0x1F400byte,所以数据存储从0x8000000——>0x801F400都是安全的。
RAM:0x20000000+0x4E20byte,所以数据存储从0x20000000——>0x20004E20都是安全的。
计算一下我此时KEIL中的IROM和IRAM。此时的芯片的STM32F103RBT6,FLASH是128KB,RAM是20KB。
ROM中的SIZE是30000=30K 此时flash 代码14K
RAM中的SIZE是7000=7K 此时RAM代码是 20K
1G=1024M 1M=1024K 1K(B)=1024Byte(字节) 1Byte=8bit(位)
16位系统中:1字=2字节(byte)=16bit
32位系统中:1字=4字节(byte)=32bit
64位系统中:1字=8字节(byte)=64bit
计算机中,一个地址,代表一个字节(1Byte)
比如:地址0x0000 0000就占一个字节,
地址0x0000 0001也占一个字节,
地址0x0000 0002也占一个字节,
。。。
地址0x0000 000F也占一个字节,
也就是说: 0x0000 0000 - 0x0000 000F总共有16个地址,占16个字节。
备注:十六进制1位 = 二进制4位,计算机只能识别二进制:1101 0101这种,所以要换算成二进制计算
STM32在上电后,默认从flash启动,之后将RW段中的RW-data(初始化不为零的全局变量)搬运到RAM中,(因为自身定义的值不能改变)但不会搬运RO-data段,(因为都是初始化为0或者没赋值,不需要管它的值是多少)。
即CPU的执行代码从flash中读取,另外根据编译器给出的ZI地址和大小分配出ZI段,并将这块RAM区域清零。
其中动态内存堆为未使用的 RAM 空间,应用程序申请和释放的内存块都来自该空间。
详细分析请参考:https://bbs.elecfans.com/jishu_1404990_1_3.html
如下面的例子;
rt_uint8_t* msg_ptr;
msg_ptr = (rt_uint8_t*) rt_malloc (128); //msg_ptr 指针指向的 128 字节内存空间位于动态内存堆空间中。
rt_memset(msg_ptr, 0, 128);
代码中的 msg_ptr 指针指向的 128 字节内存空间位于动态内存堆空间中。
而一些全局变量则是存放于 RW 段和 ZI 段中,
RW 段存放的是具有初始值的全局变量(而常量形式的全局变量则放置在 RO 段中,是只读属性的),ZI 段存放的系统未初始化的全局变量,如下面的例子:
#include
const static rt_uint32_t sensor_enable = 0x000000FE; //sensor_enable 存放在 RO 段中
rt_uint32_t sensor_value; //sensor_value 存放在 ZI 段中,系统启动后会自动初始化成零(由用户程序或编译器提供的一些库函数初始化成零)
rt_bool_t sensor_inited = RT_FALSE; //sensor_inited 变量则存放在 RW 段中
void sensor_init()
{
/* ... */
}
sensor_value 存放在 ZI 段中,系统启动后会自动初始化成零(由用户程序或编译器提供的一些库函数初始化成零)。sensor_inited 变量则存放在 RW 段中,而 sensor_enable 存放在 RO 段中。
ROM是存固化程序的,RAM是存数据的。
FLASH ROM比普通的ROM读写速度快,擦写方便,一般用来存储用户程序和需要永久保存的数据。
代码中采集到的没必要永久存储的数据,就放在RAM中,需要永久保存的数据,就需要存放到FLASH里。
ROM:存放指令代码和一些固定数值,程序运行后不可改动。
凡是c文件及h文件中所有代码、全局变量、局部变量、’const’限定符定义的常量数据、startup.asm文件中的代码(类似ARM中的bootloader或者X86中的BIOS,一些低端的单片机是没有这个的)通通都存储在ROM中。
RAM:用于程序运行中数据的随机存取,掉电后数据消失。
凡是整个程序中,所用到的需要被改写的量,都存储在RAM中,“被改变的量”包括全局变量、局部变量、堆栈段。
程序经过编译、汇编、链接后,生成hex文件。用专用的烧录软件,通过烧录器将hex文件烧录到ROM中,这个时候的ROM中,包含所有的程序内容:无论是一行一行的程序代码,函数中用到的局部变量,头文件中所声明的全局变量,const声明的只读常量,都被生成了二进制数据,包含在hex文件中,全部烧录到了ROM里面,此时的ROM,包含了程序的所有信息,正是由于这些信息,“指导”了CPU的所有动作。
可能有人会有疑问,既然所有的数据在ROM中,那RAM中的数据从哪里来?什么时候CPU将数据加载到RAM中?
回答这个问题,首先必须明确一条:ROM是只读存储器,CPU只能从里面读数据,而不能往里面写数据,掉电后数据依然保存在存储器中;
RAM是随机存储器,CPU既可以从里面读出数据,又可以往里面写入数据,掉电后数据不保存,这是条永恒的真理,始终记挂在心。
RAM中的数据不是在烧录的时候写入的,同时也说明,在CPU运行时,RAM中已经写入了数据。关键就在这里:这个数据不是人为写入的,CPU写入的,那CPU又是什么时候写入的呢?
这里所做的工作是为整个程序的顺利运行做好准备,或者说是对RAM的初始化(注:ROM是只读不写的),工作任务有几项:
1、为全局变量分配地址空间---如果全局变量已赋初值,则将初始值从ROM中拷贝到RAM中,如果没有赋初值,则这个全局变量所对应的地址下的初值为0或者是不确定的。当然,如果已经指定了变量的地址空间,则直接定位到对应的地址就行,那么这里分配地址及定位地址的任务由“连接器”完成。
2、设置堆栈段的长度及地址---用C语言开发的单片机程序里面,普遍都没有涉及到堆栈段长度的设置,但这不意味着不用设置。堆栈段主要是用来在中断处理时起“保存现场”及“现场还原”的作用,其重要性不言而喻。而这么重要的内容,也包含在了编译器预设的内容里面,确实省事,可并不一定省心。
3、分配数据段data,常量段const,代码段code的起始地址。代码段与常量段的地址可以不管,它们都是固定在ROM里面的,无论它们怎么排列,都不会对程序产生影响。但是数据段的地址就必须得关心。数据段的数据时要从ROM拷贝到RAM中去的,而在RAM中,既有数据段data,也有堆栈段stack,还有通用的工作寄存器组。通常,工作寄存器组的地址是固定的,这就要求在绝对定址数据段时,不能使数据段覆盖所有的工作寄存器组的地址。必须引起严重关注。
通常的做法是:普通的flashMCU是在上电时或复位时,c指针里面的存放的是“0000”,表示CPU从ROM的0000地址开始执行指令,在该地址处放一条跳转指令,使程序跳转到_main函数中,然后根据不同的指令,一条一条的执行,当中断发生时(中断数量也很有限,2~5个中断),按照系统分配的中断向量表地址,在中断向量里面,放置一条跳转到中断服务程序的指令,如此如此,整个程序就跑起来了。决定CPU这样做,是这种ROM结构所造成的。