豪威的ov系列的摄像头可谓在FPGA图像处理中应用广泛,虽然博主利用黑金给的教材直接跑程序就可以得到摄像头的实时显示,但是无奈黑金给的代码太多,太繁琐。看了半天勉强看懂每个文件的大体意思,知道了之间的关系,会改改基本参数,仅此而已。那还毕业毛业啊这样。。。所以博主打算自己编写一套完整的系统来实现读取摄像头并且进行图像处理,然后实时显示的系统。虽然说万事开头难,但是怎么说呢,不积跬步,无以至千里。所以博主打算先成功读取豪威的摄像头啊。
首先豪威ov5642的摄像头和5640很相似,都是用iic进行通信的,虽然豪威官方的通信方式是SCCB,但是不同之处只是在读数据时候时序有些不同,由于我们是配置寄存器,往里面写数据的,所以时序一模一样的。关于iic的通信这里就不多介绍了,博主有相关的博客可以参考,只是补充一点,这里设备的地址不再是8位而是16位了,所以应答需要两次。由于黑金给的板子比较良心,不需要上电启动,直接配置寄存器即可,所以没有一点难度。建议先做下仿真看看时序有没有问题。。。
好了,寄存器配置完后,我们自己设置一个done信号来提示寄存器已经配置完毕,像素数据要输出了。其实我发现done信号可有可无,因为相机自己会有一个像素有效信号href,这个信号有效,就可以读数据。这样就可以抓数据啦怎么抓呢,就是通过ila将data信号获取,然后看一行data数据的个数来判断是否读对了。来看结果
看,这里显示href有效的一个周期内总共有1280个数据,由于我们设置的分辨率是640的,正好是一半,所以说明我们的代码没有问题。代码很简单,就是iic的代码,配置完直接读取数据就行。。
START: begin
if(count>=16'd0&&count<=16'd299)
slk<=1'b1;
else
slk<=1'b0;
if(count>=16'd0&&count<=16'd200)
sda<=1'b1;
else
sda<=1'b0;
if(count==16'd499&&writecount==6'd0)
STATE<=WRITE_DEVICE;
end
WRITE_DEVICE: begin
if(count>=16'd0&&count<=16'd124)
slk<=1'b0;
else if(count>=16'd125&&count<=16'd374)
slk<=1'b1;
else if(count>=16'd375&&count<=16'd499)
slk<=1'b0;
if(writecount==6'd7&&count==16'd499)
begin
STATE<=ASK;
writecount<=writecount+1'b1;
//ask sda 1'bz
//sda<=1'bz;
end
else if(count==16'd499)
writecount<=writecount+1'b1;
else
writecount<=writecount;
//写设备地址
sda<=writedata[6'd31-writecount];
end
WRITE_HIGHADD: begin
if(count>=16'd0&&count<=16'd124)
slk<=1'b0;
else if(count>=16'd125&&count<=16'd374)
slk<=1'b1;
else if(count>=16'd375&&count<=16'd499)
slk<=1'b0;
if(writecount==6'd15&&count==16'd499)
begin
STATE<=ASK;
writecount<=writecount+1'b1;
//ask sda 1'bz
//sda<=1'bz;
end
else if(count==16'd499)
writecount<=writecount+1'b1;
else
writecount<=writecount;
//写设备地址
sda<=writedata[6'd31-writecount];
end
WRITE_LOWADD: begin
if(count>=16'd0&&count<=16'd124)
slk<=1'b0;
else if(count>=16'd125&&count<=16'd374)
slk<=1'b1;
else if(count>=16'd375&&count<=16'd499)
slk<=1'b0;
if(writecount==6'd23&&count==16'd499)
begin
STATE<=ASK;
writecount<=writecount+1'b1;
//ask sda 1'bz
//sda<=1'bz;
end
else if(count==16'd499)
writecount<=writecount+1'b1;
else
writecount<=writecount;
//写设备地址
sda<=writedata[6'd31-writecount];
end
WRITE_DATA: begin
if(count>=16'd0&&count<=16'd124)
slk<=1'b0;
else if(count>=16'd125&&count<=16'd374)
slk<=1'b1;
else if(count>=16'd375&&count<=16'd499)
slk<=1'b0;
if(writecount==6'd31&&count==16'd499)
begin
STATE<=ASK;
// writecount<=writecount+1'b1;
//ask sda 1'bz
//sda<=1'bz;
end
else if(count==16'd499)
writecount<=writecount+1'b1;
else
writecount<=writecount;
//写设备地址
sda<=writedata[6'd31-writecount];
end
STATE_END: begin
if(count>=16'd0&&count<=16'd200)
slk<=1'b0;
else
slk<=1'b1;
if(count>=16'd0&&count<=16'd300)
sda<=1'b0;
else
sda<=1'b1;
if(count==16'd499)
STATE<=DONE;
end
ASK: begin
if(count>=16'd0&&count<=16'd124)
slk<=1'b0;
else if(count>=16'd125&&count<=16'd374)
slk<=1'b1;
else if(count>=16'd375&&count<=16'd499)
slk<=1'b0;
if(count==16'd249)
isask<=sda;
if(count==16'd499)
begin
sda<=1'b0;
STATE<=IS_ASK;
end
else
sda<=1'bz;
end
IS_ASK : begin
//if(isask!=0&&writecount==6'd7)
//begin
//STATE<=WRITE_DEVICE;
//writecount<=6'd0;
//end
if(writecount==6'd8)
STATE<=WRITE_HIGHADD;
/*else if(isask==!0&&writecount==6'd15)
begin
STATE<=WRITE_HIGHADD;
writecount<=6'd7;
end*/
else if(writecount==6'd16)
STATE<=WRITE_LOWADD;
/*else if(isask==!0&&writecount==6'd23)
begin
STATE<=WRITE_LOWADD;
writecount<=6'd15;
end*/
else if(writecount==6'd24)
STATE<=WRITE_DATA;
/*else if(isask==!0&&writecount==6'd31)
begin
STATE<=WRITE_DATA;
writecount<=6'd23;
end*/
else if(writecount==6'd31)
STATE<=STATE_END;
end
DONE: begin
writecount<=6'd0;
isdone<=1'b1;
STATE<=FINAL;
end
FINAL:begin
STATE<=START;
isdone<=1'b0;
end