我们有一个正在研究的论文项目,他们正试图让外部RAM为STM32F417 MCU工作。 该项目正在尝试一些非常耗费资源的东西,内部RAM还不够。
问题是如何做到最好。
当前的方法是将链接脚本(gnu ld)中的RAM地址替换为外部RAM的地址。
该方法的问题在于,在初始化期间,芯片必须在内部RAM上运行,因为FSMC尚未初始化。
它似乎工作但是一旦pvPortMalloc运行我们得到一个硬故障,它可能是由于解除引用虚假地址,我们可以看到变量未在系统初始化时正确初始化(这是有道理的,我猜自内部当它可能应该是时,根本不使用RAM。
我意识到这是一个模糊的问题,但在Cortex M4 MCU(更具体地说是STM32F4)的外部RAM中运行代码的一般方法是什么?
由于
答案 0 :(得分:3)
FreeRTOS定义并使用单个大内存区域进行堆栈和堆管理;这只是一个字节数组,其大小由configTOTAL_HEAP_SIZE
中的FreeRTOSConfig.h
符号指定。 FreeRTOS使用其pvPortMalloc
函数在此内存区域中分配任务堆栈,因此这里的主要目标是将FreeRTOS堆区域放入外部SRAM。
FreeRTOS堆内存区域在heap_*.c
中定义(heap_3.c
除外,它使用标准库malloc并且它没有定义任何自定义堆区域),该变量被调用ucHeap
。您可以使用编译器扩展来设置其部分。对于海湾合作委员会来说,这将是:
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
现在我们需要配置链接描述文件以将此自定义部分放入外部SRAM。有几种方法可以做到这一点,它还取决于您使用的工具链。使用GCC,一种方法是为SRAM定义一个存储区域,并将".sram_data"
的一个部分附加到SRAM区域,如:
MEMORY
{
...
/* Define SRAM region */
sram : ORIGIN = <SRAM_START_ADDR>, LENGTH = <SRAM_SIZE>
}
SECTIONS
{
...
/* Define .sram_data section and place it in sram region */
.sram_data :
{
*(.sram_data)
} >sram
...
}
这会将ucHeap
区域放在外部SRAM中,而所有其他文本和数据部分将放在默认的内存区域(内部闪存和内存)。
一些注意事项:
xTaskCreate
)ucHeap
(即ext RAM)中,但全局变量仍然分配在内部RAM中。如果仍有内部RAM大小问题,可以使用编译器扩展配置其他全局变量放置在".sram_section"
中(如ucHeap所示)pvPortMalloc/vPortFree
,而不是stdlib malloc/free
。这是因为只有pvPortMalloc/vPortFree
将在ext RAM中使用ucHeap区域(并且它们是线程安全的,这是一个加号)pvPortMalloc/vPortFree
使用不同的内存块大小进行大量动态任务创建/删除和内存分配,请考虑使用heap_4.c
而不是heap_2.c
。使用多个不同的块大小时,heap_2.c
存在内存碎片问题,而heap_4.c
能够将相邻的空闲内存块组合成一个大块另一个(也可能更简单)的解决方案是将ucHeap变量定义为指针而不是数组,如下所示:
static uint8_t * const ucHeap = <SRAM_START_ADDR>;
这不需要任何特殊的链接器脚本编辑,所有内容都可以放在默认的部分中。请注意,使用此解决方案,链接器不会明确为堆保留任何内存,并且您将丢失一些可能有用的信息/错误(例如堆区域不适合ext RAM)。但只要你在外部RAM中只有ucHeap
并且你的configTOTAL_HEAP_SIZE
小于外部RAM大小,那就可以了。
答案 1 :(得分:2)
当应用程序启动时,它将尝试通过将数据清零为零来初始化数据,或者将数据初始化为非零值,具体取决于放置变量的部分。使用正常的运行时模型,在调用main()之前发生。所以你有类似的东西:
1)重置向量调用init代码 2)C运行时初始化代码初始化变量 3)C运行时初始化代码调用main()
如果使用链接器将变量放在外部RAM中,则需要确保在初始化之前可以访问RAM,否则会出现硬故障。因此,您需要拥有一个为您设置系统的引导加载程序,然后启动您的应用程序....或者更简单地只需编辑启动代码即可执行以下操作:
1)重置向量调用init代码 2)&gt;&gt;&gt; C运行时初始化代码配置外部RAM&lt;&lt;&lt; 3)C运行时初始化代码初始化变量 4)C运行时初始化代码调用main()。
这样,在您尝试访问RAM之前,RAM就可用了。
但是,如果您只想在外部RAM中安装FreeRTOS堆,那么您可以保持初始代码不变,只需使用适当的堆实现 - 基本上不只是声明一个大的静态数组。例如,如果使用heap_5,那么您需要做的就是确保在执行任何分配之前调用堆init函数,因为堆init只描述了要用作堆的RAM,而不是静态地声明堆。