STM32H7在RT-Thread上的多内存使用方法

一,STM32H7 RAM介绍

使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
在这里插入图片描述在这里插入图片描述
通过上图和上表就能发现如果要使用DMA就必须对多RAM进行管理,要么自己去实现内存管理,要么通过__attribute__ 关键字去定义,这样或多或少会有些麻烦,后来看到安福莱STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间 这篇文章,想到RT-Thread 肯定也应该是支持多内存管理的,看到查看官方的文档中心发现 可以使用 memheap 管理算法。
在这里插入图片描述
既然RT-Thread 已经支持了多内存的管理算法,那么接下来就要考虑一个问题,RT-Thread是默认使能HEAP,且RT-Thread很多优秀的组件都使用了动态内存,所以要解决究竟是哪一块内存分给rt_malloc 使用。

二 多RAM管理办法

STM32H7的内存可用内存有很多,DTCM和AXI SRAM使用哪一个作为主heap呢?本文分别对DTCM和AXI SRAM做主heap来进行介绍。
首先找到RT-Thread bsp/stm32/目录下的stm32h7的支持包,通过ENV工具打开 memheap
在这里插入图片描述之后重新生成工程。

1,TCM区域做为主heap

TCM区域的优势是速度快,仅仅只支持MDMA的访问,但是内存小只有128K,不支持其他DMA的访问

  第一步 修改keil连接文件link.sct  
      ; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
 第三步 写一个axi_sram.c
struct rt_memheap axi_sram_heap;
void *axi_sram_malloc(unsigned long size)
{
    return rt_memheap_alloc(&axi_sram_heap,size);
}

void axi_sram_free(void *ptr)
{
    rt_memheap_free(ptr);
}

void *axi_sram_calloc(unsigned int n,unsigned int size)
{
    void* ptr = NULL;
    
    ptr = axi_sram_malloc(n * size);
    if(ptr)
    {
        memset(ptr, 0, n*size);
    }
    
    return ptr;
}
 第四步 修改drv_common.c,增加一行axi_sram初始化的代码
  #if defined(RT_USING_HEAP)
    rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif

    rt_memheap_init(&axi_sram_heap,"AXISRAM",(void *)RT_AXI_SRAM_BEGIN,RT_AXI_SRAM_SIZE);   

编写一个测试代码

int main(void)
{
    int count = 1;
    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    
    char *test_ptr;

    while (count++)
    {
        test_ptr = axi_sram_malloc(100);
        rt_pin_write(LED0_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED0_PIN, PIN_LOW);
        rt_thread_mdelay(500);
        axi_sram_free(test_ptr);
    }
    return RT_EOK;
}

编译一下

Program Size: Code=55136 RO-data=7508 RW-data=548 ZI-data=4060  
After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed:  00:00:08

没有错误,没有警告,下载正常运行。

2,AXI SRAM区域作为主heap

AXI区域 的主要优势是内存大 512K ,支持DMA1 DMA2 IDMA的访问,劣势不如TCM速度快

  第一步 修改keil连接文件link.sct  
  ; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM_HEAP 0x24000000 0x00080000  {  ; RW data
   *(.RAM_HEAP)
  }
}
 第二步 修改board.h
#define STM32_SRAM_SIZE           (128)
#define STM32_SRAM_END            (0x20000000 + STM32_SRAM_SIZE * 1024)

#if defined(__CC_ARM) || defined(__CLANG_ARM)
extern int Image$$RW_IRAM1$$ZI$$Limit;
#define HEAP_BEGIN      (&Image$$RW_IRAM1$$ZI$$Limit)
#elif __ICCARM__
#pragma section="CSTACK"
#define HEAP_BEGIN      (__segment_end("CSTACK"))
#else
extern int __bss_end;
#define HEAP_BEGIN      (&__bss_end)
#
 第三步 修改board.h
#define STM32_SRAM_SIZE           (512)
#define STM32_SRAM_END            (0x24000000 + STM32_SRAM_SIZE * 1024)

#if defined(__CC_ARM) || defined(__CLANG_ARM)
//extern int Image$$RW_IRAM2$$ZI$$Limit;
#define HEAP_BEGIN      0x24000000//(&Image$$RW_IRAM1$$ZI$$Limit)
#elif __ICCARM__
#pragma section="CSTACK"
#define HEAP_BEGIN      (__segment_end("CSTACK"))
#else
extern int __bss_end;
#define HEAP_BEGIN      (&__bss_end)
#endif

设置heap的起始区域是0x24000000区域的512k大小。
修改完毕看一下,来测试一下

#define LED0_PIN    GET_PIN(B, 10)
    uint8_t test_buff[1000]= {0};
int main(void)
{   
    int count = 1;
    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    
    char *test_ptr;
    test_buff[10] = 1; 
    while (count++)
    {
        test_ptr = rt_malloc(100);
        rt_pin_write(LED0_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED0_PIN, PIN_LOW);
        rt_thread_mdelay(500);
        rt_free(test_ptr);
    }
    return RT_EOK;
}

编译一下

Build started: Project: project
*** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
Build target 'rtthread'
compiling main.c...
linking...
.\board\linker_scripts\link.sct(15): warning: L6314W: No section matches pattern *(.RAM_HEAP).
Program Size: Code=55084 RO-data=7508 RW-data=548 ZI-data=4964  
Finished: 0 information, 1 warning and 0 error messages.
After Build - User command #1: fromelf --bin .\build\keil\Obj\rt-thread.axf --output rtthread.bin
".\build\keil\Obj\rt-thread.axf" - 0 Error(s), 1 Warning(s).
Build Time Elapsed:  00:00:02

有一处警告 不要紧,查看一下map文件
在这里插入图片描述
可以看到定义的test_buff是在地址0x20000898的位置。

三 总结分析

实验成功

TCM作为了主heap既使用rt_malloc来分配tcm区域的内存,axi_sram_malloc 来分配 axi区域的内存,但是这种方法存在一个问题,如果在使用DMA的时候,会出现问题,RT-Thread的组件默认使用了rt_malloc去申请内存,如果想正常的使用这种方法,需要更具实际情况去把组件里面的rt_malloc去替换成axi_sram_mallo。

AXI_SRAM做为主heap既使用rt_malloc去分配axi_sram区域的内存。如果要使用tcm区域,那么就直接定义全局变量就可以了。使用这样方法存在的问题就是无法把高速的tcm利用率最大化,优势就是就是不需要重定向RT-Thread组件里面的rt_malloc。

致谢

感谢 liu2guang balanceTWK jiejieTop aeo123 lymzzyh greedyhao zylx 的帮助,以上排名不分先后。

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RT-Thread 作品秀】基于RT-Thread的网络照相机作者:吴顶顶 概述随着科技的进步和互联网的发展,基于物联网的可拍照设备也越来越多的融入到人们的生活中来,例如在超市中,管理者利用拍照设备定时抓取货架照片,分析货物状态,并补充、优化货物摆放;在酒吧里,管理者会利用拍照设备定时抓拍酒架照片,传送到网络平台供大众浏览,以招揽更多顾客。本网络照相机基于STM32H7+RTThread平台,采集摄像头数据,并通过无线网络传送到服务器,提供SD卡配网、手动拍摄、定时拍摄、照片推送等功能,并提供windows上位机提供控制和照片显示功能。 主要功能有: 格式化sd卡:格式化sd卡,但是会保留网络配置文件,其他文件全部删除 设备重启:重启设备 实时拍照:发送指令给照相机,照相机拍照,并把照片回传 定时拍照:照相机依据下发的拍照时间,在时间到达时拍摄一张照片,并传给服务器 按键拍照:点击板上用户按钮,拍摄一张照片,并传给服务器 定时任务:可以新建/删除/查询定时拍照任务,任务存储在sd卡中,重启有效 开发环境硬件:ART-PI(STM32H750主控)+ OV2640模组 RT-Thread版本:4.0.3 SDK 版本:1.0.1 开发工具及版本:RT-Thread Studio 1.1.5, Qt5.14.0 RT-Thread使用情况概述内核部分:调度器,信号量,互斥锁,内存管理 调度器:多任务调度 信号量:用于唤醒对应任务 互斥锁:用于互斥资源独占访问 内存管理:动态内存申请与释放 组件部分:虚拟文件系统,IPC,I2C,RTC,NTP 虚拟文件系统:文件操作,sd卡、照片文件 IPC:mqtt发送数据需要 I2C:配置摄像头模块需要 RTC和NTP:同步时间 软件包部分:paho mqtt,cJSON,netutils pahomqtt:用于和服务器通信 cJSON:解析、封装mqtt消息 netutils:NTP网络对时 其他:base64 用于将图片文件转换成字符串,便于mqtt传输 硬件框架总体的硬件框架如下图所示: 本网络摄像机硬件结果较为简单,即art-pi连接一个摄像头模组,art-pi板上用到了AP6212无线模块,外部内存,led指示灯,和sd卡。其中,摄像头模块用于采集图像信号;AP6212用于和服务器进行通信;因一张图像数据量较大,片内内存不够,故而使用外部内存;led灯用于指示设备工作状态;sd卡用于保存网络、服务器、和定时任务配置。 软件框架说明整体的软件框架如下图所示,网络照相机内部有一个proxy线程,负责和云端进行通信,在接收到云端消息后会解析,并分发到其他的线程执行,然后将执行结果返回到云端;照相机发生了其他的事件,例如用户按键拍照,也会将数据传给proxy线程,proxy线程再将数据发送到云端。用户通过上位机终端软件连接上云服务器,实现与照相机的通信及控制。 整个系统支持接入多个照相机,如下图所示,不同的照相机通过sd卡配置文件中sn进行区分,上位机软件可以显示所有在线的照相机,但同一时间只支持操作一个。 软件模块说明1. 用户线程创建流程如下图所示为用户线程创建流程 用户线程作用描述如下: main:用于创建sd_card 线程,检测按键事件,闪灯; sd_card:用于管理与sd卡相关的工作,包括拍照,网络配置,定时任务; network:负责联网,根据sd卡的配置文件连接到指定的wifi网络; proxy:负责启动mqtt,并管理与云端的通信,其他线程都需要通过proxy线程与云端交互数据; event:定时任务和按键任务,在定时时间到达时,或者用户按键时拍摄照片并通过proxy上传云端。 2. 通信接口及流程2.1 MQTT订阅主题设备向服务器订阅主题: /ter/query/discovery,用于接收设备发现消息 /ter/sn/request,用于接收针对该设备的指令,其中sn为设备的SN号,下同 客户端向服务器订阅主题: /dev/response/discovery,用于接收设备发现回复 /dev/response/will,用于接收设备遗嘱消息 /dev/sn/response,用于接收设备操作指令回复 /dev/sn/event,用于接收设备的通知 2.2 设备发现所有的设备均订阅/ter/query/discovery主题,客户端向该主题发布发现消息,所有收到消息的设备向/dev/response/discovery回复一条消息,而客户端又订阅了/dev/response/discovery主题,故而便可以知道哪些设备在线了。 设备连上服务器的时候,会定义一个遗嘱消息,主题为/dev/sn/will,客户端订阅了该主题,当设备因为某些原因掉线,则超过一定时间之后,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值