TI 生成 TPG 流程 Test Pattern Generator
TI 生成 TPG Test Pattern Generator
1.主要作用:
- 生成各种预定义的图形和模式用来检查CSI接口的图像传输质量
- 调试和验证使用TPG生成的测试图形可以方便地验证接口的正确性和稳定性
2.代码中的体现
static const char * const ub960_tpg_qmenu[] = {
"Disabled",
"1 vertical color bar",
"2 vertical color bars",
"4 vertical color bars",
"8 vertical color bars",
};
v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler, &ub960_ctrl_ops, //向链表中新增一个菜单式控制变量
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ub960_tpg_qmenu) - 1, 0, 0,
ub960_tpg_qmenu);
static const struct v4l2_ctrl_ops ub960_ctrl_ops = {
.s_ctrl = ub960_s_ctrl,
};
static int ub960_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct ub960_data *priv =
container_of(ctrl->handler, struct ub960_data, ctrl_handler);
switch (ctrl->id) {
case V4L2_CID_TEST_PATTERN:
if (ctrl->val == 0)
ub960_disable_tpg(priv);
else
ub960_enable_tpg(priv, ctrl->val);
break;
}
return 0;
}
总结: 向 subdev 链表中新增一个菜单式控制变量 ub960_s_ctrl(tpg0)用来使能tpg功能 (可控条树的条纹)
3.开启/关闭 tpg
开启:
static void ub960_enable_tpg(struct ub960_data *priv, int tpg_num)
{
/*
* Note: no need to write UB960_REG_IND_ACC_CTL: the only indirect
* registers target we use is "CSI-2 Pattern Generator & Timing
* Registers", which is the default
*/
/*
* TPG can only provide a single stream per CSI TX port. If
* multiple streams are currently enabled, only the first
* one will use the TPG, other streams will be halted.
*/
struct v4l2_mbus_framefmt *fmt;
u8 vbp, vfp;
u16 blank_lines;
u16 width;
u16 height;
u16 bytespp = 2; /* For MEDIA_BUS_FMT_UYVY8_1X16 */
u8 cbars_idx = tpg_num - TEST_PATTERN_V_COLOR_BARS_1;
u8 num_cbars = 1 << cbars_idx;
u16 line_size;
u16 bar_size;
u16 act_lpf;
u16 tot_lpf;
u16 line_pd;
struct v4l2_subdev_state *state;
state = v4l2_subdev_lock_active_state(&priv->sd);
vbp = 33;
vfp = 10;
blank_lines = vbp + vfp + 2; /* total blanking lines */
fmt = v4l2_state_get_stream_format(state, 4, 0);
width = fmt->width;
height = fmt->height;
line_size = width * bytespp;
bar_size = line_size / num_cbars;
act_lpf = height;
tot_lpf = act_lpf + blank_lines;
line_pd = 100000000 / 60 / tot_lpf;
/* Disable forwarding from FPD-3 RX ports */
ub960_write(priv, UB960_SR_FWD_CTL1,
UB960_SR_FWD_CTL1_PORT_DIS(0) |
UB960_SR_FWD_CTL1_PORT_DIS(1));
/* Access Indirect Pattern Gen */
ub960_write(priv, UB960_SR_IND_ACC_CTL,
UB960_SR_IND_ACC_CTL_IA_AUTO_INC | 0);
ub960_write_ind8(priv, UB960_IR_PGEN_CTL,
UB960_IR_PGEN_CTL_PGEN_ENABLE);
/* YUV422 8bit: 2 bytes/block, CSI-2 data type 0x1e */
ub960_write_ind8(priv, UB960_IR_PGEN_CFG, cbars_idx << 4 | 0x2);
ub960_write_ind8(priv, UB960_IR_PGEN_CSI_DI, 0x1e);
ub960_write_ind16(priv, UB960_IR_PGEN_LINE_SIZE1, line_size);
ub960_write_ind16(priv, UB960_IR_PGEN_BAR_SIZE1, bar_size);
ub960_write_ind16(priv, UB960_IR_PGEN_ACT_LPF1, act_lpf);
ub960_write_ind16(priv, UB960_IR_PGEN_TOT_LPF1, tot_lpf);
ub960_write_ind16(priv, UB960_IR_PGEN_LINE_PD1, line_pd);
ub960_write_ind8(priv, UB960_IR_PGEN_VBP, vbp);
ub960_write_ind8(priv, UB960_IR_PGEN_VFP, vfp);
v4l2_subdev_unlock_state(state);
}
//关闭
static void ub960_disable_tpg(struct ub960_data *priv)
{
/* TPG off, enable forwarding from FPD-3 RX ports */
ub960_write(priv, UB960_SR_FWD_CTL1, 0x00);
ub960_write_ind8(priv, UB960_IR_PGEN_CTL, 0x00);
}
4.对上述理解的一些重要的概念
VFP: Vertical front porch,垂直前肩;
VBP: Vertical back porch,垂直后肩;
act_lpf:Active Lines Per Frame 活动行数
tot_lpf:Total Lines Per Frame 总活动行数
基于数字图像水平的一些重要概念(科普作用)
1.场同步 (VSYNC)
告诉电子枪控制电子枪控制器下面要开始新的画面。对于数字图像信息,当VSYNC信号有效时,表示新的一帧图像信息开始了
2.行同步(HSYNC)
行同步就是让电子枪控制器知道下面要开始新的一行像素。每一行信息的开始都有一个HSYNC
3.数据使能(DE)
在数据使能区是有效的色彩数据,不在使能范围内的都显示黑色。下图中灰色区域都是使能数据
4.前肩(Front Porch)/后肩 (Back Porch)
行同步或场同步信号发出后,视频数据不能立即使能,要留出电子枪回扫的时间。以行扫描为例,从HSYNC结束到DE开始的区间成为行扫描的后肩,从DE结束到HSYNC开始称为前肩。具体水平前肩/后肩的含义如下图所示
其他一些缩写
HFP: Horizon front porch,水平前肩;
HBP: Horizon back porch,水平后肩;
HDP:Horizon display period,水平显示周期;
VDP: Vertical display period,垂直显示周期。
5.总结上面的流程
主要流程如下
1.v4l2_subdev_lock_active_state函数获取当前活动的子设备状态。
2.设置垂直后沿和前沿的行数,以及计算总空白行数。
3.从子设备状态中获取视频帧的宽度和高度。
4.计算每行的字节大小(line_size),这是通过宽度乘以每像素的字节数得到的。
5.根据彩色条的数量计算每个彩色条的大小(bar_size)。
6.设置活动行帧数(act_lpf)为视频帧的高度,总帧数(tot_lpf)为活动行帧数加上空白行数。
7.计算每行的像素时钟周期数(line_pd),这里假设视频帧率为60Hz,并假设像素时钟频率为100MHz(100000000)。
参数赋值具体如下
-
vbp = 33;
vfp = 10;
blank_lines = vbp + vfp + 2;
给VFP、VBP 分别赋予33 10;blank_lines 值为33 +10 +2 (并不理解这些值怎么来的,芯片手册没有解释) -
width = fmt->width;
height = fmt->height; //获取分辨率 -
line_size = width * bytespp; //每一个像素点为 2 byte 每一行大小
bar_size = line_size / num_cbars; //每一个条纹的大小
act_lpf = height; //活动行数
tot_lpf = act_lpf + blank_lines; //活动行帧数加上空白行数
line_pd = 100000000 / 60 / tot_lpf; //基于总帧数来估算每行的时间长度(100000000 猜测像素时钟,60为帧率 计算每行时间长度)