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

一,STM32H7 RAM介绍

使用过STM32H7的朋友应该知道H7的RAM是有很多的区域的,不同的区域,使用了不同的总线,所能支持的外设也就不一样了,具体的总线结构如下图所示
STM32H7在RT-Thread上的多内存使用方法_第1张图片STM32H7在RT-Thread上的多内存使用方法_第2张图片
通过上图和上表就能发现如果要使用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
STM32H7在RT-Thread上的多内存使用方法_第3张图片之后重新生成工程。

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文件
STM32H7在RT-Thread上的多内存使用方法_第4张图片
可以看到定义的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 的帮助,以上排名不分先后。

你可能感兴趣的:(原创)