历史上的今天
今天是:2024年12月17日(星期二)
2020年12月17日 | STM32F7xx —— 内存管理
2020-12-17 来源:eefocus
目的:高效、快速的分配,并在适当的时候回收内存资源。最终就是实现malloc和free函数。(实现方法参考原子哥)
#define CONFIG_SRAM_OUT_ENABLE 0
typedef enum
{
SRAM_TYPE_IN, // 内部内存池
#if(CONFIG_SRAM_OUT_ENABLE == 1)
SRAM_YPE_OUT, // 外部内存池(SDRAM)
#endif
SRAM_TYPE_DTCM, // DTCM内存池(此部分SRAM仅仅CPU可以访问!!!)
SRAM_TYPE_MAX, // 最多支持的SRAM块数.
} sram_type_t;
// 内部SRAM
#define SRAM_IN_BLOCK_SIZE 64 // 内存块大小为64字节
#define SRAM_IN_MAX_SIZE (160 * 1024) // 最大管理内存160K
#define SRAM_IN_ALLOC_TABLE_SIZE (SRAM_IN_MAX_SIZE / SRAM_IN_BLOCK_SIZE)
#if(CONFIG_SRAM_OUT_ENABLE == 1)
// 外部SDRAM里面
#define SRAM_OUT_BLOCK_SIZE 64 // 内存块大小为64字节
#define SRAM_OUT_MAX_SIZE (100 *1024) // 最大管理内存100K
#define SRAM_OUT_ALLOC_TABLE_SIZE (SRAM_OUT_MAX_SIZE / SRAM_OUT_BLOCK_SIZE)
#endif
// CCM,用于管理DTCM(特别注意,这部分SRAM,仅CPU可以访问!!)
#define SRAM_DTCM_BLOCK_SIZE 64 //内存块大小为64字节
#define SRAM_DTCM_MAX_SIZE (100 *1024) //最大管理内存60K
#define SRAM_DTCM_ALLOC_TABLE_SIZE (SRAM_DTCM_MAX_SIZE/SRAM_DTCM_BLOCK_SIZE)
//内存池(32字节对齐)
__align(32) uint8_t sram_in_base[SRAM_IN_MAX_SIZE]; // 内部SRAM内存池
uint32_t sram_in_map_base[SRAM_IN_ALLOC_TABLE_SIZE];
#if(CONFIG_SRAM_OUT_ENABLE == 1)
__align(32) uint8_t sram_out_base[SRAM_OUT_MAX_SIZE] __attribute__((at(0xC01F4000))); // 外部SDRAM内存池
uint32_t sram_out_map_base[SRAM_OUT_ALLOC_TABLE_SIZE] __attribute__((at(0xC01F4000 + SRAM_OUT_MAX_SIZE))); // 外部SRAM内存池MAP
#endif
__align(32) uint8_t sram_dtcm_base[SRAM_DTCM_MAX_SIZE] __attribute__((at(0x20000000))); // 内部DTCM内存池
uint32_t sram_dtcm_map_base[SRAM_DTCM_ALLOC_TABLE_SIZE] __attribute__((at(0x20000000 + SRAM_DTCM_MAX_SIZE))); //内部DTCM内存池MAP
static const uint32_t memtblsize[SRAM_TYPE_MAX] = {SRAM_IN_ALLOC_TABLE_SIZE,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
SRAM_OUT_ALLOC_TABLE_SIZE,
#endif
SRAM_DTCM_ALLOC_TABLE_SIZE
}; //内存表大小
static const uint32_t memblksize[SRAM_TYPE_MAX] = {SRAM_IN_BLOCK_SIZE,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
SRAM_OUT_BLOCK_SIZE,
#endif
SRAM_DTCM_BLOCK_SIZE
}; //内存分块大小
static const uint32_t memsize[SRAM_TYPE_MAX] = {SRAM_IN_MAX_SIZE,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
SRAM_OUT_MAX_SIZE,
#endif
SRAM_DTCM_MAX_SIZE
}; //内存总大小
void mymem_init(uint8_t type);
uint16_t mymem_perused(uint8_t type);
typedef struct
{
void (* init)(uint8_t );
uint16_t (* perused)(uint8_t); // 内存使用率
uint8_t *membase[SRAM_TYPE_MAX]; // 内存池 管理SRAMBANK个区域的内存
uint32_t *memmap[SRAM_TYPE_MAX]; // 内存管理状态表
uint8_t memrdy[SRAM_TYPE_MAX]; // 内存管理是否就绪
} sram_dev_t;
//内存管理控制器
static sram_dev_t sram_dev =
{
mymem_init, // 内存初始化
mymem_perused, // 内存使用率
sram_in_base,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
sram_out_base,
#endif
sram_dtcm_base, // 内存池
sram_in_map_base,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
sram_out_map_base,
#endif
sram_dtcm_map_base,
0,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
0,
#endif
0,
};
// 内存管理初始化
static void mymem_init(uint8_t memx)
{
memset(sram_dev.memmap[memx], 0, memtblsize[memx] * 4); // 内存状态表数据清零
sram_dev.memrdy[memx] = 1; // 内存管理初始化OK
}
// 获取内存使用率
// type:所属内存块
// 返回值:使用率(扩大了10倍,0~1000,代表0.0%~100.0%)
static uint16_t mymem_perused(uint8_t type)
{
uint32_t used = 0;
uint32_t i;
for(i = 0; i < memtblsize[type]; ++i)
{
if(sram_dev.memmap[type][i])
{
used++;
}
}
return (used * 1000) / (memtblsize[type]);
}
// 内存分配(内部调用)
// type:所属内存块
// size:要分配的内存大小(字节)
// 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
static uint32_t mymem_malloc(uint8_t type, uint32_t size)
{
signed long offset = 0;
uint32_t nmemb; // 需要的内存块数
uint32_t cmemb = 0; // 连续空内存块数
uint32_t i;
if(!sram_dev.memrdy[type])
{
sram_dev.init(type); // 未初始化,先执行初始化
}
if(size == 0)
{
return 0xFFFFFFFF; // 不需要分配
}
nmemb = size / memblksize[type]; // 获取需要分配的连续内存块数
if(size % memblksize[type])
{
nmemb++;
}
for(offset = memtblsize[type] - 1; offset >= 0; offset--) // 搜索整个内存控制区
{
if(!sram_dev.memmap[type][offset])
{
cmemb++; // 连续空内存块数增加
}
else
{
cmemb = 0; // 连续内存块清零
}
if(cmemb == nmemb) // 找到了连续nmemb个空内存块
{
for(i = 0; i < nmemb; i++) // 标注内存块非空
{
sram_dev.memmap[type][offset + i] = nmemb;
}
return (offset * memblksize[type]); // 返回偏移地址
}
}
return 0xFFFFFFFF; // 未找到符合分配条件的内存块
}
// 释放内存(内部调用)
// type:所属内存块
// offset:内存地址偏移
// 返回值:0,释放成功;1,释放失败;
static uint8_t mymem_free(uint8_t type, uint32_t offset)
{
int i;
if(!sram_dev.memrdy[type])// 未初始化,先执行初始化
{
sram_dev.init(type);
return 1;// 未初始化
}
if(offset < memsize[type]) // 偏移在内存池内.
{
int index = offset / memblksize[type]; // 偏移所在内存块号码
int nmemb = sram_dev.memmap[type][index]; // 内存块数量
for(i = 0; i < nmemb; i++) // 内存块清零
{
sram_dev.memmap[type][index + i] = 0;
}
return 0;
}
else
{
return 2; // 偏移超区了.
}
}
void MemInit(uint8_t type)
{
memset(sram_dev.memmap[type], 0, memtblsize[type] * 4); // 内存状态表数据清零
sram_dev.memrdy[type] = 1; // 内存管理初始化OK
}
// 释放内存(外部调用)
// type:所属内存块
// ptr:内存首地址
void MemFree(uint8_t type, void *ptr)
{
uint32_t offset;
if(ptr == NULL)
{
return; // 地址为0.
}
offset = (uint32_t)ptr - (uint32_t)sram_dev.membase[type];
mymem_free(type, offset); // 释放内存
}
// 分配内存
void *MemAlloc(uint8_t type, uint32_t size)
{
uint32_t offset;
offset = mymem_malloc(type, size);
if(offset == 0XFFFFFFFF)
{
return NULL;
}
else
{
return (void*)((uint32_t)sram_dev.membase[type] + offset);
}
}
// 重新分配内存
void *MemRealloc(uint8_t type, void *ptr, uint32_t size)
{
uint32_t offset;
offset = mymem_malloc(type, size);
if(offset == 0xFFFFFFFF)
{
return NULL;
}
else
{
memcpy((void*)((uint32_t)sram_dev.membase[type] + offset), ptr, size); // 拷贝旧内存内容到新内存
MemFree(type, ptr); // 释放旧内存
return (void*)((uint32_t)sram_dev.membase[type] + offset); // 返回新内存首地址
}
}
史海拾趣
|
本帖最后由 jameswangsynnex 于 2015-3-3 20:01 编辑 我们大量ROHM BU72435库存价格好,有需求请和我联系。 陈庭松 13138889236 … 查看全部问答> |
|
请想象一下,当您乔迁新居,要将电器的电源插头插进墙上插座里去,结果却发现根本不能匹配时是什么感受。应该感谢几十年之前设立的电气标准,发生这种事情的可能性已经很少了。其他还有一些标准也在为我们服务,比如我们可以跟与不同网络服务商打交 ...… 查看全部问答> |
|
Windows CE中的命令提示行的和PC机上的XP中的有啥区别? 网上说: Windows CE和Windows XP Embedded存在诸多本质区别。首先,Windows CE是一款全32位、Unicode操作系统,它不支持MS-DOS或Windows 3.x应用。 这里说的MS-DOS不就是台式机上的命令提示行中DOS ...… 查看全部问答> |
|
我想实现在wince液晶上 显示采样信号波形。波形频率很低。 肯定要包括ADC驱动,和应用程序 第一个问题:我想要ADC每隔500ms采样一次,用中断来实现。这个500ms中断在驱动中如何实现? 第二个问题:应用程序获取AD结果可以使用流驱动接口,但是读 ...… 查看全部问答> |
|
串口通讯中的DCB结构 我看很多程序,它里面使用了BCD结构,但是BCD结果不是在winbase.h中定义的吗, 程序里面并没有#include \"winbase.h\",但是编译确实成功的,为什么? 我是学了VC现在学EVC,觉得有点困扰,EVC很多库函数都不一样了,怎么找 ...… 查看全部问答> |
|
以下我做了不同平台的测试 第一个平台是Default language为中文(中国) 第二个平台是Default language为英语(英文) 第三个平台是Default language为英语(英文),并加入MUI多国语言的支持. 应用程序代码如下: char cTest[] & ...… 查看全部问答> |
|
小弟关于bootloader中有几个问题不清楚,麻烦兄弟们帮忙解释下, 1,其中涉及到内存映射,它的作用是什么? 2,cpu又是如何区分flash和ram的地址呢,难到有控制flash和ram地址的寄存器吗? 3,如果flash的os要加载到ram中执行,又是如何实现拷贝的呢,如 ...… 查看全部问答> |
|
各位同道中人,欢迎各位谈谈自己入门的经验以及推荐一些好的资料,作为LZ,先为大家献上一点啦! 现面有几个不错的网站 ,仅供参考 http://162.105.146.27/cgi-bin/ftp_search?BeginWith=208&FType=255&word=Linux http://linux.ubuntu.org. ...… 查看全部问答> |
|
在下大四学生,之前在学校只接触过很浅的嵌入式知识,现在毕业设计被安排在一公司参加一个项目,要实现一块板子的以太网通讯功能,板子应该是arm cortex m3核心,lm3s9b92的型号,我要实现的功能是将温度、液位等数据通过以太网接口传给计算机,我 ...… 查看全部问答> |




