一,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的访问
- ; *************************************************************
- ; *** 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)
- }
- }
复制代码- 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速度快
- ; *************************************************************
- ; *** 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)
- }
- }
复制代码- #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)
- #
复制代码- #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。
|