Gcc 在外部RAM中运行FreeRTOS的STM32F4

Gcc 在外部RAM中运行FreeRTOS的STM32F4,gcc,ld,ram,stm32,cortex-m3,Gcc,Ld,Ram,Stm32,Cortex M3,我们有一个论文项目正在进行中,他们正试图让外部RAM为STM32F417 MCU工作。 该项目正在尝试一些真正需要资源的东西,而内部RAM是不够的 问题是如何最好地做到这一点 当前的方法是用外部RAM的地址替换链接脚本gnu ld中的RAM地址 这种方法的问题是,在初始化过程中,芯片必须在内部RAM上运行,因为FSMC尚未初始化 这似乎是可行的,但一旦pvPortMalloc运行,我们就会遇到一个硬故障,这可能是由于取消引用伪地址,我们可以看到变量在系统初始化时没有正确初始化,我想这是有道理的,

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

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

当前的方法是用外部RAM的地址替换链接脚本gnu ld中的RAM地址

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

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

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


谢谢

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

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
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
    ...
}
1重置向量调用初始化代码 2C运行时初始化代码初始化变量 3 C运行时初始化代码调用main

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

1重置向量调用初始化代码
2>>>C运行时初始化代码配置外部RAM当应用程序启动时,它将尝试通过将数据清除为零或将其初始化为非零值来初始化数据,具体取决于变量所在的部分。使用正常运行时模型,这将在调用main之前发生。所以你有这样的想法:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
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
    ...
}
1重置向量调用初始化代码 2C运行时初始化代码初始化变量 3 C运行时初始化代码调用main

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

1重置向量调用初始化代码
2>>>C运行时初始化代码配置外部RAMFreeRTOS定义并使用单个大内存区域进行堆栈和堆管理;这只是一个字节数组,其大小由FreeRTOSConfig.h中的configTOTAL\u HEAP\u size符号指定。FreeRTOS使用其pvPortMalloc函数在该内存区域分配任务堆栈,因此这里的主要目标是将FreeRTOS堆区域放入外部SRAM中

FreeRTOS堆内存区域在heap*.c中定义,heap*.3.c除外,它使用标准库malloc,并且没有定义任何自定义堆区域,该变量称为ucHeap。您可以使用编译器扩展来设置其节。对于GCC来说,这类似于:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
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
    ...
}
现在,我们需要配置链接器脚本,以将此自定义部分放入外部SRAM。有几种方法可以做到这一点,这同样取决于您使用的工具链。使用GCC,一种方法是为SRAM定义一个内存区域,并为附加到SRAM区域的.SRAM_数据定义一个部分,如:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
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
    ...
}

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

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

FreeRTOS堆内存区域在heap*.c中定义,heap*.3.c除外,它使用标准库malloc,并且没有定义任何自定义堆区域,该变量称为ucHeap。您可以使用编译器扩展来设置其节。对于GCC来说,这类似于:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
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
    ...
}
现在我们需要配置链接器脚本来放置这个自定义分区 n进入外部SRAM。有几种方法可以做到这一点,这同样取决于您使用的工具链。使用GCC,一种方法是为SRAM定义一个内存区域,并为附加到SRAM区域的.SRAM_数据定义一个部分,如:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".sram_data")));
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
    ...
}

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

您到底需要在外部SRAM中放置什么?大数据结构?你所有的读写数据?您需要您的代码从SRAM运行,还是可以驻留在闪存中?我们最初的想法是,将所有内容都放在外部ram中是最容易的。有些加密密钥和计算对于MCU来说实在太大了。但出于某些原因,我们无论如何都需要这样做。代码可以从flash执行,所以我指的是堆栈和堆。您使用的是什么版本的FreeRTOS堆管理源文件heap_1.c、heap_2.c等。?我相信FreeRTOS使用pvPortMalloc在堆中分配任务堆栈,所以这可能是您需要移动到SRAM的唯一方法,但这在很大程度上取决于您使用的heap.*.c版本。您需要将什么确切地放置到外部SRAM中?大数据结构?你所有的读写数据?您需要您的代码从SRAM运行,还是可以驻留在闪存中?我们最初的想法是,将所有内容都放在外部ram中是最容易的。有些加密密钥和计算对于MCU来说实在太大了。但出于某些原因,我们无论如何都需要这样做。代码可以从flash执行,所以我指的是堆栈和堆。您使用的是什么版本的FreeRTOS堆管理源文件heap_1.c、heap_2.c等。?我相信FreeRTOS使用pvPortMalloc在堆中分配任务堆栈,所以这可能是您唯一需要移动到SRAM的事情,但这在很大程度上取决于您使用的heap.*.c版本