stm32内存管理总结

发布者:MysticGarden最新更新时间:2017-09-06 来源: eefocus关键字:stm32  内存管理 手机看文章 扫描二维码
随时随地手机看文章

一、内存管理简介

内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。内存管理的实现方法有很多种,他们其实最终都是要实现 2 个函数:malloc 和 free;malloc 函数用于内存申请,free 函数用于内存释放。本章,我们介绍一种比较简单的办法来实现:分块式内存管下面我们介绍一下该方法的实现原理,如图 42.1.1 所示:

                                      

内存管理表的项值代表的意义为:当该项值为 0 的时候,代表对应的内存块未被占用,当该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。比如某项值为 10,那么说明包括本项对应的内存块在内,总共分配了 10 个内存块给外部的某
个指针。内寸分配方向如图所示,是从顶到底的分配方向。即首先从最末端开始找空内存。当内存管理刚初始化的时候,内存表全部清零,表示没有任何内存块被占用。


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


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

四、部分驱动函数

//内存池(32字节对齐)
__align(32) u8 mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池
__align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000)));//外部SRAM内存池
//内存管理表
u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; //内部SRAM内存池MAP
u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE)));//外部SRAM内存池MAP
//内存管理参数   
const u32 memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE};//内存表大小
const u32 memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE};//内存分块大小
const u32 memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE};//内存总大小




//内存管理控制器
struct _m_mallco_dev mallco_dev=
{
my_mem_init,  //内存初始化
my_mem_perused,//内存使用率
mem1base,mem2base,//内存池
mem1mapbase,mem2mapbase,//内存管理状态表
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    {  
        if(mallco_dev.memmap[memx][i])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            {  
                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    {  
        int index=offset/memblksize[memx]; //偏移所在内存块号码  
        int nmemb=mallco_dev.memmap[memx][index];  //内存块数量
        for(i=0;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);  


关键字:stm32  内存管理 引用地址:stm32内存管理总结

上一篇:基于stm32f103zet6之nor flash的学习
下一篇:基于stm32f103zet6之UC/OS_II的学习2(初步分析OS--点灯大法)

推荐阅读最新更新时间:2024-03-16 15:36

STM32 时钟RCC相关配置参考stm32f10x_rcc.h
1. 时钟使能配置: RCC_LSEConfig()、RCC_HSEConfig()、 RCC_HSICmd()、RCC_LSICmd()、RCC_PLLCmd()...... 2. 时钟源相关配置: RCC_PLLConfig()、RCC_SYSCLKConfig()、 RCC_RTCCLKConf()..... 3. 分频系数选择配置: RCC_HCLKConfig()、RCC_PCLK1Config()、RCC_PCLK2Config()...... 4. 外设时钟使能: RCC_APB1PeriphClockCmd(); // APB1线上外设时钟使能 RCC_APB2PeriphC
[单片机]
<font color='red'>STM32</font> 时钟RCC相关配置参考stm32f10x_rcc.h
意法半导体新型STM32系列获ARM RealView微控制器开发工具包支持
中国上海,2007年6月27日 —— ARM公司(伦敦证交所:ARM;纳斯达克:ARMHY)宣布即日起,RealView微控制器开发工具包将支持意法半导体基于ARM Cortex-M3处理器的全新 STM32F1xx系列器件。    STM32F101 (接入行)和STM32F103 (性能行)将是意法半导体首个基于ARM Cortex-M3处理器的器件系列,兼具卓越的高性能和低功耗,待机功耗仅为2?A。该系列器件拥有高达72MHz的CPU时钟速度、128Kbyte片上闪存ROM及20Kbyte片上RAM,还包括A/D、CAN、USB、SPI、I2C等众多外设及多达80个GPIO。    RealView微控制器开发工具包3.1可
[新品]
STM32之定时器
一、定时器简介 1、时钟来源 2、定时器结构(以基本定时器为例) 二、基本定时器的编程方法 1、基本定时器的寄存器 2、例程 /** * @brief 定时器6的初始化,定时周期0.01s * @param 无 * @retval 无 */ void TIM6_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /*AHB = 72MHz,RCC_CFGR的PPRE1 = 2,所以APB1 = 36MHz,TIM2CLK = APB1*2 = 72MHz */ RCC_APB1PeriphClockCmd(RCC_APB1Per
[单片机]
<font color='red'>STM32</font>之定时器
STM32--读写内部Flash
Flash模块组织 存储器被组织为程序存储器模块,数据EEPROM模块和信息块。 程序存储器块分为4 KB的扇区,每个扇区都是进一步分成16页,每页256字节。 程序存储器页面擦除 该操作用于擦除程序存储器中的页面(64个字)。要做到这一点: ●解锁FLASH_PECR寄存器 1.将PEKEY1 = 0x89ABCDEF写入编程/擦除密钥寄存器(FLASH_PEKEYR) 2.将PEKEY2 = 0x02030405写入编程/擦除密钥寄存器(FLASH_PEKEYR) ●解锁程序存储器 ●解锁FLASH_PECR寄存器 1. 将PRGKEY1 = 0x8C9DAEBF写入程序存储器密钥寄存器 (FLASH_
[单片机]
STM32--读写内部Flash
STM32数模转换器(DAC)简析
STM32F4xx系列提供的DAC模块是12 位电压输出数模转换器。DAC可以按 8 位或 12 位模式进行配置,并且可与DMA控制器配合使用。在 12 位模式下,数据可以采用左对齐或右对齐。DAC有两个输出通道,每个通道各有一个转换器。在DAC双通道模式下,每个通道可以单独进行转换;当两个通道组合在一起同步执行更新操作时,也可以同时进行转换。可通过一个输入参考电压引脚VREF+(与ADC共享)来提高分辨率。 DAC通道框图 DAC引脚 DAC通道使能 将 DAC_CR 寄存器中的相应 ENx 位置 1,即可接通对应 DAC 通道。经过一段启动时间tWAKEUP 后,DAC 通道被真正使能。 注意:ENx 位只会使能模
[单片机]
<font color='red'>STM32</font>数模转换器(DAC)简析
STM32单片机串口DMA解析
讨论三个问题:1、什么叫串口DMA 请求;2、串口简要复习;3、串口DMA发送流程。 1、什么叫串口DMA 请求(战舰STM32开发板) 说这个问题之前先简单回顾DMA的基本特性。先导出原子哥的PPT内容: DMA全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。 STM32有两个DMA控制器(DMA2只存在于大容量产品中),DMA1有7个通道,DMA2有5个通道,每个通道专门用来管理来自于一个或者多个外设对存储器的访问请求。还有一个仲裁器来协调各个DMA请求的优先权。 作用:为CPU减负
[单片机]
<font color='red'>STM32</font>单片机串口DMA解析
初涉STM32之浅谈时钟使能问题
作为一个STM32的菜鸟级人物,我刚开始接触STM32时,其实和当年开始学习51单片机的心理是一样的。茫然,谁说不是呢?但是,正常的学习途径无非就是看书,然后敲代码,最后烧程序,有问题就check,然后再继续烧,我都怀疑我快成了火头工。因为在我的印象中,只有这类职业才和“烧”有着密不可分的联系。即使当一名敬业又牛逼的火头工是我毕生的梦想。OK,不侃了。我希望,通过写日志把我作为一个菜鸟在学习STM32中的问题记录下来,同时以我为鉴,规避那些没有必要的破事。 1. 学习STM32要不要基础 原则上它应该是需要的,但是,我们也能发现很多人也是没有基础的。比如说,我们实验室的大师兄原来是管理专业,但是现在相当牛逼,软硬皆通。如果你和很多
[单片机]
stm32 程序二次加载:串口
使用串口二次加载程序即:不需要拆机就能够对产品进行升级,通过Bootloader就可以完成这项工作。该BootLoader的主要功能就是接受串口发送过来的应用程序并存放在固定的内存地址上,程序指针跳转到该地址上,程序就加载成功。 1、STM32在线升级 (IAP) IAP(In-Application Programming) 指MCU可以在系统中获取新代码并对自己重新编程,即可用程序来改变程序。 1.1、IAP编写流程: 由Bootloader负责检测SD卡中是否有固件更新所需的BIN文件,或者通过SPI、CAN、以太网、串口等方式获取BIN文件。 如果获取到所需要的BIN文件,则开始复制文件更新固件,更新结束
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved