点击查看代码
#include "xaxivdma.h" // 引入Xilinx提供的VDMA驱动库
#include "xaxivdma_i.h"
#include "sleep.h" // 引入Xilinx提供的延时函数库
#include "ff.h" // 引入FatFs文件系统库
#define DDR_BASEADDR 0x00000000 // 定义DDR存储器的起始地址
#define VDMA_BASEADDR XPAR_AXI_VDMA_0_BASEADDR // 定义VDMA模块的基地址
#define H_STRIDE 800 // 定义图像水平方向的跨度(即一行像素所占的字节数)
#define H_ACTIVE 800 // 定义图像水平方向的分辨率
#define V_ACTIVE 480 // 定义图像垂直方向的分辨率
#define COUNTS_PER_SECOND (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ)/64 // 定义每秒钟的计数数目
#define VIDEO_LENGTH (H_STRIDE*V_ACTIVE) // 定义视频数据的长度(以字节为单位)
#define VDMA_MM2S_START DDR_BASEADDR + 0x2000000 // 定义VDMA偏移量,用于指定VDMA接收数据的存储地址
static FATFS fatfs; // 定义FatFs文件系统对象
u8 picture[800*480*3]={0}; // 定义图像数据缓冲区大小(尺寸为800x480,并且每个像素由RGB三个分量组成)
u8 picture_reverse[800*480*3]={0}; // 定义反转后的图像数据缓冲区
void Xil_DCacheFlush(void); // 声明函数Xil_DCacheFlush,用于刷新CPU高速缓存
// 显示图像的函数,参数disp_base_addr为显示窗口的起始地址,addr为待显示图像的首地址,size_x和size_y为图像的分辨率,scale_x和scale_y为缩放比例,mode为缩放方式(1表示垂直方向缩放,2表示水平方向缩放,0表示不缩放)
void show_img(u8 *disp_base_addr, u8 *addr, u32 size_x, u32 size_y, u32 scale_x, u32 scale_y, u8 mode)
{
u32 i, j, k, l;
for(j=0;j<size_y/scale_y;j++) // 遍历行
{
for(i=0;i<size_x/scale_x;i++) // 遍历列
{
if (mode == 1) { // 如果是垂直方向缩放
u32 r = 0, g = 0, b = 0;
for(k=0;k<scale_x;k++) {
for(l=0;l<scale_y;l++) {
r += *(addr+((i*scale_x+k)+(j*scale_y+l)*size_x)*3+0); // 累加红色分量
g += *(addr+((i*scale_x+k)+(j*scale_y+l)*size_x)*3+1); // 累加绿色分量
b += *(addr+((i*scale_x+k)+(j*scale_y+l)*size_x)*3+2); // 累加蓝色分量
}
}
*(disp_base_addr+(i+j*size_x/scale_x)*3+0) = r/(scale_x*scale_y); // 计算平均值并存储到显示窗口对应位置的缓冲区中(红色)
*(disp_base_addr+(i+j*size_x/scale_x)*3+1) = g/(scale_x*scale_y); // (绿色)
*(disp_base_addr+(i+j*size_x/scale_x)*3+2) = b/(scale_x*scale_y); // (蓝色)
} else if (mode == 2) { // 如果是水平方向缩放
for(l = 0; l < scale_y; l++) {
for(k = 0; k < scale_x; k++) {
u8 r = *(addr+((i*scale_x+k)+(j*scale_y+l)*size_x)*3+0); // 取出原始图像的RGB三个分量
u8 g = *(addr+((i*scale_x+k)+(j*scale_y+l)*size_x)*3+1);
u8 b = *(addr+((i*scale_x+k)+(j*scale_y+l)*size_x)*3+2);
// 将RGB颜色值转换为灰度值
u8 gray = (u8)(0.2989 * r + 0.5870 * g + 0.1140 * b);
// 对灰度值进行阈值化处理(如果大于等于128,则置为白色255,否则置为黑色0)
u8 binary = (gray >= 128) ? 255 : 0;
*(disp_base_addr+((i*scale_x)+k + ((j*scale_y)+l)*size_x*scale_x)*3+0) = binary; // 存储到显示窗口对应位置的缓冲区中(红色)
*(disp_base_addr+((i*scale_x)+k + ((j*scale_y)+l)*size_x*scale_x)*3+1) = binary; // (绿色)
*(disp_base_addr+((i*scale_x)+k + ((j*scale_y)+l)*size_x*scale_x)*3+2) = binary; // (蓝色)
}
}
} else { // 如果不需要缩放
for(k = 0; k < scale_x*scale_y; k++) {
*(disp_base_addr+(i+j*size_x/scale_x)*scale_x*scale_y*3+k*3+0) = *(addr+(i*scale_x*scale_y+k+j*size_x*scale_y)*3+0); // 直接将原始图像的RGB三个分量存储到显示窗口对应位置的缓冲区中(红色)
*(disp_base_addr+(i+j*size_x/scale_x)*scale_x*scale_y*3+k*3+1) = *(addr+(i*scale_x*scale_y+k+j*size_x*scale_y)*3+1); // (绿色)
*(disp_base_addr+(i+j*size_x/scale_x)*scale_x*scale_y*3+k*3+2) = *(addr+(i*scale_x*scale_y+k+j*size_x*scale_y)*3+2); // (蓝色)
}
}
}
}
Xil_DCacheFlush(); // 刷新CPU高速缓存
}
// 初始化SD卡并挂载文件系统
int SD_Init()
{
FRESULT rc;
rc = f_mount(&fatfs,"",0);
if(rc)
{
xil_printf("ERROR : f_mount returned %d\r\n",rc);
return XST_FAILURE;
}
return XST_SUCCESS;
}
// 读取SD卡中指定文件的数据到指定地址
int SD_Transfer_read(char *FileName,u8 *DestinationAddress,u32 ByteLength)
{
FIL fil;
FRESULT rc;
UINT br;
rc = f_open(&fil,FileName,FA_READ); // 打开指定文件
if(rc)
{
xil_printf("ERROR : f_open returned %d\r\n",rc);
return XST_FAILURE;
}
rc = f_lseek(&fil, 54); // 跳过位图文件头(54字节)
if(rc)
{
xil_printf("ERROR : f_lseek returned %d\r\n",rc);
return XST_FAILURE;
}
rc = f_read(&fil, DestinationAddress,ByteLength,&br); // 读取文件数据
if(rc)
{
xil_printf("ERROR : f_read returned %d\r\n",rc);
return XST_FAILURE;
}
rc = f_close(&fil); // 关闭文件
if(rc)
{
xil_printf(" ERROR : f_close returned %d\r\n", rc);
return XST_FAILURE;
}
return XST_SUCCESS;
}
int main(void)
{
int i, j;
SD_Init(); // 初始化SD卡并挂载文件系统
SD_Transfer_read("A.bmp",picture,800*480*3); // 读取图像数据
// 反转图像颜色
for (i = 0; i < 800*480*3; i += 3) {
picture_reverse[i] = picture[i + 2]; // 将蓝色分量赋值给红色分量
picture_reverse[i + 1] = picture[i + 1]; // 将绿色分量保持不变
picture_reverse[i + 2] = picture[i]; // 将红色分量赋值给蓝色分量
}
// 设置VDMA
Xil_Out32((VDMA_BASEADDR + 0x000), 0x0000008b); // VDMA控制寄存器,启用循环模式
Xil_Out32((VDMA_BASEADDR + 0x05c), VDMA_MM2S_START); // VDMA写通道(MM2S)起始地址
Xil_Out32((VDMA_BASEADDR + 0x058), (H_ACTIVE*3)); // VDMA写通道(MM2S)水平方向偏移量
Xil_Out32((VDMA_BASEADDR + 0x054), (H_STRIDE*3)); // VDMA写通道(MM2S)水平方向大小
Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE); // VDMA写通道(