《STM32H7R7开发指南 V1.1 》第五十一章 内存管理实验

第五十一章 内存管理实验


       如果我们所用的内存都是直接定义一个数组来使用,灵活性会比较差,很多时候不能满足实际使用需求。为了解决这些问题,我们来学习内存管理,实现对内存的动态管理。

       本章分为如下几个小节:

       51.1 内存管理简介

       51.2 硬件设计

       51.3 程序设计

       51.4 下载验证

 

        51.1 内存管理简介

       内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效、快速的分配,并且在适当的时候释放和回收内存资源。内存管理的实现方法有很多种,其实最终都是要实现两个函数:malloc和free。malloc函数用来内存申请,free函数用于内存释放。

       本章,我们介绍一种比较简单的办法来实现:分块式内存管理。下面我们介绍一下该方法的实现原理,如图51.1.1所示:


图51.1.1 分块式内存管理原理


       从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成。内存池被等分为了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个内存管理表项目的值都清零,标记释放,完成一次内存释放。

       关于分块式内存管理的原理,我们就介绍到这里。


        51.2 硬件设计


       1. 例程功能

       开机后,显示提示信息,等待外部输入。KEY0用于申请内存,每次申请2K字节内存,KEY1用于释放内存,KEY_UP用于切换操作内存区(SRAMIN/SRAMEX/SRAM12 /SRAMDTCM/SRAMITCM,总共管理5个内存块)。

       LED0闪烁用于提示程序正在运行。


       2. 硬件资源


       1)LED灯

              LED0 – PD14


       2)独立按键  

              KEY0  - PE9

              KEY1  - PE8

              WK_UP – PC13 


       3)串口1 (PB14/PB15连接在板载USB转串口芯片CH340上面)


       4)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(包括MCU屏和RGB屏,都支持)


       5)HyperRAM


        51.3 程序设计  


       51.3.1 程序解析


       1. MALLOC代码

       这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。MALLOC驱动源码包括两个文件:malloc.c和malloc.h。 

       下面我们介绍malloc.h中比较重要的一些结构体和内存参数宏定义,其定义如下:

/* 内存池编号定义 */
#define SRAMIN      0       /* AXI-SRAM1~4内存池,AXI-SRAM1~4共456KB */
#define SRAMEX      1       /* XSPI2 HyperRAM内存池,XSPI2 HyperRAM共32MB */
#define SRAM12      2       /* AHB-SRAM1/2内存池,AHB-SRAM1~2,共32KB */
#define SRAMDTCM    3       
/* DTCM内存池,DTCM共64KB,此部分内存仅CPU和HPDMA(通过AHB)可以访问!!!! */
#define SRAMITCM    4       
/* ITCM内存池,DTCM共64KB,此部分内存仅CPU和HPDMA(通过AHB)可以访问!!!! */
 
#define SRAMBANK    5       /* 定义支持的SRAM块数. */
 
#define MT_TYPE     uint32_t
 
/* mem1内存参数设定.mem1是H7R内部的AXI-SRAM1~4 */
#define MEM1_BLOCK_SIZE         (64)  /* 内存块大小为64字节 */
#define MEM1_MAX_SIZE           ((0x00062000 / (MEM1_BLOCK_SIZE + sizeof(MT_TYPE))) * MEM1_BLOCK_SIZE)  /* AXI-SRAM1~4最大空闲0x00072000字节 */
#define MEM1_ALLOC_TABLE_SIZE   (MEM1_MAX_SIZE / MEM1_BLOCK_SIZE)                                       
 
/* mem2内存参数设定.mem2是H7R外部的XSPI2 HyperRAM */
#define MEM2_BLOCK_SIZE         (64)  /* 内存块大小为64字节 */
#define MEM2_MAX_SIZE           ((0x01E0C000 / (MEM2_BLOCK_SIZE + sizeof(MT_TYPE))) * MEM2_BLOCK_SIZE)  /* XSPI2 HyperRAM空闲0x01E0C000字节 */
#define MEM2_ALLOC_TABLE_SIZE   (MEM2_MAX_SIZE / MEM2_BLOCK_SIZE)                                       
 
/* mem3内存参数设定.mem3是H7R内部的AHB-SRAM1~2 */
#define MEM3_BLOCK_SIZE         (64)  /* 内存块大小为64字节 */
#define MEM3_MAX_SIZE           ((0x00008000 / (MEM3_BLOCK_SIZE + sizeof(MT_TYPE))) * MEM3_BLOCK_SIZE)  /* AHB-SRAM1~2空闲0x00008000字节 */
#define MEM3_ALLOC_TABLE_SIZE   (MEM3_MAX_SIZE / MEM3_BLOCK_SIZE)                                       
 
/* mem4内存参数设定.mem4是H7R内部的DTCM */
#define MEM4_BLOCK_SIZE         (64)  /* 内存块大小为64字节 */
#define MEM4_MAX_SIZE           ((0x00010000 / (MEM4_BLOCK_SIZE + sizeof(MT_TYPE))) * MEM4_BLOCK_SIZE)  /* DTCM空闲0x00010000字节 */
#define MEM4_ALLOC_TABLE_SIZE   (MEM4_MAX_SIZE / MEM4_BLOCK_SIZE)                                       
 
/* mem5内存参数设定.mem5是H7R内部的ITCM */
#define MEM5_BLOCK_SIZE         (64)  /* 内存块大小为64字节 */
#define MEM5_MAX_SIZE           ((0x00010000 / (MEM5_BLOCK_SIZE + sizeof(MT_TYPE))) * MEM5_BLOCK_SIZE)  /* ITCM空闲0x00010000字节 */
#define MEM5_ALLOC_TABLE_SIZE   (MEM5_MAX_SIZE / MEM5_BLOCK_SIZE)

       这部分代码,定义了很多关键数据,比如内存块大小的定义:MEM1_BLOCK_SIZE、MEM2_BLOCK_SIZE、MEM3_BLOCK_SIZE、MEM4_BLOCK_SIZE和MEM5_BLOCK_SIZE,都是64字节。

       MEM1_ALLOC_TABLE_SIZE ~ MEM5_ALLOC_TABLE_SIZE,则分别代表内存池1 ~ 5的内存管理表大小。

       从这里可以看出,如果内存分块越小,那么内存管理表就越大,当分块为4字节1个块的时候,内存管理表就和内存池一样大了(管理表的每项都是uint32_t类型)。显然是不合适的,我们这里取64字节,比例为1:16,内存管理表相对就比较小了。

       通过这个内存管理控制器_m_malloc_dev结构体,我们把分块式内存管理的相关信息,其初始化函数、获取使用率、内存池、内存管理表以及内存管理的状态保存下来,实现对内存池的管理控制。

       下面介绍malloc.c文件,其中,内存池、内存管理表、内存管理参数和内存管理控制器的定义如下:

/* 内存池定义 */
static uint8_t mem1base[MEM1_MAX_SIZE] __attribute__((aligned(64)));                                                        /* AXI-SRAM1~2内存池 */
static uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((aligned(64))) __attribute__((section(".bss.ARM.__at_0x701F4000")));   
/* XSPI2 HyperRAM内存池,LTDC使用前1280 * 800 * 2=0x1F4000字节空间 */
static uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((aligned(64))) __attribute__((section(".bss.ARM.__at_0x30000000")));   /* AHB-SRAM1~2内存池 */
static uint8_t mem4base[MEM4_MAX_SIZE] __attribute__((aligned(64))) __attribute__((section(".bss.ARM.__at_0x20000000")));   /* DTCM内存池 */
static uint8_t mem5base[MEM5_MAX_SIZE] __attribute__((aligned(64))) __attribute__((section(".bss.ARM.__at_0x00000000")));   /* ITCM内存池 */
 
/* 内存管理表 */
static MT_TYPE mem1mapbase[MEM1_ALLOC_TABLE_SIZE];                                                                          /* AXI-SRAM1~2内存池MAP */
static MT_TYPE mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((section(".bss.ARM.__at_0x71E3B840")));                     
/* XSPI2 HyperRAM内存池MAP */
static MT_TYPE mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((section(".bss.ARM.__at_0x30007840")));                     
/* AHB-SRAM1~2内存池MAP */
static MT_TYPE mem4mapbase[MEM4_ALLOC_TABLE_SIZE] __attribute__((section(".bss.ARM.__at_0x2000F0C0")));                     
/* DTCM内存池MAP */
static MT_TYPE mem5mapbase[MEM5_ALLOC_TABLE_SIZE] __attribute__((section(".bss.ARM.__at_0x0000F0C0")));                     
/* ITCM内存池MAP */
 
/* 内存管理参数 */
const uint32_t memtblsize[SRAMBANK] = { MEM1_ALLOC_TABLE_SIZE, MEM2_ALLOC_TABLE_SIZE, MEM3_ALLOC_TABLE_SIZE,
MEM4_ALLOC_TABLE_SIZE, MEM5_ALLOC_TABLE_SIZE};                                      /* 内存表大小 */
 
const uint32_t memblksize[SRAMBANK] = { MEM1_BLOCK_SIZE, MEM2_BLOCK_SIZE, MEM3_BLOCK_SIZE,  MEM4_BLOCK_SIZE, MEM5_BLOCK_SIZE};                                                  /* 内存分块大小 */
 
const uint32_t memsize[SRAMBANK] = { MEM1_MAX_SIZE, MEM2_MAX_SIZE, MEM3_MAX_SIZE, MEM4_MAX_SIZE, MEM5_MAX_SIZE};                                                         /* 内存总大小 */
 
/* 内存管理控制器 */
struct _m_mallco_dev mallco_dev =
{
    my_mem_init,                                         /* 内存初始化 */
    my_mem_perused,                                      /* 内存使用率 */
    mem1base, mem2base, mem3base, mem4base, mem5base,    /* 内存池 */
mem1mapbase, mem2mapbase, mem3mapbase, mem4mapbase, mem5mapbase,   
/* 内存管理状态表 */
    0, 0, 0, 0, 0,                                       /* 内存管理未就绪 */
};

       我们通过内存管理控制器mallco_dev结构体,实现对六个内存池的管理控制。

       第一个是AXI-SRAM1~2内存池,定义为:

static uint8_t mem1base[MEM1_MAX_SIZE] __attribute__((aligned(64)));

       第二个是XSPI2 HyperRAM内存池,定义为:

static uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((aligned(64))) __attribute__((section(".bss.ARM.__at_0x701F4000")));

       第三个是AHB-SRAM1~2内存池,定义为:

static uint8_t mem3base[MEM3_MAX_SIZE] __attribute__((aligned(64))) __attribute__((section(".bss.ARM.__at_0x30000000")));

       第四个是DTCM内存池,定义为:

static uint8_t mem4base[MEM4_MAX_SIZE] __attribute__((aligned(64))) __attribute__((section(".bss.ARM.__at_0x20000000")));

       第五个是ITCM内存池,定义为:

static uint8_t mem5base[MEM5_MAX_SIZE] __attribute__((aligned(64))) __attribute__((section(".bss.ARM.__at_0x00000000")));

       因为STM32H7R7内部有5个连续的内存块,因此总共需要5个内存池,AXI SRAM内存池的首地址由编译器指定,其他几个内部内存池的首地址就是相应SRAM的首地址。

       其中,__aligned(64)定义内存池为64字节对齐,以适应各种不同场合的需求。

       这样总共有5部分内存,分成5个内存池,每个内存池需要一个内存管理表,因此又有5个内存管理表:mem1mapbase~ mem5mapbase,内存管理表所占内存,也指定在对应的内存块里面分配。因此:内存池+内存管理表,基本上就占了整个内存块的全部空间了。

       下面介绍其他的malloc代码,具体如下:

/**
 * @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)
{
uint8_t mttsize = sizeof(MT_TYPE);  
/* 获取memmap数组的类型长度(uint16_t /uint32_t)*/
my_mem_set(mallco_dev.memmap[memx], 0, memtblsize[memx] * mttsize); 
/* 内存状态表数据清零 */
    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     : 无效的内存偏移地址
 */
static 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, 超区域了(失败);
 */
static 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代码的核心函数:my_mem_malloc和my_mem_free,分别用于内存申请和内存释放。思路就是前面51.1所介绍的分配内存和释放内存,不过在这里,这两个函数知识内部调用,外部调用我们另外定义了mymalloc和myfree两个函数,其他函数我们就不多介绍了。


       2. main.c代码

       main.c代码如下:

/* 内存池名称定义 */
static const char *sramx_tbl[SRAMBANK] = {"SRAMIN  ", "SRAMEX  ", "SRAM12  ", "SRAMDTCM", "SRAMITCM"};
 
int main(void)
{
    uint8_t t = 0;
    uint8_t key;
    char *p = NULL;
    char *tp = (char *)sramx_tbl[0];
    uint8_t sramx = 0;
    char paddr[20];
    uint16_t memused;
    
    sys_mpu_config();                   /* 配置MPU */
    sys_cache_enable();                 /* 使能Cache */
    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(300, 6, 2);    /* 配置时钟,600MHz */
    delay_init(600);                    /* 初始化延时 */
    usart_init(115200);                 /* 初始化串口 */
    led_init();                         /* 初始化LED */
    key_init();                         /* 初始化按键 */
    hyperram_init();                    /* 初始化HyperRAM */
    lcd_init();                         /* 初始化LCD */
    my_mem_init(SRAMIN);                /* 初始化AXI-SRAM1~4内存池 */
    my_mem_init(SRAMEX);                /* 初始化XSPI2 HyperRAM内存池 */
    my_mem_init(SRAM12);                /* 初始化AHB-SRAM1~2内存池 */
    my_mem_init(SRAMDTCM);              /* 初始化DTCM内存池 */
    my_mem_init(SRAMITCM);              /* 初始化ITCM内存池 */
    
    lcd_show_string(30, 40, 200, 16, 16, "STM32", RED);
    lcd_show_string(30, 60, 200, 16, 16, "MALLOC TEST", RED);
    lcd_show_string(30, 80, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 100, 200, 16, 16, "KEY0:Malloc & WR & Show", RED);
    lcd_show_string(30, 120, 200, 16, 16, "KEY_UP:SRAMx KEY1:Free", RED);
    lcd_show_string(30, 140, 200, 16, 16, "SRAMIN ", BLUE);
    lcd_show_string(30, 156, 200, 16, 16, "SRAMIN   USED:", BLUE);
    lcd_show_string(30, 172, 200, 16, 16, "SRAMEX   USED:", BLUE);
    lcd_show_string(30, 188, 200, 16, 16, "SRAM12   USED:", BLUE);
    lcd_show_string(30, 204, 200, 16, 16, "SRAMDTCM USED:", BLUE);
    lcd_show_string(30, 220, 200, 16, 16, "SRAMITCM USED:", BLUE);
    
    while (1)
    {
        key = key_scan(0);
        if (key == KEY0_PRES)
        {
            /* 申请内存 */
            p = (char *)mymalloc(sramx, 2048);
            if (p != NULL)
            {
                /* 显示申请到内存的地址 */
                sprintf(paddr, "p Addr: 0x%08X", (uint32_t)p);
                lcd_show_string(30, 260, 200, 16, 16, paddr, BLUE);
                /* 写入内存并显示内容 */
                sprintf(p, "Memory Malloc Test%03d", t);
                lcd_show_string(30, 280, 200, 16, 16, p, BLUE);
            }
        }
        else if (key == KEY1_PRES)
        {
            /* 释放内存 */
            myfree(sramx, p);
            p = NULL;
            lcd_fill(30, 260, 30 + 200, 280 + 16, WHITE);
        }
        else if (key == WKUP_PRES)
        {
            /* 切换内存池 */
            if (++sramx > (SRAMBANK - 1))
            {
                sramx = 0;
            }
            lcd_show_string(30, 140, 200, 16, 16, (char *)sramx_tbl[sramx],
            BLUE);
        }
        
        /* 显示内存使用率 */
        if (tp != p)
        {
            tp = p;
            
            lcd_fill(30 + 112, 156, 30 + 112 + 200, 236 + 16, WHITE);
            
            memused = my_mem_perused(SRAMIN);
            sprintf((char *)paddr, "%d.%01d%%", memused / 10, memused % 10);
            lcd_show_string(30 + 112, 156, 200, 16, 16, (char *)paddr, BLUE);
   /* 显示AXI-SRAM1~4内存池使用率 */
            
            memused = my_mem_perused(SRAMEX);
            sprintf((char *)paddr, "%d.%01d%%", memused / 10, memused % 10);
            lcd_show_string(30 + 112, 172, 200, 16, 16, (char *)paddr, BLUE); 
  /* 显示XSPI2 HyperRAM内存池使用率 */
            
            memused = my_mem_perused(SRAM12);
            sprintf((char *)paddr, "%d.%01d%%", memused / 10, memused % 10);
            lcd_show_string(30 + 112, 188, 200, 16, 16, (char *)paddr, BLUE); 
            /* 显示AHB-SRAM1~2内存池使用率 */
            
            memused = my_mem_perused(SRAMDTCM);
            sprintf((char *)paddr, "%d.%01d%%", memused / 10, memused % 10);
            lcd_show_string(30 + 112, 204, 200, 16, 16, (char *)paddr, BLUE); 
            /* 显示DTCM内存池使用率 */
            
            memused = my_mem_perused(SRAMITCM);
            sprintf((char *)paddr, "%d.%01d%%", memused / 10, memused % 10);
            lcd_show_string(30 + 112, 220, 200, 16, 16, (char *)paddr, BLUE);
            /* 显示ITCM内存池使用率 */
        }
        
        if (++t == 20)
        {
            t = 0;
            LED0_TOGGLE();
        }
        
        delay_ms(10);
    }
}

       该部分代码比较简单,主要是对mymalloc和myfree的应用。不过这里提醒大家,如果对一个指针进行多次内存申请,而之前的申请又没释放,那么将造成“内存泄露”,这是内存管理所不希望发生的,久而久之,可能导致无内存可用的情况!所以,在使用的时候,请大家一定记得,申请的内存在用完以后,一定要释放。


        51 .4 下载验证

       将程序下载到开发板后,可以看到LED0不停的闪烁,提示程序已经在运行了。

       刚开始,所有内存的使用率均为0%,说明还没有任何内存被使用,此时我们按下KEY0,就可以看到内部SRAM内存被使用0.5%了,如下图所示:


请使用浏览器的分享功能分享到微信等