旧的背景故事
之前有过 GD32H7 打开网络功能的尝试,因为没有在最终工程产品中用到该芯片,仅作评估后封存。
当时的现象是,完全采用与官方例程一模一样的库、外设配置、调用顺序、操作方法,只是我将官方的 keil 例程改为 cmake-gcc 工程。问题是官方例程编译烧录后一切正常,而我的工程编译后无论如何都无法 ping 通。
我对 lwip 这个网络库、ETH 外设这块的了解实在有限,GD 支持也无法找到原因所在。
原因
总的来说,GD32H7 芯片需要以类似这样的配置方法,将 0x0000 开始的整个寻址区域,都设置 MPU 保护,作为背景设置,然后后续的 MPU 配置块再做实际配置。
mpu_region_init_struct mpu_init_struct;
/* disable MPU */
ARM_MPU_Disable();
mpu_init_struct.region_number = MPU_REGION_NUMBER0;
mpu_init_struct.region_base_address = 0x00000000U;
mpu_init_struct.instruction_exec = MPU_INSTRUCTION_EXEC_NOT_PERMIT;
mpu_init_struct.access_permission = MPU_AP_NO_ACCESS;
mpu_init_struct.tex_type = MPU_TEX_TYPE0;
mpu_init_struct.access_shareable = MPU_ACCESS_SHAREABLE;
mpu_init_struct.access_cacheable = MPU_ACCESS_NON_CACHEABLE;
mpu_init_struct.access_bufferable = MPU_ACCESS_NON_BUFFERABLE;
mpu_init_struct.subregion_disable = 0x87;
mpu_init_struct.region_size = MPU_REGION_SIZE_4GB;
mpu_region_config(&mpu_init_struct);
mpu_region_enable();
/* enable MPU */
ARM_MPU_Enable(MPU_MODE_PRIV_DEFAULT);
问题是如何产生的
在 GD32H7 手册1.3 存储器映射上可见
0x0000 0000~0x0007 FFFF 划归为 ITCM RAM(来自共享 RAM),但是这个区域又被划归为代码区域。我暂时不太理解其意图。总之就是在内核运行的过程中将该区域认为是 RAM 区,所以有读写可能。
依据参考材料的说法,GD 官方勘误表或任何手册都没有描述这一点。当然官方例程很多时候也没有做到这一点,否则我此前改为 gcc 编译应当是一切正常。只有 ST 官方的甚至 touchgfx 这个图形库手册而非芯片手册中有这样的描述。
M7处理器上,必须防止对外部存储器的推测性访问,否则可能引发高延迟或系统错误。 对于STM32H7R/S,这将影响访问内存的AXI主设备,并显著降低图形性能。 MPU可通过控制可访问的地址范围来防止推测性读取访问。 最简单的方法是使用包含整个内存区域的背景区域,通过将其设置为“强排序,永不执行”来限制访问。 背景区域应定义在默认区域ID-1中,因为所有其他区域的优先级都将高于此区域。 然后,应为需要访问的内存区域定义具有相应设置的其他MPU区域。 在STM32H7R/S上最多可定义16个区域。
也就是这是一个 M7 内核原设计就有的缺陷,而我使用 stm32H7 只是 ST 官方做成芯片时使用某种手段规避了问题,或者甚至只是恰巧没有碰到。
参考资料备查
GD32H7移植NEXTDUO问题
https://forum.anfulai.cn/forum.php?mod=viewthread&tid=125782&extra=
GD32H757ZMT6 仅因 Flash/Load image 布局变化,程序运行稳定性就出现明显差异
https://forum.anfulai.cn/forum.php?mod=viewthread&tid=131926&extra=