打印
[FPGA]

OV7670摄像头显示(4)

[复制链接]
583|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
guyu_1|  楼主 | 2020-11-7 18:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1.5.2设计思路
本工程使用的SCCB接口协议,只有两根线,时钟线sio_c和数据线sio_d,因此如果要使用这个接口,我们需要时钟线的频率要求、读数据的时序和写数据的时序。知道了需求,那么在查看数据手册的时候便容易很多。
下图为三线传输开始的标志,本工程中使用的是两线传输,因此可以将下图中的SCCB_E信号忽略,然后可以看出,在sio_c为高的时候,sio_d拉低,表示数据传输的开始,但是在图中看不出sio_d拉低到sio_c拉低的间隔时间是多少。
Sio_c周期计数器count_sck:该计数器表示sio_c一个周期需要的时钟周期个数。加一条件为(flag_r || flag_w),表示接收到读使能或者写使能之后便开始计数;结束条件为数120个,跟工程设置的SCCB时钟频率为208Khz,一个周期约为4800ns,因此需要数120个,数完就清零。
位计数器count_bit:该计数器表示每个阶段需要传输的数据位数。加一条件为end_count_sck,每传输一位需要一个sio_c的周期;结束条件为数bit_num个,阶段不同,传输的数据数也不同,写数据阶段bit_num=30,读数据阶段bit_num=21
阶段计数器count_duan:该计数器表示传输数据所需要的阶段。加一条件为end_count_bit,每个阶段的数据传输完成之后,表示当前阶段结束;结束条件为数duan_num个,写数据阶段,duan_num=1,读数据阶段duan_num=2
SCCB时钟信号sio_c:初始状态为高电平,由于频率为208K,因此高电平和低电平各持续60个时钟周期,又由于开始条件保持时间和开始条件建立时间的存在,sio_c在每个阶段的第一个数据和最后一个数据部分不能变为低电平,所以变低的条件为(count_bit>=0 && count_bit < (bit_num-2) &&add_count_sck && count_sck == SIO_C-1);从低变高的条件为(count_bit>=1 && count_bit < bit_num && add_count_sck&& count_sck == SIO_C/2-1)
准备好接收指示信号rdy:该信号为0时,表示当前模块处于发送或者接收状态,不能接收上游模块发送的数据。该信号为1时,表示当前看模块处于空闲状态,可以接受上游模块发送的数据。因此该信号为1的条件是(wen || ren || flag_r|| flag_w)。注意rdy信号需要使用组合逻辑产生。
1.5.3参考代码
  •    always  @(posedge clk or negedge rst_n)begin
  •         if(rst_n==1'b0)begin
  •             count_sck <= 0;
  •         end
  •         else if(add_count_sck)begin
  •             if(end_count_sck)begin
  •                 count_sck <= 0;
  •             end
  •             else begin
  •                 count_sck <= count_sck + 1;
  •             end
  •         end
  •     end
  •     assign add_count_sck = flag_r || flag_w;
  •     assign end_count_sck = add_count_sck && count_sck == SIO_C-1;
  •     always  @(posedge clk or negedge rst_n)begin
  •         if(rst_n==1'b0)begin
  •             count_bit <= 0;
  •         end
  •         else if(add_count_bit)begin
  •             if(end_count_bit)begin
  •                 count_bit <= 0;
  •             end
  •             else begin
  •                 count_bit <= count_bit + 1;
  •             end
  •         end
  •     end
  •     assign add_count_bit = end_count_sck;
  •     assign end_count_bit = add_count_bit && count_bit == bit_num+2-1;
  •     always  @(posedge clk or negedge rst_n)begin
  •         if(rst_n==1'b0)begin
  •             rdata_vld <= 0;
  •         end
  •         else if(flag_r && end_count_duan)begin
  •             rdata_vld <= 1;
  •         end
  •         else begin
  •             rdata_vld <= 0;
  •         end
  •     end
  •     always  @(*)begin
  •         if(ren || wen || flag_r || flag_w)begin
  •             rdy = 0;
  •         end
  •         else begin
  •             rdy = 1;
  •         end
  •     end
  • endmodule

[color=rgb(51, 102, 153) !important]复制代码



1.6 图像采集模块设计1.6.1接口信号
  
信号名
  
I/O
位宽
定义
clk
I
1
工作时钟 25M
rst_n
I
1
系统复位信号,低电平有效
en_capture
I
1
摄像头配置完成指示信号,当其为1时,表示摄像头完成了配置。
vsync
I
1
摄像头帧同步信号,该信号拉高几个时钟周期,表示一帧图像传输的开始。
href
I
I
摄像头行同步信号,该信号为高电平时,摄像头输出的数据有效。
din
I
8
摄像头输出数据
dout
O
16
输出图像数据
dout_vld
O
1
输出图像数据有效指示信号
dout_sop
O
1
输出图像第一个有效数据指示信号
dout_eop
O
1
输出图像最后一个有效数据指示信号

1.6.2设计思路
下面时序图是从OV7670摄像头数据手册中得到的,可以看出来摄像头输出的数据跟随像素时钟时钟,一个时钟周期输出一个字节的数据,而且数据只在行同步信号href为高时有效,我们可以将行同步信号href当作是摄像头输出数据有效指示信号来使用。输出图像数据有效指示信号dout_vld:一个像素数据为2个字节,摄像头每个时钟输出一个字节,因此是输出两次有效一次。初始状态为0,表示数据无效,当行计数器cnt_x的第0位为1的时候,该信号变为1,表示输出图像数据有效。
最后一个有效数据指示信号dout_eop:当行计数器cnt_x等于1280-1,并且列计数器等于480-1的时候,表示输出最后一个有效数据,该信号为高,其他时候为低电平。
1.6.3参考代码
  •    always @ (posedge clk or negedge rst_n)begin
  •         if(!rst_n)begin
  •             cnt_x <= 0;
  •         end
  •         else if(add_cnt_x)begin
  •             if(end_cnt_x)begin
  •                 cnt_x <= 0;
  •             end
  •             else begin
  •                 cnt_x <= cnt_x + 1;
  •             end
  •         end
  •     end
  •     assign add_cnt_x = flag_capture && din_vld;
  •     assign end_cnt_x = add_cnt_x && cnt_x == COL*2-1;
  •     always @ (posedge clk or negedge rst_n)begin
  •         if(!rst_n)begin
  •             cnt_y <= 0;
  •         end
  •         else if(add_cnt_y)begin
  •             if(end_cnt_y)begin
  •                 cnt_y <= 0;
  •             end
  •             else begin
  •                 cnt_y <= cnt_y + 1;
  •             end
  •         end
  •     end
  •     assign add_cnt_y = end_cnt_x;
  •     assign end_cnt_y = add_cnt_y && cnt_y == ROW-1;
  •     always @ (posedge clk or negedge rst_n)begin
  •         if(!rst_n)begin
  •             dout <= 0;
  •         end
  •         else if(din_vld)begin
  •             dout <= {dout[7:0],din};
  •         end
  •     end
  •     assign din_vld = flag_capture && href;
  •     always @ (posedge clk or negedge rst_n)begin
  •         if(!rst_n)begin
  •             dout_vld <= 0;
  •         end
  •         else if(flag_dout_vld)begin
  •             dout_vld <= 1;
  •         end
  •         else begin
  •             dout_vld <= 0;
  •         end
  •     end
  •     assign flag_dout_vld = add_cnt_x && cnt_x[0] == 1;
  •     always @ (posedge clk or negedge rst_n)begin
  •         if(!rst_n)begin
  •             dout_sop <= 0;
  •         end
  •         else if(flag_dout_vld && cnt_x[10:1] == 0 && cnt_y == 0)begin
  •             dout_sop <= 1;
  •         end
  •         else begin
  •             dout_sop <= 0;
  •         end
  •     end
  •     always @ (posedge clk or negedge rst_n)begin
  •         if(!rst_n)begin
  •             dout_eop <= 0;
  •         end
  •         else if(flag_dout_vld && cnt_x[10:1] == COL-1 && cnt_y == ROW-1)begin
  •             dout_eop <= 1;
  •         end
  •         else begin
  •             dout_eop <= 0;
  •         end
  •     end

[color=rgb(51, 102, 153) !important]复制代码



1.7 存储控制模块设计
1.7.1接口信号
  
信号名
  
I/O
位宽
定义
clk
I
1
工作时钟 25M
rst_n
I
1
系统复位信号,低电平有效
clk_in
I
1
SDRAM时钟,100M
din
I
16
输入图像数据
din_vld
I
1
输入图像数据有效指示信号
din_sop
I
1
第一个有效图像数据指示信号
din_eop
I
1
最后一个有效图像数据指示信号
dout
O
16
输出图像数据
wr_req
O
1
写SDRAM请求信号
rd_req
O
1
读SDRAM请求信号
wdata
O
16
写SDRAM数据
wr_ack
I
1
写SDRAM响应
rd_ack
I
1
读SDRAM响应
sd_rdata
I
16
读SDRAM数据
sd_rdata_vld
I
1
读SDRAM数据有效指示信号
display_area
I
1
显示器显示区域指示信号
bank
O
2
SDRAM的Bank地址
addr
O
13
SDRAM的地址
1.7.2设计思路
本工程的主体时钟为25M,显示器的分辨率为640*480,相当于一个时钟周期显示一个像素。而摄像头的工作时钟也是25M,但是数据位宽为8bit,相当于两个时钟输出一个像素,如果直接将采集模块接收到的数据送给显示器显示,那么一个像素点会被显示两次,这肯定是不对的,因此需要先将摄像头输出的数据缓存起来,当存够一帧图像之后,再送给显示器进行显示,显示器本该1秒显示60帧图像的,降低到了30帧,但是显示的图像是正确而且连续的
FIFO的读使能:当进入到有效显示区域的时候,便将FIFO内部数据读出。

FIFO的写使能:当SDRAM输出有效数据的时候,写使能便拉高,将数据写入。

1.7.3参考代码
  • always  @(*)begin
  •             if(rd_wfifo_flag)
  •                 bank=waddr_bank;
  •             else
  •                 bank=raddr_bank;
  •     end
  •          always  @(*)begin
  •             if(rd_wfifo_flag)
  •                 addr=waddr;
  •             else
  •                 addr=raddr;
  •     end
  • fifo_16bwrite        fifo_16bwrite_inst (
  •         .aclr        ( ~rst_n        ),
  •         .data        (din             ),
  •         .rdclk       (clk_in          ),
  •         .rdreq       (wfifo_rdreq     ),
  •         .wrclk       (clk             ),
  •         .wrreq       (wfifo_wrreq     ),
  •         .q           (wdata           ),
  •         .rdempty     (wfifo_rdempty   ),
  •         .rdusedw     (wfifo_rdusedw   )
  •     always @(posedge clk_in or negedge rst_n)begin
  •         if(!rst_n)begin
  •             cnt_rd_wfifo <= 0;
  •         end
  •         else if(add_cnt_rd_wfifo)begin
  •             if(end_cnt_rd_wfifo)
  •                 cnt_rd_wfifo <= 0;
  •             else
  •                 cnt_rd_wfifo <= cnt_rd_wfifo + 1;
  •         end
  •     end
  •     assign add_cnt_rd_wfifo = rd_wfifo_flag&&((cnt_rd_wfifo==0&&wr_ack)||(cnt_rd_wfifo!=0));
  •     assign end_cnt_rd_wfifo = add_cnt_rd_wfifo && cnt_rd_wfifo== 512-1;
  •     always  @(*)begin
  •             if(add_cnt_rd_wfifo&&wfifo_rdempty==0)
  •                 wfifo_rdreq=1;
  •             else
  •                 wfifo_rdreq=0;
  •     end
  • assign add_cnt_bank = change_bank_instr;
  • assign end_cnt_bank = add_cnt_bank && cnt_bank==8-1 ;


[color=rgb(51, 102, 153) !important]复制代码



1.8 SDRAM接口模块设计
本模块的设计跟上一个案例《SDRAM读写控制器》基本一样,这里就不再做介绍,想要了解的可以去明德扬论坛搜素相关**即可。
【每周FPGA案例】SDRAM读写控制器

1.9 VGA接口模块设计
本模块的设计可以参考明德扬书籍《FPGA至简设计原理与应用》中关于VGA部分的案例,也可以在明德扬论坛中搜索书籍名称。
【FPGA至简设计原理与应用】书籍连载17 第三篇FPGA至简设计项目 第八章VGA显示颜色

1.10 效果和总结

使用特权

评论回复

相关帖子

沙发
zhangmangui| | 2020-11-10 23:29 | 只看该作者
这个我也设计过   

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

53

主题

61

帖子

2

粉丝