In embedded bare metal programming, as a primary CODER. Often have to deal with the CPU, memory and so on. The CPU is the source of power for the system, and its importance is self-evident. However, in bare metal programming, the management of memory can not be ignored. If you pay a little attention, it may cause a memory leak, and the memory access will be abnormal. Causes the system to crash.
Embedded products, the stability requirements and strict. If you don’t move, you will crash, and that will be a big problem. The following is some of my own introduction to the memory management of embedded system bare metal programming.
1. Never use the malloc and free that comes with the system.Malloc and free are a good memory allocation method in PC programming. However, it is not necessarily easy to use in embedded. Since there is no MMU in the embedded bare metal programming, it is the memory management unit. Can not achieve dynamic mapping of memory (do not understand what is called dynamic mapping students, you can refer to the online information). In other words, in fact, malloc and free can not achieve dynamic memory management. This requires a dedicated memory area to be allocated as a mallo memory area during the startup phase. See the following information in the startup file startup_stm32f10x_md.s in STM32:
[plain] view plain copy
Heap_Size EQU 0x00000800 AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
Among them, Heap_Size defines a macro definition. The value is 0x00000800. Heap_Mem is a request for a contiguous memory of size Heap_Size. Simplified to the C language version as follows:
#define Heap_Size 0x00000800
Unsigned char Heap_Mem[Heap_Size] = {0};
The memory requested here, in the next code, is registered in the system for the malloc and free functions:
__user_iniTIal_stackheap
LDR R0, = Heap_Mem ; Returns the heap memory start address in the system
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size); Returns the end address of the heap memory in the system
LDR R3, = Stack_Mem
BX LR
As analyzed above, in fact, in the bare metal programming, the management of the heap memory. It's not intelligent, it's not how much you want to apply. Instead, use a fixed amount of memory for the allocation of heap memory. This is often not the best solution when designing. This memory, if it is applied for multiple times in different sizes, will cause memory fragmentation. Eventually it is impossible to apply for enough memory. Causes the system to run incorrectly. This is even more unacceptable in embedded systems where the memory is already small. So, the suggestion is to set that Heap_Size to 0. Give up on its use.
More deadly, some malloc, free functions, due to the lazy of engineering staff. The implementation may even be as follows:
Unsigned char mem_buffer[512];
Unsigned char *mem_offset = & mem_buffer;
Void *malloc(int size)
{
Unsigned char *tmp = mem_offset;
Mem_offset += size;
Return (void *)tmp;
}
Void free(void *mem)
{
Mem_offset = mem;
}
2. A better alternative: memory pool.
Maybe some students think: memory pool, what is this?
The memory pool, in a nutshell, is a pre-allocated block of fixed-size memory. Later, when you want to apply for a fixed-size memory, you can apply from the memory pool. When you are done, you have to put it back. Note that the memory pool can only request a fixed amount of memory for each application. There are many benefits to doing this:
(1) The size of each dynamic memory application is fixed, which can effectively prevent memory fragmentation. (As for why, think about it, each application is a fixed size, and the recycling is also a fixed size)
(2) High efficiency, no complicated memory allocation algorithm is needed. The time complexity of application and release can be achieved by O(1).
(3) Simple to implement and easy to use.
(4) The application for memory is released within the controllable range. It will not appear to run in the future, run, and then no longer apply for memory.
Memory pool, not a very powerful technology. In fact, it can be done very simply. Just need a linked list. At the time of initialization, the memory requested by the global variable is placed one by one in the linked list. At the time of application, you only need to take your head and return. When released, you only need to insert the memory into the linked list. The following is a simple example (using the transplanted Linux kernel linked list, the migration of the linked list, there will be time to analyze later):
#define MEM_BUFFER_LEN 5 //Number of memory blocks
#define MEM_BUFFER_SIZE 256 //The size of each block of memory
// The description of the memory pool, using the union, to reflect the wisdom of the poor. For example, what one of my classmates said: One byte, I can’t wait for it to be 8 bytes.
Typedef union mem {
Struct list_head list;
Unsigned char buffer[MEM_BUFFER_SIZE];
}mem_t;
staTIc union mem gmem[MEM_BUFFER_LEN];
LIST_HEAD(mem_pool);
//Allocate memory
Void *mem_pop()
{
Union mem *ret = NULL;
Psr_t psr;
Psr = ENTER_CRITICAL();
If(!list_empty(&mem_pool)) { //There is a memory pool available
Ret = list_first_entry(&mem_pool, union mem, list);
//printf("mem_pool = 0x%p ret = 0x%p", &mem_pool, &ret-"list);
List_del(&ret-"list);
}
EXIT_CRITICAL(psr);
Return ret;//-"buffer;
}
/ / Recycle memory
Void mem_push(void *mem)
{
Union mem *tmp = NULL;
Psr_t psr;
Tmp = (void *)mem;//container_of(mem, struct mem, buffer);
Psr = ENTER_CRITICAL();
List_add(&tmp-"list, &mem_pool);
//printf("free = 0x%p", &tmp-"list);
EXIT_CRITICAL(psr);
}
/ / Initialize the memory pool
Void mem_pool_init()
{
Int i;
Psr_t psr;
Psr = ENTER_CRITICAL();
For(i=0; i
List_add(&(gmem[i].list), &mem_pool);
//printf("add mem 0x%p", &(gmem[i].list));
}
EXIT_CRITICAL(psr);
}
We adopt the advanced technology imported from Europe, patented technology, specialized software to optimize the design for 11kV cast resin Dry Type Transformer. The core is made of cold-rolled grain-oriented silicon steel sheet which cut in step-lap by GEORG Germany TBA core cutting lines and laminated by the method of fifth-order step-by-step stacking technology, enabling the no-load performance of the core to improve greatly. The epoxy resin from American HUNTSMAN is adopted for the windings which casted in the vacuum resin casting machine imported from HEDRICH, Germany. The winding material ensures good permeability, no bubbles occur, which leads to minimum partial discharge. The HV and LV winding mate with each other tightly, which ensures solid strength of structure and capability to withstand short circuit and vibration. Under normal service condition, the service life of dry type transformer is 30 years. No crack will form on the surface of transformer winding due to temperature variation as long as the transformer runs under normal service condition.
11Kv Transformer,11Kv Dry Type Transformer,11Kv Cast-Resin Transformer,2500Kva Dry-Type Transformer
Hangzhou Qiantang River Electric Group Co., Ltd.(QRE) , https://www.qretransformer.com