關(guān)鍵詞:FPGA;高頻時鐘;VHDL
1 引言
隨著應(yīng)用系統(tǒng)向高速度、低功耗和低電壓方向的發(fā)展,對電路設(shè)計的要求越來越高?傳統(tǒng)集成電路設(shè)計技術(shù)已無法滿足性能日益提高的整機系統(tǒng)的要求。同時,由于IC設(shè)計與工藝技術(shù)水平的提高,集成電路規(guī)模越來越大,復(fù)雜程度越來越高。目前已經(jīng)可以將整個系統(tǒng)集成在一個芯片上,即片上系統(tǒng)(System on a Chip?縮寫為SOC),這種芯片以具有系統(tǒng)級性能的復(fù)雜可編程邏輯器件(CPLD)和現(xiàn)場可編程門陣列(FPGA)為主要代表。與主要實現(xiàn)組合邏輯功能的CPLD相比,FPGA主要用于實現(xiàn)時序邏輯功能。對于ASIC設(shè)計來說,采用FPGA在實現(xiàn)小型化、集成化和高可靠性系統(tǒng)的同時,還可以減少風險、降低成本、縮短開發(fā)周期。
2 系統(tǒng)硬件組成
本文介紹的時鐘板主要由于為PET(正電子發(fā)射斷層掃描儀)的前端電子學(xué)模塊提供32路系統(tǒng)時鐘(62.5MHz)和32路同步時鐘(4MHz)。時鐘信號之間的偏差要求在2ns之內(nèi)。為了消除各路時鐘信號之間的偏差,文中介紹利用FPGA來實現(xiàn)主時鐘的分頻、零延時輸出和分配,同時利用LVDS技術(shù)實現(xiàn)多路時鐘的傳輸?shù)膶崿F(xiàn)方法。圖1所示是其硬件設(shè)計示意圖。
由圖1可知,該時鐘電路的具體工作原理是:首先由精密晶體振蕩器產(chǎn)生62.5MHz的時鐘信號,然后經(jīng)時鐘驅(qū)動芯片CY2305輸入FPGA芯片的時鐘引腳GCLK以作為時鐘源。該時鐘在FPGA芯片內(nèi)部經(jīng)DLL(延遲鎖定環(huán))模塊分別生成62.5MHz的系統(tǒng)時鐘和4MHz的同步時鐘?LVTTL電平信號?,然后由內(nèi)部的IOB(輸入輸出功能模塊)分配到64個輸出引腳(32路62.5MHz系統(tǒng)時鐘和32路4MHz同步時鐘),這64路LVTTL電平信號兩兩進入32塊LVDS(兩路)驅(qū)動轉(zhuǎn)換芯片后,即可轉(zhuǎn)換為LVDS信號并通過差分雙絞線傳輸給前端電子學(xué)模塊的32塊數(shù)字電路板。
圖2
2.1 FPGA的結(jié)構(gòu)
單元型FPGA主要由三部分組成:可配置邏輯模塊CLB(Configurable Logic Block),輸入、輸出模塊I/OB和可編程連線PI(Programmable Interconnect)。對于不同規(guī)格的芯片,可分別包含8×8、20×20、44×44甚至92×92個CLB陣列,同時配有64、160、352、甚至448個I/OB以及為實現(xiàn)可編程連線所必需的其它部件。圖2所示是本設(shè)計中使用的XC2S30芯片的內(nèi)部結(jié)構(gòu)。
2.2 Xinlinx公司的SpartanII系列FPGA
Xinlinx公司目前生產(chǎn)的FPGA有兩類代表性產(chǎn)品?一類是XC40003/Spartan系列?另一類是Vir-tex/SpartanII系列。這兩類產(chǎn)品除具有FPGA的三種基本資源(可編程I/O、可編程邏輯功能模塊CLB和可編程布線等)外?還具有片內(nèi)RAM資源。但兩種產(chǎn)品也有所不同。其中XC4000E可以用于實現(xiàn)片內(nèi)分布RAM,同時專門為實現(xiàn)可編程片上系統(tǒng)開發(fā)的Virtex系列,其片內(nèi)分布RAM和塊RAM都可以實現(xiàn),并可實現(xiàn)片上系統(tǒng)所要求的其他性能,如時鐘分配和多種電平接口等特性。SpartanII系列與Virtex系列產(chǎn)品相比,除了塊RAM數(shù)量少于Virtex系列產(chǎn)品外,其余有關(guān)性能(如典型門范圍、線寬、金屬層、芯內(nèi)電壓、芯片輸入輸出引腳電壓、系統(tǒng)頻率和所含DLL個數(shù)等)都基本相同,它的一個突出優(yōu)點(也是本設(shè)計選用該系列芯片的主要原因)是:該系列產(chǎn)品是專門為取代掩膜門陣列的低價位FPGA,在達到門陣列數(shù)量時,其價格可與門陣列相比。因此,本文介紹的時鐘電路的設(shè)計選用SpartanII系列FP-GA中的XC2S30-5PQ208芯片來實現(xiàn)。
3 用FPGA實現(xiàn)時鐘分頻和分配
如圖2所示?SpartanII系列芯片內(nèi)部含有四個全數(shù)字延時鎖定環(huán)(DLL),每一個DLL可驅(qū)動兩個全局時鐘分布網(wǎng)絡(luò)。通過控制DLL輸出時鐘的一個采樣?可以補償由于布線網(wǎng)絡(luò)帶來的時鐘延時,從而有效消除從外部輸入端口到器件內(nèi)部各個時鐘負載的延時。DLL除提供對用戶輸入時鐘的零延時之外,還具有時鐘倍頻和分頻功能。它可以對時鐘源進行兩倍頻和1.5、2、3、4、5、8或16分頻。本設(shè)計就是利用DLL的零延時和分頻功能來實現(xiàn)對62.5MHz時鐘的輸出和16分頻后4MHz(約)時鐘的輸出。
3.1 數(shù)字延時鎖定環(huán)(DLL)的結(jié)構(gòu)原理
圖3是一個DLL的內(nèi)部原理框圖,它由各類時鐘延時線和控制邏輯組成。延時線主要用于對時鐘輸入端CLKIN產(chǎn)生一個延時。通過器件內(nèi)部的時鐘分布網(wǎng)絡(luò)可將該輸入時鐘分配給所有的內(nèi)部寄存器和時鐘反饋端CLKFB??刂七壿媱t主要用于采樣輸入時鐘和反饋時鐘以調(diào)整延時線。這里所說的延時線由壓控延時或衰減延時組件構(gòu)成,SpartanII系列芯片選用了后者。DLL可在輸入時鐘和反饋時鐘之間不停地插入延時,直到兩個時鐘的上升沿同步為止。當兩時鐘同步時,DLL鎖定。在DLL鎖定后,只要輸入時鐘沒有變化,兩時鐘就不會出現(xiàn)可識別偏差。因此,DLL輸出時鐘就補償了時鐘分布網(wǎng)絡(luò)帶來的輸入時鐘延時,從而消除了源時鐘和負載之間的延時。
3.2 DLL功能的實現(xiàn)
SpartanII系列芯片內(nèi)含專門實現(xiàn)DLL功能的宏單元模塊BUFGDLL,其結(jié)構(gòu)簡圖如圖4所示。該模塊由IBUFG、CLKDLL和BUFG三個庫元件組成?其原理框圖如圖5所示。圖5中,CLKDLL庫元件用于實現(xiàn)DLL的主要功能?包括完成時鐘的零延時輸出、時鐘的倍頻以及分頻和鏡像操作。而IBUFG和BUFG則分別實現(xiàn)外部時鐘的輸入以及將輸出時鐘分配到芯片引腳。本設(shè)計的時鐘分頻就是將62.5MHz的時鐘由IBUFG輸入?經(jīng)CLKDLL分頻后再由CLKDV端傳給BUFG?然后經(jīng)片內(nèi)IOBUF分配到芯片的普通I/O輸出引腳。
4 軟件實現(xiàn)
在設(shè)計的總體構(gòu)思和器件選擇完成后,必須進行的工作是建立設(shè)計輸入文件,該文件主要用于描述所設(shè)計電路的邏輯功能。這里使用的是XILINX公司提供的開發(fā)工具FOUNDATION 4.1。本設(shè)計采用硬件描述語言VHDL來設(shè)計,其部分程序如下:
entity lvds is
port (
pclk: in STD LOGIC;
pclk_62: out std_logic_vector(31 downto 0);?
pclk_4: out std_logic_vector(31 downto 0));
end lvds;
architecture lvds_arch of lvds is
component clkdll
port( clkin: in std_logic;
clkfb : in std_logic;
rst: in std_logic;
clk0: out std_logic;
clk90 : out std_logic;
clk180: out std_logic;
clk270: out std_logic;
clk2x : out std_logic;
clkdv: out std_logic;
locked: out std_logic);
end component;
begin
reset n<=‘0' ;
uibuf : ibufg port map (
i => pclk,
o => clk);
udll: clkdll port map( clkin => clk,
rst => reset_n,
clkfb => clkfb,
clk0 => clk0,
clk90 => open,
clk180 => open,
clk270 => open,
clk2x => clk2x,
clkdv => clkdv,
locked => locked
);
bufg_clk0: bufg port map ( i => clk0,
o=>clk_int2;
);
clkfb<=clk_int2;
process(clk2x);
begin
if clk2x′event and clk2x=′1′ then
clk_int <=clk int2;
clk_int3<= clkdv;
pclk_62(0)<=clk_int;
pclk_62(1)<=clk_int;
…
…
pclk_62(31)<=clk_int;
pclk_4(0)<=clk_int3;
pclk_4(1)<=clk_int3;
…
…
pclk_4(31)<=clk_int3;
end if;
end process;
end lvds_arch;