【STM32H7教程】第27章 STM32H7的TCM,SRAM等五块内存的动态内存分配实现

发布者:anluran最新更新时间:2023-04-23 来源: zhihu关键字:STM32H7  TCM  SRAM  动态内存分配 手机看文章 扫描二维码
随时随地手机看文章

27.1 初学者重要提示

  1. 学习本章节前,务必优先学习第25章,了解TCM,SRAM等五块内存区的基础知识,比较重要。

  2. 将RTX5系统的动态内存管理整理了出来,可以同时管理多个分区。如果其它RTOS中使用,记得做互斥保护或者加个调度锁均可。

  3. 支持动态内存使用情况统计。

27.2 动态内存管理移植

移植比较简单,仅需添加两个文件到工程即可。

27.2.1 MDK版的移植

  • 第1步,添加如下两个文件到MDK中

注,以本章配套例子为例,这两个文件的路径Usermalloc。

  • 第2步,添加路径。

  • 第3步,添加头文件。

如果哪个源文件要用到动态内存,包含rtx_lib.h即可,本章配套例子是直接将其放在了bsp.h文件里面,哪个源文件要用到动态内存,直接包含bsp.h头文件即可。

通过这简单的三步就完成了MDK的移植。

27.2.2 IAR版的移植

  • 第1步,添加如下两个文件到IAR中

注,以本章配套例子为例,这两个文件的路径Usermalloc。

  • 第2步,添加路径。

  • 第3步,添加头文件。

如果哪个源文件要用到动态内存,包含rtx_lib.h即可,本章配套例子是直接将其放在了bsp.h文件里面,哪个源文件要用到动态内存,直接包含bsp.h头文件即可。

通过这简单的三步就完成了IAR的移植。

27.3 动态内存的使用方法

下面分别以MDK和IAR为例进行说明:

27.3.1 MDK上的动态内存用法

  • 定义动态内存区

比如当前的主RAM用的DTCM,我们就可以直接定义一块大的数组作为动态内存空间:

/* DTCM, 64KB */

/* 用于获取当前使用的空间大小 */

mem_head_t *DTCMUsed; 

/* 定义为64位变量,首地址是8字节对齐 */             

uint64_t AppMallocDTCM[64*1024/8]; 

如果要使用AXI SRAM作为动态内存空间,可以使用__attribute__((at( )))指定地址。


/* D1域, AXI SRAM, 512KB */

/* 用于获取当前使用的空间大小 */

mem_head_t *AXISRAMUsed;  

/* 定义为64位变量,首地址是8字节对齐 */ 

uint64_t AppMallocAXISRAM[512*1024/8]__attribute__((at(0x24000000))); 

初始化动态内存区

调用动态内存管理提供的函数osRtxMemoryInit即可做初始化:


osRtxMemoryInit(AppMallocDTCM,    sizeof(AppMallocDTCM));

osRtxMemoryInit(AppMallocAXISRAM, sizeof(AppMallocAXISRAM));

申请动态内存

通过函数void *osRtxMemoryAlloc (void *mem, uint32_t size, uint32_t type)做动态内存申请。


第1个参数填写内存区首地址,比如申请的AppMallocDTCM,就填AppMallocDTCM即可。


第2个参数填写申请的字节大小,单位字节。


第3个参数固定填0即可。


返回值是所申请缓冲区的首地址,如果没有空间可用,将返回NULL,这点要特别注意!


举个例子:


uint32_t *DTCM_Addres0, *AXISRAM_Addres0;


/* 从DTCM申请280字节空间,使用指针变量DTCM_Addres0操作这些空间时不要超过280字节大小 */    

DTCM_Addres0 = osRtxMemoryAlloc(AppMallocDTCM, 280, 0);

DTCMUsed = MemHeadPtr(AppMallocDTCM);

printf("DTCM总大小 = %d字节,申请大小 = 0280字节,当前共使用大小 = %d字节rn", 

                                             DTCMUsed->size, DTCMUsed->used);


/* 从AXI SRAM 申请160字节空间,使用指针变量AXISRAM_Addres0操作这些空间时不要超过160字节大小 */    

AXISRAM_Addres0 = osRtxMemoryAlloc(AppMallocAXISRAM, 160, 0);

AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);

printf("AXI SRAM总大小 = %d字节,申请大小 = 0162字节,当前共使用大小 = %d字节rn", 

                                            AXISRAMUsed->size, AXISRAMUsed->used);

申请了空间后,就可以直接使用了。另外注意红色字体部分,通过DTCMUsed->used和AXISRAMUsed->used可以获取当前使用的空间大小。


释放动态内存

通过函数uint32_t osRtxMemoryFree (void *mem, void *block)做动态内存释放。


第1个参数填写内存区首地址,比如释放的AppMallocDTCM,就填AppMallocDTCM即可。


第2个参数填写申请内存时所获取的内存区首地址,这里用于释放。


返回值,返回1表示成功,返回0表示失败。


举个例子:


/* 释放从DTCM申请的280字节空间 */

osRtxMemoryFree(AppMallocDTCM, DTCM_Addres0);

DTCMUsed = MemHeadPtr(AppMallocDTCM);

printf("释放DTCM动态内存区申请的0280字节,当前共使用大小 = %d字节rn", DTCMUsed->used);


/* 释放从AXI SRAM申请的160字节空间 */

osRtxMemoryFree(AppMallocAXISRAM, AXISRAM_Addres0);

AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);

printf("释放AXI SRAM动态内存区申请的0160字节,当前共使用大小 = %d字节rn", AXISRAMUsed->used);

27.3.2 IAR上的动态内存用法

注:IAR使用这个动态内存管理,仅在定义时跟MDK略有不同,其它地方是一样的。


定义动态内存区

比如当前的主RAM用的DTCM,我们就可以直接定义一块大的数组作为动态内存空间:


/* DTCM, 64KB */

/* 用于获取当前使用的空间大小 */

mem_head_t *DTCMUsed; 

/* 定义为64位变量,首地址是8字节对齐 */             

uint64_t AppMallocDTCM[64*1024/8]; 

如果要使用AXI SRAM作为动态内存空间,可以使用__attribute__((at( )))指定地址。


/* D1域, AXI SRAM, 512KB */

/* 用于获取当前使用的空间大小 */

mem_head_t *AXISRAMUsed;  

/* 指定下面数组的地址为0x24000000 */ 

#pragma location = 0x24000000

uint64_t AppMallocAXISRAM[512*1024/8];

初始化动态内存区

调用动态内存管理提供的函数osRtxMemoryInit即可做初始化:


osRtxMemoryInit(AppMallocDTCM,    sizeof(AppMallocDTCM));

osRtxMemoryInit(AppMallocAXISRAM, sizeof(AppMallocAXISRAM));

申请动态内存

通过函数void *osRtxMemoryAlloc (void *mem, uint32_t size, uint32_t type)做动态内存申请。


第1个参数填写内存区首地址,比如申请的AppMallocDTCM,就填AppMallocDTCM即可。


第2个参数填写申请的字节大小,单位字节。


第3个参数固定填0即可。


返回值是所申请缓冲区的首地址,如果没有空间可用,将返回NULL,这点要特别注意!


举个例子:


uint32_t *DTCM_Addres0, *AXISRAM_Addres0;


/* 从DTCM申请280字节空间,使用指针变量DTCM_Addres0操作这些空间时不要超过280字节大小 */    

DTCM_Addres0 = osRtxMemoryAlloc(AppMallocDTCM, 280, 0);

DTCMUsed = MemHeadPtr(AppMallocDTCM);

printf("DTCM总大小 = %d字节,申请大小 = 0280字节,当前共使用大小 = %d字节rn", 

                                             DTCMUsed->size, DTCMUsed->used);


/* 从AXI SRAM 申请160字节空间,使用指针变量AXISRAM_Addres0操作这些空间时不要超过160字节大小 */    

AXISRAM_Addres0 = osRtxMemoryAlloc(AppMallocAXISRAM, 160, 0);

AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);

printf("AXI SRAM总大小 = %d字节,申请大小 = 0162字节,当前共使用大小 = %d字节rn", 

                                            AXISRAMUsed->size, AXISRAMUsed->used);

申请了空间后,就可以直接使用了。另外注意红色字体部分,通过DTCMUsed->used和AXISRAMUsed->used可以获取当前使用的空间大小。


释放动态内存

通过函数uint32_t osRtxMemoryFree (void *mem, void *block)做动态内存释放。


第1个参数填写内存区首地址,比如释放的AppMallocDTCM,就填AppMallocDTCM即可。


第2个参数填写申请内存时所获取的内存区首地址,这里用于释放。


返回值,返回1表示成功,返回0表示失败。


举个例子:


/* 释放从DTCM申请的280字节空间 */

osRtxMemoryFree(AppMallocDTCM, DTCM_Addres0);

DTCMUsed = MemHeadPtr(AppMallocDTCM);

printf("释放DTCM动态内存区申请的0280字节,当前共使用大小 = %d字节rn", DTCMUsed->used);


/* 释放从AXI SRAM申请的160字节空间 */

osRtxMemoryFree(AppMallocAXISRAM, AXISRAM_Addres0);

AXISRAMUsed = MemHeadPtr(AppMallocAXISRAM);

printf("释放AXI SRAM动态内存区申请的0160字节,当前共使用大小 = %d字节rn", AXISRAMUsed->used)

27.4 实验例程说明(MDK)

配套例子:


V7-006_TCM,SRAM等五块内存的动态内存分配实现


实验目的:


学习TCM,SRAM等五块内存的动态内存分配实现。

实验内容:


启动自动重装软件定时器0,每100ms翻转一次LED2。

实验操作:


K1键按下,从DTCM依次申请280字节,64字节和6111字节。

K1键松开,释放从DTCM申请的空间。

K2键按下,从AXI SRAM依次申请160字节,32字节和2333字节。

K2键松开,释放从AXI SRAM申请的空间。

K3键按下,从D2域SRAM依次申请200字节,96字节和4111字节。

K3键松开,释放从D2域SRAM申请的空间。

摇杆OK键按下,从D3域SRAM依次申请300字节,128字节和5111字节。

摇杆OK键松开,释放从D3域SRAM申请的空间。

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1

程序设计:

系统栈大小分配:

RAM空间用的DTCM:

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/*

*********************************************************************************************************

*    函 数 名: bsp_Init

*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次

*    形    参:无

*    返 回 值: 无

*********************************************************************************************************

*/

void bsp_Init(void)

{

    /* 配置MPU */

    MPU_Config();

    

    /* 使能L1 Cache */

    CPU_CACHE_Enable();


    /* 

       STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:

       - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。

       - 设置NVIV优先级分组为4。

     */

    HAL_Init();


    /* 

       配置系统时钟到400MHz

       - 切换使用HSE。

       - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。

    */

    SystemClock_Config();


    /* 

       Event Recorder:

       - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。

       - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章

    */    

#if Enable_EventRecorder == 1  

    /* 初始化EventRecorder并开启 */

    EventRecorderInitialize(EventRecordAll, 1U);

    EventRecorderStart();

#endif

    

    bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */

    bsp_InitTimer();      /* 初始化滴答定时器 */

    bsp_InitUart();    /* 初始化串口 */

    bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    

    bsp_InitLed();        /* 初始化LED */    

}

MPU配置和Cache配置:

数据Cache和指令Cache都开启。


AXI SRAM的MPU属性:


Write back, Read allocate,Write allocate。


FMC的扩展IO的MPU属性:


必须Device或者Strongly Ordered。


D2 SRAM1,SRAM2和SRAM3的MPU属性:


Write through, read allocate,no write allocate。


D3 SRAM4的MPU属性:


Write through, read allocate,no write allocate。


/*

*********************************************************************************************************

*    函 数 名: MPU_Config

*    功能说明: 配置MPU

*    形    参: 无

*    返 回 值: 无

*********************************************************************************************************

*/

static void MPU_Config( void )

{

    MPU_Region_InitTypeDef MPU_InitStruct;


    /* 禁止 MPU */

    HAL_MPU_Disable();


    /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */

    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;

    MPU_InitStruct.BaseAddress      = 0x24000000;

    MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;

    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;

    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;

    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;

    MPU_InitStruct.Number           = MPU_REGION_NUMBER0;

    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;

    MPU_InitStruct.SubRegionDisable = 0x00;

    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;


    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    

    

    /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */

    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;

    MPU_InitStruct.BaseAddress      = 0x60000000;

    MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    

    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;

[1] [2] [3] [4] [5] [6] [7]
关键字:STM32H7  TCM  SRAM  动态内存分配 引用地址:【STM32H7教程】第27章 STM32H7的TCM,SRAM等五块内存的动态内存分配实现

上一篇:【STM32H7教程】第28章 STM32H7时间关键代码在ITCM执行的超简单方法
下一篇:【STM32H7教程】第26章 STM32H7的TCM,SRAM等五块内存的超方便使用方式

推荐阅读最新更新时间:2024-11-02 09:50

赛普拉斯的异步SRAM系列又添新丁
静态随机存取存储器(SRAM)市场领导者赛普拉斯半导体公司日前宣布,其具有错误校正码(ECC)的4Mb异步SRAM正在出样。这些新款SRAM的片上ECC功能可提供最高水平的数据可靠性,而无需额外的错误校正芯片,从而简化了设计,并缩小了电路板尺寸。该器件可在工业、军事、通讯、数据处理、医疗、消费及汽车等应用中确保数据的可靠性。 由背景辐射引起的软错误可损坏存储器中的内容,造成重要数据的遗失。赛普拉斯新型异步SRAM系列中的硬件ECC模块可在线执行所有的错误校正功能,而无需用户干预,能达到业界最佳的小于0.1 FIT/Mb的软错误率(SER)性能(一个FIT等于器件每工作十亿小时发生一次错误)。这些新款器件与
[嵌入式]
赛普拉斯的异步<font color='red'>SRAM</font>系列又添新丁
STM32L5系列—SRAM、Flash和启动机制的最新安全特性(一)
SRAM SRAM 原生地址 vs. 别名地址 BOOT启动地址 启动地址选择 / TZEN = 0 演示:启动地址选择 / TZEN = 0 启动地址选择 / TZEN = 1 片上Flash 在系统架构中位置 片上Flash. 组织结构 片上Flash. 安全相关特性 Trust Zone(TZ) 环境的使能和撤销
[单片机]
基于FPGA和SRAM的数控振荡器的设计与实现
1 引言   数控振荡器是数字通信中调制解调单元必不可少的部分,同时也是各种数字频率合成器和数字信号发生器的核心。随着数字通信技术的发展。对传送数据的精度和速率要求越来越高。如何得到可数控的高精度的高频载波信号是实现高速数字通信系统必须解决的问题。可编程逻辑器件和大容量存储器的发展为这一问题的解决带来了曙光。本文介绍如何用FPGA(现场可编程逻辑门阵列)和SRAM(静态随机存储器)实现高精度数控振荡器。 2 NCO概述    NCO(Numerical Controlled Oscillator)即数控振荡器用于产生可控的正弦波或余弦波。其实现的方法目前主要有计算法和查表法等。计算法以软件编程的方式通过实时计算产生正弦波样本.该
[应用]
工程师笔记|STM32H7双核CM4作为Master初始化系统
STM32H7双核单片机内部集成了CM7和CM4这两个内核,在目前官方提供的例程中,大都是使用CM7作为Master初始化系统时钟,然后通过释放硬件信号量HSEM唤醒CM4,那么是否可以将CM7与CM4的角色互换,让CM4作为Master去初始化系统时钟呢? 答案肯定是可以的 可行的方案分析 方案一 目前官方提供的例程路径如下,可以使得D2域的CM4进行系统时钟的初始化: ……STM32CubeRepositorySTM32Cube_FW_H7_V1.9.0ProjectsSTM32H747I-EVALExamplesPWRPWR_D2ON_D1OFFEWARM 但是通过查看对应项目工程的readme.txt文件,发现:
[单片机]
OK6410A 开发板 (五) 2 OK6410A u-boot-2021.01 ethernet SRAM接口
代码位于 https://github.com/lisider/u-boot/tree/ok6410a 提交id : 1334ebb659844e51b60bbbdbce5b3d7da7d82e2c 代码include/configs/ok6410a.h 中的 CONFIG_DM9000_BASE 为 0x18000000 或者 0x18000300 都可以 因为都在 SROMC Bank 1 内 eth_legacy ping 流程(硬件无关) static init_fnc_t init_sequence_r = { initr_net eth_initialize board_eth_in
[单片机]
更快的STM32H7微控制器,为产品带来更高的性能和经济性
半导体供应商意法半导体(STMicroelectronics,简称ST;纽约证券交易所代码:STM)推出运算速度破纪录的嵌入闪存的STM32* 微控制器(MCU),让注重成本的新产品也具有图形用户界面、 AI和先进网络保护的高端功能。 新的STM32H7 MCU基于Arm® Cortex®-M7内核,主频550 MHz,是深度嵌入式应用市场上内核速度最快的片上集成闪存的MCU。这些单核微控制器配备高达1 MB的闪存,为注重成本的应用产品带来更高的性能和经济性。 新产品可以运行存放在外部存储器内的代码,同时处理性能和安全保护功能不受任何影响。在可变存储器控制器(FMC)和八线SPI存储器接口等功能的辅助下,无论是运行片
[单片机]
更快的<font color='red'>STM32H7</font>微控制器,为产品带来更高的性能和经济性
58.外部SRAM实验
一。IS62WV51216 简介 1. IS62WV51216 是 ISSI(Integrated Silicon Solution, Inc)公司生产的一颗 16 位宽 512K (512*16,即 1M 字节)容量的 CMOS 静态内存芯片。 实验选用的芯片没有CS2引脚。 2. IS62WV51216读时序 3. IS62WV51216写时序 二。FSMC简介 1. STM32中FSMC框图 为什么VBT6不能用FSMC功能驱动SRAM? STM32与SRAM连接必须要连接19根地址线,FSMC_A0对应的引脚为PF0,而在100脚的STM32芯片上只有A,B,C,
[单片机]
58.外部<font color='red'>SRAM</font>实验
关于高速单片机STM32H7定时器同步启动并输出多路PWM波形的探究
随着嵌入式系统技术的不断发展,PWM(Pulse Width Modulation)信号在各种应用场景中得到了广泛应用,例如电机控制、LED灯控、音频处理等方面。在多个PWM信号同时输出时,为了保证信号的同步性和稳定性,定时器同步启动技术成为了必要的手段。 STM32系列芯片以其高性能和多功能外设而广受业界认可。其中,STM32H7系列芯片配备了丰富的定时器模块,既具备通用性又具备高性能,支持多种工作模式,可以满足多种嵌入式应用对高精度、多信号输出的需求。 本文基于STM32H7芯片,研究了定时器同步启动技术在PWM信号多路输出中的应用。我们在通过研究相关技术的基础上,提出了一种基于定时器同步启动的PWM输出方案,并通过实
[单片机]
关于高速单片机<font color='red'>STM32H7</font>定时器同步启动并输出多路PWM波形的探究
热门资源推荐
热门放大器推荐
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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