在外部 RAM 中运行 FreeRTOS 的 STM32F4

eva*_*ing 1 ram gcc cortex-m3 stm32 ld

我们有一个论文项目正在工作,他们正试图让外部 RAM 为 STM32F417 MCU 工作。该项目正在尝试一些真正需要资源且内部 RAM 不够的东西。

问题是如何最好地做到这一点。

当前的方法只是将链接脚本 (gnu ld) 中的 RAM 地址替换为外部 RAM 的地址。

这种方法的问题在于,在初始化期间,由于 FSMC 尚未初始化,因此芯片必须在内部 RAM 上运行。

它似乎可以工作,但是一旦 pvPortMalloc 运行,我们就会遇到一个硬错误,这可能是由于取消引用虚假地址,我们可以看到变量在系统初始化时没有正确初始化(我猜这是有道理的,因为内部 RAM 不是完全使用,可能应该使用)。

我意识到这是一个模糊的问题,但是在 Cortex M4 MCU(更具体地说是 STM32F4)上的外部 RAM 中运行代码时,一般的方法是什么?

谢谢

小智 5

FreeRTOS 定义并使用单个大内存区域进行堆栈和堆管理;这只是一个字节数组,其大小由 中的configTOTAL_HEAP_SIZE符号指定FreeRTOSConfig.h。FreeRTOS 使用其pvPortMalloc函数在此内存区域中分配任务堆栈,因此此处的主要目标是将 FreeRTOS 堆区域放入外部 SRAM。

FreeRTOS 堆内存区域定义在heap_*.c(heap_3.c使用标准库 malloc的除外,它没有定义任何自定义堆区域),该变量称为ucHeap。您可以使用编译器扩展来设置其部分。对于 GCC,这将类似于:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
Run Code Online (Sandbox Code Playgroud)

现在我们需要配置链接描述文件以将此自定义部分放入外部 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
    ...
}
Run Code Online (Sandbox Code Playgroud)

这会将区域放置ucHeap在外部 SRAM 中,而所有其他文本和数据部分将放置在默认存储区域(内部闪存和 ram)中。

一些注意事项:

  • 确保在调用任何 FreeRTOS 函数(例如xTaskCreate)之前初始化 SRAM 控制器/FSMC
  • 一旦启动任务,所有堆栈分配的变量将被放置在ucHeap(即ext RAM)中,但全局变量仍然分配在内部RAM 中。如果您仍然有内部 RAM 大小问题,您可以配置其他全局变量以放置在".sram_section"using 编译器扩展中(如 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>;
Run Code Online (Sandbox Code Playgroud)

这不需要任何特殊的链接器脚本编辑,所有内容都可以放在默认部分中。请注意,使用此解决方案,链接器不会为堆显式保留任何内存,并且您将丢失一些潜在有用的信息/错误(例如堆区域不适合 ext RAM)。但是只要您只有ucHeap外部 RAM 并且您的 RAMconfigTOTAL_HEAP_SIZE小于外部 RAM 大小,这可能会正常工作。