STM32H7,arm-none-eabi-gcc。用 DMA 发送 64 字节的帧。关闭缓存时一切正常。加上 -DUSE_DCACHE 后,分析仪显示帧是错的。复位后的第一帧是对的。之后的帧带着上一帧的字节,按 32 字节一块。有时前面是新的,尾部是旧的。
最终编译器会把拷贝循环移到使能写入之后。但 -O0 也一样。tx_buf 加 volatile 也一样。循环后面加 DSB 也一样。反汇编里,存储指令都在 CR 写入之前。
for (size_t i = 0; i < n; i++)
tx_buf[i] = data[i];
__asm volatile ("dsb 0xF" ::: "memory");
DMA1_S3_M0AR = (uint32_t)(uintptr_t)tx_buf;
DMA1_S3_NDTR = (uint32_t)n;
DMA1_S3_CR |= DMA_EN;
缓存是在 board_init() 里开启的:
SystemInit();
#ifdef USE_DCACHE
SCB_EnableICache();
SCB_EnableDCache();
#endif
构建命令:
make clean && make OPT=-O0 DEFS=-DUSE_DCACHE -DTRACE_ITM
在我看来顺序是对的,数据却还是旧的。还有什么可能?
从英语翻译·查看原文STM32H7, arm-none-eabi-gcc. DMA TX of a 64 byte frame. Cache off: fine. With -DUSE_DCACHE, the analyzer shows wrong frames. The first frame after reset is correct. Later ones carry bytes of the previous frame, in 32 byte blocks. Sometimes the front is new and the tail is old.
Eventually the compiler moves the copy loop behind the enable write. But -O0 is the same. tx_buf volatile is the same. DSB after the loop is the same. In the disassembly the stores come before the CR write.
for (size_t i = 0; i < n; i++)
tx_buf[i] = data[i];
__asm volatile ("dsb 0xF" ::: "memory");
DMA1_S3_M0AR = (uint32_t)(uintptr_t)tx_buf;
DMA1_S3_NDTR = (uint32_t)n;
DMA1_S3_CR |= DMA_EN;
Cache is enabled in board_init():
SystemInit();
#ifdef USE_DCACHE
SCB_EnableICache();
SCB_EnableDCache();
#endif
Build:
make clean && make OPT=-O0 DEFS=-DUSE_DCACHE -DTRACE_ITM
The order looks right to me and the data is still old. What else is there?