利用摄像头捕获数据、SDRAM缓存数据、VGA协议驱动屏幕显示图像构成图像实时显示系统。
摄像头捕获数据的速度(12MHz、6MHz、3MHz)与VGA协议驱动速度(25MHz)不同,导致摄像头捕获数据不能够直接输出给VGA,所以中间必须加入大容量的缓冲器。
整个设计需要的时钟有:给摄像头提供24MHz的时钟,给SDR SDRAM提供的100MHz的时钟(相移270度),给SDR SDRAM控制器提供的100MHz的时钟,给VGA协议驱动提供的100MHz的时钟。
时钟产生
采用片内的PLL产生所需的时钟。
摄像头驱动设计
摄像头设计共分为三部分:硬件复位(ov7670_hardware_reset)、寄存器配置(ov7670_reg_init)、数据捕获输出(ov7670_cap)。
硬件复位和寄存器配置采用24MHz的时钟进行驱动,摄像头捕获模块采用摄像头输出的pclk来进行驱动。
硬件复位的操作为将cmos_rst_n信号拉低一段时间(大约1ms),拉高后一段时间(大约1ms)内不允许进行任何其他操作。在复位完成后,输出一个复位完成信号。
module ov7670_hardware_reset (
input wire clk,
input wire rst_n,
output wire cmos_rst_n,
output wire cmos_hardware_rst_done
);
parameter T = 50_000;
reg [15:0] cnt;
always @ (posedge clk, negedge rst_n) begin
if (rst_n == 1'b0)
cnt <= 16'd0;
else
if (cnt < T)
cnt <= cnt + 1'b1;
else
cnt <= cnt;
end
assign cmos_rst_n = (cnt < T/2) ? 1'b0 : 1'b1;
assign cmos_hardware_rst_done = (cnt == T) ? 1'b1 : 1'b0;
endmodule
摄像头有很多寄存器,具体可以查看手册中所对应的信息,这里只给出一些关键寄存器的配置。
配置寄存器的地址和配置所需的数据拼接到一起形成一个八位的数据。具体代码查看reg_config。
利用线性序列机实现SCCB协议驱动,将对应的数据配置进去。具体代码查看sccb_wr。
编写控制器从reg_config中读出数据,控制sccb_wr模块将数据配置到摄像头中,配置完成后需要等待10帧的图像(摄像头输出的VS信号为帧同步信号,有一次的高脉冲表示一帧,设计时只需要等待VS信号的10个上升沿即可),才能够输出稳定的图像信息。具体代码查看ov7670_reg_config_ctrl。
图像数据的捕获比较简单,按照摄像头手册的标准输出时序进行捕获即可。由于摄像头输出的数据为RGB565,而摄像头接口只有三位数据线,所以输出时,每两个数据对应一个像素点。具体代码查看ov7670_cap。
VGA协议驱动
VGA协议与8.5节类似,但是需要在图像显示有效区去读取FIFO,然后将数据输出到VGA接口上。由于摄像头的接口是RGB565,而VGA接口为RGB232接口,故将RGB565对应的高位输出到RGB232上(再分配管脚时,低位不分配也可以)。具体代码查看vga_ctrl。
SDR SDRAM控制器
本系统中的图像模式为640X480,在SDRAM中存储的方式设定为SDRAM每一行存储160个像素点,利用四行的存储空间存储一行的图像信息。故而需要将SDR SDRAM控制器中的读写模块更改为页读页写模式,并且每次突发的长度为160。具体代码查看sdr_wr_ctrl和sdr_rd_ctrl。
SDR SDRAM的控制器中共分为四部分:输入缓冲器(sdr_wrfifo)、输出缓冲器(sdr_rdfifo)、SDR SDRAM驱动(sdr_drive)和读写控制器(sdr_mem_ctrl)。
输入缓冲器为一个FIFO,捕获到摄像头数据输入到此FIFO中,然后写入到SDRAM中。
输出缓冲器为一个FIFO,SDRAM的数据输入到此FIFO中,然后被VGA模块读出输出给VGA接口。
SDR SDRAM驱动为控制接口模块,完成对SDRAM的写入和读出。
读写控制器为控制上述三个模块进行协调工作的模块:当输入缓冲器中的数量大于160时,读出160个写入SDRAM中;当输出缓冲器中的数量小于160时,从SDRAM中读出160个写入到输出缓冲器中。每次控制读写命令发出后,等待100个时钟周期(等待SDRAM控制器读写进行)。在进行写入和读出时,为了防止图像撕裂(写入速度比读出速度要慢,读出数据时,就会发生前半帧为新数据,后半帧为旧数据,造成一种图像撕裂的感觉),采用两个bank进行缓冲(当输出地址在最后一行时,需要判断输入地