STM32F407 SD卡文件系统接口优化-DMA字节对齐问题

前几天,做了图片显示的实验,将一张24BIT的BMP从SD卡显示到TFT LCD上。
LCD用FSMC控制。
速度真他慢,真像PPT的渐变效果。

测试了一下,300ms一屏,实在无法忍受。
决定看看时间都浪费在哪里。

测试1:

如果刷一种颜色到LCD,只要10ms。
程序就是用FOR循环将320*240个U16发到LCD。

测试2:

屏蔽从SD卡读数据,只执行将原来图片显示中显示的代码。
运行时间27ms。应该算正常,毕竟有不少的数据处理。

也就是说,读数据画了270ms。要优化,就只能从大头入手,毕竟你就算把图片数据处理全优化掉,也才17ms。
根据本人多人经验:只要涉及到数据读取速度的优化,有一个屡试不爽的方法,就是一次读多一点的数据。

由于RAM不够,不可能将图片一次性全部读到RAM,原来的程序是每次读一行,那么我们现在就改为一次读10行吧。

测试3:

改为一次读10行或者20行,测试,时间300ms?

经验失效?
不应该,毕竟多年经验。而且时间确实是浪费在读数据啊?
分析一下读数据,并输出LOG调试,发现问题:
1 每次读一行,FATFS文件系统调用SD卡接口时,只会读一个SECTOR。
2 每次读多行,FATFS文件系统调用SD卡接口时,会读取多个SECTOR。但是,但是,由于SD卡使用DMA,需要4字节对齐。
程序中对指针进行判断,如果不是四字节对齐,那么就改为一次读一个SECTOR。
如果关键路径在SD卡读sector数据,那么,我们的优化就没有效果,这当然正常,毕竟我读再多,你还是每次读一个sector。

测试4:

把4字节对齐的处理屏蔽,就用原来的读多块,不对齐只会造成数据错,功能还是能跑的。
实测,100ms,但是图片确实显示不对了,有点拖影。
(如果4字节 DMA不对齐,读写会有1-3个字节的偏移;2字节DMA补对齐,则会有1个字节的偏移;这也是一个经验)

那么说:
读多一点数据,这个经验还是有效的。

但是字节对齐还是个问题啊?

百度,GOOGLE:
http://bbs.21ic.com/icview-561094-1-1.html
“STM32F2/F4的DMA支持拆分重组了,也就是buffer可以是非对齐的方式(需要在配置时使能)。
如果是F1,常用的方法是自己准备一块4字节对齐的buffer,当应用程序传进来的buffer不对齐时,使用自己的buffer,并与应用程序的buffer做memcpy。
当然,应用程序要尽量避免使用不对齐的buffer.”

看文档:
“9.3.10 可编程数据宽度、封装/解封、字节序”

看代码:

SDDMA_InitStructure.DMA_Channel = SD_SDIO_DMA_CHANNEL;
SDDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;
SDDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)BufferSRC;
SDDMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
SDDMA_InitStructure.DMA_BufferSize = BufferSize;
SDDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
SDDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
SDDMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
SDDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
SDDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
SDDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
SDDMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
SDDMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
SDDMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
SDDMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;

既然可以设置外设跟内存的字长,那么说明两者可以设置不同字长啊,也就是文档中所说的封装,也就是别人说的拆分重组吧?

测试5:

将DMA_MemoryDataSize改为DMA_MemoryDataSize_Byte.
图片显示正常,刷屏时间100ms.

求证:

查阅多家开发板例程代码,好像都是判断地址,不是4字节对齐就改为一次读一个sector然后拷贝数据。
心里犯嘀咕,难道改为byte会有啥隐藏问题?

留下评论