STM32F4-内存管理

news2024/11/29 9:51:08

1 SRAM的使用

        STM32F407自带 192K SRAM,一般应用足够,但对内存要求高时,如算法或GUI,可能不够用。因此,通常在开发板上增加 1M字节SRAM芯片,例如XM8A51216,满足大内存需求。

        XM8A51216 是星忆存储科技公司生产的一颗 16 位宽 512K(512*16bit,即 1M 字节)容量的CMOS 静态内存芯片。

XM8A51216功能框图

        图中 A0~18 为地址线,总共 19 根地址线(即 2^19=512K,1K=1024);

        DQ0~15 为数据线,总共 16 根数据线。

        CEn 是芯片使能信号,低电平有效;

        OEn 是输出使能信号,低电平有效;

        WEn 是写使能信号,低电平有效;

        BLEn 和 BHEn 分别是高字节控制和低字节控制信号。

  • FSMC_NE3:这是STM32 FSMC的第三个片选信号线。在FSMC中,每个片选信号线对应一个外部存储器区域,通过配置FSMC的相关寄存器,可以定义每个区域的地址范围、数据宽度、访问时序等参数。

根据FSMC的NEx的接线,可知SRAM起始地址

        由于 外部SRAM接的是 FSMC的 NE3,

片外SRAM

        一个 Bank为256M,FSMC支持4个Bank。

        FSMC 只支持 BANK1~4。一个BANK 256M。

        0x6000 0000~0x6FFF FFFF       BANK1     SRAM使用

        0x7000 0000~0x7FFF FFFF       BANK2    

        0x8000 0000~0x8FFF FFFF       BANK3     FLASH使用

        0x9000 0000~0x9FFF FFFF       BANK4     PC卡使用

        每个 BANK 又被分为 4 个区,一个区 64 M。 

        要实现XM8A51216访问,需配置FSMC:

        1) 使能FSMC时钟,配置相关IO为复用输出;

RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);//使能 FSMC 时钟 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF);
 GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_FSMC);//PD0,AF12

        2) 设置FSMC BANK1区域3的工作模式、位宽和读写时序;

void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct);

        3) 使能BANK1区域3。//一个BANK256M,故BANK1_AREA3偏移地址128M

FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); // 使能 BANK1的区域3

        配置完成后,可通过地址0X68000000访问XM8A51216。 

        因为 Bank1从0x6000 0000开始,一个BANK 256M,至 0x6FFF FFFF结束。

        注意,我们说内存地址大小 xxM的时候,指的是MB,因为1映射地址可寻址到一个字节的存储单元。

        一个地址通常对应一个字节(8位)的存储单元。

        这意味着,如果你有一个32位的地址,它可以指向4GB(2^32字节)内存空间中的任何一个字节。

        一个地址可以寻址到一个8位的存储单元(即一个字节)。

2 内存管理简介

        内存管理旨在高效、快速分配、释放和回收内存资源,核心实现两个函数:

        malloc申请内存

        free释放内存

分块式内存管理原理

        分块式内存管理内存池内存管理表组成,

        内存池等分为n块,管理表记录每块状态。

        表项为0表示未占用,非零表示连续占用块数。分配从顶到底,初始化时表项全零。

        分配原理

        malloc从内存管理表末端开始,找m块连续空闲内存,将其标记为m并返回起始地址;若不足m块,返回NULL。

        释放原理

        free根据指针p找到对应内存块管理表项,将其及连续m-1项清零,标记释放。

3 正点原子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 内存池映射表  
u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000 + MEM2_MAX_SIZE))); // 外部 SRAM 内存池映射表  
u16 mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000 + MEM3_MAX_SIZE))); // 内部 CCM 内存池映射表

        __align(xx) 指定了变量 mem1base 应该按照 xx 字节对齐

         __attribute__((at(0Xxx))) 是 __attribute__ 的一个标准用法,它指定了变量应该被放置在特定的内存地址 0Xxx。

        之所以将内存定义为三个内存池,是因为STM32F4有三个不同地址和访问特性的内存区域:

        内部普通SRAM(地址从0X2000 0000开始,共128KB),所有外设均可访问。

        内部CCM内存(地址从0X1000 0000开始,共64KB),仅CPU可访问,DMA等外设不可直接访问。

        外部SRAM(地址从0X6800 0000开始,共1024KB)。

        由于内存池需要连续的内存空间,因此这三个内存区域各自形成一个内存池,总共三个内存池进行管理。内存池的大小(MEM1_MAX_SIZE、MEM2_MAX_SIZE、MEM3_MAX_SIZE)在malloc.h中定义,外部SRAM和CCM内存池从各自的首地址开始,而内部SRAM内存池的首地址由编译器自动分配。所有内存池均使用__align(32)进行32字节对齐,以满足不同场合的需求。

// 内存管理参数定义  
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 = {  
    .mem_init = my_mem_init,         // 内存初始化函数  
    .mem_perused = my_mem_perused,   // 内存使用率函数  
    .mem_pools = {                   // 内存池  
        mem1base,  
        mem2base,  
        mem3base  
    },  
    .mem_map_bases = {               // 内存管理状态表  
        mem1mapbase,  
        mem2mapbase,  
        mem3mapbase  
    },  
    .mem_ready = {0, 0, 0}           // 内存管理未就绪标志  
};
// 内存分配函数(内部调用)  
// memx: 所属内存块  
// size: 要分配的内存大小(字节)  
// 返回值: 0XFFFFFFFF 代表错误;其他为内存偏移地址  
u32 my_mem_malloc(u8 memx, u32 size) {  
    signed long offset = 0;  
    u32 nmemb = (size + memblksize[memx] - 1) / memblksize[memx]; // 计算所需内存块数  
    u32 cmemb = 0; // 连续空内存块数  
  
    if (!mallco_dev.memrdy[memx]) mallco_dev.init(memx); // 未初始化则先初始化  
    if (size == 0) return 0XFFFFFFFF; // 不需要分配内存  
  
    for (offset = memtblsize[memx] - 1; offset >= 0; offset--) { // 从后向前搜索空内存块  
        if (!mallco_dev.memmap[memx][offset]) cmemb++; // 连续空内存块数增加  
        else cmemb = 0; // 重置连续空内存块数  
        if (cmemb == nmemb) { // 找到足够的连续空内存块  
            for (u32 i = 0; i < nmemb; i++) mallco_dev.memmap[memx][offset + i] = nmemb; // 标记为已占用  
            return offset * memblksize[memx]; // 返回内存偏移地址  
        }  
    }  
    return 0XFFFFFFFF; // 未找到足够的连续空内存块  
}  
  
// 释放内存函数(内部调用)  
// memx: 所属内存块  
// offset: 内存地址偏移  
// 返回值: 0 代表释放成功;1 代表未初始化;2 代表偏移超区  
u8 my_mem_free(u8 memx, u32 offset) {  
    if (!mallco_dev.memrdy[memx]) {  
        mallco_dev.init(memx); // 未初始化则先初始化  
        return 1; // 返回未初始化状态  
    }  
    if (offset >= memsize[memx]) return 2; // 偏移超区  
  
    int index = offset / memblksize[memx]; // 计算内存块索引  
    int nmemb = mallco_dev.memmap[memx][index]; // 获取内存块数量  
    for (int i = 0; i < nmemb; i++) mallco_dev.memmap[memx][index + i] = 0; // 释放内存块  
    return 0; // 释放成功  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2215848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mac安装brew指引

1、根据官网提示 https://brew.sh/ 执行命令行 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 安装成功后依次执行 echo export PATH"/opt/homebrew/bin:$PATH" >> ~/.bash_profilesource ~…

WinRAR为什么会自动设置密码?取消自动加密的详细方法

在使用WinRAR压缩文件的过程中&#xff0c;部分用户可能会发现压缩文件时总是自动设置密码。这种情况可能会让人感到困惑&#xff0c;特别是在你并不需要对文件加密的时候。本文将解释为什么会发生这种情况&#xff0c;以及如何取消这种自动设置密码的操作&#xff0c;让你的压…

Leetcode 1489. 找到最小生成树里的关键边和伪关键边

1.题目基本信息 1.1.题目描述 给你一个 n 个点的带权无向连通图&#xff0c;节点编号为 0 到 n-1 &#xff0c;同时还有一个数组 edges &#xff0c;其中 edges[i] [fromi, toi, weighti] 表示在 fromi 和 toi 节点之间有一条带权无向边。最小生成树 (MST) 是给定图中边的一…

114.WEB渗透测试-信息收集-ARL(5)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;113.WEB渗透测试-信息收集-ARL&#xff08;4&#xff09; 输入&#xff1a; docker ps 查…

GPT和BERT

GPT和BERT都是基于Trm的应用&#xff0c;可以理解为GPT是decoder的应用&#xff0c;BERT可以说是encoder的应用 GPT 如图&#xff0c;就是GPT的原理&#xff0c;GPT是做生成式的任务的&#xff0c;没有办法进行下游任务改造&#xff0c;训练也是针对生成式的任务进行训练 BE…

【JavaEE】【IO】文件操作

目录 一、文件1.1 文件的概念1.2 文件的操作1.3 路径1.4 文件分类 二、Java中的文件元信息、路径操作2.1 属性2.2 构造方法2.3 方法2.3.1 文件路径2.3.2 文件判断2.3.3 文件创建删除2.3.4 其他操作 三、文件读写操作3.1 流&#xff08;Stream&#xff09;3.1.1 字节流3.1.1.1 I…

vmware虚拟机 报错:客户机操作系统已禁用 CPU,请关闭或重置虚拟机 的解决方法

打开cpu虚拟化全部进行勾选 ctrl e 进行关机 勾选上打开就好了 如果没有那个选项 关机>打开虚拟机>管理>更改硬件兼容性> 往小处改改> >更改此虚拟机

【干货】老师用什么小程序发布期中考试成绩?

即将迎来新学期第一次期中考试。考试结束后&#xff0c;老师们又要开始忙碌于成绩的统计和发布工作。易查分小程序就是其中一个非常实用的选择。它专为发布成绩而设计&#xff0c;能够帮助老师们轻松地完成成绩的发布工作。 通过易查分小程序&#xff0c;老师们可以快速地将成绩…

雷池社区版配置遇到问题不要慌,查看本文解决

很多新人不太熟悉反向代理&#xff0c;所以导致配置站点出现问题 配置问题 记录常见的配置问题 配置后攻击测试没有拦截记录 检查访问请求有没有真实经过雷池 有很多新人配置站点后&#xff0c;真实的网站流量还是走的源站&#xff0c;导致雷池这边什么数据都没有 配置后…

【工程测试技术】第4章 常用传感器分类,机械式,电阻式,电容式,电感式,光电式传感器

上理考研周导师的哔哩哔哩频道 我在频道里讲课哦 目录 4.1 常用传感器分类 4.2 机械式传感器及仪器 4.3 电阻式、电容式与电感式传感器 1.变阻器式传感器 2.电阻应变式传感器 3.固态压阻式传感器 4.典型动态电阻应变仪 4.3.2 电容式传感器 1.变换原理 2.测量电路 …

如何下载3GPP协议?

一、进入3GPP网页 https://www.3gpp.org/ 二、点击“Specifications &Technologies” 三、点击“FTP Server” 网址&#xff1a; https://www.3gpp.org/specifications-technologies 四、找到“latest”&#xff0c;查看最新版 网址&#xff1a; https://www.3gpp.org/ftp…

Android Framework AMS(05)startActivity分析-2(ActivityThread启动到Activity拉起)

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要解读AMS通过startActivity启动Activity的整个流程的整个流程的第二阶段&#xff1a;从ActivityThread启动到Activity拉起。 第一阶段文…

【超详细】UDP协议

UDP传输层协议的一种&#xff0c;UDP(User Datagram Protocol 用户数据报协议)&#xff1a; 传输层协议无连接不可靠传输面向数据报 UDP协议端格式 定长报头&#xff0c;8字节源端口号和目的端口号来定位16位UDP长度, 表示整个数据报(UDP首部UDP数据)的最大长度如果校验和出错…

Java重修笔记 第六十七天 坦克大战(完结)

奋斗一个多月终于把坦克大战写出来了&#xff0c;看了韩老师的思路然后自己手打&#xff0c;自己做不出来就看视频然后再写&#xff0c;总结收获和难点突破点如下&#xff1a; 1. 抽象类意识 刚开始没有将 Hero 和 Enemy 抽象出顶级父类 Tank&#xff0c;看了韩老师的视频&…

存储器学习记录(资源整合)

&#xff08;一&#xff09;整合资料&#xff1a; openedv.com/thread-300792-1-1.html 需搭配的底板&#xff1a; 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、 openedv.com/thread-272902-1-1.html 、、、、、、、、、、、、、、、、、、、、…

如何给4G模块(ESP32设备),ESP8266进行联网?

具体步骤&#xff1a; 1.打开uPyLoader&#xff0c;选择端口号&#xff0c;连接 连接成功后&#xff0c;点击工具栏的file-navigate&#xff0c;找到联网代码所在目录 联网代码&#xff1a; import network import timedef wifi_connect(ssid, password):wlan network.WLA…

实战篇:(三)项目实战Vue 3 + WebGL 创建一个简单的 3D 渲染应用

Vue 3 WebGL 创建一个简单的 3D 渲染应用 我们将使用 Vue 3 和 WebGL 创建一个简单的 3D 渲染应用。项目将展示如何在 Vue 组件中集成 WebGL&#xff0c;并渲染一个旋转的立方体。 1. 项目准备 首先&#xff0c;确保你已经安装了 Node.js 和 Vue CLI。如果还没有安装&#x…

一键docker脚本

#!/bin/bash ## Author: SuperManito ## Modified: 2024-10-07 ## License: MIT ## GitHub: https://github.com/SuperManito/LinuxMirrors ## Website: https://linuxmirrors.cn## Docker CE 软件源列表 # 格式&#xff1a;"软件源名称软件源地址" mirror_list_dock…

WebGl 如何给页面绑定点击事件

在WebGL中给页面绑定点击事件&#xff0c;可以通过为WebGL的绘图上下文所在的<canvas>元素添加事件监听器来实现点击事件的处理。 1. 画布添加点击事件 const ctx document.getElementById(canvas) const gl ctx.getContext(webgl)ctx.onclick function (e) {// 给ca…

深入理解WPF中的命令机制

Windows Presentation Foundation&#xff08;WPF&#xff09;是微软推出的一种用于构建桌面客户端应用程序的技术。它被认为是现代Windows应用程序的基础&#xff0c;具有强大的图形和媒体处理能力。在WPF中&#xff0c;“命令”是一个重要的概念&#xff0c;它为应用程序开发…