OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 32899|回复: 28

MDK下外扩SRAM指定地址分配空间问题(内存管理详解!!)

[复制链接]

4

主题

125

帖子

1

精华

高级会员

Rank: 4

积分
870
金钱
870
注册时间
2014-8-7
在线时间
49 小时
发表于 2014-9-23 09:10:50 | 显示全部楼层 |阅读模式
5金钱
各位大神,请问外扩SRAM中按照
 uint8_t TxBuffer[2048] __attribute__((at(0X68000000)));
 uint8_t data[2048] __attribute__((at(0X68000000)));...
来定义数组,可是编译后总是出现
..\OBJ\test.axf: Error: L6982E: AT section test.o(.ARM.__AT_0x68000000) with base 0x68000000 limit 0x68001864 overlaps address range with AT section malloc.o(.ARM.__AT_0x68000000) with base 0x68000000 limit 0x68032000.
..\OBJ\test.axf: Error: L6982E: AT section synaptics.o(.ARM.__AT_0x68000000) with base 0x68000000 limit 0x68002760 overlaps address range with AT section malloc.o(.ARM.__AT_0x68000000) with base 0x68000000 limit 0x68032000.
这种情况。我找了很多帖子都没有遇到这种情况的,是不是我的程序写错了呢,还是地址分配我没注意。
对了,使用外部SRAM还有一种是使用编译器定义的,在外部初始化FSMC该怎么操作呢?

最佳答案

查看完整内容[请看2#楼]

                                                                    ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

125

帖子

1

精华

高级会员

Rank: 4

积分
870
金钱
870
注册时间
2014-8-7
在线时间
49 小时
 楼主| 发表于 2014-9-23 09:10:51 | 显示全部楼层

                                                                           基于STM32原子战舰板内存管理源码详解 ( 本文是基于原子哥的c源码 )
  
     1, 内存管理简介
    内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。内存管理的实现方法有很多种,他们其实最终都是要实现2个函数:malloc和free;malloc函数用于内存申请,free函数用于内存释放。
    先回顾一下c语言知识:计算机内存一般分为静态存储区用以存储全局变量或常量和动态存储区用以存储函数内部变量或形参或函数运算结果。malloc()函数的作用是请求系统在内存的动态存储区分配若干个字节的存储空间,函数的返回值是首字节地址,可见malloc()函数是指针类型。free(P)的作用是释放指针变量P所指向的动态空间。
    本章,我们介绍一种比较简单的办法来实现:分块式内存管理。下面我们介绍一下该方法的实现原理,如图所示(示意图):
 内存块1 内存块2 内存块3 ……内存块n     内存池
    |       |       |          |
 第1项   第2项   第3项   ……第n项       内存管理表
                        <<-----分配方向
                                 |
                        malloc,free等函数
    图解:从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成。内存池被等分为n块,对应的内存管理表,大小也为n,内存管理表的每一个项对应内存池的一块内存。
    内存管理表的项值代表的意义为:当该项值为0的时候,代表对应的内存块未被占用,当该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。比如某项值为10,那么说明包括本项对应的内存块在内,总共分配了10个内存块给外部的某个指针。
 内寸分配方向如图所示,是从顶à底的分配方向。即首先从最末端开始找空内存。当内存管理刚初始化的时候,内存表全部清零,表示没有任何内存块被占用。
 
分配原理:
    当指针p调用malloc申请内存的时候,先判断p要分配的内存块数(m),然后从第n项开始,向下查找,直到找到m块连续的空内存块(即对应内存管理表项为0),然后将这m个内存管理表项的值都设置为m(标记被用),最后,把最后的这个空内存块的地址返回指针p,完成一次分配。注意,如果当内存不够的时候(找到最后也没找到连续的m块空闲内存),则返回NULL(空指针)给p,表示分配失败。
 
释放原理:
    当p申请的内存用完,需要释放的时候,调用free函数实现。free函数先判断p指向的内存地址所对应的内存块,然后找到对应的内存管理表项目,得到p所占用的内存块数目m(内存管理表项目的值就是所分配内存块的数目),将这m个内存管理表项目的值都清零,标记释放,完成一次内存释放。
 关于分块式内存管理的原理,我们就介绍到这里。
 
2, 硬件设计:
 本章实验功能简介:开机后,显示提示信息,等待外部输入。KEY0用于申请内存,每次申请2K字节内存。KEY1用于写数据到申请到的内存里面。KEY2用于释放内存。WK_UP用于切换操作内存区(内部内存/外部内存)。DS0用于指示程序运行状态。本章我们还可以通过USMART调试,测试内存管理函数。
 本实验用到的硬件资源有:
 1) 指示灯DS0
 2) 四个按键
 3) 串口  //USMART
 4) TFTLCD模块
 5) IS62WV51216
 
3, 软件设计:
    本章,我们将内存管理部分单独做一个分组,在工程目录下新建一个MALLOC的文件夹,然后新建malloc.c和malloc.h两个文件,将他们保存在MALLOC文件夹下。在MDK新建一个MALLOC的组,然后将malloc.c文件加入到该组,并将MALLOC文件夹添加到头文件包含路径。打开malloc.c文件,输入如下代码:由于本实验涉及到的c语言知识,尤其是指针知识较多,所以就边用边学。
 #include "malloc.h"   
//内存池(4字节对齐)
 __align(4) u8 mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池
 /*
 " u8 mem1base[MEM1_MAX_SIZE];"该数组是定义拿出内部内存池的40K的空间来做实验,为什么该数组是u8类型?计算机内存是以字节为单位的存储空间,内存中的每个字节都有唯一的编号,这个编号就叫地址。在这里就是定义40K个元素,每个元素代表一个字节。整个数组就代表整个内部SRAM内存池的总容量即40K个元字节的总空间容量。因为不管是存储什么数据类型内存中的地址编号都是32位的,即每个地址编号可以容纳4个字节,而不同的数据类型存储在不同的内存存储区,这就是为什么定义变量时一定要先声明其数据类型的原因。存储一个字符需要一个字节的存储空间,存储一个short类型需要2个字节的存储空间,存储一个int或float需要4个字节空间,就如同PLC内存中的字节,字,双字的定义规则一样(如字节MB0,MB1,MB0和MB1构成MW0;MW0和MW2构成32位的双字DW0,DW4,DW8)。“__align(4)”就是规定4个字节对齐,即每个32的地址编号存储一个数据类型?比如,字符存储区中地址编号MB0可以存储一个字节即8个位的数据,而存储MB0这个地址编号是以32位的空间来存储,也就是说不管是什么类型数据,存储它的地址编号都是32的,所以指针值一定是32位的。

 //“#define MEM1_MAX_SIZE 40*1024  //最大管理内存 40K”,意思是mem1base[MEM1_MAX_SIZE]有40k个元素
 */
 __align(4) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000)));//外部SRAM内存池
 //#define MEM2_MAX_SIZE  200*1024  //最大管理内存200K,意思是mem2base[MEM2_MAX_SIZE]数组有200K个u8类型元素,第一个元素的地址存储在 //外部存储器SRAM的0X68000000地址,
 //内存管理表
 u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; //内部SRAM内存池MAP
 /*
 //#define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //内存表大小,MEM1_MAX_SIZE/MEM1_BLOCK_SIZE==1250
 //#define MEM1_BLOCK_SIZE 32  //内存块大小为32字节;“MEM1_MAX_SIZE/MEM1_BLOCK_SIZE ”的含义是内部SRAM内存池总共40K字节的容量除以32个字节,得到一共40K/32==1250个内存块;也就是说将内部SRAM内存池划为1250个内存块。
 “u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE];”实际上就等于“u16 mem1mapbase[1250];”意思是定义一个有1250个内存块(元素)的数组,每个元素是u16类型数据;数组名“mem1mapbase”就是mem1mapbase[0](该数组的第一个元素它代表1250个内存块中的第一个内存块)的地址,也可以说是指针常量;结合与之关联的结构体成员“u16 *memmap[2]={ mem1mapbase,mem2mapbase}”指针类型数组;在这里“mem2mapbase”是外部内存的第一个内存块的地址,是个指针常量用以存放u16类型数据的地址值;结合
 “mymemset(mallco_dev.memmap[0], 0,memtblsize[0]*2);”函数分析:结合本程序和结构体有关定义“u16 *memmap[2]; ”,首元素memmap[0]=mem1mapbase;也就是说“mallco_dev.memmap[0]”在这里表示1250个内部内存块中第一个内存块的地址,根据“u16 *memmap[2]={ mem1mapbase,mem2mapbase}”推断出“mallco_dev.memmap[0]”是u16类型指针;
 “memtblsize[0]”是什么意思呢?根据“const u32 memtblsize[2]={1250,6250};”可以得知memtblsize[0]==1250即内部内存一共有1250个管理项,
 void mymemset(void *s,u8 c,u32 count) 

    u8 *xs = s; 
    while(count--)*xs++=c; 
} //把u8类型数据c填充到以指针变量s为首地址的内存空间中,填充多少个数由count值决定
 
该函数的意思是把u8类型的数据“c”填充到u16类型指针元素memmap[0]中(根据结构体定义“u16 *memmap[2]; ”,而memmap[0]=mem1mapbase),说白了就是把u8类型的数据“c”填充到1250个内存块中的count个内存块中。
 而mallco_dev.memmap[memx]是16位的,为了将其全部清零,所以乘以2.
 本例中,用到了指针类型数组“u16 *memmap[2]={ mem1mapbase,mem2mapbase}”,为什么要定义指针类型数组呢?mem1mapbase是数组
 “u16 mem1mapbase[1250];”的首个元素地址(即*mem1mapbase等价于mem1mapbase[0]),而mem1mapbase[0]就代表内部存储器1250个存储块中的第一个存储块;根据结构体赋值定义可知:memmap[0]=mem1mapbase。所以mem1mapbase就是“mallco_dev.memmap[0]”,即mem1mapbase是函数mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2)的第一个形参,因为*mem1mapbase等价于mem1mapbase[0]),而mem1mapbase[0]就代表内部存储器1250个存储块中的第一个存储块。结合
 void mymemset(void *s,u8 c,u32 count)函数分析, mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2)函数的意思是:把0写入到1250个存储块中的第一个存储块中;这样就将一个存储块的值赋值为0了。
推断出“mallco_dev.memmap[0]”是u16类型指针;
 ;
 */
 u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE)));
 /*
 “#define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE”
“#define MEM2_BLOCK_SIZE 32”
 外部SRAM内存池MAP,同理,“MEM2_MAX_SIZE/MEM2_BLOCK_SIZE”的含义是外部SRAM内存池总共200K字节的容量除以32个字节,得到一共200K/32==6250个内存块;也就是说将外部SRAM内存池划为6250个内存块。
 */
 //内存管理参数  
/*
 内存管理表“MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE”分别是1250和6250个“项”.
 每个内存分块大小即内部和外部SRAM每个内存块占有32个字节空间“MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE”分别是32个字节;
 内存总大小“MEM1_MAX_SIZE,MEM2_MAX_SIZE”,分别是40K和200K个字节的总容量空间
 mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);
 */
 const u32 memtblsize[2]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE};//内存管理表大小
 const u32 memblksize[2]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE}; //内存分块大小
 const u32 memsize[2]={MEM1_MAX_SIZE,MEM2_MAX_SIZE}; //内存总大小
 /*
 struct _m_mallco_dev  //内存管理控制器,定义一个结构体类型数据,或结构体变量,
 {
 void (*init)(u8); //初始化
 u8 (*perused)(u8); //内存使用率
 u8  *membase[2]; //内存池 管理2个区域的内存   mem1base,mem2base内存池
 u16 *memmap[2]; //内存管理状态表  mem1mapbase(==1250块),mem2mapbase(6250), //内存管理状态表
 u8  memrdy[2]; //内存管理是否就绪
 };
 1,结构体成员“void (*init)(u8);”是定义了一个指向函数的指针变量,该指针变量名是init;void表示该函数没有返回值(函数的数据类型由返回值决定);u8是函数的形参。指向函数的指针变量格式:数据类型 + (*变量名)(形参)
 本例中:
 void mem_init(u8 memx) 

    mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零  memx:所属内存块,即几号内存块
     mymemset(mallco_dev.membase[memx], 0,memsize[memx]); //内存池所有数据清零 
    mallco_dev.memrdy[memx]=1;//内存管理初始化OK 

    也就是说,本例中用指向函数的指针变量来表示函数。c语言规定函数名就是函数的入口地址,也就是说函数名也是一个指针,指向函数的入口,根据这个原理,可以将指向函数的指针作为函数的参数调用,可以在不同的情况调用不同的函数;如果一个指向函数的指针变量等于函数名就可以说该指向函数的指针变量指向了该函数,那么指针变量与函数就是一样的了。比如:“mem_init(memx);”就等同于“mallco_dev.init(memx);”
 2,指针类型数组“u8  *membase[2];”,意思是该指针类型数组有两个“char *”类型的指针元素或者说有两个“u8 *”类型指针元素;为什么要定义“u8 *”类型呢?因为内存存储区是根据数据类型来划分的,如果不明确声明类型就乱套了。
 在C语言和C++语言中,数组元素全为指针的数组称为指针数组。一维指针数组的定义形式为:“类型名 *数组标识符[数组长度]”。
 例如,一个一维指针数组的定义:int *ptr_array[10]。该指针数组有10个元素,每个元素都是int类型的指针即“int *”类型;
 指针类型数组“u8  *membase[2];”的赋值是mem1base,mem2base, “mem1base,mem2base”分别是内部内存池和外部内存池的数组名,是指针常量即首元素的地址;因为事先已经定义“u8 mem1base[MEM1_MAX_SIZE]”即“u8 mem1base[40K];”。
 */
 //内存管理控制器,结构体变量赋值,即初始化
 struct _m_mallco_dev mallco_dev=
 {
 mem_init, //内存初始化,将函数名“mem_init”赋给结构体成员“void (*init)(u8);”即指向函数的指针变量,
 mem_perused, //内存使用率
 mem1base,mem2base, //内存池
 mem1mapbase,mem2mapbase, //内存管理状态表,mem1mapbase(1250项),mem2mapbase(6250项)
 0,0,   //内存管理未就绪
 };
 /*
 1,“void *des”无类型指针,不能指向具体的数据,“void *des”无类型指针指向内存中的数据类型由用户自己确定,如malloc()函数的返回值就是“void *des”无类型指针,因为malloc()函数的返回值是不确定的是根据形参的数据类型确定的
 2,“void mymemcpy(void *des,void *src,u32 n) ”函数的理解:
 des是指针,但是不确定指向什么类型的数据,换句话说des指针存储的什么类型数据不确定,“u8 *xdes=des;”将des指针存储的数据
 存储到一个新的“u8 *”类型指针xdes中;“u8 *xsrc=src;”同理。
 “*xdes++=*xsrc++; ”,当*xsrc++(自增)时,即指针“src”指针自增,也就是说把“src”指针逐位复制到des目标指针去了。复制个数就是n。
 3,“*P”的意义:a),“*P”就是以指针变量P的内容(P的内容就是指针变量P里存储的某一类型数据的指针值)为地址的变量;b),指针运算符“*”如果是在定义变量时候加在前面,意思是这个变量是指针变量,如 char *a;如果是在访问指针变量的时候加在前面(如*a),意思是取指针变量指向的值,如 char b=*a; 上面定义了a是一个字符指针,这里就是把指针变量a指向的值取出来并赋给b。
*/
 //复制内存,作用是将源地址的内容复制到目标地址
 //*des:目的地址
 //*src:源地址
 //n:需要复制的内存长度(字节为单位)
 void mymemcpy(void *des,void *src,u32 n) 
{  //“void *des”无类型指针,不能指向具体的数据,“void *des”无类型指针指向内存中的数据类型由用户自己确定
     u8 *xdes=des;//目标地址,“*xdes”转换成u8类型,也可以理解为把目的地地址des存储到xdes指针中
 u8 *xsrc=src;
    while(n--)*xdes++=*xsrc++; 

//设置内存
 //*s:内存首地址
 //c :要设置的值
 //count:需要设置的内存大小(字节为单位)
 void mymemset(void *s,u8 c,u32 count) 

    u8 *xs = s; 
    while(count--)*xs++=c; 
} //以*s为内存首地址的count个字节中,填充c,即把c写入到*s为首地址的内存中,个数多少由count值决定
  
//内存管理初始化 
//memx:所属内存块,要么SRAMEX==1(外部内存);要么SRAMIN(内部内存)==0
 /*
 const u32 memtblsize[2]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE};//内存管理表大小
 const u32 memblksize[2]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE}; //内存分块大小
 const u32 memsize[2]={MEM1_MAX_SIZE,MEM2_MAX_SIZE}; //内存总大小
 
*/
 void mem_init(u8 memx) //如“mem_init(SRAMIN);”表示内部内存块
 {  //memmap,是16位的,mymemset,设置是针对8位的,那么1个16位的数据是不是2个8位组成的啊?!
    mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零 
//把u8类型的数据“0”填充到u16类型指针元素memmap[0]中(根据结构体定义“u16 *memmap[2]; ”),memmap[0]=mem1mapbase==1250,
 //也就是说“mallco_dev.memmap[memx]”在这里表示1250个内部内存块用以存储u16类型指针,
//“memtblsize[memx]”是什么呢?memtblsize[memx]即memtblsize[0]==1250个内部内存管理表,
//而mallco_dev.memmap[memx]是16位的,为了将其全部清零,所以乘以2.
     mymemset(mallco_dev.membase[memx], 0,memsize[memx]); //内存池所有数据清零 
//memsize[0]==40K字节空间, mallco_dev.membase[memx]==40K字节空间,
 mallco_dev.memrdy[memx]=1; //内存管理初始化OK 
}
 /*
 
 */ 
//获取内存使用率
 //memx:所属内存块,要么SRAMEX==1(外部内存);要么SRAMIN(内部内存)==0
 //返回值:使用率(0~100)
 u8 mem_perused(u8 memx) 

    u32 used=0; 
    u32 i; 
    for(i=0;i<memtblsize[memx];i++) 
    { 
        if(mallco_dev.memmap[memx])used++;
    } //mallco_dev.memmap[memx]是二维数组。当内存块初始化后该值为0,
     return (used*100)/(memtblsize[memx]);  //used*100,乘以100是将小数变成整数
 } 
//内存分配(内部调用)
 //memx:所属内存块
 //size:要分配的内存大小(字节数)
 //返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
//向memx存储器申请size个字节的连续存储空间,并将size个字节中首个字节的地址偏移值标注出来,注意是地址偏移值而不是地址。
 u32 mem_malloc(u8 memx,u32 size) 

    signed long offset=0; 
    u16 nmemb; //需要的内存块数 
u16 cmemb=0;//连续空内存块数
     u32 i; 
    if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先执行初始化
    /*
       “mallco_dev.init(memx);”是什么意思?mallco_dev.init(memx)是结构体变量mallco_dev的一个成员,本句中就是对结构体成员的引用,即执行
        mem_init(u8 memx)函数的意思;如何引用结构体中指向函数的指针变量成员?既然是指向函数的指针变量且有赋值,在引用时按照格式:
        结构体变量名.指向函数的指针变量名(形参);
     */
    if(size==0)return 0XFFFFFFFF;//不需要分配 memblksize[memx]==32
     nmemb=size/memblksize[memx];   //获取需要分配的连续内存块数
    /*
         c语言规定:除法的运算结果与运算对象的数据类型有关,两个数都是int则商(即结果)是int,若商(即结果)有小数则省略掉小数点部分。本例中
         size和memblksize[memx]都是int,所以结果只能是int。假设size<32,则nmemb==0;
        c语言规定取余运算的运算对象必须是int。当小数对大数取余时余(即结果)是小数本身;例如,在“if(size%memblksize[memx])nmemb++;”中 ,
        假设size<32,则size%memblksize[memx]的结果是size值本身,所以执行“nmemb++;”运算,这时运算结果是nmemb==1;如果size是32的整数倍则不执行   
       “nmemb++;”运算;
        memtblsize[0]==1250,memtblsize[1]==6250,
        mallco_dev.memmap[memx][offset]是什么意思?
     */
    if(size%memblksize[memx])nmemb++; 
    for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区 
    {    
if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加,offset从1249->0变化
 /*
          如,{ memmap[0][149],memmap[0][148],...memmap[0][1],memmap[0][0]};实际上可以把“mallco_dev.memmap[memx][offset]”视为具有1250个变量的一维数组,每个元素对应的实际意义是对应的一个内存块,顺序是offset从1249(高)->0(低)变化;如果哪个变量等于0(即空闲)就执行 “cmemb++;”操作,这样就可以计算出连续空闲内存块数cmemb;切记!目的是要获取连续的空闲的内存块数!这样就必须结合下一句 “else cmemb=0;”来分析;如果没有出现连续的空闲内存块(即数组顺序相连的变量值没有出现类似“0,0,0,0,0”这样的情况),程序会执行下一语  句“else cmemb=0;”即把上面的“cmemb”统计值清零,这样程序就会在for循环里面继续寻找符合“if(cmemb==nmemb)”条件的状态出现,如果for循环执行完了还没有出现符合“if(cmemb==nmemb)”条件的状态,则返回0XFFFFFFFF结束本函数表示没有找到符合条件的内存块。假设:size=65,那么nmemb就是3即需要获取连续3个内存块来存放65个字节,再假设数组顺序相连的变量值出现了类似“0,0,0,0,0”这样的情况(即有连续4个空闲的内存块),这时就出现了符合“if(cmemb==nmemb)”条件的状态,即当cmemb计数计到3的时候(即出现了连续相连的3个内存块)就符合“cmemb==nmemb”了,程序就自然进入“if(cmemb==nmemb)”语句。offset*memblksize[memx]代表什么呢?offset的取值范围是0-1249,memblksize[memx]代表每个内存块的字节数即32,offset*memblksize[memx]就是返回偏移地址值;也就是把连续空闲的内存块对应的地址的首地址值标注出来。
       */   
         else cmemb=0; //连续内存块清零
 if(cmemb==nmemb) //找到了连续nmemb个空内存块
 {
             for(i=0;i<nmemb;i++)   //标注内存块非空,以免下一个for循环时再次将该空间计入
            { 
                mallco_dev.memmap[memx][offset+i]=nmemb; 
            } 
            return (offset*memblksize[memx]);//返回偏移地址 
}
     } 
    return 0XFFFFFFFF;//未找到符合分配条件的内存块 

//释放内存(内部调用)
//memx:所属内存块
 //offset:内存地址偏移
 //返回值:0,释放成功;1,释放失败; 
u8 mem_free(u8 memx,u32 offset) 

    int i; 
    if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化
 {
 mallco_dev.init(memx); //本句等价于“mem_init(memx);”  
        return 1;//未初始化 
    } 
    if(offset<memsize[memx])//以免偏移在内存池内. memsize[memx]==40K字节
     { 
        int index=offset/memblksize[memx]; //偏移所在内存块号码  memblksize[memx]==32,
         int nmemb=mallco_dev.memmap[memx][index]; //内存块数量
         for(i=0;i<nmemb;i++)   //内存块清零
         { 
            mallco_dev.memmap[memx][index+i]=0; 
        } 
        return 0; 
    }else return 2;//偏移超区了. 

//释放内存(外部调用)
//memx:所属内存块
 //ptr:内存首地址
void myfree(u8 memx,void *ptr) 

u32 offset; 
    if(ptr==NULL)return;//地址为0. 
  offset=(u32)ptr-(u32)mallco_dev.membase[memx]; 
    mem_free(memx,offset);//释放内存    

//分配内存(外部调用)
 //memx:所属内存块
 //size:内存大小(字节)
 //返回值:分配到的内存首地址.
 //在memx存储器中,找出size个字节的连续空闲的内存空间,并将连续空闲的内存空间指针值标注出来;返回值就是这个指针值
 /*
 mallco_dev.membase[memx]即mallco_dev.membase[0]代表MCU内部存储器的40K字节中的第一个字节变量的地址,是u8类型指针变量,也就是说一个字节占用一个地址;换句话说,把内部存储器的40K字节的地址定义为一个“u8 mem1base[MEM1_MAX_SIZE]”数组,指针类型数组“u8  *membase[2];”的赋值是{mem1base,mem2base},而“mem1base,mem2base”分别是内部内存池和外部内存池的数组名,各自首元素的地址亦是个指针常量;因为事先已经定义
 “u8 mem1base[MEM1_MAX_SIZE]”即“u8 mem1base[40K];”。如何理解“(void*)((u32)mallco_dev.membase[memx]+offset); ”呢?
 1),已经说过mallco_dev.membase[memx]是首个变量的地址即40k字节中首个字节的地址值;
 2),“offset”是:向memx存储器申请size个字节的连续空闲存储空间,这个找到的连续空闲空间当中首个字节的地址偏移值就是offset,offset==32(将32个字节空间组成一个内存块)*内存块号(如,假设向内部存储器申请64个字节的连续空闲存储空间,通过“mem_malloc(memx,size); ”函数得到在第五个存储块开始有连续2个存储快空闲可供使用(假设是5号和4号存储快),因为每个存储快有32个字节即有32个地址编号,4*32==128(这里的4是指第四块),5*32==160(这里的5是指第五块),那么这个160就是40K个字节编号当中的地址偏移值offset,即128-192号就是第四块和第五块内存块所对应的指针编号);注意offset是地址偏移值而不是地址;为什么要引入地址偏移值这个概念呢?假设第一个字节的地址值是0x0000 6800,那么就知道(0x0000 6800+160)的值就是第五块内存的指针。
 3),“(u32)mallco_dev.membase[memx]”代表指针类型数组,意义是内部存储器40K字节中的第一个字节变量的地址,原来存放的是u8类型数据的地址,现在强制类型转换扩展为u32类型;
 4),(void*)((u32)mallco_dev.membase[memx]+offset); 转换为无类型指针,指针值是32位,由此可知,“void *mymalloc(u8 memx,u32 size)”函数的返回值就是一个指针,即形参size所指向的由高向低的首个指针值;“void *mymalloc(u8 memx,u32 size)”是个指针类型函数,只能赋给指针。
 */
 void *mymalloc(u8 memx,u32 size) //p=mymalloc(sramx,2048)

    u32 offset;       
offset=mem_malloc(memx,size);      
    if(offset==0XFFFFFFFF)return NULL; 
    else return (void*)((u32)mallco_dev.membase[memx]+offset); 

//重新分配内存(外部调用)
 //memx:所属内存块
 //*ptr:旧内存首地址
 //size:要分配的内存大小(字节)
 //返回值:新分配到的内存首地址.
 void *myrealloc(u8 memx,void *ptr,u32 size) 

    u32 offset; 
    offset=mem_malloc(memx,size); 
    if(offset==0XFFFFFFFF)return NULL;    
    else 
    {    
   mymemcpy((void*)((u32)mallco_dev.membase[memx]+offset),ptr,size); //拷贝旧内存内容到新内存  
     // 把size个字节指针ptr复制到“((u32)mallco_dev.membase[memx]+offset)”, 
        myfree(memx,ptr);  //释放旧内存,因为在mem_malloc(memx,size)中已经将连续空闲内存块标注为1(已被占用),清除掉原来的标记
         return (void*)((u32)mallco_dev.membase[memx]+offset);  //返回新内存首地址,无类型指针
     } 
}
 
头文件:
 #ifndef __MALLOC_H
 #define __MALLOC_H
 
typedef unsigned long  u32;
 typedef unsigned short u16;
 typedef unsigned char  u8; 
#ifndef NULL
 #define NULL 0
 #endif
 
#define SRAMIN 0 //内部内存池
 #define SRAMEX  1 //外部内存池
 

//mem1内存参数设定.mem1完全处于内部SRAM里面
 #define MEM1_BLOCK_SIZE 32    //内存块大小为32字节
 #define MEM1_MAX_SIZE 40*1024  //最大管理内存 40K
 #define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //内存表大小
 
//mem2内存参数设定.mem2的内存池处于外部SRAM里面,其他的处于内部SRAM里面
 #define MEM2_BLOCK_SIZE 32    //内存块大小为32字节
 #define MEM2_MAX_SIZE    200*1024  //最大管理内存200K
 #define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //内存表大小
 
 
 struct _m_mallco_dev  //内存管理控制器
 {
 void (*init)(u8); //初始化
 u8 (*perused)(u8); //内存使用率
 u8 *membase[2]; //内存池 管理2个区域的内存
 u16 *memmap[2]; //内存管理状态表
 u8  memrdy[2]; //内存管理是否就绪
 };
 extern struct _m_mallco_dev mallco_dev; //在mallco.c里面定义,定义全局变量,结构体变量mallco_dev
 
void mymemset(void *s,u8 c,u32 count); //设置内存
 void mymemcpy(void *des,void *src,u32 n);//复制内存    
void mem_init(u8 memx); //内存管理初始化函数(外/内部调用)
 u32 mem_malloc(u8 memx,u32 size); //内存分配(内部调用)
 u8 mem_free(u8 memx,u32 offset); //内存释放(内部调用)
 u8 mem_perused(u8 memx); //获得内存使用率(外/内部调用)
////////////////////////////////////////////////////////////////////////////////
 //用户调用函数
 void myfree(u8 memx,void *ptr);   //内存释放(外部调用)
 void *mymalloc(u8 memx,u32 size); //内存分配(外部调用)
 void *myrealloc(u8 memx,void *ptr,u32 size);//重新分配内存(外部调用)
 #endif
    这部分代码,定义了很多关键数据,比如内存块大小的定义:MEM1_BLOCK_SIZE和MEM2_BLOCK_SIZE,都是32字节。内存池总大小,内部为40K,外部为200K(最大支持到近1M字节,不过为了方便演示,这里只管理200K内存)。MEM1_ALLOC_TABLE_SIZE和MEM2_ALLOC_TABLE_SIZE,则分别代表内存池1和2的内存管理表大小。
 从这里可以看出,如果内存分块越小,那么内存管理表就越大,当分块为2字节1个块的时候,内存管理表就和内存池一样大了(管理表的每项都是u16类型)。显然是不合适的,我们这里取32字节,比例为1:16,内存管理表相对就比较小了。
 主函数部分:
 int main(void)
 {
 u8 key; 
  u8 i=0;   
u8 *p=0;
 u8 *tp=0;
 u8 paddr[18]; //存放的内容“P Addr:+p地址的ASCII值”
 u8 sramx=0; //默认为内部sram
  
  Stm32_Clock_Init(9); //系统时钟设置
 uart_init(72,9600); //串口初始化为9600
 delay_init(72);   //延时初始化
led_init();   //初始化与LED连接的硬件接口
 LCD_Init();   //初始化LCD
 usmart_dev.init(72); //初始化USMART
   Key_Init(); //按键初始化 
  FSMC_SRAM_Init(); //初始化外部SRAM,因为用到了外部sram
 mem_init(SRAMIN); //初始化内部内存池,SRAMIN==0
 mem_init(SRAMEX); //初始化外部内存池,SRAMEX==1
   
  POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,200,16,16,"WarShip STM32");
 LCD_ShowString(60,70,200,16,16,"MALLOC TEST");
 LCD_ShowString(60,90,200,16,16,"WANG YAN");
 LCD_ShowString(60,110,200,16,16,"2013/12/16"); 
LCD_ShowString(60,130,200,16,16,"key_right:Malloc  key_left:Free");
 LCD_ShowString(60,150,200,16,16,"wake_up:SRAMx key_down:Read");
 
  POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(60,170,200,16,16,"SRAMIN");
 LCD_ShowString(60,190,200,16,16,"SRAMIN USED:   %");
 LCD_ShowString(60,210,200,16,16,"SRAMEX USED:   %");
 
  while(1)
 {
 key=Key_Scan(0);//不支持连按
 switch(key)
 {
 case 0://没有按键按下
 break;
 case key_right: //KEY0按下
 p=mymalloc(sramx,2048);//申请2K字节,即64个内存块的空间
 if(p!=NULL)sprintf((char*)p,"Memory Malloc Test%03d",i);//向p写入一些内容
 break;
             case key_down: //KEY1按下  
if(p!=NULL) //NULL==0;
 {
 sprintf((char*)p,"Memory Malloc Test%03d",i);//更新显示内容 
// LCD_ShowString(60,270,200,16,16,p);
                       LCD_ShowString(60,250,200,16,16,p);//显示P的内容
 printf("Memory Malloc Test%03d\n",i);//将“Memory Malloc Test”用串口输出,利用串口助手可以看到输出的结果
 //"03"表示参数“i”的值只显示3位,%-输出控制符;d-将“i”以十进制的形式输出;i的范围0--255;输出参数可以是多个,可以参考郝斌老师的相关视频;
 //输出控制符包含:%Ld--L代表long类型;%c--代表字符类型;:%X--代表16进制并大写;
                   }
 break;
 case key_left: //KEY2按下 
myfree(sramx,p);//释放内存
 p=0; //指向空地址
 break;
 case wake_up: //KEY UP按下
  sramx=!sramx;//切换当前malloc/free操作对象
 if(sramx)LCD_ShowString(60,170,200,16,16,"SRAMEX");
 else LCD_ShowString(60,170,200,16,16,"SRAMIN");
 break;
 }
 if(tp!=p)
 {//在内存paddr值处显示:“P Addr:0X%08X”,“0X%08X”以大写16进制显示参数tp(32位),“08”表示8位数。0X AAAA AAAA
           //刚进入程序时,因为执行了“mem_init(SRAMIN);”初始化函数,所以p==0;所以LCD不会有显示
 //因为程序一开始就有“u8 *tp=0;”,所以若不按下任何按键LCD就不会显示下面的内容(即“if(tp!=p)”控制的显示内容);
              tp=p;//PAddr显示的是指针p本身的地址值;指针值是u32类型
 sprintf((char*)paddr,"P Addr:0X%08X",(u32)tp);//将指针p本身的地址值在LCD上打印出来即显示
 LCD_ShowString(60,230,200,16,16,paddr); //显示p的地址
    if(p)
              LCD_ShowString(60,250,200,16,16,p);//显示P的内容,即指针p内存储的数据“Memory Malloc Test%03d”
    else LCD_Fill(60,250,239,266,WHITE); //p=0,清除显示
 }
 delay_ms(10);  
i++;
 if((i%20)==0)//DS0闪烁.
 {
 LCD_ShowNum(60+96,190,mem_perused(SRAMIN),3,16);//显示内部内存使用率
 LCD_ShowNum(60+96,210,mem_perused(SRAMEX),3,16);//显示外部内存使用率
   led0=!led0;
   }
 }  
}
 总结:通过内存管理的学习,更加深刻的领会到指针是c语言的灵魂,对c语言的知识是一个巩固和提高;同时也学习到了sprintf()函数的运用技巧。
 
  本章希望利用USMART调试内存管理,所以在USMART里面添加了mymalloc和myfree两个函数,用于测试内存分配和内存释放。大家可以通过USMART自行测试。
 
4,下载验证:
     在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32开发板上,得到原子哥文档里面的图片所示。
     可以看到,内外内存的使用率均为0%,说明还没有任何内存被使用,此时我们按下KEY0,就可以看到内部内存被使用5%(每按下一次申请2K的空间,lcd上显示的使用率递增5%;20*2K==40K)了,同时看到下面提示了指针p所指向的地址(其实就是被分配到的内存地址)和内容。多按几次KEY0,可以看到内存使用率持续上升(注意对比p的值,可以发现是递减的,说明是从顶部开始分配内存!),此时如果按下KEY2,可以发现内存使用率降低了5%,但是再按KEY2将不再降低,说明“内存泄露”了。这就是前面提到的对一个指针多次申请内存,而之前申请的内存又没释放,导致的“内存泄露”。按KEY_UP按键,可以切换当前操作内存(内部内存/外部内存),KEY1键用于更新p的内容,更新后的内容将重新显示在LCD模块上面。
   

回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2014-9-23 10:37:44 | 显示全部楼层
你这两个地址打架了,你只出现一个地址试试。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

4

主题

125

帖子

1

精华

高级会员

Rank: 4

积分
870
金钱
870
注册时间
2014-8-7
在线时间
49 小时
 楼主| 发表于 2014-9-23 11:40:15 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
地址换了,把数组大小*4再加到分配到地址。
在例程中实验通过了,但是转到我的程序中就打架了。~~~~(>_<)~~~~
回复

使用道具 举报

4

主题

125

帖子

1

精华

高级会员

Rank: 4

积分
870
金钱
870
注册时间
2014-8-7
在线时间
49 小时
 楼主| 发表于 2014-9-23 11:42:57 | 显示全部楼层
回复【2楼】 正点原子 :
---------------------------------
原子哥,挺崇拜你的,所以ID比你还多三点。不会打我吧。
我是新手,请多指教!有些问题有点幼稚,还望不被打!O(∩_∩)O哈哈~
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2014-9-23 12:30:35 | 显示全部楼层
回复【4楼】正.点.原.子:
---------------------------------
您好。尽量要换图片哦。。。这样容易大家弄混淆的。谢谢支持
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2014-9-24 00:19:34 | 显示全部楼层
你上传代码我看下吧。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

4

主题

125

帖子

1

精华

高级会员

Rank: 4

积分
870
金钱
870
注册时间
2014-8-7
在线时间
49 小时
 楼主| 发表于 2014-9-24 16:44:21 | 显示全部楼层
回复【6楼】正点原子:
---------------------------------
感谢原子哥,问题已经解决了。原来对内存管理的代码不是熟悉,修改下内存管理的地址和参数就可以了,谢谢!
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2014-9-24 23:19:04 | 显示全部楼层
回复【8楼】正.点.原.子:
---------------------------------
楼主你这超详细啊。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

4

主题

125

帖子

1

精华

高级会员

Rank: 4

积分
870
金钱
870
注册时间
2014-8-7
在线时间
49 小时
 楼主| 发表于 2014-11-12 11:47:51 | 显示全部楼层
(*^__^*) 嘻嘻……
回复

使用道具 举报

9

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
82
金钱
82
注册时间
2013-2-13
在线时间
0 小时
发表于 2014-12-31 16:48:41 | 显示全部楼层
楼主你好,请问你具体是改哪里了呢?我也遇到这个问题,但不知道修改哪里
回复

使用道具 举报

4

主题

125

帖子

1

精华

高级会员

Rank: 4

积分
870
金钱
870
注册时间
2014-8-7
在线时间
49 小时
 楼主| 发表于 2015-1-2 14:47:41 | 显示全部楼层
回复【11楼】托卡玛克:
---------------------------------
在内存管理malloc的头文件中,将MEM1_MAX_SIZE的大小改成你需要的就行了。
回复

使用道具 举报

9

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
82
金钱
82
注册时间
2013-2-13
在线时间
0 小时
发表于 2015-1-5 00:32:24 | 显示全部楼层
回复【12楼】正.点.原.子:
---------------------------------
非常感谢,貌似偏置也要改。
回复

使用道具 举报

1

主题

215

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2013-9-23
在线时间
4 小时
发表于 2015-2-11 17:57:23 | 显示全部楼层
来 学习学习
回复

使用道具 举报

16

主题

173

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2441
金钱
2441
注册时间
2014-11-5
在线时间
348 小时
发表于 2015-8-22 16:14:55 | 显示全部楼层
7楼写得太详细了,一看就懂,赞一个
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2015-8-22 20:27:34 | 显示全部楼层
cool....
回复

使用道具 举报

22

主题

104

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
235
金钱
235
注册时间
2015-5-4
在线时间
34 小时
发表于 2015-11-2 16:55:45 | 显示全部楼层
7楼写得太详细了,我是通过这个开始入门内存管理的
回复

使用道具 举报

6

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
132
金钱
132
注册时间
2015-10-22
在线时间
30 小时
发表于 2015-11-20 15:55:01 | 显示全部楼层
内存池总大小,内部为 40K,外部为 960K      编译出错 把960K改小就可以,改为400K    这个960K怎么理解  原子哥哥!
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2015-11-20 22:22:28 | 显示全部楼层
回复【18楼】libin925X:
---------------------------------
说明内存不够
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

5

主题

21

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
425
金钱
425
注册时间
2015-12-25
在线时间
39 小时
发表于 2016-4-19 21:32:34 | 显示全部楼层
正.点.原.子 发表于 2015-1-2 14:47
回复【11楼】托卡玛克:
---------------------------------
在内存管理malloc的头文件中,将MEM1_MAX_SIZE ...

我想用外部SRAM,但是,这些大小不是固定的吗?内部最大100多K,外部最大1MB,基本上原子哥都用了呀?我外部就想用300K,原子哥已经开到了900K,按理说够用了呀?
回复

使用道具 举报

5

主题

21

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
425
金钱
425
注册时间
2015-12-25
在线时间
39 小时
发表于 2016-4-19 21:36:49 | 显示全部楼层

我想用外部SRAM,但是,我外部就想用300K,原子哥已经开到了900K,按理说够用了呀?
我用了FATFS文件系统,用到了malloc,用了malloc,是不是就不能用指定外部SRAM的方法了?(我想把原子哥的“外部SRAM实验”与“FATFS测试工程”结合在一起,完成AD采集并存储)
回复

使用道具 举报

14

主题

73

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
296
金钱
296
注册时间
2016-6-23
在线时间
29 小时
发表于 2016-7-29 09:47:11 | 显示全部楼层
marble 发表于 2016-4-19 21:36
我想用外部SRAM,但是,我外部就想用300K,原子哥已经开到了900K,按理说够用了呀?
我用了FATFS文件系 ...

您好,您用过FATFS实验中的malloc以后,还能用外部SRAM吗?malloc占用了多少外部SRAM呢。谢谢
回复

使用道具 举报

5

主题

21

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
425
金钱
425
注册时间
2015-12-25
在线时间
39 小时
发表于 2016-7-29 10:45:42 | 显示全部楼层
lol 发表于 2016-7-29 09:47
您好,您用过FATFS实验中的malloc以后,还能用外部SRAM吗?malloc占用了多少外部SRAM呢。谢谢

我后来直接用的数组,2000个双字节,也够用了。
回复

使用道具 举报

14

主题

73

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
296
金钱
296
注册时间
2016-6-23
在线时间
29 小时
发表于 2016-7-29 10:49:45 | 显示全部楼层
marble 发表于 2016-7-29 10:45
我后来直接用的数组,2000个双字节,也够用了。

您的数组是全局数组吗?定义在外部SRAM还是内部SRAM?
回复

使用道具 举报

5

主题

21

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
425
金钱
425
注册时间
2015-12-25
在线时间
39 小时
发表于 2016-7-30 10:17:26 | 显示全部楼层
lol 发表于 2016-7-29 10:49
您的数组是全局数组吗?定义在外部SRAM还是内部SRAM?

用的全局数组,定义在内部SRAM
回复

使用道具 举报

2

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
134
金钱
134
注册时间
2016-5-3
在线时间
42 小时
发表于 2016-10-29 11:26:53 | 显示全部楼层
继续逛,继续膜拜大神。
回复

使用道具 举报

0

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2016-10-20
在线时间
10 小时
发表于 2016-11-16 14:06:13 | 显示全部楼层
谢谢分享!!
回复

使用道具 举报

1

主题

4

帖子

0

精华

新手上路

积分
35
金钱
35
注册时间
2017-3-25
在线时间
3 小时
发表于 2017-3-25 09:56:07 | 显示全部楼层
正点原子 发表于 2014-9-23 10:37
你这两个地址打架了,你只出现一个地址试试。

”因为不管是存储什么数据类型内存中的地址编号都是32位的,即每个地址编号可以容纳4个字节“
请问地址编号跟地址可容量有什么关系吗?
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2017-6-17
在线时间
6 小时
发表于 2017-11-6 21:59:22 | 显示全部楼层

我遇到个奇怪的问题,这样子定义 uint16_t  flg_bit_all  __attribute__((at(0x20000040))); 能通过编译,但如果我换个地址 uint16_t  flg_bit_all  __attribute__((at(0x20000004))); 就不行,总是报错: Error: L6971E: system_stm32f10x.o(.data) type RW incompatible with main.o(.ARM.__AT_0x20000004) type ZI in er RW_IRAM1.    不知道怎么回事
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-7 12:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表