基于DDR3的摄像头OV5640的VGA显示
作者:互联网
基于DDR3的摄像头OV5640的VGA显示
一.DDR3 SDRAM
1.基本介绍
DDR3 SDRAM 英 文 全 称 “ Double-Data-Rate Three Synchronous Dynamic Random Access Memory”,译为“第三代双倍速率同步动态随机存取内存”或“同步动态随机存储器”,是动态随机存储器(Dynamic Random Access Memory,简称 DRAM)家族的一份子。
同步、动态、随机是其性能特点的外在说明,也是其区别其他存储器的特色标签。这三个概念性的标签,我们要好好理解掌握。
双倍速率(Double-Data-Rate):DDR3 SDRAM 存储器与 SDRAM 有一个很大的不同,DDR3 SDRAM 或者说带 DDR 开头的。包括 DDR1、DDR2、DDR3、DDR4、DDR4,他们都有一个很大的相似点,就是双边沿输出输入数据,通俗来讲就是在一个周期内输出 2 次数据,上升沿输出一次数据,下降沿输出一次数据。而 SDRAM 则是在一个周期内的上升沿输出一次数据,下降沿不输出,所以同频率的 DDR3 SDRAM 与 SDRAM 相比速度快一倍。
同步(Synchronous):与通常的异步 DRAM 不同,DDR3 SDRAM 存在一个同步接口,其工作时钟的时钟频率与对应控制器(CPU/FPGA)的时钟频率相同,并且 SDRAM 内部的命令发送与数据传输均以此时钟为基准,实现指令或数据的同步操作;
动态(Dynamic):DDR3 SDRAM 需要不断的刷新来保证存储阵列内数据不丢失;
随机(Random):数据在 DDR3 SDRAM 中并不是按照线性依次存储,而是可以自由指定地址进行数据的读写。
空间存储量大、读写速度快以及价格相对便宜等优点使其在存储界屹立不倒、经久不衰,广泛应用在计算机中。
2.存储原理
简单来说,DDR3 SDRAM 内部可以理解为一个存储阵列,这是 DDR3 SDRAM 区别于管道式存储,实现随机地址存取的结构特点。为方便读者理解,我们将 DDR3 SDRAM 内部存储阵列类比于一张表格,表格中的每一个单元格可以类比为存储阵列的单个存储单元。若想要实现存储阵列中的某一存储单元的数据读写操作,我们要通过行地址(RowAddress)和列地址(Column Address)(先行后列)精确定位到这一存储单元,进而进行数据的
读写操作,这就是所谓的随机地址存取。DDR3 SDRAM 存储阵列类比图,如下图所示:
DDR3 SDRAM 的基本存储单位是存储单元,而一个存储单元的容量为若干个 Bit,对于 DDR3 SDRAM 而言就是芯片的位宽,每个 Bit 存放于一个单独的存储体中,存储体是利用电容能够保持电荷以及可充放电的特性制成,主要由行选通三极管、列选通三极管、存储电容以及刷新放大器构成。电容所存储的电荷会随时间慢慢释放,这就需要不断刷新为电容充电,以保证存储数据可靠性。
如图所示:将每个存储单元简化为单 Bit 的存储体,再将若干存储体排列为矩阵,同一行将行地址线相连,同一列将列地址线相连,就构成了一个存储阵列的简化模型。DDR3 SDRAM:内部存储阵列的简化模型,具体见图:
3.内部逻辑功能图
由图 可知,DDR3 SDRAM 内部包含一个逻辑控制单元,内部包含模式寄存器和命令解码器。外部通过 CS_N、RAC_N、CAS_N、WE_N 以及地址总线向逻辑控制单元输入命令,命令经过命令解码器进行译码后,将控制参数保存到模式寄存器中,逻辑控制单元进而控制逻辑运行。外部通过地址总线输入地址信息,地址信息在逻辑控制单元进行逻辑控制时起到辅助作用,除此之外,复用的地址总线与 Bank 控制逻辑、行地址复用器、列地址计数锁存器、列地址解码器等内部器件共同作用,精确选定存储阵列中与行列地址相对应的存储单元,进而进行数据存取操作。
4.AXI接口介绍
AXI 的英文全称是 Advancede Xtensible Interface,即高级可扩展接口。之所以要采用 AXI4 接口对 ddr 进行读写是因为 Xilinx 的 migddrIp 核,无论是 6 系列还是 7 系列还是最新的 FPGA,都集成了 AXI4 接口,为了采用 AXI4 接口进行读写,后续可以兼容 xilinx的其他 fpga,可复用性更强。
AXI 协议是一种高性能、高带宽、低延迟的片内总线,具有如下特点:
1、总线的地址/控制和数据通道是分离的;
2、支持不对齐的数据传输;
3、支持突发传输,突发传输过程中只需要首地址;
4、具有分离的读/写数据通道;
5、支持显著传输访问和乱序访问;
6、更加容易进行时序收敛。
在数字电路中只能传输二进制数 0 和 1,因此可能需要一组信号才能高效地传输信息,这一组信号就组成了接口。AXI4 协议支持以下三种类型的接口:
1、AXI4:高性能存储映射接口。
2、AXI4-Lite:简化版的 AXI4 接口,用于较少数据量的存储映射通信。
3、AXI4-Stream:用于高速数据流传输,非存储映射接口。
在这里我们首先解释一下存储映射(Meamory Map)这一概念。如果一个协议是存储映射的,那么主机所发出的会话(无论读或写)就会标明一个地址。这个地址对应于系统存储空间中的一个地址,表明是针对该存储空间的读写操作。AXI4 协议支持突发传输,主要用于处理器访问存储器等需要指定地址的高速数据传输场景。AXI-Lite 为外设提供单个数据传输,主要用于访问一些低速外设中的寄存器。而 AXI-Stream 接口则像 FIFO 一样,数据传输时不需要地址,在主从设备之间直接连续读写数据,主要用于如视频、高速AD、PCIe、DMA 接口等需要高速数据传输的场合。
二.OV5640摄像头
1.基本介绍
该摄像头主要由镜头、图像传感器、板载电路及下方的信号引脚组成。镜头部件包含一个镜头座和一个可旋转调节距离的凸透镜,通过旋转可以调节焦距,正常使用时,镜头座覆盖在电路板上遮光,光线只能经过镜头传输到正中央的图像传感器,它采集得的图像数据直接传输给 FPGA 芯片,FPGA 将接收到的图像数据缓存到 DDR3 SDRAM中,在 VGA 图像显示有效区域,VGA 驱动自 DDR3 SDRAM 读取图像数据在显示屏上进行显示。图像传感器是摄像头的核心部件,上述摄像头中的图像传感器是一款型号为
OV5640 的 CMOS 类型数字图像传感器。该传感器支持输出最大为 500 万像素的图像(2592x1944 分辨率),支持使用 VGA 时序输出图像数据,输出图像的数据格式支持YUV(422/420)、YCbCr422、 RGB565 以及 JPEG 格式,若直接输出 JPEG 格式的图像时可大大减少数据量,方便网络传输。它还可以对采集得的图像进行补偿,支持伽玛曲线、 白平衡、饱和度、色度等基础处理。根据不同的分辨率配置,传感器输出图像数据的帧率从 15-60 帧可调,工作时功率在 150mW-200mW 之间。
2.功能框图
(1) 控制寄存器
标号1处的是 OV5640 的控制寄存器,它根据这些寄存器配置的参数来运行,而这些参数是由外部控制器通过 SIO_C 和 SIO_D 引脚写入的, SIO_C 与 SIO_D 使 用的通讯协议跟 I2C 十分类似。
(2) 通信、控制信号及时钟
标号2处包含了 OV5640 的通信、控制信号及外部时钟,其中 PCLK、 HREF 及VSYNC 分别是像素同步时钟、行同步信号以及帧同步信号,这与液晶屏控制中的信号是很类似的。 RESETB 引脚为低电平时,用于复位整个传感器芯片,PWDN 用于控制芯片进入低功耗模式。注意最后的一个 XCLK 引脚,它跟 PCLK是完全不同的, XCLK 是用于驱动整个传感器芯片的时钟信号,是外部输入到OV5640 的信号;而 PCLK 是 OV5640 输出数据时的同步信号,它是由 OV5640 输出的信号。 XCLK 可以外接晶振或由外部控制器提供。
(3) 感光矩阵
标号3处的是感光矩阵,光信号在这里转化成电信号,经过各种处理,这些信号存储成由一个个像素点表示的数字图像。
(4) 数据输出信号
标号4处包含了 DSP 处理单元,它会根据控制寄存器的配置做一些基本的图像处理运算。这部分还包含了图像格式转换单元及压缩单元,转换出的数据最终通过Y0-Y9 引脚输出,一般来说我们使用 8 根据数据线来传输。
(5) 数据输出信号
标号⑤处为 VCM 处理单元,他会通过图像分析来实现图像的自动对焦功能。要实现自动对焦还需要下载自动对焦固件到模组.(暂时没有加入这个功能)
三.代码设计
1.整体设计
各子模块功能介绍:
由图表可知,OV5640-VGA 图像显示工程包含表格模块ov5640_vga_640x480 作为实验工程的顶层模块,内部实例化各子功能模块,连接对应信号,对外接收摄像头采集的图像数据,将处理后的数据存入 DDR3 SDRAM,在 VGA 显示器上显示出来;clk_gen 模块,调用 IP 核生成,产生整个实验工程的工作时钟;ov5640_top 模块,是 ov5640 部分各子功能模块的集合,实现 ov5640 摄像头的配置、图像采集与处理;DDR3 SDRAM_top 模块为 DDR3 SDRAM 读写控制器,存储处理后的图像数据;vga_ctrl 模块实现 VGA 显示器的驱动控制,读取 DDR3 SDRAM 存储的图像数据并在 VGA 显示屏上显示出来。
时钟生成模块直接调用PLL即可,AXI_DDR模块工程量较多,这里不做太多介绍,VGA驱动不需要介绍,这里仅详细介绍OV5640模块。
各模块的功能:
由上述图表可知,第一部分的 OV5640 相关模块包含 4 个子模块,首先是 ov5640_top模块,这一模块作为 ov5640 部分的顶层模块,内部实例化 3 个子功能模块,连接各子模块对应信号,外部对摄像头进行相关配置并接收摄像头采集的数据信息;ov5640_cfg 模块,是寄存器配置模块,内部包含对 ov5640 摄像头的配置信息;i2c_ctrl 模块,i2c 协议与SCCB 协议几乎无差别,使用 i2c 协议代替 SCCB 接口协议向 ov5640 摄像头写ov5640_cfg 模块内部包含的寄存器配置信息;ov5640_data 模块,是 ov5640 摄像头的图像采集模块,将摄像头传入的图像数据处理后写入 DDR3 SDRAM
2.OV5640各模块代码
ov5640_top模块
module ov5640_top(
input wire sys_clk , //系统时钟
input wire sys_rst_n , //复位信号
input wire sys_init_done , //系统初始化完成(SDRAM + 摄像头)
input wire ov5640_pclk , //摄像头像素时钟
input wire ov5640_href , //摄像头行同步信号
input wire ov5640_vsync , //摄像头场同步信号
input wire [ 7:0] ov5640_data , //摄像头图像数据
output wire cfg_done , //寄存器配置完成
output wire sccb_scl , //SCL
inout wire sccb_sda , //SDA
output wire ov5640_wr_en , //图像数据有效使能信号
output wire [15:0] ov5640_data_out //图像数据
);
//parameter define
parameter SLAVE_ADDR = 7'h3C ; // 器件地址(SLAVE_ADDR)
parameter BIT_CTRL = 1'b1 ; // 字地址位控制参数(16b/8b)
parameter CLK_FREQ = 26'd50_000_000; // i2c_dri模块的驱动时钟频率(CLK_FREQ)
parameter I2C_FREQ = 18'd250_000 ; // I2C的SCL时钟频率
//wire define
wire cfg_end ;
wire cfg_start ;
wire [23:0] cfg_data ;
wire cfg_clk ;
//------------- i2c_ctrl_inst -------------
i2c_ctrl
#(
.DEVICE_ADDR (SLAVE_ADDR ), //i2c设备器件地址
.SYS_CLK_FREQ (CLK_FREQ ), //i2c_ctrl模块系统时钟频率
.SCL_FREQ (I2C_FREQ ) //i2c的SCL时钟频率
)
i2c_ctrl_inst
(
.sys_clk (sys_clk ), //输入系统时钟,50MHz
.sys_rst_n (sys_rst_n ), //输入复位信号,低电平有效
.wr_en (1'b1 ), //输入写使能信号
.rd_en ( ), //输入读使能信号
.i2c_start (cfg_start ), //输入i2c触发信号
.addr_num (BIT_CTRL ), //输入i2c字节地址字节数
.byte_addr (cfg_data[23:8]), //输入i2c字节地址
.wr_data (cfg_data[7:0] ), //输入i2c设备数据
.rd_data ( ), //输出i2c设备读取数据
.i2c_end (cfg_end ), //i2c一次读/写操作完成
.i2c_clk (cfg_clk ), //i2c驱动时钟
.i2c_scl (sccb_scl ), //输出至i2c设备的串行时钟信号scl
.i2c_sda (sccb_sda ) //输出至i2c设备的串行数据信号sda
);
//------------- ov5640_cfg_inst -------------
ov5640_cfg ov5640_cfg_inst(
.sys_clk (cfg_clk ), //系统时钟,由iic模块传入
.sys_rst_n (sys_rst_n ), //系统复位,低有效
.cfg_end (cfg_end ), //单个寄存器配置完成
.cfg_start (cfg_start ), //单个寄存器配置触发信号
.cfg_data (cfg_data ), //ID,REG_ADDR,REG_VAL
.cfg_done (cfg_done ) //寄存器配置完成
);
//------------- ov5640_data_inst -------------
ov5640_data ov5640_data_inst(
.sys_rst_n (sys_rst_n & sys_init_done ), //复位信号
.ov5640_pclk (ov5640_pclk ), //摄像头像素时钟
.ov5640_href (ov5640_href ), //摄像头行同步信号
.ov5640_vsync (ov5640_vsync ), //摄像头场同步信号
.ov5640_data (ov5640_data ), //摄像头图像数据
.ov5640_wr_en (ov5640_wr_en ), //图像数据有效使能信号
.ov5640_data_out (ov5640_data_out) //图像数据
);
endmodule
i2c_ctrl模块
// An highlighted block
module i2c_ctrl
#(
parameter DEVICE_ADDR = 7'b1010_000 , //i2c设备地址
parameter SYS_CLK_FREQ = 26'd50_000_000 , //输入系统时钟频率
parameter SCL_FREQ = 18'd250_000 //i2c设备scl时钟频率
)
(
input wire sys_clk , //输入系统时钟,50MHz
input wire sys_rst_n , //输入复位信号,低电平有效
input wire wr_en , //输入写使能信号
input wire rd_en , //输入读使能信号
input wire i2c_start , //输入i2c触发信号
input wire addr_num , //输入i2c字节地址字节数
input wire [15:0] byte_addr , //输入i2c字节地址
input wire [7:0] wr_data , //输入i2c设备数据
output reg i2c_clk , //i2c驱动时钟
output reg i2c_end , //i2c一次读/写操作完成
output reg [7:0] rd_data , //输出i2c设备读取数据
output reg i2c_scl , //输出至i2c设备的串行时钟信号scl
inout wire i2c_sda //输出至i2c设备的串行数据信号sda
);
// parameter define
parameter CNT_CLK_MAX = (SYS_CLK_FREQ/SCL_FREQ) >> 2'd3 ; //cnt_clk计数器计数最大值
parameter CNT_START_MAX = 8'd100; //cnt_start计数器计数最大值
parameter IDLE = 4'd00, //初始状态
START_1 = 4'd01, //开始状态1
SEND_D_ADDR = 4'd02, //设备地址写入状态 + 控制写
ACK_1 = 4'd03, //应答状态1
SEND_B_ADDR_H = 4'd04, //字节地址高八位写入状态
ACK_2 = 4'd05, //应答状态2
SEND_B_ADDR_L = 4'd06, //字节地址低八位写入状态
ACK_3 = 4'd07, //应答状态3
WR_DATA = 4'd08, //写数据状态
ACK_4 = 4'd09, //应答状态4
START_2 = 4'd10, //开始状态2
SEND_RD_ADDR = 4'd11, //设备地址写入状态 + 控制读
ACK_5 = 4'd12, //应答状态5
RD_DATA = 4'd13, //读数据状态
N_ACK = 4'd14, //非应答状态
STOP = 4'd15; //结束状态
// wire define
wire sda_in ; //sda输入数据寄存
wire sda_en ; //sda数据写入使能信号
// reg define
reg [7:0] cnt_clk ; //系统时钟计数器,控制生成clk_i2c时钟信号
reg [3:0] state ; //状态机状态
reg cnt_i2c_clk_en ; //cnt_i2c_clk计数器使能信号
reg [1:0] cnt_i2c_clk ; //clk_i2c时钟计数器,控制生成cnt_bit信号
reg [2:0] cnt_bit ; //sda比特计数器
reg ack ; //应答信号
reg i2c_sda_reg ; //sda数据缓存
reg [7:0] rd_data_reg ; //自i2c设备读出数据
// cnt_clk:系统时钟计数器,控制生成clk_i2c时钟信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 8'd0;
else if(cnt_clk == CNT_CLK_MAX - 1'b1)
cnt_clk <= 8'd0;
else
cnt_clk <= cnt_clk + 1'b1;
// i2c_clk:i2c驱动时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
i2c_clk <= 1'b1;
else if(cnt_clk == CNT_CLK_MAX - 1'b1)
i2c_clk <= ~i2c_clk;
// cnt_i2c_clk_en:cnt_i2c_clk计数器使能信号
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_i2c_clk_en <= 1'b0;
else if((state == STOP) && (cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))
cnt_i2c_clk_en <= 1'b0;
else if(i2c_start == 1'b1)
cnt_i2c_clk_en <= 1'b1;
// cnt_i2c_clk:i2c_clk时钟计数器,控制生成cnt_bit信号
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_i2c_clk <= 2'd0;
else if(cnt_i2c_clk_en == 1'b1)
cnt_i2c_clk <= cnt_i2c_clk + 1'b1;
// cnt_bit:sda比特计数器
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 3'd0;
else if((state == IDLE) || (state == START_1) || (state == START_2)
|| (state == ACK_1) || (state == ACK_2) || (state == ACK_3)
|| (state == ACK_4) || (state == ACK_5) || (state == N_ACK))
cnt_bit <= 3'd0;
else if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
cnt_bit <= 3'd0;
else if((cnt_i2c_clk == 2'd3) && (state != IDLE))
cnt_bit <= cnt_bit + 1'b1;
// state:状态机状态跳转
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else case(state)
IDLE:
if(i2c_start == 1'b1)
state <= START_1;
else
state <= state;
START_1:
if(cnt_i2c_clk == 3)
state <= SEND_D_ADDR;
else
state <= state;
SEND_D_ADDR:
if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
state <= ACK_1;
else
state <= state;
ACK_1:
if((cnt_i2c_clk == 3) && (ack == 1'b0))
begin
if(addr_num == 1'b1)
state <= SEND_B_ADDR_H;
else
state <= SEND_B_ADDR_L;
end
else
state <= state;
SEND_B_ADDR_H:
if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
state <= ACK_2;
else
state <= state;
ACK_2:
if((cnt_i2c_clk == 3) && (ack == 1'b0))
state <= SEND_B_ADDR_L;
else
state <= state;
SEND_B_ADDR_L:
if((cnt_bit == 3'd7) && (cnt_i2c_clk == 3))
state <= ACK_3;
else
state <= state;
ACK_3:
if((cnt_i2c_clk == 3) && (ack == 1'b0))
begin
if(wr_en == 1'b1)
state <= WR_DATA;
else if(rd_en == 1'b1)
state <= START_2;
else
state <= state;
end
else
state <= state;
WR_DATA:
if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
state <= ACK_4;
else
state <= state;
ACK_4:
if((cnt_i2c_clk == 3) && (ack == 1'b0))
state <= STOP;
else
state <= state;
START_2:
if(cnt_i2c_clk == 3)
state <= SEND_RD_ADDR;
else
state <= state;
SEND_RD_ADDR:
if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
state <= ACK_5;
else
state <= state;
ACK_5:
if((cnt_i2c_clk == 3) && (ack == 1'b0))
state <= RD_DATA;
else
state <= state;
RD_DATA:
if((cnt_bit == 3'd7) &&(cnt_i2c_clk == 3))
state <= N_ACK;
else
state <= state;
N_ACK:
if(cnt_i2c_clk == 3)
state <= STOP;
else
state <= state;
STOP:
if((cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))
state <= IDLE;
else
state <= state;
default: state <= IDLE;
endcase
// ack:应答信号
always@(*)
case (state)
IDLE,START_1,SEND_D_ADDR,SEND_B_ADDR_H,SEND_B_ADDR_L,
WR_DATA,START_2,SEND_RD_ADDR,RD_DATA,N_ACK:
ack <= 1'b1;
ACK_1,ACK_2,ACK_3,ACK_4,ACK_5:
if(cnt_i2c_clk == 2'd0)
ack <= sda_in;//1'b0;//
else
ack <= ack;
default: ack <= 1'b1;
endcase
// i2c_scl:输出至i2c设备的串行时钟信号scl
always@(*)
case (state)
IDLE:
i2c_scl <= 1'b1;
START_1:
if(cnt_i2c_clk == 2'd3)
i2c_scl <= 1'b0;
else
i2c_scl <= 1'b1;
SEND_D_ADDR,ACK_1,SEND_B_ADDR_H,ACK_2,SEND_B_ADDR_L,
ACK_3,WR_DATA,ACK_4,START_2,SEND_RD_ADDR,ACK_5,RD_DATA,N_ACK:
if((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2))
i2c_scl <= 1'b1;
else
i2c_scl <= 1'b0;
STOP:
if((cnt_bit == 3'd0) &&(cnt_i2c_clk == 2'd0))
i2c_scl <= 1'b0;
else
i2c_scl <= 1'b1;
default: i2c_scl <= 1'b1;
endcase
// i2c_sda_reg:sda数据缓存
always@(*)
case (state)
IDLE:
begin
i2c_sda_reg <= 1'b1;
rd_data_reg <= 8'd0;
end
START_1:
if(cnt_i2c_clk <= 2'd0)
i2c_sda_reg <= 1'b1;
else
i2c_sda_reg <= 1'b0;
SEND_D_ADDR:
if(cnt_bit <= 3'd6)
i2c_sda_reg <= DEVICE_ADDR[6 - cnt_bit];
else
i2c_sda_reg <= 1'b0;
ACK_1:
i2c_sda_reg <= 1'b1;
SEND_B_ADDR_H:
i2c_sda_reg <= byte_addr[15 - cnt_bit];
ACK_2:
i2c_sda_reg <= 1'b1;
SEND_B_ADDR_L:
i2c_sda_reg <= byte_addr[7 - cnt_bit];
ACK_3:
i2c_sda_reg <= 1'b1;
WR_DATA:
i2c_sda_reg <= wr_data[7 - cnt_bit];
ACK_4:
i2c_sda_reg <= 1'b1;
START_2:
if(cnt_i2c_clk <= 2'd1)
i2c_sda_reg <= 1'b1;
else
i2c_sda_reg <= 1'b0;
SEND_RD_ADDR:
if(cnt_bit <= 3'd6)
i2c_sda_reg <= DEVICE_ADDR[6 - cnt_bit];
else
i2c_sda_reg <= 1'b1;
ACK_5:
i2c_sda_reg <= 1'b1;
RD_DATA:
if(cnt_i2c_clk == 2'd2)
rd_data_reg[7 - cnt_bit] <= sda_in;
else
rd_data_reg <= rd_data_reg;
N_ACK:
i2c_sda_reg <= 1'b1;
STOP:
if((cnt_bit == 3'd0) && (cnt_i2c_clk < 2'd3))
i2c_sda_reg <= 1'b0;
else
i2c_sda_reg <= 1'b1;
default:
begin
i2c_sda_reg <= 1'b1;
rd_data_reg <= rd_data_reg;
end
endcase
// rd_data:自i2c设备读出数据
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_data <= 8'd0;
else if((state == RD_DATA) && (cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))
rd_data <= rd_data_reg;
// i2c_end:一次读/写结束信号
always@(posedge i2c_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
i2c_end <= 1'b0;
else if((state == STOP) && (cnt_bit == 3'd3) &&(cnt_i2c_clk == 3))
i2c_end <= 1'b1;
else
i2c_end <= 1'b0;
// sda_in:sda输入数据寄存
assign sda_in = i2c_sda;
// sda_en:sda数据写入使能信号
assign sda_en = ((state == RD_DATA) || (state == ACK_1) || (state == ACK_2)
|| (state == ACK_3) || (state == ACK_4) || (state == ACK_5))
? 1'b0 : 1'b1;
// i2c_sda:输出至i2c设备的串行数据信号sda
assign i2c_sda = (sda_en == 1'b1) ? i2c_sda_reg : 1'bz;
endmodule
ov5640_cfg模块(寄存器配置模块)
module ov5640_cfg
(
input wire sys_clk , //系统时钟,由iic模块传入
input wire sys_rst_n , //系统复位,低有效
input wire cfg_end , //单个寄存器配置完成
output reg cfg_start , //单个寄存器配置触发信号
output wire [23:0] cfg_data , //ID,REG_ADDR,REG_VAL
output reg cfg_done //寄存器配置完成
);
//parameter define
parameter REG_NUM = 8'd251 ; //总共需要配置的寄存器个数
parameter CNT_WAIT_MAX = 15'd20000 ; //寄存器配置等待计数最大值
//wire define
wire [23:0] cfg_data_reg[REG_NUM-1:0] ; //寄存器配置数据暂存
//reg define
reg [14:0] cnt_wait ; //寄存器配置等待计数器
reg [7:0] reg_num ; //配置寄存器个数
//cnt_wait:寄存器配置等待计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_wait <= 15'd0;
else if(cnt_wait < CNT_WAIT_MAX)
cnt_wait <= cnt_wait + 1'b1;
//reg_num:配置寄存器个数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
reg_num <= 8'd0;
else if(cfg_end == 1'b1)
reg_num <= reg_num + 1'b1;
//cfg_start:单个寄存器配置触发信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cfg_start <= 1'b0;
else if(cnt_wait == (CNT_WAIT_MAX - 1'b1))
cfg_start <= 1'b1;
else if((cfg_end == 1'b1) && (reg_num < REG_NUM))
cfg_start <= 1'b1;
else
cfg_start <= 1'b0;
//cfg_done:寄存器配置完成
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cfg_done <= 1'b0;
else if((reg_num == REG_NUM) && (cfg_end == 1'b1))
cfg_done <= 1'b1;
//cfg_data:ID,REG_ADDR,REG_VAL
assign cfg_data = (cfg_done == 1'b1) ? 24'b0 : cfg_data_reg[reg_num];
//----------------------------------------------------
//cfg_data_reg:寄存器配置数据暂存 ID REG_ADDR REG_VAL
assign cfg_data_reg[000] = {16'h3103, 8'h11};
assign cfg_data_reg[001] = {16'h3008, 8'h82};
assign cfg_data_reg[002] = {16'h3008, 8'h42};
assign cfg_data_reg[003] = {16'h3103, 8'h03};
assign cfg_data_reg[004] = {16'h3017, 8'hff};
assign cfg_data_reg[005] = {16'h3018, 8'hff};
assign cfg_data_reg[006] = {16'h3034, 8'h1A};
assign cfg_data_reg[007] = {16'h3037, 8'h13};
assign cfg_data_reg[008] = {16'h3108, 8'h01};
assign cfg_data_reg[009] = {16'h3630, 8'h36};
assign cfg_data_reg[010] = {16'h3631, 8'h0e};
assign cfg_data_reg[011] = {16'h3632, 8'he2};
assign cfg_data_reg[012] = {16'h3633, 8'h12};
assign cfg_data_reg[013] = {16'h3621, 8'he0};
assign cfg_data_reg[014] = {16'h3704, 8'ha0};
assign cfg_data_reg[015] = {16'h3703, 8'h5a};
assign cfg_data_reg[016] = {16'h3715, 8'h78};
assign cfg_data_reg[017] = {16'h3717, 8'h01};
assign cfg_data_reg[018] = {16'h370b, 8'h60};
assign cfg_data_reg[019] = {16'h3705, 8'h1a};
assign cfg_data_reg[020] = {16'h3905, 8'h02};
assign cfg_data_reg[021] = {16'h3906, 8'h10};
assign cfg_data_reg[022] = {16'h3901, 8'h0a};
assign cfg_data_reg[023] = {16'h3731, 8'h12};
assign cfg_data_reg[024] = {16'h3600, 8'h08};
assign cfg_data_reg[025] = {16'h3601, 8'h33};
assign cfg_data_reg[026] = {16'h302d, 8'h60};
assign cfg_data_reg[027] = {16'h3620, 8'h52};
assign cfg_data_reg[028] = {16'h371b, 8'h20};
assign cfg_data_reg[029] = {16'h471c, 8'h50};
assign cfg_data_reg[030] = {16'h3a13, 8'h43};
assign cfg_data_reg[031] = {16'h3a18, 8'h00};
assign cfg_data_reg[032] = {16'h3a19, 8'hf8};
assign cfg_data_reg[033] = {16'h3635, 8'h13};
assign cfg_data_reg[034] = {16'h3636, 8'h03};
assign cfg_data_reg[035] = {16'h3634, 8'h40};
assign cfg_data_reg[036] = {16'h3622, 8'h01};
assign cfg_data_reg[037] = {16'h3c01, 8'h34};
assign cfg_data_reg[038] = {16'h3c04, 8'h28};
assign cfg_data_reg[039] = {16'h3c05, 8'h98};
assign cfg_data_reg[040] = {16'h3c06, 8'h00};
assign cfg_data_reg[041] = {16'h3c07, 8'h08};
assign cfg_data_reg[042] = {16'h3c08, 8'h00};
assign cfg_data_reg[043] = {16'h3c09, 8'h1c};
assign cfg_data_reg[044] = {16'h3c0a, 8'h9c};
assign cfg_data_reg[045] = {16'h3c0b, 8'h40};
assign cfg_data_reg[046] = {16'h3810, 8'h00};
assign cfg_data_reg[047] = {16'h3811, 8'h10};
assign cfg_data_reg[048] = {16'h3812, 8'h00};
assign cfg_data_reg[049] = {16'h3708, 8'h64};
assign cfg_data_reg[050] = {16'h4001, 8'h02};
assign cfg_data_reg[051] = {16'h4005, 8'h1a};
assign cfg_data_reg[052] = {16'h3000, 8'h00};
assign cfg_data_reg[053] = {16'h3004, 8'hff};
assign cfg_data_reg[054] = {16'h300e, 8'h58};
assign cfg_data_reg[055] = {16'h302e, 8'h00};
assign cfg_data_reg[056] = {16'h4300, 8'h61};
assign cfg_data_reg[057] = {16'h501f, 8'h01};
assign cfg_data_reg[058] = {16'h440e, 8'h00};
assign cfg_data_reg[059] = {16'h5000, 8'ha7};
assign cfg_data_reg[060] = {16'h3a0f, 8'h30};
assign cfg_data_reg[061] = {16'h3a10, 8'h28};
assign cfg_data_reg[062] = {16'h3a1b, 8'h30};
assign cfg_data_reg[063] = {16'h3a1e, 8'h26};
assign cfg_data_reg[064] = {16'h3a11, 8'h60};
assign cfg_data_reg[065] = {16'h3a1f, 8'h14};
assign cfg_data_reg[066] = {16'h5800, 8'h23};
assign cfg_data_reg[067] = {16'h5801, 8'h14};
assign cfg_data_reg[068] = {16'h5802, 8'h0f};
assign cfg_data_reg[069] = {16'h5803, 8'h0f};
assign cfg_data_reg[070] = {16'h5804, 8'h12};
assign cfg_data_reg[071] = {16'h5805, 8'h26};
assign cfg_data_reg[072] = {16'h5806, 8'h0c};
assign cfg_data_reg[073] = {16'h5807, 8'h08};
assign cfg_data_reg[074] = {16'h5808, 8'h05};
assign cfg_data_reg[075] = {16'h5809, 8'h05};
assign cfg_data_reg[076] = {16'h580a, 8'h08};
assign cfg_data_reg[077] = {16'h580b, 8'h0d};
assign cfg_data_reg[078] = {16'h580c, 8'h08};
assign cfg_data_reg[079] = {16'h580d, 8'h03};
assign cfg_data_reg[080] = {16'h580e, 8'h00};
assign cfg_data_reg[081] = {16'h580f, 8'h00};
assign cfg_data_reg[082] = {16'h5810, 8'h03};
assign cfg_data_reg[083] = {16'h5811, 8'h09};
assign cfg_data_reg[084] = {16'h5812, 8'h07};
assign cfg_data_reg[085] = {16'h5813, 8'h03};
assign cfg_data_reg[086] = {16'h5814, 8'h00};
assign cfg_data_reg[087] = {16'h5815, 8'h01};
assign cfg_data_reg[088] = {16'h5816, 8'h03};
assign cfg_data_reg[089] = {16'h5817, 8'h08};
assign cfg_data_reg[090] = {16'h5818, 8'h0d};
assign cfg_data_reg[091] = {16'h5819, 8'h08};
assign cfg_data_reg[092] = {16'h581a, 8'h05};
assign cfg_data_reg[093] = {16'h581b, 8'h06};
assign cfg_data_reg[094] = {16'h581c, 8'h08};
assign cfg_data_reg[095] = {16'h581d, 8'h0e};
assign cfg_data_reg[096] = {16'h581e, 8'h29};
assign cfg_data_reg[097] = {16'h581f, 8'h17};
assign cfg_data_reg[098] = {16'h5820, 8'h11};
assign cfg_data_reg[099] = {16'h5821, 8'h11};
assign cfg_data_reg[100] = {16'h5822, 8'h15};
assign cfg_data_reg[101] = {16'h5823, 8'h28};
assign cfg_data_reg[102] = {16'h5824, 8'h46};
assign cfg_data_reg[103] = {16'h5825, 8'h26};
assign cfg_data_reg[104] = {16'h5826, 8'h08};
assign cfg_data_reg[105] = {16'h5827, 8'h26};
assign cfg_data_reg[106] = {16'h5828, 8'h64};
assign cfg_data_reg[107] = {16'h5829, 8'h26};
assign cfg_data_reg[108] = {16'h582a, 8'h24};
assign cfg_data_reg[109] = {16'h582b, 8'h22};
assign cfg_data_reg[110] = {16'h582c, 8'h24};
assign cfg_data_reg[111] = {16'h582d, 8'h24};
assign cfg_data_reg[112] = {16'h582e, 8'h06};
assign cfg_data_reg[113] = {16'h582f, 8'h22};
assign cfg_data_reg[114] = {16'h5830, 8'h40};
assign cfg_data_reg[115] = {16'h5831, 8'h42};
assign cfg_data_reg[116] = {16'h5832, 8'h24};
assign cfg_data_reg[117] = {16'h5833, 8'h26};
assign cfg_data_reg[118] = {16'h5834, 8'h24};
assign cfg_data_reg[119] = {16'h5835, 8'h22};
assign cfg_data_reg[120] = {16'h5836, 8'h22};
assign cfg_data_reg[121] = {16'h5837, 8'h26};
assign cfg_data_reg[122] = {16'h5838, 8'h44};
assign cfg_data_reg[123] = {16'h5839, 8'h24};
assign cfg_data_reg[124] = {16'h583a, 8'h26};
assign cfg_data_reg[125] = {16'h583b, 8'h28};
assign cfg_data_reg[126] = {16'h583c, 8'h42};
assign cfg_data_reg[127] = {16'h583d, 8'hce};
assign cfg_data_reg[128] = {16'h5180, 8'hff};
assign cfg_data_reg[129] = {16'h5181, 8'hf2};
assign cfg_data_reg[130] = {16'h5182, 8'h00};
assign cfg_data_reg[131] = {16'h5183, 8'h14};
assign cfg_data_reg[132] = {16'h5184, 8'h25};
assign cfg_data_reg[133] = {16'h5185, 8'h24};
assign cfg_data_reg[134] = {16'h5186, 8'h09};
assign cfg_data_reg[135] = {16'h5187, 8'h09};
assign cfg_data_reg[136] = {16'h5188, 8'h09};
assign cfg_data_reg[137] = {16'h5189, 8'h75};
assign cfg_data_reg[138] = {16'h518a, 8'h54};
assign cfg_data_reg[139] = {16'h518b, 8'he0};
assign cfg_data_reg[140] = {16'h518c, 8'hb2};
assign cfg_data_reg[141] = {16'h518d, 8'h42};
assign cfg_data_reg[142] = {16'h518e, 8'h3d};
assign cfg_data_reg[143] = {16'h518f, 8'h56};
assign cfg_data_reg[144] = {16'h5190, 8'h46};
assign cfg_data_reg[145] = {16'h5191, 8'hf8};
assign cfg_data_reg[146] = {16'h5192, 8'h04};
assign cfg_data_reg[147] = {16'h5193, 8'h70};
assign cfg_data_reg[148] = {16'h5194, 8'hf0};
assign cfg_data_reg[149] = {16'h5195, 8'hf0};
assign cfg_data_reg[150] = {16'h5196, 8'h03};
assign cfg_data_reg[151] = {16'h5197, 8'h01};
assign cfg_data_reg[152] = {16'h5198, 8'h04};
assign cfg_data_reg[153] = {16'h5199, 8'h12};
assign cfg_data_reg[154] = {16'h519a, 8'h04};
assign cfg_data_reg[155] = {16'h519b, 8'h00};
assign cfg_data_reg[156] = {16'h519c, 8'h06};
assign cfg_data_reg[157] = {16'h519d, 8'h82};
assign cfg_data_reg[158] = {16'h519e, 8'h38};
assign cfg_data_reg[159] = {16'h5480, 8'h01};
assign cfg_data_reg[160] = {16'h5481, 8'h08};
assign cfg_data_reg[161] = {16'h5482, 8'h14};
assign cfg_data_reg[162] = {16'h5483, 8'h28};
assign cfg_data_reg[163] = {16'h5484, 8'h51};
assign cfg_data_reg[164] = {16'h5485, 8'h65};
assign cfg_data_reg[165] = {16'h5486, 8'h71};
assign cfg_data_reg[166] = {16'h5487, 8'h7d};
assign cfg_data_reg[167] = {16'h5488, 8'h87};
assign cfg_data_reg[168] = {16'h5489, 8'h91};
assign cfg_data_reg[169] = {16'h548a, 8'h9a};
assign cfg_data_reg[170] = {16'h548b, 8'haa};
assign cfg_data_reg[171] = {16'h548c, 8'hb8};
assign cfg_data_reg[172] = {16'h548d, 8'hcd};
assign cfg_data_reg[173] = {16'h548e, 8'hdd};
assign cfg_data_reg[174] = {16'h548f, 8'hea};
assign cfg_data_reg[175] = {16'h5490, 8'h1d};
assign cfg_data_reg[176] = {16'h5381, 8'h1e};
assign cfg_data_reg[177] = {16'h5382, 8'h5b};
assign cfg_data_reg[178] = {16'h5383, 8'h08};
assign cfg_data_reg[179] = {16'h5384, 8'h0a};
assign cfg_data_reg[180] = {16'h5385, 8'h7e};
assign cfg_data_reg[181] = {16'h5386, 8'h88};
assign cfg_data_reg[182] = {16'h5387, 8'h7c};
assign cfg_data_reg[183] = {16'h5388, 8'h6c};
assign cfg_data_reg[184] = {16'h5389, 8'h10};
assign cfg_data_reg[185] = {16'h538a, 8'h01};
assign cfg_data_reg[186] = {16'h538b, 8'h98};
assign cfg_data_reg[187] = {16'h5580, 8'h06};
assign cfg_data_reg[188] = {16'h5583, 8'h40};
assign cfg_data_reg[189] = {16'h5584, 8'h10};
assign cfg_data_reg[190] = {16'h5589, 8'h10};
assign cfg_data_reg[191] = {16'h558a, 8'h00};
assign cfg_data_reg[192] = {16'h558b, 8'hf8};
assign cfg_data_reg[193] = {16'h501d, 8'h40};
assign cfg_data_reg[194] = {16'h5300, 8'h08};
assign cfg_data_reg[195] = {16'h5301, 8'h30};
assign cfg_data_reg[196] = {16'h5302, 8'h10};
assign cfg_data_reg[197] = {16'h5303, 8'h00};
assign cfg_data_reg[198] = {16'h5304, 8'h08};
assign cfg_data_reg[199] = {16'h5305, 8'h30};
assign cfg_data_reg[200] = {16'h5306, 8'h08};
assign cfg_data_reg[201] = {16'h5307, 8'h16};
assign cfg_data_reg[202] = {16'h5309, 8'h08};
assign cfg_data_reg[203] = {16'h530a, 8'h30};
assign cfg_data_reg[204] = {16'h530b, 8'h04};
assign cfg_data_reg[205] = {16'h530c, 8'h06};
assign cfg_data_reg[206] = {16'h5025, 8'h00};
assign cfg_data_reg[207] = {16'h3008, 8'h02};
assign cfg_data_reg[208] = {16'h3035, 8'h11};
assign cfg_data_reg[209] = {16'h3036, 8'h46};
assign cfg_data_reg[210] = {16'h3c07, 8'h08};
assign cfg_data_reg[211] = {16'h3820, 8'h47};
assign cfg_data_reg[212] = {16'h3821, 8'h00};
assign cfg_data_reg[213] = {16'h3814, 8'h31};
assign cfg_data_reg[214] = {16'h3815, 8'h31};
assign cfg_data_reg[215] = {16'h3800, 8'h00};
assign cfg_data_reg[216] = {16'h3801, 8'h00};
assign cfg_data_reg[217] = {16'h3802, 8'h00};
assign cfg_data_reg[218] = {16'h3803, 8'h04};
assign cfg_data_reg[219] = {16'h3804, 8'h0a};
assign cfg_data_reg[220] = {16'h3805, 8'h3f};
assign cfg_data_reg[221] = {16'h3806, 8'h07};
assign cfg_data_reg[222] = {16'h3807, 8'h9b};
assign cfg_data_reg[223] = {16'h3808, 8'h02};
assign cfg_data_reg[224] = {16'h3809, 8'h80};
assign cfg_data_reg[225] = {16'h380a, 8'h01};
assign cfg_data_reg[226] = {16'h380b, 8'he0};
assign cfg_data_reg[227] = {16'h380c, 8'h07};
assign cfg_data_reg[228] = {16'h380d, 8'h68};
assign cfg_data_reg[229] = {16'h380e, 8'h03};
assign cfg_data_reg[230] = {16'h380f, 8'hd8};
assign cfg_data_reg[231] = {16'h3813, 8'h06};
assign cfg_data_reg[232] = {16'h3618, 8'h00};
assign cfg_data_reg[233] = {16'h3612, 8'h29};
assign cfg_data_reg[234] = {16'h3709, 8'h52};
assign cfg_data_reg[235] = {16'h370c, 8'h03};
assign cfg_data_reg[236] = {16'h3a02, 8'h17};
assign cfg_data_reg[237] = {16'h3a03, 8'h10};
assign cfg_data_reg[238] = {16'h3a14, 8'h17};
assign cfg_data_reg[239] = {16'h3a15, 8'h10};
assign cfg_data_reg[240] = {16'h4004, 8'h02};
assign cfg_data_reg[241] = {16'h3002, 8'h1c};
assign cfg_data_reg[242] = {16'h3006, 8'hc3};
assign cfg_data_reg[243] = {16'h4713, 8'h03};
assign cfg_data_reg[244] = {16'h4407, 8'h04};
assign cfg_data_reg[245] = {16'h460b, 8'h35};
assign cfg_data_reg[246] = {16'h460c, 8'h22};
assign cfg_data_reg[247] = {16'h4837, 8'h22};
assign cfg_data_reg[248] = {16'h3824, 8'h02};
assign cfg_data_reg[249] = {16'h5001, 8'ha3};
assign cfg_data_reg[250] = {16'h3503, 8'h00};
//-------------------------------------------------------
endmodule
ov5640_data模块(将摄像头采集到的数据发送给DDR3)
module ov5640_data(
input wire sys_rst_n,
//OV5640
input wire ov5640_pclk,
input wire ov5640_href,
input wire ov5640_vsync,
input wire [7:0] ov5640_data,
//写FIFO
output wire ov5640_wr_en,
output wire [15:0] ov5640_data_out
);
parameter PIC_WAIT = 4'd10;//图像稳定前等待帧图像个数
wire pic_flag ; //帧图像标志信号,每拉高一次,表示一帧完整图像
reg ov5640_vsync_dly ;//摄像头输入长信号打拍
reg [3:0] cnt_pic ;//图像帧数计数器
reg pic_valid ;//帧有效标志信号
reg [7:0] pic_data_reg ;//输入8位图像数据缓存
reg [15:0] data_out_reg ;//输出16位图像数据缓存
reg data_flag ;//输入8位图像数据缓存
reg data_flag_dly1 ;//图像数据拼接标志信号打拍
//ov5640_vsync_dly:摄像头输入长信号打拍
always@(posedge ov5640_pclk or negedge sys_rst_n)
begin
if(!sys_rst_n)
ov5640_vsync_dly <= 1'b0;
else
ov5640_vsync_dly <= ov5640_vsync;
end
//pic_flag:帧图像标志信号,每拉高一次,表示一帧完整图像
assign pic_flag = ((ov5640_vsync_dly == 1'b0) &&
(ov5640_vsync == 1'b1)) ? 1'b1: 1'b0;
//cnt_pic:图像帧计数器
always@(posedge ov5640_pclk or negedge sys_rst_n)
begin
if(!sys_rst_n)
cnt_pic <= 4'd0;
else if(cnt_pic < PIC_WAIT)
cnt_pic <= cnt_pic + 1'b1;
else
cnt_pic <= cnt_pic;
end
//pic_valid:真有效信号
always@(posedge ov5640_pclk or negedge sys_rst_n)
begin
if(!sys_rst_n)
pic_valid <= 1'b0;
else if((cnt_pic == PIC_WAIT) && (pic_flag == 1'b1))
pic_valid <= 1'b1;
else
pic_valid <= pic_valid;
end
//data_out_reg,pic_data_reg,data_flag:输出16位图像数据缓存
//输入8位图像数据缓存
always@(posedge ov5640_pclk or negedge sys_rst_n)
begin
if(!sys_rst_n)
begin
data_out_reg <= 16'd0;
pic_data_reg <= 8'd0;
data_flag <= 1'b0;
end
else if(ov5640_href == 1'b1)
begin
data_out_reg <= data_out_reg ;
pic_data_reg <= ov5640_data;
data_flag <= ~data_flag;
if(data_flag == 1'b1)
data_out_reg <= {pic_data_reg,ov5640_data};
else
data_out_reg <= data_out_reg;
end
else
begin
data_out_reg <= data_out_reg;
pic_data_reg <= 8'd0;
data_flag <= 1'b0;
end
end
//data_flag_dly1:图片数据缓存打拍
always@(posedge ov5640_pclk or negedge sys_rst_n)
begin
if(!sys_rst_n)
data_flag_dly1 <= 1'b0;
else
data_flag_dly1 <= data_flag;
end
//ov5640_data_out :输出16位图像数据
assign ov5640_data_out = (pic_valid == 1'b1) ? data_out_reg: 16'd0;
//ov5640_wr_en:输出16位图片数据使能
assign ov5640_wr_en = pic_valid ?data_flag_dly1 : 1'b1;
endmodule
四.上板验证结果
由于VGA是调用之前写过的640*480分辨率的模块,所以四周会有一些显示问题,后期更改一下分辨率和时钟即可。
由于DDR3实现的流程和代码都比较复杂,所以没有展示DDR3的代码。如有需要整个工程的文件,欢迎邮箱留言,看到后就会给大家分享!
初学入门,分享学习笔记和心得,如有指教,感激不尽!
标签:16,DDR3,VGA,assign,ov5640,cfg,OV5640,data,reg 来源: https://blog.csdn.net/weixin_46628093/article/details/115558116