OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 13029|回复: 14

【正点原子探索者STM32F407开发板例程连载+教学】第42章 内存管理实验

[复制链接]

230

主题

1950

帖子

10

精华

论坛元老

Rank: 8Rank: 8

积分
4562
金钱
4562
注册时间
2010-12-14
在线时间
32 小时
发表于 2014-12-6 18:50:15 | 显示全部楼层 |阅读模式

第四十二章 内存管理实验

 


1.硬件平台:正点原子探索者STM32F407开发板 
2.软件平台:MDK5.1
 3.固件库版本:V1.4.0 

上一章,我们学会了使用STM32F4驱动外部SRAM,以扩展STM32F4的内存,加上STM32F4本身自带的192K字节内存,我们可供使用的内存还是比较多的。如果我们所用的内存都像上一节的testsram那样,定义一个数组来使用,显然不是一个好办法。

本章,我们将学习内存管理,实现对内存的动态管理。本章分为如下几个部分:

42.1 内存管理简介

42.2 硬件设计

42.3 软件设计

42.4 下载验证

 

42.1 内存管理简介

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

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

42.1.1 分块式内存管理原理

       从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成。内存池被等分为n块,对应的内存管理表,大小也为n,内存管理表的每一个项对应内存池的一块内存。

       内存管理表的项值代表的意义为:当该项值为0的时候,代表对应的内存块未被占用,当该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。比如某项值为10,那么说明包括本项对应的内存块在内,总共分配了10个内存块给外部的某个指针。

内寸分配方向如图所示,是从顶à底的分配方向。即首先从最末端开始找空内存。当内存管理刚初始化的时候,内存表全部清零,表示没有任何内存块被占用。

分配原理

当指针p调用malloc申请内存的时候,先判断p要分配的内存块数(m),然后从第n项开始,向下查找,直到找到m块连续的空内存块(即对应内存管理表项为0),然后将这m个内存管理表项的值都设置为m(标记被占用),最后,把最后的这个空内存块的地址返回指针p,完成一次分配。注意,如果当内存不够的时候(找到最后也没找到连续的m块空闲内存),则返回NULLp,表示分配失败。

释放原理

p申请的内存用完,需要释放的时候,调用free函数实现。free函数先判断p指向的内存地址所对应的内存块,然后找到对应的内存管理表项目,得到p所占用的内存块数目m(内存管理表项目的值就是所分配内存块的数目),将这m个内存管理表项目的值都清零,标记释放,完成一次内存释放。

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

 

42.2 硬件设计

本章实验功能简介:开机后,显示提示信息,等待外部输入。KEY0用于申请内存,每次申请2K字节内存。KEY1用于写数据到申请到的内存里面。KEY2用于释放内存。KEY_UP用于切换操作内存区(内部SRAM内存/外部SRAM内存/内部CCM内存)。DS0用于指示程序运行状态。本章我们还可以通过USMART调试,测试内存管理函数。

本实验用到的硬件资源有:

1)  指示灯DS0

2)  四个按键

3)  串口

4)  TFTLCD模块

5)  IS62WV51216

这些我们都已经介绍过,接下来我们开始软件设计。

42.3 软件设计

打开本章实验工程可以看到,我们新增了MALLOC分组,同时在分组中新建了文件malloc.c以及头文件malloc.h。 内存管理相关的函数和定义主要是在这两个文件中。

       打开malloc.c文件,代码如下:

//内存池(32字节对齐)

__align(32) u8 mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池

__align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000)));

//外部SRAM内存池

__align(32) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X10000000)));

//内部CCM内存池

//内存管理表

u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE];       //内部SRAM内存池MAP

u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000

+MEM2_MAX_SIZE)));        //外部SRAM内存池MAP

u16 mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000

+MEM3_MAX_SIZE)));        //内部CCM内存池MAP

//内存管理参数       

const u32 memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,

MEM2_ALLOC_TABLE_SIZE,MEM3_ALLOC_TABLE_SIZE};     //内存表大小

const u32 memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE,

MEM3_BLOCK_SIZE};                                                               //内存分块大小

const u32 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,                                                    //内存管理未就绪

}; 

//复制内存

//*des:目的地址

//*src:源地址

//n:需要复制的内存长度(字节为单位)

void mymemcpy(void *des,void *src,u32 n) 

    u8 *xdes=des;

       u8 *xsrc=src;

    while(n--)*xdes++=*xsrc++; 

//设置内存

//*s:内存首地址

//c :要设置的值

//count:需要设置的内存大小(字节为单位)

void mymemset(void *s,u8 c,u32 count) 

    u8 *xs = s; 

    while(count--)*xs++=c; 

}       

//内存管理初始化 

//memx:所属内存块

void my_mem_init(u8 memx) 

    mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零 

       mymemset(mallco_dev.membase[memx], 0,memsize[memx]);   //内存池所有数据清零 

       mallco_dev.memrdy[memx]=1;                                              //内存管理初始化OK 

//获取内存使用率

//memx:所属内存块

//返回值:使用率(0~100)

u8 my_mem_perused(u8 memx) 

    u32 used=0;u32 i;   

    for(i=0;i<memtblsize[memx];i++) { if(mallco_dev.memmap[memx])used++; }    

    return (used*100)/(memtblsize[memx]); 

//内存分配(内部调用)

//memx:所属内存块

//size:要分配的内存大小(字节)

//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址

u32 my_mem_malloc(u8 memx,u32 size) 

    signed long offset=0; 

    u32 nmemb;   //需要的内存块数 

       u32 cmemb=0;//连续空内存块数

    u32 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;//未找到符合分配条件的内存块 

//释放内存(内部调用)

//memx:所属内存块

//offset:内存地址偏移

//返回值:0,释放成功;1,释放失败

u8 my_mem_free(u8 memx,u32 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;//偏移超区了

//释放内存(外部调用)

//memx:所属内存块

//ptr:内存首地址

void myfree(u8 memx,void *ptr) 

       u32 offset;  

       if(ptr==NULL)return;//地址为0. 

      offset=(u32)ptr-(u32)mallco_dev.membase[memx];     

    my_mem_free(memx,offset);       //释放内存     

//分配内存(外部调用)

//memx:所属内存块

//size:内存大小(字节)

//返回值:分配到的内存首地址.

void *mymalloc(u8 memx,u32 size) 

    u32 offset;  

       offset=my_mem_malloc(memx,size);                       

    if(offset==0XFFFFFFFF)return NULL; 

    else return (void*)((u32)mallco_dev.membase[memx]+offset); 

//重新分配内存(外部调用)

//memx:所属内存块

//*ptr:旧内存首地址

//size:要分配的内存大小(字节)

//返回值:新分配到的内存首地址.

void *myrealloc(u8 memx,void *ptr,u32 size) 

    u32 offset;   

    offset=my_mem_malloc(memx,size);       

    if(offset==0XFFFFFFFF)return NULL;    

    else 

    {                                                               

           mymemcpy((void*)((u32)mallco_dev.membase[memx]+offset),ptr,size); 

//拷贝旧内存内容到新内存  

        myfree(memx,ptr);                  //释放旧内存

        return (void*)((u32)mallco_dev.membase[memx]+offset); //返回新内存首地址

    } 

}

       这里,我们通过内存管理控制器mallco_dev结构体(mallco_dev结构体见malloc.h),实现对三个内存池的管理控制。为甚

       首先,是内部SRAM内存池,定义为:

__align(32) u8 mem1base[MEM1_MAX_SIZE];       

       然后,是外部SRAM内存池,定义为:

__align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); 

最后,是内部CCM内存池,定义为:

__align(32) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X10000000)));        

       这里之所以要定义成3个,是因为这三个内存区域的地址都不一样,STM32F4内部内存分为两大块:1,普通内存(又分为主要内存和辅助内存,地址从:0X2000 0000开始,共128KB),这部分内存任何外设都可以访问。2CCM内存(地址从:0X1000 0000开始,共64KB),这部分内存仅CPU可以访问,DMA之类的不可以直接访问,使用时得特别注意!!

       而外部SRAM,地址是从0X6800 0000开始的,共1024KB。所以,这样总共有3部分内存,而内存池必须是连续的内存空间,才可以,这样3个内存区域,就有3个内存池,因此,分成了3块来管理。

其中,MEM1_MAX_SIZEMEM2_MAX_SIZEMEM3_MAX_SIZE为在malloc.h里面定义的内存池大小,外部SRAM内存池指定地址为0X6800 0000,也就是从外部SRAM的首地址开始的,CCM内存池从0X1000 0000开始,同样是从CCM内存的首地址开始的。但是,内部SRAM内存池的首地址则由编译器自动分配。__align(32)定义内存池为32字节对齐,以适应各种不同场合的需求。

此部分代码的核心函数为:my_mem_mallocmy_mem_free,分别用于内存申请和内存释放。思路就是我们在42.1接所介绍的那样分配和释放内存,不过这两个函数只是内部调用,外部调用我们使用的是mymallocmyfree两个函数。其他函数我们就不多介绍了,保存malloc.c,然后,打开malloc.h,代码如下:

#ifndef __MALLOC_H

#define __MALLOC_H

#include "stm32f4xx.h"#ifndef NULL

#define NULL 0

#endif

//定义三个内存池

#define SRAMIN        0            //内部内存池

#define SRAMEX       1            //外部内存池

#define SRAMCCM     2            //CCM内存池(此部分SRAM仅仅CPU可以访问!!!)

#define SRAMBANK   3            //定义支持的SRAM块数.  

//mem1内存参数设定.mem1完全处于内部SRAM里面.

#define MEM1_BLOCK_SIZE            32                      //内存块大小为32字节

#define MEM1_MAX_SIZE                100*1024             //最大管理内存 100K

#define MEM1_ALLOC_TABLE_SIZE       MEM1_MAX_SIZE/MEM1_BLOCK_SIZE      

//内存表大小

//mem2内存参数设定.mem2的内存池处于外部SRAM里面

#define MEM2_BLOCK_SIZE            32                       //内存块大小为32字节

#define MEM2_MAX_SIZE                960 *1024            //最大管理内存960K

#define MEM2_ALLOC_TABLE_SIZE       MEM2_MAX_SIZE/MEM2_BLOCK_SIZE      

//内存表大小        

//mem3内存参数设定.mem3处于CCM,用于管理CCM(特别注意,这部分SRAM,CPU

//以访问!!)

#define MEM3_BLOCK_SIZE                   32               //内存块大小为32字节

#define MEM3_MAX_SIZE                60 *1024             //最大管理内存60K

#define MEM3_ALLOC_TABLE_SIZE       MEM3_MAX_SIZE/MEM3_BLOCK_SIZE      

//内存表大小

//内存管理控制器

struct _m_mallco_dev

{

       void (*init)(u8);                                 //初始化

       u8 (*perused)(u8);                          //内存使用率

       u8   *membase[SRAMBANK];           //内存池 管理SRAMBANK个区域的内存

       u16 *memmap[SRAMBANK];           //内存管理状态表

       u8  memrdy[SRAMBANK];              //内存管理是否就绪

};

extern struct _m_mallco_dev mallco_dev;    //mallco.c里面定义

void mymemset(void *s,u8 c,u32 count);     //设置内存

void mymemcpy(void *des,void *src,u32 n);      //复制内存    

void my_mem_init(u8 memx);                   //内存管理初始化函数(/内部调用)

u32 my_mem_malloc(u8 memx,u32 size);   //内存分配(内部调用)

u8 my_mem_free(u8 memx,u32 offset);      //内存释放(内部调用)

u8 my_mem_perused(u8 memx);                //获得内存使用率(/内部调用)

////////////////////////////////////////////////////////////////////////////////

//用户调用函数

void myfree(u8 memx,void *ptr);              //内存释放(外部调用)

void *mymalloc(u8 memx,u32 size);           //内存分配(外部调用)

void *myrealloc(u8 memx,void *ptr,u32 size);//重新分配内存(外部调用)

#endif

这部分代码,定义了很多关键数据,比如内存块大小的定义:MEM1_BLOCK_SIZEMEM2_BLOCK_SIZEMEM3_BLOCK_SIZE,都是32字节。内存池总大小,内部SRAM内存池大小为100K,外部SRAM内存池大小为960K,内部CCM内存池大小为60K

MEM1_ALLOC_TABLE_SIZEMEM2_ALLOC_TABLE_SIZEMEM3_ALLOC_TABLE_

SIZE,则分别代表内存池123的内存管理表大小。

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

其他就不多说了,大家自行看代码理解就好。接下来我们看看主函数代码:

int main(void)

{           

       u8 key; u8 i=0; u8 *p=0;       u8 *tp=0;             

       u8 paddr[18];                       //存放P Addr:+p地址的ASCII

       u8 sramx=0;                        //默认为内部sram

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2

       delay_init(168);  //初始化延时函数

       uart_init(115200);         //初始化串口波特率为115200

       LED_Init();                                //初始化LED

      LCD_Init();                                //LCD初始化 

      KEY_Init();                                //按键初始化

      FSMC_SRAM_Init();                  //初始化外部SRAM 

       my_mem_init(SRAMIN);     //初始化内部内存池

       my_mem_init(SRAMEX);    //初始化外部内存池

       my_mem_init(SRAMCCM);  //初始化CCM内存池

      POINT_COLOR=RED;//设置字体为红色

       LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");      

       LCD_ShowString(30,70,200,16,16,"MALLOC TEST");    

       LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");

       LCD_ShowString(30,110,200,16,16,"2014/5/15");  

       LCD_ShowString(30,130,200,16,16,"KEY0:Malloc  KEY2:Free");

       LCD_ShowString(30,150,200,16,16,"KEY_UP:SRAMx KEY1:Read");

      POINT_COLOR=BLUE;//设置字体为蓝色

       LCD_ShowString(30,170,200,16,16,"SRAMIN");

       LCD_ShowString(30,190,200,16,16,"SRAMIN  USED:   %");

       LCD_ShowString(30,210,200,16,16,"SRAMEX  USED:   %");

       LCD_ShowString(30,230,200,16,16,"SRAMCCM USED:   %");

      while(1)

       {    

              key=KEY_Scan(0);//不支持连按 

              switch(key)

              {

                     case 0://没有按键按下  

                            break;

                     case KEY0_PRES: //KEY0按下

                            p=mymalloc(sramx,2048);//申请2K字节

                            if(p!=NULL)sprintf((char*)p,"Memory Malloc Test%03d",i);//p写入内容

                            break;

                     case KEY1_PRES: //KEY1按下    

                            if(p!=NULL)

                            {

                                   sprintf((char*)p,"Memory Malloc Test%03d",i);//更新显示内容       

                                   LCD_ShowString(30,270,200,16,16,p);       //显示P的内容

                            }

                            break;

                     case KEY2_PRES: //KEY2按下   

                            myfree(sramx,p);   //释放内存

                            p=0;                      //指向空地址

                            break;

                     case WKUP_PRES:       //KEY UP按下

                            sramx++;

                            if(sramx>2)sramx=0;

                            if(sramx==0)LCD_ShowString(30,170,200,16,16,"SRAMIN ");

                            else if(sramx==1)LCD_ShowString(30,170,200,16,16,"SRAMEX ");

                            else LCD_ShowString(30,170,200,16,16,"SRAMCCM");

                            break;

              }

              if(tp!=p)

              {

                     tp=p;

                     sprintf((char*)paddr,"P Addr:0X%08X",(u32)tp);

                     LCD_ShowString(30,250,200,16,16,paddr);       //显示p的地址

                     if(p)LCD_ShowString(30,270,200,16,16,p);//显示P的内容

                  else LCD_Fill(30,270,239,266,WHITE);     //p=0,清除显示

              }

              delay_ms(10);  

              i++;

              if((i%20)==0)//DS0闪烁.

              {

                     LCD_ShowNum(30+104,190,my_mem_perused(SRAMIN),3,16);//显示使用率

                     LCD_ShowNum(30+104,210,my_mem_perused(SRAMEX),3,16);//显示使用率

                     LCD_ShowNum(30+104,230,my_mem_perused(SRAMCCM),3,16);//使用率

                    LED0=!LED0;

             }

       }

}

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

42.4 下载验证

在代码编译成功之后,我们通过下载代码到ALIENTEK探索者STM32F4开发板上,得到如图42.4.1所示界面:

42.4.1 程序运行效果图

可以看到,所有内存的使用率均为0%,说明还没有任何内存被使用,此时我们按下KEY0,就可以看到内部SRAM内存被使用2%了,同时看到下面提示了指针p所指向的地址(其实就是被分配到的内存地址)和内容。多按几次KEY0,可以看到内存使用率持续上升(注意对比p的值,可以发现是递减的,说明是从顶部开始分配内存!),此时如果按下KEY2,可以发现内存使用率降低了2%,但是再按KEY2将不再降低,说明“内存泄露”了。这就是前面提到的对一个指针多次申请内存,而之前申请的内存又没释放,导致的“内存泄露”。

       KEY_UP按键,可以切换当前操作内存(内部SRAM内存/外部SRAM内存/内部CCM内存),KEY1键用于更新p的内容,更新后的内容将重新显示在LCD模块上面。

 

 

实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm 

正点原子探索者STM32F407开发板购买地址http://item.taobao.com/item.htm?id=41855882779

  

第四十二章 内存管理实验-STM32F4开发指南-正点原子探索者STM32开发板.pdf

555.57 KB, 下载次数: 1358

实验37 内存管理实验.zip

527.01 KB, 下载次数: 1476

我是开源电子网?网站管理员,对网站有任何问题,请与我联系!QQ:389063473Email:389063473@qq.com
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

15

主题

72

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
348
金钱
348
注册时间
2015-5-2
在线时间
29 小时
发表于 2015-5-2 22:19:19 | 显示全部楼层
请教原子哥,
// 释放内存(外部调用) 
// memx:所属内存块
// ptr:内存首地址 
void myfree(u8 memx, void *ptr)
{
u32 offset;
// 地址为0
if(ptr == NULL) return;
offset = (u32)ptr - (u32)malloc_dev.membase[memx];
mem_free(memx, offset);
}


// 重新分配内存(外部调用)
// memx:所属内存块
// *ptr:旧内存首地址
// size:要分配的内存大小(字节)
// 返回值:新分配到的内存首地址.
void *myrealloc(u8 memx, void *ptr, u32 size)
{
u32 offset;
offset = mem_malloc(memx, size);
if(offset == 0xFFFFFFFF)
return NULL;
else
{
// 拷贝旧内存内容到新内存
mymemcpy((void*)((u32)malloc_dev.membase[memx] + offset), ptr, size);
// 释放旧内存
myfree(memx, ptr);
// 返回新内存首地址
return ((void*)((u32)malloc_dev.membase[memx] + offset));
}
}


myfree函数的偏移地址是offset = (u32)ptr - (u32)malloc_dev.membase[memx];
myrealloc的偏移地址是(u32)malloc_dev.membase[memx] + offset)
想了好久不知道为啥是这样啊?!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-5-5 00:49:46 | 显示全部楼层
回复【2楼】ndzhzsdw:
---------------------------------
你觉得应该是如何?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

15

主题

72

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
348
金钱
348
注册时间
2015-5-2
在线时间
29 小时
发表于 2015-5-5 20:35:27 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
原子哥  我的理解是:mem_malloc先分配一块内存,返回值为实际地址。
              接着调用myfree,入口参数也是实际地址,但myfree函数里面所引用的memfree应用的是偏移地址,所以偏移地址offset = 实际地址 - 基地址
我想了两天  应该就是这样了。
回复 支持 反对

使用道具 举报

15

主题

72

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
348
金钱
348
注册时间
2015-5-2
在线时间
29 小时
发表于 2015-5-5 20:48:30 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
而且 通过这个 我也明白了最开始不懂的一个问题: 为什么要写一个mem_malloc  和  my_malloc    mem_free 和 my_free.
原来 mem_malloc  的入口参数是偏移地址,是给my_malloc 调用的。my_malloc 是用户函数,使用的是实际地址。嗯,就这样!
所以我们在main函数中直接用用户函数my_malloc    和   my_free  直接输入实际地址就可以了     它们自己内部会转换成偏移地址。
回复 支持 反对

使用道具 举报

6

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
95
金钱
95
注册时间
2014-4-18
在线时间
5 小时
发表于 2015-6-23 15:50:08 | 显示全部楼层

[mw_shl_code=c,true]//mem2内存参数设定.mem2的内存池处于外部SRAM里面 #define MEM2_BLOCK_SIZE 32 //内存块大小为32字节 #define MEM2_MAX_SIZE 960 *1024 //最大管理内存960K #define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //内存表大小 //内存池(32字节对齐) __align(32) u8 mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池 __align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); //外部SRAM内存池 __align(32) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X10000000))); //内部CCM内存池 //内存管理表 u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; //内部SRAM内存池MAP u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE))); //外部SRAM内存池MAP u16 mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000+MEM3_MAX_SIZE))); //内部CCM内存池MAP[/mw_shl_code]
这个外部内存管理表数组分配的是 "u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE]"等于30*2K byte.
 经过计算得MEM2_ALLOC_TABLE_SIZE = 30K个字节

而我们的外部内存总共只有1024K个字节,那这样加上管理的960K字节和管理表的60K字节等于1020K字节<1024K字节.

所以,用这种方法最多只能管理960K字节大小的内存了.
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-6-23 19:38:10 | 显示全部楼层
回复【6楼】Acksman:
---------------------------------
最多是2M字节,如果想管理更大,将u16改为u32,或者将块大小改大都可以
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

6

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
95
金钱
95
注册时间
2014-4-18
在线时间
5 小时
发表于 2015-6-24 15:12:12 | 显示全部楼层
回复【7楼】正点原子:
---------------------------------
不是很明白,能不能详细一点!
这样吧U16改为U32不是增加了管理表的空间了吗,这样不是在这个有限的1G空间里面,所能用的内存不是更加少了吗?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-6-24 22:56:30 | 显示全部楼层
回复【8楼】Acksman:
---------------------------------
这就是带来的坏处啊。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

7

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2014-10-6
在线时间
0 小时
发表于 2015-10-16 10:53:52 | 显示全部楼层


原子哥你好,请教一个问题。
芯片stm32f407。keil编译器,勾选上面两项后,外设128KRAM空间满后,keil能自动将多出的数据保存至CCM RAM吗?
回复 支持 反对

使用道具 举报

12

主题

26

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-4-4
在线时间
25 小时
发表于 2016-7-28 18:02:58 | 显示全部楼层
本帖最后由 落叶~ 于 2016-7-28 18:35 编辑

@正点原子 例程中主函数中释放内存的那段有问题呀,
case KEY2_PRES:        //KEY2°′&#207;&#194;         
myfree(sramx,p);//êí·&#197;&#196;ú′&#230;
p=0;                        //应该改为p=p+2048;                吧
break;
这里释放完是释放2kb的内存,p不能都重设为0,如果我设了8kb的内存,然后按下释放内存只会释放2kb再按就没用了,而释放完内存的地址不是0
回复 支持 反对

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2014-12-12
在线时间
1 小时
发表于 2016-8-17 00:03:28 | 显示全部楼层
有个问题请教下原子个,我使用CCM,把部分。o文件的data和bss放到这里面,如果代码里面有malloc,这时候会开辟内存失败,这是为什么
回复 支持 反对

使用道具 举报

7

主题

85

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
298
金钱
298
注册时间
2013-10-10
在线时间
5 小时
发表于 2016-9-2 14:35:38 | 显示全部楼层
好久不见,原子哥。请问怎么解决在多次释放内存之后的内存碎片的问题呢?
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2017-7-14
在线时间
2 小时
发表于 2017-7-14 16:07:47 | 显示全部楼层
正点原子 发表于 2015-6-23 19:38
回复【6楼】Acksman:
---------------------------------
最多是2M字节,如果想管理更大,将u16改为u32,或 ...

malloc内存管理程序移植,没有更改程序的任何代码,只是添加都我的工程中,编译出现错误:a value of type "void *" cannot be used to initialize an entity of type "u8 *",请教一下原子哥这个问题该如何解决?本来想发帖子问的,可是我的账号和我朋友的账号都发不了贴,显示405。谢谢原子哥!
回复 支持 反对

使用道具 举报

2

主题

45

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
382
金钱
382
注册时间
2013-3-28
在线时间
36 小时
发表于 2021-3-11 17:48:57 | 显示全部楼层
请教一个问题:MCU只有128K RAM,原程序已经使用30K,如果使用内存管理,但之前程序不改变(不用内存管理),之后增加的功能才使用。那再初始化内存池时,是不是要把30KRAM空间保留,只能初始化98K以内?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 12:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表