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接口信号 
|    信号名    |  |  |  |   |  |  |  |   |  |  |  |   |  |  | 摄像头配置完成指示信号,当其为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接口信号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 效果和总结 
 |