我正在使用LWIP和HAL驱动程序调试STM32H725VG上的HTTP服务器,这些驱动程序最初都是由STM32CubeMX生成的。问题是,在某些情况下,通过HAL_ETH_Transmit
发送的数据有一些字节被0x00替换,并且这些损坏的内容成功地到达客户端。
我已经检查了缓冲区中的数据作为参数传递到HAL_ETH_Transmit
在调用这个函数之前和之后都是完整的。因此,显然,损坏发生在从RAM传输到MAC时,因为校验和是根据损坏的数据计算的。所以我认为这个问题可能是由于缓存和DMA之间的相互作用。我试过禁用D-cache,然后损坏不会发生。
然后我认为我应该使用__DSB()
指令,应该将缓存的数据写入RAM。启用D-cache后,我在调用HAL_ETH_Transmit
之前添加了__DSB()
(这是由STM32CubeMX生成的low_level_output
函数内部),并且…什么也没发生:数据仍然损坏。
然后,经过一些实验,我发现SCB_CleanDCache()
调用之后(或代替)__DSB()
解决了这个问题。
这让我很好奇。DSB
指令说明如下:
数据同步屏障是一种特殊的内存屏障。在此指令完成之前,程序顺序中没有指令在此指令之后执行。当:
- 在此指令完成之前所有显式内存访问。
- 在此指令完成之前的所有缓存、分支预测器和TLB维护操作。
SCB_DisableDCache
的描述中有以下关于SCB_CleanDCache
的说明:
当禁用数据缓存时,您必须清理(
SCB_CleanDCache
)整个缓存,以确保任何脏数据都被刷新到外部内存。
当"所有显式内存访问"完成时,为什么DSB
不刷新缓存?完成,似乎包括缓存刷新?
dsb ish
作为线程间内存顺序的内存屏障;它只是命令当前CPU访问连贯缓存。您不会期望dsb ish
刷新任何缓存,因为在相同的内部可共享缓存一致性域中不需要这样做。就像你引用的手册中所说的,它完成内存操作。
在回写缓存上的可缓存操作只更新缓存;等待它们完成并不意味着要刷新缓存。
你的ARM系统我认为有多个相干域的微控制器与DSP?你的__DSB
内在编译成dsb sy
指令吗?假设这不会刷新缓存,它们的意思大概是它对内存/缓存操作进行排序,包括显式刷新,这仍然是必要的。
我会把钱押在业绩上。
刷新缓存意味着将数据从缓存写入内存。内存访问速度慢
L1缓存大小(假设ARM Cortex-A9)为32KB。您不希望无缘无故地将整个32KB从缓存移动到内存中。可能有二级缓存,很容易是512KB-1MB(甚至可能更多)。你也不想移动整个L2。
事实上,您的整个DMA传输可能小于缓存的大小。根本没有理由那样做。