顶层模块
module ov5640_hdmi( input sys_clk , //系统时钟 input sys_rst_n , //系统复位,低电平有效 //摄像头接口 input cam_pclk , //cmos 数据像素时钟 input cam_vsync , //cmos 场同步信号 input cam_href , //cmos 行同步信号 input [7:0] cam_data , //cmos 数据 output cam_rst_n , //cmos 复位信号,低电平有效 output cam_pwdn , //电源休眠模式选择 0:正常模式 1:电源休眠模式 output cam_scl , //cmos SCCB_SCL线 inout cam_sda , //cmos SCCB_SDA线 // DDR3 inout [15:0] ddr3_dq , //DDR3 数据 inout [1:0] ddr3_dqs_n , //DDR3 dqs负 inout [1:0] ddr3_dqs_p , //DDR3 dqs正 output [13:0] ddr3_addr , //DDR3 地址 output [2:0] ddr3_ba , //DDR3 banck 选择 output ddr3_ras_n , //DDR3 行选择 output ddr3_cas_n , //DDR3 列选择 output ddr3_we_n , //DDR3 读写选择 output ddr3_reset_n , //DDR3 复位 output [0:0] ddr3_ck_p , //DDR3 时钟正 output [0:0] ddr3_ck_n , //DDR3 时钟负 output [0:0] ddr3_cke , //DDR3 时钟使能 output [0:0] ddr3_cs_n , //DDR3 片选 output [1:0] ddr3_dm , //DDR3_dm output [0:0] ddr3_odt , //DDR3_odt //hdmi接口 output tmds_clk_p , // TMDS 时钟通道 output tmds_clk_n , output [2:0] tmds_data_p , // TMDS 数据通道 output [2:0] tmds_data_n , output tmds_oen // TMDS 输出使能 );
由于ov5640的时钟和屏幕的时钟不一样,所以必须将读取到的数据先进行缓存,然后在显示在屏幕上,该实验用的时65M时钟频率的像素模式,所以我们可以通过乒乓操作,让两者达到一个平衡。
时钟模块
clk_wiz_0 u_clk_wiz_0 ( // Clock out ports .clk_out1 (clk_200m), .clk_out2 (clk_50m), .clk_out3 (pixel_clk_5x), .clk_out4 (pixel_clk), // Status and control signals .reset (~sys_rst_n), .locked (locked), // Clock in ports .clk_in1 (sys_clk) );
OV5640摄像头驱动模块
OV5640 驱动模块负责驱动 OV5640 SCCB 接口总线,将像素时钟驱动下的传感器输出的场同步信号、行同步信号以及 8 位数据转换成 DDR 读写控制模块的写使能信号和 16 位写数据信号,完成对 OV5640 传感器图像的采集。
module ov5640_dri ( input clk , //时钟 input rst_n , //复位信号,低电平有效 //摄像头接口 input cam_pclk , //cmos 数据像素时钟 input cam_vsync , //cmos 场同步信号 input cam_href , //cmos 行同步信号 input [7:0] cam_data , //cmos 数据 output cam_rst_n , //cmos 复位信号,低电平有效 output cam_pwdn , //cmos 电源休眠模式选择信号 output cam_scl , //cmos SCCB_SCL线 inout cam_sda , //cmos SCCB_SDA线 //摄像头分辨率配置接口 input [12:0] cmos_h_pixel , //水平方向分辨率 input [12:0] cmos_v_pixel , //垂直方向分辨率 input [12:0] total_h_pixel , //水平总像素大小 input [12:0] total_v_pixel , //垂直总像素大小 input capture_start , //图像采集开始信号 output cam_init_done , //摄像头初始化完成 //用户接口 output cmos_frame_vsync, //帧有效信号 output cmos_frame_href , //行有效信号 output cmos_frame_valid, //数据有效使能信号 output [15:0] cmos_frame_data //有效数据 );
//I2C配置模块 i2c_ov5640_rgb565_cfg u_i2c_cfg( .clk (i2c_dri_clk), .rst_n (rst_n), .i2c_exec (i2c_exec), .i2c_data (i2c_data), .i2c_rh_wl (i2c_rh_wl), //I2C读写控制信号 .i2c_done (i2c_done), .i2c_data_r (i2c_data_r), .cmos_h_pixel (cmos_h_pixel), //CMOS水平方向像素个数 .cmos_v_pixel (cmos_v_pixel) , //CMOS垂直方向像素个数 .total_h_pixel (total_h_pixel), //水平总像素大小 .total_v_pixel (total_v_pixel), //垂直总像素大小 .init_done (cam_init_done) ); //I2C驱动模块 i2c_dri #( .SLAVE_ADDR (SLAVE_ADDR), //参数传递 .CLK_FREQ (CLK_FREQ ), .I2C_FREQ (I2C_FREQ ) ) u_i2c_dr( .clk (clk), .rst_n (rst_n ), .i2c_exec (i2c_exec ), .bit_ctrl (BIT_CTRL ), .i2c_rh_wl (i2c_rh_wl), //固定为0,只用到了IIC驱动的写操作 .i2c_addr (i2c_data[23:8]), .i2c_data_w (i2c_data[7:0]), .i2c_data_r (i2c_data_r), .i2c_done (i2c_done ), .scl (cam_scl ), .sda (cam_sda ), .dri_clk (i2c_dri_clk) //I2C操作时钟 ); //CMOS图像数据采集模块 cmos_capture_data u_cmos_capture_data( //系统初始化完成之后再开始采集数据 .rst_n (rst_n & capture_start), .cam_pclk (cam_pclk), .cam_vsync (cam_vsync), .cam_href (cam_href), .cam_data (cam_data), .cmos_frame_vsync (cmos_frame_vsync), .cmos_frame_href (cmos_frame_href ), .cmos_frame_valid (cmos_frame_valid), //数据有效使能信号 .cmos_frame_data (cmos_frame_data ) //有效数据 );
I2C 驱动模块(i2c_dri)
module i2c_dri #( parameter SLAVE_ADDR = 7'b1010000 , //EEPROM从机地址 parameter CLK_FREQ = 26'd50_000_000, //模块输入的时钟频率 parameter I2C_FREQ = 18'd250_000 //IIC_SCL的时钟频率 ) ( input clk , input rst_n , //i2c interface input i2c_exec , //I2C触发执行信号 input bit_ctrl , //字地址位控制(16b/8b) input i2c_rh_wl , //I2C读写控制信号 input [15:0] i2c_addr , //I2C器件内地址 input [ 7:0] i2c_data_w , //I2C要写的数据 output reg [ 7:0] i2c_data_r , //I2C读出的数据 output reg i2c_done , //I2C一次操作完成 output reg i2c_ack , //I2C应答标志 0:应答 1:未应答 output reg scl , //I2C的SCL时钟信号 inout sda , //I2C的SDA信号 //user interface output reg dri_clk //驱动I2C操作的驱动时钟 );
I2C 驱动模块负责驱动 OV5640 SCCB接口总线 ,但SCCB协议和I2C协议的区别时I2C的第九位时从机应答位,二SCCB的第九位是任意,所以可以SCCB的驱动可以直接移植I2C的驱动。
i2c 配置模块(i2c_ov5640_rgb565_cfg)
该模块寄存需要配置的寄存器地址、数据以及控制初始化的开始与结束,同时该模块输出 OV5640 的寄存器地址和数据以及控制 I2C 驱动模块开始执行的控制信号,直接连接到 I2C 驱动模块的用户接口,从而完成对 OV5640 传感器的初始化 。
module i2c_ov5640_rgb565_cfg ( input clk , //时钟信号 input rst_n , //复位信号,低电平有效 input [7:0] i2c_data_r, //I2C读出的数据 input i2c_done , //I2C寄存器配置完成信号 input [12:0] cmos_h_pixel , input [12:0] cmos_v_pixel , input [12:0] total_h_pixel, //水平总像素大小 input [12:0] total_v_pixel, //垂直总像素大小 output reg i2c_exec , //I2C触发执行信号 output reg [23:0] i2c_data , //I2C要配置的地址与数据(高16位地址,低8位数据) output reg i2c_rh_wl, //I2C读写控制信号 output reg init_done //初始化完成信号 );
共需要配置250个寄存器
摄像头图像采集模块(cmos_capture_data)
摄像头采集模块在像素时钟的驱动下将传感器输出的场同步信号、行同步信号以及 8 位数据转换成 DDR 读写控制模块的写使能信号和 16 位写数据信号,完成对 OV5640 传感器图像的采集 。
module cmos_capture_data( input rst_n , //复位信号 //摄像头接口 input cam_pclk , //cmos 数据像素时钟 input cam_vsync , //cmos 场同步信号 input cam_href , //cmos 行同步信号 input [7:0] cam_data , //用户接口 output cmos_frame_vsync , //帧有效信号 output cmos_frame_href , //行有效信号 output cmos_frame_valid , //数据有效使能信号 output [15:0] cmos_frame_data //有效数据 );
将采集到的颜色数据最为wr_fifo的输入
DDR3控制器模块
DDR3 控制模块负责驱动 DDR3 片外存储器,缓存图像传感器输出的图像数据
module ddr3_top( input sys_clk_i , //MIG IP核输入时钟 input clk_ref_i , //ddr3参考时钟 input rst_n , //复位,低有效 //DDR3接口信号 input [27:0] app_addr_rd_min , //读ddr3的起始地址 input [27:0] app_addr_rd_max , //读ddr3的结束地址 input [7:0] rd_bust_len , //从ddr3中读数据时的突发长度 input [27:0] app_addr_wr_min , //读ddr3的起始地址 input [27:0] app_addr_wr_max , //读ddr3的结束地址 input [7:0] wr_bust_len , //从ddr3中读数据时的突发长度 // DDR3 IO接口 inout [15:0] ddr3_dq , //ddr3 数据 inout [1:0] ddr3_dqs_n , //ddr3 dqs负 inout [1:0] ddr3_dqs_p , //ddr3 dqs正 output [13:0] ddr3_addr , //ddr3 地址 output [2:0] ddr3_ba , //ddr3 banck 选择 output ddr3_ras_n , //ddr3 行选择 output ddr3_cas_n , //ddr3 列选择 output ddr3_we_n , //ddr3 读写选择 output ddr3_reset_n , //ddr3 复位 output [0:0] ddr3_ck_p , //ddr3 时钟正 output [0:0] ddr3_ck_n , //ddr3 时钟负 output [0:0] ddr3_cke , //ddr3 时钟使能 output [0:0] ddr3_cs_n , //ddr3 片选 output [1:0] ddr3_dm , //ddr3_dm output [0:0] ddr3_odt , //ddr3_odt //用户 input ddr3_read_valid , //DDR3 读使能 input ddr3_pingpang_en , //DDR3 乒乓操作使能 input wr_clk , //wfifo时钟 input rd_clk , //rfifo的读时钟 input wr_en , //数据有效使能信号 input [15:0] wrdata , //有效数据 input rdata_req , //请求像素点颜色数据输入 input rd_load , //输出源更新信号 input wr_load , //输入源更新信号 output [15:0] rddata , //rfifo输出数据 output init_calib_complete //ddr3初始化完成信号 );
DDR 读写模块(ddr3_rw)
该模块负责与 MIG 模块的命令和地址的交互,根据 FIFO 控制模块中 fifo 的剩余数据量来切换 DDR3 的读写命令和地址 。
module ddr3_rw( input ui_clk , //用户时钟 input ui_clk_sync_rst , //复位,高有效 input init_calib_complete , //DDR3初始化完成 input app_rdy , //MIG IP核空闲 input app_wdf_rdy , //MIG写FIFO空闲 input app_rd_data_valid , //读数据有效 input [9:0] wfifo_rcount , //写端口FIFO中的数据量 input [9:0] rfifo_wcount , //读端口FIFO中的数据量 input rd_load , //输出源更新信号 input wr_load , //输入源更新信号 input [27:0] app_addr_rd_min , //读DDR3的起始地址 input [27:0] app_addr_rd_max , //读DDR3的结束地址 input [7:0] rd_bust_len , //从DDR3中读数据时的突发长度 input [27:0] app_addr_wr_min , //写DDR3的起始地址 input [27:0] app_addr_wr_max , //写DDR3的结束地址 input [7:0] wr_bust_len , //从DDR3中写数据时的突发长度 input ddr3_read_valid , //DDR3 读使能 input ddr3_pingpang_en , //DDR3 乒乓操作使能 output rfifo_wren , //从ddr3读出数据的有效使能 output [27:0] app_addr , //DDR3地址 output app_en , //MIG IP核操作使能 output app_wdf_wren , //用户写使能 output app_wdf_end , //突发写当前时钟最后一个数据 output [2:0] app_cmd //MIG IP核操作命令,读或者写 );
MIG 模块(mig_series)
DDR3模块如何移植详见:DDR3介绍-CSDN博客
FIFO 控制模块(ddr3_fifo_ctrl)
负责对输入和输出的数据进行时钟域的切换和位宽的转换。
module ddr3_fifo_ctrl( input rst_n , //复位信号 input wr_clk , //wfifo时钟 input rd_clk , //rfifo时钟 input ui_clk , //用户时钟 input wr_en , //数据有效使能信号 input [15:0] wrdata , //有效数据 input [127:0] rfifo_din , //用户读数据 input rdata_req , //请求像素点颜色数据输入 input rfifo_wren , //从ddr3读出数据的有效使能 input wfifo_rden , //wfifo读使能 input rd_load , //输出源场信号 input wr_load , //输入源场信号 output [127:0] wfifo_dout , //用户写数据 output [9:0] rfifo_wcount , //rfifo剩余数据计数 output [9:0] wfifo_rcount , //wfifo写进数据计数 output reg [15:0] rddata //读有效数据 );
hdmi显示模块
显示模块的代码可以移植hdmi的通用.v文件,RGB2DVI 模块 -----> DVI发送端顶层模块和video_driver------>视频显示驱动模块,在显示模块中,当像素坐标处于有有效区范围内时,video_driver会发送一个data_req(数据请求信号),rd_fifo就会从DDR3中一次读出128个数据,128/16=8,即8个像素点位置的数据,通过一个计数器,当这8个像素点的数据都显示出来后,再次让rd_fifo从DDR3中读取128个数据.这样,图像就能通过hdmi线顺利的显示在屏幕上了。
具体的hdmi模块如何移植详见:HDMI彩条实验-CSDN博客