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



我有一个项目在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 位无关。 它是由访问外部 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 字节边界限制的缓存中。 它似乎工作正常,但它并没有让我充满信心。

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

先写入内存,然后读取或配置链接器 将堆区域初始化归零...这可能需要汇编代码来获得正确的排序,以便在零初始化可能失败的情况下首先启用 RAM

最新更新