F4内存管理

 指定使用特定地址


Keil MDK将变量固定到指定地址_keil 定义数据到指定区域_Little_Star_W的博客-CSDN博客

 怎么看程序使用了多少SRAM

mdk(keil)怎么查看整个工程占用FLASH及SRAM大小_mdk如何查看程序大小_LYuer_的博客-CSDN博客

SRAM内部管理

F4手册提到(2.3.1)

系统 SRAM 可按字节、半字(16 位)或全字(32 位)访问。读写操作以 CPU 速度执行, 
且等待周期为 0。系统 SRAM 分为三个块:

  • 映射在地址 0x2000 0000 的 112 KB 和 16 KB 块,可供所有 AHB 主控总线访问。
  • 在地址 0x1000 0000 映射的 64 KB 块,只能供 CPU 通过数据总线访问。

大概意思是前面两个块用在高速总线上,片上外设的寄存器这类的可以访问;第三个块没有指定用上,CPU访问;

所以可以得到三个SRAM块使用,一个是正常的SRAM   0x2000 0000一般数据是在这里开始 ,一个是指定0x1000 0000才能使用这个块

外扩SRAM

外扩的SRAM指定范围为0x6000 0000 到0x6FFF FFFF,大概可以外扩256M=(0x6FFF FFFF-0x6000 0000)/1024/1024   M

开发板上外扩这个芯片IS62WV51216,512*16b=1MB大小的外部内存;

内存管理结构图

内存管理原理

构成:从内存管理结构图,可以知道由内存表和内存块组成,内存块又有大小;

申请查找:从内存表的末端开始查找是否使用;有标记非0的就已经在使用。

释放:从内存表的申请得到的地址,正向从地址开始清零内存表;

所以程序需要内存池,和内存表;内存表需要16位的,表可管理地址做大可以偏移65535个字节;

需要建立内存池 m字节,需要m/内存块大小*2(16位)字节;

申请内存

uint32_t my_mem_the_malloc(uint8_t memx ,uint32_t size)
{
   signed long offset=0;
	 uint32_t mem_block_num=size/mem_block_size[memx]; //需要的内存分块数
	 uint32_t mem_block_breakup=0;   //块数记录
	 uint32_t i;
	 if(my_mem_mallcoc.memrdy[memx]!=1)my_mem_mallcoc.init(memx);
	 if(size==0) return 0XFFFFFFFF; //如果申请为0返回错误
	 if(size%mem_block_size[memx])//如果有多余的多申请一个块
		       mem_block_num++;
	  for( offset=mem_map_size[memx]-1;offset>=0;offset--   )//从最后位置查找表,一直查找完
		{
		     if(my_mem_mallcoc.memmap[memx][offset] == 0) 
				 {
						mem_block_breakup++;//连续就累加连续个数
				 }else
				 {
						mem_block_breakup=0;//不连续,就记录清零
				 }
				 if(mem_block_num==mem_block_breakup)//如果需要的个数,和查找到连续个数相等,就是查找完成
				 {
							for(i= 0 ;i<mem_block_num ;i++)
						 {
						   my_mem_mallcoc.memmap[memx][offset+i]=mem_block_num;//然后找到对应的块对应的表,标记起来这个mem_block_num块,标记为申请的块数

						 }
				     return ( offset*mem_block_size[memx]);//标记完返回偏移量,一个表对应一个32字节的块,所以偏移量*块大小
				 
				 }
		
		
		}
	  return 0xffffffff;

}
  1. 确保初始化和申请大小不为0
  2. 用申请内存字节需要多少个内存表,从表后面开始查询是否使用,直到查询到连续内存表连续未使用。不成功返回,成功就标记内存表,为申请内存表个数的值,返回申请的内存偏移量;
  3. 把偏移量转成地址返回;

释放内存

uint8_t my_mem_the_free(uint8_t memx ,uint32_t offsize)
{
	int i;
  
	if(my_mem_mallcoc.memrdy[memx]==0)
	{
	   my_mem_mallcoc.init(memx);
		 return 1;//内存池没有初始化返回1

	}
	if(offsize<mem_max_size[memx])//确保没有超出内存池大小
	{
	   
		  int index=offsize/mem_block_size[memx];//通过偏移量,得到偏移分块数
		  int mem_block_breakup=my_mem_mallcoc.memmap[memx][index];//找到内存管理表的对应块数位置起始
	    for( i=0;i<mem_block_breakup;i++)
			{
			      my_mem_mallcoc.memmap[memx][index+i]=0;//把表标记清0;
			
			}
	    return 0;//释放完毕返回0
	}

 return 2;//超出内存池的界返回2
	

}
  1. 利用地址转成内存表偏移量
  2. 找到起始内存表把内存表的标数作为数量,把后面的表都清零;

错误经验

1、申请的内存不能过大,因为内部SRAM本身程序也需要用到一些SRAM;

2、外部SRAM需要初始化FSMC,才能使用外扩SRAM

3、使用内部SRAM的默认指定0x2000 0000 ,所以使用外部或者其他SRAM块都需要指定地址

以上如果出现,就会出现死机;

程序

点c文件

#include"my_malloc_1.h"
#include"main.h"

struct m_malloc_struct my_malloc;


//32字节对齐,一个内存块大小32字节 ,指定地址
__ALIGNED(32)  uint8_t mem1base[MEM1_MAX_SIZE];
__ALIGNED(32)  uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((__section(".ARM.__at_0x68000000")));//外部SRAM内存池
__ALIGNED(32)  uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((__section(".ARM.__at_0x10000000")));//内部CCM内存池


uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE];
uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((__section(".ARM.__at_0x68018000")  ));//外部SRAM内存管理状态表
uint16_t mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((__section(".ARM.__at_0x1000F000")  ));//内部SRAM内存管理状态表

const uint32_t mem_map_size[SRAMBANK] ={ MEM1_ALLOC_TABLE_SIZE , MEM2_ALLOC_TABLE_SIZE,MEM3_ALLOC_TABLE_SIZE};//内存表的大小
const uint32_t mem_block_size[SRAMBANK] ={ MEM1_BLOCK_SIZE , MEM2_BLOCK_SIZE ,MEM3_BLOCK_SIZE }; // 内存池分块的大小
const uint32_t mem_max_size[SRAMBANK] ={MEM1_MAX_SIZE , MEM2_MAX_SIZE , MEM3_MAX_SIZE }; //内存池可管理的大小


struct m_malloc_struct my_mem_mallcoc=
{
    my_mem_init,
    my_mem_use_rote,
	  mem1base,mem2base,mem3base,
	  mem1mapbase,mem2mapbase,mem3mapbase,
    
};





void my_mem_init(uint8_t memx )//初始化内存
{
	int i=0;

	for(i=0;i<mem_max_size[memx];i++)
	{
	   my_mem_mallcoc.membase[memx][i]=0;
	
	}
		for(i=0;i<mem_map_size[memx];i++)
	{
	   my_mem_mallcoc.memmap[memx][i]=0;
	
	}
 //  memset( &my_mem_mallcoc.membase[memx][0],0 ,mem_max_size[memx]);//清除内存池所有
//	 memset(my_mem_mallcoc.memmap[memx] ,0 ,mem_map_size[memx]);//清除内存表
	 my_mem_mallcoc.memrdy[memx]=1;//内存池初始化成功

}


uint8_t my_mem_use_rote(uint8_t memx  )//生成使用率
{
	uint32_t i,use=0;

  for(i=0;i<mem_max_size[memx];i++)//检查内存管理表
	{
	   if(my_mem_mallcoc.memmap[i]!=0)
		 {
		    use++;
		 }
	
	}
  return (use*100)/mem_max_size[memx]; //转换为百分比
}



uint32_t my_mem_the_malloc(uint8_t memx ,uint32_t size)
{
   signed long offset=0;
	 uint32_t mem_block_num=size/mem_block_size[memx]; //需要的内存分块数
	 uint32_t mem_block_breakup=0;   //块数记录
	 uint32_t i;
	 if(my_mem_mallcoc.memrdy[memx]!=1)my_mem_mallcoc.init(memx);
	 if(size==0) return 0XFFFFFFFF; //如果申请为0返回错误
	 if(size%mem_block_size[memx])//如果有多余的多申请一个块
		       mem_block_num++;
	  for( offset=mem_map_size[memx]-1;offset>=0;offset--   )//从最后位置查找表,一直查找完
		{
		     if(my_mem_mallcoc.memmap[memx][offset] == 0) 
				 {
						mem_block_breakup++;//连续就累加连续个数
				 }else
				 {
						mem_block_breakup=0;//不连续,就记录清零
				 }
				 if(mem_block_num==mem_block_breakup)//如果需要的个数,和查找到连续个数相等,就是查找完成
				 {
							for(i= 0 ;i<mem_block_num ;i++)
						 {
						   my_mem_mallcoc.memmap[memx][offset+i]=mem_block_num;//然后找到对应的块对应的表,标记起来这个mem_block_num块,标记为申请的块数

						 }
				     return ( offset*mem_block_size[memx]);//标记完返回偏移量,一个表对应一个32字节的块,所以偏移量*块大小
				 
				 }
		
		
		}
	  return 0xffffffff;

}

uint8_t my_mem_the_free(uint8_t memx ,uint32_t offsize)
{
	int i;
  
	if(my_mem_mallcoc.memrdy[memx]==0)
	{
	   my_mem_mallcoc.init(memx);
		 return 1;//内存池没有初始化返回1

	}
	if(offsize<mem_max_size[memx])//确保没有超出内存池大小
	{
	   
		  int index=offsize/mem_block_size[memx];//通过偏移量,得到偏移分块数
		  int mem_block_breakup=my_mem_mallcoc.memmap[memx][index];//找到内存管理表的对应块数位置起始
	    for( i=0;i<mem_block_breakup;i++)
			{
			      my_mem_mallcoc.memmap[memx][index+i]=0;//把表标记清0;
			
			}
	    return 0;//释放完毕返回0
	}

 return 2;//超出内存池的界返回2
	

}



void *mymalloc(uint8_t memx ,uint32_t size)
{
	uint32_t offset=0;
  offset=my_mem_the_malloc( memx , size);//返回偏移量,已经处理过的偏移量,指向内存池的第几个
  if(offset==0xffffffff)
	{
		   return NULL;
	}
	else { 
	
	     return (void *)((uint32_t)my_mem_mallcoc.membase[memx]+offset);//返回指向内存池第几字节的地址
	}
}


void myfree(uint8_t memx ,void *p)
{
	uint32_t offset=0;
  if(p==NULL)return ;
	offset=(uint32_t)p-(uint32_t)my_mem_mallcoc.memmap[memx];//通过地址,来确定偏移量
  my_mem_the_free( memx , offset);


}




点H文件

#ifndef MY_MALLOC_1_H
#define MY_MALLOC_1_H
#include"main.h"

/***   内存池1        ******/
#define MEM1_BLOCK_SIZE 32   //内存分块大小
#define MEM1_MAX_SIZE 2*1024 //内存最大管理100K
#define MEM1_ALLOC_TABLE_SIZE  MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //内存1的内存表大小


/***   内存池2        ******/
#define MEM2_BLOCK_SIZE 32 //内存分块大小
#define MEM2_MAX_SIZE 9*1024 //内存最大管理96K
#define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //内存2的内存表大小


/***   内存池3        ******/
#define MEM3_BLOCK_SIZE 32 //内存分块大小
#define MEM3_MAX_SIZE 6*1024 //内存最大管理96K
#define MEM3_ALLOC_TABLE_SIZE MEM3_MAX_SIZE/MEM3_BLOCK_SIZE //内存2的内存表大小


#define SRAMBANK 3

struct m_malloc_struct 
{
  void ( *init ) (uint8_t);  //函数指针,用来初始化
	uint8_t  (*use_rote)(uint8_t); //函数指针 ,使用率
	uint8_t  *membase[SRAMBANK];  //内存池  SARMBANK个内存池
	uint16_t *memmap[SRAMBANK];   //内存管理表  SARMBANK个
	uint8_t  memrdy[SRAMBANK];    //内存管理,是否就绪

};
extern struct m_malloc_struct my_malloc;

void my_mem_init(uint8_t memx );//初始化内存
uint8_t my_mem_use_rote(uint8_t memx  );//生成使用率
void *mymalloc(uint8_t memx ,uint32_t size);
void myfree(uint8_t memx ,void *p);
#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值