正点原子内存管理学习和修改

        由于项目需要用到内存管理进行动态申请和释放,今天又重新学习了一下正点原子的内存管理实验,温习了一下内存管理的实质。首先先上正点原子内存管理的源代码:

malloc.c文件:

#include "./MALLOC/malloc.h"#if !(__ARMCC_VERSION >= 6010050)   /* 不是AC6编译器,即使用AC5编译器时 *//* 内存池(32字节对齐) */
static __align(32) uint8_t mem1base[MEM1_MAX_SIZE];                                                           /* 内部SRAM内存池 */
static __align(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((at(0X10000000)));                           /* 内部CCM内存池 */
static __align(32) uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((at(0XC01F4000)));                           /* 外部SDRAM内存池,前面2M给LTDC用了(1280*800*2) *//* 内存管理表 */
static MT_TYPE mem1mapbase[MEM1_ALLOC_TABLE_SIZE];                                                            /* 内部SRAM内存池MAP */
static MT_TYPE mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000 + MEM2_MAX_SIZE)));            /* 内部CCM内存池MAP */
static MT_TYPE mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0XC01F4000 + MEM3_MAX_SIZE)));            /* 外部SRAM内存池MAP */#else      /* 使用AC6编译器时 *//* 内存池(32字节对齐) */
static __ALIGNED(32) uint8_t mem1base[MEM1_MAX_SIZE];                                                         /* 内部SRAM内存池 */
static __ALIGNED(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((section(".bss.ARM.__at_0X10000000")));    /* 内部CCM内存池 */
static __ALIGNED(32) uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((section(".bss.ARM.__at_0XC01F4000")));    /* 外部SDRAM内存池,前面2M给LTDC用了(1280*800*2) *//* 内存管理表 */
static MT_TYPE mem1mapbase[MEM1_ALLOC_TABLE_SIZE];                                                            /* 内部SRAM内存池MAP */
static MT_TYPE mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((section(".bss.ARM.__at_0X1000F000")));       /* 内部CCM内存池MAP */
static MT_TYPE mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((section(".bss.ARM.__at_0XC1E30000")));       /* 外部SRAM内存池MAP */#endif/* 内存管理参数 */
const uint32_t memtblsize[SRAMBANK] = {MEM1_ALLOC_TABLE_SIZE, MEM2_ALLOC_TABLE_SIZE, MEM3_ALLOC_TABLE_SIZE};  /* 内存表大小 */
const uint32_t memblksize[SRAMBANK] = {MEM1_BLOCK_SIZE, MEM2_BLOCK_SIZE, MEM3_BLOCK_SIZE};                    /* 内存分块大小 */
const uint32_t memsize[SRAMBANK] = {MEM1_MAX_SIZE, MEM2_MAX_SIZE, MEM3_MAX_SIZE};                             /* 内存总大小 *//* 内存管理控制器 */
struct _m_mallco_dev mallco_dev=
{my_mem_init,                                /* 内存初始化 */my_mem_perused,                             /* 内存使用率 */mem1base, mem2base, mem3base,               /* 内存池 */mem1mapbase, mem2mapbase, mem3mapbase,      /* 内存管理状态表 */0, 0, 0,                                    /* 内存管理未就绪 */
};/*** @brief       复制内存* @param       *des : 目的地址* @param       *src : 源地址* @param       n    : 需要复制的内存长度(字节为单位)* @retval      无*/
void my_mem_copy(void *des, void *src, uint32_t n)  
{  uint8_t *xdes = des;uint8_t *xsrc = src; while (n--)*xdes++ = *xsrc++;  
}  /*** @brief       设置内存值* @param       *s    : 内存首地址* @param       c     : 要设置的值* @param       count : 需要设置的内存大小(字节为单位)* @retval      无*/
void my_mem_set(void *s, uint8_t c, uint32_t count)  
{  uint8_t *xs = s;  while (count--)*xs++ = c;  
}  /*** @brief       内存管理初始化* @param       memx : 所属内存块* @retval      无*/
void my_mem_init(uint8_t memx)  
{  my_mem_set(mallco_dev.memmap[memx], 0, memtblsize[memx] * 4);  /* 内存状态表数据清零 */mallco_dev.memrdy[memx] = 1;                                   /* 内存管理初始化OK */
}/*** @brief       获取内存使用率* @param       memx : 所属内存块* @retval      使用率(扩大了10倍,0~1000,代表0.0%~100.0%)*/
uint16_t my_mem_perused(uint8_t memx)  
{  uint32_t used = 0;  uint32_t i;for (i = 0; i < memtblsize[memx]; i++)  {if (mallco_dev.memmap[memx][i]){used++;}}return (used * 1000) / (memtblsize[memx]);  
}/*** @brief       内存分配(内部调用)* @param       memx : 所属内存块* @param       size : 要分配的内存大小(字节)* @retval      内存偏移地址*   @arg       0 ~ 0xFFFFFFFE : 有效的内存偏移地址*   @arg       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 (!mallco_dev.memrdy[memx]){mallco_dev.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 (!mallco_dev.memmap[memx][offset]){cmemb++;                                            /* 连续空内存块数增加 */}else {cmemb = 0;                                          /* 连续内存块清零 */}if (cmemb == nmemb)                                     /* 找到了连续nmemb个空内存块 */{for (i = 0;i < nmemb; i++)                          /* 标注内存块非空  */{  mallco_dev.memmap[memx][offset + i] = nmemb;  }return (offset * memblksize[memx]);                 /* 返回偏移地址  */}}return 0XFFFFFFFF;                                          /* 未找到符合分配条件的内存块 */
}/*** @brief       释放内存(内部调用)* @param       memx   : 所属内存块* @param       offset : 内存地址偏移* @retval      释放结果*   @arg       0, 释放成功;*   @arg       1, 释放失败;*   @arg       2, 超区域了(失败);*/
uint8_t my_mem_free(uint8_t memx, uint32_t offset)
{int i;if (!mallco_dev.memrdy[memx])                   /* 未初始化,先执行初始化 */{mallco_dev.init(memx);return 1;                                   /* 未初始化 */}if (offset < memsize[memx])                     /* 偏移在内存池内. */{int index = offset / memblksize[memx];      /* 偏移所在内存块号码 */int nmemb = mallco_dev.memmap[memx][index]; /* 内存块数量 */for (i = 0; i < nmemb; i++)                 /* 内存块清零 */{mallco_dev.memmap[memx][index + i] = 0;}return 0;}else{return 2;                                  /* 偏移超区了. */}
}/*** @brief       释放内存(外部调用)* @param       memx : 所属内存块* @param       ptr  : 内存首地址* @retval      无*/
void myfree(uint8_t memx, void *ptr)
{uint32_t offset;if (ptr == NULL)return;     /* 地址为0. */offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase[memx];my_mem_free(memx, offset);  /* 释放内存 */
}/*** @brief       分配内存(外部调用)* @param       memx : 所属内存块* @param       size : 要分配的内存大小(字节)* @retval      分配到的内存首地址.*/
void *mymalloc(uint8_t memx, uint32_t size)
{uint32_t offset;offset = my_mem_malloc(memx, size);if (offset == 0xFFFFFFFF)   /* 申请出错 */{return NULL;            /* 返回空(0) */}else                        /* 申请没问题, 返回首地址 */{return (void *)((uint32_t)mallco_dev.membase[memx] + offset);}
}/*** @brief       重新分配内存(外部调用)* @param       memx : 所属内存块* @param       *ptr : 旧内存首地址* @param       size : 要分配的内存大小(字节)* @retval      新分配到的内存首地址.*/
void *myrealloc(uint8_t memx, void *ptr, uint32_t size)
{uint32_t offset;offset = my_mem_malloc(memx, size);if (offset == 0xFFFFFFFF)                                                          /* 申请出错 */{return NULL;                                                                   /* 返回空(0) */}else                                                                               /* 申请没问题, 返回首地址 */{my_mem_copy((void *)((uint32_t)mallco_dev.membase[memx] + offset), ptr, size); /* 拷贝旧内存内容到新内存 */myfree(memx, ptr);                                                             /* 释放旧内存 */return (void *)((uint32_t)mallco_dev.membase[memx] + offset);                  /* 返回新内存首地址 */}
}

malloc.h文件:

#ifndef __MALLOC_H
#define __MALLOC_H#include "./SYSTEM/sys/sys.h"#ifndef NULL
#define NULL 0
#endif/* 定义三个内存池 */
#define SRAMIN                  0                               /* 内部内存池 */
#define SRAMCCM                 1                               /* CCM内存池(此部分SRAM仅仅CPU可以访问!!!) */
#define SRAMEX                  2                               /* 外部内存池(SDRAM) *//* 定义内存管理表类型,当外扩SDRAM的时候,必须使用uint32_t类型,否则可以定义成uint16_t,以节省内存占用 */
#define MT_TYPE     uint32_t#define SRAMBANK                3                               /* 定义支持的SRAM块数. *//* mem1内存参数设定.mem1完全处于内部SRAM里面. */
#define MEM1_BLOCK_SIZE         64                              /* 内存块大小为64字节 */
#define MEM1_MAX_SIZE          160 * 1024                       /* 最大管理内存 160K */
#define MEM1_ALLOC_TABLE_SIZE  MEM1_MAX_SIZE / MEM1_BLOCK_SIZE  /* 内存表大小 *//* mem2内存参数设定.mem2处于CCM,用于管理CCM(特别注意,这部分SRAM,仅CPU可以访问!!) */
#define MEM2_BLOCK_SIZE         64                              /* 内存块大小为64字节 */
#define MEM2_MAX_SIZE           60 * 1024                       /* 最大管理内存60K */
#define MEM2_ALLOC_TABLE_SIZE   MEM2_MAX_SIZE / MEM2_BLOCK_SIZE /* 内存表大小 *//* mem3内存参数设定.mem3的内存池处于外部SDRAM里面 */
#define MEM3_BLOCK_SIZE         64                              /* 内存块大小为64字节 */
#define MEM3_MAX_SIZE           28912 * 1024                    /* 最大管理内存28912K */
#define MEM3_ALLOC_TABLE_SIZE   MEM3_MAX_SIZE / MEM3_BLOCK_SIZE /* 内存表大小 *//* 内存管理控制器 */
struct _m_mallco_dev
{void (*init)(uint8_t);              /* 初始化 */uint16_t (*perused)(uint8_t);       /* 内存使用率 */uint8_t *membase[SRAMBANK];         /* 内存池 管理SRAMBANK个区域的内存 */uint32_t *memmap[SRAMBANK];         /* 内存管理状态表 */uint8_t  memrdy[SRAMBANK];          /* 内存管理是否就绪 */
};extern struct _m_mallco_dev mallco_dev;                         /* 在mallco.c里面定义 *//******************************************************************************************/void my_mem_set(void *s, uint8_t c, uint32_t count);            /* 设置内存 */
void my_mem_copy(void *des, void *src, uint32_t n);             /* 复制内存 */
void my_mem_init(uint8_t memx);                                 /* 内存管理初始化函数(外/内部调用) */
uint32_t my_mem_malloc(uint8_t memx, uint32_t size);            /* 内存分配(内部调用) */
uint8_t my_mem_free(uint8_t memx, uint32_t offset);             /* 内存释放(内部调用) */
uint16_t my_mem_perused(uint8_t memx) ;                         /* 获得内存使用率(外/内部调用)  *//* 用户调用函数 */
void myfree(uint8_t memx, void *ptr);                           /* 内存释放(外部调用) */
void *mymalloc(uint8_t memx, uint32_t size);                    /* 内存分配(外部调用) */
void *myrealloc(uint8_t memx, void *ptr, uint32_t size);        /* 重新分配内存(外部调用) */#endif

对于单个内存池来说在移植的时候只需要修改以下内容:

        malloc.h文件中的:内存块大小宏定义(MEMx_BLOCK_SIZE)、内存池大小宏定义(MEMx_MAX_SIZE)、内存管理表单个元素的大小(MT_TYPE),通过这三个参即可得到内存管理表元素的个数。

        malloc.c文件中需要修改的是:内存池的对其方式[__align(32)]、内存池的指定地址[__attribute__((at(0XC0000000)))],修改了这两个参数就能保证内存池的定义不会出错。

        对于内存管理的移植除了需要修改单个内存池的定义信息外还需要修改内存池的数量(SRAMBANK)、内存池的编号(#define SRAMIN      0 ;#define SRAMCCM      1  ;#define SRAMEX     2    ),同时还需要修改内存管理控制器结构体的参数(mallco_dev)。

从上面可以看出正点原子这份代码是基于“保证内存池的大小”的角度进行定义的,换句话说我是指定了了内存池的大小,但是没有指定整个内存池和内存管理表的大小,所以可以换一种方式进行定义:指定单个内存池全部的大小,然后自己程序自己去计算block的数量,这样就可以保证单个内存池所占用的内存不会超过指定的大小,修改如下:

/* mem1内存参数设定.mem1完全处于内部SRAM里面. */
#define MEM1_TOTAL_SIZE         64*1024 		/* 内部SRAM大小为64K字节 */
#define MEM1_BLOCK_SIZE         64                  /* 内存块大小为64字节 */
#define MEM1_ALLOC_TABLE_NUM    MEM1_TOTAL_SIZE/(MEM1_BLOCK_SIZE+sizeof(MT_TYPE)) /* block的数量=内存管理表的数量*/
#define MEM1_MAX_SIZE			MEM1_ALLOC_TABLE_NUM*MEM1_BLOCK_SIZE	/* 内存池的大小为:block的大小*数量 *//* mem2内存参数设定.mem2处于CCM,用于管理CCM(特别注意,这部分SRAM,仅CPU可以访问!!) */
#define MEM2_TOTAL_SIZE         64*1024 		/* CCM大小为64K字节 */
#define MEM2_BLOCK_SIZE         64                  /* 内存块大小为64字节 */
#define MEM2_ALLOC_TABLE_NUM    MEM2_TOTAL_SIZE/(MEM2_BLOCK_SIZE+sizeof(MT_TYPE)) /* block的数量=内存管理表的数量*/
#define MEM2_MAX_SIZE			MEM2_ALLOC_TABLE_NUM*MEM2_BLOCK_SIZE	/* 内存池的大小为:block的大小*数量 *//* mem3内存参数设定.mem3的内存池处于外部SDRAM里面 */
#define MEM3_TOTAL_SIZE         32*1024*1024 		/* SDRAM大小为32M字节 */
#define MEM3_BLOCK_SIZE         64                  /* 内存块大小为64字节 */
#define MEM3_ALLOC_TABLE_NUM    MEM3_TOTAL_SIZE/(MEM3_BLOCK_SIZE+sizeof(MT_TYPE)) /* block的数量=内存管理表的数量*/
#define MEM3_MAX_SIZE			MEM3_ALLOC_TABLE_NUM*MEM3_BLOCK_SIZE	/* 内存池的大小为:block的大小*数量 */

最后再附上单独管理SDRAM的测试代码:

malloc.c源代码#include "malloc.h"/* 内存池(32字节对齐) */
static __align(32) uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((at(0XC0000000)));                           /* 外部SDRAM内存池  SDRAM起始地址:0XC0000000*//* 内存管理表 */
static MT_TYPE mem3mapbase[MEM3_ALLOC_TABLE_NUM] __attribute__((at(0XC0000000 + MEM3_MAX_SIZE)));            /* 外部SRAM内存池MAP *//* 内存管理参数 */
const uint32_t memtblsize[SRAMBANK] = {MEM3_ALLOC_TABLE_NUM};   			 /* 内存表数量 */
const uint32_t memblksize[SRAMBANK] = {MEM3_BLOCK_SIZE};                   	 /* 单个block大小 */
const uint32_t memsize[SRAMBANK] = {MEM3_MAX_SIZE};                             /* 每个内存池的大小 *//* 内存管理控制器 */
struct _m_mallco_dev mallco_dev=
{my_mem_init,                                /* 内存初始化 */my_mem_perused,                             /* 内存使用率 */mem3base,             					  /* 内存池 */mem3mapbase,     							/* 内存管理状态表 */0,                                   	  /* 内存管理未就绪 */
};/*** @brief       复制内存* @param       *des : 目的地址* @param       *src : 源地址* @param       n    : 需要复制的内存长度(字节为单位)* @retval      无*/
void my_mem_copy(void *des, void *src, uint32_t n)  
{  uint8_t *xdes = des;uint8_t *xsrc = src; while (n--)*xdes++ = *xsrc++;  
}  /*** @brief       设置内存值* @param       *s    : 内存首地址* @param       c     : 要设置的值* @param       count : 需要设置的内存大小(字节为单位)* @retval      无*/
void my_mem_set(void *s, uint8_t c, uint32_t count)  
{  uint8_t *xs = s;  while (count--)*xs++ = c;  
}  /*** @brief       内存管理初始化* @param       memx : 所属内存块* @retval      无*/
void my_mem_init(uint8_t memx)  
{  my_mem_set(mallco_dev.memmap[memx], 0, memtblsize[memx] * 4);  /* 内存状态表数据清零 */mallco_dev.memrdy[memx] = 1;                                   /* 内存管理初始化OK */
}/*** @brief       获取内存使用率* @param       memx : 所属内存块* @retval      使用率(扩大了10倍,0~1000,代表0.0%~100.0%)*/
uint16_t my_mem_perused(uint8_t memx)  
{  uint32_t used = 0;  uint32_t i;for (i = 0; i < memtblsize[memx]; i++)  {if (mallco_dev.memmap[memx][i]){used++;}}return (used * 1000) / (memtblsize[memx]);  
}/*** @brief       内存分配(内部调用)* @param       memx : 所属内存块* @param       size : 要分配的内存大小(字节)* @retval      内存偏移地址*   @arg       0 ~ 0xFFFFFFFE : 有效的内存偏移地址*   @arg       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 (!mallco_dev.memrdy[memx]){mallco_dev.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 (!mallco_dev.memmap[memx][offset]){cmemb++;                                            /* 连续空内存块数增加 */}else {cmemb = 0;                                          /* 连续内存块清零 */}if (cmemb == nmemb)                                     /* 找到了连续nmemb个空内存块 */{for (i = 0;i < nmemb; i++)                          /* 标注内存块非空  */{  mallco_dev.memmap[memx][offset + i] = nmemb;  }return (offset * memblksize[memx]);                 /* 返回偏移地址  */}}return 0XFFFFFFFF;                                          /* 未找到符合分配条件的内存块 */
}/*** @brief       释放内存(内部调用)* @param       memx   : 所属内存块* @param       offset : 内存地址偏移* @retval      释放结果*   @arg       0, 释放成功;*   @arg       1, 释放失败;*   @arg       2, 超区域了(失败);*/
uint8_t my_mem_free(uint8_t memx, uint32_t offset)
{int i;if (!mallco_dev.memrdy[memx])                   /* 未初始化,先执行初始化 */{mallco_dev.init(memx);return 1;                                   /* 未初始化 */}if (offset < memsize[memx])                     /* 偏移在内存池内. */{int index = offset / memblksize[memx];      /* 偏移所在内存块号码 */int nmemb = mallco_dev.memmap[memx][index]; /* 内存块数量 */for (i = 0; i < nmemb; i++)                 /* 内存块清零 */{mallco_dev.memmap[memx][index + i] = 0;}return 0;}else{return 2;                                  /* 偏移超区了. */}
}/*** @brief       释放内存(外部调用)* @param       memx : 所属内存块* @param       ptr  : 内存首地址* @retval      无*/
void myfree(uint8_t memx, void *ptr)
{uint32_t offset;if (ptr == NULL)return;     /* 地址为0. */offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase[memx];my_mem_free(memx, offset);  /* 释放内存 */
}/*** @brief       分配内存(外部调用)* @param       memx : 所属内存块* @param       size : 要分配的内存大小(字节)* @retval      分配到的内存首地址.*/
void *mymalloc(uint8_t memx, uint32_t size)
{uint32_t offset;offset = my_mem_malloc(memx, size);if (offset == 0xFFFFFFFF)   /* 申请出错 */{return NULL;            /* 返回空(0) */}else                        /* 申请没问题, 返回首地址 */{return (void *)((uint32_t)mallco_dev.membase[memx] + offset);}
}/*** @brief       重新分配内存(外部调用)* @param       memx : 所属内存块* @param       *ptr : 旧内存首地址* @param       size : 要分配的内存大小(字节)* @retval      新分配到的内存首地址.*/
void *myrealloc(uint8_t memx, void *ptr, uint32_t size)
{uint32_t offset;offset = my_mem_malloc(memx, size);if (offset == 0xFFFFFFFF)                                                          /* 申请出错 */{return NULL;                                                                   /* 返回空(0) */}else                                                                               /* 申请没问题, 返回首地址 */{my_mem_copy((void *)((uint32_t)mallco_dev.membase[memx] + offset), ptr, size); /* 拷贝旧内存内容到新内存 */myfree(memx, ptr);                                                             /* 释放旧内存 */return (void *)((uint32_t)mallco_dev.membase[memx] + offset);                  /* 返回新内存首地址 */}
}malloc.h源代码#ifndef __MALLOC_H
#define __MALLOC_H#include "main.h"#ifndef NULL
#define NULL 0
#endif/* 定义三个内存池 */
#define SRAMEX                  0                               /* 外部内存池(SDRAM) *//* 定义内存管理表类型,当外扩SDRAM的时候,必须使用uint32_t类型,否则可以定义成uint16_t,以节省内存占用 */
#define MT_TYPE     uint32_t#define SRAMBANK                1                               /* 定义支持的SRAM块数. */#define MEM3_TOTAL_SIZE         32*1024*1024																			/* SDRAM大小为32M字节 */
#define MEM3_BLOCK_SIZE         64                              									/* 内存块大小为64字节 */
#define MEM3_ALLOC_TABLE_NUM    MEM3_TOTAL_SIZE/(MEM3_BLOCK_SIZE+sizeof(MT_TYPE)) /* block的数量=内存管理表的数量*/
#define MEM3_MAX_SIZE						MEM3_ALLOC_TABLE_NUM*MEM3_BLOCK_SIZE							/* 内存池的大小为:block的大小*数量 *//* 内存管理控制器 */
struct _m_mallco_dev
{void (*init)(uint8_t);              /* 初始化 */uint16_t (*perused)(uint8_t);       /* 内存使用率 */uint8_t *membase[SRAMBANK];         /* 内存池 管理SRAMBANK个区域的内存 */uint32_t *memmap[SRAMBANK];         /* 内存管理状态表 */uint8_t  memrdy[SRAMBANK];          /* 内存管理是否就绪 */
};extern struct _m_mallco_dev mallco_dev;                         /* 在mallco.c里面定义 *//******************************************************************************************/void my_mem_set(void *s, uint8_t c, uint32_t count);            /* 设置内存 */
void my_mem_copy(void *des, void *src, uint32_t n);             /* 复制内存 */
void my_mem_init(uint8_t memx);                                 /* 内存管理初始化函数(外/内部调用) */
uint32_t my_mem_malloc(uint8_t memx, uint32_t size);            /* 内存分配(内部调用) */
uint8_t my_mem_free(uint8_t memx, uint32_t offset);             /* 内存释放(内部调用) */
uint16_t my_mem_perused(uint8_t memx) ;                         /* 获得内存使用率(外/内部调用)  *//* 用户调用函数 */
void myfree(uint8_t memx, void *ptr);                           /* 内存释放(外部调用) */
void *mymalloc(uint8_t memx, uint32_t size);                    /* 内存分配(外部调用) */
void *myrealloc(uint8_t memx, void *ptr, uint32_t size);        /* 重新分配内存(外部调用) */#endifmain函数添加测试代码char *str = 0;
mallco_dev.init(SRAMEX);
str = mymalloc(SRAMEX, 50);
if(str)
{sprintf(str, "012345678900123456789001234567890");HAL_Delay(10);//这里因为SDRAM的读写需要时间所以一定需要插入一点延时,不然串口无打印信息printf("%s\n",str);myfree(SRAMEX,str);
}

测试结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/74287.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

时空观测者:俯身拾贝

目录 中华文明时空贝壳集&#xff08;按时间排序&#xff09;1. 良渚玉琮&#xff08;约公元前3300-2300年&#xff09;2. 三星堆青铜神树&#xff08;公元前1200年&#xff09;3. 殷墟甲骨文&#xff08;约公元前14世纪&#xff09;4. 京杭大运河&#xff08;公元前486年始建&…

护网期间监测工作全解析:内容与应对策略

护网期间监测工作全解析&#xff1a;内容与应对策略 一、引言 在数字化浪潮中&#xff0c;网络安全的重要性愈发凸显&#xff0c;护网行动作为保障关键信息基础设施安全的关键举措&#xff0c;备受瞩目。护网期间&#xff0c;监测工作是发现潜在威胁、防范攻击的重要防线。全…

【Centos7搭建Zabbix4.x监控HCL模拟网络设备:zabbix-server搭建及监控基础05

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 5.zabbix监控HCL模拟网络设备 在保证zabbix-server与HCL网络相通的情况下进行如下操作。 5.1创建主机群 配置-主机群-创建主机群 图 19 取名&#xff0c;添加。 图 20 5.2 创建监控…

趣味极简品牌海报艺术贴纸设计圆润边缘无衬线粗体装饰字体 Chunko Bold - Sans Serif Font

Chunko Bold 是一种功能强大的显示字体&#xff0c;体现了大胆极简主义的原则 – 当代设计的主流趋势。这种自信的字体将粗犷的几何形状与现代的趣味性相结合&#xff0c;具有圆润的边缘和强烈的存在感&#xff0c;与当今的极简主义设计方法完美契合。无论是用于鲜明的构图还是…

Spring Boot(十七):集成和使用Redis

Redis(Remote Dictionary Server,远程字典服务器)是一个开源的、基于内存的数据结构存储系统,它可以用作数据库、缓存和消息中间件。Spring Boot 中集成和使用Redis主要涉及以下几个步骤: 添加依赖 在项目的pom.xml文件中添加Redis的依赖。Spring Boot提供了对Redis的集…

2025-03-21 Unity 序列化 —— 自定义2进制序列化

文章目录 前言1 项目结构1.1 整体1.2 代码 2 实现2.1 Processor2.1.1 BaseType2.1.2 CollectionType2.1.3 CustomType 2.2 ByteFormatter2.3 ByteHelper 3 使用 前言 ​ BinaryFormatter 类可以将 C# 类对象快速转换为字节数组数据。 ​ 在网络开发时&#xff0c;不会使用 Bi…

为WordPress自定义一个留言板

要在WordPress中创建一个留言反馈表单&#xff0c;并实现后台管理功能&#xff0c;您可以按照以下步骤进行操作&#xff1a; 1. 创建留言反馈表单 首先&#xff0c;您需要使用一个表单插件来创建表单。推荐使用 Contact Form 7 或 WPForms。以下是使用 Contact Form 7 的示例…

嵌入式项目:利用心知天气获取天气数据实验方案

【实验目的】 1、利用心知天气服务器获取指定位置天气数据 2、将天气数据解析并可视化显示到OLED屏幕 【实验原理】 【实验步骤】 官网注册

go-zero学习笔记

内容不多&#xff0c;只有部分笔记&#xff0c;剩下的没有继续学下去&#xff0c;包括路由与处理器、日志中间件、请求上下文 文章目录 1、go-zero核心库1.1 路由与处理器1.2 日志中间件1.3 请求上下文 1、go-zero核心库 1.1 路由与处理器 package mainimport ("github…

【Go】Go语言继承-多态模拟

继承&#xff08;结构体嵌入&#xff09;多态&#xff08;接口实现和空接口&#xff09; 1. 继承&#xff08;结构体嵌入&#xff09; Go 语言没有传统的面向对象的继承机制&#xff0c;但可以通过“结构体嵌入”实现类似继承的效果。 结构体嵌入&#xff1a;在结构体中嵌入另…

kotlin知识体系(四) : inline、noinline、crossinline 关键字对应编译后的代码是怎样的 ?

kotlin中inline、noinline、crossinline 关键字的作用 在 Kotlin 里&#xff0c;inline、noinline 和 crossinline 这几个关键字和高阶函数紧密相关&#xff0c;它们能够对高阶函数的行为进行优化和控制。下面为你详细阐述它们的作用和原理。 inline 关键字 inline 关键字用…

LabVIEW FPGA与Windows平台数据滤波处理对比

LabVIEW在FPGA和Windows平台均可实现数据滤波处理&#xff0c;但两者的底层架构、资源限制、实时性及应用场景差异显著。FPGA侧重硬件级并行处理&#xff0c;适用于高实时性场景&#xff1b;Windows依赖软件算法&#xff0c;适合复杂数据处理与可视化。本文结合具体案例&#x…

深度解析 Android Matrix 变换(二):组合变换 pre、post

前言 在上一篇文章中&#xff0c;我们讲解了 Canvas 中单个变换的原理和效果&#xff0c;即缩放、旋转和平移。但是单个旋转仅仅是基础&#xff0c;Canvas 变换最重要的是能够随意组合各种变换以实现想要的效果。在这种情况下&#xff0c;就需要了解如何组合变换&#xff0c;以…

Java并发编程之CountDownLatch

1. 基本原理 计数器 CountDownLatch 在创建时需要指定一个初始计数值。这个值通常代表需要等待完成的任务数或线程数。 等待与递减 等待&#xff1a;调用 await() 方法的线程会被阻塞&#xff0c;直到计数器变为 0。递减&#xff1a;每当一个任务完成后&#xff0c;应调用 cou…

C++|GLog开源库的使用 如何实现自定义类型消息日志

参考&#xff1a; C glog使用教程与代码演示 C第三方日志库Glog的安装与使用超详解 GLOG从入门到入门 glog 设置日志级别_glog C版本代码分析 文章目录 日志等级自定义消息创建使用宏定义 日志等级 在 glog 中&#xff0c;日志的严重性是通过 LogSeverity 来区分的&#xff0c…

FAQ - VMware vSphere Web 控制台中鼠标控制不了怎么办?

问题描述 在VMware vSphere vCenter Server 的 Web 控制台中新建了一台 Windows Server 2008 R2 虚拟机&#xff0c;但是鼠标进入控制台后&#xff0c;可以看见鼠标光标&#xff0c;但是移动却没有反应。 根因分析 暂无。 解决方案 选中虚拟机>操作>编辑设置>添加新…

Rust+WebAssembly:开启浏览器3D渲染新时代

引言 在当今的 Web 开发领域&#xff0c;随着用户对网页交互体验的要求日益提高&#xff0c;3D 渲染技术在 Web 应用中的应用愈发广泛。从沉浸式的 Web 游戏&#xff0c;到逼真的虚拟展示场景&#xff0c;3D 渲染引擎承担着将虚拟 3D 世界呈现到用户浏览器中的关键任务。其性能…

在小米AX6000中添加tailscale monitor

经过测试&#xff0c;发现小米路由器中的tailscale可能会因为某种原因状态异常&#xff0c; 为了让tailscale恢复正常&#xff0c;所以又写了monitor用来监控&#xff1a; #!/bin/sh# Define Tailscale related paths TAILSCALED_PATH"/tmp/tailscale/tailscale_1.80.3_a…

表达式括号匹配(stack)(信息学奥赛一本通-1353)

【题目描述】 假设一个表达式有英文字母&#xff08;小写&#xff09;、运算符&#xff08;&#xff0c;—&#xff0c;∗&#xff0c;/&#xff09;和左右小&#xff08;圆&#xff09;括号构成&#xff0c;以“ ”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号…

IM 基于 WebRtc 视频通信功能

IM&#xff08;即时通讯&#xff09;基于 WebRTC&#xff08;Web Real-Time Communication&#xff0c;网页实时通讯&#xff09; 原理 WebRTC 是一种支持网页浏览器进行实时语音通话或视频通话的技术&#xff0c;它提供了一组 JavaScript API&#xff0c;使得在浏览器之间无…