目次

PLLC(Phase Locked Loop Controller)

 CPLD/FPGAを利用して、PLL(Phase Locked Loop)ICをテストする コントローラを作成します。  PLL_ICを利用すると、周波数逓倍が簡単に実現できます。  周波数逓倍機能を利用して、1kHzから1kHz刻みで200kHzまで  発振させてみます。 PLL_ICには、CMOSシリーズの4046を使います。  4046内部には、位相比較器(Phase Comparator)、  電圧制御発振器(VoltageControlled Oscillator)が含まれています。  基本となる使い方は、下図です。  位相比較器(以下PCと略記)には、基準となるクロックと外部分周器から  の出力クロックを接続します。  電圧制御発振器(以下VCOと略記)の入力には、PCからの出力をフィルタ  を介して、接続します。また、VCOの出力には、外部分周器を接続します。  外部分周器の出力クロックをPCの入力に接続します。

ブロック図作成

 動作仕様から、ブロック図を作成します。  4046のPCに、基準クロックと分周器の出力クロックを  与えます。  Clock Generatorで、基準クロックの1kHzを生成します。  CPLDに4MHzのクロックを入力し、4000分周すると1kHzと  なります。  VCOの出力クロックを、分周する回路をClock Dividerで  実現します。  ブロック図で動作を決めたならば、必要な信号を考えます。

entity定義

 ブロック図で外部とやりとりする信号が決まれば、entityを定義します。 entity pllx is Port ( -- system nRESET : in std_logic; CLOCK : in std_logic; -- Divide DCNT : in std_logic_vector(10 downto 0); MCLK : out std_logic; SCLK : in std_logic; DCLK : out std_logic; OE : in std_logic--; ); end pllx;  Clock Dividerの分周比は、1kHz〜200kHzの逓倍なので  8ビットあれば充分ですが、11ビットとして最大2048kHz  まで逓倍できるようにします。  4046のVCOでは、2048kHzまで発振できませんが、74HC4046  を利用すれば、実現可能です。

Clock Generator

 システムクロックを4MHzとすると、4000分周すれば  PCに与える1kHzを生成できます。  4000を超えない、2のべき乗の最大値は4096です。  4096を生成するには、バイナリカウンタのビット数を12  とすればよいので、内部にカウンタ用レジスタを用意します。  signal iMCNT : std_logic_vector(11 downto 0) ;  クロック出力のために、1ビットのレジスタを用意し  このレジスタにカウント値により、1か0を設定します。  signal iMCLK : std_logic ;  システムクロックを入力し、バイナリカウンタをインクリメント  します。バイナリカウンタの値により、出力値を決めると分周が  できるので、次のように定義します。 -- master clock MCLK <= iMCLK ; -- master clock process( nRESET , CLOCK ) begin if ( nRESET = '0' ) then iMCNT <= (others => '0') ; elsif rising_edge( CLOCK ) then iMCNT <= iMCNT + '1' ; if ( conv_integer( iMCNT ) = 4000 ) then iMCNT <= (others => '0') ; end if ; end if; end process; iMCLK <= '1' when ( conv_integer( iMCNT ) = 0 ) else '0' ;

Clock Divider定義

 VCOの出力クロックを入力し、内部カウンタを+1します。  DIPスイッチで設定された値と比較し、一致したならば1を  異なれば0を出力する仕様とします。  DIPスイッチで設定するビット数は、11ビットとしたので  内部カウンタは、11ビットとします。  signal iCNT : std_logic_vector(10 downto 0) ;  クロック出力のために、1ビットのレジスタを用意し  このレジスタにカウント値により、1か0を設定します。  signal iDCLK : std_logic ;  内部カウンタの値とDIPスイッチで指定した値が一致  したとき、カウンタをゼロクリアするのを忘れずに  記述します。   -- divide clock   process( nRESET , SCLK )   begin   if ( nRESET = '0' ) then   iCNT <= (others => '0') ;   elsif rising_edge( SCLK ) then   iCNT <= iCNT + '1' ;   if ( iCNT = DCNT ) then   iCNT <= (others => '0') ;   end if ;   end if;   end process;   iDCLK <= '1' when ( conv_integer(iCNT) = 0 ) else '0' ;  分周クロック出力を制御するピンを用意したので  そのためのコードを記述します。   -- divide clock   DCLK <= iDCLK when ( OE = '1' ) else '0' ;

全ソースコード

 ブロック図から各ブロックを定義したので、まとめます。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity pllx is Port ( -- system nRESET : in std_logic; CLOCK : in std_logic; -- Divide DCNT : in std_logic_vector(10 downto 0); MCLK : out std_logic; SCLK : in std_logic; DCLK : out std_logic; OE : in std_logic--; ); end pllx; architecture Behavioral of pllx is signal iMCLK : std_logic ; signal iMCNT : std_logic_vector(11 downto 0) ; signal iDCLK : std_logic ; signal iCNT : std_logic_vector(10 downto 0) ; begin -- master clock MCLK <= iMCLK ; -- divide clock DCLK <= iDCLK when ( OE = '1' ) else '0' ; -- master clock process( nRESET , CLOCK ) begin if ( nRESET = '0' ) then iMCNT <= (others => '0') ; elsif rising_edge( CLOCK ) then iMCNT <= iMCNT + '1' ; if ( conv_integer( iMCNT ) = 4000 ) then iMCNT <= (others => '0') ; end if ; end if; end process; iMCLK <= '1' when ( conv_integer( iMCNT ) = 0 ) else '0' ;  -- divide clock  process( nRESET , SCLK )  begin   if ( nRESET = '0' ) then   iCNT <= (others => '0') ;   elsif rising_edge( SCLK ) then   iCNT <= iCNT + '1' ;   if ( iCNT = DCNT ) then   iCNT <= (others => '0') ;   end if ;   end if;  end process;  iDCLK <= '1' when ( conv_integer(iCNT) = 0 ) else '0' ;  -- divide clock  DCLK <= iDCLK when ( OE = '1' ) else '0' ; end Behavioral;

CPLD選定

 手元にあるCPLDボードには、XC9572が実装されています。  XC9572に2ブロックが入るかを試してみると、収納できました。  同じピン配置で同一サイズのXC9536では、マクロセルの割当が  できず、収納できませんでした。  他にあるCool RunnerII(256マクロセル品)では、マクロセル数が  XC9572より多いので、楽に入りました。  マクロセル数が、72以上のCPLDを利用すればよいでしょう。

別のソースコード

 CPLD、FPGAは複数のクロック入力を持っているので  基準クロックとVCOの分周クロックを別に設定する  構成を考えました。  VCOからフィードバックしてくるクロックを  最大9999分周できるようにしました。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity plltst is generic ( TOPX : integer := 13 ; RMAX : integer := 5888 -- ; 11.776MHz => 1kHz ); port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- VCO CLKX : in std_logic ; -- divider DIVX : in std_logic_vector(13 downto 0) ; -- controlo out ACLK : out std_logic ; BCLK : out std_logic ; MCLK : out std_logic -- ; ); end plltst; architecture Behavioral of plltst is -- component clock generator component clkgenx is generic ( TOPX : integer ; RMAX : integer --; ); port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- output CLKOUT : out std_logic -- ; ); end component ; -- clock signal iMCLK : std_logic ; -- divider signal iDIVX : std_logic_vector(13 downto 0) ; signal iCNTVX : std_logic_vector(13 downto 0) ; signal iBCLK : std_logic ; begin -- component clock generator (11.776MHz/5888 = 2kHz) XCLKX : clkgenx generic map (TOPX,RMAX) port map (nRESET,CLOCK,iMCLK); -- input iDIVX <= DIVX ; -- output MCLK <= not iMCLK ; ACLK <= iMCLK ; BCLK <= iBCLK ; -- counter process (nRESET,CLKX) begin if ( nRESET = '0' ) then iCNTVX <= (others => '0') ; iBCLK <= '0' ; elsif rising_edge(CLKX) then if ( iCNTVX = iDIVX ) then iCNTVX <= (others => '0') ; iBCLK <= '1' ; else iCNTVX <= iCNTVX + '1' ; iBCLK <= '0' ; end if ; end if ; end process ; end Behavioral;


目次 inserted by FC2 system