RT-Thread-Nano移植
- [1. 动态内存堆](#1. 动态内存堆)
-
- [1.1 问题](#1.1 问题)
- [1.2 解决](#1.2 解决)
- [3. 问题根源](#3. 问题根源)
1. 动态内存堆
1.1 问题
按照官方文档:在 RT-Thread Studio 上使用 RT-Thread Nano,新建nano工程后,可以正常运行。
但是开启内存管理后,系统无法正常启动,串口没有任何输出。
1.2 解决
参考详细说明:RT-Thread Nano 移植原理
原因是没有指定动态内存堆的起始地址和结束地址,需要在board.c中指定。有两种方法:
- 方法1:使用数组作为动态内存堆。如果要使用Finsh组件,RT_HEAP_SIZE 设置尽量大一些
c
board.c文件中添加:
#if defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024*4
static uint32_t rt_heap[RT_HEAP_SIZE];
RT_WEAK void *rt_heap_begin_get(void)
{
return rt_heap;
}
RT_WEAK void *rt_heap_end_get(void)
{
return rt_heap + RT_HEAP_SIZE;
}
#endif
- 方法2:指定系统HEAP,把空余RAM全部作为动态内存heap使用
- 使用 RAM ZI 段结尾处作为 HEAP 的起始地址
- 使用 RAM 的结尾地址作为 HEAP 的结尾地址
不同编译器的内存标识不一样,不同环境下的获取方式:
- MDK环境下,栈结束地址的获取:
c
extern unsigned char Image$$ER_IROM1$$Limit; // 获取RW段在FLASH中的加载地址
extern unsigned char Image$$RW_IRAM1$$Base; // 获取RW段在RAM中的运行地址
extern unsigned char Image$$RW_IRAM1$$RW$$Limit; // 获取RW段在RAM中的结束地址
extern unsigned char Image$$RW_IRAM1$$ZI$$Limit; // 获取ZI段在RAM中的结束地址
- IAR环境下,栈结束地址的获取:
c
#pragma section="CSTACK"
#define HEAP_BEGIN (__segment_end("CSTACK"))
- GCC环境下,栈结束地址的获取。RT-Thread Studio用的就是GCC编译环境:
c
extern int __bss_end;
#define HEAP_BEGIN ((void *)&__bss_end)
c
#define STM32_SRAM1_START (0x20000000)
#define STM32_SRAM1_END (STM32_SRAM1_START + 20 * 1024) // 结束地址 = 0x20000000(基址) + 20K(RAM大小)
#if defined(__CC_ARM) || defined(__CLANG_ARM)
extern int Image$$RW_IRAM1$$ZI$$Limit; // RW_IRAM1,需与链接脚本中运行时域名相对应
#define HEAP_BEGIN ((void *)&Image$$RW_IRAM1$$ZI$$Limit)
#endif
#define HEAP_END STM32_SRAM1_END
3. 问题根源
RT-Thread Studio使用的是GCC编译器,使能动态内存后,在drv_common.h文件中,定义了heap的开始和结束地址
- HEAP_BEGIN:堆的起始地址,
- HEAP_END:堆的结束地址
- 可以看到,这里把SRAM中空闲的内存,全部用作heap空间
- 在link.lds中,定义了栈分配地址。(对应stm32 在 KEIL MDK 开发环境下的链接脚本文件 xxx.sct,散列文件)
因为我在新建项目的时候选择的是STM32F103ZGT6(flash1G,SRAM 96K),而实际的芯片是STM32F103ZGT6(flash 512M,SRAM 64K),所以HEAP地址错误,导致使能动态内存后,程序无法找到内存空间,系统无法正常运行。
参考: