我有一个在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。
这是缓存问题,内存问题,库问题吗?我该如何解决?
注意:我不在乎数组是否未初始化。我很高兴复制垃圾。
答案 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字节边界限制的缓存中。看来还可以,但是并没有让我充满信心。