指定使用特定地址
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;
}
- 确保初始化和申请大小不为0
- 用申请内存字节需要多少个内存表,从表后面开始查询是否使用,直到查询到连续内存表连续未使用。不成功返回,成功就标记内存表,为申请内存表个数的值,返回申请的内存偏移量;
- 把偏移量转成地址返回;
释放内存
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、申请的内存不能过大,因为内部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