生成的工程中,可以在BSP中找到XVTC的驱动代码。 其中的xvtc.h是总的头文件,其中定义了各种参数, xvtc_hw.h是硬件相关的定义,定义了各个寄存器的offset,各个bit位的mask,并给出了各个基础宏的alias宏别名,以及各个基础宏拟函数的encapsulation,宏拟函数的再封装,形成宏拟函数别名。 +++++++++++++++++++++++++++++++++++++++++++++++++++ xvtc.h解析。 1)XVTC_VMODE_* 定义了各种VMODE对应的参数值。 2)XVTC_EN_GENERATOR,XVTC_EN_DETECTOR 使能generator或者detector对应的参数值。 3)XVtc_Config 定义了RDB的结构体。(resource description block) 4)XVtc_Polarity 定义了PDB的结构体。(parameter description block) 5)XVtc_SourceSelect 定义了PDB的结构体。 6)XVtc_Signal 定义了PDB的结构体。 7)XVtc_HoriOffsets 定义了PDB的结构体。 8)XVtc_Timing 定义了PDB的结构体。 9)XVtc 定义了RCB的结构体。(resource description block)
- XVtc_Reset
宏拟函数,封装了具体操作。 11)XVtc_SyncReset 宏拟函数,封装了具体操作。 12)XVtc_EnableSync 宏拟函数,封装了具体操作。 13)XVtc_RegUpdateEnable 宏拟函数,封装了具体操作。 14)XVtc_IntrEnable 宏拟函数,封装了具体操作。 15)XVtc_IntrClear 宏拟函数,封装了具体操作。
+++++++++++++++++++++++++++++++++++++++++++++++++++++ xvtc.c解析。 1)XVtc_EnableGenerator 使能generator。 这里使用了嵌入式中常用的技巧,就是bitmask。 如果是set bit,那么就使用自或赋值运算符,和mask进行自或运算,
CtrlRegValue |= XVTC_CTL_GE_MASK;
如果是clear bit,那么就使用自与赋值运算符,和mask的反码进行自与运算,注意反码要进行类型强转,
CtrlRegValue &= (u32)(~(XVTC_CTL_GE_MASK));
2)XVtc_SetPolarity 设置video timing中各个信号的极性值。 在SOD设计思想下,各个信号的极性值,被封装为一个PDB。本函数利用PDB中的数据,写入寄存器的对应bit。
if (PolarityPtr->ActiveVideoPol)
PolRegValue |= XVTC_POL_AVP_MASK;
3)XVtc_GetPolarity 获取video timing中各个信号的极性值。 在SOD设计思想下,各个信号的极性值,被封装为一个PDB。本函数读取寄存器值后,使用bitmask分离出各个bit的值,判断后,修改PDB中的各个成员变量。
if (PolRegValue & XVTC_POL_ACP_MASK)
PolarityPtr->ActiveChromaPol = 1;
4)XVtc_SetSource 设置video timing中各个信号的极性值源自于哪个寄存器。 如果设置为1,则源自于generator,如果是0,则源自于detector。 在SOD设计思想下,各个信号的极性源,被封装为一个PDB。本函数利用PDB中的数据,写入寄存器的对应bit。
5)XVtc_SetSkipLine 设置chroma信号是否跳行,跳行参数是一个单独的参数,不需要封装成PDB结构体。所以传递时,直接传值即可,不需要传址。
6)XVtc_GetSkipLine 获取chroma信号是否跳行,跳行参数是一个单独的参数,不需要封装成PDB结构体。但是需要将获取的值写入buffer,所以仍然需要传址,只不过,传址不是PDB的指针,而是单独的整形变量的指针。
7)XVtc_SetSkipPixel 设置chroma信号是否跳像素,跳像素参数是一个单独的参数,不需要封装成PDB结构体。所以传递时,直接传值即可,不需要传址。
8)XVtc_GetSkipPixel 获取chroma信号是否跳像素,跳像素参数是一个单独的参数,不需要封装成PDB结构体。但是需要将获取的值写入buffer,所以仍然需要传址,只不过,传址不是PDB的指针,而是单独的整形变量的指针。
9)XVtc_SetDelay 设置horidelay和vertdelay。 两个参数,是单独的整形变量,不需要封装成PDB结构体。所以传递时,直接传值即可。不需要传址。 这里使用了嵌入式中常用的技巧,就是bitsmask。 如果是create bitvector,就使用与运算符,使参数和bitsmask进行与运算。并赋值给中间临时变量。
RegValue = HoriDelay & XVTC_GGD_HDELAY_MASK;
这里还使用了嵌入式中常用的技巧,就是bitshift。 不同于mask的set或者clear方式, bitshift是用宏指定移动的位数,使用左移操作符或者右移操作符, 通过shift left 或者shift right,将参数值,搬移到合适的window上, 然后再使用bitsmask,生成bitvector, 然后再使用自或赋值运算,将生成的bitvector,插入到中间变量中去。
RegValue |= (VertDelay << XVTC_GGD_VDELAY_SHIFT)
& XVTC_GGD_VDELAY_MASK;
10)XVtc_GetDelay 获取horidelay和vertdelay。 两个参数,是单独的整形变量,不需要封装成PDB,但是需要将获取的值写入buffer,所以仍然需要传址,只不过,传址不是PDB的指针,而是单独的整形变量的指针。 这里,仍然使用了bitsmask,用与运算create bitvector。
*HoriDelayPtr = RegValue & XVTC_GGD_HDELAY_MASK;
先使用bitsmask,用与运算来create bitvector, 得到bitvector后,使用了bitshift,将bitvector,搬移到合适的window上。
*VertDelayPtr = (RegValue & XVTC_GGD_VDELAY_MASK)
>> XVTC_GGD_VDELAY_SHIFT;
11)XVtc_SetFSync 设置fsync的位置,
12)XVtc_GetFSync 获取fsync的位置,
13)XVtc_SetGeneratorHoriOffset 设置以line number为单位的位置,即vblank和vsync, 这些参数被封装成为PDB,所以需要传址, 通过start position和end position的形式给出。 vtc内部维护计数器,在start的位置拉高信号,在end的位置拉低信号,
14)XVtc_GetGeneratorHoriOffset 获取vblank和vsync,以line number为单位的位置 这些参数被封装成为PDB,所以需要传址,
15)XVtc_SetGenerator 设置timing的size等参数, 16)XVtc_GetGenerator 获取timing的size等参数。
17)XVtc_ConvVideoMode2Timing 根据videomode 填充timing的PDB结构体的各项参数。 18)XVtc_ConvTiming2Signal 根据timing的PDB结构体中的各项参数,填充XVtc_Signal的PDB,XVtc_HoriOffsets的PDB,XVtc_Polarity的PDB。 19)XVtc_SetGeneratorTiming 根据根据timing的PDB结构体中的各项参数,首先转换成各种signal的PDB,然后,依次将各个signal的PDB中的参数,写入对应的REG中。
20)XVtc_SetGeneratorVideoMode 根据videomode,首先将mode转化成timing的PDB,然后,调用XVtc_SetGeneratorTiming,将各项参数,写入对应的REG中。
++++++++++++++++++++++++++++++++++++++++++++++++++ 实际使用时,使用高层次的封装函数,通常就够用了。 例如: XVtc_SetGeneratorVideoMode 或者 XVtc_SetGeneratorTiming
如果需要精细的定制timing,就需要手工修改timing的PDB中的各项参数,然后再写入REG。
除了设置参数, 还需要setsource,以及enable,以及regupdateenable.
下面以720p模式为例,分析timing的PDB。 首先学习几个重要的参数, 在signalcfg这个PDB中,有如下参数: originmode----Set Frame Origin to Start of Active Video
Htotal----这是VTC的HCNT的计数器总数,例如为7,则HCNT计数从0到6,周而复始, Hactivestart----当检测到HCNT为此值时,拉高active_video信号,同时拉低hblank, Hfrontporchstart----当检测到HCNT为此值时,拉低active_video信号,同时拉高hblank, Hsyncstart----当检测到HCNT为此值时,拉高hsync, Hbackporchstart----当检测到HCNT为此值时,拉低hsync,
Vtotal----这是VTC的VCNT的计数器总数,例如为7,则VCNT计数从0到6,周而复始。 Vactivestart----当检测到VCNT为此值时,拉高内部信号Vactiveen,它和active_video在内部相与,此时,active_video可以输出. Vchromastart----当检测到VCNT为此值时,拉高内部信号Vchromaen,它和active_chroma在内部相与,此时,active_chroma可以输出. Vfrontporchstart----当检测到VCNT为此值时,拉低内部信号Vactiveen,同时拉高vblank, Vsyncstart----当检测到VCNT为此值时,拉高vsync, Vbackporchstart----当检测到VCNT为此值时,拉低vsync,
By default, the blanking signal rises at the same clock edge the last active video signal (of a frame) falls and falls at the same clock edge the first active video signal (of a frame) rises. Also by default, the vsync signals rises and falls at the same clock edge as a rising edge of the 6th rising edge of the hblank signal. 所以,我们看到,Hblank的包络区域,和active_video的包络区域是相反的。 而且,我们看到,Vblank的上升沿对齐到Hblank的上升沿,Vblank的下降沿对齐到Hblank的下降沿。
也可以精调vblank的上升沿和下降沿位置, 如果要使vblank的上升沿不对齐于hblank的上升沿,例如,hblank在1280时上升,那么,设置vblank在1285上升,可以使vblank上升沿滞后5个clk, 如果要是vblank的下降沿不对齐于hblank的下降沿,例如,hblank在1650时下降,那么,设置vblank在1645下降,可以使vblank下降沿提前5个clk,
也可以精调vsync的上升沿和下降沿位置, 如果要使vsync的上升沿不对齐于hblank的上升沿,例如,设置vsync在0上升,可以使vsync上升沿对齐到active_video的上升沿,即hblank的下降沿, 如果要是vsync的下降沿不对齐于hblank的上升沿,例如,设置v在1275下降,可以使vsync下降沿提前于active_video的下降沿即hblank的上升沿,5个clk下降,
在timing这个PDB中,有如下参数: HActiveVideo----一行的有效像素数 HFrontPorch----Hblank的前部门廊的像素数, HSyncWidth----Hblank的Hsync的像素数, HBackPorch----Hblank的后部门廊的像素数, HSyncPolarity----Hsync的极性
VActiveVideo----一帧的有效像素行数 V0FrontPorch----Vblank的前部门廊行数, V0SyncWidth----Vblank的Vsync的行数, V0BackPorch----Vblank的后部门廊行数, VSyncPolarity----Vsync的极性
调用API,可以将timing的格式转换成signalcfg的格式, 通常使用timing格式。
++++++++++++++++++++++++++++++++++++++++++++++++ 补充: 嵌入式中常用的位操作。 对于一个32位的U32 的int,我们需要把它整理成bit segment。 这就需要用到嵌入式中的多种位操作技巧。 例如,bitmask,bitshift,等等。 对于一个U32的int,在没有进行位处理时,我们可以视为bitstring, 对于一个U32的int,如果只有某个感兴趣的有效区域为全1,其余的不感兴趣的无效区域为全0,那么我们称之为一个bitvector。 bitvector和bitstring的区别就在此,一个具有ROI,一个不具有ROI。 显然,bitmask就是一个U32,而它,就是一个bitvector。
我们使用bitmask或者bitsmask, 如果使用与操作符&,对bitstring进行处理后,就起到了get value of ROI 的作用。 如果使用或操作符|,对bitstring进行处理后,就起到了set value of ROI 的作用。 如果使用与操作符&,但是是使用的opposite mask,就起到了clear value of ROI的作用。
对于一个已经包含了ROI的bitvector,(通常是本步骤的运算结果),通常使用或操作符|,插入到另一个btivector中,(通常是中间临时变量),从而形成一个更新的中间结果。 这里,或操作符|,起到"拼位运算符"的作用。
|