原创博客,转载请注明出处:FPGA配置OV5640摄像头及RGB图像数据采集 - 没落骑士 - 博客园
https://www.cnblogs.com/moluoqishi/p/9506706.html
本文设计思想采用明德扬至简设计法。在做摄像头数据采集处理之前,需要配置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
298
299
300
寄存器配置模块:
> 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
120 if(rst_n==1'b0)begin
121 config_done <= 0;
122 end
123 else if(end_reg_cnt)begin
124 config_done <= 1;
125 end
126 end
127
128 assign finish = config_done && rdy;
129
130 always@(*)
131 begin//op_reg_data [25] wr [24] rd [23:8] reg_addr [7:0] wr_data
132 case(reg_cnt)
133 //15fps VGA YUV output // 24MHz input clock, 24MHz PCLK
134 0:op_reg_data= {RW_CTRL, 24'h310311};// system clock from pad, bit[1]
135 1:op_reg_data= {RW_CTRL, 24'h300882};// software reset, bit[7]// delay 5ms
136 2:op_reg_data= {RW_CTRL, 24'h300842};// software power down, bit[6]
137 3:op_reg_data= {RW_CTRL, 24'h310303};// system clock from PLL, bit[1]
138 4:op_reg_data= {RW_CTRL, 24'h3017ff};// FREX, Vsync, HREF, PCLK, D[9:6] output enable
139 5:op_reg_data= {RW_CTRL, 24'h3018ff};// D[5:0], GPIO[1:0] output enable
140 6:op_reg_data= {RW_CTRL, 24'h30341A};// MIPI 10-bit
141 7:op_reg_data= {RW_CTRL, 24'h303713};// PLL root divider, bit[4], PLL pre-divider, bit[3:0]
142 8:op_reg_data= {RW_CTRL, 24'h310801};// PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2] // SCLK root divider, bit[1:0]
143 9:op_reg_data= {RW_CTRL, 24'h363036};
144 10:op_reg_data= {RW_CTRL, 24'h36310e};
145 11:op_reg_data= {RW_CTRL, 24'h3632e2};
146 12:op_reg_data= {RW_CTRL, 24'h363312};
147 13:op_reg_data= {RW_CTRL, 24'h3621e0};
148 14:op_reg_data= {RW_CTRL, 24'h3704a0};
149 15:op_reg_data= {RW_CTRL, 24'h37035a};
150 16:op_reg_data= {RW_CTRL, 24'h371578};
151 17:op_reg_data= {RW_CTRL, 24'h371701};
152 18:op_reg_data= {RW_CTRL, 24'h370b60};
153 19:op_reg_data= {RW_CTRL, 24'h37051a};
154 20:op_reg_data= {RW_CTRL, 24'h390502};
155 21:op_reg_data= {RW_CTRL, 24'h390610};
156 22:op_reg_data= {RW_CTRL, 24'h39010a};
157 23:op_reg_data= {RW_CTRL, 24'h373112};
158 24:op_reg_data= {RW_CTRL, 24'h360008};// VCM control
159 25:op_reg_data= {RW_CTRL, 24'h360133};// VCM control
160 26:op_reg_data= {RW_CTRL, 24'h302d60};// system control
161 27:op_reg_data= {RW_CTRL, 24'h362052};
162 28:op_reg_data= {RW_CTRL, 24'h371b20};
163 29:op_reg_data= {RW_CTRL, 24'h471c50};
164 30:op_reg_data= {RW_CTRL, 24'h3a1343};// pre-gain = 1.047x
165 31:op_reg_data= {RW_CTRL, 24'h3a1800};// gain ceiling
166 32:op_reg_data= {RW_CTRL, 24'h3a19f8};// gain ceiling = 15.5x
167 33:op_reg_data= {RW_CTRL, 24'h363513};
168 34:op_reg_data= {RW_CTRL, 24'h363603};
169 35:op_reg_data= {RW_CTRL, 24'h363440};
170 36:op_reg_data= {RW_CTRL, 24'h362201}; // 50/60Hz detection 50/60Hz 灯光条纹过滤
171 37:op_reg_data= {RW_CTRL, 24'h3c0134};// Band auto, bit[7]
172 38:op_reg_data= {RW_CTRL, 24'h3c0428};// threshold low sum
173 39:op_reg_data= {RW_CTRL, 24'h3c0598};// threshold high sum
174 40:op_reg_data= {RW_CTRL, 24'h3c0600};// light meter 1 threshold[15:8]
175 41:op_reg_data= {RW_CTRL, 24'h3c0708};// light meter 1 threshold[7:0]
176 42:op_reg_data= {RW_CTRL, 24'h3c0800};// light meter 2 threshold[15:8]
177 43:op_reg_data= {RW_CTRL, 24'h3c091c};// light meter 2 threshold[7:0]
178 44:op_reg_data= {RW_CTRL, 24'h3c0a9c};// sample number[15:8]
179 45:op_reg_data= {RW_CTRL, 24'h3c0b40};// sample number[7:0]
180 46:op_reg_data= {RW_CTRL, 24'h381000};// Timing Hoffset[11:8]
181 47:op_reg_data= {RW_CTRL, 24'h381110};// Timing Hoffset[7:0]
182 48:op_reg_data= {RW_CTRL, 24'h381200};// Timing Voffset[10:8]
183 49:op_reg_data= {RW_CTRL, 24'h370864};
184 50:op_reg_data= {RW_CTRL, 24'h400102};// BLC start from line 2
185 51:op_reg_data= {RW_CTRL, 24'h40051a};// BLC always update
186 52:op_reg_data= {RW_CTRL, 24'h300000};// enable blocks
187 53:op_reg_data= {RW_CTRL, 24'h3004ff};// enable clocks
188 54:op_reg_data= {RW_CTRL, 24'h300e58};// MIPI power down, DVP enable
189 55:op_reg_data= {RW_CTRL, 24'h302e00};
190 56:op_reg_data= {RW_CTRL, 24'h430060};// RGB565
191 57:op_reg_data= {RW_CTRL, 24'h501f01};// ISP RGB
192 58:op_reg_data= {RW_CTRL, 24'h440e00};
193 59:op_reg_data= {RW_CTRL, 24'h5000a7}; // Lenc on, raw gamma on, BPC on, WPC on, CIP on // AEC target 自动曝光控制
194 60:op_reg_data= {RW_CTRL, 24'h3a0f30};// stable range in high
195 61:op_reg_data= {RW_CTRL, 24'h3a1028};// stable range in low
196 62:op_reg_data= {RW_CTRL, 24'h3a1b30};// stable range out high
197 63:op_reg_data= {RW_CTRL, 24'h3a1e26};// stable range out low
198 64:op_reg_data= {RW_CTRL, 24'h3a1160};// fast zone high
199 65:op_reg_data= {RW_CTRL, 24'h3a1f14};// fast zone low// Lens correction for ? 镜头补偿
200 66:op_reg_data= {RW_CTRL, 24'h580023};
201 67:op_reg_data= {RW_CTRL, 24'h580114};
202 68:op_reg_data= {RW_CTRL, 24'h58020f};
203 69:op_reg_data= {RW_CTRL, 24'h58030f};
204 70:op_reg_data= {RW_CTRL, 24'h580412};
205 71:op_reg_data= {RW_CTRL, 24'h580526};
206 72:op_reg_data= {RW_CTRL, 24'h58060c};
207 73:op_reg_data= {RW_CTRL, 24'h580708};
208 74:op_reg_data= {RW_CTRL, 24'h580805};
209 75:op_reg_data= {RW_CTRL, 24'h580905};
210 76:op_reg_data= {RW_CTRL, 24'h580a08};
211 77:op_reg_data= {RW_CTRL, 24'h580b0d};
212 78:op_reg_data= {RW_CTRL, 24'h580c08};
213 79:op_reg_data= {RW_CTRL, 24'h580d03};
214 80:op_reg_data= {RW_CTRL, 24'h580e00};
215 81:op_reg_data= {RW_CTRL, 24'h580f00};
216 82:op_reg_data= {RW_CTRL, 24'h581003};
217 83:op_reg_data= {RW_CTRL, 24'h581109};
218 84:op_reg_data= {RW_CTRL, 24'h581207};
219 85:op_reg_data= {RW_CTRL, 24'h581303};
220 86:op_reg_data= {RW_CTRL, 24'h581400};
221 87:op_reg_data= {RW_CTRL, 24'h581501};
222 88:op_reg_data= {RW_CTRL, 24'h581603};
223 89:op_reg_data= {RW_CTRL, 24'h581708};
224 90:op_reg_data= {RW_CTRL, 24'h58180d};
225 91:op_reg_data= {RW_CTRL, 24'h581908};
226 92:op_reg_data= {RW_CTRL, 24'h581a05};
227 93:op_reg_data= {RW_CTRL, 24'h581b06};
228 94:op_reg_data= {RW_CTRL, 24'h581c08};
229 95:op_reg_data= {RW_CTRL, 24'h581d0e};
230 96:op_reg_data= {RW_CTRL, 24'h581e29};
231 97:op_reg_data= {RW_CTRL, 24'h581f17};
232 98:op_reg_data= {RW_CTRL, 24'h582011};
233 99:op_reg_data= {RW_CTRL, 24'h582111};
234 100:op_reg_data= {RW_CTRL, 24'h582215};
235 101:op_reg_data= {RW_CTRL, 24'h582328};
236 102:op_reg_data= {RW_CTRL, 24'h582446};
237 103:op_reg_data= {RW_CTRL, 24'h582526};
238 104:op_reg_data= {RW_CTRL, 24'h582608};
239 105:op_reg_data= {RW_CTRL, 24'h582726};
240 106:op_reg_data= {RW_CTRL, 24'h582864};
241 107:op_reg_data= {RW_CTRL, 24'h582926};
242 108:op_reg_data= {RW_CTRL, 24'h582a24};
243 109:op_reg_data= {RW_CTRL, 24'h582b22};
244 110:op_reg_data= {RW_CTRL, 24'h582c24};
245 111:op_reg_data= {RW_CTRL, 24'h582d24};
246 112:op_reg_data= {RW_CTRL, 24'h582e06};
247 113:op_reg_data= {RW_CTRL, 24'h582f22};
248 114:op_reg_data= {RW_CTRL, 24'h583040};
249 115:op_reg_data= {RW_CTRL, 24'h583142};
250 116:op_reg_data= {RW_CTRL, 24'h583224};
251 117:op_reg_data= {RW_CTRL, 24'h583326};
252 118:op_reg_data= {RW_CTRL, 24'h583424};
253 119:op_reg_data= {RW_CTRL, 24'h583522};
254 120:op_reg_data= {RW_CTRL, 24'h583622};
255 121:op_reg_data= {RW_CTRL, 24'h583726};
256 122:op_reg_data= {RW_CTRL, 24'h583844};
257 123:op_reg_data= {RW_CTRL, 24'h583924};
258 124:op_reg_data= {RW_CTRL, 24'h583a26};
259 125:op_reg_data= {RW_CTRL, 24'h583b28};
260 126:op_reg_data= {RW_CTRL, 24'h583c42};
261 127:op_reg_data= {RW_CTRL, 24'h583dce};// lenc BR offset // AWB 自动白平衡
262 128:op_reg_data= {RW_CTRL, 24'h5180ff};// AWB B block
263 129:op_reg_data= {RW_CTRL, 24'h5181f2};// AWB control
264 130:op_reg_data= {RW_CTRL, 24'h518200};// [7:4] max local counter, [3:0] max fast counter
265 131:op_reg_data= {RW_CTRL, 24'h518314};// AWB advanced
266 132:op_reg_data= {RW_CTRL, 24'h518425};
267 133:op_reg_data= {RW_CTRL, 24'h518524};
268 134:op_reg_data= {RW_CTRL, 24'h518609};
269 135:op_reg_data= {RW_CTRL, 24'h518709};
270 136:op_reg_data= {RW_CTRL, 24'h518809};
271 137:op_reg_data= {RW_CTRL, 24'h518975};
272 138:op_reg_data= {RW_CTRL, 24'h518a54};
273 139:op_reg_data= {RW_CTRL, 24'h518be0};
274 140:op_reg_data= {RW_CTRL, 24'h518cb2};
275 141:op_reg_data= {RW_CTRL, 24'h518d42};
276 142:op_reg_data= {RW_CTRL, 24'h518e3d};
277 143:op_reg_data= {RW_CTRL, 24'h518f56};
278 144:op_reg_data= {RW_CTRL, 24'h519046};
279 145:op_reg_data= {RW_CTRL, 24'h5191f8};// AWB top limit
280 146:op_reg_data= {RW_CTRL, 24'h519204};// AWB bottom limit
281 147:op_reg_data= {RW_CTRL, 24'h519370};// red limit
282 148:op_reg_data= {RW_CTRL, 24'h5194f0};// green limit
283 149:op_reg_data= {RW_CTRL, 24'h5195f0};// blue limit
284 150:op_reg_data= {RW_CTRL, 24'h519603};// AWB control
285 151:op_reg_data= {RW_CTRL, 24'h519701};// local limit
286 152:op_reg_data= {RW_CTRL, 24'h519804};
287 153:op_reg_data= {RW_CTRL, 24'h519912};
288 154:op_reg_data= {RW_CTRL, 24'h519a04};
289 155:op_reg_data= {RW_CTRL, 24'h519b00};
290 156:op_reg_data= {RW_CTRL, 24'h519c06};
291 157:op_reg_data= {RW_CTRL, 24'h519d82};
292 158:op_reg_data= {RW_CTRL, 24'h519e38};// AWB control // Gamma 伽玛曲线
293 159:op_reg_data= {RW_CTRL, 24'h548001};// Gamma bias plus on, bit[0]
294 160:op_reg_data= {RW_CTRL, 24'h548108};
295 161:op_reg_data= {RW_CTRL, 24'h548214};
296 162:op_reg_data= {RW_CTRL, 24'h548328};
297 163:op_reg_data= {RW_CTRL, 24'h548451};
298 164:op_reg_data= {RW_CTRL, 24'h548565};
299 165:op_reg_data= {RW_CTRL, 24'h548671};
300 166:op_reg_data= {RW_CTRL, 24'h54877d};
301 167:op_reg_data= {RW_CTRL, 24'h548887};
302 168:op_reg_data= {RW_CTRL, 24'h548991};
303 169:op_reg_data= {RW_CTRL, 24'h548a9a};
304 170:op_reg_data= {RW_CTRL, 24'h548baa};
305 171:op_reg_data= {RW_CTRL, 24'h548cb8};
306 172:op_reg_data= {RW_CTRL, 24'h548dcd};
307 173:op_reg_data= {RW_CTRL, 24'h548edd};
308 174:op_reg_data= {RW_CTRL, 24'h548fea};
309 175:op_reg_data= {RW_CTRL, 24'h54901d};// color matrix 色彩矩阵
310 176:op_reg_data= {RW_CTRL, 24'h53811e};// CMX1 for Y
311 177:op_reg_data= {RW_CTRL, 24'h53825b};// CMX2 for Y
312 178:op_reg_data= {RW_CTRL, 24'h538308};// CMX3 for Y
313 179:op_reg_data= {RW_CTRL, 24'h53840a};// CMX4 for U
314 180:op_reg_data= {RW_CTRL, 24'h53857e};// CMX5 for U
315 181:op_reg_data= {RW_CTRL, 24'h538688};// CMX6 for U
316 182:op_reg_data= {RW_CTRL, 24'h53877c};// CMX7 for V
317 183:op_reg_data= {RW_CTRL, 24'h53886c};// CMX8 for V
318 184:op_reg_data= {RW_CTRL, 24'h538910};// CMX9 for V
319 185:op_reg_data= {RW_CTRL, 24'h538a01};// sign[9]
320 186:op_reg_data= {RW_CTRL, 24'h538b98}; // sign[8:1] // UV adjust UV色彩饱和度调整
321 187:op_reg_data= {RW_CTRL, 24'h558006};// saturation on, bit[1]
322 188:op_reg_data= {RW_CTRL, 24'h558340};
323 189:op_reg_data= {RW_CTRL, 24'h558410};
324 190:op_reg_data= {RW_CTRL, 24'h558910};
325 191:op_reg_data= {RW_CTRL, 24'h558a00};
326 192:op_reg_data= {RW_CTRL, 24'h558bf8};
327 193:op_reg_data= {RW_CTRL, 24'h501d40};// enable manual offset of contrast// CIP 锐化和降噪
328 194:op_reg_data= {RW_CTRL, 24'h530008};// CIP sharpen MT threshold 1
329 195:op_reg_data= {RW_CTRL, 24'h530130};// CIP sharpen MT threshold 2
330 196:op_reg_data= {RW_CTRL, 24'h530210};// CIP sharpen MT offset 1
331 197:op_reg_data= {RW_CTRL, 24'h530300};// CIP sharpen MT offset 2
332 198:op_reg_data= {RW_CTRL, 24'h530408};// CIP DNS threshold 1
333 199:op_reg_data= {RW_CTRL, 24'h530530};// CIP DNS threshold 2
334 200:op_reg_data= {RW_CTRL, 24'h530608};// CIP DNS offset 1
335 201:op_reg_data= {RW_CTRL, 24'h530716};// CIP DNS offset 2
336 202:op_reg_data= {RW_CTRL, 24'h530908};// CIP sharpen TH threshold 1
337 203:op_reg_data= {RW_CTRL, 24'h530a30};// CIP sharpen TH threshold 2
338 204:op_reg_data= {RW_CTRL, 24'h530b04};// CIP sharpen TH offset 1
339 205:op_reg_data= {RW_CTRL, 24'h530c06};// CIP sharpen TH offset 2
340 206:op_reg_data= {RW_CTRL, 24'h502500};
341 207:op_reg_data= {RW_CTRL, 24'h300802}; // wake up from standby, bit[6]
342
343 //set OV5640 to video mode 720p
344 208:op_reg_data= {RW_CTRL, 24'h303521};// PLL input clock =24Mhz, PCLK =84Mhz
345 209:op_reg_data= {RW_CTRL, 24'h303669};// PLL
346 210:op_reg_data= {RW_CTRL, 24'h3c0707}; // lightmeter 1 threshold[7:0]
347 211:op_reg_data= {RW_CTRL, 24'h382047}; // flip
348 212:op_reg_data= {RW_CTRL, 24'h382100}; // mirror
349 213:op_reg_data= {RW_CTRL, 24'h381431}; // timing X inc
350 214:op_reg_data= {RW_CTRL, 24'h381531}; // timing Y inc
351 215:op_reg_data= {RW_CTRL, 24'h380000}; // HS
352 216:op_reg_data= {RW_CTRL, 24'h380100}; // HS
353 217:op_reg_data= {RW_CTRL, 24'h380200}; // VS
354 218:op_reg_data= {RW_CTRL, 24'h3803fa}; // VS
355 219:op_reg_data= {RW_CTRL, 24'h38040a}; // HW (HE)
356 220:op_reg_data= {RW_CTRL, 24'h38053f}; // HW (HE)
357 221:op_reg_data= {RW_CTRL, 24'h380606}; // VH (VE)
358 222:op_reg_data= {RW_CTRL, 24'h3807a9}; // VH (VE)
359 223:op_reg_data= {RW_CTRL, 24'h380805}; // DVPHO (1280)
360 224:op_reg_data= {RW_CTRL, 24'h380900}; // DVPHO (1280)
361 225:op_reg_data= {RW_CTRL, 24'h380a02}; // DVPVO (720)->
362 226:op_reg_data= {RW_CTRL, 24'h380bd0}; // DVPVO (720)->
363 227:op_reg_data= {RW_CTRL, 24'h380c07}; // HTS
364 228:op_reg_data= {RW_CTRL, 24'h380d64}; // HTS
365 229:op_reg_data= {RW_CTRL, 24'h380e02}; // VTS
366 230:op_reg_data= {RW_CTRL, 24'h380fe4}; // VTS
367 231:op_reg_data= {RW_CTRL, 24'h381304}; // timing V offset
368 232:op_reg_data= {RW_CTRL, 24'h361800};
369 233:op_reg_data= {RW_CTRL, 24'h361229};
370 234:op_reg_data= {RW_CTRL, 24'h370952};
371 235:op_reg_data= {RW_CTRL, 24'h370c03};
372 236:op_reg_data= {RW_CTRL, 24'h3a0202}; // 60Hz max exposure
373 237:op_reg_data= {RW_CTRL, 24'h3a03e0}; // 60Hz max exposure
374 238:op_reg_data= {RW_CTRL, 24'h3a0800}; // B50 step
375 239:op_reg_data= {RW_CTRL, 24'h3a096f}; // B50 step
376 240:op_reg_data= {RW_CTRL, 24'h3a0a00}; // B60 step
377 241:op_reg_data= {RW_CTRL, 24'h3a0b5c}; // B60 step
378 242:op_reg_data= {RW_CTRL, 24'h3a0e06}; // 50Hz max band
379 243:op_reg_data= {RW_CTRL, 24'h3a0d08}; // 60Hz max band
380 244:op_reg_data= {RW_CTRL, 24'h3a1402}; // 50Hz max exposure
381 245:op_reg_data= {RW_CTRL, 24'h3a15e0}; // 50Hz max exposure
382 246:op_reg_data= {RW_CTRL, 24'h400402}; // BLC line number
383 247:op_reg_data= {RW_CTRL, 24'h30021c}; // reset JFIFO, SFIFO, JPG
384 248:op_reg_data= {RW_CTRL, 24'h3006c3}; // disable clock of JPEG2x, JPEG
385 249:op_reg_data= {RW_CTRL, 24'h471303}; // JPEG mode 3
386 250:op_reg_data= {RW_CTRL, 24'h440704}; // Quantization sacle
387 251:op_reg_data= {RW_CTRL, 24'h460b37};
388 252:op_reg_data= {RW_CTRL, 24'h460c20};
389 253:op_reg_data= {RW_CTRL, 24'h483716}; // MIPI global timing
390 254:op_reg_data= {RW_CTRL, 24'h382404}; // PCLK manual divider
391 255:op_reg_data= {RW_CTRL, 24'h5001a3}; // SDE on, CMX on, AWB on, scale on
392 256:op_reg_data= {RW_CTRL, 24'h350300}; // AEC/AGC on
393 257:op_reg_data= {RW_CTRL, 24'h301602}; //Strobe output enable
394 258:op_reg_data= {RW_CTRL, 24'h3b070a}; //FREX strobe mode1
395 //strobe flash and frame exposure
396 259:op_reg_data={RW_CTRL, 24'h3b0083}; //STROBE CTRL: strobe request ON, Strobe mode: LED3
397 260:op_reg_data={RW_CTRL, 24'h3b0000}; //STROBE CTRL: strobe request OFF
398
399 default:op_reg_data={RW_CTRL, 24'h000000};
400 endcase
401 end
402
403
404 endmodule
405
上电时序模块:
> 1 `timescale 1ns / 1ps
2
3
4 module setup(
5 input clk,//50MHZ
6 input rst_n,
7 output reg init_en,
8
9 output reg ov_pwdn1,
10 output reg ov_rst_n1,
11 output reg ov_pwdn2,
12 output reg ov_rst_n2
13 );
14
15 parameter MS_CYC = 50_000;
16
17 reg [16-1:0] ms_cnt;
18 wire add_ms_cnt;
19 wire end_ms_cnt;
20 reg [ (5-1):0] wait_cnt ;
21 wire add_wait_cnt ;
22 wire end_wait_cnt ;
23 reg [5-1:0] N;
24 reg [ (2-1):0] phase_cnt ;
25 wire add_phase_cnt ;
26 wire end_phase_cnt ;
27 reg setup_done;
28
29
30 //ms计数
31 always @(posedge clk or negedge rst_n)begin
32 if(!rst_n)begin
33 ms_cnt <= 0;
34 end
35 else if(add_ms_cnt)begin
36 if(end_ms_cnt)
37 ms_cnt <= 0;
38 else
39 ms_cnt <= ms_cnt + 1;
40 end
41 end
42
43 assign add_ms_cnt = !setup_done;
44 assign end_ms_cnt = add_ms_cnt && ms_cnt== MS_CYC-1; //1_000_000/20 = 50_000
45
46 always @(posedge clk or negedge rst_n) begin
47 if (rst_n==0) begin
48 wait_cnt <= 0;
49 end
50 else if(add_wait_cnt) begin
51 if(end_wait_cnt)
52 wait_cnt <= 0;
53 else
54 wait_cnt <= wait_cnt+1 ;
55 end
56 end
57 assign add_wait_cnt = (end_ms_cnt);
58 assign end_wait_cnt = add_wait_cnt && wait_cnt == (N)-1 ;
59
60 always @(posedge clk or negedge rst_n) begin
61 if (rst_n==0) begin
62 phase_cnt <= 0;
63 end
64 else if(add_phase_cnt) begin
65 if(end_phase_cnt)
66 phase_cnt <= 0;
67 else
68 phase_cnt <= phase_cnt+1 ;
69 end
70 end
71 assign add_phase_cnt = (end_wait_cnt);
72 assign end_phase_cnt = add_phase_cnt && phase_cnt == (3)-1 ;
73
74 always @(posedge clk or negedge rst_n)begin
75 if(rst_n==1'b0)begin
76 setup_done <= 0;
77 end
78 else if(end_phase_cnt)begin
79 setup_done <= 1;
80 end
81 end
82
83
84 always@(*)begin
85 case(phase_cnt)
86 0:N = 5;
87 1:N = 2;
88 2:N = 21;
89 default:;
90 endcase
91 end
92
93 //信号逻辑
94 always @(posedge clk or negedge rst_n)begin
95 if(rst_n==1'b0)begin
96 ov_pwdn1 <= 1;
97 ov_pwdn2 <= 1;
98 end
99 else if(add_phase_cnt && phase_cnt == 0)begin
100 ov_pwdn1 <= 0;
101 ov_pwdn2 <= 0;
102 end
103 end
104
105 always @(posedge clk or negedge rst_n)begin
106 if(rst_n==1'b0)begin
107 ov_rst_n1 <= 0;
108 ov_rst_n2 <= 0;
109 end
110 else if(add_phase_cnt && phase_cnt == 1)begin
111 ov_rst_n1 <= 1;
112 ov_rst_n2 <= 1;
113 end
114 end
115
116 always @(posedge clk or negedge rst_n)begin
117 if(rst_n==1'b0)begin
118 init_en <= 0;
119 end
120 else if(end_phase_cnt)begin
121 init_en <= 1;
122 end
123 end
124
125
126 endmodule
以下是生成原理图结构及仿真波形:
下面完成最重要的板级调试,先测试SCCB读,再测试SCCB写。
读状态下SIOD信号有响应,并非所有寄存器数据均为0,说明SCCB_interface模块将摄像头内部寄存器初始值读出。接下来把寄存器配置模块WR_CTRL设置为2'b11,检测读取数据是否与写入一致,从而进一步验证SCCB读写时序。
写入数据状态下,第9bit SIO_D信号被从机拉低,从机收到完整字节数据。这再次说明了SCCB的本质就是IIC。读取数据与写入数据基本一致,说明SCCB读写时序无误。现在在是PCLK时钟域下抓取VSYNC HREF DATA波形,ILA可以稳定启动并捕获到信号与DVP接口时序一致,此时摄像头正常工作。
配置完成后开始采集RGB数据。根据RGB565时序,每两个字节数据组成一个像素数据,因此采集输出过程中只需将PCLK时钟上升沿得到的两个数据拼接为16bit像素数据即可。
- 没落骑士 - 博客园