目次

周波数カウンタ

 XC9572を2個使い、周波数カウンタを実現してみます。

 周波数は、70MHzくらいまで測定できるとし
 100Hzより下は、無視します。

 ブロック図は、以下。



 個々のCPLDの内容をVHDLで記述していきます。

  カウンタ

  10進数カウンタを1個定義して、6個並べます。



  10進数カウンタの1個は、次のように定義。

  process (nRESET,CLOCK)
  begin 
    if ( nRESET = '0' ) then
      iDIGA <= "0000" ;
    elsif rising_edge( CLOCK ) then
      if ( ENX = '1' ) then
        if ( iDIGA = "1010" ) then
          iDIGA <= "0000" ;
        else
          iDIGA <= iDIGA + '1' ;
        end if ;
      end if ;
    end if ;
  end process ;

  iCA <= '1' when ( iDIGA = "1010" ) else '0' ;

  最初のカウンタが、クロックでインクリメントしないと
  上位桁の方は、キャリーでインクリメントする非同期の
  カウンタにすれば、これで充分。

  制御側は、カウンタをすべてリセットしてから
  クロックによるインクリメントを許可する方式
  を採用します。

  ひとつ上の桁は、次のように定義。

  process (nRESET,iCA)
  begin 
    if ( nRESET = '0' ) then
      iDIGB <= "0000" ;
    elsif rising_edge( iCA ) then
      if ( iDIGB = "1010" ) then
        iDIGB <= "0000" ;
      else
        iDIGB <= iDIGB + '1' ;
      end if ;
    end if ;
  end process ;

  iCB <= '1' when ( iDIGB = "1010" ) else '0' ;

  残りの4カウンタは、信号名とレジスタ名を変えて
  定義していきます。

  カウントが終わったなら、6カウンタの値を外部に
  取り出せるようにして、表示は制御側に一任。

  この方式を採用するので、レジスタ番号と指定し
  4ビットの値を出力するブロックを定義します。

  ブロック図では、以下。



  VHDLコードは次のように単純にしておきます。


  -- output
  DIG  <= iDIG  ;

  -- selector
  iDIG <= iDIGB when ( SELX = "001" ) else
          iDIGC when ( SELX = "010" ) else
          iDIGD when ( SELX = "011" ) else
          iDIGE when ( SELX = "100" ) else
          iDIGF when ( SELX = "101" ) else
          iDIGA ;

  まとめると、以下。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ttx is
  port (
    -- system 
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ;
    -- input
    ENX    : in  std_logic ;
    SELX   : in  std_logic_vector(2 downto 0) ; 
    -- output
    DIG    : out std_logic_vector(3 downto 0) ;
    DIGV   : out std_logic -- ;
  );
end ttx;

architecture Behavioral of ttx is
  -- internal register
  signal iDIG  : std_logic_vector(3 downto 0) ;
  signal iDIGA : std_logic_vector(3 downto 0) ;
  signal iDIGB : std_logic_vector(3 downto 0) ;
  signal iDIGC : std_logic_vector(3 downto 0) ;
  signal iDIGD : std_logic_vector(3 downto 0) ;
  signal iDIGE : std_logic_vector(3 downto 0) ;
  signal iDIGF : std_logic_vector(3 downto 0) ;
  -- internal carry
  signal iCA   : std_logic ;
  signal iCB   : std_logic ;
  signal iCC   : std_logic ;
  signal iCD   : std_logic ;
  signal iCE   : std_logic ;
  signal iCF   : std_logic ;
begin
  -- output
  DIG  <= iDIG  ;
  DIGV <= iCF ;

  -- selector
  iDIG <= iDIGB when ( SELX = "001" ) else
          iDIGC when ( SELX = "010" ) else
          iDIGD when ( SELX = "011" ) else
          iDIGE when ( SELX = "100" ) else
          iDIGF when ( SELX = "101" ) else
          iDIGA ;

  -- DIGIT_A (10^0)
  process (nRESET,CLOCK)
  begin 
    if ( nRESET = '0' ) then
      iDIGA <= "0000" ;
    elsif rising_edge( CLOCK ) then
      if ( ENX = '1' ) then
        if ( iDIGA = "1010" ) then
          iDIGA <= "0000" ;
        else
          iDIGA <= iDIGA + '1' ;
        end if ;
      end if ;
    end if ;
  end process ;

  iCA <= '1' when ( iDIGA = "1010" ) else '0' ;

  -- DIGIT_B (10^1)
  process (nRESET,iCA)
  begin 
    if ( nRESET = '0' ) then
      iDIGB <= "0000" ;
    elsif rising_edge( iCA ) then
      if ( iDIGB = "1010" ) then
        iDIGB <= "0000" ;
      else
        iDIGB <= iDIGB + '1' ;
      end if ;
    end if ;
  end process ;

  iCB <= '1' when ( iDIGB = "1010" ) else '0' ;

  -- DIGIT_C (10^2)
  process (nRESET,iCB)
  begin 
    if ( nRESET = '0' ) then
      iDIGC <= "0000" ;
    elsif rising_edge( iCB ) then
      if ( iDIGC = "1010" ) then
        iDIGC <= "0000" ;
      else
        iDIGC <= iDIGC + '1' ;
      end if ;
    end if ;
  end process ;

  iCC <= '1' when ( iDIGC = "1010" ) else '0' ;

  -- DIGIT_D (10^3)
  process (nRESET,iCC)
  begin 
    if ( nRESET = '0' ) then
      iDIGD <= "0000" ;
    elsif rising_edge( iCC ) then
      if ( iDIGD = "1010" ) then
        iDIGD <= "0000" ;
      else
        iDIGD <= iDIGD + '1' ;
      end if ;
    end if ;
  end process ;

  iCD <= '1' when ( iDIGD = "1010" ) else '0' ;

  -- DIGIT_E (10^4)
  process (nRESET,iCD)
  begin 
    if ( nRESET = '0' ) then
      iDIGE <= "0000" ;
    elsif rising_edge( iCD ) then
      if ( iDIGE = "1010" ) then
        iDIGE <= "0000" ;
      else
        iDIGE <= iDIGE + '1' ;
      end if ;
    end if ;
  end process ;

  iCE <= '1' when ( iDIGE = "1010" ) else '0' ;

  -- DIGIT_F (10^5)
  process (nRESET,iCE)
  begin 
    if ( nRESET = '0' ) then
      iDIGF <= "0000" ;
    elsif rising_edge( iCE ) then
      if ( iDIGF = "1010" ) then
        iDIGF <= "0000" ;
      else
        iDIGF <= iDIGF + '1' ;
      end if ;
    end if ;
  end process ;

  iCF <= '1' when ( iDIGF = "1010" ) else '0' ;

end Behavioral;

  ピンアサインは、次のようにしておきます。

NET "clock"  LOC = "P5" ;
NET "nreset" LOC = "P39" ;

NET "digv"   LOC = "P44" ;

NET "enx"    LOC = "P1" ;

NET "dig<3>"  LOC = "P38" ;
NET "dig<2>"  LOC = "P37" ;
NET "dig<1>"  LOC = "P36" ;
NET "dig<0>"  LOC = "P35" ;

NET "selx<2>"  LOC = "P43" ;
NET "selx<1>"  LOC = "P42" ;
NET "selx<0>"  LOC = "P40" ;

  コントローラ

  コントローラは、次の3動作が必要と考えました。

  カウンタ制御
  カウンタ値リード
  ダイナミック点灯




  カウンタ制御は、次のシーケンスで実現。
  1. カウンタクリア
  2. 10ms待ち
  3. カウンタ値リードシーケンサを起動
  4. 1に戻る
  シーケンスをVHDLコードに変換すると、以下。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= 0 ; elsif rising_edge( CLOCK ) then case iSTATE is when 0 => iSTATE <= 1 ; iSCNT <= 49999 ; when 1 => if iSCNT = 0 then iSTATE <= 2 ; else iSTATE <= 1 ; iSCNT <= iSCNT - 1 ; end if ; when 2 => iSTATE <= 3 ; when 3 => iSTATE <= 0 ; when others => iSTATE <= 0 ; end case ; end if ; end process ; iXRST <= '1' when ( iSTATE = 0 ) else '0' ; iENX <= '1' when ( iSTATE = 1 ) else '0' ; iGTRG <= '1' when ( iSTATE = 2 ) else '0' ;   カウンタのリセット、イネーブルとシーケンサへの   トリガーは、イベント信号で対応してます。   カウンタ値リードは、カウンタ制御シーケンサからの   イベント信号を監視し、信号が'1'になったらレジスタ   番号を与えて、各カウンタの値を複写。   この動作をシーケンサで定義すると、以下。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iGSTATE <= 0 ; iDIGA <= "0000" ; iDIGB <= "0000" ; iDIGC <= "0000" ; iDIGD <= "0000" ; iDIGE <= "0000" ; iDIGF <= "0000" ; elsif rising_edge( CLOCK ) then case iGSTATE is when 0 => if ( iGTRG = '1' ) then iGSTATE <= 1 ; else iGSTATE <= 0 ; end if ; when 1 => iGSTATE <= 2 ; when 2 => iGSTATE <= 3 ; iDIGA <= DIGIN ; when 3 => iGSTATE <= 4 ; when 4 => iGSTATE <= 5 ; iDIGB <= DIGIN ; when 5 => iGSTATE <= 6 ; when 6 => iGSTATE <= 7 ; iDIGC <= DIGIN ; when 7 => iGSTATE <= 8 ; when 8 => iGSTATE <= 9 ; iDIGD <= DIGIN ; when 9 => iGSTATE <= 10 ; when 10 => iGSTATE <= 11 ; iDIGE <= DIGIN ; when 11 => iGSTATE <= 12 ; when 12 => iGSTATE <= 13 ; iDIGF <= DIGIN ; when 13 => iGSTATE <= 0 ; when others => iGSTATE <= 0 ; end case ; end if ; end process ; XADR <= "000" when ( iGSTATE = 1 or iGSTATE = 2 ) else "001" when ( iGSTATE = 3 or iGSTATE = 4 ) else "010" when ( iGSTATE = 5 or iGSTATE = 6 ) else "011" when ( iGSTATE = 7 or iGSTATE = 8 ) else "100" when ( iGSTATE = 9 or iGSTATE = 10 ) else "101" when ( iGSTATE = 11 or iGSTATE = 12 ) else "111" ;   ステートを遷移させて、ステートに合わせて   レジスタ番号出力とレジスタ値の複写をして   いきます。   ダイナミック点灯は、複写したレジスタ値を   外部デコーダに出力するのとカソードを制御   するシーケンスで実現。   シーケンスをカウンタで生成し、ステートごとに   処理を追加していきます。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iDSTATE <= 0 ; elsif rising_edge( CLOCK ) then if iDSTATE = 13 then iDSTATE <= 0 ; else iDSTATE <= iDSTATE + 1 ; end if ; end if ; end process ; iDIG <= iDIGB when ( iDSTATE = 2 or iDSTATE = 3 ) else iDIGC when ( iDSTATE = 4 or iDSTATE = 5 ) else iDIGD when ( iDSTATE = 6 or iDSTATE = 7 ) else iDIGE when ( iDSTATE = 8 or iDSTATE = 9 ) else iDIGF when ( iDSTATE = 10 or iDSTATE = 11 ) else iDIGA ; iDSEL <= "000001" when ( iDSTATE = 1 ) else "000010" when ( iDSTATE = 3 ) else "000100" when ( iDSTATE = 5 ) else "001000" when ( iDSTATE = 7 ) else "010000" when ( iDSTATE = 9 ) else "100000" when ( iDSTATE = 11 ) else "000000" ;   バイナリーカウンタでシーケンスを回して   カウンタ値で、レジスタ出力値とカソード   の制御信号を生成。   ダイナミック点灯にしているので、1桁分の表示は   1msよりも短くしておきます。   3つのシーケンサ(ステートマシン)を利用した   コントローラのVHDLコードは、以下。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity ttcon is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- 5MHz -- input XADR : out std_logic_vector(2 downto 0) ; DIGIN : in std_logic_vector(3 downto 0) ; -- output XRST : out std_logic ; ENX : out std_logic ; DIG : out std_logic_vector(3 downto 0) ; SELX : out std_logic_vector(5 downto 0) --; ); end ttcon; architecture Behavioral of ttcon is -- internal register signal iDIG : std_logic_vector(3 downto 0) ; signal iDIGA : std_logic_vector(3 downto 0) ; signal iDIGB : std_logic_vector(3 downto 0) ; signal iDIGC : std_logic_vector(3 downto 0) ; signal iDIGD : std_logic_vector(3 downto 0) ; signal iDIGE : std_logic_vector(3 downto 0) ; signal iDIGF : std_logic_vector(3 downto 0) ; -- state machine signal iDSTATE : integer range 0 to 13 ; signal iDSEL : std_logic_vector(5 downto 0); signal iGSTATE : integer range 0 to 13 ; signal iGTRG : std_logic ; signal iSTATE : integer range 0 to 3 ; signal iSCNT : integer range 0 to 49999 ; signal iXRST : std_logic ; signal iENX : std_logic ; begin -- output DIG <= iDIG ; SELX <= iDSEL ; XRST <= not iXRST ; ENX <= iENX ; -- 7 segment LED control process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iDSTATE <= 0 ; elsif rising_edge( CLOCK ) then if iDSTATE = 13 then iDSTATE <= 0 ; else iDSTATE <= iDSTATE + 1 ; end if ; end if ; end process ; iDIG <= iDIGB when ( iDSTATE = 2 or iDSTATE = 3 ) else iDIGC when ( iDSTATE = 4 or iDSTATE = 5 ) else iDIGD when ( iDSTATE = 6 or iDSTATE = 7 ) else iDIGE when ( iDSTATE = 8 or iDSTATE = 9 ) else iDIGF when ( iDSTATE = 10 or iDSTATE = 11 ) else iDIGA ; iDSEL <= "000001" when ( iDSTATE = 1 ) else "000010" when ( iDSTATE = 3 ) else "000100" when ( iDSTATE = 5 ) else "001000" when ( iDSTATE = 7 ) else "010000" when ( iDSTATE = 9 ) else "100000" when ( iDSTATE = 11 ) else "000000" ; -- get counter values process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iGSTATE <= 0 ; iDIGA <= "0000" ; iDIGB <= "0000" ; iDIGC <= "0000" ; iDIGD <= "0000" ; iDIGE <= "0000" ; iDIGF <= "0000" ; elsif rising_edge( CLOCK ) then case iGSTATE is when 0 => if ( iGTRG = '1' ) then iGSTATE <= 1 ; else iGSTATE <= 0 ; end if ; when 1 => iGSTATE <= 2 ; when 2 => iGSTATE <= 3 ; iDIGA <= DIGIN ; when 3 => iGSTATE <= 4 ; when 4 => iGSTATE <= 5 ; iDIGB <= DIGIN ; when 5 => iGSTATE <= 6 ; when 6 => iGSTATE <= 7 ; iDIGC <= DIGIN ; when 7 => iGSTATE <= 8 ; when 8 => iGSTATE <= 9 ; iDIGD <= DIGIN ; when 9 => iGSTATE <= 10 ; when 10 => iGSTATE <= 11 ; iDIGE <= DIGIN ; when 11 => iGSTATE <= 12 ; when 12 => iGSTATE <= 13 ; iDIGF <= DIGIN ; when 13 => iGSTATE <= 0 ; when others => iGSTATE <= 0 ; end case ; end if ; end process ; XADR <= "000" when ( iGSTATE = 1 or iGSTATE = 2 ) else "001" when ( iGSTATE = 3 or iGSTATE = 4 ) else "010" when ( iGSTATE = 5 or iGSTATE = 6 ) else "011" when ( iGSTATE = 7 or iGSTATE = 8 ) else "100" when ( iGSTATE = 9 or iGSTATE = 10 ) else "101" when ( iGSTATE = 11 or iGSTATE = 12 ) else "111" ; -- counter process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= 0 ; elsif rising_edge( CLOCK ) then case iSTATE is when 0 => iSTATE <= 1 ; iSCNT <= 49999 ; when 1 => if iSCNT = 0 then iSTATE <= 2 ; else iSTATE <= 1 ; iSCNT <= iSCNT - 1 ; end if ; when 2 => iSTATE <= 3 ; when 3 => iSTATE <= 0 ; when others => iSTATE <= 0 ; end case ; end if ; end process ; iXRST <= '1' when ( iSTATE = 0 ) else '0' ; iENX <= '1' when ( iSTATE = 1 ) else '0' ; iGTRG <= '1' when ( iSTATE = 2 ) else '0' ; end Behavioral;   ピンアサインは、次のようにしてます。 # system NET "nreset" LOC = "P39"; NET "clock" LOC = "P5" ; # address NET "xadr<0>" LOC = "P6" ; NET "xadr<1>" LOC = "P7" ; NET "xadr<2>" LOC = "P8" ; NET "xrst" LOC = "P18" ; NET "enx" LOC = "P19" ; # data in NET "digin<0>" LOC = "P1" ; NET "digin<1>" LOC = "P2" ; NET "digin<2>" LOC = "P3" ; NET "digin<3>" LOC = "P4" ; # data out NET "dig<0>" LOC = "P11" ; NET "dig<1>" LOC = "P12" ; NET "dig<2>" LOC = "P13" ; NET "dig<3>" LOC = "P14" ; # selector NET "selx<0>" LOC = "P24" ; NET "selx<1>" LOC = "P25" ; NET "selx<2>" LOC = "P26" ; NET "selx<3>" LOC = "P27" ; NET "selx<4>" LOC = "P28" ; NET "selx<5>" LOC = "P29" ;  ハードウエアは、次のようにしました。  44ピンのソケットにXC9572を入れて使います。  左にコントローラ、右にカウンタのCPLDを配置。  インバータとして74HC04を使い、CPLDのドライブ  能力を超えたときのバッファとして利用。  また、正論理で7セグメントLEDのカソードを駆動  する方式としました。  レジスタは、マクロセルを消費しますが、インバータ  バッファはマクロセルを消費しません。  インバータバッファを使うのは、駆動能力に余裕が  ないと判断した場合に限ります。  インバータバッファとして6個を超える場合には  トランジスタアレイを使います。  8素子のトランジスタアレイは、以下。

目次

inserted by FC2 system