探测器开发过程中,经常需要对内部寄存器进行初始化配置,有些甚至是需要在每帧图像结束后都重新配置一下寄存器参数。
在特权老师的教学视频中,将OV5640探测器的寄存器配置模块设计如下:
`timescale 1ns/1ps
//实现OV5640的I2C寄存器初始化配置
module m_i2c_ov5640_top #(
parameter P_CLK_FREQ = 50_000_000, //i_clk的时钟频率
parameter P_I2C_FREQ = 100_000 //o_i2c_sclk的时钟频率
)
(
input i_clk,
input i_rst_n,
//OV5640的I2C接口
output o_i2c_sclk,
inout io_i2c_sdat,
//I2C配置完成信号
output o_config_done
);
wire w_i2c_en; //I2C的数据传输使能信号,保持一个时钟周期高电平
wire w_i2c_wren; //1--I2C写入,0--I2C读出
wire w_i2c_end; //I2C传输结束指示信号,高电平有效一个时钟周期
wire w_i2c_ack; //I2C操作响应信号,低电平表示响应成功
wire[39:0] w_i2c_wdata; //bit39~32 -- ID ADDR (read), bit31~24 -- ID ADDR(write), bit23~8 -- Sub ADDR, bit7~0 -- Write DATA
wire[7:0] w_i2c_rdata;
wire[8:0] w_lut_index;
wire[23:0] w_lut_data;
wire[8:0] w_lut_size;
//
m_i2c_ov5640_init #(
.P_CLK_FREQ(P_CLK_FREQ)
)
uut_m_i2c_ov5640_init(
.i_clk (i_clk),
.i_rst_n (i_rst_n),
.o_i2c_en (w_i2c_en), //I2C的数据传输使能信号,保持一个时钟周期高电平
.o_i2c_wren (w_i2c_wren), //1--I2C写入,0--I2C读出
.o_i2c_wdata (w_i2c_wdata), //bit39~32 -- ID ADDR (read), bit31~24 -- ID ADDR(write), bit23~8 -- Sub ADDR, bit7~0 -- Write DATA
.o_config_done (o_config_done),
.o_lut_index (w_lut_index),
.i_lut_data (w_lut_data),
.i_lut_size (w_lut_size)
);
//I2C配置时序产生模块
m_i2c_controller #(
.P_CLK_FREQ(P_CLK_FREQ), //i_clk的时钟频率
.P_I2C_FREQ(P_I2C_FREQ) //o_i2c_sclk的时钟频率
)
uut_m_i2c_controller(
.i_clk (i_clk),
.i_rst_n (i_rst_n),
.o_i2c_sclk (o_i2c_sclk),
.io_i2c_sdat (io_i2c_sdat),
.i_i2c_en (w_i2c_en), //I2C的数据传输使能信号,保持一个时钟周期高电平
.i_i2c_wren (w_i2c_wren), //1--I2C写入,0--I2C读出
.o_i2c_end (w_i2c_end), //I2C传输结束指示信号,高电平有效一个时钟周期
.o_i2c_ack (w_i2c_ack), //I2C操作响应信号,低电平表示响应成功
.i_i2c_wdata (w_i2c_wdata), //bit39~32 -- ID ADDR (read), bit31~24 -- ID ADDR(write), bit23~8 -- Sub ADDR, bit7~0 -- Write DATA
.o_i2c_rdata (w_i2c_rdata)
);
//I2C配置数据LUT模块
m_i2c_ov5640_config uut_m_i2c_ov5640_config(
.LUT_INDEX (w_lut_index),
.LUT_DATA (w_lut_data),
.LUT_SIZE (w_lut_size)
);
endmodule
这个模块中,分别例化了三个模块,依次实现初始化逻辑控制、I2C读写驱动、OV5640寄存器配置信息。
模块在初始化结束后,输出config_done信号用于表明寄存器配置完成。
这种架构代码简洁,每个模块的功能又很明确,在此引用,用于学习。