STM32F4在外部RAM中运行FreeRTOS

时间:2016-03-30 18:02:52

标签: gcc ld ram stm32 cortex-m3

我们有一个正在研究的论文项目,他们正试图让外部RAM为STM32F417 MCU工作。 该项目正在尝试一些非常耗费资源的东西,内部RAM还不够。

问题是如何做到最好。

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

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

它似乎工作但是一旦pvPortMalloc运行我们得到一个硬故障,它可能是由于解除引用虚假地址,我们可以看到变量未在系统初始化时正确初始化(这是有道理的,我猜自内部当它可能应该是时,根本不使用RAM。

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

由于

2 个答案:

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

一些注意事项:

  • 确保在调用任何FreeRTOS函数之前初始化SRAM控制器/ FSMC(如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,而不是静态地声明堆。