ZYNQ基础系列 VTC+VDMA+Vid_Out核 构建一个简单的显示通路

ZYNQ基础系列(三)VTC+VDMA+Vid_Out核 构建一个简单的显示通路的准备工作

https://blog.csdn.net/long_fly/article/details/78968043

构建一个简单的显示通路的部件

在上一篇ZYNQ基础系列(二) IO口模拟HDMI中,介绍了VGA到HDMI输出的IP核的使用方法,本文将先介绍三个VIVADO自带的视频输出通路相关的重要IP核,搭建一个比较简单的视频通路,为不久之后的摄像头到显示屏通路打下基础:

1> Video Timing Controller
2> AXI4-Stream to Video Out
3> Video DMA
  
  

首先要对IP核的功能和配置有一个了解,才能做到肆无忌惮的去搭建通路

VTC核

这个IP核其实可以就看做是一个时序发生器,产生显示器输出所需要的时序信号,有了此核之后,那些各种显示消隐区也就不需要怎么考虑了,省心了很多
1>引脚
完整的引脚图如下:
这里写图片描述

Optional AXI4-Lite Control Interface : 用于通过AXI总线实时动态更换VTC核的参数
Detector Interface : 图中的Video Timing (input) Interface,探测器接口,用于捕捉视频时序然后处理
Generator Interface : 图中Video Timing (input) Interface,用于生成的视频时序

引脚 I/O 功能
clk I 核的工作时钟
clken I 时钟使能(高有效)
gen_aclken I 生成模式工作时钟使能(高有效)
det_aclken I 探测模式工作时钟使能(高有效)
resetn I 复位信号(低有效)
irq O 中断信号输出(高有效)
intc_if[31:0] O INTC接口:[31:8]和状态寄存器(0x0004)的[31:8]一样;[5:0]和异常寄存器(0x0008)的[21:16]一样;[7:6]为0
fsync_in I 帧同步输入
fsync_out[(fs-1):0] O 帧同步输出

如果需要通过AXI总线对核进行配置的话,还需要去查一下各个寄存器的功能,这里暂时不需要动态配置,配置过程仅通过GUI配置一次

2>GUI配置
第一页:
这里写图片描述
选项说明:

名称 功能
Include AXI4-Lite Interface 添加AXI控制
Include INTC Interface 添加intc_if接口
Interlaced Video Support 好像是支持视频混合吧,反正就是打了这个勾,输出就选择Field ID这个线了
Synchronize Generator to Detector or to fsync_in 时序生成自动同步到时序探测或帧同步
每行的最大时钟数和每帧的最大行数 决定GUI第二页数据的范围,在满足条件的前提下,要尽量小
Frame Syncs 帧同步的数量,同时决定了fsync_out的线宽
生成和探测的使能 就是生成和探测的使能

还是第一页:
这里写图片描述

现在只看时序生成的模式:

名称 功能
Field ID Generation 启用Field ID输出
Vertical Blank Generation 允许垂直空白输出
Horizontal Blank Generation 允许水平空白输出
Vertical Sync Generation 允许垂直同步输出
Horizontal Sync Generation 允许水平同步输出
Active Video Generation 视频active线输出
Active Chroma Generation 色度active线输出
Auto Generation Mode 生成的视频时序输出会随探测到的输入改变而改变;若不勾选,将仅基于第一个检测到的输入格式生成视频时序输出,即使探测块失锁,生成的同步信号仍继续输出

第二页:
这里写图片描述
第二页的配置尤为简单,选择分辨率,大部分的显示器都可以找的到对应的分辨率,如果没有的话,也可以自定义参数
可以看到参数后面有个范围([0-4095]),那是因为我们第一页选了4096,实际上不需要这么大

第三页:
帧同步位置,暂时不管它


注意 :
不知道是不是VIVADO版本的问题(我的是2017.4),VIVADO有个BUG,就是IP核在原理图中显示的引脚与实际不符
这里写图片描述
比如,clken明明是高电平有效的,他在引脚上画了个圈表示低有效,这就很糟心了,所以以后需要在原理图连线的话,都不要被表象欺骗了,最好是点进GUI配置界面看一看IP核预览(上面有图,这个GUI预览的引脚显示却是正常的)
我不是针对这一个IP核,总之,连原理图的时候,各个IP核的使能信号需要特别注意一下


Vid_Out核

AXI4-Stream类型速度很快且容易处理,一般内部视频流都是这个格式,HLS做的图像处理核也是通过AXI4-Stream接口,这个HLS核一般也是放在VDMA的后面,但是AXI4-Stream终究是要转换为VIDEO接口来驱动外界的视频接收器(如显示屏),这个转换就由Vid_Out核来实现
这使得视频设计人员能够快速方便地将具有AXI4-Stream接口的视频处理模块连接到外部视频接收器,该核与VTC核协同工作,生成视频格式的时序信号(可以直接驱动VGA)
1>引脚
完整的引脚图如下:
这里写图片描述
AXI4-Stream接口 : AXI4-Stream格式视频的输入接口
Video Timing Inputs接口 : VTC生成的时序输出的接入口
Video Outputs : 转换后的视频格式,可以直接驱动VGA(硬件电路允许的话)

引脚 I/O 功能
aclk I AXI4-Stream流的时钟(官方图里这个引脚画错了)
aclken I AXI4-Stream流的时钟使能(高有效)
aresetn I AXI4-Stream流的复位(低有效)
vid_io_out_clk I 本地视频时钟(必须和VTC的工作时钟同步)
vid_io_out_ce I 本地视频时钟使能
vid_io_out_reset I 本地视频复位信号
fid I 针对混合视频的Field ID输入,0=偶数场,1=奇数场(同步到aclk)
vtg_ce O 用于暂停时序发生器达到同步的目的(接VTC时钟使能)
locked O 表明VTC是否锁定到输入时序(同步到vid_io_out_clk)
overflow O FIFO溢出(同步到vid_io_out_clk)
underflow O FIFO空(同步到vid_io_out_clk)
status[31:0] O 用于监视同步状态机的状态

2>GUI配置
这里写图片描述

选项 功能
Pixels Per Clock 指定要并行输出的像素数(影响输入和输出的数据位宽)
Video Format 选择相应的视频格式(决定输入输出线宽)
AXI4S视频输入分量线宽 改变输入位宽
本地视频输出分量线宽 改变输出位宽
FIFO Depth 指定FIFO深度
Clock Mode AXI4S和显示输出不在一个时钟域里的时候就需要独立时钟了
Timing Mode 时序模式,(官方建议选从模式,有能力动态调整AXI4S和vidout的相差)
Hysteresis Level 滞后等级,留FIFO的一部分作为缓冲

VDMA核

FrameBuffer帧缓存 : 每一存储单元对应屏幕上的一个像素,整个帧缓存对应一帧图像,相当于一块画布,画好之后直接通知显示设备显示
VDMA 核 : 可以方便的实现多帧缓存,也就是拥有多个画布,其最多可以控制32个画布,并可自由地进行画布切换;用户可以通过VDMA的写通道将 AXI-S类型的数据流转为Memory Map类型写入DDR,也可以通过读通道从DDR读取Memory Map类型数据以 AXI-S类型输出。VDMA本质上是一个数据搬运的核,为数据进出DDR提供了一种便捷的方案。
1>引脚
这里写图片描述
虽然上面不是全部的引脚,但是几个重要的引脚和接口都已经展示出来了,下面再配一张VDMA核的框图,一起说明
这里写图片描述
从框图中可以看出,VDMA核主要由控制和状态寄存器、数据搬运模块、行缓冲构成,数据通过行缓冲缓存和数据搬运模块进出 DDR,实现读写数据,几个和外界通信的重要接口:
AXI4-Lite 接口(S_AXI_LITE) : PS通过该接口对VDMA实现配置
AXI4 Memory Map 读接口(M_AXI_MM2S) : 存储器的读接口(映射到存储器读)
AXI4 Memory Map 写接口(M_AXI_S2MM) : 存储器的写接口(映射到存储器写)
AXI4-S 主接口(M_AXIS_MM2S) : 存储器读出图像到AXI-S视频流
AXI4-S 从接口(S_AXIS_S2MM) : AXI-S视频流写入图像到存储器

主要引脚:

引脚信号 功能
s_axi_lite_aclk s_axi_lite接口的时钟
m_axi_mm2s_aclk m_axi_mm2s接口的时钟
m_axi_s2mm_aclk m_axi_s2mm的时钟
m_axis_mm2s_aclk m_axis_mm2s的时钟
s_axis_s2mm_aclk s_axis_s2mm的时钟
axi_resetn 核的复位信号(至少16个s_axi_lite_aclk,低有效)
mm2s_introut mm2s通道的中断输出
s2mm_introut s2mm通道的中断输出

视频同步接口信号:

信号 功能
mm2s_fsync帧同步信号 使能该信号后,VDMA操作始于 mm2s_fsync每个下降沿(该信号至少持续一个 m_axis_mm2s_aclk 时钟周期)
s2mm_fsync帧同步信号 使能该信号后,VDMA操作始于 s2mm_fsync每个下降沿(该信号至少持续一个 s_axis_s2mm_aclk时钟周期)

GenLock相关信号:

信号 功能
mm2s_frame_ptr_in mm2s帧编号的输入
mm2s_frame_ptr_out 当前mm2s的帧编号输出
s2mm_frame_ptr_in s2mm帧编号的输入
s2mm_frame_ptr_out 当前s2mm的帧编号输出

2>常用寄存器
寄存器都是小端格式:
这里写图片描述
MM2S,也就是从DDR中读数据:

寄存器名称 偏移地址 功能
MM2S_VDMACR 00h MM2S VDMA控制寄存器
MM2S_VDMASR 04h MM2S VDMA状态寄存器
MM2S_START_ADDRESS 5C~98h MM2S帧存起始地址(1~16)
MM2S_FRMDLY_STRIDE 58h MM2S帧延迟和跨度寄存器
MM2S_HSIZE 54h MM2S 水平方向显示大小寄存器
MM2S_VSIZE 50h MM2S 垂直方向显示大小寄存器

类似的S2MM(往DDR写数据):

寄存器名称 偏移地址 功能
S2MM_VDMACR 30h S2MM VDMA控制寄存器
S2MM_VDMASR 34h S2MM VDMA状态寄存器
S2MM_START_ADDRESS AC~E8h S2MM帧存起始地址(1~16)
S2MM_FRMDLY_STRIDE A8h S2MM 帧延迟和跨度寄存器
S2MM_HSIZE A4h S2MM 水平方向显示大小寄存器
S2MM_VSIZE A0h S2MM 垂直方向显示大小寄存器
PARK_PRT_REG 28h MM2S 和 S2MM Park 指针寄存器

以MM2S为例大致说明重要寄存器的配置:
1>MM2S_VDMACR(00h)
MM2S的控制寄存器,重要的在后四位
这里写图片描述

bit位 名称 功能
3 GenlockEn 1=使能Genlock或动态Genlock同步(仅当GUI配置Genlock Mode为Slave、Dynamic-Master或Dynamic-Slave,此位才起作用)
2 Reset 1=复位MM2S通道
1 Circular_Park 0=park模式:缓存页停留在PARK_PTR_REG.RdFrmPntrRef 指定的位置;1=Circular模式:循环切换缓存页
0 RS 1=运行;0=停止

注:具体可以查看手册PARK_PTR_REG(28h)寄存器,使用park模式,可以通过操作RdFrmPtrRef和WrFrmPtrRef,实现帧缓存任意切换

2>MM2S_VDMASR(04h)
这里写图片描述
重要的是bit0:Halted位,指示VDMA是否停止运行(1=停止),只读

3> MM2S_START_ADDRESS (5C~98h)

    Xil_Out32((VDMA_BASEADDR + 0x5c), VIDEO_BASEADDR0);
    Xil_Out32((VDMA_BASEADDR + 0x60), VIDEO_BASEADDR1); 
    Xil_Out32((VDMA_BASEADDR + 0x64), VIDEO_BASEADDR2);
  
  

用于存放帧存的起始地址,上述代码为只有3个帧存时的配置
帧存最多可以达到32个,但是5C~98h只够写16个,于是就需要配合MM2S_REG_INDEX(14h)寄存器,MM2S_REG_INDEX=1时:5Ch就是第17个帧存的起始地址

4> MM2S_FRMDLY_STRIDE(58h)
MM2S帧延迟(24-28bit)和跨度(0-15bit)寄存器
这里写图片描述
帧延迟:( Genlock Mode为Slave时有效),指定从接口比主接口至少要延迟多少个帧
跨度:相邻两行的第一个像素间的距离

5> MM2S_HSIZE(54h)和MM2S_VSIZE(50h)
假如是RGB 800*600(每个像素点3个字节)
MM2S_HSIZE用于指定一行有多少字节:800*3
MM2S_VSIZE用于指定有多少行:600(配置完就开始工作,所以对这个寄存器的配置,必须放在最后)

往DDR写数据的S2MM的相关寄存器与这些类似,具体的查看手册
3>SDK配置
初始化配置的关键代码:

/*  帧存地址参数  */
#define DDR_BASEADDR    0x00000000
#define VIDEO_BASEADDR0 0x01000000
#define VIDEO_BASEADDR1 DDR_BASEADDR + 0x3000000
#define VIDEO_BASEADDR2 DDR_BASEADDR + 0x4000000
/*  分辨率参数800*600分辨率  */
#define H_STRIDE            800
#define H_ACTIVE            800
#define V_ACTIVE            600
/*****************往DDR写数据设置**********************/
Xil_Out32((VDMA_BASEADDR + 0x030), 0x00000003);//使能循环模式
Xil_Out32((VDMA_BASEADDR + 0x0AC), VIDEO_BASEADDR0);//帧存0地址
Xil_Out32((VDMA_BASEADDR + 0x0B0), VIDEO_BASEADDR1);//帧存1地址
Xil_Out32((VDMA_BASEADDR + 0x0B4), VIDEO_BASEADDR2);//帧存2地址
Xil_Out32((VDMA_BASEADDR + 0x0A8), (H_STRIDE*4));   //跨度设置(800 * 4) bytes
Xil_Out32((VDMA_BASEADDR + 0x0A4), (H_ACTIVE*4));   //行宽设置(800* 4) bytes
Xil_Out32((VDMA_BASEADDR + 0x0A0), V_ACTIVE);       //行数设置(600)
/*****************从DDR读数据设置**********************/
Xil_Out32((VDMA_BASEADDR + 0x000), 0x3);//使能循环模式
Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0);//帧存0地址
Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR1);//帧存1地址
Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR2);//帧存2地址
Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*4));   //跨度设置(800 * 4) bytes
Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4));   //行宽设置(800* 4) bytes
Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE);       //行数设置(600)
  
  

4>GUI配置
第一页:
这里写图片描述

选项 功能
Address Width DDR地址线宽度
Frame Buffers 帧缓存的数量
Memory Map Data Width VDMA与DDR控制器的AXI总线宽度
Write Burst Size 写猝发大小(在一次写猝发中,每一时钟节拍内传输数据字节的最大字节数),详见AXI4具体协议
Stream Data Width AXI4-S流的数据宽度
Line Buffer Depth Line Buffer的深度
读通道的各选项 与写通道类似

第二页:
这里写图片描述

选项 功能
Enable Asynchronous Mode 开启异步模式(各工作时钟异步),同步模式下时钟必须同源
Enable Vertical Flip S2MM有效时,垂直翻转图像
Fsync Options 帧同步设置
None:自由运行模式下,视频数据尽可能快地被转移,不用等待外部触发。
s2mm fsync:VDMA在s2mm_fsync输入信号的下降沿,开始一帧的工作
s2mm tuser:写通道的s_axis_s2mm_tuser(0)信号作为帧起始信号
Genlock Mode 同步锁相模式【注】
Allow Unaligned Transfers 是否允许非对齐传输(选中,允许数据重新对齐;否则,起始地址宽度必须与写存储器映射数据宽度字节的倍数对齐)
读通道的各选项 与写通道类似

【注】同步锁相模式:
四种方式,以S2MM(写通道为例),读通道可以类比出来
1>Master模式
该通道不会跳过或重复任一帧数据,并把当前帧的编号输出到s2mm_frame_ptr_out 端口。
通道不会检测 s2mm_frame_ptr_in端口提供的帧编号。
Slave通道应跟随Master通道变化,但有一定的延迟。延迟大小预定义在寄存器s2mm_frmdly_stride[28:24]

2>Slave模式
该通道会通过跳过或重复一些帧的方式,尝试与Master同步,会对s2mm_frame_ptr_in 端口进行采样,获取Master的帧编号,为了实现状态反馈,通道会把当前帧的编号输出到s2mm_frame_ptr_out 端口
指定通道工作在Slave模式,必须进行如下操作:

  • 将 GenlockEn置位(S2MM_VDMACR[3]=1),使能主从通道间的 Genlock 同步
  • 将 GenlockSrc置位(S2MM_VDMACR[7]=1),使能内部 Genlock 模式
    如果在GUI配置中同时使能读写通道,该位默认置位
    当 GenlockSRC置位时,VDMA 默认支持内部同步锁相总线(就没有必要在外部对帧指针端口 *_frame_ptr_out 和 *_frame_ptr_in进行连接了)
  • 根据主从通道的帧率,使用 s2mm_frmdly_stride[28:24]设定合适的延迟时间。

3>动态Master模式
动态 MasterMaster的区别在于,主通道会跳过从通道正在操作的帧。动态 Master检测到Slave正在操作某帧的话,就会跳过该帧,在其他帧缓存中循环操作

4>动态Slave模式
Dynamic Slave通道会操作Dynamic Master通道上一周期操作的帧,当动态 Slave比Master慢的时候,Slave会适当跳过一些帧

将在下一篇ZYNQ基础系列(四)中完成一个简单视频通路的搭建

ZYNQ基础系列(四)VTC+VDMA+Vid_Out核 开始构建一个简单的显示通路

https://blog.csdn.net/long_fly/article/details/79066302

ZYNQ7010把SD卡的图片显示到HDMI

ZYNQ基础系列(三)中有相关IP核的初步介绍,在已有的基础上可以搭建一个基础的显示通路了
实验目的:在Mi701N开发板的基础上,驱动800*600的显示屏输出图片(图片文件[.bin文件]存放SD卡中)

一、PL部分实现

大体框图:
这里写图片描述

  • AXI接口连接模块和复位模块是通过自动生成的
  • rgb2dvi模块:用于IO口输出HDMI信号 [在ZYNQ基础系列(二)],也可以不加该模块直接以VGA形式输出,或者加一个驱动HDMI芯片的IP核输出
  • PS模块:注意根据板子具体情况设置PS时钟和PL时钟以及DDR型号
  • CLOCK模块:PS倍频到100M的时钟输出(图中红色线)作为CLOCK模块的输入,由于分辨率是800*600的,所以时钟clock1输出40M,clock2是clock1的5倍,200M,(两个输出时钟,图中青色线),该模块的lock信号作为显示通路的复位信号
  • VTC、VDMA和Vid_Out核的配置,和上一文中的一样

二、制作图片文件

Image2Lcd工具
这里写图片描述
按照如上设置,将.bin图片文件,导出

三、SDK部分实现

初始化:首先PS通过AXI总线配置PL的工作模式
工作:从SD卡中读取图片文件,然后PS将图片数据写入DDR,PL不断从DDR中读取数据,然后通过视频通路,显示在屏幕上

设置开启xilinx自带的文件系统的库:
这里写图片描述
如图将xilffs勾选(否则提示找不到 ff.h 文件):
这里写图片描述
勾选此库之后,就可以使用文件系统相关的函数了
等下的代码中,SD_InitSD_Transfer_read分别是初始化SD卡和读取SD卡中的文件内容(.bin文件)

将读取的.bin数据存到DDR中:
等下的代码中,show_img函数,将完成数据存到DDR相应地址的操作

对PL中的VDMA的配置:
通过PS完成对VDMA的初始化,详先上一文

PS完整代码:

#include "xaxivdma.h"
#include "xaxivdma_i.h"
#include "sleep.h"

#include <string.h>
#include "xparameters.h"
#include "xil_printf.h"
#include "ff.h"
#include "xdevcfg.h"

#define DDR_BASEADDR        0x00000000
#define VDMA_BASEADDR       XPAR_AXI_VDMA_0_BASEADDR
#define H_STRIDE            800
#define H_ACTIVE            800
#define V_ACTIVE            600

#define VIDEO_BASEADDR0 DDR_BASEADDR + 0x1000000
#define VIDEO_BASEADDR1 DDR_BASEADDR + 0x2000000
#define VIDEO_BASEADDR2 DDR_BASEADDR + 0x3000000

void Xil_DCacheFlush(void);

unsigned char picture1[800*600*3]={0};
static FATFS fatfs;

void show_img(u32 x, u32 y, u32 disp_base_addr, unsigned char * addr, u32 size_x, u32 size_y)
{
    u32 i=0;
    u32 j=0;
    u32 r,g,b;
    u32 start_addr=disp_base_addr;
    start_addr = disp_base_addr + 4*x + y*4*H_STRIDE;
    for(j=0;j<size_y;j++)
    {
        for(i=0;i<size_x;i++)
        {
            b = *(addr+(i+j*size_x)*3+0);
            g = *(addr+(i+j*size_x)*3+1);
            r = *(addr+(i+j*size_x)*3+2);
            Xil_Out32((start_addr+(i+j*H_STRIDE)*4),((r<<16)|(g<<8)|(b<<0)|0x0));
        }
    }
    Xil_DCacheFlush();
}

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;
}
int SD_Transfer_read(char *FileName,u32 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, 0);
    if(rc)
    {
        xil_printf("ERROR : f_lseek returned %d\r\n",rc);
        return XST_FAILURE;
    }
    rc = f_read(&fil, (void*)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)
{
    u32 i;
    xil_printf("Starting the first VDMA \n\r");

    //VDMA configurateAXI VDMA0
    /*****************往DDR写数据设置**********************/
    //Xil_Out32((VDMA_BASEADDR + 0x030), 0x3);// enable circular mode
    //Xil_Out32((VDMA_BASEADDR + 0x0AC), VIDEO_BASEADDR0);  // start address
    //Xil_Out32((VDMA_BASEADDR + 0x0B0), VIDEO_BASEADDR1);  // start address
    //Xil_Out32((VDMA_BASEADDR + 0x0B4), VIDEO_BASEADDR2);  // start address
    //Xil_Out32((VDMA_BASEADDR + 0x0A8), (H_STRIDE*4));     // h offset (800 * 4) bytes
    //Xil_Out32((VDMA_BASEADDR + 0x0A4), (H_ACTIVE*4));     // h size (600 * 4) bytes
    //Xil_Out32((VDMA_BASEADDR + 0x0A0), V_ACTIVE);         // v size (600)
    /*****************从DDR读数据设置**********************/
    Xil_Out32((VDMA_BASEADDR + 0x000), 0x3);        // enable circular mode
    Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0);    // start address
    Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR1);    // start address
    Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR2);    // start address
    Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*4));       // h offset (800 * 4) bytes
    Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4));       // h size (800 * 4) bytes
    Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE);           // v size (600)

    for(i=0;i<H_STRIDE*H_ACTIVE;i++)
    {
        Xil_Out32(VIDEO_BASEADDR0+i,0);
    }

    SD_Init();
    SD_Transfer_read("test.bin",(u32)picture1,800*600*3+1);

    while(1)
    {
        show_img(0,0,VIDEO_BASEADDR0,&picture1[0],800,600);
        show_img(0,0,VIDEO_BASEADDR1,&picture1[0],800,600);
        show_img(0,0,VIDEO_BASEADDR2,&picture1[0],800,600);
        sleep(5);
    }
    return 0;
}
  
  

四、实验现象

这里写图片描述

发布了42 篇原创文章 · 获赞 148 · 访问量 41万+

猜你喜欢

转载自blog.csdn.net/baidu_37503452/article/details/104999352