STM32H7 +外部SDRAM-长度为3的memcpy崩溃-字边界,缓存设置?

时间:2018-08-30 04:47:36

标签: caching gcc stm32 memcpy

我有一个在STM32H753ieval板上运行的项目,该项目具有外部存储器中的堆,并带有freeRTOS,以STM32多维数据集演示为模型。

目前未启用MPU和缓存。 (据我所知,它们的功能已被注释掉)

这在main()函数中有效,其中a和b在内部内存中。

int* aptr;
int* bptr;

int main()
{
    //  MPU_Config();
    //  CPU_CACHE_Enable();

    int a[100]; int b[100];
    memcpy(a, b, 3);
    aptr = a;
    bptr = b;
    ...

但是,当freeRTOS线程在堆上创建变量时,memcpy无法使用某些长度值。

static void mymemcpy(char* dst, char* src, int len)
{
    for (int i = 0; i < len; i++)
    {
        dst[i] = src[i];
    }
}

void StartThread(void* arg)
{
    int a[100]; int b[100];
    for (int i = 0; i < 10; i++)
    {
        memcpy(aptr, bptr, i);   //works, using same mem as main
    }
    for (int i = 0; i < 10; i++)
    {
        mymemcpy(a, b, i);       //works, using external ram mem, but with mymemcpy
    }
    memcpy(a, b, 4);             //works, seems not a overrun issue
    for (int i = 0; i < 10; i++)
    { 
        memcpy(a, b, i);         //jumps to random memory when i == 3, probably an undefined handler
    }
    while(1);
}

这是我第一次处理微缓存和外部RAM。

这是缓存问题,内存问题,库问题吗?我该如何解决?

注意:我不在乎数组是否未初始化。我很高兴复制垃圾。

2 个答案:

答案 0 :(得分:0)

该设备很可能崩溃,因为对初始化内存的读取可能没有设置正确的ECC位,并且当处理器在读取操作期间发现此错误时,便会出现双位错误。

首先写入内存,然后读取它或配置链接器 零初始化您的堆区域...这可能需要汇编代码才能获得正确的排序,然后首先启用ram,否则零初始化可能会失败

答案 1 :(得分:0)

这个问题也使我感到非常悲伤。它与未初始化的缓冲区或ECC位无关。这是由访问外部SDRAM时的数据对齐错误引起的。微读指令可以在4个字节的边界内访问的任何字节组。它无法跨越读取4字节边界。例子:

Load Register R0 (4-bytes) @ 0xc0000000; // good juju
Load Register R0 (2-bytes) @ 0xc0000002; // good juju
Load Register R0 (1-byte)  @ 0xc0000003; // good juju
Load Register R0 (4-bytes) @ 0xc0000004; // good juju
Load Register R0 (4-bytes) @ 0xc0000002; // bad juju
Load Register R0 (2-bytes) @ 0xc0000003; // bad juju

跨4字节边界执行读取会导致总线异常(我的事件被硬故障处理程序捕获)。

您的a和b缓冲区在堆栈中声明,因此您将不知道它们的起始地址。您的mymemcpy()是安全的,因为它一次复制1个字节。但是,newlib memcpy实际上一次复制4个字节。该代码可能会尝试跨4字节边界读取并引发异常。即使起始地址位于4字节边界上,结束地址也可能不在此位置。

同样的问题也适用于memset,memcmp等。但是它也可能在后台发生。示例:

std::array<uint8_t, 10> a; 
std::array<uint8_t, 10> b; 
a = b;  // potentially bad juju because = operator calls memcpy

为解决此问题,我启用了数据缓存并设置了MPU区域。微型计算机不会直接访问外部SDRAM。而是将数据加载到没有4字节边界限制的缓存中。看来还可以,但是并没有让我充满信心。