摄像头控制模块(reg_config_camera_ov5640_phy.v)用于控制ov5640的相关操作, 绝大多数操作都会在初始化过程中完成, 少量的操作会在实际工程中使用。当ov5640上电复位模块准备好后(提供initial_en信号), 摄像头控制模块就可以正常配置ov5640的相关参数了。(具体参数内容, 可以参照ov5640 的技术手册)
参考目录:图像采集与传输系统的设计
ov5640模块控制框图:
其中power_on_delay_ov5640_phy.v 模块是提供ov5640上电和reset的逻辑,同时输出initial_en 给reg_config_camera_ov5640_phy.v 模块,
1)摄像头控制模块得到initial_en后,通过i2c总线,开始对ov5640硬件的相关寄存器进行配置。
2)当所有寄存器配置完成后,转入到控制模式,接收flash_switch的信号,点亮或者熄灭ov5640硬件上的闪光灯。
3)同时, 摄像头模块也是可以接收,发送 uart数据的, 这时uart作为ov5640寄存器的调试接口, 可以将uart 数据转换为 i2c的数据发送给ov5640,也可以通过i2c 控制, 将ov5640的寄存器读出, 发送到uart上。
reg_config_camera_ov5640_phy.v (摄像头控制模块)可以分为以下几个部分:
i2c_master_top.v : i2c IP ,用于控制 i2c 总线上的数据读写。
按键(return键)控制逻辑: 用于接收按键信息, 点亮、熄灭闪光灯。
i2c控制状态机: 1)初始化ov5640的相关寄存器, 2)读取按键信息,发送i2c 命令到ov5640硬件, 点亮,熄灭闪光灯。
camera 初始化数据:一组静态数据,在系统启动时, 会被初始化状态机所调用, 将这些数据写入到ov5640 芯片中去。
串口调试逻辑:在状态机空闲期间, 可以使用uart 接口 ,接收uart 数据写入到ov5640寄存器中, 也可以根据uart 命令,读取ov5640 芯片寄存器中的数据, 并发送这些数据到uart上。
具体程序解析:
闪光灯控制逻辑:
assign reg_conf_done = reg_conf_done_reg ;
/*
闪光灯开关信号st_Strobe的产生,按键每按一次(改变st_mux),
sign_Strobe的值在2'b01或者2'b10间进行一次赋值。(sign_Strobe为2'b01,
打开闪光灯。sign_Strobe为2'b10,则关闭闪光灯)
*/
reg [1:0] sign_Strobe = 2'b00;
reg st_mux = 0;
always @ ( posedge clk_50m)
if (!initial_en)
begin
sign_Strobe <= 2'b00;
st_mux <= 0;
end
else
begin
if ( flash_switch )
begin
sign_Strobe <= st_mux ? 2'b10 : 2'b01;
st_mux <= st_mux + 1;
end
else sign_Strobe <= 2'b00;
end
接收flash_switch 过来的按键信息, 每当按键按下一次, st_mux 就翻转一次,同时使用sign_strobe 记录当前的按键状态; sign_strobe = 2’b01 , 打开闪光灯, sign_strobe = 2’b10 , 关闭闪光灯。
状态机控制逻辑:
// 首先配置基本的253个寄存器,OV5640摄像头可以正常工作,采集图像。
// 寄存器253,254的作用分别是打开闪光灯,关闭闪光灯。
reg [1:0] i2c_st = 0;
always@(posedge clk_50m )
if(!initial_en) // OV5640摄像头上电未完成时,配置寄存器的电路模块处于复位状态
begin
i2c_st <= 0;
reg_wr_i2c <= 0;
reg_index <= 0;
reg_conf_done_reg <= 0;
end
else
begin
// 整个寄存器的配置过程分为2部分,基本寄存器的配置(0~252),
// 闪光灯寄存器的配置两部分。基本寄存器的配置在reg_conf_done_reg为低电平的状态下实现
if(reg_conf_done_reg == 1'b0)
begin
if( reg_index <= 252 )
begin
// 调用IIC总线配置(0~252)寄存器的值,配置完成后,将reg_conf_done_reg值拉高
case(i2c_st)
0:
begin
i2c_data <= {ov5640_devide_id, 1'b0, reg_data};
reg_wr_i2c <= 1;
i2c_st <= 1;
end
1:
begin
if(wr_done_i2c)
begin
reg_wr_i2c <= 0;
i2c_st <= 2;
end
else ;
end
2:
begin
reg_index <= reg_index + 1'b1;
i2c_st <= 0;
end
endcase
end
else
reg_conf_done_reg <= 1'b1;
end
else
begin
// 在reg_conf_done_reg为高电平阶段,等待闪光灯开关命令(即向摄像头模块OV564的03b00寄存器写入不同的寄存器值 )。
//(通过闪光灯开关按键调整sign_Strobe的值,进行执行对闪光灯控制寄存器写入不同的值的过程)
case(i2c_st)
0:
begin
if( sign_Strobe == 2'b01 )
begin
i2c_st <= 1;
reg_index <= 253;
end
else
begin
if (sign_Strobe == 2'b10)
begin //
i2c_st <= 1 ;
reg_index <= 254 ;
end
else ;
end
end
1:
begin
i2c_data <= {ov5640_devide_id, 1'b0, reg_data }; //IIC Device address is 0x3c
reg_wr_i2c <= 1;
i2c_st <= 2;
end
2:
begin
if(wr_done_i2c)
begin //IIC发送结束
reg_wr_i2c <= 0;
i2c_st <= 3;
end
else ;
end
3:
begin
i2c_st <= 0;
reg_index <= 253;
end
endcase
end
end
在initial_en == 0 时, 所有状态, 变量 清零。 当initial_en == 1 时: (允许状态机对0v5640 进行初始化操作)
如果没有完成初始化操作(reg_conf_done_reg == 0) , 初始化ov5640 相关的寄存器, 知道所需要的寄存器全部初始化完毕。将reg_confi_done_reg = 1;
如果完成了初始化操作, 等待按键是否被按下,检测不同的按键值,然后将按键所代表的含义(点亮 flash led, 熄灭 flash led)发送给ov5640.
camera 初始化数据:
camera 初始化数据,用于初始化camera芯片,完成相关的配置工作,包括camera 芯片的时钟设置,分辨率的设置,图像采样设置,输出模式设置,图像位置设置,图像颜色调整等, 很多操作。 这里我们选择的时 640×480@30Hz ,RGB565, DVP 模式,将图像数据输出给fpga。 很多具体的操作,需要仔细阅读ov5640的相关寄存器手册。
uart 转i2c 控制逻辑:
/*
本模块的功能是在线调试OV5640寄存器 。工程中经常使用串口来在线读写寄存器,通过写入的值和读出来的值进行比对一致性判断
(1:验证IIC总线的读写的正确性,2.可以快速进行相关寄存器的配置,)命令格式 参考本工程PDF文档附件
*/
// uart read and write 5640 configuration register
// 串口接收计算机(波特率115200)下发的寄存器配置命令
//************* 串口在线配置OV5640寄存器
reg [2:0] uart_st = 0;
always @ (posedge clk_50m)
if(reg_conf_done_reg == 0)
begin
uart_wr_i2c <= 0 ;
uart_rd_i2c <= 0 ;
uart_st <= 0 ;
uart_sel <= 0 ;
end
else
begin
case ( uart_st )
0:
begin
txd_start <= 0;
uart_wr_i2c <= 0;
uart_rd_i2c <= 0;
if(rxd_done & (rxd_data == 01) ) // 串口发送第1byte数据为01,则之后的配置命令对OV5640执行
uart_st <= 1 ;
else
uart_st <= 0 ;
end
1:
begin
uart_wr_i2c <= 0 ;
uart_rd_i2c <= 0 ;
uart_sel <= 1 ; // IIC的读写请求命令,地址等相关信息切换到串口通道
if(rxd_done)
begin
cmd_dir <= rxd_data ; // 接收读写命令
uart_st <= 2 ;
end
else ;
end
2:
begin
if(rxd_done)
begin
i2c_data_r[23:16] <= rxd_data ; //接收读写寄存器地址高8bit数据
uart_st <= 3 ;
end
else ;
end
3:
begin
if( rxd_done )
begin
i2c_data_r[15:08] <= rxd_data ; //接收读写寄存器地址低8bit数据
if(cmd_dir[0])
uart_st <= 6 ; //依据接收的读或者写命令调用IIC总线进行读操作或者写操作
else
uart_st <= 4 ;
end
else ;
end
4: // write cmd
begin
if(rxd_done)
begin
i2c_data_r[07:00] <= rxd_data; //待写入5640摄像头寄存器的8bit数据
uart_wr_i2c <= 1;
uart_st <= 5;
end
else ;
end
5:
begin
if( wr_done_i2c )
begin
uart_wr_i2c <= 0;
uart_sel <= 0;
uart_st <= 0;
end
else ;
end
6: //read cmd
begin
uart_rd_i2c <= 1;
uart_st <= 7;
end
7:
begin
if( rd_done_i2c )
begin
uart_rd_i2c <= 0;
txd_data <= i2c_read_data ; // 读回来的数据给到串口的发送端口
txd_start <= 1 ;
uart_sel <= 0 ;
uart_st <= 0 ;
end
end
endcase
end
uart 转i2c 控制逻辑:
状态0: 等待uart 是否有数据被接收到, 同时查看一下接收到的第一个数据是否为01, 如果数据为01,表示uart 准备调试camera; 如果为02,表示uart 准备调试adv7511.
状态1: 等待uart 接收第二个数据,这个数据为I2C的地址,并且从这个数据的最低位还能判断出对I2C的读写操作。同时uart_sel 切换I2C master IP 到uart上。
状态2:接收数据为寄存器的高8位数据
状态3:接收数据为寄存器的低8位数据,同时判断uart的操作: I2C 读, I2C写,根据不同的操作,跳转到不同的状态机。
状态4:写操作,将下一个uart 接收到的数据写入I2C (给寄存器赋值)
状态5:写操作完成, 同时将uart_sel 切换到数据初始化状态机上。
状态6:对I2C master IP 进行读操作
状态7:将I2C 读取到的数据,发送到uart 上。
示例:
uart 的调试方法在“图像采集uart 在线调试使用文档说明”中有详细描述。 使用方法:使用计算机uart 工具,举例sscom。uart 115200波特率 , hex 显示, hex 发送。
举例:
01 78 4741 07
01 78 4741 00
01 78 503D 80
01 78 503D 00
uart 调试 ov5640 芯片 格式为:
调试读命令: id(1byte) + i2c 地址(1byte) + 寄存器(2bytes)
调试写命令: id(1byte) + i2c 地址(1byte) + 寄存器(2bytes)+ 寄存器值(1byte)
id : 8bit , 01 = ov5640; 02 = adv7511. 用来指示当前的调试命令和哪个模块通讯(ov5640,adv7511)
i2c地址: 8bit, 在读命令中 这个地址的最低位是‘1’,在写命令中这个地址的最低为是‘0’。
寄存器:ov5640 的寄存器是16bit的, 对于adv7511来说, 寄存器是由8bit,所以,在读写adv7511时:都是00xx,将高位地址 设置位‘00’。
寄存器值:8bit, 写命令才有。 写入寄存器的值。
图1
