STM32CubeMX系列|内存管理

内存管理

1.内存管理简介

STM32F103ZET6内部有64KB的SRAM内存,加上外扩的128KB容量的SRAM后,可使用的内存还是比较多的。本例程将介绍一种简单的内存管理方式(即分块内存管理)来有效管理这些内存,类似于C语言中通过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. 硬件设计

D1指示灯用来提示系统运行状态,K_UP用来申请内存,K_DOWN用来释放内存,K_RIGHT用来选择所操作的内存,TFTLCD和串口1用来显示内存状态及内存使用率

  • D1指示灯
  • K_UP/K_DOWN/K_RIGHT
  • USART1
  • TFTLCD模块
  • IS62WV12816

以上硬件的电路图,在之前的例程中都有介绍过,请参考相应的例程

3. 软件设计

3.1 STM32CubeMX设置
  • RCC设置外接HSE,时钟设置为72M
  • PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • PA0设置为GPIO输入模式、下拉模式;PE3/PE4设置为GPIO输入模式、上拉模式
  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
  • 激活FSMC,详细请参考TFTLCD显示章节的设置
  • 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
3.2 MDK-ARM编程
  • 添加按键驱动文件key.c和key.h,参考按键输入例程
  • 添加TFTLCD驱动文件tftlcd.c 和tftlcd.h,参考TFTLCD显示例程
  • 添加IS62WV12816芯片驱动文件sram.c和sram.h,参考外部SRAM例程
  • 添加内存管理驱动文件malloc.c和malloc.h

几个重要函数:

/*释放内存*/
void myfree(u8 memx,void *paddr){
    
     
	u32 offset;   
	if(paddr==NULL)return;	//内存首地址  
 	offset=(u32)paddr-(u32)malloc_cortol.membase[memx];	//memx为所属内存块     
    my_mem_free(memx,offset);	//释放内存      
}  
/*分配内存*/
void *mymalloc(u8 memx,u32 size){
    
      
    u32 offset;   
	offset=my_mem_malloc(memx,size);  	//size表示内存大小(字节)   	 	   
    if(offset==0XFFFFFFFF)
    	return NULL;  
    else 
    	return (void*)((u32)malloc_cortol.membase[memx]+offset);  //返回分配到的内存首地址 
}  
/*重新分配内存*/
void *myrealloc(u8 memx,void *paddr,u32 size){
    
      
    u32 offset;    
    offset=my_mem_malloc(memx,size);  //memx表示所属内存块;size为要分配的内存大小(字节)	
    if(offset==0XFFFFFFFF)return NULL;     
    else{
    
      									   
		my_mem_cpy((void*)((u32)malloc_cortol.membase[memx]+offset),paddr,size);	//拷贝旧内存内容到新内存   
        myfree(memx,paddr); //paddr表示旧内存首地址
        return (void*)((u32)malloc_cortol.membase[memx]+offset); //返回新内存首地址
    }  
}
  • 在main.c文件下编写内存管理测试代码
int main(void){
    
    
  /* USER CODE BEGIN 1 */
	uint8_t key, i=0, *p=0,*tp=0;		 
	uint8_t paddr[18];						
	uint8_t sramx=0;							
  /* USER CODE END 1 */
  	HAL_Init();
  	SystemClock_Config();
  	MX_GPIO_Init();
  	MX_FSMC_Init();
  	MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
 	TFTLCD_Init();           				 
	FSMC_SRAM_Init();						 
	my_mem_init(SRAMIN);				
	my_mem_init(SRAMEX);				
	FRONT_COLOR=BROWN;
	LCD_DrawRectangle(25,25,215,135);
	FRONT_COLOR=RED;					
	LCD_ShowString(30,30,200,16,16,"ANDYXI STM32");	
	LCD_ShowString(30,50,200,16,16,"STM32CubeMX");	
	LCD_ShowString(30,70,200,16,16,"MALLOC TEST");
	FRONT_COLOR=BLACK;
	LCD_ShowString(30,90,200,16,16, "K_R:Malloc  K_L:Free");
	LCD_ShowString(30,110,200,16,16,"K_U:SRAMx   K_D:Write");
 	FRONT_COLOR=BLUE;
	LCD_ShowString(30,170,200,16,16,"SRAMIN");
	LCD_ShowString(30,190,200,16,16,"SRAMIN USED:   %");
	LCD_ShowString(30,210,200,16,16,"SRAMEX USED:   %");
  /* USER CODE END 2 */
  while (1){
    
    
    key=KEY_Scan(0);			
	switch(key){
    
    
		case 0:					
			break;
		case KEY_RIGHT_PRES:		
			p=mymalloc(sramx,2048);
			if(p!=NULL)sprintf((char*)p,"Memory Malloc Test%03d",i);
				break;
		case KEY_DOWN_PRES:		   
			if(p!=NULL){
    
    
				sprintf((char*)p,"Memory Malloc Test%03d",i);	 
				LCD_ShowString(30,250,200,16,16,p);			
			}
			break;
		case KEY_LEFT_PRES:			  
			myfree(sramx,p); p=0;			
				break;
		case KEY_UP_PRES:		 
 			sramx=!sramx;	
			if(sramx)LCD_ShowString(30,170,200,16,16,"SRAMEX");
			else LCD_ShowString(30,170,200,16,16,"SRAMIN");
			break;
		}
		if(tp!=p){
    
    
			tp=p;
			sprintf((char*)paddr,"P Addr:0X%08X",(uint32_t)tp);
			LCD_ShowString(30,230,200,16,16,paddr);	
			if(p)LCD_ShowString(30,250,200,16,16,p);
		    else LCD_Fill(30,250,239,266,WHITE);	
		}
		HAL_Delay(10);   
		i++;
		if((i%20)==0){
    
     
			LCD_ShowNum(30+96,190,my_mem_perused(SRAMIN),3,16);
			LCD_ShowNum(30+96,210,my_mem_perused(SRAMEX),3,16);
 			HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
 		}
	}
}

4. 下载验证

编译无误下载到开发板后,可以看到D1指示灯不断闪烁,KEY_UP可以切换当前操作内存(内部SRAM/外部SRAM),KEY_DOWN用于更新p的内容,KEY_LEFT用于释放内存,更新的数据都会显示在LCD屏上

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Chuangke_Andy/article/details/108987360