【缘由】
我原来在STM32F769I-DISC1开发板上使用ST7789成功的实现了LVGL,使用spi_dma实现16bit传数据,原来跑得一切正常的。我今天移植FreeRTOS之后,考虑到性能优化,在main中,添加了指令缓存与数据缓存之后,就出现了花屏现象:
SCB_EnableICache(); /* Enable D-Cache */ SCB_EnableDCache();
现象如下:
禁用后,一切又正常了,因此我怀疑是开启I-Cache与D-Cache的原因。
【原因分析】
经查找资料,分析可能是我在发送DMA数据之前有缓存数据存在,因此发生送的数据有可能没有请理。网上的如下原因分析:
在 STM32F769 中启用指令缓存(I-Cache)和数据缓存(D-Cache)后,DMA 发送数据出错,可能是由缓存一致性问题导致的。下面详细分析可能的原因及对应的解决办法。 可能的原因 1. 缓存一致性问题 启用 D-Cache 后,数据可能会被缓存到高速缓存中,而 DMA 直接访问的是内存地址。如果缓存中的数据与内存中的数据不一致,DMA 就可能发送错误的数据。 2. 未进行缓存操作 在进行 DMA 操作前后,没有对相关的缓存区域进行适当的操作(如使无效、清理等),导致缓存中的数据没有及时更新到内存中,或者内存中的数据没有及时更新到缓存中。 3. 地址对齐问题 DMA 操作通常要求数据地址和长度满足一定的对齐要求。如果数据地址或长度没有正确对齐,可能会导致 DMA 传输出错。
【解决方法】
根据以及资料的提示,我找到了DMA发送的地方,在传输之前清理D-Cache,确保数据从缓存写回到内存。DMA发送结束之后使D-Cache无效,确保后续访问的数据是最新的。
修改代码如下:
while (total_size > 0) { uint16_t chunk_size = (total_size > 32000) ? 32000 : total_size; // 清理D-Cache,确保数据从缓存写回到内存 SCB_CleanDCache_by_Addr((uint32_t *)(color_p + offset), chunk_size * 2); // 使用 DMA 发送数据 if (HAL_SPI_Transmit_DMA(&hspi2, (uint8_t *)(color_p + offset), chunk_size*2) != HAL_OK) { printf("DMA transmission failed\r\n"); break; } // 等待DMA传输完成 while (spi2_dma_tx_flag == 0) ; // 使D-Cache无效,确保后续访问的数据是最新的 SCB_InvalidateDCache_by_Addr((uint32_t *)(color_p + offset), chunk_size * 2); spi2_dma_tx_flag = 0; // 重置标志 total_size -= chunk_size; offset += chunk_size; }
重新烧录程序后,花屏现象成功解决。
【经验总结】
这次的现象,是显示屏,很容易就出现问题。如果在其他的场合,比如发送串口数据,那问题暴露就不是这么的明显。因此在开启数据缓存功能之后,切记要注意这点,在DMA传输之前把数据清理。