目次

周波数カウンタ

 CPLDは、内部ゲート数が少なくても、100MHzの  周波数で動作できます。 アマチュア無線受信機器、ラジオを作る場合、周波数  カウンタがあると、何かと便利です。XC9572が、2個  あったので、周波数カウンタを作成しました。  CPLDを2個使うので、担当する機能を考え、ブロック図  にしておきます。  100MHzの半分の周波数50MHzを目標に、6桁分の  7セグメントLEDを使います。  3桁を1パッケージにした、7セグメントLEDを  2つ利用することに。  CPLDは、内部ゲート数が少ないので、4ビットの  情報から7セグメントLED用ビットパターンを生成  するには、CMOSの4511を使います。  出力から設計しています。  10kHzを利用して、6桁分の4ビットデータを出力します。  セレクタ用カウンタにiDCNTを使うとすると  以下のVHDLコードになります。 iLOUT <= iVAL(23 downto 20) when ( iDCNT = "0000" or iDCNT = "0001" ) else iVAL(19 downto 16) when ( iDCNT = "0010" or iDCNT = "0011" ) else iVAL(15 downto 12) when ( iDCNT = "0100" or iDCNT = "0101" ) else iVAL(11 downto 8) when ( iDCNT = "0110" or iDCNT = "0111" ) else iVAL( 7 downto 4) when ( iDCNT = "1000" or iDCNT = "1001" ) else iVAL( 3 downto 0) when ( iDCNT = "1010" or iDCNT = "1011" ) else "0000" ;  また、7セグメントLEDのどの桁に電流を  流すかを指定するための出力を確定します。 LENA <= "100000" when ( iDCNT = "0000" or iDCNT = "0001" ) else "010000" when ( iDCNT = "0010" or iDCNT = "0011" ) else "001000" when ( iDCNT = "0100" or iDCNT = "0101" ) else "000100" when ( iDCNT = "0110" or iDCNT = "0111" ) else "000010" when ( iDCNT = "1000" or iDCNT = "1001" ) else "000001" when ( iDCNT = "1010" or iDCNT = "1011" ) else "000000" ;  最高周波数を100MHzとするため、DPを点灯するか  しないかの指定も定義しておきます。 XLDP <= '1' when ( iDCNT = "1010" or iDCNT = "1011" ) else '1' when ( iDCNT = "0100" or iDCNT = "0101" ) else '0' ;  10kHzで動作クロックするとして、XC9572の5、6、7ピン  のどれかをクロック入力ピンとして指定できるので  6ピンを使うことにします。  選択用カウンタは、単純なカウンタで定義できます。 process (nRESET,DCLK) begin if ( nRESET = '0' ) then iDCNT <= "0000" ; elsif rising_edge(DCLK) then iDCNT <= iDCNT + '1' ; if ( conv_integer(iDCNT) = 12 ) then iDCNT <= "0000" ; end if ; end if ; end process ;  一つのCPLDに入れるブロックを確定します。 シーケンサを利用して、外部カウンタをリセット、パルス カウント、カウント値入力します。  シーケンサでは、次の状態を繰り返します。
  1. 待ち時間を作るカウント値設定
  2. 外部カウンタクリア
  3. 時間待ち(1ms)
  4. カウンタの奇数桁の内容取得
  5. カウンタの偶数桁の内容取得
  6. 1にもどる
 シーケンサ動作を、定義します。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= "000" ; iCNT <= (others => '0') ; elsif rising_edge(CLOCK) then case conv_integer(iSTATE) is -- set counter when 0 => iSTATE <= "001" ; iCNT <= conv_std_logic_vector(999,10) ; -- clear internal counter when 1 => iSTATE <= "011" ; -- delay when 3 => if ( conv_integer(iCNT) = 0 ) then iSTATE <= "111" ; else iCNT <= iCNT - '1' ; iSTATE <= "011" ; end if ; -- enable latch trigger when 7 => iSTATE <= "110" ; iVAL(23 downto 20) <= DIG54 ; iVAL(15 downto 12) <= DIG32 ; iVAL( 7 downto 4) <= DIG10 ; -- enable latch trigger when 6 => iSTATE <= "100" ; -- return first state when 4 => iSTATE <= "000" ; iVAL(19 downto 16) <= DIG54 ; iVAL(11 downto 8) <= DIG32 ; iVAL( 3 downto 0) <= DIG10 ; -- default when others => iSTATE <= "000" ; end case ; end if ; end process ; iRSIG <= '1' when ( iSTATE = "001" ) else '0' ; iENABLE <= '1' when ( iSTATE = "011" ) else '0' ; SEL <= '1' when ( iSTATE = "110" or iSTATE = "100" ) else '0' ;  内部動作が確定したので、全体を定義します。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity fqcnt0 is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- 1MHz DCLK : in std_logic ; -- 10kHz -- input DIG10 : in std_logic_vector(3 downto 0); DIG32 : in std_logic_vector(3 downto 0); DIG54 : in std_logic_vector(3 downto 0); -- output LOUT : out std_logic_vector(3 downto 0); LENA : out std_logic_vector(5 downto 0); XLDP : out std_logic ; SEL : out std_logic ; nRSIG : out std_logic ; ENABLE : out std_logic -- ; ); end fqcnt0; architecture Behavioral of fqcnt0 is -- sequencer signal iSTATE : std_logic_vector(2 downto 0); signal iCNT : std_logic_vector(9 downto 0); signal iRSIG : std_logic ; signal iENABLE : std_logic ; -- latch signal iVAL : std_logic_vector(23 downto 0); -- display signal iDCNT : std_logic_vector(3 downto 0); signal iLOUT : std_logic_vector(3 downto 0); begin -- output nRSIG <= not iRSIG ; ENABLE <= iENABLE ; LOUT <= iLOUT ; -- sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= "000" ; iCNT <= (others => '0') ; elsif rising_edge(CLOCK) then case conv_integer(iSTATE) is -- set counter when 0 => iSTATE <= "001" ; iCNT <= conv_std_logic_vector(999,10) ; -- clear internal counter when 1 => iSTATE <= "011" ; -- delay when 3 => if ( conv_integer(iCNT) = 0 ) then iSTATE <= "111" ; else iCNT <= iCNT - '1' ; iSTATE <= "011" ; end if ; -- enable latch trigger when 7 => iSTATE <= "110" ; iVAL(23 downto 20) <= DIG54 ; iVAL(15 downto 12) <= DIG32 ; iVAL( 7 downto 4) <= DIG10 ; -- enable latch trigger when 6 => iSTATE <= "100" ; -- return first state when 4 => iSTATE <= "000" ; iVAL(19 downto 16) <= DIG54 ; iVAL(11 downto 8) <= DIG32 ; iVAL( 3 downto 0) <= DIG10 ; -- default when others => iSTATE <= "000" ; end case ; end if ; end process ; iRSIG <= '1' when ( iSTATE = "001" ) else '0' ; iENABLE <= '1' when ( iSTATE = "011" ) else '0' ; SEL <= '1' when ( iSTATE = "110" or iSTATE = "100" ) else '0' ; -- display process (nRESET,DCLK) begin if ( nRESET = '0' ) then iDCNT <= "0000" ; elsif rising_edge(DCLK) then iDCNT <= iDCNT + '1' ; if ( conv_integer(iDCNT) = 12 ) then iDCNT <= "0000" ; end if ; end if ; end process ; -- 7 segment LED selector iLOUT <= iVAL(23 downto 20) when ( iDCNT = "0000" or iDCNT = "0001" ) else iVAL(19 downto 16) when ( iDCNT = "0010" or iDCNT = "0011" ) else iVAL(15 downto 12) when ( iDCNT = "0100" or iDCNT = "0101" ) else iVAL(11 downto 8) when ( iDCNT = "0110" or iDCNT = "0111" ) else iVAL( 7 downto 4) when ( iDCNT = "1000" or iDCNT = "1001" ) else iVAL( 3 downto 0) when ( iDCNT = "1010" or iDCNT = "1011" ) else "0000" ; XLDP <= '1' when ( iDCNT = "1010" or iDCNT = "1011" ) else '1' when ( iDCNT = "0100" or iDCNT = "0101" ) else '0' ; -- 7 segment LED selector LENA <= "100000" when ( iDCNT = "0000" or iDCNT = "0001" ) else "010000" when ( iDCNT = "0010" or iDCNT = "0011" ) else "001000" when ( iDCNT = "0100" or iDCNT = "0101" ) else "000100" when ( iDCNT = "0110" or iDCNT = "0111" ) else "000010" when ( iDCNT = "1000" or iDCNT = "1001" ) else "000001" when ( iDCNT = "1010" or iDCNT = "1011" ) else "000000" ; end Behavioral;  ピンアサインは、以下としました。 # system NET "CLOCK" LOC = "P5" ; NET "DCLK" LOC = "P6" ; NET "nRESET" LOC = "P39" ; # input NET "DIG54<0>" LOC = "P1" ; NET "DIG54<1>" LOC = "P2" ; NET "DIG54<2>" LOC = "P3" ; NET "DIG54<3>" LOC = "P4" ; NET "DIG32<0>" LOC = "P8" ; NET "DIG32<1>" LOC = "P9" ; NET "DIG32<2>" LOC = "P11" ; NET "DIG32<3>" LOC = "P12" ; NET "DIG10<0>" LOC = "P13" ; NET "DIG10<1>" LOC = "P14" ; NET "DIG10<2>" LOC = "P18" ; NET "DIG10<3>" LOC = "P19" ; # 7 segment LED output NET "LOUT<3>" LOC = "P44" ; NET "LOUT<2>" LOC = "P43" ; NET "LOUT<1>" LOC = "P42" ; NET "LOUT<0>" LOC = "P40" ; NET "LENA<5>" LOC = "P38" ; NET "LENA<4>" LOC = "P37" ; NET "LENA<3>" LOC = "P36" ; NET "LENA<2>" LOC = "P35" ; NET "LENA<1>" LOC = "P34" ; NET "LENA<0>" LOC = "P33" ; NET "XLDP" LOC = "P29" ; NET "nRSIG" LOC = "P20" ; NET "ENABLE" LOC = "P22" ; NET "SEL" LOC = "P24" ;  外部カウンタには、周波数カウンタと  シーケンサ、データ表示クロックを  封入します。  内部は、カウンタのみなので、2つのprocess文  を使って、定義します。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity fqcnt1 is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- input SCLK : in std_logic ; -- 4MHz -- input SEL : in std_logic ; ENABLE : in std_logic ; nRSIG : in std_logic ; -- clock out MCLKS : out std_logic ; MCLK : out std_logic ; -- output DOUT10 : out std_logic_vector(3 downto 0) ; DOUT32 : out std_logic_vector(3 downto 0) ; DOUT54 : out std_logic_vector(3 downto 0) ; OVF : out std_logic -- ; ); end fqcnt1; architecture Behavioral of fqcnt1 is -- display signal iDOUT0 : std_logic_vector(3 downto 0) ; signal iDOUT1 : std_logic_vector(3 downto 0) ; signal iDOUT2 : std_logic_vector(3 downto 0) ; signal iDOUT3 : std_logic_vector(3 downto 0) ; signal iDOUT4 : std_logic_vector(3 downto 0) ; signal iDOUT5 : std_logic_vector(3 downto 0) ; signal iOVF : std_logic ; -- divider signal iMCLKS : std_logic ; signal iMCLK : std_logic ; signal iMCNTS : std_logic_vector(1 downto 0) ; signal iMCNT : std_logic_vector(7 downto 0) ; -- divider signal iCLK : std_logic ; begin -- output DOUT10 <= iDOUT1 when ( SEL = '0' ) else iDOUT0 ; DOUT32 <= iDOUT3 when ( SEL = '0' ) else iDOUT2 ; DOUT54 <= iDOUT5 when ( SEL = '0' ) else iDOUT4 ; OVF <= not iOVF ; MCLKS <= iMCLKS ; MCLK <= iMCLK ; -- divider process (nRESET,SCLK) begin if ( nRESET = '0' ) then iMCNT <= (others => '0') ; iMCLK <= '0' ; iMCNTS <= "00" ; elsif rising_edge( SCLK ) then iMCNTS <= iMCNTS + '1' ; iMCNT <= iMCNT + '1' ; if ( conv_integer(iMCNT) = 200 ) then iMCNT <= (others => '0') ; iMCLK <= not iMCLK ; end if ; end if ; end process ; iMCLKS <= iMCNTS(1) ; -- internal clock iCLK <= CLOCK & ENABLE ; -- counter (10^0) process (nRESET,iCLK) begin if ( nRESET = '0' or nRSIG = '0' ) then iDOUT0 <= "0000" ; elsif rising_edge( iCLK ) then if ( iDOUT0 = "1010" ) then iDOUT0 <= "0000" ; else iDOUT0 <= iDOUT0 + '1' ; end if ; end if ; end process ; -- counter (10^1) process (nRESET,iDOUT0(3)) begin if ( nRESET = '0' or nRSIG = '0' ) then iDOUT1 <= "0000" ; elsif falling_edge( iDOUT0(3) ) then if ( iDOUT1 = "1010" ) then iDOUT1 <= "0000" ; else iDOUT1 <= iDOUT1 + '1' ; end if ; end if ; end process ; -- counter (10^2) process (nRESET,iDOUT1(3)) begin if ( nRESET = '0' or nRSIG = '0' ) then iDOUT2 <= "0000" ; elsif falling_edge( iDOUT1(3) ) then if ( iDOUT2 = "1010" ) then iDOUT2 <= "0000" ; else iDOUT2 <= iDOUT2 + '1' ; end if ; end if ; end process ; -- counter (10^3) process (nRESET,iDOUT2(3)) begin if ( nRESET = '0' or nRSIG = '0' ) then iDOUT3 <= "0000" ; elsif falling_edge( iDOUT2(3) ) then if ( iDOUT3 = "1010" ) then iDOUT3 <= "0000" ; else iDOUT3 <= iDOUT3 + '1' ; end if ; end if ; end process ; -- counter (10^4) process (nRESET,iDOUT3(3)) begin if ( nRESET = '0' or nRSIG = '0' ) then iDOUT4 <= "0000" ; elsif falling_edge( iDOUT3(3) ) then if ( iDOUT3 = "1010" ) then iDOUT4 <= "0000" ; else iDOUT4 <= iDOUT4 + '1' ; end if ; end if ; end process ; -- counter (10^5) process (nRESET,iDOUT4(3)) begin if ( nRESET = '0' or nRSIG = '0' ) then iDOUT5 <= "0000" ; iOVF <= '0' ; elsif falling_edge( iDOUT4(3) ) then if ( iDOUT3 = "1010" ) then iDOUT5 <= "0000" ; iOVF <= '1' ; else iDOUT5 <= iDOUT5 + '1' ; iOVF <= '0' ; end if ; end if ; end process ; end Behavioral;  10進数カウンタは、次のタイミングチャートで  最下位桁から、次の桁の加算にするためfalling  edgeを使います。  10の位、100の位は、次のように変わります。  ピンアサインは、以下としました。 # system NET "CLOCK" LOC = "P5" ; NET "SCLK" LOC = "P6" ; NET "nRESET" LOC = "P39" ; # input NET "ENABLE" LOC = "P1" ; NET "OVF" LOC = "P2" ; NET "SEL" LOC = "P3" ; NET "nRSIG" LOC = "P4" ; # clock output NET "MCLKS" LOC = "P7" ; NET "MCLK" LOC = "P8" ; # LED NET "DOUT54<3>" LOC = "P44" ; NET "DOUT54<2>" LOC = "P43" ; NET "DOUT54<1>" LOC = "P42" ; NET "DOUT54<0>" LOC = "P40" ; NET "DOUT32<3>" LOC = "P38" ; NET "DOUT32<2>" LOC = "P37" ; NET "DOUT32<1>" LOC = "P36" ; NET "DOUT32<0>" LOC = "P35" ; NET "DOUT10<3>" LOC = "P34" ; NET "DOUT10<2>" LOC = "P29" ; NET "DOUT10<1>" LOC = "P28" ; NET "DOUT10<0>" LOC = "P27" ;


目次 inserted by FC2 system