STM32F4在外部RAM中运行FreeRTOS



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

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

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

这种方法的问题是,在初始化过程中,由于FSMC尚未初始化,芯片必须在内部RAM上运行。

它似乎有效,但一旦运行pvPortMalloc,我们就会出现硬故障,这可能是由于取消引用伪造的地址,我们可以看到变量在系统初始化时没有正确初始化(我想这是有道理的,因为内部RAM根本没有使用,而它可能应该使用)。

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

感谢

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

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

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中,而所有其他文本和数据部分将放在默认存储区域(内部闪存和ram)中。

几个注意事项:

  • 在调用任何FreeRTOS函数(如xTaskCreate)之前,请确保初始化SRAM控制器/FFSMC
  • 一旦启动任务,所有堆栈分配的变量都将放在ucHeap(即extRAM)中,但全局变量仍分配在内部RAM中。如果仍然存在内部RAM大小问题,可以使用编译器扩展配置其他全局变量以放置在".sram_section"中(如ucHeap所示)
  • 如果您的代码使用动态内存分配,请确保使用pvPortMalloc/vPortFree,而不是stdlib malloc/free。这是因为只有pvPortMalloc/vPortFree会使用extRAM中的ucHeap区域(而且它们是线程安全的,这是一个优点)
  • 如果使用具有不同内存块大小的pvPortMalloc/vPortFree进行大量动态任务创建/删除和内存分配,请考虑使用heap_4.c而不是heap_2.c。当使用几个不同的块大小时,heap_2.c存在内存碎片问题,而heap_4.c能够将相邻的空闲内存块组合成一个大块

另一个(可能更简单)的解决方案是将ucHeap变量定义为指针而不是数组,如下所示:

static uint8_t * const ucHeap = <SRAM_START_ADDR>;

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

当应用程序启动时,它将尝试通过将数据清零或初始化为非零值来初始化数据,具体取决于变量所在的部分。使用正常运行时模型,这将在调用main()之前发生。所以你有这样的东西:

1) 重置矢量调用init代码2) C运行时初始化代码初始化变量3) C运行时初始化代码调用main()

如果使用链接器将变量放置在外部RAM中,则需要确保在初始化之前RAM是可访问的,否则将出现硬故障。因此,您需要有一个引导加载程序来为您设置系统,然后启动您的应用程序。。。。或者更简单地说,只需编辑启动代码即可执行以下操作:

1) 重置矢量调用init代码2)>>C运行时初始化代码配置外部RAM<lt<3) C运行时初始化代码初始化的变量4) C运行时init代码调用main()。

这样,在你尝试访问它之前,RAM是可用的。

然而,如果您只想在外部RAM中拥有FreeRTOS堆,那么您可以不影响init代码,只需使用适当的堆实现——基本上是一个不只是声明大型静态数组的堆实现。例如,如果您使用heap_5,那么您所需要做的就是确保在执行任何分配之前调用heap-init函数,因为heap-init只是描述将哪个RAM用作堆,而不是静态地声明堆。

最新更新