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

STM32H7 + external SDRAM - memcpy with length 3 crashes - word boundaries, cache settings?

我在 STM32H753ieval 板上有一个项目 运行,在外部存储器中有堆,使用 freeRTOS,以 STM32 立方体演示为模型。

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

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

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。

这是缓存问题、内存问题还是库问题?我该如何解决?

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

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

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

这个问题也让我很伤心。它与未初始化的缓冲区或 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 区域。 micro 不直接访问外部 SDRAM。相反,数据被加载到没有 4 字节边界限制的缓存中。貌似还可以,但是我的信心不足。