STM32H7, arm-none-eabi-gcc. DMA TX кадра в 64 байта. С выключенным кешем всё нормально. С -DUSE_DCACHE анализатор показывает неверные кадры. Первый кадр после сброса правильный. Следующие несут байты предыдущего кадра, блоками по 32 байта. Иногда начало новое, а хвост старый.
В итоге компилятор переносит цикл копирования за запись в enable. Но с -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?