在视频处理电路中使用Philips公司提供的可编程视频输入处理芯片SAA7111,大大降低了视频输入处理部分的设计难度,减小了电路板的制作尺寸,因此,它被广泛应用于视频桌面系统、图像多媒体、数字电视、图像处理和视频电话等领域。而使用SAA7111的前提是首先实现对SAA7111的初始化,利用DSP或者单片机对SAA7111进行初始化已有报道。本文在简单介绍I2C总线和SAA7111芯片的基础上,重点介绍使用FPGA(现场可编程门阵列)模拟I2C(Inter-Integrated Circuit)总线接口对SAA7111进行初始化。 1 I2C总线技术简介 I2C总线是一种由SDA(串行数据线)和SCL(串行时钟线)组成的串行总线,它利用这两根总线在MCU(微控制单元)与被控IC之间进行双向数据传送,各种被控电路均并联在这条总线上。当总线备用时,两根线都是高电平,只有当总线关闭时,SCL才转变为低电平。在标准模式下,I2C总线的数据传输速度可达100 kbit/s,在高速模式下则可达400 kbit/s。由于在I2C总线上每传输一位数据都有1个时钟脉冲相对应,所以,I2C总线的时钟周期一般在2.5 s~10 s之间。 I2C总线为同步传输总线,其中与数据传输有关的信号有开始信号、停止信号、应答信号和位传输等4种类型。开始信号是在SCL为高电平期间,SDA出现由高电平向低电平的变化,由此启动I2C总线,如图1(a)所示。停止信号是在SCL为高电平期间,SDA出现由低电平向高电平的变化,它意味着即将停止I2C总线的数据传输,如图1(b)所示。应答信号是指接收数据的IC在接收到发送方发送的8 bit数据后,应向发送数据的IC发出特定的低电平脉冲,表示已经完成本次数据的接收。数据位传输是在I2C总线启动后或应答信号后的第1~8个时钟脉冲对应于1个字节的8个bit位的数据传输。SCL在高电平期间,数据串行传输;SCL在低电平期间,容许SDA上的电平发生转换,为数据发送做准备。 图1 I2C总线开始信号和停止信号 I2C总线在进行数据传输时,每一帧数据均为1个字节,并且按照由高到低的顺序发送1个字节的8个bit。对于每个bit数据的传输,要求在时钟信号为高电平期间,数据线上的数据必须保持稳定的逻辑电平状态。只有在时钟线为低电平时,才允许数据线上的电平状态发生变化。另外,在启动I2C总线后,传输的字节数没有限制,只要求每传输一个字节,对方回应一个应答信号。 I2C总线的工作方式分为多主工作方式和单主工作方式。其中,在单主方式下,I2C总线上只有1个主器件成为主节点,该节点会永远占用I2C总线,而不会出现总线竞争的现象。在这种情况下,主器件若没有I2C总线接口,就可以利用其IO来模拟I2C总线接口。在视频采集系统中,采用的就是单主工作方式,FPGA为I2C总线的主节点。 2 SAA7111芯片简介 SAA7111是一款功能强大的模拟前端和数字视频译码器,常应用在嵌入式视频应用的高度集成的电路中。内部包含两路模拟处理通道,能实现视频源的选择、抗混叠滤波、A/D转换、自动嵌位、自动增益控制、时钟产生、多制式解码以及亮度、对比度和饱和度的控制,从而将PAL、NTSC等不同制式的模拟复合视频数据解码成亮度、色度和相关同步的数字信号,而这些功能是依靠外部控制器对它内部寄存器的设置来实现的,本系统中就是利用FPGA实现对它内部寄存器的设置。SAA7111原理框图如图2所示。 图2 SAA7111功能方框图 工作时,模拟视频图像从SAA7111的4个输入端口(AI11,AI12,AI21,AI22)中的一个端口输入,经模拟处理后,一路通过缓冲器从模拟输出端(AOUT)输出用于监视,另一路经A/D后产生数字色度信号、亮度信号,分别进行亮度信号处理、色度信号处理。亮度信号处理的结果,一路送到色度信号处理器进行综合处理,产生Y、U、V信号,经格式化后从VPO输出,输出的信号格式有422YUV或CCIR-656(8位)等;另一路进入同步分离器,经数字PLL,产生相应的行、场同步信号HS、VS及像素时钟信号LLC和LLC2等信号,这些信号是实现视频数据采集的依据。 3 SAA7111初始化的FPGA设计 在视频处理系统中,SAA7111是视频的输入处理部分,主要实现模拟输入视频信号的数字化;但在它工作之前,FPGA应通过SAA7111的I2C总线接口对其进行初始化。在SAA7111正常工作后,FPGA再根据SAA7111输出的行、场信号和像素时钟信号,实现视频的数字采集,并将采集的数据传输到后续的处理芯片中。关于SAA7111和外围器件的详细连接可参考SAA7111的芯片资料。SAA7111和FPGA的连接图如图3所示。 图3 SAA7111和FPGA的连接 FPGA对SAA7111进行初始化,必须解决以下几个问题:首先是产生I2C总线的时钟信号;其次是实现I2C总线的开始信号、停止信号、位传输信号和判断应答信号;再次是要确定SAA7111不同寄存器的设置数据。
3.1 I2C总线时钟的产生 一般情况下,FPGA的时钟频率较高,常为几十MHz,而I2C总线的时钟频率为几百kHz,用图4的方式可借助于FPGA的时钟获得I2C总线的时钟。需要说明的是,图中工作时钟的频率应为I2C总线时钟频率的M倍。这是因为系统中的任何一个I2C总线上的信号都是用M个工作时钟的周期来完成,而D触发器则是为了确保工作时钟的占空比为50%而设计的。 图4 12C总线时钟产生图 假设FPGA时钟为50 MHz,I2C总线时钟为200 kHz,M为8,则工作时钟为1.6 MHz,再考虑到D触发器相当于2分频,则 N= 50MHz/(200 kHz×8×2) = 16
3.2 关键信号的产生和传输 根据前面对I2C总线开始信号的讨论,再结合3.1节的设计将利用8个工作时钟产生一个I2C总线信号,很容易设计出I2C总线的开始信号。即规定:第1个脉冲上升沿到第3个脉冲上升沿之间,SCL为低、SDA为高;第3个脉冲上升沿到第5个脉冲上升沿之间,SCL为高、SDA为高;第5个脉冲上升沿到第7个脉冲上升沿之间,SCL为高、SDA为低;第7个脉冲上升沿到第9个脉冲上升沿之间,SCL为低、SDA为低。这样经过8个脉冲周期,就可产生一个开始信号。具体如图5所示。 图5 I2C总线开始信号设计时序 相应的VHDL源程序代码如下(假设为S1状态) if clk'event and clk='1' then case cnt is when 0|1 scl<='0';sda<='1';cnt:=cnt+1; when 2|3 scl<='1';sda<='1';cnt:=cnt+1; when 4|5 scl<='1';sda<='0';cnt:=cnt+1; when 6 scl<='0';sda<='0';ent:=ent+1; when 7 cnt:=0;tempstate<=S2; when others=>tmpstate<=S0; end case; end if; 其中:cnt为工作时钟clk的计数器变量,初始值为0;S2为启动I2C总线后的下一个的状态;tmpstate为状态变量。停止信号也很容易照此设计,在此不再累赘。 而对于数据bit位的传输,根据I2C总线规范要求,在数据位的传输过程中,SDA信号在SCL信号为高电平期间不容许发生跳变,可用SCL高电平期间的前、后各1个脉冲来作为数据的建立时间和保持时间。由此得到如图6所示的数据bit的传输设计。 图6 I2C总线数据位reg的设计时序 传输‘reg'(代表“0”或“1”)的源程序代码如下(假设为S4状态): if clk'event and clk='1' then case cnt is when 0 scl<='0';sda<='1';cnt:=cnt+1; when 1 scl<='0';sda<=reg;cnt:=cnt+1; when 2|3|4 scl<='1';cnt:=cnt+1; when 5 scl<='0';cnt:=cnt+1; when 6 sda<='1';cnt:=cnt+1; when 7 cnt:=0;bitnum:=bitnum+1;tempstate<=S3; when others=>tmpstate<=S0; end case; end if; 其中:reg为信号寄存器,可以直接与SDA线相连;bitnum为表示正在传输字节的第几个bit数据。这样,在一个bit位数据传输的基础上,使用一个8 bit的寄存器存储要传输的字节,很容易实现1字节数据的传输。比如,在类型为std_logic_vector(7 downto 0)的寄存器ByteReg中存放着待发的数据,则传输1字节数据相应的源程序代码如下(假设为S3状态): if clk'event and clk='1'then if bitnum>7 then bitnum:=0;sendnum:=sendnum+1; tmpstate<=S5; else ent:=0;reg<=ByteReg(bitnum); tmpstate<=S4; end if; end if; 其中,S5用来等待来自SAA7111的应答信号。需要注意的是,在程序中要将SDA设置成inout类型的端口,在发送数据时是输出端口,而在检查SAA7111的ACK信号时,又是输入端口。至于发送完一个字节的数据后,要等待SAA7111返回的ACK信号,就是检查来自SDA上的逻辑状态是否为低电平信号“0”,在此不再累赘。
3.3 SAA7111寄存器的设置 对SAA7111进行初始化本质上是对SAA7111内部的每个寄存器的每一位写入相应的数值,SAA7111的32个寄存器(00H~1FH)中有22个是可编程的,有些是可读寄存器,保存着芯片和厂商的标识等信息,真正需要编程的只有19个,其中每个寄存器都有一个子地址。在对多个连续的寄存器进行操作时,寄存器地址有自动加1功能,所以确定第1个子地址后,可以不考虑地址的变化,顺序写入各寄存器的数值即可实现寄存器的连续设置。另外,在对SAA7111初始化时,还需要确定从地址,而从地址由硬件连接图决定,当芯片引脚IICSA信号是低电平时,表示SAA7111的写地址为48H。芯片的各个寄存器的意义可以参考SAA7111的文档资料。 系统若设置为自动增益控制、625行50 Hz、PAL制式、YUV422的16位数字视频信号输出,则寄存器初始化值如表1所列。
表1 系统中SAA7111寄存器初始化值 SubAddress | Data | SubAddress | Data | 00H | 00H | 01H | 00H | 02H | C1H | 03H | 33H | 04H | 00H | 05H | 00H | 06H | EBH | 07H | E0H | 08H | 88H | 09H | 01H | 0AH | 80H | 0BH | 47H | 0CH | 40H | 0DH | 00H | 0EH | 01H | 0FH | 00H | 10H | 40H | 11H | 1CH | 12H | 03H | | | 这样,系统的入口参数可定义为:SAA7111的从地址为48H,子地址为00H,随后是SAA7111各寄存器应该设置的19个数据,共21个字节的数据,相应地在代码中可以定义如下数据类型存放这些寄存器的数值: type dataram is array(18 downto 0)of std_logic_ vector(7 downto 0) 这样,程序的主要功能就是将这些数据通过I2C总线正确写入SAA7111的芯片中。4 SAA7111初始化的实现 SAA7111的工作模式、输入端口选择、色彩控制等图像采集的控制参数都是由其内部的寄存器决定,FPGA可通过SAA7111的I2C总线接口对其内部寄存器进行读写操作,具体的写时序如图7所示。
Start Slave | address W | ACK-s | SubAddress W | ACK-s | Data(Nbytes) | ACK-s | Pause | 图7 SAA7111 初始化写入数据的时序 其中:Start为开始信号;Slave address为从地址;ACK-s为从器件发出的应答信号;SubAddress为子地址;Data(N bytes)为要写的各数据;Pause为停止信号。当N=1时,表示要传一个数据;当N>1时,表示要传多个数据,同时将完成片内子地址的自动增加,实现对地址连续的寄存器的写操作。这里N=19。 本系统用状态转移图来实现,首先定义了dataram数组类型的变量SendData,用来保存所有将要写入SAA7111芯片的数据,定义sendnum表示SendData的下标变量,随着sendnum的改变,可以读取SendData(sendnum)不同的8 bit字节数据。其中不同位置字节的变量,定义bitnum变量代表同一字节中不同bit位的变量。这样,程序代码初始化用S0完成,随后,进入S1状态。在S1状态下FPGA完成向SAA7111发送起始信号,随后进入S2状态。S2是一个检测状态,它检查数据是否发送完毕,若sendnum为19,则表示数据发送完毕,则程序跳转状态S6;否则,表示没有发送完毕,则将SendData(sendnum)数据赋给发送的字节寄存器ByteReg,随后进入S3状态。S3状态则根据bit.num检查字节ByteReg是否发送完毕,若发送完毕,则跳转到S5状态;否则,跳转到S4状态。S4状态实现一个bit位的发送,发送完毕后,bitnum加1,再跳转回s3。s5用来检查来自SAA7111的应答信号,若检测到SDA为低电平,则表明一个字节数据发送完毕,sendnum加1,返回S2状态。S6状态用来发送停止信号。 至此,SAA7111的初始化过程完毕,系统具体的状态转移图如图8所示。 图8 SAA7111初始化的时序流程 需要注意的是,在S5状态中,为了避免由于器件工作异常而引起的死循环,设置一个超时计数器,当等待时间超过超时计数器设置的数值,则跳初始化状态S0,重新对SAA7111进行配置。5 结束语 本方案引入SAA7111视频输入处理芯片,简化了系统的硬件设计,通过FPGA对12C总线两条传输线的时序模拟,完成了对视频输入处理芯片的控制,正确实现了对SAA7111的初始化。实验结果表明该方案灵活、方便、可行,也很稳定。需要指出的是:由于FP.GA时钟频率过高,可利用分频技术,使得I2C总线时钟频率在规范要求的范围内,同时,在开发过程中要严格按照I2C总线的时序要求编写相关代码。
|