STM32读取bmp图片 条纹 错色 以及FatFs读写错误

您所在的位置:网站首页 fatfs读取文件大小 STM32读取bmp图片 条纹 错色 以及FatFs读写错误

STM32读取bmp图片 条纹 错色 以及FatFs读写错误

2023-08-28 04:14| 来源: 网络整理| 查看: 265

前言

从SD卡读取BMP图片到屏幕,用的SDIO加DMA的方式。运行了freertos实时系统,fatfs文件系统。

硬件平台:STM32F429IGT6

屏幕尺寸:1024*600 图像缓存在外部sdram中,16位色

目标:解决一些贴子,描述读取BMP图像问题 和一些帖子fatfs读写出错问题

问题

BMP一种简单的文件格式,尤其是24位色彩图像,就是像素的阵列在内存中的顺序排列,最前面14字节的fileHeader, 接着40字节infoHeader,(选项的颜色表),BGR BGR BGR....more...

 图像的尺寸在infoHeader中,其中要注意的是每一row 都是4 字节对齐。格式详情就不再描述了,可以自行搜索。最近看到一些帖子,说用fatfs文件系统读取BMP图像,有条纹,变色,错乱等等,还有一些帖子说fatfs文件系统超过512左右读写出错,发生的数据的整体偏移,f_read的字节流偶尔被 多插入或缺失了 一个 或 几个 字节。比如这张图片,在阿莫电子论坛看到的Fatfs中F_read(),为什么读超过500字节就出问题??? (amobbs.com 阿莫电子论坛)

 注意背景的黑点开头的蓝色条纹

原因

        先说原因,是因为fatfs对SD的访问,通过DMA读取要4字节对齐,就是说介绍DMA数据的Buffer要4字节对齐。不然(SDIO与DMA)的FIFO对齐缘故,会有一或几个错误字节插入字节流,导致f_read读取的字节流,会发生整体性偏移一个或两个字节。不要怀疑文件系统。ST官方的解决办法是,官方知道fatfs文件系统对SD的访问可能不会遵守4字节对齐。它方案是当用户传入pBuffer指针是4字节对齐,直接用DMA读取多个sector。不是4字节对齐的,就用4字节对齐的scratch[BLOCKSIZE]先读取一个sector,然后copy到pBuffer中。写SD也类似。并且在cubeMX生成的SD与Fatfs的read 和write 接口代码中,加入了一个定义开关ENABLE_SCRATCH_BUFFER 如下

/* * Some DMA requires 4-Byte aligned address buffer to correctly read/wite data, * in FatFs some accesses aren't thus we need a 4-byte aligned scratch buffer to correctly * transfer data */ /* USER CODE BEGIN enableScratchBuffer */ #define ENABLE_SCRATCH_BUFFER /* USER CODE END enableScratchBuffer */ /* Private variables ---------------------------------------------------------*/ #if defined(ENABLE_SCRATCH_BUFFER) ... __ALIGN_BEGIN static uint8_t scratch[BLOCKSIZE] __ALIGN_END;//BLOCKSIZE =512 #endif

我于是用硬件平台 搭了个范例,参数在前言中,先看的用于测试的原始图片pic004.bmp,如下

图片 没选好,四周都是白的,但是不影响。

平台正确显示,的图片如下:小黄人 是黄的,苹果是红的。

 图片下面 的条子 是未覆盖完全,显示完全正确。

然后下面自己的代码,我将移除对对ENABLE_SCRATCH_BUFFER 的支持,直接通过DMA对SD读写数据。调用HAL_SD_ReadBlocks_DMA(&hsd,pData,BlockAdd,NumberOfBlocks);不管pData是否4字节对齐。pData 的空间pvPortMalloc()函数分配的,对齐是否看运气。

然后错误图片来了,什么都没有变,唯一变得是pData 4字节对齐是否。

 4字节对齐是否 还是有影响的,颜色变了,右边还有一条裂纹,很明显BGR发生了字节的整体错位,再一些技巧把pData对齐到其他 非4字节对齐的位置。图片如下代码后

prow = pvPortMalloc(rowlen+8);//多要8字节好对齐 prow4align = prow; if(((uint32_t)prow4align)&0x03ul) {prow4align = (uint8_t *)((((uint32_t)prow4align)+3)&(~0x03ul));} //先4字节对齐,然后偏移1 2 3等等 prow4align +=3;/* advance 3byte */ //如果改变这个advance 值,对图片有影响,恭喜你,你找到原因了,4字节对齐故障

还是 ,颜色变了,右边还有一条裂纹。

 下面是我的 BMP图片读取显示参考代码。

/** ****************************************************************************** * @file : * @author :@GAOJUN * @date : * @brief : ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ /****** include begin ******/ #include "user_lib.h" /****** include end ******/ /** * @brief * @note * @param * @param * @retval None */ void user_bmp_trans_row(uint8_t *prow,uint16_t rowWidth,uint16_t yloc) { uint8_t *sbuf =prow; uint8_t *dbuf =(uint8_t *)&frame01[0][0]; uint16_t *desbuf; uint16_t wdes = 1024; uint8_t bppd = 2; uint16_t dcolor =0u; uint32_t scolor =0u; uint32_t index; /* line_comment */ dbuf = dbuf +(((uint32_t)(wdes*bppd))*(yloc)); desbuf = (uint16_t *)dbuf; for(index =0;index>=3; scolor =2; scolor =3; /* color */ dcolor = scolor; desbuf[index] = dcolor; } } /** * @brief * @note * @param * @param * @retval None */ void user_sd_bmp_test_main(void) { FATFS fatfs; FIL infile; uint8_t retSD; FRESULT fr; uint32_t br; BMP_TypeDef bmp; uint8_t *prow; uint8_t *prow4align; uint32_t rowlen; retSD = f_mount(&fatfs,"0:",1); // if(retSD){} // else{} fr = f_open(&infile, "0:/pics/pic004.bmp",FA_READ); if(fr){} else { f_read(&infile,(void *)&bmp.fHeader.bfType,sizeof(bmp),&br); if(br != sizeof(bmp)) { return ; } /* continue,tag check "BM" */ if(bmp.fHeader.bfType != 0x4D42u) { return ; } /* bit check */ if(bmp.iHeader.biBitCount != 24u) {return ;} /* fetch image data */ f_rewind(&infile); f_lseek(&infile,bmp.fHeader.bfOffBits); /* aligned 4 byte */ rowlen = bmp.iHeader.biWidth*3; if(rowlen%4){rowlen += 4- rowlen%4;} prow = pvPortMalloc(rowlen+8); prow4align = prow; // if(((uint32_t)prow4align)&0x03ul) // {prow4align = (uint8_t *)((((uint32_t)prow4align)+3)&(~0x03ul));} // prow4align +=3;/* advance 3byte */ if(prow ==NULL){return ;} for(uint16_t i=0;i< bmp.iHeader.biHeight;i++) { /* read a row */ f_read(&infile,prow4align,rowlen,&br); /* translate a row */ user_bmp_trans_row(prow4align,bmp.iHeader.biWidth,(bmp.iHeader.biHeight-i-1)); if(br !=rowlen){break;} } vPortFree(prow); } f_close(&infile); }

参考头文件如下:

/** ****************************************************************************** * @file : * @author :@GAOJUN * @date : * @brief : ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ /****** include begin ******/ #include "user_lib_def.h" /****** include end ******/ /** * @brief XXX_handle Structure definition */ typedef __packed struct { uint16_t bfType; uint32_t bfSize; uint16_t bfReserved1; uint16_t bfReserved2; uint32_t bfOffBits; }BMP_FHEADER_TypeDef; /** * @brief XXX_handle Structure definition */ typedef __packed struct { uint32_t biSize; uint32_t biWidth; uint32_t biHeight; uint16_t biPlanes; uint16_t biBitCount; uint32_t biCompression; uint32_t biSizeImage; uint32_t biXPelsPerMeter; uint32_t biYPelsPerMeter; uint32_t biClrUsed; uint32_t biClrImportant; }BMP_IHEADER_TypeDef; /** * @brief color table rgb item Structure definition */ typedef __packed struct { uint8_t rgbBlue; uint8_t rgbGreen; uint8_t rgbRed; uint8_t rgbReserved; }BMP_TBITEM_TypeDef; /** * @brief XXX_handle Structure definition */ typedef __packed struct { BMP_FHEADER_TypeDef fHeader; BMP_IHEADER_TypeDef iHeader; }BMP_TypeDef; /*----------------------------------------------------------------------------*/ void user_sd_bmp_test_main(void);

图片尺寸1024*575。上面代码,先读取54字节的头信息,然后偏移到f_lseek(&infile,bmp.fHeader.bfOffBits);后开始读取BGRBGR等等,512-54=458(456+2),456%4=0 如果我们在54字节处开始4字节对齐的Buffer的读取一横线1024*3。如上代码,将在文件系统读取第2个512字节块时,无法4字节对齐。图案(54-|-456-|-2)_(2-510),这里2)_(2就开始没有对齐。为了f_read不在乎对齐,就必须修改文件系统的read write驱动去主动对齐。

参考如下

/** ****************************************************************************** * @file : * @author :@GAOJUN * @date : * @brief : ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ /****** include begin ******/ #include "user_lib.h" #include /****** include end ******/ /* * Some DMA requires 4-Byte aligned address buffer to correctly read/wite data, * in FatFs some accesses aren't thus we need a 4-byte aligned scratch buffer to correctly * transfer data */ #define ENABLE_SCRATCH_BUFFER /* Private variables ---------------------------------------------------------*/ /****** Private variables begin ******/ osSemaphoreId_t SDBinarySemRxHandle; const osSemaphoreAttr_t SDBinarySemRx_attributes = { .name = "SDBinarySemRx" }; osSemaphoreId_t SDBinarySemTxHandle; const osSemaphoreAttr_t SDBinarySemTx_attributes = { .name = "SDBinarySemTx" }; #if defined(ENABLE_SCRATCH_BUFFER) static uint8_t scratch[BLOCKSIZE] __ALIGNED(4); #endif static volatile DSTATUS Stat = STA_NOINIT; extern volatile uint16_t run_led_period; /****** Private variables end ******/ /** * @brief * @note * @param * @param * @retval None */ DSTATUS user_sd_check_status(void) { Stat = STA_NOINIT; if(HAL_SD_GetCardState(&hsd) ==HAL_SD_CARD_TRANSFER) { Stat &= ~STA_NOINIT; } return Stat; } /** * @brief * @note * @param * @param * @retval None */ DSTATUS user_sd_init(void) { Stat = STA_NOINIT; /* related semaphore */ SDBinarySemRxHandle = osSemaphoreNew(1, 0, &SDBinarySemRx_attributes); SDBinarySemTxHandle = osSemaphoreNew(1, 0, &SDBinarySemTx_attributes); /* low level hardware */ user_sdio_sd_init(); /* check status */ Stat = user_sd_check_status(); return Stat; } /** * @brief Tx Transfer completed callbacks * @param hsd: Pointer to SD handle * @retval None */ void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) { osSemaphoreRelease(SDBinarySemTxHandle); } /** * @brief Rx Transfer completed callbacks * @param hsd: Pointer SD handle * @retval None */ void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) { osSemaphoreRelease(SDBinarySemRxHandle); } /** * @brief * @note * @param * @param * @retval None */ DRESULT user_SD_ReadBlocks_DMA(uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks) { uint16_t timeout =3000; DRESULT res = RES_ERROR; #if defined(ENABLE_SCRATCH_BUFFER) if (!((uint32_t)pData & 0x3)) { #endif /* Fast path cause destination buffer is correctly aligned */ /* prepare semaphore */ osSemaphoreAcquire(SDBinarySemRxHandle,0); /* start DMA stream */ HAL_SD_ReadBlocks_DMA(&hsd,pData,BlockAdd,NumberOfBlocks); /* wait cplt semaphore release */ osSemaphoreAcquire(SDBinarySemRxHandle,800); /* and then wait for card state ok */ while(timeout) { /// if(HAL_SD_GetCardState(&hsd) ==HAL_SD_CARD_TRANSFER) { res = RES_OK; break; } /* wait a moment and release cpu also */ timeout--; osDelay(1); } if(timeout == 0u)/* timeout occur */ { res = RES_ERROR; } #if defined(ENABLE_SCRATCH_BUFFER) } else { /* Slow path, fetch each sector a part and memcpy to destination buffer */ uint32_t i; for(i=0;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3