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

发布者:BlissfulJoy最新更新时间:2019-08-26 来源: eefocus关键字:STM32H7  TCM  SRAM  动态内存  分配 手机看文章 扫描二维码
随时随地手机看文章

27.1 初学者重要提示


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


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


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


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;

MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number           = MPU_REGION_NUMBER1;

MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;

MPU_InitStruct.SubRegionDisable = 0x00;

MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

/* 配置SRAM1的属性为Write through, read allocate,no write allocate */

    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;

    MPU_InitStruct.BaseAddress      = 0x30000000;

    MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_128KB;

    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

    MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

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

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

推荐阅读最新更新时间:2024-11-14 19:42

STM32内存分配解析及变量的存储位置
内存映射 在一些桌面程序中,整个内存映射是通过虚拟内存来进行管理的,使用一种称之为内存管理单元(MMU)的硬件结构来将程序的内存映射到物理RAM。在对于RAM紧缺的嵌入式系统中,是缺少MMU内存管理单元的。因此在一些嵌入式系统中,比如常用的STM32来讲,内存映射被划分为闪存段(也被称为Flash,用于存储代码和只读数据)和RAM段,用于存储读写数据。 STM32的Flash和RAM地址范围 标题中所说的内存是指STM32的Flash和RAM,下图是ARM Cortex M3的地址映射 从图中我们可以看出,RAM地址是从0x2000 0000开始的,Flash地址是从0x8000 0000开始的。 Flash 代码
[单片机]
STM32内存<font color='red'>分配</font>解析及变量的存储位置
ATtiny13 SRAM数据存储器
SRAM数据存储器 Figure 9 给出了ATtiny13 SRAM 空间的组织结构。 前 160 个数据存储器包括了寄存器文件、I/O 存储器及内部数据 SRAM。起始的 32 个地 址为寄存器文件与 64 个标准 I/O 存储器,接着是 64 字节的内部数据 SRAM。 数据存储器的寻址方式分为5 种:直接寻址、带偏移量的间接寻址、间接寻址、带预减量的间接寻址和带后增量的间接寻址。寄存器文件中的寄存器R26 到R31 为间接寻址的指针寄存器。 直接寻址范围可达整个数据区。 带偏移量的间接寻址模式能够寻址到由寄存器Y 和 Z 给定的基址附近的63 个地址。 在自动预减和后加的间接寻址模式中,寄存器X、Y 和Z 自动增加或减少。
[单片机]
ATtiny13 <font color='red'>SRAM</font>数据存储器
STM32H7教程】第11章 STM32H7移植SEGGER的硬件异常分析
11.1 初学者重要提示 MDK本身也是支持硬件异常分析的,就是不够直观,此贴是MDK的硬件异常分析文档: http://forum.armfly.com/forum.php?mod=viewthread&tid=21940 。 IAR8带的硬件异常分析比较好用,在本章11.6小节有说明。 11.2 移植方法 直接移植SEGGER的硬件异常代码会有错误警告,这里针对IAR和MDK版本做了些简单修改,方便大家移植到自己的工程里面。 MDK版本移植 源文件位于本章配套例子的UserseggerHardFaultHandlerMDK文件夹,添加如下两个文件到工程里面即可。 IAR版本移植 源文件位于本章配套例子
[单片机]
【<font color='red'>STM32H7</font>教程】第11章 <font color='red'>STM32H7</font>移植SEGGER的硬件异常分析
STM32通过sram启动方法来运行一个flash解锁程序
STM32通过sram启动方法 最近将两年前买的STM32F103最小系统板拿出来准备学习,安装完MDK5后写了一个点亮LED程序,发现无法下载。查了下购买评论,原来这种板子发货时已经锁定了flash。鼓捣了2、3天,最后采取的办法是通过sram启动方式,来运行一个flash解锁程序,程序运行后就可以将板子恢复。在此将该过程记录下来。 一、系统板外形是这种。 二、硬件跳线 将两个黄色跳线帽全部插在1端,即BOOT0、BOO1全部接1。 三、MDK5设置 3-1、新建一个工程,取名Flash_Unlock。设置Run-time,选择CMSIS- CORE、Device- Startup、Device- StdPeriph D
[单片机]
STM32通过<font color='red'>sram</font>启动方法来运行一个flash解锁程序
STM32F302R8T6移植RT-THREAD SRAM配置
自上篇文章,终于可以下载程序到芯片中.然后用ST-LINK在线调试,发现跑到RT-THREAD中的 rt_system_heap_init函数就不出来,跟踪进入 在两者中间就出现硬件错误的中断. 查看一下HEAP初始化的大小 可以明显看到错误在HEAP的尾地址. 看一下调用的参数 view plain copy rt_system_heap_init((void*)STM32_SRAM_BEGIN, (void*)STM32_SRAM_END); 问题就在STM32_SRAM_END这里,上图看一下 修改后的参数为 view plain copy // /e // o Inte
[单片机]
STM32F302R8T6移植RT-THREAD <font color='red'>SRAM</font>配置
瑞萨推出闪存和SRAM的32位通用微控制器
RX64M MCU集成4MB闪存和512KB SRAM, 实现了卓越的连通性和高性能,适用于工业设备及其他物联网应用。 2014年2月26日,日本东京讯—全球领先的半导体及解决方案供应商瑞萨电子株式会社(TSE:6723),今天发布了RX64M系列微控制器(MCU),作为RX族32位MCU的旗舰产品,该系列产品首次使用了40纳米工艺。这一最新系列共包括112个产品,均集成了2013年11月发布的RX系列新CPU内核“RXv2”, 运行频率为120MHz,并内置零等待周期高速闪存,,适用于要求高速实时性能及大容量存储器的工业设备及网络设备。新型MCU可以使系统设计人员更快速、更高效地开发出高性能、支持多种
[物联网]
瑞萨推出闪存和<font color='red'>SRAM</font>的32位通用微控制器
linux内核中的文件描述符(六)--fd的分配--expand_files
Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csdn.net/ce123) 我们先贴出expand_files函数的源码: view plain copy print ? int expand_files(struct files_struct *files, int nr) { int err, expand = 0; struct fdtable *fdt; fdt = files_fdtable(files); if (nr = fdt- max_fdset
[单片机]
FCC:美国将为5G分配更多毫米波频谱
  近日,在首届MWC-US(美国电信展)上, FCC 主席Ajit Pai宣布,今年年底 FCC 将就为 5G 分配更多毫米波频谱进行投票表决。下面就随网络通信小编一起来了解一下相关内容吧。   FCC:美国将为5G分配更多毫米波频谱   时间先回到一年前,在去年7月14日,时任 FCC 主席Tom Wheeler召集委员会(Commission)就毫米波频率分配进行投票,结果是全票通过,FCC正式为 5G 分配接近11GHz的毫米波频率。   当时,NPRM还有对未来工作的伏笔,即FCC将继续为 5G 分配更多频率努力。而这些频率中,包括了最近半年由中国和欧洲相继宣布的24GHz和42GHz频段。这也意味着:未来24GH
[网络通信]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习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