目次
前
次
周波数カウンタ
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動作が必要と考えました。
カウンタ制御
カウンタ値リード
ダイナミック点灯
カウンタ制御は、次のシーケンスで実現。
- カウンタクリア
- 10ms待ち
- カウンタ値リードシーケンサを起動
- 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素子のトランジスタアレイは、以下。
目次
前
次