Memory management experiment

More exchanges, welcome tiktok, 81849645041

objective

Understand internal memory and external memory, and realize the dynamic management of memory.

principle

Memory management refers to the technology of allocating and using computer memory resources when software is running. Its main purpose is how to allocate efficiently and quickly, and release and recycle memory resources at an appropriate time. There are many ways to implement memory management. In fact, they all need to implement two functions: malloc and free; Malloc function is used for memory application and free function is used for memory release.

A relatively simple way to achieve: block memory management.

As can be seen from the above figure, block memory management consists of memory pool and memory management table. The memory pool is equally divided into n blocks. The size of the corresponding memory management table is also n. each item of the memory management table corresponds to a piece of memory of the memory pool. The meaning of the item value in the memory management table is: when the item value is 0, it means that the corresponding memory block is not occupied; when the item value is non-zero, it means that the corresponding memory block has been occupied, and its value represents the number of memory blocks continuously occupied. For example, if the value of an item is 10, it means that a total of 10 memory blocks are allocated to an external pointer, including the memory block corresponding to this item.

The distribution direction of internal dimension is shown in the figure, which is from the top  to the bottom. That is, first find the empty memory from the end. When memory management is just initialized, all memory tables are cleared, indicating that no memory blocks are occupied.

Distribution principle

When pointer P calls malloc to apply for memory, first judge the number of memory blocks to be allocated by P (m), then start from item n and look down until m consecutive empty memory blocks are found (i.e. the corresponding memory management table entry is 0), and then set the values of these M memory management table entries to m (Mark occupied). Finally, Return the address of the last empty memory block to the pointer p to complete an allocation. Note that if there is not enough memory (no consecutive M blocks of free memory are found at last), NULL is returned to P, indicating that the allocation has failed.

Release principle

When p the requested memory runs out and needs to be released, call the free function. The free function first judges the memory block corresponding to the memory address pointed to by P, then finds the corresponding memory management table item, obtains the number of memory blocks m occupied by P (the value of the memory management table item is the number of allocated memory blocks), clears the values of these M memory management table items, marks the release, and completes a memory release.

prepare

MDK5 development environment.

STM32F4xx HAL library.

STM32F407 development board.

STM32F4xx reference manual.

STM32F4xx data book.

Circuit schematic diagram of STM32F407 development board.

step

  • Create header file bsp_mallco.h and define pins and related read-write functions.
#ifndef __BSP_SRAM_H
#ifndef __BSP_MALLOC_H
#define __BSP_MALLOC_H

#include "stm32f4xx.h"

#ifndef NULL
#define NULL 0
#endif

//Define three memory pools
#define SRAMIN 	  0 		// Internal memory pool
#define SRAMEX   1 		// External memory pool
#define SRAMCCM  2 		// CCM memory pool (this part of SRAM can only be accessed by CPU!!!)

#define SRAMBANK  	 three 	// Defines the number of SRAM blocks supported

//mem1 memory parameter setting mem1 is completely inside the internal SRAM
#define MEM1_BLOCK_SIZE 			 thirty-two 	  						// The memory block size is 32 bytes
#define MEM1_MAX_SIZE 			 100*1024   						// Maximum management memory 100K
#define MEM1_ALLOC_TABLE_SIZE 	 MEM1_MAX_SIZE/MEM1_BLOCK_SIZE  	// Memory table size

//mem2 memory parameter setting The memory pool of mem2 is in the external SRAM
#define MEM2_BLOCK_SIZE 			 thirty-two 	  						// The memory block size is 32 bytes
#define MEM2_MAX_SIZE 			 960 *1024   						// Maximum management memory 960K
#define MEM2_ALLOC_TABLE_SIZE 	 MEM2_MAX_SIZE/MEM2_BLOCK_SIZE  	// Memory table size
		 
//mem3 memory parameter setting mem3 is in CCM and is used to manage CCM (note that this part of SRAM is accessible only to CPU!!)
#define MEM3_BLOCK_SIZE 			 thirty-two 	  						// The memory block size is 32 bytes
#define MEM3_MAX_SIZE 			 60 *1024   						// Maximum management memory 60K
#define MEM3_ALLOC_TABLE_SIZE 	 MEM3_MAX_SIZE/MEM3_BLOCK_SIZE  	// Memory table size

//Memory management controller
struct _m_mallco_dev
{
	void (*init)(uint8_t);					//initialization
	uint8_t (*perused)(uint8_t);		  	    	//Memory usage
	uint8_t 	*membase[SRAMBANK];				//The memory pool manages the memory of SRAMBANK regions
	uint16_t *memmap[SRAMBANK]; 				//Memory management status table
	uint8_t  memrdy[SRAMBANK]; 				//Is memory management ready
};
extern struct _m_mallco_dev mallco_dev;	 //In mallco Defined in C

void mymemset(void *s, uint8_t c, uint32_t count);	//Set memory
void mymemcpy(void *des, void *src, uint32_t n);//Copy memory     
void my_mem_init(uint8_t memx);				//Memory management initialization function (external / internal call)
uint32_t my_mem_malloc(uint8_t memx, uint32_t size);	//Memory allocation (internal call)
uint8_t my_mem_free(uint8_t memx, uint32_t offset);		//Memory release (internal call)
uint8_t my_mem_perused(uint8_t memx);				//Get memory usage (external / internal calls) 

//User call function
void myfree(uint8_t memx, void *ptr);  			//Memory release (external call)
void *mymalloc(uint8_t memx, uint32_t size);			//Memory allocation (external call)
void *myrealloc(uint8_t memx, void *ptr, uint32_t size);//Reallocate memory (external call)
#endif
  • Create source file bsp_mallco.c and implement the read-write operation function
#include "bsp_mallco.h"

/***Memory pool (32 byte aligned)***/
// Internal SRAM memory pool
__align(32) uint8_t mem1base[MEM1_MAX_SIZE];
// External SRAM memory pool
__align(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((at(0x68000000)));
// Internal CCM memory pool
__align(32) uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((at(0x10000000)));


/***Memory management table***/
// Internal SRAM memory pool MAP
uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE];		
// External SRAM memory pool MAP
uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE)));	
// Internal CCM memory pool MAP
uint16_t mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000+MEM3_MAX_SIZE)));	


/***Memory management parameters***/
// Memory table size Total Bytes / block size (32 bytes)
const uint32_t memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE, MEM2_ALLOC_TABLE_SIZE, MEM3_ALLOC_TABLE_SIZE};	
// Memory block size 32 bytes
const uint32_t memblksize[SRAMBANK]={MEM1_BLOCK_SIZE, MEM2_BLOCK_SIZE, MEM3_BLOCK_SIZE};					
// Total memory size total bytes
const uint32_t memsize[SRAMBANK]={MEM1_MAX_SIZE, MEM2_MAX_SIZE, MEM3_MAX_SIZE};							


/***Memory management controller***/
struct _m_mallco_dev mallco_dev = 
{
	my_mem_init, //Memory initialization
	my_mem_perused, //Memory usage
	{mem1base, mem2base, mem3base}, //Memory pool
	{mem1mapbase, mem2mapbase, mem3mapbase}, //Memory management status table
	{0,0,0} //Memory management not ready
};

/**
*  Function name: mymemset
*  Description: write memory
*  Input: * s: first memory address 
*				c :Value to set 
*				count:Memory size to be set (in bytes)
*  Output: void
*/
void mymemset(void *s, uint8_t c, uint32_t count)	//Write memory
{
	uint8_t *xs = s;
	while(count--)
	{ 
		*xs++ = c;
	}
}

/**
*  Function name: mymemcpy
*  Description: copy memory
*  Input: * des: destination address
*				 *src:source address
*				    n:Length of memory to be copied (in bytes)
*  Output: void
*/
void mymemcpy(void *des,void *src,uint32_t n) //Copy memory 
{
	uint8_t *xdes = des;
	uint8_t *xsrc = des;
	while(n--)
	{
		*xdes++ = *xsrc++;
	}
}    

/**
*  Function name: my_mem_init
*  Description: memory management initialization function (external / internal call)
*  Input: memx memory block
*  Output: void
*/
void my_mem_init(uint8_t memx)
{
	// Memory status table data reset 
	mymemset(mallco_dev.memmap[memx], 0, memtblsize[memx]*2);
	// Clear all data of memory pool
	mymemset(mallco_dev.membase[memx], 0, memsize[memx]);
	// Memory management initialization OK
	mallco_dev.memrdy[memx] = 1;
}

/**
*  Function name: my_mem_malloc
*  Description: memory allocation (internal call)
*  Input: memx: memory block size: memory size to allocate (bytes)
*  Output: 0xfffffff, representing error; Other, memory offset address
*/
uint32_t my_mem_malloc(uint8_t memx, uint32_t size)
{
	signed long offset = 0;
	uint32_t nmemb; 			//Number of memory blocks required
	uint32_t cmemb = 0;  //Number of contiguous empty memory blocks
	uint32_t i;
	if(!mallco_dev.memrdy[memx]) //Not initialized, initialize first
	{ 
		mallco_dev.init(memx);
	}
	if(size == 0) //No allocation required
	{
		return 0xFFFFFFFF; 
	}
	nmemb = size/memblksize[memx]; //Gets the number of contiguous memory blocks to allocate
	if(size%memblksize[memx]){
		nmemb++;
	}
	for(offset=memtblsize[memx]-1;offset>=0;offset--) // Search the entire memory control area
  { 
		if(!mallco_dev.memmap[memx][offset]) // The number of consecutive empty memory blocks increases
		{ 
			cmemb++;
		}
		else // Continuous memory block reset
		{ 
			cmemb=0;
		}
		if(cmemb == nmemb) // Found consecutive nmemb empty memory blocks
		{ 
			for(i=0;i<nmemb;i++) // Label memory block is not empty
		  { 
				mallco_dev.memmap[memx][offset+i]=nmemb;
			}
			return offset*memblksize[memx]; // Return offset address
		}
	}
	
	return 0xFFFFFFFF; // No memory blocks matching the allocation criteria were found
}

/**
*  Function name: my_mem_free
*  Description: memory release (internal call)
*  Input: memx: memory block offset: memory address offset
*  Output: 0, released successfully; 1. Release failed;
*/
uint8_t my_mem_free(uint8_t memx, uint32_t offset)
{
	uint32_t i;
	if(!mallco_dev.memrdy[memx]) // Not initialized, initialize first
	{ 
		mallco_dev.init(memx);
		return 1;
	}
	if(offset < memsize[memx]) // The offset is in the memory pool 
	{ 
		uint32_t index = offset/memblksize[memx]; // Offset memory block number
		uint32_t nmemb = mallco_dev.memmap[memx][index]; // Number of memory blocks
		for(i=0;i<nmemb;i++) // Memory block reset
	  { 
			mallco_dev.memmap[memx][index+i]=0;
		}
		return 0;
	}
	else{
		return 2; //The offset is out of range
	}
}

/**
*  Function name: my_mem_perused
*  Description: get memory usage (external / internal calls)
*  Input: memx: memory block
*  Output: utilization rate (0 ~ 100)
*/
uint8_t my_mem_perused(uint8_t memx)
{
	uint32_t used = 0,i;
	for(i=0;i<memtblsize[memx];i++)
	{
		if(mallco_dev.memmap[memx][i])
		{
			used++;
		}
	}
	
	return (used*100)/memblksize[memx];
}


//User call function
/**
*  Function name: myfree
*  Description: memory release (external call)
*  Input: memx: memory block
*  Output: ptr: first memory address
*/
void myfree(uint8_t memx, void *ptr)
{
	uint32_t offset;
	if(ptr == NULL)
	{
		return;
	}
	offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase[memx];
	my_mem_free(memx, offset);
}

/**
*  Function name: mymalloc
*  Description: memory allocation (external call)
*  Input: memx: memory block size: memory size (bytes)
*  Output: the first memory address allocated to
*/
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)mallco_dev.membase[memx]+offset);
	}
}

/**
*  Function name: myrealloc
*  Description: reallocate memory (external call)
*  Input: memx: memory block * ptr: old memory first address size: memory size to be allocated (bytes)
*  Output: the first address of the newly allocated memory
*/
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
	{
		// Copy old memory contents to new memory 
		mymemcpy((void *)((uint32_t)mallco_dev.membase[memx]+offset), ptr, size);
		//Free old memory
		myfree(memx, ptr);
		//Return new memory address
		return (void *)((uint32_t)mallco_dev.membase[memx]+offset);
	}
}
  • main.c to switch different memory and read and write the data of the specified address.
#include "bsp_clock.h"
#include "bsp_uart.h"
#include "bsp_key.h"
#include "bsp_sram.h" 
#include "bsp_led.h"
#include "bsp_mallco.h"
#include <string.h>

int main(void)
{
	uint8_t i=0;	   
	uint8_t *p=0;
	uint8_t sramx=0;					//The default is internal sram
	uint8_t tx[] = "SRAMEX Malloc Test";
	uint32_t n = sizeof(tx);
	uint8_t rx[n];
	
	CLOCLK_Init(); // Initialize system clock
	UART_Init(); // Serial port initialization
	KEY_Init(); // Key initialization
	LED_Init(); // LED initialization
	SRAM_Init(); // SRAM initialization
	
	my_mem_init(SRAMIN); //Initialize internal memory pool
	my_mem_init(SRAMEX); //Initialize external memory pool
	my_mem_init(SRAMCCM);//Initialize CCM memory pool
	
	while(1)
	{
		uint8_t key = KEY_Scan(0);
		 if(key == 1) // KEY0 press
		 { 
			 p = mymalloc(sramx,2048); // Request 2K bytes
			  
			 if(p!=NULL && sramx == 0) // Internal memory pool
			 { 
				strcpy((char*)p,"SRAMIN Malloc Test"); // Write something to the internal memory pool
				HAL_Delay(100);
			  printf("%s \n",p); 
			 }
			 else if(p!=NULL && sramx == 2) // CCM memory pool
			 { 
				strcpy((char*)p,"SRAMCCM Malloc Test"); // Write something to CCM memory pool
				HAL_Delay(100);
			  printf("%s \n",p);  
			 }
			 else if(p!=NULL && sramx == 1) // External memory pool
			 { 
				SRAM_WriteBuff(p,tx,n); // Write something to CCM memory pool
				HAL_Delay(100);
				SRAM_ReadnBuff(p,rx,n);
				printf("%s \n",rx);
			 }
			 
			 myfree(sramx,p);
			  p=0;
			 i++;
		 }
		 
		 if(key == 2)
		 { // KEY1 press to switch SRAM
			sramx++;
			 if(sramx>2)
			 {
				 sramx=0;
			 }
			 
			 if(sramx == 0) printf("SRAMIN \n");
			 if(sramx == 1) printf("SRAMEX \n");
			 if(sramx == 2) printf("SRAMCCM \n"); 	
		 }
		 
		 HAL_Delay(50);
	}
}

phenomenon

Download the compiled program to the development board. Key1 switches the memory, and key0 writes data in the corresponding memory and prints the read data.

Keywords: C Embedded system Single-Chip Microcomputer stm32

Added by GKWelding on Mon, 28 Feb 2022 03:53:48 +0200