STM32H7, arm-none-eabi-gcc예요. 64바이트 프레임을 DMA TX로 보내요. 캐시를 끄면 괜찮아요. -DUSE_DCACHE를 켜면 분석기에 잘못된 프레임이 보여요. 리셋 후 첫 프레임은 맞아요. 그다음부터는 이전 프레임의 바이트가 32바이트 블록 단위로 섞여 있어요. 가끔 앞쪽은 새 데이터고 뒤쪽은 옛날 데이터예요.
결국 컴파일러가 복사 루프를 enable 쓰기 뒤로 옮겨요. 근데 -O0도 똑같아요. tx_buf를 volatile로 해도 똑같아요. 루프 뒤에 DSB를 넣어도 똑같아요. 디스어셈블리에서는 store가 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?