GD32(4)存储管理

微控制器内存介绍

       大部分微控制器内部中只有Flash和SRAM两种存储器,Flash中会存储代码以及const定义的常量(除了局部非静态常量,即函数内定义的非static常量,emmm我也很奇怪)。SRAM中则存储所有的变量以及局部非静态常量。通过代码可能更好的理解这一点:

  const static int si_c ;    //在Flash中存储
  static int si;             //在SRAM中存储
  const int i_c;             //在Flash中存储 
  int i;                     //在SRAM中存储

void num(void)
{
  const static int sj_c ;    //在Flash中存储
  static int sj;             //在SRAM中存储
  const int j_c;             //在SRAM中存储
  int j;                     //在SRAM中存储
}

要验证上述类型的变量存储位置,可以定义后通过printf函数打印其地址。

       除了以上方式会直接使用到微控制器内部存储器外,还可以通过malloc函数动态分配内存,通过malloc函数分配的内存,同样是位于微控制器内部Flash中,如下所示:

#include "stdlib.h"

void num(void)
{
  int* num;
  num = (int*)malloc(50);
}

       一般来说,对微控制器的内存应用到此为止,通过malloc函数能基本运用到所有内存(SRAM一般较小,存储变量即可),但对更大的数据量则需要外部存储器进行存储,外部Flash、SRAM乃至SDRAM芯片可以存储大量数据,据此也引发了相应的问题:微控制器难以对外部存储器芯片进行有效的空间管理,即使使用EXMC、FSMC等接口,也只是对访问比较方便而已,因此需要通过编程,实现对各个存储器的管理。

内存管理原理

       内存管理本质上是建立1张内存管理表(当然也可以有其它方法),类似NAND Flash管理中的FTL层,将表内的某一项对于实际内存的1小块,当通过设定的API函数申请内存时,内存管理表中对应项被赋值,同时实际内存的对应的块被分配,如下图所示。

在这里插入图片描述

       在存储管理中,有以下几个主要变量、宏定义:

#define MemorySize  512*1024//外部存储块总大小
#define BlockNum  512       //将外部存储块分为512块,对应内存管理表第1项至第512项
#define BlockSize MemorySize/BlockNum    //每个存储块大小
#define StartAddr 0         //外部存储块的访问首地址(通过EXMC接口的话可查阅手册)

int MemTable[100] = {0};    //下标为单数的元素为申请地址的首项,单数+1块为末项
int MemNum = 0;             //已被分配的存储块数量

注意:每块存储块的大小决定了能申请的地址最小值。

内存分配原理

       内存分配需要实现1个API函数,该函数的传入参数有两个:接收指针、申请地址大小。其中,接收指针用于存放分配的地址块首地址,申请地址大小应该以字节为单位。

       在该函数中,需要完成以下事项:

  • 根据申请地址的大小,计算分配存储块的数量。
  • 从下标为0开始,根据MemTable,寻找足够、未被分配、连续的存储块以分配,若实在找不到,则返回0表示分配失败。
  • 表示已被分配的块数量加1。
  • 在MemTable中登记。
  • 计算地址块首地址后,将其赋值给接收指针。

内存释放原理

       内存释放同样需要1个API函数,该函数仅需要1个传入参数,即接收指针。接收指针用于计算首末地址块的位置。

       在该函数中,需要完成以下事项:

  • 根据接收指针及存储区域首地址,计算首末地址块的位置。
  • 将MemTable中,被释放的内存块对应两个元素后开始,所有元素下标减2。
  • 表示已被分配的块数量减1

参考代码

以下程序仅供参考!

宏定义及.c文件内部变量

#define MemorySize  512*1024//外部存储块总大小
#define BlockNum  512       //将外部存储块分为512块,对应内存管理表第1项至第512#define BlockSize MemorySize/BlockNum    //每个存储块大小
#define StartAddr 0         //外部存储块的访问首地址(通过EXMC接口的话可查阅手册)

int MemTable[100] = {0};    //下标为单数的元素为申请地址的首项,单数+1块为末项
int MemNum = 0;             //已被分配的存储条数量

内存分配

int MemDistribute(int size, char* p)
{
  int num;     //分配存储块的数量
  int i = 0;   //已确定块的数量
  int j = 0;
  int Startaddr = 1;

  num = size / BlockSize;
  if((size % BlockSize) != 0)num++;  //整数存储块放不下
  
  while(i < num)  //通过循环寻找足够、未被分配、连续的存储块
  {
    if((Startaddr + size - 1) >= BlockNum)return 0;  //剩余空间不足,返回
    
    for(j = 0; j < MemNum; j++)   //循环检查该块是否已被分配
    {
      if(MemTable[j*2] == (Startaddr+i)) //如果该块已被分配为其它存储块的首地址(只可能是首地址)
      {
        Startaddr = MemTable[j*2+1]+1;    //跳过这一整段被分配的内存
        i = 0;
        break;
      }
    }
    
    if(MemTable[j*2] == 0) //循环了所有被分配的存储条,该块未被分配
    {
      i = i+1;                 //进行下一块的判断
    }
  }
  
  MemNum++;
  MemTable[(MemNum-1)*2] = Startaddr;
  MemTable[(MemNum-1)*2+1] = Startaddr + size -1;
  p = (char*)(StartAddr + Startaddr * BlockNum);
  
  return 1;
}

内存释放

int MemRelease(char* p)
{
  int num;    
  int i = 0;   
  int j = 0;
  int Startaddr;

  Startaddr = (int)(p - StartAddr) / BlockNum;
  
  if((Startaddr > BlockNum) || (MemNum == 0))return 0;
  
  while(i < MemNum)
  {
    if(Startaddr == MemTable[i*2])
    {
      for(j = i; j < MemNum + 1; j++)
      {
        MemTable[j*2] = MemTable[j*2+2];
        MemTable[i*2+3] = MemTable[i*2+3];
      }
      MemNum--;
      break;
    }
    i++;
  }
  
  return 1;
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值