赞
踩
<1>OV5640 的控制寄存器,它根据这些寄存器配置的参数来运行,而这些参数是由外部控制器通过 SIO_C 和 SIO_D 引脚写入的, SIO_C与 SIO_D 使用的通讯协议跟 I2C十分类似。
<2>OV5640的通信、控制信号及外部时钟,其中 PCLK、 HREF 及VSYNC分别是像素同步时钟、行同步信号以及帧同步信号,这与液晶屏控制中的信号是很类似的。 RESETB引脚为低电平时,用于复位整个传感器芯片,PWDN 用于控制芯片进入低功耗模式。注意最后的一个 XCLK引脚,它跟 PCLK
是完全不同的, XCLK 是用于驱动整个传感器芯片的时钟信号,是外部输入到OV5640的信号;而 PCLK是 OV5640输出数据时的同步信号,它是由 OV5640 输出的信号。 XCLK可以外接晶振或由外部控制器提供。
<3>感光矩阵,光信号在这里转化成电信号,经过各种处理,这些信号存储成由一个个像素点表示的数字图像。
<4>包含了 DSP 处理单元,它会根据控制寄存器的配置做一些基本的图像处理运算。这部分还包含了图像格式转换单元及压缩单元,转换出的数据最终通过Y0-Y9引脚输出,一般来说我们使用 8根据数据线来传输,这时仅使用 Y2-Y9 引脚。
<5>VCM 处理单元,他会通过图像分析来实现图像的自动对焦功能。要实现自动对焦还需要下载自动对焦固件到模组,后面摄像头实验详细介绍这个功能。
注意:当主机向从机进行指令或数据的写入时,串行数据线SDA上的数据在串行时钟SCL
为高电平时写入从机设备,每次只写入一位数据;串行数据线SDA中的数据在串行时钟
SCL为低电平时进行数据更新,以保证在SCL为高电平时采集到SDA数据的稳定状态。
module Power_ctrl #( parameter CNT_5MS = 20'd250_000, parameter CNT_1MS = 20'd50_000, parameter CNT_20MS = 20'd1000_000 ) ( input wire sys_clk, input wire rst, output wire pwdn, output wire resetb, output wire sccb_en, output wire clk_en ); reg [20:0] cnt; assign pwdn = (cnt >= CNT_5MS - 1'd1)?1'd0:1'd1; assign resetb = (cnt >= CNT_5MS + CNT_1MS - 1'd1)?1'd1:1'd0; assign sccb_en = (cnt >= (CNT_5MS + CNT_1MS + CNT_20MS - 1'd1))?1'd1:1'd0; assign clk_en = (cnt >= CNT_5MS - 1'd1)?1'd1:1'd0; always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt <= 1'd0; else if(cnt == (CNT_5MS + CNT_1MS + CNT_20MS - 1'd1)) cnt <= cnt; else cnt <= cnt + 1'd1; endmodule
IIC:
SSCB:
读程序验证以读ID来实现:
时序图:
Start:是用来启动读的标志位,为1时有效 statue:一共13个状态 cnt:这是一个用来统计scl周期个数的变量 cnt_stop_flag:在STOP状态下,需要先用到2个周期来完成STOP的操作,这时cnt_stop_flag为0,当完成后cnt_stop_flag置1 cnt_stop:用来对STOP状态下的计时 I2C_CLK_x:这是一个用来仿真验证的波形,它与scl相差135°的相位,在它的下降沿sda发生改变 cnt_clkx:统计I2C_CLK_x一个周期所需的计数值 cnt_clkx_flag:在cnt_clkx下降沿的前一个周期置一,下降沿处置零 I2C_SDA:sda信号线 Data:{ID,ADD},24位 I2C_CLK:就是SCL data_flag:DATA状态下,在数据稳定的地方置1一个周期,用来判断什么时候读数据 data:读出的数据 cnt_clk:统计I2C_CLK一个周期所需的计数值 cnt_clkx_flag:在I2C_CLK下降沿的前一个周期置一,下降沿处置零 read_en:结束一次读操作的标志
由于在SSCB时序开始时是sda先产生下降沿,且sda的数据需在scl高电平时保持稳定,所以采用135°相位差的方法来完成,135不是固定的,可以进行一定的修改,sda数据在每个I2C_CLK_x下降沿处改变,在数据发送和接收状态时,每次发8个数据,然后就就进入下一状态,在这里有个问题就是ID号的第八位是省去的,实际的ID就是七位,因为之前没注意,导致第一次仿真无误后上板时出错,查阅资料发现IIC的应答阶段与SSCB不太一样,其实也差不多,就是SSCB的应答处理你可以不用判断是否应答成功,因为SSCB不一定为返回给你正确的应答值,本程序的x表示为应答状态,即不关心状态,在STOP状态时,先利用好两个周期的时间来完成STOP的操作,然后又是和开头的操作一样,重新开始,然后发读的ID,本程序中,sda在所有的x状态和DATA状态都为1’dz,接着开始读数据即可,然后进行NO ACK操作,sda主动置为高电平,完成后就再进行一次STOP操作,结束整个读操作。(注意:SSCB没有IIC的连续读和连续写)
开始位:
停止位:
上面两图第一个信号是scl,第二个是sda
module SSCB_ID ( input wire sys_clk, input wire rst, input wire read_en, input wire [15:0] addr, input wire [7:0] ID, input wire sda_rd, output reg sda, output reg scl, output reg read_end, output reg [7:0] Data_reg, output reg [12:0] statue, output wire [23:0] Cmd ); localparam IDLE = 13'b0_0000_0000_0001, START_ID1 = 13'b0_0000_0000_0010, x_ack1 = 13'b0_0000_0000_0100, ADD_H = 13'b0_0000_0000_1000, x_ack2 = 13'b0_0000_0001_0000, ADD_L = 13'b0_0000_0010_0000, x_ack3 = 13'b0_0000_0100_0000, STOP = 13'b0_0000_1000_0000, START_ID2 = 13'b0_0001_0000_0000, x_ack4 = 13'b0_0010_0000_0000, DATA = 13'b0_0100_0000_0000, NO = 13'b0_1000_0000_0000, END = 13'b1_0000_0000_0000; localparam CLOCK = 30'd50_000_000, I2C_CLK = 30'd400_000, START_MAX = (CLOCK/I2C_CLK)*3/4 - 1'd1, MAX = CLOCK/I2C_CLK - 1'd1, MAX_2 = (CLOCK/I2C_CLK)/2 - 1'd1; //wire [23:0] Cmd; //reg sda; assign Cmd = {ID,addr}; //reg sda; reg [20:0] cnt; reg [20:0] cnt_stop; reg cnt_stop_flag; reg I2C_CLK_x; reg [20:0] cnt_CLKx; reg cnt_clkx_flag; reg data_flag; reg [20:0] cnt_clk; reg cnt_clk_flag; //结束标志 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) read_end <= 1'd0; else if(statue == END && cnt_clk == MAX - 1'd1) read_end <= 1'd1; else read_end <= 1'd0; //相移135°的I2C信号计数 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_CLKx <= 1'd0; else if(cnt_CLKx == MAX) cnt_CLKx <= 1'd0; else if(read_en == 1'd1 && (statue == STOP) && cnt_stop_flag == 1'd1) cnt_CLKx <= cnt_CLKx + 1'd1; else if(read_en == 1'd1 && (statue !=STOP) && statue != NO && statue != END) cnt_CLKx <= cnt_CLKx + 1'd1; else cnt_CLKx <= 1'd0; //相移135°的I2C信号周期更替标志 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_clkx_flag <= 1'd0; else if(cnt_CLKx == MAX - 1'd1) cnt_clkx_flag <= 1'd1; else cnt_clkx_flag <= 1'd0; //相移135°的I2C信号产生 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) I2C_CLK_x <= 1'd1; else if((statue == STOP && cnt_stop_flag != 1'd1) || (statue == x_ack3 && cnt_clkx_flag == 1'd1) || (statue == DATA && cnt == 6'd8 && cnt_clkx_flag == 1'd1) || (statue == NO && statue == END)) I2C_CLK_x <= 1'd1; else if(cnt_CLKx <= MAX_2 -1'd1 && read_en == 1'd1) I2C_CLK_x <= 1'd0; else if(cnt_CLKx <= MAX - 1'd1 && read_en == 1'd1) I2C_CLK_x <= 1'd1; else if(read_en != 1'd1) I2C_CLK_x <= 1'd1; //STOP状态时的计数停 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_stop_flag <= 1'd0; else if(statue == STOP && cnt == 2'd2 && cnt_stop == MAX) cnt_stop_flag <= 1'd1; else if(statue == START_ID2) cnt_stop_flag <= 1'd0; //STOP状态下让I2C总线停止两个周期的计 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_stop <= 1'd0; else if(statue == STOP && cnt_stop == MAX) cnt_stop <= 1'd0; else if(statue == STOP && cnt_stop_flag != 1'd1) cnt_stop <= cnt_stop + 1'd1; else cnt_stop <= 1'd0; //SCL时钟生成 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_clk <= 1'd0; else if(statue == STOP || statue == IDLE) cnt_clk <= 1'd0; else if(cnt_clk == MAX) cnt_clk <= 1'd0; else cnt_clk <= cnt_clk + 1'd1; //SCL时钟生成 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) scl <= 1'd1; else if(statue == END && cnt_clk_flag == 1'd1) scl <= 1'd1; else if(statue == STOP || (statue == x_ack3 && cnt_clkx_flag == 1'd1)) scl <= 1'd1; else if(statue == STOP && cnt_stop_flag == 1'd1 && cnt_clkx_flag == 1'd1) scl <= 1'd0; else if(statue == IDLE && cnt_CLKx == START_MAX) scl <= 1'd0; else if(cnt_clk <= MAX_2 && read_en == 1'd1 && statue != IDLE) scl <= 1'd0; else if(cnt_clk < MAX && read_en == 1'd1 && statue != IDLE) scl <= 1'd1; else if(cnt_clk == MAX && read_en == 1'd1 && statue != IDLE) scl <= 1'd0; else if(read_en != 1'd1) scl <= 1'd1; //全局计数 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt <= 1'd0; else if(statue == STOP) begin if(cnt_stop == MAX && cnt == 2'd2) cnt <= 1'd0; else if(cnt_stop == MAX) cnt <= cnt + 1'd1; else cnt <= cnt; end else if(statue == NO && statue == END) cnt <= 1'd0; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) cnt <= 1'd0; else if(cnt_clkx_flag == 1'd1) cnt <= cnt + 1'd1; else cnt <= cnt; //I2C信号周期更替标志 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_clk_flag <= 1'd0; else if(cnt_clk == MAX - 1'd1) cnt_clk_flag <= 1'd1; else cnt_clk_flag <= 1'd0; //data数据记录标志 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) data_flag <= 1'd0; else if(statue == DATA && cnt_clk == START_MAX) data_flag <= 1'd1; else data_flag <= 1'd0; //数据存储 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) Data_reg <= 1'd0; else if(statue == DATA && data_flag == 1'd1) Data_reg <= {Data_reg[6:0],sda_rd}; else Data_reg <= Data_reg; //状态机跳转 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) statue <= IDLE; else case(statue) IDLE: if(read_en == 1'd1 && cnt_CLKx == START_MAX) statue <= START_ID1; START_ID1: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= x_ack1; x_ack1: if(cnt_clkx_flag == 1'd1) statue <= ADD_H; ADD_H: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= x_ack2; x_ack2: if(cnt_clkx_flag == 1'd1) statue <= ADD_L; ADD_L: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= x_ack3; x_ack3: if(cnt_clkx_flag == 1'd1) statue <= STOP; STOP: if(cnt_stop_flag == 1'd1 && cnt_CLKx == START_MAX) statue <= START_ID2; START_ID2: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= x_ack4; x_ack4: if(cnt_clkx_flag == 1'd1) statue <= DATA; DATA: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= NO; NO: if(cnt_clk_flag == 1'd1) statue <= END; END: if(cnt_clk_flag == 1'd1) statue <= IDLE; default:statue <= IDLE; endcase always@(posedge sys_clk or negedge rst) if(rst == 1'd0) sda <= 1'd1; else case(statue) IDLE: if(read_en == 1'd1) sda <= 1'd0; else sda <= 1'd1; START_ID1: if(cnt_clkx_flag == 1'd1 && cnt < 6'd7) sda <= Cmd[22 - cnt]; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd7) sda <= 1'd0; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd0; x_ack1: if(cnt_clkx_flag == 1'd1) sda <= Cmd[15 - cnt]; ADD_H: if(cnt_clkx_flag == 1'd1 && cnt <= 6'd7) sda <= Cmd[15 - cnt]; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd0; x_ack2: if(cnt_clkx_flag == 1'd1) sda <= Cmd[7 - cnt]; ADD_L: if(cnt_clkx_flag == 1'd1 && cnt <= 6'd7) sda <= Cmd[7 - cnt]; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd0; x_ack3: if(cnt_clkx_flag == 1'd1) sda <= 1'd0; STOP: if(cnt_stop_flag != 1'd1 && cnt == 1'd0) sda <= 1'd0; else if(cnt_stop_flag == 1'd1) sda <= 1'd0; else sda <= 1'd1; START_ID2: if(cnt_clkx_flag == 1'd1 && cnt < 6'd7) sda <= Cmd[22 - cnt]; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd7) sda <= 1'd1; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd0; x_ack4: sda <= 1'd0; DATA: if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd1; else sda <= 1'd0; NO: if(cnt_clk_flag == 1'd1) sda <= 1'd0; else sda <= 1'd1; END: if(cnt_clk_flag == 1'd1) sda <= 1'd1; default:sda <= 1'd1; endcase /* assign sda_x = (statue == x_ack1 || statue == x_ack2 || statue == x_ack3 || statue == x_ack4 || (statue == DATA))?1'dz:sda; */ endmodule
结果演示:
IIC与SSCB通用
设置寄存器时会用到
module SSCB_WR ( input wire sys_clk, input wire rst, input wire WR_en, input wire [15:0] addr, input wire [7:0] ID, input wire [7:0] data, output reg sda, output reg scl, output reg WR_end, output reg [9:0] statue ); localparam IDLE = 10'b0000000001, START_ID1 = 10'b0000000010, x_ack1 = 10'b0000000100, ADD_H = 10'b0000001000, x_ack2 = 10'b0000010000, ADD_L = 10'b0000100000, x_ack3 = 10'b0001000000, DATA = 10'b0010000000, x_ack4 = 10'b0100000000, END = 10'b1000000000; localparam CLOCK = 30'd50_000_000, I2C_CLK = 30'd400_000, START_MAX = (CLOCK/I2C_CLK)*3/4 - 1'd1, MAX = CLOCK/I2C_CLK - 1'd1, MAX_2 = (CLOCK/I2C_CLK)/2 - 1'd1; wire [23:0] Cmd; //reg sda; assign Cmd = {ID,addr}; reg [20:0] cnt; reg I2C_CLK_x; reg [20:0] cnt_CLKx; reg cnt_clkx_flag; reg [20:0] cnt_clk; reg cnt_clk_flag; //结束标志 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) WR_end <= 1'd0; else if(statue == END && cnt_clk == MAX - 1'd1) WR_end <= 1'd1; else WR_end <= 1'd0; //相移135°的I2C信号计数 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_CLKx <= 1'd0; else if(cnt_CLKx == MAX) cnt_CLKx <= 1'd0; else if(WR_en == 1'd1 && statue != x_ack4 && statue != END) cnt_CLKx <= cnt_CLKx + 1'd1; else cnt_CLKx <= 1'd0; //相移135°的I2C信号周期更替标志 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_clkx_flag <= 1'd0; else if(cnt_CLKx == MAX - 1'd1) cnt_clkx_flag <= 1'd1; else cnt_clkx_flag <= 1'd0; //相移135°的I2C信号产生 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) I2C_CLK_x <= 1'd1; else if((statue == DATA && cnt == 6'd8 && cnt_clkx_flag == 1'd1) || (statue == x_ack4 && statue == END)) I2C_CLK_x <= 1'd1; else if(cnt_CLKx <= MAX_2 -1'd1 && WR_en == 1'd1) I2C_CLK_x <= 1'd0; else if(cnt_CLKx <= MAX - 1'd1 && WR_en == 1'd1) I2C_CLK_x <= 1'd1; else if(WR_en != 1'd1) I2C_CLK_x <= 1'd1; //SCL时钟生成 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_clk <= 1'd0; else if(statue == IDLE) cnt_clk <= 1'd0; else if(cnt_clk == MAX) cnt_clk <= 1'd0; else cnt_clk <= cnt_clk + 1'd1; //SCL时钟生成 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) scl <= 1'd1; else if(statue == END && cnt_clk_flag == 1'd1) scl <= 1'd1; else if(statue == IDLE && cnt_CLKx == START_MAX) scl <= 1'd0; else if(cnt_clk <= MAX_2 && WR_en == 1'd1 && statue != IDLE) scl <= 1'd0; else if(cnt_clk < MAX && WR_en == 1'd1 && statue != IDLE) scl <= 1'd1; else if(cnt_clk == MAX && WR_en == 1'd1 && statue != IDLE) scl <= 1'd0; else if(WR_en != 1'd1) scl <= 1'd1; //全局计数 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt <= 1'd0; else if(statue == x_ack4 && statue == END) cnt <= 1'd0; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) cnt <= 1'd0; else if(cnt_clkx_flag == 1'd1) cnt <= cnt + 1'd1; else cnt <= cnt; //I2C信号周期更替标志 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_clk_flag <= 1'd0; else if(cnt_clk == MAX - 1'd1) cnt_clk_flag <= 1'd1; else cnt_clk_flag <= 1'd0; //状态机跳转 always@(posedge sys_clk or negedge rst) if(rst == 1'd0) statue <= IDLE; else case(statue) IDLE: if(WR_en == 1'd1 && cnt_CLKx == START_MAX) statue <= START_ID1; START_ID1: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= x_ack1; x_ack1: if(cnt_clkx_flag == 1'd1) statue <= ADD_H; ADD_H: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= x_ack2; x_ack2: if(cnt_clkx_flag == 1'd1) statue <= ADD_L; ADD_L: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= x_ack3; x_ack3: if(cnt_clkx_flag == 1'd1) statue <= DATA; DATA: if(cnt == 8'd8 && cnt_clkx_flag == 1'd1) statue <= x_ack4; x_ack4: if(cnt_clk_flag == 1'd1) statue <= END; END: if(cnt_clk_flag == 1'd1) statue <= IDLE; default:statue <= IDLE; endcase always@(posedge sys_clk or negedge rst) if(rst == 1'd0) sda <= 1'd1; else case(statue) IDLE: if(WR_en == 1'd1) sda <= 1'd0; else sda <= 1'd1; START_ID1: if(cnt_clkx_flag == 1'd1 && cnt < 6'd7) sda <= Cmd[22 - cnt]; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd7) sda <= 1'd0; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd0; x_ack1: if(cnt_clkx_flag == 1'd1) sda <= Cmd[15 - cnt]; ADD_H: if(cnt_clkx_flag == 1'd1 && cnt <= 6'd7) sda <= Cmd[15 - cnt]; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd0; x_ack2: if(cnt_clkx_flag == 1'd1) sda <= Cmd[7 - cnt]; ADD_L: if(cnt_clkx_flag == 1'd1 && cnt <= 6'd7) sda <= Cmd[7 - cnt]; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd0; x_ack3: if(cnt_clkx_flag == 1'd1) sda <= data[7 - cnt]; DATA: if(cnt_clkx_flag == 1'd1 && cnt <= 6'd7) sda <= data[7 - cnt]; else if(cnt_clkx_flag == 1'd1 && cnt == 6'd8) sda <= 1'd0; x_ack4: if(cnt_clk_flag == 1'd1) sda <= 1'd0; else sda <= 1'd0; END: if(cnt_clk_flag == 1'd1) sda <= 1'd1; default:sda <= 1'd1; endcase /* assign sda_x = (statue == x_ack1 || statue == x_ack2 || statue == x_ack3 || statue == x_ack4 || (statue == DATA))?1'dz:sda; */ endmodule
module OV5640_cfg ( input wire sys_clk, input wire rst, input wire start, input wire write_end, output wire [23:0] cfg_data, output reg WR_en, output reg init_end ); parameter REG_NUM = 8'd251 ; wire [23:0] cfg_data_reg[REG_NUM-1:0] ; reg [15:0] cnt; reg [8:0] number; reg cnt_en; parameter delay = 16'd9999; always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt_en <= 1'd0; else if(write_end == 1'd1 && init_end != 1'd1) cnt_en <= 1'd1; else if(cnt == delay) cnt_en <= 1'd0; else cnt_en <= cnt_en; always@(posedge sys_clk or negedge rst) if(rst == 1'd0) init_end <= 1'd0; else if(number == REG_NUM && cnt == delay) init_end <= 1'd1; always@(posedge sys_clk or negedge rst) if(rst == 1'd0) cnt <= 1'd0; else if(cnt == delay) cnt <= 1'd0; else if(WR_en != 1'd1 && start == 1'd1 && init_end != 1'd1 && cnt_en == 1'd1) cnt <= cnt + 1'd1; else cnt <= 1'd0; always@(posedge sys_clk or negedge rst) if(rst == 1'd0) number <= 1'd0; else if(write_end == 1'd1 && number != REG_NUM) number <= number + 1'd1; else number <= number; always@(posedge sys_clk or negedge rst) if(rst == 1'd0) WR_en <= 1'd0; else if(write_end == 1'd1) WR_en <= 1'd0; else if(number != REG_NUM && cnt == delay) WR_en <= 1'd1; else if(number == 1'd0 && start == 1'd1) WR_en <= 1'd1; assign cfg_data = (number != REG_NUM)?cfg_data_reg[number]:1'd0; //cfg_data_reg:寄存器配置数据暂存 ID REG_ADDR REG_VAL assign cfg_data_reg[000] = {16'h3103, 8'h11}; assign cfg_data_reg[001] = {16'h3008, 8'h82}; assign cfg_data_reg[002] = {16'h3008, 8'h42}; assign cfg_data_reg[003] = {16'h3103, 8'h03}; assign cfg_data_reg[004] = {16'h3017, 8'hff}; assign cfg_data_reg[005] = {16'h3018, 8'hff}; assign cfg_data_reg[006] = {16'h3034, 8'h1A}; assign cfg_data_reg[007] = {16'h3037, 8'h13}; assign cfg_data_reg[008] = {16'h3108, 8'h01}; assign cfg_data_reg[009] = {16'h3630, 8'h36}; assign cfg_data_reg[010] = {16'h3631, 8'h0e}; assign cfg_data_reg[011] = {16'h3632, 8'he2}; assign cfg_data_reg[012] = {16'h3633, 8'h12}; assign cfg_data_reg[013] = {16'h3621, 8'he0}; assign cfg_data_reg[014] = {16'h3704, 8'ha0}; assign cfg_data_reg[015] = {16'h3703, 8'h5a}; assign cfg_data_reg[016] = {16'h3715, 8'h78}; assign cfg_data_reg[017] = {16'h3717, 8'h01}; assign cfg_data_reg[018] = {16'h370b, 8'h60}; assign cfg_data_reg[019] = {16'h3705, 8'h1a}; assign cfg_data_reg[020] = {16'h3905, 8'h02}; assign cfg_data_reg[021] = {16'h3906, 8'h10}; assign cfg_data_reg[022] = {16'h3901, 8'h0a}; assign cfg_data_reg[023] = {16'h3731, 8'h12}; assign cfg_data_reg[024] = {16'h3600, 8'h08}; assign cfg_data_reg[025] = {16'h3601, 8'h33}; assign cfg_data_reg[026] = {16'h302d, 8'h60}; assign cfg_data_reg[027] = {16'h3620, 8'h52}; assign cfg_data_reg[028] = {16'h371b, 8'h20}; assign cfg_data_reg[029] = {16'h471c, 8'h50}; assign cfg_data_reg[030] = {16'h3a13, 8'h43}; assign cfg_data_reg[031] = {16'h3a18, 8'h00}; assign cfg_data_reg[032] = {16'h3a19, 8'hf8}; assign cfg_data_reg[033] = {16'h3635, 8'h13}; assign cfg_data_reg[034] = {16'h3636, 8'h03}; assign cfg_data_reg[035] = {16'h3634, 8'h40}; assign cfg_data_reg[036] = {16'h3622, 8'h01}; assign cfg_data_reg[037] = {16'h3c01, 8'h34}; assign cfg_data_reg[038] = {16'h3c04, 8'h28}; assign cfg_data_reg[039] = {16'h3c05, 8'h98}; assign cfg_data_reg[040] = {16'h3c06, 8'h00}; assign cfg_data_reg[041] = {16'h3c07, 8'h08}; assign cfg_data_reg[042] = {16'h3c08, 8'h00}; assign cfg_data_reg[043] = {16'h3c09, 8'h1c}; assign cfg_data_reg[044] = {16'h3c0a, 8'h9c}; assign cfg_data_reg[045] = {16'h3c0b, 8'h40}; assign cfg_data_reg[046] = {16'h3810, 8'h00}; assign cfg_data_reg[047] = {16'h3811, 8'h10}; assign cfg_data_reg[048] = {16'h3812, 8'h00}; assign cfg_data_reg[049] = {16'h3708, 8'h64}; assign cfg_data_reg[050] = {16'h4001, 8'h02}; assign cfg_data_reg[051] = {16'h4005, 8'h1a}; assign cfg_data_reg[052] = {16'h3000, 8'h00}; assign cfg_data_reg[053] = {16'h3004, 8'hff}; assign cfg_data_reg[054] = {16'h300e, 8'h58}; assign cfg_data_reg[055] = {16'h302e, 8'h00}; assign cfg_data_reg[056] = {16'h4300, 8'h61}; assign cfg_data_reg[057] = {16'h501f, 8'h01}; assign cfg_data_reg[058] = {16'h440e, 8'h00}; assign cfg_data_reg[059] = {16'h5000, 8'ha7}; assign cfg_data_reg[060] = {16'h3a0f, 8'h30}; assign cfg_data_reg[061] = {16'h3a10, 8'h28}; assign cfg_data_reg[062] = {16'h3a1b, 8'h30}; assign cfg_data_reg[063] = {16'h3a1e, 8'h26}; assign cfg_data_reg[064] = {16'h3a11, 8'h60}; assign cfg_data_reg[065] = {16'h3a1f, 8'h14}; assign cfg_data_reg[066] = {16'h5800, 8'h23}; assign cfg_data_reg[067] = {16'h5801, 8'h14}; assign cfg_data_reg[068] = {16'h5802, 8'h0f}; assign cfg_data_reg[069] = {16'h5803, 8'h0f}; assign cfg_data_reg[070] = {16'h5804, 8'h12}; assign cfg_data_reg[071] = {16'h5805, 8'h26}; assign cfg_data_reg[072] = {16'h5806, 8'h0c}; assign cfg_data_reg[073] = {16'h5807, 8'h08}; assign cfg_data_reg[074] = {16'h5808, 8'h05}; assign cfg_data_reg[075] = {16'h5809, 8'h05}; assign cfg_data_reg[076] = {16'h580a, 8'h08}; assign cfg_data_reg[077] = {16'h580b, 8'h0d}; assign cfg_data_reg[078] = {16'h580c, 8'h08}; assign cfg_data_reg[079] = {16'h580d, 8'h03}; assign cfg_data_reg[080] = {16'h580e, 8'h00}; assign cfg_data_reg[081] = {16'h580f, 8'h00}; assign cfg_data_reg[082] = {16'h5810, 8'h03}; assign cfg_data_reg[083] = {16'h5811, 8'h09}; assign cfg_data_reg[084] = {16'h5812, 8'h07}; assign cfg_data_reg[085] = {16'h5813, 8'h03}; assign cfg_data_reg[086] = {16'h5814, 8'h00}; assign cfg_data_reg[087] = {16'h5815, 8'h01}; assign cfg_data_reg[088] = {16'h5816, 8'h03}; assign cfg_data_reg[089] = {16'h5817, 8'h08}; assign cfg_data_reg[090] = {16'h5818, 8'h0d}; assign cfg_data_reg[091] = {16'h5819, 8'h08}; assign cfg_data_reg[092] = {16'h581a, 8'h05}; assign cfg_data_reg[093] = {16'h581b, 8'h06}; assign cfg_data_reg[094] = {16'h581c, 8'h08}; assign cfg_data_reg[095] = {16'h581d, 8'h0e}; assign cfg_data_reg[096] = {16'h581e, 8'h29}; assign cfg_data_reg[097] = {16'h581f, 8'h17}; assign cfg_data_reg[098] = {16'h5820, 8'h11}; assign cfg_data_reg[099] = {16'h5821, 8'h11}; assign cfg_data_reg[100] = {16'h5822, 8'h15}; assign cfg_data_reg[101] = {16'h5823, 8'h28}; assign cfg_data_reg[102] = {16'h5824, 8'h46}; assign cfg_data_reg[103] = {16'h5825, 8'h26}; assign cfg_data_reg[104] = {16'h5826, 8'h08}; assign cfg_data_reg[105] = {16'h5827, 8'h26}; assign cfg_data_reg[106] = {16'h5828, 8'h64}; assign cfg_data_reg[107] = {16'h5829, 8'h26}; assign cfg_data_reg[108] = {16'h582a, 8'h24}; assign cfg_data_reg[109] = {16'h582b, 8'h22}; assign cfg_data_reg[110] = {16'h582c, 8'h24}; assign cfg_data_reg[111] = {16'h582d, 8'h24}; assign cfg_data_reg[112] = {16'h582e, 8'h06}; assign cfg_data_reg[113] = {16'h582f, 8'h22}; assign cfg_data_reg[114] = {16'h5830, 8'h40}; assign cfg_data_reg[115] = {16'h5831, 8'h42}; assign cfg_data_reg[116] = {16'h5832, 8'h24}; assign cfg_data_reg[117] = {16'h5833, 8'h26}; assign cfg_data_reg[118] = {16'h5834, 8'h24}; assign cfg_data_reg[119] = {16'h5835, 8'h22}; assign cfg_data_reg[120] = {16'h5836, 8'h22}; assign cfg_data_reg[121] = {16'h5837, 8'h26}; assign cfg_data_reg[122] = {16'h5838, 8'h44}; assign cfg_data_reg[123] = {16'h5839, 8'h24}; assign cfg_data_reg[124] = {16'h583a, 8'h26}; assign cfg_data_reg[125] = {16'h583b, 8'h28}; assign cfg_data_reg[126] = {16'h583c, 8'h42}; assign cfg_data_reg[127] = {16'h583d, 8'hce}; assign cfg_data_reg[128] = {16'h5180, 8'hff}; assign cfg_data_reg[129] = {16'h5181, 8'hf2}; assign cfg_data_reg[130] = {16'h5182, 8'h00}; assign cfg_data_reg[131] = {16'h5183, 8'h14}; assign cfg_data_reg[132] = {16'h5184, 8'h25}; assign cfg_data_reg[133] = {16'h5185, 8'h24}; assign cfg_data_reg[134] = {16'h5186, 8'h09}; assign cfg_data_reg[135] = {16'h5187, 8'h09}; assign cfg_data_reg[136] = {16'h5188, 8'h09}; assign cfg_data_reg[137] = {16'h5189, 8'h75}; assign cfg_data_reg[138] = {16'h518a, 8'h54}; assign cfg_data_reg[139] = {16'h518b, 8'he0}; assign cfg_data_reg[140] = {16'h518c, 8'hb2}; assign cfg_data_reg[141] = {16'h518d, 8'h42}; assign cfg_data_reg[142] = {16'h518e, 8'h3d}; assign cfg_data_reg[143] = {16'h518f, 8'h56}; assign cfg_data_reg[144] = {16'h5190, 8'h46}; assign cfg_data_reg[145] = {16'h5191, 8'hf8}; assign cfg_data_reg[146] = {16'h5192, 8'h04}; assign cfg_data_reg[147] = {16'h5193, 8'h70}; assign cfg_data_reg[148] = {16'h5194, 8'hf0}; assign cfg_data_reg[149] = {16'h5195, 8'hf0}; assign cfg_data_reg[150] = {16'h5196, 8'h03}; assign cfg_data_reg[151] = {16'h5197, 8'h01}; assign cfg_data_reg[152] = {16'h5198, 8'h04}; assign cfg_data_reg[153] = {16'h5199, 8'h12}; assign cfg_data_reg[154] = {16'h519a, 8'h04}; assign cfg_data_reg[155] = {16'h519b, 8'h00}; assign cfg_data_reg[156] = {16'h519c, 8'h06}; assign cfg_data_reg[157] = {16'h519d, 8'h82}; assign cfg_data_reg[158] = {16'h519e, 8'h38}; assign cfg_data_reg[159] = {16'h5480, 8'h01}; assign cfg_data_reg[160] = {16'h5481, 8'h08}; assign cfg_data_reg[161] = {16'h5482, 8'h14}; assign cfg_data_reg[162] = {16'h5483, 8'h28}; assign cfg_data_reg[163] = {16'h5484, 8'h51}; assign cfg_data_reg[164] = {16'h5485, 8'h65}; assign cfg_data_reg[165] = {16'h5486, 8'h71}; assign cfg_data_reg[166] = {16'h5487, 8'h7d}; assign cfg_data_reg[167] = {16'h5488, 8'h87}; assign cfg_data_reg[168] = {16'h5489, 8'h91}; assign cfg_data_reg[169] = {16'h548a, 8'h9a}; assign cfg_data_reg[170] = {16'h548b, 8'haa}; assign cfg_data_reg[171] = {16'h548c, 8'hb8}; assign cfg_data_reg[172] = {16'h548d, 8'hcd}; assign cfg_data_reg[173] = {16'h548e, 8'hdd}; assign cfg_data_reg[174] = {16'h548f, 8'hea}; assign cfg_data_reg[175] = {16'h5490, 8'h1d}; assign cfg_data_reg[176] = {16'h5381, 8'h1e}; assign cfg_data_reg[177] = {16'h5382, 8'h5b}; assign cfg_data_reg[178] = {16'h5383, 8'h08}; assign cfg_data_reg[179] = {16'h5384, 8'h0a}; assign cfg_data_reg[180] = {16'h5385, 8'h7e}; assign cfg_data_reg[181] = {16'h5386, 8'h88}; assign cfg_data_reg[182] = {16'h5387, 8'h7c}; assign cfg_data_reg[183] = {16'h5388, 8'h6c}; assign cfg_data_reg[184] = {16'h5389, 8'h10}; assign cfg_data_reg[185] = {16'h538a, 8'h01}; assign cfg_data_reg[186] = {16'h538b, 8'h98}; assign cfg_data_reg[187] = {16'h5580, 8'h06}; assign cfg_data_reg[188] = {16'h5583, 8'h40}; assign cfg_data_reg[189] = {16'h5584, 8'h10}; assign cfg_data_reg[190] = {16'h5589, 8'h10}; assign cfg_data_reg[191] = {16'h558a, 8'h00}; assign cfg_data_reg[192] = {16'h558b, 8'hf8}; assign cfg_data_reg[193] = {16'h501d, 8'h40}; assign cfg_data_reg[194] = {16'h5300, 8'h08}; assign cfg_data_reg[195] = {16'h5301, 8'h30}; assign cfg_data_reg[196] = {16'h5302, 8'h10}; assign cfg_data_reg[197] = {16'h5303, 8'h00}; assign cfg_data_reg[198] = {16'h5304, 8'h08}; assign cfg_data_reg[199] = {16'h5305, 8'h30}; assign cfg_data_reg[200] = {16'h5306, 8'h08}; assign cfg_data_reg[201] = {16'h5307, 8'h16}; assign cfg_data_reg[202] = {16'h5309, 8'h08}; assign cfg_data_reg[203] = {16'h530a, 8'h30}; assign cfg_data_reg[204] = {16'h530b, 8'h04}; assign cfg_data_reg[205] = {16'h530c, 8'h06}; assign cfg_data_reg[206] = {16'h5025, 8'h00}; assign cfg_data_reg[207] = {16'h3008, 8'h02}; assign cfg_data_reg[208] = {16'h3035, 8'h11}; assign cfg_data_reg[209] = {16'h3036, 8'h46}; assign cfg_data_reg[210] = {16'h3c07, 8'h08}; assign cfg_data_reg[211] = {16'h3820, 8'h47}; assign cfg_data_reg[212] = {16'h3821, 8'h07}; assign cfg_data_reg[213] = {16'h3814, 8'h31}; assign cfg_data_reg[214] = {16'h3815, 8'h31}; assign cfg_data_reg[215] = {16'h3800, 8'h00}; assign cfg_data_reg[216] = {16'h3801, 8'h00}; assign cfg_data_reg[217] = {16'h3802, 8'h00}; assign cfg_data_reg[218] = {16'h3803, 8'hfa};//Y起始地址 assign cfg_data_reg[219] = {16'h3804, 8'h0a}; assign cfg_data_reg[220] = {16'h3805, 8'h3f}; assign cfg_data_reg[221] = {16'h3806, 8'h06};//Y结束地址 assign cfg_data_reg[222] = {16'h3807, 8'ha9}; assign cfg_data_reg[223] = {16'h3808, 8'h03};//水平输出宽度 assign cfg_data_reg[224] = {16'h3809, 8'h20}; assign cfg_data_reg[225] = {16'h380a, 8'h01};//垂直输出宽度 assign cfg_data_reg[226] = {16'h380b, 8'he0}; assign cfg_data_reg[227] = {16'h380c, 8'h07};//总水平大小 assign cfg_data_reg[228] = {16'h380d, 8'h64}; assign cfg_data_reg[229] = {16'h380e, 8'h02};//总垂直大小 assign cfg_data_reg[230] = {16'h380f, 8'he4}; assign cfg_data_reg[231] = {16'h3813, 8'h04};//垂直偏移 assign cfg_data_reg[232] = {16'h3618, 8'h00}; assign cfg_data_reg[233] = {16'h3612, 8'h29}; assign cfg_data_reg[234] = {16'h3709, 8'h52}; assign cfg_data_reg[235] = {16'h370c, 8'h03}; assign cfg_data_reg[236] = {16'h3a02, 8'h17}; assign cfg_data_reg[237] = {16'h3a03, 8'h10}; assign cfg_data_reg[238] = {16'h3a14, 8'h17}; assign cfg_data_reg[239] = {16'h3a15, 8'h10}; assign cfg_data_reg[240] = {16'h4004, 8'h02}; assign cfg_data_reg[241] = {16'h3002, 8'h1c}; assign cfg_data_reg[242] = {16'h3006, 8'hc3}; assign cfg_data_reg[243] = {16'h4713, 8'h03}; assign cfg_data_reg[244] = {16'h4407, 8'h04}; assign cfg_data_reg[245] = {16'h460b, 8'h35}; assign cfg_data_reg[246] = {16'h460c, 8'h22}; assign cfg_data_reg[247] = {16'h4837, 8'h22}; assign cfg_data_reg[248] = {16'h3824, 8'h02}; assign cfg_data_reg[249] = {16'h5001, 8'ha3}; assign cfg_data_reg[250] = {16'h3503, 8'h00}; endmodule
module OV5640_Top ( input wire sys_clk, input wire rst, inout wire sda, output wire scl, output wire pwdn, output wire resetb, output wire [9:0] statue_WR, output wire [12:0] statue_RD ); reg read_en; wire [15:0] addr; wire read_end; wire sccb_en; wire clk_en; wire start; wire [7:0] Data_reg; wire [23:0] cfg_data; wire init_end; wire write_end; wire WR_en; wire scl_rd; wire scl_wr; wire sda_rd; wire sda_wr; reg number; /* wire [9:0] statue_WR; wire [12:0] statue_RD; */ wire [7:0] ID = 8'h3C; wire [15:0] rd_add = 16'h3808; wire [23:0] Cmd; assign start = (sccb_en == 1'd1 && clk_en == 1'd1)?1'd1:1'd0; assign sda = (init_end == 1'd1)?((statue_RD == 13'b0_0000_0000_0100 || statue_RD == 13'b0_0000_0001_0000 || statue_RD == 13'b0_0000_0100_0000 || statue_RD == 13'b0_0010_0000_0000 || statue_RD == 13'b0_0100_0000_0000)?1'dz:sda_rd) :sda_wr; assign scl = (init_end == 1'd1)?scl_rd:scl_wr; always@(posedge sys_clk or negedge rst) if(rst == 1'd0) number <= 1'd1; else if(number == 1'd1 && read_end == 1'd1 && init_end == 1'd1) number <= 1'd0; always@(posedge sys_clk or negedge rst) if(rst == 1'd0) read_en <= 1'd0; else if(read_end == 1'd1) read_en <= 1'd0; else if(init_end == 1'd1 && number == 1'd1) read_en <= 1'd1; Power_ctrl #( .CNT_5MS(20'd250_000), .CNT_1MS(20'd50_000), .CNT_20MS(20'd1000_000) ) Power_ctrl_inst ( .sys_clk(sys_clk), .rst(rst), .pwdn(pwdn), .resetb(resetb), .sccb_en(sccb_en), .clk_en(clk_en) ); OV5640_cfg OV5640_cfg_inst ( .sys_clk(sys_clk), .rst(rst), .start(start), .write_end(write_end), .cfg_data(cfg_data), .WR_en(WR_en), .init_end(init_end) ); SSCB_WR SSCB_WR_inst ( .sys_clk(sys_clk), .rst(rst), .WR_en(WR_en), .addr(cfg_data[23:8]), .ID(ID), .data(cfg_data[7:0]), .sda(sda_wr), .scl(scl_wr), .WR_end(write_end), .statue(statue_WR) ); SSCB_ID SSCB_ID_inst ( .sys_clk(sys_clk), .rst(rst), .read_en(read_en), .addr(rd_add), .ID(ID), .sda_rd(sda), .sda(sda_rd), .scl(scl_rd), .read_end(read_end), .Data_reg(Data_reg), .statue(statue_RD), .Cmd(Cmd) ); endmodule
该测试是将刚才写于的寄存器数据读出来判断是否一致(该寄存器地址为16‘h3808)
<1>inout只能用wire来赋值
<2>inout在赋值时,要使用三态逻辑门来赋值(也有其他的方法,但最好还是用这个),且赋值的内容必须包含高阻态。
<3>尽量不要在底层使用inout,不然会有一些警告。
<4>底层不要数据赋值为z
<5>规范使用inout,不然可能导致电路短路
以上几点,如果不遵循,可能编译通过了,但生成的电路会不满足你的设计要求。
数据输出时序:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。