GD32F4的片上RAM坑
1. 问题描述
在GD32F450VK上移植rtthread的时候,当执行到下面函数的时候
rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
会进入context_rvds.S文件下HardFault_Handler中断,然后出错,如下:
HardFault_Handler中断一般跟内存相关,往往错误都是内存访问越界、内存不可操作或操作失败。
2. rtthread的rt_system_heap_init作用
我查看了一下关于HEAP_BEGIN和HEAP_END的配置,发现没什么问题。
#define GD32_SRAM_SIZE 256
#define GD32_SRAM_END (0x20000000 + GD32_SRAM_SIZE * 1024)
#ifdef __CC_ARM
extern int Image$$RW_IRAM1$$ZI$$Limit;
#define HEAP_BEGIN (&Image$$RW_IRAM1$$ZI$$Limit)
#elif __ICCARM__
#define HEAP_END GD32_SRAM_END
rt_system_heap_init函数主要是为malloc相关函数预先指定可用空间的函数。
HEAP_BEGIN指向的是程序运行所需要的RAM空间的尾地址,HEAP_END指向整个RAM空间的尾地址,这样整个RAM空间就被分成了两部分,前边部分是程序运行所需要的RAM空间,后部分是RAM剩余的部分作为预先为malloc准备的空间,具体如下:
对于GD32F450VK来讲,RAM起始地址是0x20000000,空间大小是256k,(&Image$ $ RW_IRAM1$ $ ZI $ $Limit)是keil获取程序运行所需RAM空间结束地址的方式,所以上面的设计应该没有什么问题。
3. 找到问题
后来查找数据手册,最后发现这256k是分成好几块的,每一块描述如下:
GD32F4xx系列微控制器含有高达256KB片上SRAM、4KB备份SRAM和512KB附加SRAM,所有的SRAM均支持字节、半字(16比特)和整字(32比特)访问。
片上SRAM可分为4块,分别为SRAM0(112KB)、SRAM1(16KB)、SRAM2(64KB)和TCMSRAM(64KB)。SRAM0、SRAM1和SRAM2可以被所有的AHB主机访问,然而,TCMSRAM(紧耦合存储器SRAM)只可被Cortex ® -M4内核的数据总线访问。BKPSRAM(备份SRAM)应用于备份域,即使当VDD供电电源掉电时,该SRAM仍可保持其内容。附加SRAM(ADDSRAM)只在一些特殊的GD32F4xx器件中可用。由于采用AHB互联矩阵,上述SRAM块可以同时被不同的AHB主机访问,例如,即使CPU正在访问SRAM0,USBHS也可以访问SRAM1。
对应空间地址如下:
这个ADDSRAM对于256k及以下的RAM是没有的,我们发现256k被分成了好几部分,而且地址上还不是连续的,因此这256k不能连续分配,这样我们的GD32_SRAM_SIZE就不能为256了,最后修改如下:
//sram
#define GD32_SRAM0_SIZE 112
#define GD32_SRAM1_SIZE 16
#define GD32_SRAM2_SIZE 64
#define GD32_TCMSRAM_SIZE 64
#define GD32_SRAM_SIZE (GD32_SRAM0_SIZE + GD32_SRAM1_SIZE + GD32_SRAM2_SIZE) //192
#define GD32_SRAM_END (0x20000000 + GD32_SRAM_SIZE * 1024)
4. 其它
上面的设计会发现一个问题那就是TCMSRAM无法得到使用。那是因为TCMSRAM(紧耦合存储器SRAM)只可被Cortex ® -M4内核的数据总线访问。
解决这个问题的方法,可以通过修改连接脚本来设置程序运行的RAM空间,指定到TCMSRAM就可以了,这个实现我会在后面来分享。