VIVADO SDK 中驱动VTC(standaloneOS)

生成的工程中,可以在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)

10) 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中,(通常是中间临时变量),从而形成一个更新的中间结果。
这里,或操作符|,起到"拼位运算符"的作用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值