一、FPGA Cyclone Ⅳ OV5640图像实时采集系统设计

  • 1、系统框架
  • 2、摄像头配置模块
  • 3、图像数据拼接模块
  • 4、SDRAM操作模块
  • 5、乒乓缓存模块
  • 6、VGA驱动模块
  • 7、顶层模块
  • 8、参数定义
  • 9、最终效果
    • ①:分析综合
    • ②:上板验证

1、系统框架

2、摄像头配置模块

使用SCCB协议配置摄像头

/**************************************功能介绍***********************************
Copyright:
Date     :
Author   :厉长川
Version  :2022.10.10 v1
Description:摄像头配置模块
*********************************************************************************/`include "param.v"module sccb( input           clk         ,//系统时钟50MHzinput           rst_n       ,//复位信号output  reg     done        ,//配置完成标志output          cmos_rst_n  ,//摄像头复位信号output          cmos_pwdn   ,//摄像头掉电使能信号output    reg     cmos_scl    ,//时钟线inout         cmos_sda     //数据线
);          //参数定义           localparam  IDLE  = 3'd0    ,//初始化START = 3'd1    ,//起始D_ADD = 3'd2    ,//写入器件地址DC    = 3'd3    ,//响应(don't care)H_ADD = 3'd4    ,//写入寄存器地址高八位L_ADD = 3'd5    ,//写入寄存器地址低八位WR    = 3'd6    ,//写数据STOP  = 3'd7    ;//停止   //中间信号定义        wire            idle2start  ;//状态跳转条件    wire            start2d_add ;        wire            d_add2dc    ;    wire            dc2h_add    ;    wire            h_add2dc    ;wire            dc2l_add    ; wire            l_add2dc    ;   wire            dc2wr       ;wire            wr2dc       ;wire            dc2stop     ;    wire            stop2idle   ;    reg     [2:0]   state_c     ;//现态reg     [2:0]   state_n     ;//次态reg     [5:0]   cnt_1m      ;//50Mhz时钟做50分频产生1Mhz时钟        wire            add_cnt_1m  ;              wire            end_cnt_1m  ; reg             clk_1m      ;//1Mhz时钟             reg     [1:0]   cnt_250k    ;//1Mhz时钟做4分频产生250Khz时钟 reg     [3:0]   cnt_bit     ;//bit计数wire            add_cnt_bit ;    reg     [7:0]   num         ;//配置寄存器个数reg     [20:0]  cnt_ms      ;//20ms计数        wire            add_cnt_ms  ;              wire            end_cnt_ms  ; reg             en          ;//sccb使能reg     [31:0]  lut_data    ;//写入数据(分别是器件地址,寄存器地址和寄存器数据,各8bit)reg     [1:0]   flag_dc     ;//计数进入DC状态次数reg             sda         ;//sccb写数据寄存//cmos_sda:sccb写数据赋值assign cmos_sda = (state_c != DC)?sda:1'bz;//cnt_ms:20ms计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_ms <= 21'b0;end else if(add_cnt_ms)begin if(end_cnt_ms)begin cnt_ms <= 21'b0;endelse begin cnt_ms <= cnt_ms + 1'b1;end endend assign add_cnt_ms = cnt_ms != `CNT_MS;assign end_cnt_ms = add_cnt_ms && cnt_ms == `CNT_MS + 1'b1; //cmos_rst_n:摄像头复位信号assign cmos_rst_n = cnt_ms > `RST_CMOS;//cmos_pwdn:摄像头掉电使能信号assign cmos_pwdn = cnt_ms < `PWDN;//en:sccb使能always @(posedge clk or negedge rst_n)begin if(!rst_n)beginen <= 1'b0;end else if(cnt_ms == `CNT_MS - 1'b1)begin en <= 1'b1;end else if(num == `NUM_CFG)begin en <= 1'b0;end end           //cnt_1m:产生1Mhz时钟计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_1m <= 6'b0;end else if(add_cnt_1m)begin if(end_cnt_1m)begin cnt_1m <= 6'b0;endelse begin cnt_1m <= cnt_1m + 1'b1;end endend assign add_cnt_1m = (state_c != IDLE);assign end_cnt_1m = add_cnt_1m && cnt_1m == `CNT_1M - 1'b1;//clk_1m:1Mhz时钟always @(posedge clk or negedge rst_n)begin if(!rst_n)beginclk_1m <= 1'b1;end else if((cnt_1m == (`CNT_1M >> 1) - 1'b1) || end_cnt_1m)begin clk_1m <= ~clk_1m;end end//cnt_250k:产生250Khz时钟计数always @(posedge clk_1m or negedge rst_n)begin if(!rst_n)begincnt_250k <= 2'b0;end else begin cnt_250k <= cnt_250k + 1'b1;end end//cnt_bit:bit计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 4'b0;end else if(add_cnt_bit)begin cnt_bit <= cnt_bit + 1'b1;endelse if(state_c == DC)begincnt_bit <= 4'b0;endend assign add_cnt_bit = ((state_c == D_ADD) || (state_c == H_ADD) || (state_c == L_ADD) || (state_c == WR))&& (cnt_250k == 2'd3) && (cnt_1m == 1'b1);//flag_dc:计数进入DC状态次数always @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag_dc <= 2'b0;end else if((cnt_250k == 2'd2) && end_cnt_1m && (state_c == DC))begin flag_dc <= flag_dc + 1'b1;end end//状态机always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end endalways @(*)begin case (state_c)IDLE  : if(idle2start)beginstate_n = START;endelse beginstate_n = state_c;endSTART : if(start2d_add)beginstate_n = D_ADD;endelse beginstate_n = state_c;endD_ADD : if(d_add2dc)beginstate_n = DC;endelse beginstate_n = state_c;endDC    : if(dc2h_add)beginstate_n = H_ADD;endelse if(dc2l_add)beginstate_n = L_ADD;endelse if(dc2wr)beginstate_n = WR;endelse if(dc2stop)beginstate_n = STOP;endelse beginstate_n = state_c;endH_ADD : if(h_add2dc)beginstate_n = DC;endelse beginstate_n = state_c;endL_ADD : if(l_add2dc)beginstate_n = DC;endelse beginstate_n = state_c;endWR    : if(wr2dc)beginstate_n = DC;endelse beginstate_n = state_c;endSTOP  : if(stop2idle)beginstate_n = IDLE;endelse beginstate_n = state_c;enddefault: state_n = state_c;endcaseend//给定状态跳转条件assign    idle2start     =   (state_c == IDLE ) && en ;assign    start2d_add    =   (state_c == START) && (cnt_250k == 2'd2) && end_cnt_1m ;assign    d_add2dc       =   (state_c == D_ADD) && (cnt_250k == 2'd2) && end_cnt_1m && (cnt_bit == 4'd8) ;assign    dc2h_add       =   (state_c == DC   ) && (cnt_250k == 2'd2) && end_cnt_1m && (flag_dc == 1'b0) ;assign    h_add2dc       =   (state_c == H_ADD) && (cnt_250k == 2'd2) && end_cnt_1m && (cnt_bit == 4'd8) ;assign    dc2l_add       =   (state_c == DC   ) && (cnt_250k == 2'd2) && end_cnt_1m && (flag_dc == 1'b1) ; assign    l_add2dc       =   (state_c == L_ADD) && (cnt_250k == 2'd2) && end_cnt_1m && (cnt_bit == 4'd8) ; assign    dc2wr          =   (state_c == DC   ) && (cnt_250k == 2'd2) && end_cnt_1m && (flag_dc == 2'd2) ;assign    wr2dc          =   (state_c == WR   ) && (cnt_250k == 2'd2) && end_cnt_1m && (cnt_bit == 4'd8) ;assign    dc2stop        =   (state_c == DC   ) && (cnt_250k == 2'd2) && end_cnt_1m && (flag_dc == 2'd3) ;assign    stop2idle      =   (state_c == STOP ) && (cnt_250k == 2'd2) && end_cnt_1m ;//cmos_scl:时钟总线always @(posedge clk or negedge rst_n)begin if(!rst_n)begincmos_scl <= 1'b1;end else if((state_c == STOP))beginif((cnt_250k == 2'd3) && end_cnt_1m)begincmos_scl <= 1'b1;endendelse if(state_c != IDLE)begin if((cnt_250k == 1'b1) && end_cnt_1m)begincmos_scl <= 1'b0;endelse if((cnt_250k == 2'd3) && end_cnt_1m)begincmos_scl <= 1'b1;endend else begin cmos_scl <= 1'b1;end end//sda:数据总线always @(posedge clk or negedge rst_n)begin if(!rst_n)beginsda <= 1'b1;end else begin case (state_c)START:if((cnt_250k == 1'b0) && end_cnt_1m)beginsda <= 1'b0;endD_ADD:if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= lut_data[32 - cnt_bit];endDC   :if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= 1'b0;endH_ADD:if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= lut_data[24 - cnt_bit];endL_ADD:if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= lut_data[16 - cnt_bit];endWR   :if((cnt_250k == 2'd3) && (cnt_1m == 2'd2))beginsda <= lut_data[8 - cnt_bit];endSTOP :if((cnt_250k == 1'b0) && end_cnt_1m)beginsda <= 1'b1;enddefault: sda <= 1'b1;endcaseend end//num:配置寄存器个数计数always @(posedge clk or negedge rst_n)begin if(!rst_n)beginnum <= 1'b0;end else if(dc2stop)begin num <= num + 1'b1;end end//done:配置完成标志always @(posedge clk or negedge rst_n)begin if(!rst_n)begindone <= 1'b0;end else if((num == `NUM_CFG) && stop2idle)begin done <= 1'b1;end end//lut_data:数据always@(*)begincase(num)            8'd0  : lut_data <= {8'h78,16'h3008,8'h82}; //Bit[7]:复位 Bit[6]:电源休眠8'd1  : lut_data <= {8'h78,16'h3008,8'h02}; //正常工作模式8'd2  : lut_data <= {8'h78,16'h3103,8'h02}; //Bit[1]:1 PLL Clock//引脚输入/输出控制 FREX/VSYNC/HREF/PCLK/D[9:6]8'd3  : lut_data <= {8'h78,8'h30,8'h17,8'hff};//引脚输入/输出控制 D[5:0]/GPIO1/GPIO0 8'd4  : lut_data <= {8'h78,16'h3018,8'hff};8'd5  : lut_data <= {8'h78,16'h3037,8'h13}; //PLL分频控制8'd6  : lut_data <= {8'h78,16'h3108,8'h01}; //系统根分频器8'd7  : lut_data <= {8'h78,16'h3630,8'h36};8'd8  : lut_data <= {8'h78,16'h3631,8'h0e};8'd9  : lut_data <= {8'h78,16'h3632,8'he2};8'd10 : lut_data <= {8'h78,16'h3633,8'h12};8'd11 : lut_data <= {8'h78,16'h3621,8'he0};8'd12 : lut_data <= {8'h78,16'h3704,8'ha0};8'd13 : lut_data <= {8'h78,16'h3703,8'h5a};8'd14 : lut_data <= {8'h78,16'h3715,8'h78};8'd15 : lut_data <= {8'h78,16'h3717,8'h01};8'd16 : lut_data <= {8'h78,16'h370b,8'h60};8'd17 : lut_data <= {8'h78,16'h3705,8'h1a};8'd18 : lut_data <= {8'h78,16'h3905,8'h02};8'd19 : lut_data <= {8'h78,16'h3906,8'h10};8'd20 : lut_data <= {8'h78,16'h3901,8'h0a};8'd21 : lut_data <= {8'h78,16'h3731,8'h12};8'd22 : lut_data <= {8'h78,16'h3600,8'h08}; //VCM控制,用于自动聚焦8'd23 : lut_data <= {8'h78,16'h3601,8'h33}; //VCM控制,用于自动聚焦8'd24 : lut_data <= {8'h78,16'h302d,8'h60}; //系统控制8'd25 : lut_data <= {8'h78,16'h3620,8'h52};8'd26 : lut_data <= {8'h78,16'h371b,8'h20};8'd27 : lut_data <= {8'h78,16'h471c,8'h50};8'd28 : lut_data <= {8'h78,16'h3a13,8'h43}; //AEC(自动曝光控制)8'd29 : lut_data <= {8'h78,16'h3a18,8'h00}; //AEC 增益上限8'd30 : lut_data <= {8'h78,16'h3a19,8'hf8}; //AEC 增益上限8'd31 : lut_data <= {8'h78,16'h3635,8'h13};8'd32 : lut_data <= {8'h78,16'h3636,8'h03};8'd33 : lut_data <= {8'h78,16'h3634,8'h40};8'd34 : lut_data <= {8'h78,16'h3622,8'h01};8'd35 : lut_data <= {8'h78,16'h3c01,8'h34};8'd36 : lut_data <= {8'h78,16'h3c04,8'h28};8'd37 : lut_data <= {8'h78,16'h3c05,8'h98};8'd38 : lut_data <= {8'h78,16'h3c06,8'h00}; //light meter 1 阈值[15:8]8'd39 : lut_data <= {8'h78,16'h3c07,8'h08}; //light meter 1 阈值[7:0]8'd40 : lut_data <= {8'h78,16'h3c08,8'h00}; //light meter 2 阈值[15:8]8'd41 : lut_data <= {8'h78,16'h3c09,8'h1c}; //light meter 2 阈值[7:0]8'd42 : lut_data <= {8'h78,16'h3c0a,8'h9c}; //sample number[15:8]8'd43 : lut_data <= {8'h78,16'h3c0b,8'h40}; //sample number[7:0]8'd44 : lut_data <= {8'h78,16'h3810,8'h00}; //Timing Hoffset[11:8]8'd45 : lut_data <= {8'h78,16'h3811,8'h10}; //Timing Hoffset[7:0]8'd46 : lut_data <= {8'h78,16'h3812,8'h00}; //Timing Voffset[10:8]8'd47 : lut_data <= {8'h78,16'h3708,8'h64};8'd48 : lut_data <= {8'h78,16'h4001,8'h02}; //BLC(黑电平校准)补偿起始行号8'd49 : lut_data <= {8'h78,16'h4005,8'h1a}; //BLC(黑电平校准)补偿始终更新8'd50 : lut_data <= {8'h78,16'h3000,8'h00}; //系统块复位控制8'd51 : lut_data <= {8'h78,16'h3004,8'hff}; //时钟使能控制8'd52 : lut_data <= {8'h78,16'h4300,8'h61}; //格式控制 RGB5658'd53 : lut_data <= {8'h78,16'h501f,8'h01}; //ISP RGB8'd54 : lut_data <= {8'h78,16'h440e,8'h00};8'd55 : lut_data <= {8'h78,16'h5000,8'ha7}; //ISP控制8'd56 : lut_data <= {8'h78,16'h3a0f,8'h30}; //AEC控制;stable range in high8'd57 : lut_data <= {8'h78,16'h3a10,8'h28}; //AEC控制;stable range in low8'd58 : lut_data <= {8'h78,16'h3a1b,8'h30}; //AEC控制;stable range out high8'd59 : lut_data <= {8'h78,16'h3a1e,8'h26}; //AEC控制;stable range out low8'd60 : lut_data <= {8'h78,16'h3a11,8'h60}; //AEC控制; fast zone high8'd61 : lut_data <= {8'h78,16'h3a1f,8'h14}; //AEC控制; fast zone low//LENC(镜头校正)控制 16'h5800~16'h583d8'd62 : lut_data <= {8'h78,16'h5800,8'h23}; 8'd63 : lut_data <= {8'h78,16'h5801,8'h14};8'd64 : lut_data <= {8'h78,16'h5802,8'h0f};8'd65 : lut_data <= {8'h78,16'h5803,8'h0f};8'd66 : lut_data <= {8'h78,16'h5804,8'h12};8'd67 : lut_data <= {8'h78,16'h5805,8'h26};8'd68 : lut_data <= {8'h78,16'h5806,8'h0c};8'd69 : lut_data <= {8'h78,16'h5807,8'h08};8'd70 : lut_data <= {8'h78,16'h5808,8'h05};8'd71 : lut_data <= {8'h78,16'h5809,8'h05};8'd72 : lut_data <= {8'h78,16'h580a,8'h08};8'd73 : lut_data <= {8'h78,16'h580b,8'h0d};8'd74 : lut_data <= {8'h78,16'h580c,8'h08};8'd75 : lut_data <= {8'h78,16'h580d,8'h03};8'd76 : lut_data <= {8'h78,16'h580e,8'h00};8'd77 : lut_data <= {8'h78,16'h580f,8'h00};8'd78 : lut_data <= {8'h78,16'h5810,8'h03};8'd79 : lut_data <= {8'h78,16'h5811,8'h09};8'd80 : lut_data <= {8'h78,16'h5812,8'h07};8'd81 : lut_data <= {8'h78,16'h5813,8'h03};8'd82 : lut_data <= {8'h78,16'h5814,8'h00};8'd83 : lut_data <= {8'h78,16'h5815,8'h01};8'd84 : lut_data <= {8'h78,16'h5816,8'h03};8'd85 : lut_data <= {8'h78,16'h5817,8'h08};8'd86 : lut_data <= {8'h78,16'h5818,8'h0d};8'd87 : lut_data <= {8'h78,16'h5819,8'h08};8'd88 : lut_data <= {8'h78,16'h581a,8'h05};8'd89 : lut_data <= {8'h78,16'h581b,8'h06};8'd90 : lut_data <= {8'h78,16'h581c,8'h08};8'd91 : lut_data <= {8'h78,16'h581d,8'h0e};8'd92 : lut_data <= {8'h78,16'h581e,8'h29};8'd93 : lut_data <= {8'h78,16'h581f,8'h17};8'd94 : lut_data <= {8'h78,16'h5820,8'h11};8'd95 : lut_data <= {8'h78,16'h5821,8'h11};8'd96 : lut_data <= {8'h78,16'h5822,8'h15};8'd97 : lut_data <= {8'h78,16'h5823,8'h28};8'd98 : lut_data <= {8'h78,16'h5824,8'h46};8'd99 : lut_data <= {8'h78,16'h5825,8'h26};8'd100: lut_data <= {8'h78,16'h5826,8'h08};8'd101: lut_data <= {8'h78,16'h5827,8'h26};8'd102: lut_data <= {8'h78,16'h5828,8'h64};8'd103: lut_data <= {8'h78,16'h5829,8'h26};8'd104: lut_data <= {8'h78,16'h582a,8'h24};8'd105: lut_data <= {8'h78,16'h582b,8'h22};8'd106: lut_data <= {8'h78,16'h582c,8'h24};8'd107: lut_data <= {8'h78,16'h582d,8'h24};8'd108: lut_data <= {8'h78,16'h582e,8'h06};8'd109: lut_data <= {8'h78,16'h582f,8'h22};8'd110: lut_data <= {8'h78,16'h5830,8'h40};8'd111: lut_data <= {8'h78,16'h5831,8'h42};8'd112: lut_data <= {8'h78,16'h5832,8'h24};8'd113: lut_data <= {8'h78,16'h5833,8'h26};8'd114: lut_data <= {8'h78,16'h5834,8'h24};8'd115: lut_data <= {8'h78,16'h5835,8'h22};8'd116: lut_data <= {8'h78,16'h5836,8'h22};8'd117: lut_data <= {8'h78,16'h5837,8'h26};8'd118: lut_data <= {8'h78,16'h5838,8'h44};8'd119: lut_data <= {8'h78,16'h5839,8'h24};8'd120: lut_data <= {8'h78,16'h583a,8'h26};8'd121: lut_data <= {8'h78,16'h583b,8'h28};8'd122: lut_data <= {8'h78,16'h583c,8'h42};8'd123: lut_data <= {8'h78,16'h583d,8'hce};//AWB(自动白平衡控制) 16'h5180~16'h519e8'd124: lut_data <= {8'h78,16'h5180,8'hff};8'd125: lut_data <= {8'h78,16'h5181,8'hf2};8'd126: lut_data <= {8'h78,16'h5182,8'h00};8'd127: lut_data <= {8'h78,16'h5183,8'h14};8'd128: lut_data <= {8'h78,16'h5184,8'h25};8'd129: lut_data <= {8'h78,16'h5185,8'h24};8'd130: lut_data <= {8'h78,16'h5186,8'h09};8'd131: lut_data <= {8'h78,16'h5187,8'h09};8'd132: lut_data <= {8'h78,16'h5188,8'h09};8'd133: lut_data <= {8'h78,16'h5189,8'h75};8'd134: lut_data <= {8'h78,16'h518a,8'h54};8'd135: lut_data <= {8'h78,16'h518b,8'he0};8'd136: lut_data <= {8'h78,16'h518c,8'hb2};8'd137: lut_data <= {8'h78,16'h518d,8'h42};8'd138: lut_data <= {8'h78,16'h518e,8'h3d};8'd139: lut_data <= {8'h78,16'h518f,8'h56};8'd140: lut_data <= {8'h78,16'h5190,8'h46};8'd141: lut_data <= {8'h78,16'h5191,8'hf8};8'd142: lut_data <= {8'h78,16'h5192,8'h04};8'd143: lut_data <= {8'h78,16'h5193,8'h70};8'd144: lut_data <= {8'h78,16'h5194,8'hf0};8'd145: lut_data <= {8'h78,16'h5195,8'hf0};8'd146: lut_data <= {8'h78,16'h5196,8'h03};8'd147: lut_data <= {8'h78,16'h5197,8'h01};8'd148: lut_data <= {8'h78,16'h5198,8'h04};8'd149: lut_data <= {8'h78,16'h5199,8'h12};8'd150: lut_data <= {8'h78,16'h519a,8'h04};8'd151: lut_data <= {8'h78,16'h519b,8'h00};8'd152: lut_data <= {8'h78,16'h519c,8'h06};8'd153: lut_data <= {8'h78,16'h519d,8'h82};8'd154: lut_data <= {8'h78,16'h519e,8'h38};//Gamma(伽马)控制 16'h5480~16'h54908'd155: lut_data <= {8'h78,16'h5480,8'h01}; 8'd156: lut_data <= {8'h78,16'h5481,8'h08};8'd157: lut_data <= {8'h78,16'h5482,8'h14};8'd158: lut_data <= {8'h78,16'h5483,8'h28};8'd159: lut_data <= {8'h78,16'h5484,8'h51};8'd160: lut_data <= {8'h78,16'h5485,8'h65};8'd161: lut_data <= {8'h78,16'h5486,8'h71};8'd162: lut_data <= {8'h78,16'h5487,8'h7d};8'd163: lut_data <= {8'h78,16'h5488,8'h87};8'd164: lut_data <= {8'h78,16'h5489,8'h91};8'd165: lut_data <= {8'h78,16'h548a,8'h9a};8'd166: lut_data <= {8'h78,16'h548b,8'haa};8'd167: lut_data <= {8'h78,16'h548c,8'hb8};8'd168: lut_data <= {8'h78,16'h548d,8'hcd};8'd169: lut_data <= {8'h78,16'h548e,8'hdd};8'd170: lut_data <= {8'h78,16'h548f,8'hea};8'd171: lut_data <= {8'h78,16'h5490,8'h1d};//CMX(彩色矩阵控制) 16'h5381~16'h538b8'd172: lut_data <= {8'h78,16'h5381,8'h1e};8'd173: lut_data <= {8'h78,16'h5382,8'h5b};8'd174: lut_data <= {8'h78,16'h5383,8'h08};8'd175: lut_data <= {8'h78,16'h5384,8'h0a};8'd176: lut_data <= {8'h78,16'h5385,8'h7e};8'd177: lut_data <= {8'h78,16'h5386,8'h88};8'd178: lut_data <= {8'h78,16'h5387,8'h7c};8'd179: lut_data <= {8'h78,16'h5388,8'h6c};8'd180: lut_data <= {8'h78,16'h5389,8'h10};8'd181: lut_data <= {8'h78,16'h538a,8'h01};8'd182: lut_data <= {8'h78,16'h538b,8'h98};//SDE(特殊数码效果)控制 16'h5580~16'h558b8'd183: lut_data <= {8'h78,16'h5580,8'h06};8'd184: lut_data <= {8'h78,16'h5583,8'h40};8'd185: lut_data <= {8'h78,16'h5584,8'h10};8'd186: lut_data <= {8'h78,16'h5589,8'h10};8'd187: lut_data <= {8'h78,16'h558a,8'h00};8'd188: lut_data <= {8'h78,16'h558b,8'hf8};8'd189: lut_data <= {8'h78,16'h501d,8'h40}; //ISP MISC//CIP(颜色插值)控制 (16'h5300~16'h530c)8'd190: lut_data <= {8'h78,16'h5300,8'h08};8'd191: lut_data <= {8'h78,16'h5301,8'h30};8'd192: lut_data <= {8'h78,16'h5302,8'h10};8'd193: lut_data <= {8'h78,16'h5303,8'h00};8'd194: lut_data <= {8'h78,16'h5304,8'h08};8'd195: lut_data <= {8'h78,16'h5305,8'h30};8'd196: lut_data <= {8'h78,16'h5306,8'h08};8'd197: lut_data <= {8'h78,16'h5307,8'h16};8'd198: lut_data <= {8'h78,16'h5309,8'h08};8'd199: lut_data <= {8'h78,16'h530a,8'h30};8'd200: lut_data <= {8'h78,16'h530b,8'h04};8'd201: lut_data <= {8'h78,16'h530c,8'h06};8'd202: lut_data <= {8'h78,16'h5025,8'h00};//系统时钟分频 Bit[7:4]:系统时钟分频 input clock =24Mhz, PCLK = 48Mhz8'd203: lut_data <= {8'h78,16'h3035,8'h11}; 8'd204: lut_data <= {8'h78,16'h3036,8'h3c}; //PLL倍频8'd205: lut_data <= {8'h78,16'h3c07,8'h08};//时序控制 16'h3800~16'h38218'd206: lut_data <= {8'h78,16'h3820,8'h46};8'd207: lut_data <= {8'h78,16'h3821,8'h01};8'd208: lut_data <= {8'h78,16'h3814,8'h31};8'd209: lut_data <= {8'h78,16'h3815,8'h31};8'd210: lut_data <= {8'h78,16'h3800,8'h00};8'd211: lut_data <= {8'h78,16'h3801,8'h00};8'd212: lut_data <= {8'h78,16'h3802,8'h00};8'd213: lut_data <= {8'h78,16'h3803,8'h04};8'd214: lut_data <= {8'h78,16'h3804,8'h0a};8'd215: lut_data <= {8'h78,16'h3805,8'h3f};8'd216: lut_data <= {8'h78,16'h3806,8'h07};8'd217: lut_data <= {8'h78,16'h3807,8'h9b};//设置输出像素个数//DVP 输出水平像素点数高4位8'd218: lut_data <= {8'h78,16'h3808,8'h04};//DVP 输出水平像素点数低8位8'd219: lut_data <= {8'h78,16'h3809,8'h00};//DVP 输出垂直像素点数高3位8'd220: lut_data <= {8'h78,16'h380a,8'h03};//DVP 输出垂直像素点数低8位8'd221: lut_data <= {8'h78,16'h380b,8'h00};//水平总像素大小高5位8'd222: lut_data <= {8'h78,16'h380c,8'h08};//水平总像素大小低8位 8'd223: lut_data <= {8'h78,16'h380d,8'hc0};//垂直总像素大小高5位 8'd224: lut_data <= {8'h78,16'h380e,8'h04};//垂直总像素大小低8位     8'd225: lut_data <= {8'h78,16'h380f,8'hf8};8'd226: lut_data <= {8'h78,16'h3813,8'h06};8'd227: lut_data <= {8'h78,16'h3618,8'h00};8'd228: lut_data <= {8'h78,16'h3612,8'h29};8'd229: lut_data <= {8'h78,16'h3709,8'h52};8'd230: lut_data <= {8'h78,16'h370c,8'h03};8'd231: lut_data <= {8'h78,16'h3a02,8'h17}; //60Hz max exposure8'd232: lut_data <= {8'h78,16'h3a03,8'h10}; //60Hz max exposure8'd233: lut_data <= {8'h78,16'h3a14,8'h17}; //50Hz max exposure8'd234: lut_data <= {8'h78,16'h3a15,8'h10}; //50Hz max exposure8'd235: lut_data <= {8'h78,16'h4004,8'h02}; //BLC(背光) 2 lines8'd236: lut_data <= {8'h78,16'h4713,8'h03}; //JPEG mode 38'd237: lut_data <= {8'h78,16'h4407,8'h04}; //量化标度8'd238: lut_data <= {8'h78,16'h460c,8'h22};     8'd239: lut_data <= {8'h78,16'h4837,8'h22}; //DVP CLK divider8'd240: lut_data <= {8'h78,16'h3824,8'h02}; //DVP CLK divider8'd241: lut_data <= {8'h78,16'h5001,8'ha3}; //ISP 控制8'd242: lut_data <= {8'h78,16'h3b07,8'h0a}; //帧曝光模式  //彩条测试使能 8'd243: lut_data <= {8'h78,16'h503d,8'h00}; //8'h00:正常模式 8'h80:彩条显示//测试闪光灯功能8'd244: lut_data <= {8'h78,16'h3016,8'h02};8'd245: lut_data <= {8'h78,16'h301c,8'h02};8'd246: lut_data <= {8'h78,16'h3019,8'h02}; //打开闪光灯8'd247: lut_data <= {8'h78,16'h3019,8'h00}; //关闭闪光灯//只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写default : lut_data <= {8'h78,16'h300a,8'h00}; //器件ID高8位endcaseendendmodule

3、图像数据拼接模块

将摄像头采集的高八位和低八位图像数据进行拼接

/**************************************功能介绍***********************************
Copyright:
Date     :
Author   :厉长川
Version  :2022.10.10 v1
Description:图像数据采集模块
*********************************************************************************/`include "param.v"module pixel_sampling( input             clk           ,//像素采集工作时钟,pclk   input              rst_n         ,//复位信号   input       [7:0]   din           ,//摄像头采集像素input               vsync         ,//场同步信号input               href          ,//行有效信号output  reg         dout_valid    ,//输出数据有效标志output reg [15:0]  dout           //输出拼接完成的像素
);                                                  //中间信号定义         reg            [7:0]   din_r         ;//像素缓存reg         [1:0]   v_r           ;//场同步信号同步打拍,检测上升沿reg                 flag          ;//像素拼接标志,高电平拼接,低电平缓存reg                 pixel_valid   ;//舍弃10帧完成reg          [3:0]   cnt_frame     ;//像素帧计数wire              add_cnt_frame ;wire             end_cnt_frame ;//v_r:场同步信号同步打拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginv_r <= 2'b0;end else begin v_r <= {v_r[0], vsync};end end//cnt_frame:像素帧计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_frame <= 4'b0;end else if(add_cnt_frame)begin if(end_cnt_frame)begin cnt_frame <= 4'b0;endelse begin cnt_frame <= cnt_frame + 1'b1;end endend assign add_cnt_frame = (v_r[0] & ~v_r[1]) && (cnt_frame <= `PIXEL);assign end_cnt_frame = add_cnt_frame && cnt_frame == `PIXEL + 1'b1;//pixel_valid:舍弃10帧完成always @(posedge clk or negedge rst_n)begin if(!rst_n)beginpixel_valid <= 1'b0;end else if(cnt_frame == `PIXEL)begin pixel_valid <= 1'b1;end end//flag:像素拼接标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag <= 1'b0;end else if(href && pixel_valid)begin flag <= ~flag;end else beginflag <= 1'b0;endend//din_r:像素缓存always @(posedge clk or negedge rst_n)begin if(!rst_n)begindin_r <= 8'b0;end else if(href && pixel_valid)begin din_r <= din;end end//dout:像素拼接always @(posedge clk or negedge rst_n)begin if(!rst_n)begindout <= 16'b0;end else if(href && pixel_valid && flag)begin dout <= {din_r, din};end end//dout_valid:输出数据有效标志always @(posedge clk or negedge rst_n)begin if(!rst_n)begindout_valid <= 1'b0;end else if(href && pixel_valid)begin dout_valid <= flag;end else begindout_valid <= 1'b0;endendendmodule

4、SDRAM操作模块

SDRAM初始化、自刷新、读和写操作使用一个状态机完成

/**************************************功能介绍***********************************
Copyright:
Date     :
Author   :厉长川
Version  :2022.10.10 v1
Description:SDRAM模块
*********************************************************************************/`include    "param.v"module sdram( input               clk         ,//100Mhzinput              rst_n       ,//复位,低电平input              w_req       ,//写请求input             r_req       ,//读请求input     [23:0]  w_addr      ,//写地址input     [23:0]  r_addr      ,//读地址input     [15:0]  w_data      ,//写数据output      [15:0]  r_data      ,//读数据output reg  [12:0]  sdram_addr  ,//地址总线output reg  [1:0]   sdram_ba    ,//bank选择inout       [15:0]  sdram_dq    ,//数据总线output reg  [3:0]   cmd         ,//命令output              r_ack       ,//写操作响应output              wr_ack      ,//读操作响应output reg          init_done   ,//初始化结束output              w_done      ,//写操作完成标志output              r_done       //读操作完成标志);                               //参数定义parameter   IDLE      =   4'd0  ,//初始化PRE       =   4'd1  ,//预充电状态AREF      =   4'd2  ,//自动刷新状态REGIST    =   4'd3  ,//模式寄存器配置W_ACT     =   4'd4  ,//写行激活R_ACT     =   4'd5  ,//读行激活WRITE     =   4'd6  ,//写状态READ      =   4'd7  ,//读状态BURST     =   4'd8  ;//突发停止//状态跳转条件wire                idle2pre    ;wire                pre2aref    ;wire                aref2regist ;wire                regist2idle ;wire                aref2idle   ;wire                idle2w_act  ;wire                idle2r_act  ;wire                w_act2write ;wire                write2burst ;wire                r_act2read  ;wire                read2burst  ;wire                burst2pre   ;wire                pre2idle    ;//中间信号reg         [3:0]   state_c     ;//现态reg         [3:0]   state_n     ;//次态reg                 waite_done  ;//200us上电等待结束reg         [1:0]   atref_time  ;//自动刷新次数     reg         [13:0]  cnt_init    ;//上电初始化计数wire                add_cnt_init;wire                end_cnt_init;reg         [9:0]   cnt_aref    ;//自动刷新计数wire                add_cnt_aref;wire                end_cnt_aref;reg         [1:0]   cnt_4clk    ;//四周期时钟计数器wire                add_cnt_4clk;reg         [2:0]   cnt_7clk    ;//7周期时钟计数器wire                add_cnt_7clk;reg         [9:0]   cnt_bit     ;//读写计数wire                add_cnt_bit ;wire                end_cnt_bit ;wire                rd_ack      ;//读响应赋值reg         [2:0]   r_ack_r     ;//读响应赋值打四拍reg                 wr          ;//写操作标志reg                 rd          ;//读操作标志reg                 aref_req    ;//自动刷新请求reg                 ack_r1      ;//写响应打拍reg                 ack_r2      ;//读响应打拍reg         [15:0]  dq_r        ;//sdram读数据打拍reg                 w_ack       ;//写响应打拍reg                 w_en        ;//写使能reg                 r_en        ;//读使能// w_en:写使能always @(posedge clk or negedge rst_n)begin if(!rst_n)beginw_en <= 1'b0;end else if(w_req)begin w_en <= 1'b1;end else if(wr && pre2idle)begin w_en <= 1'b0;end end// r_en:读使能always @(posedge clk or negedge rst_n)begin if(!rst_n)beginr_en <= 1'b0;end else if(r_req)begin r_en <= 1'b1;end else if(rd && pre2idle)begin r_en <= 1'b0;end end// dq_r:sdram读数据打拍always @(posedge clk or negedge rst_n)begin if(!rst_n)begindq_r <= 16'b0;end else begin dq_r <= sdram_dq;end end// cnt_init:上电等待200us计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_init <= 14'b0;end else if(add_cnt_init)begin if(end_cnt_init)begin cnt_init <= 14'b0;endelse begin cnt_init <= cnt_init + 1'b1;end endend assign add_cnt_init = cnt_init <= `INIT_TIME;assign end_cnt_init = add_cnt_init && cnt_init == `INIT_TIME + 1'b1; // waite_done:上电等待200us结束标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwaite_done <= 1'b0;end else if(cnt_init == `INIT_TIME - 1'b1)begin waite_done <= 1'b1;end else begin waite_done <= 1'b0;end end// cnt_aref:自动刷新7us计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_aref <= 10'b0;end else if(add_cnt_aref)begin if(end_cnt_aref)begin cnt_aref <= 10'b0;endelse begin cnt_aref <= cnt_aref + 1'b1;end endend assign add_cnt_aref = init_done;assign end_cnt_aref = add_cnt_aref && cnt_aref == `AREF_TIME - 1'b1;// cnt_4clk:四周期时钟计数器always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_4clk <= 2'b0;end else if(add_cnt_4clk)begin cnt_4clk <= cnt_4clk + 1'b1;endend assign add_cnt_4clk = (state_c == PRE) || (state_c == REGIST) || (state_c == W_ACT)|| (state_c == R_ACT) || (state_c == BURST);// cnt_7clk:七周期时钟计数器always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_7clk <= 3'b0;end else if(add_cnt_7clk)begin cnt_7clk <= cnt_7clk + 1'b1;endend assign add_cnt_7clk = (state_c == AREF);// atref_time:自动刷新次数always @(posedge clk or negedge rst_n)begin if(!rst_n)beginatref_time <= 2'b0;end else if(cnt_7clk == 3'd7)begin atref_time <= atref_time + 1'b1;end end// init_done:SDRAM初始化结束always @(posedge clk or negedge rst_n)begin if(!rst_n)begininit_done <= 1'b0;end else if(regist2idle)begin init_done <= 1'b1;end end// cnt_bit:读写计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 10'b0;end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit <= 10'b0;endelse begin cnt_bit <= cnt_bit + 1'b1;end endend assign add_cnt_bit = (state_c == WRITE) || (state_c == READ);assign end_cnt_bit = add_cnt_bit && (((state_c == WRITE) && (cnt_bit == `BURST_LEN - 1'b1)) || ((state_c == READ) && (cnt_bit == `BURST_LEN - 1'b1)));// 写操作标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwr <= 1'b0;end else if(write2burst)begin wr <= 1'b1;end else if(pre2idle)begin wr <= 1'b0;end end// 读操作标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrd <= 1'b0;end else if(read2burst)begin rd <= 1'b1;end else if(pre2idle)begin rd <= 1'b0;end end// aref_req:自动刷新请求always @(posedge clk or negedge rst_n)begin if(!rst_n)beginaref_req <= 1'b0;end else if(end_cnt_aref)begin aref_req <= 1'b1;end else if(aref2idle)begin aref_req <= 1'b0;end end// 状态转移always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end end// 判断状态转移条件always @(*)begin case(state_c)IDLE    :  if(idle2pre)beginstate_n = PRE;endelse if(idle2w_act)beginstate_n = W_ACT;endelse if(idle2r_act)beginstate_n = R_ACT;endelse beginstate_n = state_c;endPRE     :    if(pre2idle)beginstate_n = IDLE;endelse if(pre2aref)beginstate_n = AREF;endelse beginstate_n = state_c;endAREF    :  if(aref2idle)beginstate_n = IDLE;endelse if(aref2regist)beginstate_n = REGIST;endelse beginstate_n = state_c;endREGIST  :    if(regist2idle)beginstate_n = IDLE;endelse beginstate_n = state_c;endW_ACT   :    if(w_act2write)beginstate_n = WRITE;endelse beginstate_n = state_c;endR_ACT   :   if(r_act2read)beginstate_n = READ;endelse beginstate_n = state_c;endWRITE   : if(write2burst)beginstate_n = BURST;endelse beginstate_n = state_c;endREAD    :   if(read2burst)beginstate_n = BURST;endelse beginstate_n = state_c;endBURST   :    if(burst2pre)beginstate_n = PRE;endelse beginstate_n = state_c;enddefault:    state_n = state_c;endcaseend// 状态转移条件赋值assign    idle2pre    =   (state_c == IDLE  ) && (waite_done || aref_req) ;//仲裁,进入自动刷新条件assign    pre2aref    =   (state_c == PRE   ) && (cnt_4clk == 2'd3) ;assign    aref2regist =   (state_c == AREF  ) && (cnt_7clk == 3'd7) && (atref_time == 2'd3) ;assign    regist2idle =   (state_c == REGIST) && (cnt_4clk == 2'd3) ;assign    aref2idle   =   (state_c == AREF  ) && (cnt_7clk == 3'd7) && (atref_time == 2'd3) && init_done ;assign    idle2w_act  =   (state_c == IDLE  ) && !aref_req && w_en && init_done ;//仲裁,进入写操作条件assign    idle2r_act  =   (state_c == IDLE  ) && !aref_req && r_en && init_done ;//仲裁,进入读操作条件assign    w_act2write =   (state_c == W_ACT ) && (cnt_4clk == 2'd3) ;assign    write2burst =   (state_c == WRITE ) && end_cnt_bit ;assign    r_act2read  =   (state_c == R_ACT ) && (cnt_4clk == 2'd3) ;assign    read2burst  =   (state_c == READ  ) && end_cnt_bit ;assign    burst2pre   =   (state_c == BURST ) && (cnt_4clk == 2'd3) ;assign    pre2idle    =   (state_c == PRE   ) && (cnt_4clk == 2'd3) && (wr || rd) ;always @(*)begin if(!rst_n)begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;end else begin case (state_c)PRE     :   if(cnt_4clk == 1'b0)begincmd = `CMD_PRE;sdram_addr = 13'b001_0_00_000_0_000;//选中所有bank进行预充电sdram_ba = 2'b00;endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endAREF    :   if(cnt_7clk == 1'b0)begincmd = `CMD_AREF;sdram_addr = 13'b0;sdram_ba = 2'b0;endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endREGIST  :   if(cnt_4clk == 1'b0)begincmd = `CMD_MOD;sdram_addr = 13'b000_0_00_010_0_111;//配置模式寄存器sdram_ba = 2'b0;endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endW_ACT   :   if(cnt_4clk == 1'b0)begincmd = `CMD_ACT;sdram_addr = w_addr[21:9];sdram_ba = w_addr[23:22];endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endR_ACT   :   if(cnt_4clk == 1'b0)begincmd = `CMD_ACT;sdram_addr = r_addr[21:9];sdram_ba = r_addr[23:22];endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endWRITE   :   if(cnt_bit == 1'b0)begincmd = `CMD_WR;sdram_addr = {4'b0000, w_addr[8:0]};sdram_ba = w_addr[23:22];endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endREAD    :   if(cnt_bit == 1'b0)begincmd = `CMD_RD;sdram_addr = {4'b0000, r_addr[8:0]};sdram_ba = r_addr[23:22];endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endBURST   :   if(cnt_4clk == 1'b0)begincmd = `CMD_BR;sdram_addr = 13'b0;sdram_ba = 2'b0;endelse begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;enddefault :   begincmd = `CMD_NOOP;sdram_addr = 13'b0;sdram_ba = 2'b0;endendcaseend end// wr_ack:写响应  assign wr_ack = (state_c == WRITE );// rd_ack:读响应     assign rd_ack = (state_c == READ ); // r_ack_r:读响应打两拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginr_ack_r <= 3'b0;end else begin r_ack_r <= {r_ack_r[1:0], rd_ack};end end // r_ack:输出的读响应assign  r_ack = r_ack_r[2];// w_ack:写响应打第一拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginw_ack <= 1'b0;end else begin w_ack <=  wr_ack;end end  // ack_r1:写响应打第二拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginack_r1 <= 1'b0;end else begin ack_r1 <= w_ack;end end// ack_r2:输出的读响应打拍always @(posedge clk or negedge rst_n)begin if(!rst_n)beginack_r2 <= 1'b0;end else begin ack_r2 <= r_ack;end end// 读写操作完成标志assign w_done = ack_r1 & ~w_ack;assign r_done = ack_r2 & ~r_ack;// 数据:sdram_dqassign sdram_dq = wr_ack?w_data:16'bz;// r_data:sdram读出数据assign r_data = r_ack?dq_r:16'd0;endmodule

5、乒乓缓存模块

/**************************************功能介绍***********************************
Copyright:
Date     :
Author   :厉长川
Version  :2022.10.10 v1
Description:数据缓存模块
*********************************************************************************/`include "param.v"module data_cache( input               clk         ,//100MHz工作时钟input                  rst_n       ,//复位信号input                 w_done      ,//写完成input                 r_done      ,//读完成input                 init_done   ,//sdram初始化结束input       [15:0]    r_data      ,//sdram数据接收fifo,输入数据input                 r_wrclk     ,//sdram数据接收fifo,写时钟input                 r_wrreq     ,//sdram数据接收fifo,写请求input       [15:0]    t_data      ,//sdram数据发送fifo,输入数据input                 t_rdclk     ,//sdram数据发送fifo,读时钟input                 t_rdreq     ,//sdram数据发送fifo,读请求   input                 w_ack       ,//写响应input                 r_ack       ,//读响应output      [15:0]   r_q         ,//sdram数据接收fifo,输出数据output reg  [23:0]    w_addr      ,//sdram写地址output reg  [23:0]    r_addr      ,//sdram读地址output      [15:0]   t_q         ,//sdram数据发送fifo,输出数据output reg            sdram_rdreq ,//sdram数据接收fifo,读请求output reg            sdram_wrreq  //sdram数据发送fifo,写请求
);                                    //中间信号定义      wire        [9:0]     r_rdusedw   ;//sdram数据接收fifo,读数据计数wire        [9:0]     t_wrusedw   ;//sdram数据发送fifo,写数据计数reg                   bank_flag   ;//bank切换标志reg                   bank_en     ;//bank切换使能// bank_flag、bank_en、w_addr:bank切换标志、bank切换使能和写地址always @(posedge clk or negedge rst_n)begin if(!rst_n)beginbank_en <= 1'b0;bank_flag <= 1'b0;w_addr <= 24'b0;end else if(w_done)begin if(w_addr[22:0] >= `ADDR_END)beginbank_en <= 1'b1;bank_flag <= ~bank_flag;endelse beginw_addr <= w_addr + `BURST_LEN;endend else if(bank_en)beginbank_en <= 1'b0;if(bank_flag)beginw_addr <= {1'b1, 23'b0};endelse beginw_addr <= {1'b0, 23'b0};endendend//r_addr:读地址always @(posedge clk or negedge rst_n)begin if(!rst_n)beginr_addr <= 24'b0;end else if(r_done)begin if(r_addr[22:0] >= `ADDR_END)beginif(!bank_flag)beginr_addr <= {1'b1, 23'b0};endelse beginr_addr <= {1'b0, 23'b0};endendelse beginr_addr <= r_addr + `BURST_LEN;endend end//sdram_rdreq、sdram_wrreq:sdram读写请求always @(posedge clk or negedge rst_n)begin if(!rst_n)beginsdram_rdreq <= 1'b0;sdram_wrreq <= 1'b0;end else if(init_done)begin if(r_rdusedw >= `BURST_LEN)beginsdram_rdreq <= 1'b0;sdram_wrreq <= 1'b1;endelse if(t_wrusedw < `BURST_LEN)beginsdram_rdreq <= 1'b1;sdram_wrreq <= 1'b0;endelse beginsdram_rdreq <= 1'b0;sdram_wrreq <= 1'b0;endend else begin sdram_rdreq <= 1'b0;sdram_wrreq <= 1'b0;end endfifo_r u_fifo_r(.aclr    (  ~rst_n  ),.data    (r_data    ),.rdclk   (clk       ),//sdram数据接收fifo,读时钟.rdreq   (w_ack     ),.wrclk   (r_wrclk   ),//sdram数据接收fifo,写时钟.wrreq   (r_wrreq   ),.q       (r_q       ),.rdusedw (r_rdusedw ));fifo_t u_fifo_t(.aclr    (  ~rst_n  ),.data    (t_data    ),.rdclk   (t_rdclk   ),//sdram数据发送fifo,读时钟.rdreq   (t_rdreq   ),.wrclk   (clk       ),//sdram数据发送fifo,写时钟.wrreq   (r_ack     ),.q       (t_q       ),.wrusedw (t_wrusedw ));endmodule

6、VGA驱动模块

/**************************************功能介绍***********************************
Copyright:
Date     :
Author   :厉长川
Version  :2022.10.10 v1
Description:VGA驱动模块1024*768
*********************************************************************************/`include "param.v"module vga( input                clk         ,//65Mhzinput               rst_n       ,//复位信号input        [15:0]  din         ,//vga输入数据output              vga_out_hs  ,//行同步output              vga_out_vs  ,//场同步output        [15:0]  vga_dout    ,//rgb像素数据output              data_req     //像素数据请求信号
);                                                  //中间信号定义    wire                data_valid  ;//输入像素有效标志  reg            [10:0]  cnt_h       ;//行同步计数器wire               add_cnt_h   ;wire               end_cnt_h   ;reg            [10:0]  cnt_v       ;//场同步计数器wire               add_cnt_v   ;wire               end_cnt_v   ;//cnt_h:行同步计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_h <= 11'b0;end else if(add_cnt_h)begin if(end_cnt_h)begin cnt_h <= 11'b0;endelse begin cnt_h <= cnt_h + 1'b1;end endend assign add_cnt_h = 1'b1;assign end_cnt_h = add_cnt_h && cnt_h == `H_TO - 1'b1;//cnt_v:场同步计数always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_v <= 11'b0;end else if(add_cnt_v)begin if(end_cnt_v)begin cnt_v <= 11'b0;endelse begin cnt_v <= cnt_v + 1'b1;end endend assign add_cnt_v = end_cnt_h;assign end_cnt_v = add_cnt_v && cnt_v == `V_TO - 1'b1;//vga_out_hs:行同步assign vga_out_hs = (cnt_h <= `H_SYNC - 1'b1) ;//vga_out_vs:场同步assign vga_out_vs = (cnt_v <= `V_SYNC - 1'b1) ;//data_req:像素数据请求信号 assign data_req = (`H_SYNC + `H_BP - 2'd2 < cnt_h) && (cnt_h <= `H_SYNC + `H_BP + `H_ACTIVE - 2'd2) &&(`V_SYNC + `V_BP < cnt_v) && (cnt_v <= `V_SYNC + `V_BP + `V_ACTIVE);//data_validassign data_valid = (`H_SYNC + `H_BP < cnt_h) && (cnt_h <= `H_SYNC + `H_BP + `H_ACTIVE) &&(`V_SYNC + `V_BP < cnt_v) && (cnt_v <= `V_SYNC + `V_BP + `V_ACTIVE);//vga_dout:rgb像素数据assign vga_dout = data_valid ? din : 16'b0;endmodule

7、顶层模块

/**************************************功能介绍***********************************
Copyright:
Date     :
Author   :厉长川
Version  :2022.10.10 v1
Description:顶层模块
*********************************************************************************/module img_pro( input             clk         ,//系统时钟50Mhzinput               rst_n       ,//复位信号,低电平有效input   [7:0]       cmos_db     ,//摄像头采集数据input               cmos_pclk   ,//摄像头pclk时钟48MHzinput               cmos_vsync  ,//摄像头场同步信号input               cmos_href   ,//摄像头行有效信号output              cmos_rst_n  ,//摄像头复位信号output              cmos_xclk   ,//摄像头xclk时钟24Mhzoutput              cmos_pwdn   ,//摄像头掉电使能信号output             cmos_scl    ,//摄像头配置时钟信号inout               cmos_sda    ,//摄像头配置数据信号output              sdram_clk   ,//sdram工作时钟output              sdram_cke   ,//sdram使能output  [12:0]      sdram_addr  ,//sdram地址总线output  [1:0]       sdram_ba    ,//sdram bank地址inout   [15:0]      sdram_dq    ,//sdram数据总线output  [1:0]       sdram_dqm   ,//数据掩码output  [3:0]       cmd         ,//sdram操作命令output              vga_out_hs  ,//vga行同步信号output              vga_out_vs  ,//vga场同步信号output  [15:0]      vga_dout     //vga输出的RGB数据);                                               //中间信号定义        wire                vga_clk     ;//vga时钟wire                clk_100MHz  ;//100MHz工作时钟wire                done        ;//摄像头配置完成标志wire    [15:0]      pixel_dout  ;//采集的像素数据wire                dout_valid  ;//采集数据有效标志wire    [15:0]      w_data      ;//sdram写入数据wire    [15:0]      r_data      ;//sdram读出数据wire    [15:0]      vga_din     ;//vga输入数据wire                data_req    ;//vga数据请求wire    [23:0]      w_addr      ;//sdram写地址wire    [23:0]      r_addr      ;//sdram读地址wire                sdram_rdreq ;//sdram数据接收fifo,读请求wire                sdram_wrreq ;//sdram数据发送fifo,写请求wire                r_ack       ;//读响应wire                wr_ack      ;//写响应wire                locked_1    ;//pll_1输出稳定标志wire                locked_2    ;//pll_2输出稳定标志wire                reset       ;//sccb、data_cache、sdram和vga模块复位信号wire                init_done   ;//sdram初始化结束wire                pixel_rst   ;//pixel_sampling模块复位信号wire                w_done      ;//写完成标志wire                r_done      ;//读完成标志//sdram_cke:sdram使能assign sdram_cke = 1'b1;//sdram_dqm:数据掩码assign sdram_dqm = 2'b00;//reset:sccb、data_cache、sdram和vga模块复位信号assign reset = locked_1 & locked_2 & rst_n;//pixel_rst:pixel_sampling模块复位信号assign pixel_rst = done & init_done & reset;sccb u_sccb(.clk          (clk           ),.rst_n        (reset         ),.done         (done          ),.cmos_rst_n   (cmos_rst_n    ),.cmos_pwdn    (cmos_pwdn     ),.cmos_scl     (cmos_scl      ),.cmos_sda     (cmos_sda      ));pixel_sampling u_pixel_sampling(.clk          (cmos_pclk     ),//摄像头pclk时钟48MHz.rst_n        (pixel_rst     ),//pixel_sampling模块复位信号.din          (cmos_db       ),//摄像头采集数据.vsync        (cmos_vsync    ),//摄像头场同步信号.href         (cmos_href     ),//摄像头行有效信号.dout_valid   (dout_valid    ),//输出数据有效标志.dout         (pixel_dout    ) //输出拼接完成的像素);data_cache u_data_cache(.clk          (clk_100MHz    ),.rst_n        (reset         ),.w_done       (w_done        ),.r_done       (r_done        ),.init_done    (init_done     ),.r_data       (pixel_dout    ),.r_wrclk      (cmos_pclk     ),.r_wrreq      (dout_valid    ),.t_data       (r_data        ),.t_rdclk      (vga_clk       ),.t_rdreq      (data_req      ),.w_ack        (wr_ack        ),.r_ack        (r_ack         ),.r_q          (w_data        ),.w_addr       (w_addr        ),.r_addr       (r_addr        ),.t_q          (vga_din       ),.sdram_rdreq  (sdram_rdreq   ),//sdram数据接收fifo,读请求.sdram_wrreq  (sdram_wrreq   ) //sdram数据发送fifo,写请求);sdram u_sdram(.clk          (clk_100MHz    ),.rst_n        (reset         ),.w_req        (sdram_wrreq   ),.r_req        (sdram_rdreq   ),.w_addr       (w_addr        ),.r_addr       (r_addr        ),.w_data       (w_data        ),.r_data       (r_data        ),.sdram_addr   (sdram_addr    ),.sdram_ba     (sdram_ba      ),.sdram_dq     (sdram_dq      ),.cmd          (cmd           ),.init_done    (init_done     ),.r_ack        (r_ack         ),.wr_ack       (wr_ack        ),.w_done       (w_done        ),//写操作完成标志.r_done       (r_done        ) //读操作完成标志);vga u_vga(.clk          (vga_clk       ),.rst_n        (reset         ),.din          (vga_din       ),.vga_out_hs   (vga_out_hs    ),.vga_out_vs   (vga_out_vs    ),.vga_dout     (vga_dout      ),.data_req     (data_req      ));pll_1 pll_1_inst (.areset       (~rst_n        ),.inclk0       (clk           ),//50MHz.c0           (vga_clk       ),//65MHz.c1           (clk_100MHz    ),//100MHz.c2           (sdram_clk     ),//100MHz,-75deg.locked       (locked_1      ));pll_2   pll_2_inst (.areset       (~rst_n        ),.inclk0       (clk           ),//50MHz系统时钟.c0           (cmos_xclk     ),//24Mhz.locked       (locked_2      ));endmodule

8、参数定义

仿真时可以修改参数节省仿真时间

/**************************************功能介绍***********************************
Copyright:
Date     :
Author   :厉长川
Version  :2022.10.10 v1
Description:参数定义
*********************************************************************************///sccb参数定义
`define     CNT_1M      6'd50                                   //1M时钟计数
`define     CNT_MS      21'd1315000                             //26.3ms时间计数
`define     PWDN        18'd255000                              //5.1ms计时
`define     RST_CMOS    19'd310000                              //1.1ms复位等待时间
`define     NUM_CFG     8'd248                                  //寄存器配置个数//pixel_sampling参数定义
`define     PIXEL       4'd10                                   //舍弃帧数//vga接口参数
// 1024*768  65Mhz
`define     H_ACTIVE    11'd1024                                //行有效
`define     H_FP        11'd24                                  //行前沿
`define     H_SYNC      11'd136                                 //行同步
`define     H_BP        11'd160                                 //行后沿
`define     H_TO        11'd1344                                //行周期
`define     V_ACTIVE    11'd768                                 //场有效
`define     V_FP        11'd3                                   //场前沿
`define     V_SYNC      11'd6                                   //场同步
`define     V_BP        11'd29                                  //场后沿
`define     V_TO        11'd806                                 //场周期 //sdram模块参数
`define     CMD_NOOP    4'b0111                                 //空指令
`define     CMD_ACT     4'b0011                                 //行激活指令
`define     CMD_RD      4'b0101                                 //读指令
`define     CMD_WR      4'b0100                                 //写指令
`define     CMD_BR      4'b0110                                 //突发终止指令
`define     CMD_PRE        4'b0010                                 //预充电指令
`define     CMD_AREF   4'b0001                                 //自动刷新指令
`define     CMD_MOD     4'b0000                                 //模式寄存器配置命令
`define     INIT_TIME   14'd10000                               //上电等待时间,10000个时钟周期(100us)
`define     AREF_TIME   10'd700                                 //自动刷新间隔时间,700个时钟周期(7us)
`define     BURST_LEN   10'd512                                 //读写突发长度
`define     ADDR_END    `H_ACTIVE * `V_ACTIVE - `BURST_LEN      //读写地址末地址

9、最终效果

①:分析综合

②:上板验证


一、FPGA Cyclone Ⅳ OV5640图像实时采集系统设计相关推荐

  1. 多路视频数据实时采集系统设计与实现

    多路视频数据实时采集系统设计与实现 常永亮   王霖萱  常馨蓉 摘要 面对越来越多的实时视频采集.播放的应用,如何能更加方便的操控视频采集,保证流畅的播放效果,成为近几年实时媒体流的一个重要研究方向 ...

  2. (二)Qt多线程实现海康工业相机图像实时采集

    系列文章目录 提示:这里是该系列文章的所有文章的目录 第一章: (一)Qt+OpenCV调用海康工业相机SDK示例开发 第二章: (二)Qt多线程实现海康工业相机图像实时采集 文章目录 系列文章目录 ...

  3. 论文:基于1394b接口的车载嵌入式图像实时采集与显示系统设计

    1.总体设计方案概述 系统分为4个模块,图像采集模块使用1394接口,采集卡保存图像数据,压缩图片:图像处理模块中,DM8168开发板嵌入Qt界面,通过电平转换芯片将信号传给FPGA,数模转换芯片与V ...

  4. basler恢复出厂设置_实现图像实时采集(使用BaslerSDK)-C

    [实例简介] [实例截图] [核心代码] DeviceRemovalHandling/ Grab/ Grab_CameraEvents/ Grab_ChunkImage/ Grab_MultiCast ...

  5. FPGA 30 综合数字ADC /DAC 信号发送采集系统设计(综合项目设计)

    FPGA 30 综合数字ADC /DAC 信号发送采集系统设计(综合项目设计) 模块名称 : 综合数字ADC /DAC 信号发送采集系统设计 主要功能 :本实验设计了一个信号发送和采集系统的设计,在整 ...

  6. FPGA 20个例程篇:19.OV7725摄像头实时采集送HDMI显示(一)

    第七章 实战项目提升,完善简历 19.OV7725摄像头实时采集送HDMI显示(一) 在例程"OV7725摄像头实时采集送HDMI显示"中,我们将走近FPGA图像处理的世界,图像处 ...

  7. FPGA USB FX2 ov5640摄像头视频采集 驱动CY7C68013A实现 提供2套工程源码和技术支持

    目录 1.前言 2.我这儿已有的 FPGA USB 通信方案 3.CY7C68013A芯片解读和硬件设计 FX2 简介 SlaveFIFO模式及其配置 4.工程详细设计方案 5.vivado工程 6. ...

  8. FPGA 20个例程篇:19.OV7725摄像头实时采集送HDMI显示(三)

    第七章 实战项目提升,完善简历 19.OV7725摄像头实时采集送HDMI显示(三) 在详细介绍过OV7725 CMOS Sensor的相关背景知识和如何初始化其内部寄存器达到输出预期视频流的目的后, ...

  9. 基于FPGA的单目内窥镜定位系统设计(上)

    今天给大侠带来基于FPGA的单目内窥镜定位系统设计,由于篇幅较长,分三篇.今天带来第一篇,上篇,话不多说,上货. 导读 随着现科技的发展和社会的进步,信息科技迅速发展,我们可从互联网.电台等媒体获取大 ...

最新文章

  1. Understanding SOAP
  2. 只服这篇“神文”:基于老子哲学、相对论的超级人工智能模型
  3. PHP Web System Optimization(undone)
  4. python使用函数的优点-Python用了这么多年,总结出超实用的功能和特点
  5. 年薪50万美金的工程师到底牛在哪里?
  6. stm32使用rtc到底用LSI还是LSE
  7. 优秀的领导与差劲的领导
  8. python中itertools groupby函数是干嘛的_Python-如何使用itertools.groupby()?
  9. python文本关键词匹配_NLP利剑篇之模式匹配
  10. [系统安全] 四十一.APT系列(6)Python解析PE文件并获取时间戳判断来源区域
  11. 动态规划求解装箱问题(洛谷P1049题题解,Java语言描述)
  12. 判断给定的两个数是否是亲和数_动画演示LeetCode算法题:004-寻找两个有序数组的中位数...
  13. vue可以直接进行运算么_Vue实现手机计算器
  14. 骁龙845_性能强大价格更吸引 超值骁龙845手机盘点
  15. 状态机编程实例及适用范围
  16. 接口测试之功能测试,性能测试,安全测试
  17. 第四章 春夏秋冬,二十四节气
  18. STOP:0x0000007E蓝屏软件故障处理
  19. python怎么算积分_蒙特卡洛方法求定积分及python实现(转)
  20. 【DDR3_Electrical Characteristics and AC Timing】_ Setup,Hold and Slew Rate Derating

热门文章

  1. 17.7.19-聊天APP-登录界面
  2. BootStrap工具使用
  3. Word制作三线表格并插入公式
  4. 虚拟机Ubuntu下共享文件夹MyShare不显示
  5. USACO美国信息学奥赛竞赛12月份开赛,中国学生备赛指南
  6. 2020.05.29
  7. 个人作业——A002-185-2513-吴光华
  8. 针对HFS 2.3漏洞进行渗透测试提权(HFS:HttpFileServer)
  9. CST—电磁及EMC仿真工具
  10. 二阶矩过程、平稳过程和随机分析