stm32内存管理(代码片段)

果果小师弟 果果小师弟     2023-02-02     259

关键词:

动态内存管理

  • 根据需要分配內存和回收内存
    通常在一块较大且连续的内存空间上进行分配和回收
  • 动态内存管理解决的问题
    内存资源稀缺,通过内存复用增加任务的并发性
  • 动态内存管理的本质
    时间换空间,通过动态分配和回收“扩大”物理内存

动态内存管理的关键

  • 时间效率
    从发出内存申请到得内存的时间越短越好
  • 空间效率
    为了管理内存而占用的内存越少越好
  • 碎片化
    最大可分配内存占空闲内存总和的比例越大越好

动态内存管理的分类

  • 定长内存管理
    将内存分为大小相同的单元,每次申请一个单元的内存

  • 变长内存管理
    每次申请需要的内存(大小不固定,以字节为单位)

  • 定长内存管理的设计与实现
    将内存分为两部分:管理单元&分配单元
    管理单元与分配单元——对应

uint8_t mem2base[960*1024] __attribute__((at(0X68000000)));

表示在外部SRAM内存区域定义一个数组,这里使用的是FSMC的BANK1的NE3,对应的外部地址就是0X68000000。不明白的去看一看STM32的FSMC章节。

//内存池(32字节对齐)   
__align(32) uint8_t mem1base[100*1024];										//内部SRAM内存池 100K
__align(32) uint8_t mem2base[960*1024] __attribute__((at(0X68000000)));		//外部SRAM内存池 960K
__align(32) uint8_t mem3base[60 *1024] __attribute__((at(0X10000000)));		//内部CCM内存池 60K

//内存管理表
uint16_t mem1mapbase[100*1024/32];											//内部SRAM内存池MAP
uint16_t mem2mapbase[960*1024/32] __attribute__((at(0X68000000+960*1024)));	//外部SRAM内存池MAP
uint16_t mem3mapbase[60 *1024/32] __attribute__((at(0X10000000+60*1024)));	//内部CCM内存池MAP

//内存管理参数	   
const uint32_t memtblsize[SRAMBANK]=100*1024/32,960*1024/32,60 *1024/32;	//内存表大小
const uint32_t memblksize[SRAMBANK]=32,32,32;					            //内存分块大小
const uint32_t memsize   [SRAMBANK]=100*1024,960*1024,60*1024;			//内存总大小

malloc.c

#include "malloc.h"	   


//内存管理就绪
#define  MEMRDY   1
#define  MEMBSY   0

//内存池(32字节对齐)   
__align(32) uint8_t mem1base[100*1024];										//内部SRAM内存池 100K
__align(32) uint8_t mem2base[960*1024] __attribute__((at(0X68000000)));		//外部SRAM内存池 960K
__align(32) uint8_t mem3base[60 *1024] __attribute__((at(0X10000000)));		//内部CCM内存池 60K

//内存管理表 32字节为单位
uint16_t mem1mapbase[100*1024/32];											//内部SRAM内存池MAP
uint16_t mem2mapbase[960*1024/32] __attribute__((at(0X68000000+960*1024)));	//外部SRAM内存池MAP
uint16_t mem3mapbase[60 *1024/32] __attribute__((at(0X10000000+60*1024)));	//内部CCM内存池MAP

//内存管理参数	   
const uint32_t memtblsize[SRAMBANK]=100*1024/32,960*1024/32,60 *1024/32;	//内存表大小
const uint32_t memblksize[SRAMBANK]=32,32,32;					            //内存分块大小
const uint32_t memsize   [SRAMBANK]=100*1024,960*1024,60*1024;			//内存总大小

//内存管理控制器
MALLOC_EDV_T  g_mallcoDev = 

	my_mem_init,					    	      //内存初始化
	my_mem_perused,						      //内存使用率
	mem1base, mem2base, mem3base,			     //内存池
	mem1mapbase, mem2mapbase, mem3mapbase,  //内存管理状态表
	MEMBSY, MEMBSY, MEMBSY,	    	           //内存管理未就绪
;


/************************************************************************
** 函数名称: mymemcpy									
** 函数功能: 复制内存
** 入口参数: void *des:目的地址
**           void *src:原地址
**           uint32_t n:  需要复制的内存长度(以字节为单位) 
** 出口参数: 												
************************************************************************/
void mymemcpy(void *des,void *src,uint32_t n)  
  
	uint8_t *xdes=des;
	uint8_t *xsrc=src; 
	while(n--)
		*xdes++=*xsrc++;  
 


/************************************************************************
** 函数名称: mymemset									
** 函数功能: 设置内存
** 入口参数: void *s:内存首地址
**           uint8_t c:要设置的值
**           uint32_t count:  需要设置的内存长度(以字节为单位) 
** 出口参数: 												
************************************************************************/
void mymemset(void *s,uint8_t c,uint32_t count)  
  
	uint8_t *xs = s;  
	while(count--)
		*xs++=c;  
	   


/************************************************************************
** 函数名称: my_mem_init									
** 函数功能: 内存管理初始化  
** 入口参数: uint8_t memx:所属内存块 
** 出口参数: 												
************************************************************************/
void my_mem_init(uint8_t memx)  
  
	//清除内存状态表-每一个内存块对应状态表中的一项
	//因为内存管理状态表示16位的,所以需要乘以2
	mymemset( g_mallcoDev.memmap[memx], 0, memtblsize[memx]*2); 
	//把所管理的内存池全部清理
	mymemset(g_mallcoDev.membase[memx], 0, memsize[memx]); 
	//表明对应的内存管理已经就绪
	g_mallcoDev.memrdy[memx] = MEMRDY;
  

/************************************************************************
** 函数名称: my_mem_perused									
** 函数功能: 计算内存使用率
** 入口参数: uint8_t memx:所属内存块 
** 出口参数: 使用率(0~100)												
************************************************************************/
uint8_t my_mem_perused(uint8_t memx)  
  
	uint32_t used=0;  
	uint32_t i;  
	
	//逐一对每个表项进行统计
	for(i=0;i<memtblsize[memx];i++)  
	  
		  //如果表项值不为0就表示对应内存块被使用了
			if(g_mallcoDev.memmap[memx][i])
				used++; 
	 
	
	//计算百分比
	return (used*100)/(memtblsize[memx]);  


/************************************************************************
** 函数名称: my_mem_malloc									
** 函数功能: 内存分配(内部调用)
** 入口参数: uint8_t memx:所属内存块 
**           uint32_t size:要分配的内存大小(字节)
** 出口参数: 0xFFFFFFFF-分配错误 其他-内存偏移地址 											
************************************************************************/
uint32_t my_mem_malloc(uint8_t memx,uint32_t size)  
  
	signed long offset=0;  
	uint32_t nmemb;	//需要的内存块数  
	uint32_t cmemb = 0;//连续空内存块数
	uint32_t i;  
	
	//未初始化,先执行初始化 
	if(g_mallcoDev.memrdy[memx] == MEMBSY)
		g_mallcoDev.init(memx);
	
	//不需要分配
  if(size == 0)
		return 0xFFFFFFFF;
	
	//获取需要分配的连续内存块数
  nmemb = size/memblksize[memx];  
	//超出不满一个内存块的部分也要申请一个内存块
  if(size%memblksize[memx])
		nmemb++;  
	
	//搜索内存块,从后往前搜索
	for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区  
	    
		//如果内存块没有被使用就代表找到一个空块
		if(g_mallcoDev.memmap[memx][offset] == 0)
		
			//连续空内存块数增加
			cmemb++;
		
		else 
		
			//连续内存块清零--只要找到一个被使用的就表示不连续了,要重新开始找
			cmemb=0;								
		
		
		//找到了连续nmemb个空内存块
		if(cmemb == nmemb)							
		
			//标注内存块非空--并且是连续nmemb个非空块
			for(i=0;i<nmemb;i++)  					
			  
				g_mallcoDev.memmap[memx][offset+i] = nmemb;  
			  
			//返回偏移地址 
			return (offset*memblksize[memx]); 
		
	  
	//未找到符合分配条件的内存块 
	return 0xFFFFFFFF; 
  

/************************************************************************
** 函数名称: my_mem_free									
** 函数功能: 释放内存(内部调用) 
** 入口参数: uint8_t memx:所属内存块
**           uint32_t offset:内存地址偏移
** 出口参数: 0-释放成功;1-释放失败										
************************************************************************/
uint8_t my_mem_free(uint8_t memx,uint32_t offset)  
  
	int i; 

  //未初始化,先执行初始化	
	if(g_mallcoDev.memrdy[memx] == MEMBSY)
	
		g_mallcoDev.init(memx);    
    return 1;//未初始化  
     
	
	//偏移在内存池内. 
	if(offset < memsize[memx])
	  
		int index = offset/memblksize[memx];			//偏移所在内存块号码  
		int nmemb = g_mallcoDev.memmap[memx][index];	//内存块数量
		
		for(i=0;i<nmemb;i++)  						//内存块清零
		  
			g_mallcoDev.memmap[memx][index+i] = 0;  
		  
		return 0;  
	
	else 
		return 2;//偏移超区了.  
  

/************************************************************************
** 函数名称: myfree									
** 函数功能: 释放内存(外部调用) 
** 入口参数: uint8_t memx:所属内存块
**           void *ptr:内存地址偏移
** 出口参数: 无									
************************************************************************/
void myfree(uint8_t memx,void *ptr)  
  
	uint32_t offset; 
	
  //地址为0. 
	if(ptr==NULL)
		return; 
	
	//计算指针在相应内存块中的偏移量
 	offset = (uint32_t)ptr-(uint32_t)g_mallcoDev.membase[memx]; 

  //释放内存 	
  my_mem_free(memx,offset);	     


/************************************************************************
** 函数名称: mymalloc									
** 函数功能: 内存分配(内部调用)
** 入口参数: uint8_t memx:所属内存块 
**           uint32_t size:要分配的内存大小(字节)
** 出口参数: 分配到的内存首地址.											
************************************************************************/
void *mymalloc(uint8_t memx,uint32_t size)  
  
	uint32_t offset;   
	
	offset=my_mem_malloc(memx,size); 
	
	if(offset == 0xFFFFFFFF)
		return NULL;  
	else 
		return (void*)((uint32_t)g_mallcoDev.membase[memx]+offset);  
  

/************************************************************************
** 函数名称: myrealloc									
** 函数功能: 重新分配内存(外部调用)
** 入口参数: uint8_t memx:所属内存块 
**           void *ptr:旧内存首地址
**           uint32_t size:要分配的内存大小(字节)
** 出口参数: 新分配到的内存首地址.										
************************************************************************/
void *myrealloc(uint8_t memx,void *ptr,uint32_t size)  
  
	uint32_t offset;    
	
	//先申请一段内存
	offset = my_mem_malloc(memx,size);  

	//申请失败
	if(offset == 0xFFFFFFFF)
		return NULL;     
	else  
	  		
    //拷贝旧内存内容到新内存  		
		mymemcpy((void*)((uint32_t)g_mallcoDev.membase[memx]+offset),ptr,size);	 
		
		//释放旧内存
		myfree(memx,ptr);  			
		
		//返回新内存首地址		
		return (void*)((uint32_t)g_mallcoDev.membase[memx]+offset);  				
	  

malloc.h

#ifndef __MALLOC_H
#define __MALLOC_H

#include "main.h"

#ifndef NULL
    #define NULL 0
#endif

//定义三个内存池
#define SRAMIN	 0		//内部内存池
#define SRAMEX   1		//外部内存池
#define SRAMCCM  2		//CCM内存池(此部分SRAM仅仅CPU可以访问!!!)
#define SRAMBANK 	3	//定义支持的SRAM块数.	

//内存管理控制器
typedef struct

    void      (*init)(uint8_t);					      //初始化
    uint8_t   (*perused)(uint8_t);		  	    //内存使用率
    uint8_t    *membase[SRAMBANK];				//内存池 管理SRAMBANK个区域的内存
    uint16_t  *memmap[SRAMBANK]; 				//内存管理状态表
    uint8_t   memrdy[SRAMBANK]; 			   	//内存管理是否就绪
MALLOC_EDV_T;

extern MALLOC_EDV_T  g_mallcoDev;	 //在mallco.c里面定义
/************************************************************************
** 函数名称: mymemcpy
** 函数功能: 复制内存
** 入口参数: void *des:目的地址
**           void *src:原地址
**           uint32_t n:  需要复制的内存长度(以字节为单位)
** 出口参数:
************************************************************************/
void mymemcpy(void *des, void *src, uint32_t n);

/************************************************************************
** 函数名称: mymemset
** 函数功能: 设置内存
** 入口参数: void *s:内存首地址
**           uint8_t c:要设置的值
**           uint32_t count:  需要设置的内存长度(以字节为单位)
** 出口参数:
************************************************************************/
void mymemset(void *s, uint8_t c, uint32_t count);

/************************************************************************
** 函数名称: my_mem_init
** 函数功能: 内存管理初始化
** 入口参数: uint8_t memx:所属内存块
** 出口参数:
************************************************************************/
void my_mem_init(uint8_t memx);

/************************************************************************
** 函数名称: my_mem_perused
** 函数功能: 计算内存使用率
** 入口参数: uint8_t memx:所属内存块
** 出口参数: 使用率(0~100)
************************************************************************/
uint8_t my_mem_perused(uint8_t memx);

/************************************************************************
** 函数名称: my_mem_malloc
** 函数功能: 内存分配(内部调用)
** 入口参数: uint8_t memx:所属内存块
**           uint32_t size:要分配的内存大小(字节)
** 出口参数: 0xFFFFFFFF-分配错误 其他-内存偏移地址
************************************************************************/
uint32_t my_mem_malloc(uint8_t memx, uint32_t size);

/************************************************************************
** 函数名称: my_mem_free
** 函数功能: 释放内存(内部调用)
** 入口参数: uint8_t memx:所属内存块
**           uint32_t offset:内存地址偏移
** 出口参数: 0-释放成功;1-释放失败
************************************************************************/
uint8_t my_mem_free(uint8_t memx, uint32_t offset);

/************************************************************************
** 函数名称: myfree
** 函数功能: 释放内存(外部调用)
** 入口参数: uint8_t memx:所属内存块
**           void *ptr:内存地址偏移
** 出口参数: 无
************************************************************************/
void myfree(uint8_t memx, void *ptr);

/************************************************************************
** 函数名称: mymalloc
** 函数功能: 内存分配(内部调用)
** 入口参数: uint8_t memx:所属内存块
**           uint32_t size:要分配的内存大小(字节)
** 出口参数: 分配到的内存首地址.
************************************************************************/
void *mymalloc(uint8_t memx, uint32_t size);

/************************************************************************
** 函数名称: myrealloc
** 函数功能: 重新分配内存(外部调用)
** 入口参数: uint8_t memx:所属内存块
**           void *ptr:旧内存首地址
**           uint32_t size:要分配的内存大小(字节)
** 出口参数: 新分配到的内存首地址.
************************************************************************/
void *myrealloc(uint8_t memx, void *ptr, uint32_t size);

#endif

用法:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "usmart.h"
#include "sram.h"
#include "malloc.h" 


int main(void)

	u8 key;		 
 	u8 i=0;	    
	u8 *p=0;
	
  HAL_Init();                   	//初始化HAL库    
  Stm32_Clock_Init(336,8,2,7);  	//设置时钟,168Mhz
	delay_init(168);               	//初始化延时函数

	KEY_Init();						//初始化KEY
	SRAM_Init();					//初始化外部SRAM 
	my_mem_init(SRAMEX);			//初始化外部内存池	
 	while(1)
		
		key=KEY_Scan(0);//不支持连按	
		switch(key)
		
			case 0://没有按键按下	
				break;
			case KEY0_PRES:	//KEY0按下
				p=mymalloc(SRAMEX,10240);//申请10K字节
				break;
			case KEY1_PRES:	//KEY1按下	   
				if(p!=NULL)
				
					sprintf((char*)p,"%d",i);//更新显示内容 	 
					LCD_ShowString(30,270,200,16,查看详情  

《嵌入式-深入剖析stm32》深入理解stm32内存管理(代码片段)

在讨论STM32的内存之前,先来看看STM32的存储器系统,我们知道,STM32大都属于Cortex-M系列的处理器,可以对32的存储器进行寻址,因此存储器的寻址空间能够达到4G,这就意味着指定和数据共用相同的地址空... 查看详情

stm32内存管理(代码片段)

动态内存管理根据需要分配內存和回收内存通常在一块较大且连续的内存空间上进行分配和回收动态内存管理解决的问题内存资源稀缺,通过内存复用增加任务的并发性动态内存管理的本质时间换空间,通过动态分配和... 查看详情

stm32h7第22章threadx动态内存管理(代码片段)

...m.php?mod=viewthread&tid=99514第22章      ThreadX动态内存管理本章节为大家讲解ThreadX动态内存管理,ThreadX支持固定数据大小的内存块式分配,也支持类似C库的malloc方式分 查看详情

stm32f429第22章threadx动态内存管理(代码片段)

...m.php?mod=viewthread&tid=99514第22章      ThreadX动态内存管理本章节为大家讲解ThreadX动态内存管理,ThreadX支持固定数据大小的内存块式分配,也支持类似C库的malloc方式分 查看详情

stm32-内存管理

#ifndef__MALLOC_H#define__MALLOC_H#include"stm32f10x.h"////////////////////////////////////////////////////////////////////////////////////本程序只供学习使用,未经作者许可,不得用于其它任何用途//ALIENTEK战舰STM32开发板V3//内存管理驱动代码// 查看详情

stm32内存分配解析及变量的存储位置(代码片段)

内存映射在一些桌面程序中,整个内存映射是通过虚拟内存来进行管理的,使用一种称为内存管理单元(MMU)的硬件结构来将程序的内存映射到物理RAM。在对于RAM紧缺的嵌入式系统中,是缺少MMU内存管理单元的。因此在一些嵌入式... 查看详情

stm32cubemx学习笔记(35)——freertos实时操作系统使用(内存管理)(代码片段)

一、FreeRTOS简介FreeRTOS是一个可裁剪、可剥夺型的多任务内核,而且没有任务数限制。FreeRTOS提供了实时操作系统所需的所有功能,包括资源管理、同步、任务通信等。FreeRTOS是用C和汇编来写的,其中绝大部分都是用C... 查看详情

lvgl动态内存使用ccmram(代码片段)

LVGL动态内存使用CCMRAM使用STM32F407VET6开发一个项目,使用了LVGL,然后关注一下STM32的RAM信息,官方介绍STM32F407的RAM可用RAM是192K,但这192K不是连续的,而是分了三块,其中只有两块是连续的,而因为STM32F... 查看详情

干货|stm32寄存器版的基础知识—内存映射(代码片段)

STM32寄存器版的基础知识—内存映射映射STM32F429芯片系统结构三大总线高速总线高速外设和低速外设内存映射1、STM32存储空间2、什么是存储器映射3、STM32F429的存储器映射寄存器映射地址重映射关于ISP与IAPSTM32F429芯片系统结构STM32... 查看详情

单片机---内存管理(代码片段)

这里针对STM32F407芯片+1M外部内存的内存管理!首先,定义3个内存池,分别是内部SRAM,外表SRAM和CCM;通过指定内存中的绝对地址,后面就可以直接通过数组操纵内存数据了。这里的mem1的大小是112KB,这里用100KB,其余12KB用作内存... 查看详情

stm32单片机系统内存启动方式(an2606文档)分享(代码片段)

STM32单片机系统内存启动方式(AN2606中文文档)分享不管是对于学习STM32还是面对设计STM32电路,阅读这个文档会对你有很大的帮助。409页的文档,几乎涵盖STM32全系列。文档地址:https://www.stmcu.com.cn/Designresource/detail/applic... 查看详情

stm32单片机系统内存启动方式(an2606文档)分享(代码片段)

STM32单片机系统内存启动方式(AN2606中文文档)分享不管是对于学习STM32还是面对设计STM32电路,阅读这个文档会对你有很大的帮助。409页的文档,几乎涵盖STM32全系列。文档地址:https://www.stmcu.com.cn/Designresource/detail/applic... 查看详情

stm32f103zet6的中断管理(代码片段)

1、STM32的中断  STM32的中断管理是属于内核部分的,所以中断管理的寄存器也是属于内核组,不属于芯片外设,在查看相关资料的时候,需要查看相对应的内核手册。  STM32F103ZET6是Cortex-M3内核的IC。Cortex-M3内核支持256个中断... 查看详情

stm32内存受限情况下摄像头驱动方式与图像裁剪的选择(代码片段)

...M,512kBRom,资源有限,接摄像头采集图像,这种情况下,内存利用制约程序设计。STM32使用DCMI接口读取摄像头,协议如下。行同步信号指示了一行数据完成,场同步信号指示了一帧图像传输完成。所以出现了两种典型的数据接收... 查看详情

stm32dma简述(代码片段)

STM32DMA简述DMA(DirectMemoryAccess)直接内存存储器,在做数据传输时能够大大减轻CPU的负担。DMA的作用DMA提供了一个关于数据的高数传输通道,这个通道不占用CPU的资源。换句话说,通过DMA通道,你在传输大规模数据的时候CPU同时也... 查看详情

stm32f103c8keil移植freertos时内存不够(代码片段)

stm32F103c8(flash64k、ram20k)keil移植FreeRTOS时内存不够linking....\\Objects\\Template.axf:Error:L6406E:Nospaceinexecutionregionswith.ANYselectormatchingled.o(.data)..\\Objects\\Template.axf:Erro 查看详情

stm32f103vet6基于stm32cubemx创建串口中断+dma不定长数据接收(代码片段)

...f4d3;DMA参数介绍🎉DMA传输方式🌿传输方向;外设到内存;内存到外设;内存到内存 查看详情