ov5640_lcd_display学习笔记
最近学习了正点原子fpga ov5640摄像头显示例程,特此记录一下。
系统框架与接口
FPGA要操控的外围器件为ov5640摄像头、LCD和DDR3,接口方面也并不算复杂,用到的接口为sccb、dvp以及RGB888。
sccb接口用来配置摄像头寄存器参数,并且iic兼容sccb,所以配置寄存器直接调用iic的驱动模块即可。
dvp接口为摄像头的数据输出接口,位宽为10bit([D[9:0]]),RGB格式输出时,有效数据位为29(D[9:2]),将摄像头数据输出的29pin接入fpga的管脚。值得注意的是,ov5640不止支持dvp接口,还支持mipi接口,不过原子的这个例程所用到的硬件仅支持dvp。
rgb888:尽管接口位宽为24(3字节为一个像素),红绿蓝色彩深度各为8bit,但实际上例程所配置摄像头的输出格式为565,也就是2字节为一个像素,红绿蓝有效位分别位5bit、6bit、5bit,其余无效位补0;
开发前需要明确的问题
- 需要什么像素数据输出格式?(图像数据格式包含YUV、RGB565、RGB555还是RAW等)
- 需要什么图像输出时序?(XQGA:2048×1536、UXGA:1600×1200、SXGA:1280*1024、WXGA:1440×900、WXGA:1280×800、XGA:1024×768、SVGA:800×600、VGA:640×480、QVGA:320×240、QQVGA:160×120等)
- LCD的分辨率是多少?(原子的LCD屏分辨率有1280×800、1024×600、800×480以及480×272)
- LCD采用哪种时序输入模式?(input timing mode:DE mode/HV mode)
只有回答上面的三个问题,才能确定配置摄像头参考时钟是多少、LCD参考时钟是多少以及计算实际带宽。
摄像头寄存器配置
摄像头上电后,有20ms初始化时间,必须等20ms后才可以对摄像头寄存器进行配置。
OV5640 的寄存器较多,对于其它寄存器的描述可以参考 OV5640 的数据手册。需要注意的是,OV5640的数据手册并没有提供全部的寄存器描述,而大多数必要的寄存器配置在 ov5640 的软件应用手册中可以找到,可以结合这两个手册学习如何对 OV5640 进行配置。
大部分默认原子的配置就好。
图像窗口与实际输出大小
//预缩放窗口水平起始点高8位
8'd212: i2c_data <= {16'h3800,8'h00}; //x_addr_st
//预缩放窗口水平起始点低8位
8'd213: i2c_data <= {16'h3801,8'h00}; //x_addr_st
//预缩放窗口垂直起始点高8位
8'd214: i2c_data <= {16'h3802,{3'd0,y_addr_st[12:8]}};
//预缩放窗口垂直起始点低8位
8'd215: i2c_data <= {16'h3803,y_addr_st[7:0]};
//预缩放窗口水平截止点高8位
8'd216: i2c_data <= {16'h3804,8'h0a}; //x_addr_end
//预缩放窗口水平截止点低8位
8'd217: i2c_data <= {16'h3805,8'h4f}; //x_addr_end
//预缩放窗口垂直截止点高8位
8'd218: i2c_data <= {16'h3806,{3'd0,y_addr_end[12:8]}};
//预缩放窗口垂直截止点低8位
8'd219: i2c_data <= {16'h3807,y_addr_end[7:0]};
//设置输出像素个数
//DVP 输出水平像素点数高4位
8'd220: i2c_data <= {16'h3808,{4'd0,cmos_h_pixel[11:8]}};
//DVP 输出水平像素点数低8位
8'd221: i2c_data <= {16'h3809,cmos_h_pixel[7:0]};
//DVP 输出垂直像素点数高3位
8'd222: i2c_data <= {16'h380a,{5'd0,cmos_v_pixel[10:8]}};
//DVP 输出垂直像素点数低8位
8'd223: i2c_data <= {16'h380b,cmos_v_pixel[7:0]};
//水平总像素大小高5位
8'd224: i2c_data <= {16'h380c,{3'd0,total_h_pixel[12:8]}}; //x_addr_max
//水平总像素大小低8位
8'd225: i2c_data <= {16'h380d,total_h_pixel[7:0]}; //x_addr_max
//垂直总像素大小高5位
8'd226: i2c_data <= {16'h380e,{3'd0,total_v_pixel[12:8]}}; //y_addr_max
//垂直总像素大小低8位
8'd227: i2c_data <= {16'h380f,total_v_pixel[7:0]}; //y_addr_max
实际有效像素输出是由cmos_h_pixel和cmos_v_pixel决定(比如LCD为1024 * 600 分辨率,0x3808(高位byte) & 0x3809(低位byte)两个寄存器就填入1024,同理0x380a(高位byte) & 0x380b(低位byte)两个寄存器就填入1024就填入600)
LCD显示时序
市面上在售的显示器或者LCD屏幕,尺寸上都有统一的工业标准,每一种显示分辨率都有相应规格的像素时钟周期和驱动时钟频率,这是开发者的研发依据。
开发者在具体的研发过程中应参考具体显示硬件的规格书或者《VESA_VGA时序标准》。
这是正点原子查找后整理过的的。
这是我自己查找手册的
一帧图像周期数计算公式:行显示周期 × 列显示周期
Number = (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)
显示一帧图像时间:Time = Number × 时钟频率周期
(如1024×600分辨率就是1344×635×20ns,50M是20ns一周期)
HSPW:行同步信号宽度,也就是 HSYNC 信号持续时间。 HSYNC 信号不是一个脉冲,而是需要持续一段时间才是有效的,单位为 CLK。
HBP:行显示后沿(或后肩),单位是 CLK。
HOZVAL:行有效显示区域,即显示一行数据所需的时间,假如屏幕分辨率为 1024*600,那么HOZVAL 就是 1024,单位为 CLK。
HFP:行显示前沿(或前肩),单位是 CLK。
VSYNC:帧(场)同步信号,当此信号有效的时候就表示开始显示新的一帧数据,查阅所使用的
LCD 数据手册可以知道此信号是低电平有效还是高电平有效。
VSPW:帧同步信号宽度,也就是 VSYNC 信号持续时间,单位为 1 行的时间。
VBP:帧显示后沿(或后肩),单位为 1 行的时间。
LINE:帧有效显示区域,即显示一帧数据所需的时间,假如屏幕分辨率为 1024*600,那么 LINE 就是600 行的时间。
VFP:帧显示前沿(或前肩),单位为 1 行的时间。
未搞懂的地方
- 上图的tFrame这个参数尽管原子工程师告诉我是调试出来,但我认为这个值应该有所依据才对。
- 寄存器配置的依据没搞懂,尽管看了OV官方的文档还是不太明白。
- LCD显示时序图1中关于行/场同步、行/场显示前沿、行/场显示后沿参数的来源并未在LCD规格书中找到。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)