为什么DSB不刷新缓存?



我正在使用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传输可能小于缓存的大小。根本没有理由那样做。

最新更新