bmp图片分段加载问题调试记录-遇到了STM32 SDIO DMA对齐问题

问题描述:

1.一次性加载所有图片数据到内存,并解析,一切正常。

2.采用512字节以内(一次读取一个扇区内的数据),分段加载,解析,一切正常,正常图片如下。

3.当我使用4096B缓冲区时(会一次读取多个扇区),解析图片就出现问题了,症状如下:

出现了很多条纹,通过调试分析应该是出现了字节错位,期初以为是算法问题,通过不断的调试发现算法没问题,最后就怀疑是否是原始数据出问题了,但是同一张图片我使用一次加载到内存的方式就不会出现这个问题。

 

我的分段加载bmp图片原理,首先给一个缓冲区,一个缓冲区大小,根据缓冲区大小计算一次读取的数据量(自动计算对齐,16位与24位位图存在插值情况,就是水平像素所占字节必须是4的整数倍,如果不是的话,会进行1-3字节插值)

我的算法中是32位就4字节对齐读取,24位就12字节对齐读取,16位就8字节对齐读取,加载原理是,先读取50个字节的bmp图头部信息,解析出响应的数据,然后获取位图数据起始位置偏移,然后使用FATFS的lseek跳转到起点位置,比如测试的文件起点是54字节处,24bit的位图,通过lseek跳转到54字节处开始读取数据。

 

怀疑1:原始文件出问题了。

通过一次加载能正常解析,排除此问题。

怀疑2:可能是算法问题

通过测试发现512字节以内的分段是正常的,算法应该不会有问题。

怀疑3:SDIO数据对齐问题或FATFS数据对齐问题

通过将读取的数据进行打印调试,发现问的第510字节处出现问题了

截图处出现问题了,这个是通过FATFS读取的文件数据打印后记录的,显示510字节处出现了2个2C,后面一个2C是异常插入进去的。

 

这是正常文件的截图,标记处只有1个2C,通过这个可以证明是文件系统读取数据出问题了,这个时候就有2个可能性,1是底层SDIO读取TF卡数据出问题了,出现这个问题肯定是对齐导致的问题,但是仔细一想,FATFS与底层读取数据的接口是以扇区为单位,一次必须读取512字节,根本不存在对齐问题,所以问题可能在FATFS内。

 

FATFS底层读取接口,以扇区为单位,固定512字节对齐,不可能出现这个问题,所以这个问题出现在FATFS内的可能性很大,在某个特殊的情况下,比如读取2个跨扇区的字节时,底层也是读取2个扇区2x512字节,然后由FATFS取出所需要的这2个字节。

 

 

 

 

通过调试发现,比如我先读的是文件的前面50个字节,然后把偏移调整到54字节,再几个扇区,理论上2次读取应该是从文件的第0扇区开始,但是实际上并不是,第二次读取会从扇区1开始,FATFS检测到内部有缓存的第一扇区数据(之前读取的),会直接拷贝到buff,然后接着读取第二扇区,可问题是给的buff地址没有对齐,原因是512字节偏移54字节,导致从buff的458字节(非4字节对齐)开始读取,上图截图所示位置,指针结尾是14A,指向的应该是BC,E8,A7,这个地址未对齐,然后传入到SD卡底层,接下来我们再看看数据读取后这个buff数据变成什么样了。

 

最后2个字节,给覆盖率,由于上面的地址结尾14A是个2B对齐,导致这个地址的最低2bit被强制清零了,也就是地址4字节对齐,导致数据buff地址往前移动了2字节,把刚刚正常的结尾AF 79 给覆盖掉了,看来最终问题还是出现在SDIO,由于我使用了DMA,SDIO的寄存器是个32位的。

 

传入到底层SD卡读取时的地址是非4字节对齐的,这就解释了为何1个扇区以内的分段是可以正常工作的,由于1个扇区以内的分段文件系统使用的是拷贝方式,而超过1个扇区的分段,会先拷贝一部分数据进去,后面的直接将指针传入到了底层(这个指针可能会非4字节对齐)

 

我的代码中DMA存储器是32位的,所以被强制对齐也是正常的,理论上还可能出现读取4字节以为的数据出问题,比如你读取1字节,给一个字节缓冲区,会被强制写4个字节进去,就会溢出。

 

 

把SDIO DMA读写方向的存储器宽度设置为8bit,问题解决了。

 

代码之前工作正常不代表就是正确的,多折腾还是会学到不少东西,也能挖掘出以前的bug,至此这个问题算是解决了,BMP图片也能随意分段加载解析,也支持缩放了,还有非4字节对齐插值的等着测试,需要测试非对齐的16位,24位位图,以及超大的bmp图片缩小问题。

 

发布了144 篇原创文章 · 获赞 371 · 访问量 81万+

猜你喜欢

转载自blog.csdn.net/cp1300/article/details/104390669
今日推荐