本文设计思想采用明德扬至简设计法。在做摄像头数据采集处理之前,需要配置OV5640传感器内部寄存器使其按要求正常工作,详细内容请参见《OV5640自动对焦照相模组应用指南》。首先要关注OV5640的上电时序:

\"\"

  主控制器控制RESET PWDN两个信号按上电时序要求变化,之后允许ov_config模块配置内部寄存器。这里始终将PWDN拉低。实验中将摄像头分辨率设置为720p,即1280*720 ,帧率为30fps,图像输出格式是RGB565。此时摄像头输入时钟XCLK频率24MHz,输出像素时钟PCLK为84MHz。由于实验使用的是OV5640双目摄像头模组,且XCLK由外部24MHz晶振给出,故ov_config模块整体结构及端口定义如下:

\"\"

  setup模块构造上电时序,两个reg_config分别配置一个OV5640摄像头。SCCB_interface子模块负责SCCB协议读写寄存器数据。由于OV5640摄像头内部寄存器地址为16位,因此写寄存器地址阶段分高低字节两次写入。datasheet中给出了OV5640的SCCB ID地址(写),故读ID地址为0X79。

\"\"

   SCCB时序图及AC characteristics如下:

\"\"

   SCCB时钟SIOC支持最大频率为400KHz,一般选100KHz即可。以下是本人设计的SCCB接口读写时序状态机,写操作:IDLE START WRI_ID WRI_REG WRI_DATA STOP 对应三相写,读操作:IDLE START WRI_ID WRI_REG STOP      START WRI_ID RD_DATA STOP对应两相写和两相读。

\"\"

上代码:

SCCB读写模块:

\"\"\"\"
  1 `timescale 1ns / 1ps
  2 
  3 
  4 module sccb_interface(
  5     input clk,
  6     input rst_n,
  7 
  8     input wr_en,
  9     input rd_en,
 10     input [8-1:0] id_addr,
 11     input [16-1:0] reg_addr,
 12     input [8-1:0] wr_data,
 13     output reg [8-1:0] rd_data,
 14     output reg rd_vld,
 15     output rdy,
 16 
 17     output reg sio_c,
 18     output reg sio_out_en,
 19     output reg sio_out,
 20     input sio_in
 21     );
 22 
 23     parameter CYC = 500;
 24     
 25 
 26 localparam  IDLE = 0 ;
 27 localparam  START = 1 ;
 28 localparam  WRI_ID = 2 ;
 29 localparam  WRI_REG = 3 ;
 30 localparam  WRI_DATA = 4;
 31 localparam  RD_DATA = 5;
 32 localparam  STOP = 6 ;
 33 
 34 //计数器
 35 reg [ (9-1):0]  div_cnt     ;
 36 wire        add_div_cnt ;
 37 wire        end_div_cnt ;
 38 reg [ (5-1):0]  bit_cnt     ;
 39 wire        add_bit_cnt ;
 40 wire        end_bit_cnt ;
 41 reg [5-1:0] N;
 42 (*DONT_TOUCH = "TRUE"*)reg [7-1:0] state_c,state_n;
 43 wire idle2start,start2wri_id,wri_id2wri_reg,wri_id2rd_data, wri_reg2wri_data,wri_reg2stop,wri_data2stop,rd_data2stop,stop2start,stop2idle;
 44 wire [18-1:0] regaddr;
 45 reg [16-1:0] reg_addr_tmp;
 46 reg [8-1:0] wr_data_tmp;
 47 wire [9-1:0] idaddr_nc;
 48 reg [8-1:0] id_addr_tmp;
 49 reg rd_oper,rd_flag;
 50 wire [9-1:0] wdata_nc;
 51 wire [8-1:0] id_rwCtrl;
 52 
 53 
 54 assign rdy = state_c == IDLE && !wr_en && !rd_en;
 55 
 56 always @(posedge clk or negedge rst_n) begin 
 57     if (rst_n==0) begin
 58         div_cnt <= 0; 
 59     end
 60     else if(add_div_cnt) begin
 61         if(end_div_cnt)
 62             div_cnt <= 0; 
 63         else
 64             div_cnt <= div_cnt+1 ;
 65    end
 66 end
 67 assign add_div_cnt = (state_c != IDLE);
 68 assign end_div_cnt = add_div_cnt  && div_cnt == (CYC)-1 ;//5000ns,200KHZ
 69 
 70 always @(posedge clk or negedge rst_n) begin 
 71     if (rst_n==0) begin
 72         bit_cnt <= 0; 
 73     end
 74     else if(add_bit_cnt) begin
 75         if(end_bit_cnt)
 76             bit_cnt <= 0; 
 77         else
 78             bit_cnt <= bit_cnt+1 ;
 79    end
 80 end
 81 assign add_bit_cnt = (end_div_cnt);
 82 assign end_bit_cnt = add_bit_cnt  && bit_cnt == (N)-1 ;
 83 
 84 always@(*)begin
 85     case(state_c)
 86         START:                  N = 1;
 87         WRI_REG:                N = 18; //(8+1)*2 = 18
 88         WRI_ID,WRI_DATA,RD_DATA:N = 9;//8+1
 89         STOP:                   N = 2;
 90         default:;
 91     endcase
 92 end
 93 
 94 //FSM:IDLE START WRI_ID WRI_REG STOP
 95 always @(posedge clk or negedge rst_n) begin 
 96     if (rst_n==0) begin
 97         state_c <= IDLE ;
 98     end
 99     else begin
100         state_c <= state_n;
101    end
102 end
103 //write:IDLE START WRI_ID WRI_REG WRI_DATA STOP IDLE...
104 //read: IDLE START WRI_ID WRI_REG STOP      START WRI_ID RD_DATA STOP IDLE...
105 
106 always @(*) begin 
107     case(state_c)  
108         IDLE :begin                             //0
109             if(idle2start) 
110                 state_n = START ;
111             else 
112                 state_n = state_c ;
113         end
114         START :begin                            //1
115             if(start2wri_id) 
116                 state_n = WRI_ID ;
117             else 
118                 state_n = state_c ;
119         end
120         WRI_ID :begin                           //2
121             if(wri_id2wri_reg) 
122                 state_n = WRI_REG ;
123             else if(wri_id2rd_data)
124                 state_n = RD_DATA;
125             else 
126                 state_n = state_c ;
127         end
128         WRI_REG :begin                          //3
129             if(wri_reg2wri_data)
130                 state_n = WRI_DATA;
131             else if(wri_reg2stop) 
132                 state_n = STOP ;
133             else 
134                 state_n = state_c ;
135         end
136         WRI_DATA:begin                          //4
137             if(wri_data2stop)
138                 state_n = STOP;
139             else 
140                 state_n = state_c;
141         end 
142         RD_DATA:begin                           //5
143             if(rd_data2stop)
144                 state_n = STOP;
145             else
146                 state_n = state_c;
147         end
148         STOP :begin                             //6
149             if(stop2start)
150                 state_n = START;
151             else if(stop2idle) 
152                 state_n = IDLE ;
153             else 
154                 state_n = state_c ;
155         end
156         default : state_n = IDLE ;
157     endcase
158 end
159 
160 assign idle2start           = state_c==IDLE         && (wr_en || rd_en);
161 assign start2wri_id         = state_c==START        && (end_bit_cnt);
162 assign wri_id2wri_reg       = state_c==WRI_ID       && (end_bit_cnt && !rd_oper);
163 assign wri_id2rd_data       = state_c==WRI_ID       && (end_bit_cnt && rd_oper);
164 assign wri_reg2wri_data     = state_c==WRI_REG      && (end_bit_cnt && !rd_flag);
165 assign wri_reg2stop         = state_c==WRI_REG      && (end_bit_cnt && rd_flag);
166 assign wri_data2stop        = state_c==WRI_DATA     && (end_bit_cnt);
167 assign rd_data2stop         = state_c==RD_DATA      && (end_bit_cnt);
168 assign stop2start           = state_c==STOP         && (end_bit_cnt && rd_flag && !rd_oper);
169 assign stop2idle            = state_c==STOP         && (end_bit_cnt && (!rd_flag || rd_oper));
170 
171 always  @(posedge clk or negedge rst_n)begin
172     if(rst_n==1'b0)begin
173         rd_oper <= 0;
174     end
175     else if(stop2start)begin
176         rd_oper <= 1;
177     end
178     else if(rd_oper && stop2idle)
179         rd_oper <= 0;
180 end
181 
182 always  @(posedge clk or negedge rst_n)begin
183     if(rst_n==1'b0)begin
184         rd_flag <= 0;
185     end
186     else if(idle2start && rd_en)begin
187         rd_flag <= 1;
188     end
189     else if(stop2idle)
190         rd_flag <= 0;
191 end
192 
193 //SCCB时钟
194 always  @(posedge clk or negedge rst_n)begin
195     if(rst_n==1'b0)
196         sio_c <= 1'b1;
197     else if(add_div_cnt && div_cnt == CYC/4-1)
198         sio_c <= 1;
199     else if(add_div_cnt && div_cnt == CYC/4+CYC/2-1)
200         sio_c <= 0;
201     else if(state_c == IDLE)
202         sio_c <= 1;//空闲状态sioc为1
203 end
204 
205 always  @(posedge clk or negedge rst_n)begin
206     if(rst_n==1'b0)begin
207         sio_out <= 1;
208     end
209     else if(state_c == START && div_cnt == CYC/2-1)
210         sio_out <= 0;//开始条件
211     else if(state_c == WRI_ID)
212         sio_out <= idaddr_nc[9-1-bit_cnt];
213     else if(wri_reg2stop || wri_data2stop || rd_data2stop)
214         sio_out <= 0;
215     else if(state_c == WRI_REG)
216         sio_out <= regaddr[18-1-bit_cnt];
217     else if(state_c == WRI_DATA)
218         sio_out <= wdata_nc[9-1-bit_cnt];
219     else if(state_c == RD_DATA && bit_cnt == 9-1)
220         sio_out <= 1;//NACK
221     else if(state_c == STOP && div_cnt == CYC/2-1 && bit_cnt == 0)
222         sio_out <= 1;//结束条件
223 end
224 
225 assign idaddr_nc = {id_rwCtrl,1'b1};
226 assign regaddr = {reg_addr_tmp[15:8],1'b1,reg_addr_tmp[7:0],1'b1};
227 assign wdata_nc = {wr_data_tmp,1'b1};
228 
229 assign id_rwCtrl = rd_oper ? {id_addr[7:1],1'b1} : id_addr;
230 
231 always  @(posedge clk or negedge rst_n)begin
232     if(rst_n==1'b0)begin
233         reg_addr_tmp <= 0;
234         wr_data_tmp <= 0;
235     end
236     else if(wr_en || rd_en)begin
237         reg_addr_tmp <= reg_addr;
238         wr_data_tmp <= wr_data;
239     end
240 end
241 
242 
243 always  @(posedge clk or negedge rst_n)begin
244     if(rst_n==1'b0)begin
245         sio_out_en <= 0;
246     end
247     else begin
248         case(state_c)
249             START,STOP:begin
250                 sio_out_en <= 1;
251             end
252             WRI_ID,WRI_DATA:begin
253                 if(bit_cnt != 9-1)
254                     sio_out_en <= 1;
255                 else
256                     sio_out_en <= 0;
257             end
258             WRI_REG:begin
259                 if(bit_cnt != 9-1 && bit_cnt != 18-1)
260                     sio_out_en <= 1;
261                 else
262                     sio_out_en <= 0;
263             end
264             RD_DATA:begin
265                 if(bit_cnt == 9-1)
266                     sio_out_en <= 1;
267                 else
268                     sio_out_en <= 0;
269             end 
270             default:sio_out_en <= 0;
271         endcase
272     end
273 end
274 
275 //read data
276 always  @(posedge clk or negedge rst_n)begin
277     if(rst_n==1'b0)begin
278         rd_data <= 0;
279     end
280     else if(state_c == RD_DATA && bit_cnt != 9-1 && div_cnt == CYC/2-1)begin
281         rd_data[8-1-bit_cnt] <= sio_in;
282     end
283 end
284 
285 always  @(posedge clk or negedge rst_n)begin
286     if(rst_n==1'b0)begin
287         rd_vld <= 0;
288     end
289     else if(rd_data2stop)begin
290         rd_vld <= 1;
291     end
292     else 
293         rd_vld <= 0;
294 end
295 
296 
297 endmodule
sccb_interface

 寄存器配置模块:

\"\"\"\"
  1 `timescale 1ns / 1ps
  2 
  3 
  4 module reg_config(
  5     input           clk,
  6     input           rst_n,
  7 
  8     input           en,
  9     output          finish,
 10 
 11     inout           sio_d,
 12     output          sio_c
 13     );
 14 
 15 localparam WR_ID = 8'h78;
 16 localparam RW_CTRL = 2'b11;//读
 17 wire sio_out_en;
 18 wire sio_out;
 19 wire sio_in;
 20 reg [9-1:0] reg_cnt;
 21 wire add_reg_cnt,end_reg_cnt;
 22 reg config_flag;
 23 reg [26-1:0] op_reg_data;
 24 wire rdy;
 25 reg wr_en;
 26 reg [16-1:0] reg_addr;
 27 reg [8-1:0] wr_data;
 28 reg config_done;
 29 reg [ (2-1):0]  rw_cnt     ;
 30 wire        add_rw_cnt ;
 31 wire        end_rw_cnt ;
 32 reg rd_en;
 33 (*DONT_TOUCH = "TRUE"*)wire [8-1:0] rd_data;
 34 (*DONT_TOUCH = "TRUE"*)wire rd_vld;
 35 
 36 sccb_interface sccb_interface(
 37     .clk    (clk) ,
 38     .rst_n     (rst_n) ,
 39     .wr_en     (wr_en) ,
 40     .rd_en     (rd_en),
 41     .id_addr   (WR_ID) ,
 42     .reg_addr  (reg_addr) ,
 43     .wr_data   (wr_data) ,
 44     .rd_data   (rd_data),
 45     .rd_vld    (rd_vld),
 46     .rdy       (rdy) ,
 47     .sio_c     (sio_c) ,
 48     .sio_out_en(sio_out_en) ,
 49     .sio_out   (sio_out) ,
 50     .sio_in    (sio_in) 
 51     );
 52 
 53     assign sio_d = sio_out_en ? sio_out : 1'bz;
 54     assign sio_in = sio_d;
 55 
 56     always @(posedge clk or negedge rst_n) begin 
 57         if (rst_n==0) begin
 58             rw_cnt <= 0; 
 59         end
 60         else if(add_rw_cnt) begin
 61             if(end_rw_cnt)
 62                 rw_cnt <= 0; 
 63             else
 64                 rw_cnt <= rw_cnt+1 ;
 65         end
 66     end
 67     assign add_rw_cnt = (config_flag && rdy);
 68     assign end_rw_cnt = add_rw_cnt  && rw_cnt == (2)-1 ;//0 write 1 read
 69 
 70     always @(posedge clk or negedge rst_n)begin
 71         if(!rst_n)begin
 72             reg_cnt <= 0;
 73         end
 74         else if(add_reg_cnt)begin
 75             if(end_reg_cnt)
 76                 reg_cnt <= 0;
 77             else
 78                 reg_cnt <= reg_cnt + 1;
 79         end
 80     end
 81 
 82     assign add_reg_cnt = end_rw_cnt;       
 83     assign end_reg_cnt = add_reg_cnt && reg_cnt == 261-1;   
 84 
 85     //配置指令
 86     always  @(posedge clk or negedge rst_n)begin
 87         if(rst_n==1'b0)begin
 88             wr_en <= 0;
 89             reg_addr <= 0;
 90             wr_data <= 0;
 91         end
 92         else if(add_rw_cnt && rw_cnt == 0)begin
 93             wr_en    <= op_reg_data[25];
 94             reg_addr <= op_reg_data[23:8];
 95             wr_data  <= op_reg_data[7:0];
 96         end
 97         else if(end_rw_cnt)begin
 98             rd_en     <= op_reg_data[24];
 99             reg_addr  <= op_reg_data[23:8];
100         end
101         else begin
102             wr_en <= 0;
103             rd_en <= 0;
104         end
105     end
106 
107 
108     always  @(posedge clk or negedge rst_n)begin
109         if(rst_n==1'b0)begin
110             config_flag <= 0;
111         end
112         else if(en && !config_flag && !config_done)begin
113             config_flag <= 1;
114         end
115         else if(end_reg_cnt)
116             config_flag <= 0;
117     end
118 
119     always  @(posedge clk or negedge rst_n)begin

					
				
收藏 打印
您的足迹: