手机扫码
链接直达
https://item.taobao.com/item.htm?ft=t&id=776516984361
上一教程讲完了SDRAM作为缓存HDMI显示,因为摄像头与HDMI TX的时钟不同频帧率也不一样,所以也需要SDRAM缓存一下,只是把上一课的测试pattern换成video_tpg_24b,但是为了工程的完整性我们没有直接替换掉video_tpg_24b而是用了一个宏TEST_PATTERN来进行测试pattern和摄像头的切换,TEST_PATTERN默认不使能。
工程解析
工程层次图
图中其它模块都跟上一教程相同不再介绍,只是增加了红框中的三个模块。这三个模块主要功能如下:
- u_i2c_master —— 由于ov5640需要通过IIC配置其寄存器才能输出我们所需格式的图像,该模块就是一个IIC Master控制器。
- u_ov5640_rgb565_cfg——这个模块驱动u_i2c_master配置OV5640,它控制配置寄存器的流程,并输出配置完成信号。
- u_cmos_data_cvt——这个模块主要是将OV5640输出的两个8bit的RGB信号拼接成RGB565信号
代码分析
u_i2c_master
module i2c_master
#(// slave address(器件地址),放此处方便参数传递
parameter SLAVE_ADDR = 7'b1010000 ,
parameter CLK_FREQ = 27'd50_000_000, // i2c_dri模块的驱动时钟频率(CLK_FREQ)
parameter I2C_FREQ = 18'd250_000 // I2C的SCL时钟频率
)(
//global clock
input clk , // i2c_dri模块的驱动时钟(CLK_FREQ)
input rst_n , // 复位信号
//i2c interface
input i2c_exec , // I2C触发执行信号
input bit_ctrl , // 字地址位控制(16b/8b)
input i2c_rh_wl , // I2C读写控制信号
input [15:0] i2c_addr , // I2C器件内地址
input [ 7:0] i2c_data_w , // I2C要写的数据
output reg [ 7:0] i2c_data_r , // I2C读出的数据
output reg i2c_done , // I2C一次操作完成
output reg scl , // I2C的SCL时钟信号
inout sda , // I2C的SDA信号
//user interface
output reg dri_clk // 驱动I2C操作的驱动时钟
);
...
endmodule
模块的端口在代码中有比较详细的注释,主要注意以下几点:
- bit_ctrl是设置地址位是8位还是16位,OV5640是16位因此需要设置为1。
- i2c_exec是用来发起一次I2C操作,相当于读或者写一个OV5640的寄存器,这个信号由u_ov5640_rgb565_cfg。
- i2c_done是告诉一次I2C操作已完成,相当于完成一次OV5640的寄存器读或者写操作,告诉u_ov5640_rgb565_cfg可以进行下一次操作了。
整个代码就是一个大状态机,代码中注释很详细就不过多解释了。
u_ov5640_rgb565_cfg
这个模块的代码的逻辑就是通地init_reg_cnt计数器,将250个寄存器的值通过u_i2c_master 挨个输出。
u_cmos_data_cvt
这个模块首先是对OV5640输出的VS信号进行然行边沿检测,并对VS的边沿计数,目的是扔掉OV5640前面不稳定数据帧。
然后就是将8位数据转16位RGB565数据,注意为了让数据有效信号cmos_frame_valid跟数据的中间对齐,将这个信号的寄存器byte_flag 多延长了一拍。
管脚约束
管脚约束部分主要添加了摄像头的管脚,都是LVCOM33即可。
摄像头的管脚分布在原理图这个地方,coms_x这个脚是预留的,摄像头上是NC的,所以可以不管。
set_pin_assignment { cam_data[0] } { LOCATION = P70; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_data[1] } { LOCATION = P71; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_data[2] } { LOCATION = P72; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_data[3] } { LOCATION = P74; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_data[4] } { LOCATION = P75; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_data[5] } { LOCATION = P76; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_data[6] } { LOCATION = P77; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_data[7] } { LOCATION = P78; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_hsync } { LOCATION = P59; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_pclk } { LOCATION = P79; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_pwdn } { LOCATION = P87; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_rst_n } { LOCATION = P66; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_scl } { LOCATION = P57; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { cam_sda } { LOCATION = P62; IOSTANDARD = LVCMOS33; PULLTYPE = PULLUP; }
set_pin_assignment { cam_vsync } { LOCATION = P52; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { clk_10m } { LOCATION = P11; IOSTANDARD = LVCMOS33; PULLTYPE = NONE; }
set_pin_assignment { i_rst_n } { LOCATION = P83; IOSTANDARD = LVCMOS33; PULLTYPE = PULLUP; }
#HDMI TX
set_pin_assignment { HDMI_CLK_P } { LOCATION = P47; IOSTANDARD = LVDS33; }
set_pin_assignment { HDMI_D0_P } { LOCATION = P55; IOSTANDARD = LVDS33; }
set_pin_assignment { HDMI_D1_P } { LOCATION = P61; IOSTANDARD = LVDS33; }
set_pin_assignment { HDMI_D2_P } { LOCATION = P64; IOSTANDARD = LVDS33; }
时序约束
#Created Clock
create_clock -name clk_10m -period 100 [get_ports {clk_10m}]
# Create camera clock
create_clock -name cam_pclk -period 20.8333 [get_ports {cam_pclk}]
# Automatically constrain PLL and other generated clocks
derive_pll_clocks
rename_clock -name {clk_sdr_ref} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[0]}]
rename_clock -name {clk_sdr_out} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[1]}]
rename_clock -name {clk_pixel} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[2]}]
rename_clock -name {clk_pixel_5x} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[3]}]
rename_clock -name {clk_i2c_36m} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[4]}]
#
rename_clock -name {clk_pll4cam} -source [get_ports {cam_pclk}] -master_clock {cam_pclk} [get_pins {u_pll4cam/pll_inst.clkc[0]}]
# Group constrain
set_clock_groups -exclusive -group [get_clocks {clk_10m}] -group [get_clocks {clk_i2c_36m}] -group [get_clocks {cam_pclk}] -group [get_clocks {clk_pll4cam}] -group [get_clocks {clk_sdr_out}] -group [get_clocks {clk_sdr_ref}] -group [get_clocks {clk_pixel clk_pixel_5x}]
创建系统时钟,即板载的10M时钟:
create_clock -name clk_10m -period 100 [get_ports {clk_10m}]
创建摄像头的时钟,OV5640当前配置为48M:
create_clock -name cam_pclk -period 20.8333 [get_ports {cam_pclk}]
让TD工具自动推导PLL的约束:
derive_pll_clocks
对PLL生成的钟进行重命名,方便后面的约束。
rename_clock -name {clk_sdr_ref} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[0]}]
rename_clock -name {clk_sdr_out} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[1]}]
rename_clock -name {clk_pixel} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[2]}]
rename_clock -name {clk_pixel_5x} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[3]}]
rename_clock -name {clk_i2c_36m} -source [get_ports {clk_10m}] -master_clock {clk_10m} [get_pins {u_system_ctrl_pll/u_sys_pll/pll_inst.clkc[4]}]
对摄像头进来的时钟进PLL之后进行重命名处理
rename_clock -name {clk_pll4cam} -source [get_ports {cam_pclk}] -master_clock {cam_pclk} [get_pins {u_pll4cam/pll_inst.clkc[0]}]
设置工程中的时钟全部为异步,因为跨时钟的数据都做了跨时钟域处理,不需要工具分析。
set_clock_groups -exclusive -group [get_clocks {clk_10m}] -group [get_clocks {clk_i2c_36m}] -group [get_clocks {cam_pclk}] -group [get_clocks {clk_pll4cam}] -group [get_clocks {clk_sdr_out}] -group [get_clocks {clk_sdr_ref}] -group [get_clocks {clk_pixel clk_pixel_5x}]
实验效果
没有回复内容