0.前言
本文讲的是如何读取SD卡中的BMP图像并存入DDR中
使用的开发板是zedboard
vivado使用的是2019.1配套SDK
1.bmp图像
讲程序之前先简单说一下bmp图像
1.1bmp位深
BMP是位图(bitmap),可以分为1、4、8、16、24及32位图像等。
1位深的bmp图只有种颜色,就是纯粹的黑白图片。图中1个像素点占1个比特位,即1个字节可以描述8个像素点。
8位深的bmp图有种颜色,通常是灰度图,即由不同程度的黑白色构成的图像,也可以是伪彩色图,即由较少色彩构成的图像。该图中1个像素点占1个字节,即1个字节可以描述1个像素点。
24位深的bmp图有种颜色,称为真彩色图。24个比特位以8位一组分三个通道,即RGB通道。该图中1个像素点占3个字节,即3个字节可以描述1个像素点。
1.2bmp图像构成
BMP文件由以下四部分组成:
- 位图文件头:用于描述整个bmp文件的情况,具体包括BMP文件的类型、文件大小和位图起始位置等信息。
- 位图信息头:含有 BMP 图像的宽、高、压缩方法,以及定义颜色等信息。
- 颜色表:用于说明位图中的颜色(24位深的bmp图像没有颜色表)。
- 像素阵列:记录位图的每一个像素点(记录顺序是在扫描行内是从左到右,扫描行之间是从下到上)。
在属性的详细信息内可以看见图像的宽、高及位深信息
这里用notepad++打开该图
画红线的部分是文件头,绿色部分是信息头,紫色部分是颜色表,橙色部分一直到最后都是像素矩阵。
其中文件头每一位的具体含义如下表
其中信息头每一位的具体含义如下表
举个例子
图中黑圈内的两个四字节数就是图像的宽和高,因为这里是小端存储的,所以宽和高分别是00000114和00000114,换成10进制就是276,和从图像属性内看到的一致。
2.bd部分
本文设计的SD卡读取及对DDR的写入只需要zynq本身就可以完成,因此BlockDesign中添加一个zynq核并打开SD以及其他基本配置即可。
3.SDK部分
3.1读取SD卡前置设置
如图所示,读取SD卡前需要先右击bsp文件选择board support package setting,然后勾选xilffs,然后选择下面的xilffs页面,将use_lfn后面的value中的0改为1。xilffs是打开SD卡需要使用的工具,use_lfn是允许读取长整型的文件名
3.2代码
完整代码如下
#include "xparameters.h"
#include "xil_printf.h"
#include "ff.h"
#include "xdevcfg.h"
#include "stdio.h"
#include "xil_io.h"
#include <stdlib.h>
#include <string.h>
#include "xil_types.h"
#include "xil_cache.h"
#define FILE_NAME "cat.bmp" //定义文件名
static FATFS fatfs; //文件系统
unsigned int const DDR_buffer_addr = 0x01000000;//DDR地址
//初始化SD卡
u32 Init()
{
FRESULT result;
TCHAR *Path = "0:/";
result =f_mount(&fatfs,Path, 0);
if(result){
printf("error : f_mount returned error \r\n");
return XST_FAILURE;
}
return XST_SUCCESS ;
}
//SD卡写函数
u32 Write(char *FileName,u32 src_addr,u32 byte_len,u32 start_addr)
{
FIL file; //文件对象
FRESULT result;
UINT BytesWr; //f_write函数返回已写入的字节数
result = f_open(&file,FileName,FA_CREATE_ALWAYS | FA_WRITE);//打开一个文件,如果不存在,则创建一个文件
if(result)
{
printf("error : f_open returned error \r\n");
return XST_FAILURE;
}
result = f_lseek(&file, start_addr);//移动打开的文件对象的文件读/写指针,相当于将鼠标放在文件的某个开始位置。
if(result)
{
printf("error : f_lseek returned error \r\n");
return XST_FAILURE;
}
result = f_write(&file,(void*) src_addr,byte_len,&BytesWr);//写文件内容
if(result)
{
printf("error : f_write returned error \r\n");
return XST_FAILURE;
}
result = f_close(&file); //关闭一个文件
if(result){
printf("error : f_close returned error \r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
//SD卡读函数
u32 Read(char *FileName,u32 DestinationAddress,u32 ByteLength,u32 start_addr)
{
FIL file; //文件对象
FRESULT result;
UINT BytesRd; //f_read函数返回已读出的字节数
result = f_open(&file,FileName,FA_READ); //打开一个只读的文件
if(result)
{
printf("error : f_open returned error \r\n");
return XST_FAILURE;
}
result = f_lseek(&file,start_addr); //相当于将鼠标放在文件的某个开始位置。
if(result)
{
printf("error : f_lseek returned error \r\n");
return XST_FAILURE;
}
result = f_read(&file, (void*)DestinationAddress,ByteLength,&BytesRd);//读文件内容
if(result)
{
printf("error : f_read returned error \r\n");
return XST_FAILURE;
}
result = f_close(&file);//关闭一个文件
if(result)
{
printf("error : f_close returned error \r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
//main函数
int main()
{
int Status,i,j,j_1,j_2,k,k_1,line_cnt,line_last,signal_cnt;
u8 bmp_head[54];
UINT *bmp_width,*bmp_height,*bmp_size,*offbit;
Init();
//读取bmp图像头文件
Status=Read(FILE_NAME, bmp_head, 54, 0);
if (Status==XST_FAILURE)
{
return XST_FAILURE;
}
//读取信息头,并显示图像高、宽、大小以及像素数据开始位等信息
xil_printf("cat.bmp head: \r");
for(i=0;i<54;i++)
xil_printf(" %x",bmp_head[i]);
bmp_width = (UINT *)(bmp_head + 0x12);
bmp_height = (UINT *)(bmp_head + 0x16);
bmp_size = (UINT *)(bmp_head + 0x22);
offbit = (UINT *)(bmp_head + 0x0A);
xil_printf("\n width = %d, height = %d, size = %d, offbit = %d bytes \r",
*bmp_width,*bmp_height,*bmp_size,*offbit);
//每次一行,将图像中除了信息头以及颜料表之外的像素数据存入DDR
for(i=0;i<=*bmp_height-1;i++){
Read(FILE_NAME,DDR_buffer_addr+i*(*bmp_width),(*bmp_width),(*offbit)+i*(*bmp_width));
}
}
terminal内打印出文件的文件头和信息头数据,和前面的对比没有问题
debug模式下,可以看见图像的数据被写入了ddr内
4.结语
本文都是比较基础的应用,如有错误,欢迎指正。