這篇文章主要介紹一下verilog讀ov7670的出廠序列號
讀時序共分為五個部分
- 首先發送start,然后發送OV7670的器件地址,ov6070的ID是0x42,0x42+一位響應位
- 發送ov7670的寄存器地址,這里可以讀取它的廠商識別號 ,比如1c 發送八位寄存器+接受一位響應位
- ov7670的SCCB時序不同與iic時序,在發送完第一個部分需要比iic時序多發送一個stop,那就是stop+start
- 再次發送ov7670的器件地址,這次需要指定讀寫,第八位是讀寫控制位,0是寫,1是讀,即0x43+響應位
- 最后就是接受數據,需要注意的是最后不是響應位,而是NA,發送高電平即可,最后跟一個結束stop
ov7670管腳
- pwdn是睡眠模式,0工作,1睡眠
- rst_n 復位 低電平復位 高電平工作
- XCLK系統時鍾輸入 官方手冊推薦使用24M
- SCl IIC時鍾引腳 我用的是100K
- SDA IIC數據輸入
簡單的列一下程序
- 100K時鍾產生
IIC時鍾對時鍾要求不嚴格,所以采用進位的方法進行分頻,所產生的時鍾頻率略小於100K,
div_en是使能信號,如果采用使能時鍾可能會出現問題。
- 時序采用狀態機的方法一步步執行,相對比較直觀
- 響應標志位,因為數據位是雙向口,需要在響應時間設置位輸入
- 狀態機
//-------------------------------- //Funtion : sda_reg always @(posedge clk or negedge rst_n) begin if(!rst_n) begin iic_clk1 <= 1'd1; sda_reg <= 1'd1; riic_data <= 1'd0; end else if(dir == 1'b1) //read case(time_cnt) //idle 6'd0 : begin iic_clk1 <= 1'd1; sda_reg <= 1'd1; end //start 6'd1 :begin iic_clk1 <= 1'd1; sda_reg <= 1'd0; end 6'd2 :begin iic_clk1 <= 1'd0; sda_reg <= 1'd0; end //ID_addr 6'd3 : sda_reg <= wdata_reg[23]; 6'd4 : sda_reg <= wdata_reg[22]; 6'd5 : sda_reg <= wdata_reg[21]; 6'd6 : sda_reg <= wdata_reg[20]; 6'd7 : sda_reg <= wdata_reg[19]; 6'd8 : sda_reg <= wdata_reg[18]; 6'd9 : sda_reg <= wdata_reg[17]; 6'd10: sda_reg <= wdata_reg[16]; //ack 6'd11: iic_clk1<= 1'd0; 6'd12: ; 6'd13: iic_clk1<= 1'd0; //sub_addr 6'd14: sda_reg <= wdata_reg[15]; 6'd15: sda_reg <= wdata_reg[14]; 6'd16: sda_reg <= wdata_reg[13]; 6'd17: sda_reg <= wdata_reg[12]; 6'd18: sda_reg <= wdata_reg[11]; 6'd19: sda_reg <= wdata_reg[10]; 6'd20: sda_reg <= wdata_reg[9]; 6'd21: sda_reg <= wdata_reg[8]; //ack 6'd22: iic_clk1<= 1'd0; 6'd23: ; 6'd24: iic_clk1<= 1'd0; //stop 6'd25:begin iic_clk1 <= 1'd1; sda_reg <= 1'd0; end 6'd26:begin iic_clk1 <= 1'd1; sda_reg <= 1'd1; end //start 6'd27:begin iic_clk1 <= 1'd1; sda_reg <= 1'd1; end 6'd28:begin iic_clk1 <= 1'd1; sda_reg <= 1'd0; end //ID_addr 6'd29: sda_reg <= wdata_reg[7]; 6'd30: sda_reg <= wdata_reg[6]; 6'd31: sda_reg <= wdata_reg[5]; 6'd32: sda_reg <= wdata_reg[4]; 6'd33: sda_reg <= wdata_reg[3]; 6'd34: sda_reg <= wdata_reg[2]; 6'd35: sda_reg <= wdata_reg[1]; 6'd36: sda_reg <= wdata_reg[0]; //ack 6'd37: iic_clk1<= 1'd0; 6'd38: ; 6'd39: iic_clk1<= 1'd0; //read_data 6'd40: riic_data[7] <= iic_sda; 6'd41: riic_data[6] <= iic_sda; 6'd42: riic_data[5] <= iic_sda; 6'd43: riic_data[4] <= iic_sda; 6'd44: riic_data[3] <= iic_sda; 6'd45: riic_data[2] <= iic_sda; 6'd46: riic_data[1] <= iic_sda; 6'd47: riic_data[0] <= iic_sda; //nack 6'd48: sda_reg <= 1'd1; //stop 6'd49:begin iic_clk1 <= 1'd1; sda_reg <= 1'd0; end 6'd50:begin iic_clk1 <= 1'd1; sda_reg <= 1'd1; end default : begin iic_clk1 <= 1'd1; sda_reg <= 1'd1; end endcase end
- iic_clk和iic_sda
sda是雙向端口,在輸入的1時候設置為高阻態
dir是讀寫方向控制段,這里只是讀所以置一
- sigtab抓取數據