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.