Day5-OV5640摄像头
今天任务:了解这个摄像头的传输协议&接通实现在屏幕上接收摄像头采集到的图像

将采集到的数据 通过image array转换成10bit的ADC,再进行一个ISP的寄存器设置,再转换成摄像头可以识别的图像数据
OV5640摄像头主要特性:
1. 支持500W像素
2. 今天玩的这玩意,不是标准的720p,所以会有黑边
3. 是标准的串行SCCB·接口,与IIC接口相同
4. 在720p下能实现60帧60fps
引脚介绍
Power Down是高有效输入信号(不工作的时候是低电平,工作时候高电平)
Reset 是低有效输入信号
SIOC和SIOD是他的SCCB的时序,两个数据传输的接口,跟IIC的时序差不多
SDA负责传输数据,SCL负责输入时钟
Vsync是场同步信号,HREF是反向行同步信号(hsync取反后的信号)
XVCLK是系统输入时钟,PCLK是像素时钟
D0-D7是摄像头采集数据传输的接口
这个路径里面是有用的引脚信息:
ZYNQ资料/01_原理图/EBAZ4205_EXBOARD_20200313.pdf

上电时序
上电时序指 硬件芯片从完全断电状态到进入正常工作状态,各个控制信号必须遵循的“先后顺序”和“时间间隔”
如果这个顺序不对(比如复位拉早了,或者掉电没关掉),芯片内部的状态机可能会错乱,导致摄像头不出图、系统不启动,甚至损伤芯片

其中这里D0Y00和AVDD是内部已经配置好了的,无需改动(毕竟也没有这俩的对应接口信息)
所以下面看这个PWDN RESETB XVCLK
图片下面文案说明了这几个t1,t2...的要求
相应的,可以直接看总结资料里的中文版时序图

这里明确说明了t2,t3,t4的要求,于是需要三个计数器去计时
实际会让t2为6ms,t3为2ms这样
这里是对应关系,输入时钟是50兆Hz,也就是20纳秒,转到6ms就是30万次
SCCB时序介绍(也就当是IIC了)
SIO_C是一个时钟,周期性变化,最小周期$t_syc$是10微秒$μs$,即最大频率为100K,所以需要在代码里面要小于100K
SIO_D是传的数据
SCCB的传输阶段介绍
先传ID地址,再传一段子地址/寄存器地址,再写
再传,再写 再传,再写
ID地址是这个摄像头的地址,然后Sub是寄存器的地址

下图讲了,
芯片内部0x3100编号的寄存器用来存放 SCCB 总线通信的设备 ID,上电默认值是0x78,这个数值就是 SCCB 时序里的 ID Address。
从级ID是0x78



提示词1用于控制OV5640图像传感器的上电时序
“在FPGA内部产生符合传感器手册要求的硬件控制信号,确保摄像头能正常启动并进入可配置状态。”
也就说,让他内部自己有一个时间控制系统,使得满足上电时序要求,并令ov5640_pwdn 和 ov5640_rst_n 这两根线能跑起来,最终实现摄像头的启动
其中,
ov5640_pwdn:在6ms到的那一刻,从高电平 “掉下来” (拉低),让芯片通电。
ov5640_rst_n:再过2ms,从低电平 “弹上去” (拉高),让芯片开始复位初始化。
这两根线在此之后就不再变化了(保持固定电平),直到板子彻底断电。
注意:这个模块并没有让摄像头直接出图像,它的目标就是 “启动”
----pow ctrl 请用 Verilog-2001 编写可综合的 OV5640 上电时序控制模块。 模块接口必须完全如下: module power_ctrl( input sclk, input s_rst_n, output ov5640_pwdn, output ov5640_rst_n, output power_done ); 要求: 1. sclk频率为50MHz,周期20ns。 2. AVDD和DOVDD已经由硬件稳定提供,不需要控制。 3. s_rst_n为异步低电平复位。 4. 复位期间: ov5640_pwdn=1; ov5640_rst_n=0; power_done=0。 5. s_rst_n释放后等待6ms,将ov5640_pwdn拉低。 6. PWDN拉低后等待2ms,将ov5640_rst_n拉高。 7. RESET释放后等待21ms,将power_done拉高。 8. power_done拉高后保持为1,用于启动后续SCCB配置。 9. 使用三个计数器依次完成时序: 6ms=300000个时钟; 2ms=100000个时钟; 21ms=1050000个时钟。 10. 计数器达到目标后停止计数,避免溢出。 11. 不需要控制XVCLK。 12. 代码必须可综合,时序逻辑使用非阻塞赋值。 只输出完整的Verilog代码。
提示词2是 对寄存器进行初始化配置
“利用时钟线SCL的时间控制,完成对寄存器状态的设置与读取,使得后续可以对寄存器进行调控,从而在宏观上体现为对摄像头的调整”
寄存器是一个个小的运行模块,控制存储器“被写”,状态存储器“被读”,通过在微观上对这些存储器的调整,才能在宏观上看到对摄像头的调整
请用 Verilog-2001 编写可综合的 OV5640 SCCB/I²C 控制器。 模块接口必须完全如下: module ov5640_iic( input sclk, input s_rst_n, output reg iic_scl, inout iic_sda, input start, input [31:0] wdata, output reg [7:0] riic_data, output reg busy ); 重要条件: 1. 输入 sclk 已经由 50MHz 分频得到: sclk = 50MHz / 512 = 97.65625kHz。 2. busy期间每个sclk上升沿翻转一次iic_scl,使: iic_scl ≈ 48.828kHz。 3. wdata格式: [31:24]:设备地址字节,最低位为读写位; [23:8]:16位寄存器地址; [7:0]:写数据。 OV5640写地址通常为0x78,读地址为0x79。 4. 写操作: START→0x78→ACK→地址高字节→ACK→地址低字节→ACK→数据→ACK→STOP。 5. 读操作必须使用: START→0x78→ACK→地址高字节→ACK→地址低字节→ACK →STOP→START→0x79→ACK→读取8位数据→NACK→STOP。 注意这里要求STOP后重新START,不要只使用repeated START。 6. start为单个sclk周期脉冲。仅在busy=0时接受start,并立即锁存wdata;busy期间忽略新的start。 7. 数据MSB优先。SDA只能在SCL低电平时改变,START和STOP除外。 8. ACK和读取数据期间必须释放SDA: assign iic_sda = sda_oe ? sda_out : 1'bz; 9. 读取数据时,在SCL高电平稳定阶段采样SDA,最终保存到riic_data。 10. 读取一个字节后,主机发送NACK,再产生STOP。 11. 空闲时: iic_scl=1、SDA释放、busy=0。 12. s_rst_n为异步低电平复位。 13. ACK可以暂时不判断是否有效,但ACK周期必须正确释放SDA。请在代码中预留ACK检测位置。 14. 组合逻辑必须有默认赋值,避免锁存器;时序逻辑使用非阻塞赋值。 15. 模块将直接替换现有工程中的同名模块,所以不能修改端口、位宽、信号方向和wdata编码。 请检查状态跳转,确保写操作发送数据后才STOP,读操作发送0x79并收到ACK后才进入数据接收。 只输出完整的Verilog代码。
提示词3用于 让ov5640_cfg掌握控制寄存器的权利,作为总指挥,叫下属去控制寄存器
最终实现对寄存器的调控
写一个 Verilog 模块,用于上电后通过 I2C 控制器自动对 OV5640 摄像头传感器进行寄存器初始化配置。 模块名为 ov5640_cfg,接口如下: 输入: sclk - 系统时钟,约 50MHz,驱动状态机和 I2C 时序 s_rst_n - 异步复位,低有效 estart - 调试用外部启动信号,在自动配置完成后可手动发起 I2C 传输 ewdata[31:0] - 调试用外部写入数据,格式为 {8bit设备地址, 16bit寄存器地址, 8bit寄存器值} 输出: iic_scl - I2C 时钟线,由内部 I2C 控制器驱动 iic_sda - I2C 数据线,双向 inout riic_data[7:0] - I2C 读回数据 内部架构: 1. 定义一个 localparam ANUM = 304,表示配置表中寄存器的数量。 2. 用一个 packed 数组 cfg_array[ANUM-1:0],每个元素 32bit 宽,格式为: {8'h78, 16'hREG_ADDR, 8'hREG_VAL} 其中 8'h78 是 OV5640 的 I2C 写地址。用 304 条 assign 语句逐条填充这个数组, 每行注释 // ID REG_ADDR REG_VAL。这些是 OV5640 的初始化寄存器序列, 包括 PLL 配置、时钟分频、输出格式(RGB565)、分辨率(1024x720)、DSP 参数、 AWB/AEC 等共约 300 条寄存器写入。 3. 设计一个自动状态机: - cfg_index(9bit 寄存器):当前已发送的配置条目计数 - start(1bit 寄存器):发往 I2C 控制器的启动脉冲 - cfg_index == 0 时产生第一个 start 脉冲 - 检测 I2C 控制器的 busy 信号下降沿(busy_neg),表示上一次传输完成, 此时若 cfg_index < ANUM 则再次产生 start 脉冲,cfg_index 加 1 - cfg_index 达到 ANUM 后停止,进入延时等待 4. 配置完成后的延时: - cnt_200us(16bit 寄存器):在 cfg_index >= ANUM 后开始递增计数 - localparam DELAY_200US = 10000(对应 sclk 频率下的约 200µs) - 当 cnt_200us >= DELAY_200US 时,cfg_done 置 1 5. 双模式切换: - cfg_done == 0 时:iic_start = start,iic_wdata = cfg_array[cfg_index](自动模式) - cfg_done == 1 时:iic_start = estart,iic_wdata = ewdata(调试模式,允许外部手动读写寄存器) 6. busy_neg 的检测: - 用 3bit 移位寄存器 busy_arr 对 busy 信号打两拍 - busy_neg = busy_arr[2] & ~busy_arr[1](检测下降沿) 7. 例化一个 ov5640_iic 模块,连接 sclk、s_rst_n、iic_scl、iic_sda、 start(iic_start)、wdata(iic_wdata)、riic_data、busy。
提示词4用于
请用 Verilog 编写一个 ov5640_data 模块,用于处理 OV5640 摄像头传感器的输出数据。 模块接口如下: input s_rst_n // 系统复位(低有效) input ov5640_pclk // OV5640 像素时钟 input ov5640_href // OV5640 行参考信号 input ov5640_vsync // OV5640 场同步信号 input [7:0] ov5640_data // OV5640 8位像素数据 output wire m_vsync // 输出场同步 output wire m_href // 输出行参考 output wire [15:0] m_data // 输出16位拼接数据 output reg m_wr_en // 输出写使能 内部寄存器要求使用以下命名: reg ov5640_vsync_r1 // vsync打一拍 reg [3:0] frame_cnt // 帧计数器 reg [7:0] ov5640_data_r1 // 上一字节数据 wire ov5640_vsync_pos // vsync上升沿检测 wire frame_vaild // 帧有效标志 功能要求: 1. 在 ov5640_pclk 时钟域下,对 ov5640_vsync 和 ov5640_data 各打一拍。 2. 通过 ov5640_vsync 的上升沿检测(ov5640_vsync & ~ov5640_vsync_r1),在系统复位后计数帧数。 3. frame_cnt 在 frame_vaild 为低且 vsync 上升沿到来时加 1,复位清零。 4. frame_vaild 在前 10 帧期间为低(frame_cnt < 10),之后拉高。 5. m_wr_en:当 frame_vaild 且 ov5640_href 有效时,每个 pclk 翻转一次(乒乓写使能);否则为 0。 6. m_data:将上一拍数据 ov5640_data_r1 与当前 ov5640_data 拼接为 16 位输出(先到的字节在高位)。 7. m_vsync / m_href:仅在 frame_vaild 有效时透传 ov5640_vsync / ov5640_href,否则输出 0。 8. 复位为异步复位,低有效。 请按上述要求输出完整模块代码。

浙公网安备 33010602011771号