【14】、STM32F767——————>内存管理

STM32H7 单片机使用DTCMRAM空间提升程序运行速度(STM32CubeIDE) 阅读详情
  1. 简述
    1. 内存管理是指运行时对计算机内存资源的分配和使用的技术
    2. 其目的是如何高效、快速的分配,并且在适当的时候释放和回收内存资源
    3. 内存管理函数只有两个:内存申请malloc(),内存释放free()
  2. 分块式内存管理
    1. 框图
    2. 组成:
      1. 内存池
      2. 内存管理表
      3. 内存池被等分为n块,对应的内存管理表,大小 也为n,内存管理表的每一个项对应内存池的一块内存
      4. 内存管理表项值意义:项值为0,表示对应的内存块未被占用,非0,己占用
      5. 分配方向:顶->底,即首先从末端开始找空内存,初始化时内存表全部清零
    3. 申请原理
      1. 指针p调用malloc函数申请内存时,先判断p要分配的内存块数(m)
      2. 然后从第n项开始,向下查找,直到找到m块连续的空内存块,然后将m个内存管理表项的值都设置为m(非0)
      3. 内存不够,如果没有找到m块空闲内存,则返回null给p,表示分配失败
    4. 释放原理
      1. 指针p调用free函数,先判断p指向内存地址所对应的内存块,找到对应的内存管理表项目
      2. 得到p所占用的内存块数目m,将m个内存管理表项目值都清零,标记释放
    5. 内存池地址范围
      1. 普通内存:起始地址:0x2002 0000,大小:384KB,任何外设都可以访问
      2. DTCM内存:起始地址:0x2000 0000,大小:128KB,CPU和DMA外设访问
      3. 外部SDRAM:起始地址:0xc000 0000,大小:32768KB
    6. 例程
      1. //内存池(32字节对齐)
        __align(64) u8 mem1base[MEM1_MAX_SIZE];													//内部SRAM内存池
        __align(64) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0XC01F4000)));					//外部SDRAM内存池,前面2M给LTDC用了(1280*800*2)
        __align(64) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X20000000)));					//内部DTCM内存池
        //内存管理表
        u32 mem1mapbase[MEM1_ALLOC_TABLE_SIZE];													//内部SRAM内存池MAP
        u32 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0XC01F4000+MEM2_MAX_SIZE)));	//外部SRAM内存池MAP
        u32 mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0X20000000+MEM3_MAX_SIZE)));	//内部DTCM内存池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]*4);	//内存状态表数据清零  
         	mallco_dev.memrdy[memx]=1;								//内存管理初始化OK  
        }  
        //获取内存使用率
        //memx:所属内存块
        //返回值:使用率(扩大了10倍,0~1000,代表0.0%~100.0%)
        u16 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*1000)/(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);  				//返回新内存首地址
            }  
        }
        

         

      2. 参考原子
    7. 下载验证
      1. 无
    8. 总结
      1. 无
    9. 参考资料
      1. 正点原子:STM32F7 开发指南(HAL 库版)
基于STM32F767的FreeRTOS的移植 (一)FreeRTOS简介 1.1 什么是FreeRTOS? FreeRTOS是一个免费的RTOS类系统。RTOS不是指某一个确定的系统,而是指一类系统。例如UCOS、RTX、RT-Thread等。 操作系统允许多个任务同时运行,但实际上一个处理器核心在某一时刻只能运行一个任务。操作系统中的任务调度器的责任就是决定在某一时刻究竟运行哪个任务,任务调度在各个任务之间的切换非常快,这就造成了同一时刻有... 阅读详情

相关推荐

STM32F767内存访问故障排查:HardFault与Cache一致性实战

在嵌入式系统开发中,内存访问异常是令工程师头疼的问题,尤其是在基于ARM Cortex-M7内核的高性能MCU上。理解Cache、MPU与存储架构是定位故障的前提。STM32F767等器件集成了多块SRAM和D-Cache,若DMA与外设交互时未处理缓存一致性,会导致数据错乱,甚至触发HardFault。通过解析CFSR、BFAR等寄存器,可快速区分总线错误、内存管理故障或用法错误。合理配置MPU将DMA缓冲区设为不可缓存,或手动执行Cache Clean/Invalidate,能有效避免随机死机。此外,线

weixin_29172963的博客 280

c++空指针会占用内存吗_阿波罗 STM32F767 开发板资料连载第四十四章 内存管理实验

1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子第四十四章 内存管理实验在第十九章,我们学会了使用 STM32F767 驱动外部 SDRAM,以扩展 STM32F767 的内存,加上 STM32F767 本身自带的 512K 字节内存,我们可供使用的内存还是比较多的。如果我们所用的内存...

weixin_39541212的博客 318

STM32 UART协议设计与中断状态机实现原理

UART(通用异步收发传输器)是嵌入式系统中最基础的串行通信接口,其核心在于帧同步、缓冲管理与中断协同。理解波特率生成原理、RXNE/TC标志机制及状态机驱动的帧识别逻辑,是保障数据完整性的前提。在STM32平台中,寄存器级配置(如USART_BRR、CR1)与HAL库抽象之间存在明确映射关系,而中断服务程序(ISR)采用有限状态机(FSM)模型可实现确定性执行和抗干扰接收。典型应用场景包括调试日志重定向(printf)、Modbus从机通信及工业网关数据透传。本文聚焦于CR/LF帧边界识别、STA状态变量

weixin_42584507的博客 331

stm32f767自举及在RAM中调试

自举

m0_38012497的博客 2024

告别内存碎片!在STM32上用RTX5内存池管理动态数据,实测效率提升明显

本文详细介绍了在STM32平台上使用RTX5内存池管理动态数据的方法,有效解决了传统malloc/free机制导致的内存碎片问题。通过实测数据对比,RTX5内存池在分配时间、内存利用率和系统稳定性方面均有显著提升,特别适合嵌入式实时系统开发。

weixin_30493401的博客 385

STM32H7B0 HAL库中关于DMA的注意事项以及DCMI调试遇到的问题及解决方法

由于需要用到摄像头,用IO驱动的话会比较慢,这里使用的STM32H7B0中的DCMI接口,由于DMA用的比较少,在这里卡了3天,期间各种测试,从硬件到软件,接用IO读OV2640,可以读到数据,确定硬件没有问题,DCMI的DMA一直进错误中断Transfer Error Interrupt management。配置IO也要注意一下D0,D1,D3可以复用到其他IO,一定不要弄错,配置完要对着IO检查一遍,频率使用也很重要,我这里用到的频率如下。放到 MX_DMA_Init();//使能D-Cache。

シ❤゛甜虾的个人博客 7167

单片机STM32在开发中常用库函数详解

1.GPIO初始化函数 用法: voidGPIO_Configuration(void) { GPIO_InitTypeDefGPIO_InitStructure;//GPIO状态恢复默认参数 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_标号|GPIO_Pin_标号; //管脚位置定义,标号可以是NONE、ALL、0至15。 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//最高输出速度为50MHz GPIO_InitStruct

dcw142857的博客 3414

STM32F767数据手册

STM32F767数据手册

将关键代码和数据段定位到特定DTCM-RAM/ITCM-RAM中【STM32F767】

首先查看用到的XXX-RAM的映射地址,其中主SRAM映射的起始地址从0x20020000开始,大小368kb,TCM-RAM起始地址0x20000000,ITCM-RAM起始地址0x00000000。具体能带来多大的优势,没有查询,但是不经过其他协议直接与CPU交流,效果应该非常好!目的:将关键数据重定位到DTCM-RAM,关键代码段重定位到ITCM-RAM中,SRAM1作为主SRAM。说明:散列文件的语法以及AC6和AC5区别自行查资料(推荐硬汉论坛,如有哪里不正确的地方,有问题可以留言交流!

Mr1sky的博客 1497

实战详细讲解Qt插件plugin的编写与用法

qt插件的开发,可以说是动态库的开发,因为调用方式类似,多熟悉一下,利用Qt框架开发很简单的。在想想这种调用过程有的熟悉,比如公司买了一堆摄像头,公司要对摄像头进行二次开发,实现自己想要的功能,集成到一套设备里去,然后在卖给用户。此时厂商肯定会提供开发文档,并给你SDK包(软件开发工具包), 包里你会发现只有头文件和一堆库文件,没有源文件,因为实现的过程是产商公司保密的,给你看还得了。所以都封装成了库的形式给你调用,如静态库或者动态库。

qq_44667165的博客 1万+

[Spawn service failed. Exiting] ROS2运行turtlebot3_gazebo例程卡住_报错

[Spawn service failed. Exiting] ROS2运行turtlebot3_gazebo例程卡住_报错

Feizhai2的博客 4861

如何将FreeRTOS移植到STM32F767的代码中

准备工作 准备基础工程 要移植 FreeRTOS,肯定需要一个基础工程,基础工程越简单越好,这里我们就用基础例程中的跑马灯实验来作为基础工程。 FreeRTOS 系统源码 FreeRTOS 系统源码在上一章已经详细的讲解过如何获取了,这里我们会将 FreeRTOS 的系统源码放到开发板光盘中去,路径为:6,软件资料->14,FreeRTOS 学习资料->FreeRTOS 源码。 FreeRTOS 移植 向工程中添加相应文件 1、添加 FreeRTOS 源码 在基础工程中新建一个名为 FreeRT

weixin_43491077的博客 580

Quartus ||———基于Verilog HDL的数字秒表设计实验

Quartus ||———基于Verilog HDL的数字秒表设计实验一、实验目的二、实验步骤(一)新建工程(二)添加设计文件(三)综合分析与功能仿真1、综合分析2、功能仿真 一、实验目的 用Verilog HDL设计一个数字跑表,所需引脚和功能如下: 二、实验步骤 (一)新建工程 在创建好工程名称后,选定芯片类型 (二)添加设计文件 新建Verilog文件,键入代码如下 module n_clk_top( input clk, input rese

TBMmagic的博客 5525

阿波罗STM32F767 FreeRTOS扩展例程

阿波罗STM32F767   4,程序源码3,扩展例程  5,FreeRTOS扩展例程

czhaii的专栏 374

Win10 Xbox游戏安装错误终极解决方案

Win10 Xbox游戏安装错误终极解决方案作为Windows 10系统深度用户,相信不少玩家都遇到过Xbox应用安装游戏失败的问题。这类问题轻则影响游戏体验,重则导致系统资源占用异常。本文将结合微软官方技术文档与实际维修案例,系统讲解Xbox游戏安装错误的深层原因与解决方案,帮助读者建立完整的故障处理思维体系。

mmoo_python的博客 2065

mfcc总结,这个mel三角滤波器分组到底是如何起作用的呢?

先看fft频谱图(这是4096字节取样fft计算,横轴频率是从0到512,后边意义不大,未取,纵轴是振幅),那些我随便画的蓝色线,你有什么联想?: 再看,这绿色线,是否有一种上升后,便逐渐式微的感觉,都是三角形的,这或许也是mel当初和绝大多数人看到的: 如果在振幅上加上一条限制的黑线(振幅门槛限制),黑色线以下很多频率就没有意义了,你看,有用的频率连一半(512/2=256)都占不到...

ganggangwawa的博客 9908

STM32嵌入式GUI开发全栈工具链实战:从电路仿真到TouchGFX界面部署

本文详细介绍了STM32嵌入式GUI开发全流程,从NI Multisim电路仿真、Altium Designer PCB设计,到STM32CubeMX外设配置与TouchGFX界面开发,最后通过Keil5完成编译部署。提供了多工具协同工作流优化方案和常见问题解决方案,帮助开发者高效构建稳定流畅的嵌入式GUI应用。

water的专栏 1049

redhawk:Low Power Analysis

1.rush current与switch cell 在standby状态下为了控制leakage power我们选择power gating的设计方式,使用power switch cell关闭block/power domain的电源。 power switch的基本介绍可见: 低功耗设计-Power Switch power switch的table中有四种状态,对应block工作、待机和上电,下电。low power analysis主要分析上电的过程。 上电过程可以看做mos电容

m0_61544122的博客 3203

STM32 HAL库开发学习8. STM32的嵌套中断控制器NVIC

NVIC 全称为 Nested Vectored Interrupt Controller,即嵌套向量中断控制器,它是 ARM Cortex - M 系列微控制器内核的关键组成部分,在 STM32 等基于该内核的芯片中广泛应用,主要负责管理和处理中断请求。ARM推出的 Cortex-M0和Cortex-M0+结构相对简单,集成了NVIC实现基本的中断管理功能。Cortex-M3 引入了Thumb-2指令集,支持更复杂的中断处理,包括嵌套中断。

猿来这样-谢厂节的博客 1805

UFS软件分区介绍

本文主要介绍了ufs软件分区管理的概况,能够使大家对软件分区有个大体的认识

肥匪斐's blogs 1万+

《【一看就会】Autoware.universe的“规划”部分源码梳理》系列文章目录(持续更新中)

第零章:Planning综述 第一章:【一】全局路径生成模块——mission_planner 第二章:【二】路径行为规划模块——behavior_path_planner第一部分——behavior_path_planner模块 第三章:【二】路径行为规划模块——behavior_path_planner第二部分——behavior_path_planner_common模块(1) 第四章:【二】路径行为规划模块——behavior_path_planner第三部分——behavior_path_plan

weixin_48386130的博客 2339

Qwen2.5-0.5B Instruct与STM32嵌入式开发结合方案

本文介绍了如何在星图GPU平台自动化部署🤖Qwen2.5-0.5B Instruct镜像,实现STM32嵌入式设备的智能对话功能。该轻量级模型通过量化优化,可在资源受限的硬件上运行,典型应用于智能家居语音控制,为用户提供本地化、低延迟的AI交互体验。

weixin_32102617的博客 95

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

手动移植LWIP协议到RTOS

https://doc.embedfire.com/net/lwip/zh/latest/doc/chapter8/chapter8.html

weixin_50580465的博客 612

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

STM32F7--->SDRAM

文章目录SDRAMSDRAM信号线存储单元存储结构数据传输控制命令空操作命令激活命令读写命令预充电命令刷新命令设置模式寄存器命令初始化写操作读操作FMC接口驱动SDRAM附录交代声明 SDRAM SDRAM英文名是 Synchronous Dynamic Random Access Memory ,即同步动态随机存储器,相较于 SRAM(静态存储器) SDRAM 具有:容量大和价格便宜的特点。 STM32F767 支持 SDRAM ,我们可以外挂 SDRAM ,从而大大降低外扩内存的成本,如下SDRAM

qq_42069216的博客 2479

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【11】uC/OS-III应用开发————>RAM内存管理(STM32F767)

简述 在嵌入式系统中,内存分配应根据系统特点选择使用 动态内存分配算法:普通业务系统,动态内存上限取决于硬件,使用效率高 静态内存分配算法:可靠性非常高的系统,需要考虑内存上限,使用效率低 uC/OS内存管理是采用内存池的方式进行管理 静态划分一大块连续空间做为内存管理的空间,内部划分若干块 使用的时候就从内存池中获取内存块,使用完将其放回 核心机制: 内存池...

Dream Catcher 766

【正点原子STM32】STM32基础知识(F1F4F7H7 STM32系统框架、寻址范围、存储器映射的存储器功能划分、寄存器映射)

一、STM32系统框架 - 1.1、Cortex M内核 & 芯片 - 1.2、F1系统架构 - 1.3、F4系统架构 - 1.4、F7系统架构 - 1.5、H7系统架构 二、STM32的寻址范围? 三、存储器映射 - 存储器功能划分(F1为例) - STM32F1存储器映射图 四、寄存器映射 - 寄存器基础知识 - STM32寄存器分类 - 寄存器映射(F1为例) - 寄存器描述解读 - 寄存器映射举例 - 寄存器地址计算 - GPIOA_ODR寄存器地址计算过程: - 使用结构体,可以很方便的

咖喱年糕的博客 4245
上一篇: 【0】嵌入式TCP/IP协议————>LWIP介绍
下一篇: 【2】嵌入式TCP/IP协议——————LWIP无系统移植
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值