【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(三)-SD卡的操作流程

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(四)-介绍库函数,获取一些SD卡的信息

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(五)-文件管理初步介绍

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(六)-FatFs使用的思路介绍

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(七)-准备移植FatFs

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(八)-认识内存管理

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(终)-配合内存管理来遍历SD卡

首先说明一下,为何要介绍内存管理

在SD卡的读取中,你并不知道对方到底存了多少文件?文件名的长度又是多少?

文件个数先暂定100个额度吧,文件名长度先默认长文件名255字节

那么你要申请数组来记录,u8 file_name[100][255];

这样你就已经花掉25.5K的内存了,但你又保证,100个额度,绝对够用吗?

1000个额度?那就需要255K的内存了。。。

先看一下我使用的这颗芯片(本篇中提到芯片这个字样,并且没有明确说是哪个型号时,指的是我使用的这颗,也就是下图STM32F405RGT6)

RAM只有192K,还比255K小,这时候,就体现内存管理的作用了,当然,这里先不谈外部扩展的事情

芯片内部有三个内存,分别是SRAM1、SRAM2、CCM,如下图2显示

下图1红框:64K的CCM,是包含在192+4K里面的

CCM(core coupled memory)(核心耦合存储器):理论上是最快的,但是它只能被CPU访问,像其他外设(DMA、以太、USB),都无法访问

接着来讲一下【分块式内存管理】的原理

它是由内存池和内存管理表两个部分组成的

里面有n个内存块

每个内存块,对应内存管理表的一项

项值为0,代表对应的内存块未被使用

而项值为非0,里面的数值代表被连续占用的内存块数

分配内存时,先给一个参数m(此参数表示需要多少内存块)

然后从第n项开始,向下查找,直到发现m块连续的空内存

把这些连续的空内存,项值都设置成m

最终在把这些空内存块的地址返回(谁申请内存的就返回给谁)

由于我使用的是正点原子的探索者开发板,这里先提取两个文件《malloc.c》《malloc.h》

里面有封装好的函数,只要了解一些宏定义,和一些其他的设置即可

malloc.c

#include "malloc.h"	   

//内存池(32字节对齐)
__align(32) u8 mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池
__align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); //外部SRAM内存池,attribute修饰,指向0x68000000首地址
__align(32) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X10000000))); //内部CCM内存池,attribute修饰,指向0x10000000首地址
//内存管理表
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][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<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); //返回新内存首地址
}
}

  

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

  

在头文件《malloc.h》里

首先看到三个宏定义《SRAMIN》《SRAMEX》《SRAMCCM》

这几个的说明,在注释里已经写的很清楚了

探索者开发板还扩充外部(extern)的SRAM,所以宏定义命名为SRAMEX吧?

再加上内部SRAM和CCM,总共就有3个内存池了

下方一点的宏定义《SRAMBANK》,因为有3个内存池,这里就设置为3

紧接着的是三个区域的宏定义,《mem1》《mem2》《mem3》

这三个也就是对应上方的《内部SRAM》《外部SRAM》《CCM》

里面除了内存管理表大小的宏定义不要改以外,其余两个看各位的需求

额外提一点,假设像宏定义《MEM1_MAX_SIZE》一样,设置了100K的内存

这里可是实打实的100K,虽然内存管理表也会占用到内存,但并不在这100K内

它还会额外占 MEM1_MAX_SIZE * 2 个字节的空间

乘2是因为,它是u16类型的

然后来看源文件《malloc.c》

最上方定义了《内存池》《内存管理表》《内存管理参数》

首先是内存池,直接看【__align(32) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X10000000)));】

__align是字节对齐,这作法能让CPU更快的访问变量

attribute是修饰,指向的是CCM的首地址0x10000000,下面会放图

这里说一下,因为我还没研究正点原子开发板上,外部扩展的是什么元件,导致我不知道0x68000000这首地址是如何来的

先看下面这图,了解一下CCM的首地址吧,毕竟它是STM32F4的内存,datasheet里面都说的很清楚了

源文件《malloc.c》剩下两个定义《内存管理表》《内存管理参数》,也没什么好说的,设置好这些,等着下方的封装函数来调用吧

而这些封装好的函数,我们只要看四个函数即可

1.《my_mem_init》初始化指定的内存池

2.《mymalloc》申请内存

3.《myfree》释放内存

4.《my_mem_perused》查看内存使用率

本章就先到这里了,下一章要回头处理FatFs文件管理的后续(读取SD卡内的文件)

【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(八)-认识内存管理的更多相关文章

  1. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(终)-配合内存管理来遍历SD卡

    [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 [STM3 ...

  2. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(七)-准备移植FatFs

    [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 [STM3 ...

  3. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(六)-FatFs使用的思路介绍

    [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 [STM3 ...

  4. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(五)-文件管理初步介绍

    其他链接 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 ...

  5. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡

    由于一张SD卡要能读写,涉及到的技术有些多,我打算分以下几篇博客 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含 ...

  6. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍

    其他链接 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 ...

  7. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(三)-SD卡的操作流程

    其他链接 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 ...

  8. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(四)-介绍库函数,获取一些SD卡的信息

    其他链接 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 ...

  9. 第36章 SDIO—SD卡读写测试

    第36章     SDIO—SD卡读写测试 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/f ...

随机推荐

  1. Shadertoy 教程 Part 4 - 绘制多个2D图形和混入

    Note: This series blog was translated from Nathan Vaughn's Shaders Language Tutorial and has been au ...

  2. 转移指令原理和Inline Hook

    目录 转移指令原理和Inline Hook 转移指令 操作符offset jmp指令 根据位移进行转移的jmp指令 插播HOOK知识 Inline Hook Inline Hook 原理 Hook代码 ...

  3. 【微服务理论】API + BFF

    对于微服务,常见的架构模型就是API网关+服务. API网关实现鉴权.负载均衡.中间件等公共入口逻辑. 服务实现具体的业务功能. 那么,API网关设计中又有什么坑呢? 1.0版本 直接将服务穿透到外网 ...

  4. OpenHarmony LiteOS C-SKY指令集移植指北

    摘要:本文介绍在OpenHarmony社区LiteOS-M项目中新增C-SKY指令集的开发流程,以及适配相应qemu工程的方法和步骤,供LiteOS内核相关开发者学习交流. 本文分享自华为云社区< ...

  5. 学习JS的第二天

    一.数据类型间的转换 主要:数字与字符串之间的转换 1.隐式转换 // console.log(1==true);[] 字符串与数字相加,其结果就是字符串  类似于字符串拼接 concole.log( ...

  6. 菜鸡的Java笔记

    1.注释 在JAVA中对于注释有三种: 单行注释:// 多行注释:/*--*/ 文档注释:/**--*/ 2.关键字和标识符 在程序中描述类名称,方法名称,变量等概念就需要使用标识符来定义.而在JAV ...

  7. 菜鸡的Java笔记 第十六 - java 引用传递

    referenceDelivery    引用传递是整个java 的精髓,也是所有初学者最难学的地方        引用的本质:同一块堆内存可以被不同的栈内存所指向    下面通过三道程序来进行引用传 ...

  8. [atARC063F]Snuke's Coloring 2

    首先,可以通过将所有$x_{i}=0$都选择第1类,其余选第2类,构造出一个以$(0,0)$和$(1,h)$为左下角和右上角的矩形,答案即为$2h+2$,类似地还可以构造出$2w+2$ 若最终的矩形不 ...

  9. IDEA修改XML注释风格

    作为一个强迫症患者,每次想在xml文件用快捷键注释的时候,它自动生成的注释一直都是这样的:这令我非常难受,于是每次我都要把光标移到前面,然后再Tab以下,让它变成这样可是每次都这样,好麻烦啊,如果自己 ...

  10. N皇后问题解法

    // // Created by Administrator on 2021/8/5. // #ifndef C__TEST01_NQUEENS_HPP #define C__TEST01_NQUEE ...