Lattice CPLD (FPGA)
秋月電子で販売されているLatticeSemiconductorのCPLD
基板を入手しました。CPLDとうたってありますが、内部
は、FPGAでした。
開発環境はDiamondになっています。
開発環境Diamondは、LatticeSemiconductorのWebサイト
からダウンロードしましたが、1.3GバイトほどありUSA
が真夜中の時間帯を利用しました。
目的のファイルをダウンロードするには、LatticeSemiconductor
サイトへの登録が必要です。登録料、年会費等は不要ですが。
開発環境Diamondをインストールしてから、基板にUSBケーブルを
接続すると、次のようにLEDが点滅しました。
このDemoを実現するVHDLコードは、多分
次のようになっているはず。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity tcpld is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
LOUT : out std_logic_vector(7 downto 0) -- ;
);
end tcpld ;
architecture Behavioral of tcpld is
-- clock generator
signal iCNT : std_logic_vector(18 downto 0) ;
-- decoder
signal iLCNT : std_logic_vector(7 downto 0);
begin
-- output
LOUT <= not iLCNT ;
-- decoder
iLCNT <= X"55" when ( iCNT(18) = '1' ) else
X"aa" ;
-- clock generator
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= (others => '0') ;
elsif rising_edge(CLOCK) then
iCNT <= iCNT + '1' ;
end if ;
end process ;
end Behavioral;
Lattice Semiconductorのサイトから、デモ用Zipファイル
をダウンロードし、内容を確認すると、次のVerilogHDLの
コードを見つけました。
module Default_w_standby_top (stdby_in,stdby1,osc_clk,led0,led1,led2,led3,led4,led5,led6,led7);
input stdby_in ;
output stdby1, osc_clk ;
output led0,led1,led2,led3,led4,led5,led6,led7 ;
wire stby_flag ;
reg [21:0] cnt ;
//assign clkout = clki ;
//assign rstout = rstn ;
// Internal Oscillator
defparam OSCH_inst.NOM_FREQ = "2.08"; // This is the default frequency
OSCH OSCH_inst( .STDBY(stdby1 ), // 0=Enabled, 1=Disabled also Disabled with Bandgap=OFF
.OSC(osc_clk),
.SEDSTDBY()); // this signal is not required if not using SED - see TN1199 for more details.
pwr_cntrllr pcm1(.USERSTDBY(stdby_in ),.CLRFLAG(stby_flag ),.CFGSTDBY(1'b0 ),.STDBY(stdby1 ),.SFLAG(stby_flag));
// LED BLinking test FPGA for LATTICE X02-1200
// Turn on every other LED @ 1/2 second
always @(posedge osc_clk or posedge stdby_in)
if (stdby_in)
cnt <= 0;
else
cnt <= cnt + 1;
assign led0 = stdby_in ? 1'b1 : cnt[20];
assign led1 = stdby_in ? 1'b1 : ~cnt[20];
assign led2 = stdby_in ? 1'b1 : cnt[20];
assign led3 = stdby_in ? 1'b1 : ~cnt[20];
assign led4 = stdby_in ? 1'b1 : cnt[20];
assign led5 = stdby_in ? 1'b1 : ~cnt[20];
assign led6 = stdby_in ? 1'b1 : cnt[20];
assign led7 = stdby_in ? 1'b1 : ~cnt[20];
endmodule
デモに関連したVerilogHDLを見る限り、こちらで
考えているVHDLコードと、ほぼ同じことをやって
います。
VerilogHDLコードの中に、利用クロックを2.08MHzと
宣言しています。従って、21分周すると約2Hzでの
LEDをブリンクする処理とわかります。
CPLD/FPGAを動かす場合、最終ピン割当てが必要です。
Diamondを利用するために、その定義がどこにあるのかを
調べると、LPFという拡張子のconstraint fileに記述が
ありました。
BLOCK RESETPATHS ;
BLOCK ASYNCPATHS ;
FREQUENCY NET "osc_clk_inferred_clock" 2.080000 MHz ;
BANK 0 VCCIO 3.3 V;
BANK 1 VCCIO 3.3 V;
BANK 2 VCCIO 3.3 V;
BANK 3 VCCIO 3.3 V;
IOBUF ALLPORTS IO_TYPE=LVCMOS33 ;
LOCATE COMP "stdby_in" SITE "69" ;
LOCATE COMP "stdby1" SITE "38" ;
LOCATE COMP "osc_clk" SITE "40" ;
#
LOCATE COMP "led0" SITE "97" ;
LOCATE COMP "led1" SITE "98" ;
LOCATE COMP "led2" SITE "99" ;
LOCATE COMP "led3" SITE "100" ;
LOCATE COMP "led4" SITE "104" ;
LOCATE COMP "led5" SITE "105" ;
LOCATE COMP "led6" SITE "106" ;
LOCATE COMP "led7" SITE "107" ;
ピンアサインは、「LOCATE COMP "led0" SITE "97" ;」で
指定するとわかります。
クロックは、LPFファイル中で指定できるようです。
FREQUENCY NET "osc_clk_inferred_clock" 2.080000 MHz ;
CPLD/FPGAには、内部ブロックとピンを接続する
バンクが存在するので、利用電圧とI/Oタイプを
指定しています。
BANK 0 VCCIO 3.3 V;
BANK 1 VCCIO 3.3 V;
BANK 2 VCCIO 3.3 V;
BANK 3 VCCIO 3.3 V;
IOBUF ALLPORTS IO_TYPE=LVCMOS33 ;
コメントは、#を利用するようです。
ダウンロードしたマニュアルには、1200ZEと7000HEの
ピン対応表があります。ピン番号は、端子互換になる
ようになっています。
基板上のLEDとスイッチだけでは、やりたいことが
できないので、左右に翼のように基板をつけます。
基板上に3端子レギュレータがあるので、+5Vを
接続できるようにしました。+5Vは、USBから供給
するのが、最も楽なのでアダプタを利用しました。
Diamondの使い方をマスターするために、次のような
動作をするVHDLコードを作成して、ダウンロードして
みます。
出力パターンを変えるだけなので、カウント値により
上位4ビットが点灯、消灯になるようにします。
内蔵オシレータが利用できるようですが
外部に5MHzと10MHzの発振器を接続して
動かしてみます。
VHDLソースコードは、以下です。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity lctst is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- monitor
SEDC : out std_logic ;
-- output
LOUT : out std_logic_vector(7 downto 0) -- ;
);
end lctst ;
architecture Behavioral of lctst is
-- clock generator
signal iCNT : std_logic_vector(22 downto 0) ;
-- decoder
signal iLCNT : std_logic_vector(7 downto 0);
begin
-- output
LOUT <= not iLCNT ;
SEDC <= iCNT(22) ;
-- decoder
iLCNT <= X"F0" when ( iCNT(22) = '1' ) else
X"0F" ;
-- clock generator
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= (others => '0') ;
elsif rising_edge(CLOCK) then
iCNT <= iCNT + '1' ;
end if ;
end process ;
end Behavioral;
ソースコードができれば、ピンアサインを考えることに。
ピンアサインをDiamondでどう設定するのかをマニュアル
で理解します。
評価基板のマニュアルで、LEDとの接続ピンを確認します。
デバイスには、MachXO2_7000HE-4TG144Cが使われています。
8つのLEDがあり、ピンアサインは以下です。
PR2A 107 LED7(LED Array)
PR2B 106 LED6(LED Array)
PR3A 105 LED5(LED Array)
PR3B 104 LED4(LED Array)
PR5A 100 LED3(LED Array)
PR5B 99 LED2(LED Array)
PR7A 98 LED1(LED Array)
PR7B 97 LED0(LED Array)
他のピンは、どういう接続になっているかを
抜き出してみると、次のように。
J2
1 NC 2 VCCIO0
3 PT36D/DONE(109) 4 PT36C/INITn(110)
5 PT36B(111) 6 PT36A(112)
7 GND 8 GND
9 PT33B(113) 10 PT33A(114)
11 PT28B(115) 12 PT28A(117)
13 PT27D/PROGn(119) 14 PT27C/JTAGen(120)
15 GND 16 GND
17 PT25B(121) 18 PT25A(122)
19 PT22D/SDA(125) 20 PT22C/SDL(126)
21 PT18B/PCLKC0_1(127) 22 PT18A(128)
23 GND 24 GND
25 PT17D/TDM(130) 26 PT17C/TCK(131)
27 PT15B(132) 28 PT15A(133)
29 PT14D/TDI(136) 30 PT14C/TDO(137)
31 GND 32 GND
33 PT11B(138) 34 PT11A(139)
35 PT10B(140) 36 PT10A(141)
37 PT9B (142) 38 PT9A (143)
39 GND 40 GND
J3
1 VCC_1.2V 2 VCCIO1
3 VCC_1.2V 4 NC
5 PR24A(74) 6 PR24B(73)
7 PR23A(76) 8 PR23B(75)
9 GND 10 GND
11 PR21A(78) 12 PR21B(77)
13 PR18A(82) 14 PR18B(81)
15 GND 16 GND
17 PR17A(84) 18 PR17B(83)
19 PR16A(86) 20 PR16B(85)
21 GND 22 GND
23 PR11A/PCLKT1_0(92) 24 PR12B(93)/PCLKC1_0
25 PR11A(94) 26 PR11B(93)
27 GND 28 GND
29 PR9A(96) 30 PR9B(95)
31 PR7A(98) 32 PR7B(97)
33 GND 34 GND
35 PR5A(100) 36 PR5B(99)
37 PR3A(105) 38 PR3B(104)
39 PR2A(107) 40 PR2B(106)
J4
1 VCC_3.3V 2 VCCIO3/4/5
3 VCC_3.3V 4 NC
5 PL3A ( 1) 6 PL3B ( 2)
7 PL4A ( 3) 8 PL4B ( 4)
9 PL6A/PCLKT5_0( 5) 10 PL6B/PCLKC5_0( 6)
11 PL8A ( 9) 12 PL8B (10)
13 GND 14 GND
15 PL9A (11) 16 PL9B (12)
17 PL10A(13) 18 PL10B(14)
19 GND 20 GND
21 PL12A/PCLKT4_0(19) 22 PL12B/PCLKC4_0(20)
23 PL15A(21) 24 PL15B(22)
25 GND 26 GND
27 PL17A(23) 28 PL17B(24)
29 PL19A(25) 30 PL19B(26)
31 GND 32 GND
33 PL22A/PCLKT3_0(27) 34 PL22B/PCLKC3_0(28)
35 GND 36 GND
37 PL24A(32) 38 PL24B(33)
39 PL25A(34) 40 PL25B(35)
J5
1 NC 2 VCCIO2
3 PB38B/SI/SISPI(71) 4 PB37B(69)
5 PB38A/SN(70) 6 PB37A(68)
7 PB35B(67) 8 PB31B(62)
9 PB35A(65) 10 PB31A(61)
11 GND 12 GND
13 PB29B(60) 14 PB26B(58)
15 PB29A(59) 16 PB26A(57)
17 GND 18 GND
19 PB23B/PCLKT2_1(56) 20 PB18B(54)
21 PB23A/PCLKT2_0(55) 22 PB18A(52)
23 GND 24 GND
25 PB16B/PCLKC2_0(50) 26 PB13B(48)
27 PB16A/PCLKT2_0(49) 28 PB13A(47)
29 GND 30 GND
31 PB12B/S0/SPISO (45) 32 PB9B(43)
33 PB12A/MCLK/CCLK(44) 34 PB9A(42)
35 GND 36 GND
37 PB6B(41) 38 PB4B(39)
39 PB6A/CSSPIN(40) 40 PB4A(38)
外部接続で利用できるピンを見ると
クロック入力できるところが、複数
あります。
CPLD内部に発振器とPLLがあるので
外部クロックと同期して利用する
場合に使うことを狙っているのかも
知れません。
PLLは、基本周波数frと出力周波数をfoutと
すると、次の式で記述できます。
fout = M x fr = (m/n)xfr
Mは、基本周波数の何倍になるのかを表し
これが(m/n)という有理数になると考えて
処理します。
入手した評価基板上のCPLDは、内蔵クロックジェネレータで
2.08MHzを出力しています。デモ用回路では、クロックを分周
約2Hzにして利用しています。
20ビットカウンタで分周し、約2Hzとしていますが
2のべき乗で計算すると、最大(1024x1024-1)カウント。
2.08x1000x1000Hz/(1024x1024)となり、1024を1000とし
2.08x1000x1000Hz/(1000x1000)=2.08Hz。近似しないと
約2Hzになります。
m = 1 , n = 1024 x 1024とすると
fout = (m/n) x fr = (1/(1024x1024)) x 2.08MHz
これでfoutは約2Hzとなります。
ここまで準備ができたので、最初のプロジェクトを
作ってみます。順を追って、操作していきます。
下準備
新しいディレクトリを作成し、その中にVHDLファイル
を入れておきます。
開発環境を起動
デスクトップ上にある、次のアイコンをダブル
クリックして、開発環境を起動します。
Navigation GUIが表示されることを確認します。
新しいプロジェクトを作成するので、StartPageタブの
中にある、Projectの中のNewをクリックします。
プロジェクト新規作成の開始ページが現れるので
下の方にある、「Next」をクリックします。
プロジェクト名、ディレクトリ情報を入力する
ページが現れます。
「Browse」を操作し、サブディレクトリを指定します。
プロジェクト名を入力します。
下の方にある、「Next」をクリックすると、付加する
ファイルを指定するページが現れます。
今回は、ディレクトリ、VHDLコードは作成済みなので
「Add Source」をクリックします。
ディレクトリに格納されているVHDLファイルが見えます。
利用するファイルをすべて選択します。
「開く」のクリックで、次のページ表示になります。
下の方にある、「Next」をクリックします。
Device Selectページに遷移します。
評価基板上のチップにあうパラメータを設定します。
パラメータを確認したなら、「Next」をクリックします。
論理合成に使うツールの確認が出ます。
種々の情報が表示されるので、確認したなら
「Finish」をクリックします。
Reportsタブが表示され、プロジェクト関連
情報が表示されます。
VHDLソースコードにエラーがある場合、下にある
ステータスエリアに、赤でファイル名と行が表示
されます。
クロックソース指定
クロックソースは、LPCファイルで指定可能なので
あえて指定は不要です。ただし、LPCファイルの中で
指定は必要です。
外付けのデフォルトの5MHzを利用するとして、次のように
LPCファイルの内容を記述します。
BLOCK RESETPATHS;
BLOCK ASYNCPATHS;
LOCATE COMP "CLOCK" SITE "56" ; # 5MHz
I/Oバンク処理
CPLD/FPGAのチップは、正方形になっており、この
4辺からピンが出ています。
4辺それぞれにバンクの割当てがあるので
電源電圧とI/Oタイプを指定します。
ハードウエアで、バンクごとの電圧はすべて3.3V固定
なので、LPCファイルにそれらを指定します。
BANK 0 VCCIO 3.3 V;
BANK 1 VCCIO 3.3 V;
BANK 2 VCCIO 3.3 V;
BANK 3 VCCIO 3.3 V;
各ピンの出力は差分でなければ、次のインタフェースの
いずれかを利用できます。
- LVTTL
- LVCOMOS33
- LVCOMOS25
- LVCOMOS18
- LVCOMOS15
- LVCOMOS12
デモ用のLPCファイルでは、3.3VのCMOSタイプを指定して
LEDのブリンクをやっていたので、それに合わせます。
IOBUF ALLPORTS IO_TYPE=LVCMOS33 ;
ここまでの情報で指定できる、LPCファイルの内容を
書き出しておきます。
BLOCK RESETPATHS;
BLOCK ASYNCPATHS;
BANK 0 VCCIO 3.3 V;
BANK 1 VCCIO 3.3 V;
BANK 2 VCCIO 3.3 V;
BANK 3 VCCIO 3.3 V;
IOBUF ALLPORTS IO_TYPE=LVCMOS33 ;
LOCATE COMP "nRESET" SITE "109" ;
LOCATE COMP "CLOCK" SITE "56" ; # 5MHz
#
LOCATE COMP "LOUT[0]" SITE "97" ;
LOCATE COMP "LOUT[1]" SITE "98" ;
LOCATE COMP "LOUT[2]" SITE "99" ;
LOCATE COMP "LOUT[3]" SITE "100" ;
LOCATE COMP "LOUT[4]" SITE "104" ;
LOCATE COMP "LOUT[5]" SITE "105" ;
LOCATE COMP "LOUT[6]" SITE "106" ;
LOCATE COMP "LOUT[7]" SITE "107" ;
リセットは外付けハードウエアに入れて
あるので、負論理で利用しました。
拡張基板を接続して、次のようにしました。
J2、J5を利用して外部コネクタで拡張基板に
接続しました。
J2
1 NC
2 VCCIO0 extened board Vcc
3 PT36D/DONE(109) push switch
4 PT36C/INITn(110) CONNECTOR_1 0
5 PT36B(111) CONNECTOR_1 1
6 PT36A(112) CONNECTOR_1 2
7 GND
8 GND
9 PT33B(113) CONNECTOR_1 3
10 PT33A(114) CONNECTOR_1 4
11 PT28B(115) CONNECTOR_1 5
12 PT28A(117) CONNECTOR_1 6
13 PT27D/PROGn(119) CONNECTOR_1 7
14 PT27C/JTAGen(120) CONNECTOR_2 0
15 GND
16 GND
17 PT25B(121) CONNECTOR_2 1
18 PT25A(122) CONNECTOR_2 2
19 PT22D/SDA(125) CONNECTOR_2 3
20 PT22C/SDL(126) CONNECTOR_2 4
21 PT18B/PCLKC0_1(127)CONNECTOR_2 5
22 PT18A(128)
23 GND
24 GND
25 PT17D/TDM(130)
26 PT17C/TCK(131)
27 PT15B(132) CONNECTOR_2 6
28 PT15A(133) CONNECTOR_2 7
29 PT14D/TDI(136)
30 PT14C/TDO(137)
31 GND
32 GND
33 PT11B(138) CONNECTOR_3 0
34 PT11A(139) CONNECTOR_3 1
35 PT10B(140) CONNECTOR_3 2
36 PT10A(141) CONNECTOR_3 3
37 PT9B (142) yellow LED
38 PT9A (143) push switch
39 GND
40 GND
J5
1 NC
2 VCCIO2 extened board Vcc
3 PB38B/SI/SISPI(71) CONNECTOR_4 0
4 PB37B(69)
5 PB38A/SN(70) CONNECTOR_4 1
6 PB37A(68) CONNECTOR_4 2
7 PB35B(67) CONNECTOR_4 3
8 PB31B(62) CONNECTOR_4 4
9 PB35A(65) CONNECTOR_4 5
10 PB31A(61) CONNECTOR_4 6
11 GND
12 GND
13 PB29B(60) CONNECTOR_4 7
14 PB26B(58) CONNECTOR_5 0
15 PB29A(59) CONNECTOR_5 1
16 PB26A(57) CONNECTOR_5 2
17 GND
18 GND
19 PB23B/PCLKT2_1(56) external clock 5MHz
20 PB18B(54) CONNECTOR_5 3
21 PB23A/PCLKT2_0(55) CONNECTOR_5 4
22 PB18A(52)
23 GND
24 GND
25 PB16B/PCLKC2_0(50) external clock 10MHz
26 PB13B(48) CONNECTOR_5 5
27 PB16A/PCLKT2_0(49) CONNECTOR_5 6
28 PB13A(47) CONNECTOR_5 7
29 GND
30 GND
31 PB12B/S0/SPISO (45) CONNECTOR_6 0
32 PB9B(43) CONNECTOR_6 1
33 PB12A/MCLK/CCLK(44) CONNECTOR_6 2
34 PB9A(42) CONNECTOR_6 3
35 GND
36 GND
37 PB6B(41) CONNECTOR_6 4
38 PB4B(39) CONNECTOR_6 5
39 PB6A/CSSPIN(40)
40 PB4A(38) CONNECTOR_6 6
外部クロック生成回路は、以下。
論理合成、配置配線
論理合成、配置配線は、メニューバーの中にある
次のアイコンをクリックします。
処理がどこまで進んでいるのかは、左側に表示
されている、Processを見るとわかります。
Processが隠れているときは、下にあるタブを
クリックすると、出てきます。
WarningやErrorがあると、次のようなアイコンが
Processの中に表示されます。
何事もなければ、Signal All Greenで、次のアイコンが
表示されます。
JEDECファイル生成
CPLDというカテゴリーにチップが含まれるので
回路情報は、JEDECファイルとして生成します。
JEDECファイルの生成は、Processにあるチェックボックスに
チェックを入れたのち、JEDEC Fileをダブルクリックします。
ダウンロード
JEDECファイルに含まれている回路情報を、CPLD/FPGAに
ダウンロードするには、メニューバーの次のアイコンを
クリックします。
GUIが出てきます。
USBケーブルを認識させるために、「Detect Cable」を
クリックします。すでに認識されていれば、この操作は
不要です。
転送するJEDECファイルを指定する前に「MachXO2」を
クリックします。
「MachXO2」が使えるようになると、表示が変わります。
JEDECファイルを、File Managerで操作できるか
どうかは、アイコンのグレイ表示で判断します。
File Managerが使える状態で、次のアイコンを
クリックします。
Device PropertiesのGUI上で、3情報を指定します。
- Access Mode
- Operation
- Programming File
ファイルは、右側にあるアイコンをクリックして
ブラウザを動かすと簡単に指定できます。
3情報を指定してから、OKをクリックした後
ケーブル接続を確認したなら、次のアイコン
をクリックすると、JEDECファイルの内容を
FlashROMに転送します。
ダウンロード状況は、ステータスバーの表示
状況で確認できます。
終了
すべての操作が終わったなら、プロジェクトを
保存し、Diamondを終了します。
プロジェクトを閉じるには、メニューバーから
File→Close Projectとクリックしていきます。
プロジェクト情報の保存を聞かれるので
OKかCancelのどちらかをクリックします。
Diamondを終了するために、メニューバーから
File→Exitとクリックしていきます。
Knight Rider
複数のLEDを利用したC言語の"Hello , World !"に
相当するマイコンやCPLD/FPGAの定番テスト処理と
言えば、Knight Riderでしょう。
Michel Knightの愛車であるKnight 2000の
フロントグリルに着いたランプ処理を模倣
する処理を作成してテストします。
テスト基板には、スイッチをつけてあります。
このスイッチを利用し、Knight Riderの処理とします。
仕様は、以下。
- スイッチを押している間、LEDを点滅
- スイッチを押していないと、LEDは全消灯
- 両端から中央に点滅し、その後中央から両端に点滅する
- LEDは基板上の8個を利用
CPLD/FPGA基板上にLEDがあるので、スイッチと
クロックをどこに接続するのかを決め、LPFの
内容を指定します。
BLOCK RESETPATHS;
BLOCK ASYNCPATHS;
#
BANK 0 VCCIO 3.3 V;
BANK 1 VCCIO 3.3 V;
BANK 2 VCCIO 3.3 V;
BANK 3 VCCIO 3.3 V;
IOBUF ALLPORTS IO_TYPE=LVCMOS33 ;
#
LOCATE COMP "nRESET" SITE "109" ;
LOCATE COMP "CLOCK" SITE "50" ; # 10MHz
LOCATE COMP "ENA" SITE "143" ;
#
LOCATE COMP "LOUT[0]" SITE "97" ;
LOCATE COMP "LOUT[1]" SITE "98" ;
LOCATE COMP "LOUT[2]" SITE "99" ;
LOCATE COMP "LOUT[3]" SITE "100" ;
LOCATE COMP "LOUT[4]" SITE "104" ;
LOCATE COMP "LOUT[5]" SITE "105" ;
LOCATE COMP "LOUT[6]" SITE "106" ;
LOCATE COMP "LOUT[7]" SITE "107" ;
クロックを10MHzにしたので、分周して
ステートマシンでジョンソンカウンタを
構成します。
VHDLコードは以下。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity knight is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ; -- 10MHz
-- direction
ENA : in std_logic ;
-- output
LOUT : out std_logic_vector(7 downto 0) --;
);
end knight;
architecture behavioral of knight is
-- clock divider
signal iMCNT : std_logic_vector(19 downto 0) ;
signal iMCLK : std_logic ;
-- input
signal iENA : std_logic ;
-- output
signal iLOUT : std_logic_vector(7 downto 0) ;
-- decoder
signal iLOUTX : std_logic_vector(7 downto 0) ;
-- counter
signal iSTATE : std_logic_vector(3 downto 0) ;
begin
-- input
iENA <= not ENA ;
-- output
LOUT <= not iLOUT ;
--
iLOUT <= iLOUTX when ( iENA = '1' ) else
X"00" ;
-- decoder
iLOUTX <= X"81" when ( iSTATE = "0001" ) else
X"42" when ( iSTATE = "0011" ) else
X"24" when ( iSTATE = "0111" ) else
X"18" when ( iSTATE = "1111" ) else
X"24" when ( iSTATE = "1110" ) else
X"42" when ( iSTATE = "1100" ) else
X"81" when ( iSTATE = "1000" ) else
X"00" ;
-- clock divider
process( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iMCNT <= (others => '0') ;
elsif rising_edge( CLOCK ) then
iMCNT <= iMCNT + '1' ;
end if;
end process;
iMCLK <= iMCNT(19) ;
-- Global State machine
process( nRESET , iMCLK )
begin
if ( nRESET = '0' ) then
iSTATE <= "0000" ;
elsif rising_edge( iMCLK ) then
case conv_integer(iSTATE) is
when 0 => iSTATE <= "0001" ;
when 1 => iSTATE <= "0011" ;
when 3 => iSTATE <= "0111" ;
when 7 => iSTATE <= "1111" ;
when 15 => iSTATE <= "1110" ;
when 14 => iSTATE <= "1100" ;
when 12 => iSTATE <= "1000" ;
when 8 => iSTATE <= "0000" ;
when others => iSTATE <= "0000" ;
end case ;
end if;
end process;
end behavioral;
ステートマシンは、iSTATEの値を次のように
変化させていきます。
- 0000
- 0001
- 0011
- 0111
- 1111
- 1110
- 1100
- 1000
8状態を順番にデコーダに出力していきます。
デコーダは、入力値に対応したビットパターン
を出力していきます。
- 00000000
- 10000001
- 01000010
- 00100100
- 00011000
- 00100100
- 01000010
- 10000001
シーケンサ処理
拡張基板には、1個のLEDを実装したので
このLEDをプッシュスイッチを押すごとに
点滅と消灯を切り替えてみます。
点滅と消灯という2つの状態を持つので
シーケンサ(ステートマシン)の利用で
機械的に処理します。
点滅と消灯は、セレクタでLEDにクロックを
出力するか否かで実現します。
プッシュスイッチを押すたび、ENABLEを
1か0にするには、シーケンサを以下の
ように記述します。
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
elsif rising_edge(iMCLK) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iTRG = '1' ) then
iSTATE <= "01" ;
else
iSTATE <= "00" ;
end if ;
-- dummy skip
when 1 => iSTATE <= "11" ;
-- wait trigger
when 3 => if ( iTRG = '1' ) then
iSTATE <= "10" ;
else
iSTATE <= "11" ;
end if ;
-- return first state
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
iENABLE <= iSTATE(0) ;
ジョンソンカウンタを使い、シーケンサが
00→01→11→10のように状態遷移するよう
工夫します。
隣会うビットは、必ず1ビットしか変化しない
ように状態を定義していくと、LSBをそのまま
ENABLE信号で利用できます。
プッシュスイッチは、チャタリング除去のため
シフトレジスタを利用して、L→HかH→Lの変化
を捉えてトリガーとします。
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge(iMCLK) then
iTRG_SFT <= iTRG_SFT(1 downto 0) & (not TRG) ;
end if ;
end process ;
iTRG <= '1' when ( iTRG_SFT = "011" or iTRG_SFT = "001" ) else '0' ;
トリガーを利用して、シーケンサは
次の状態遷移をします。
状態を4つ持ちますが、半分をLEDの点滅、もう
半分をLEDの消灯で利用できます。
シーケンサは、チャタリング除去で利用した
クロック周波数と同じにしておきます。
内部でシーケンサが動いていることをモニタする
ために、CPLD/FPGA基板上の8個のLEDを点滅して
おきます。
人間の目でLEDの点滅がわかるように
しておかないと意味がなくなるので
LEDの点滅は2Hz程度にしておきます。
これらのことを踏まえ、VHDLコードを定義します。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity lcledt is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
TRG : in std_logic ;
-- output
LOUT : out std_logic_vector(7 downto 0);
LOUTX : out std_logic -- ;
);
end lcledt ;
architecture Behavioral of lcledt is
-- clock generator
signal iCNT : std_logic_vector(27 downto 0) ;
signal iMCLK : std_logic ;
-- trigger handling
signal iTRG_SFT : std_logic_vector(2 downto 0) ;
signal iTRG : std_logic ;
-- decoder
signal iLOUTX : std_logic ;
signal iLOUT : std_logic_vector(7 downto 0);
-- sequencer
signal iSTATE : std_logic_vector(1 downto 0) ;
signal iENABLE : std_logic ;
begin
-- output
LOUTX <= not iLOUTX ;
LOUT <= not iLOUT ;
-- clock generator
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= (others => '0') ;
elsif rising_edge(CLOCK) then
iCNT <= iCNT + '1' ;
end if ;
end process ;
iMCLK <= iCNT(18) ;
-- trigger
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge(iMCLK) then
iTRG_SFT <= iTRG_SFT(1 downto 0) & (not TRG) ;
end if ;
end process ;
iTRG <= '1' when ( iTRG_SFT = "011" or iTRG_SFT = "001" ) else '0' ;
-- sequencer
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
elsif rising_edge(iMCLK) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iTRG = '1' ) then
iSTATE <= "01" ;
else
iSTATE <= "00" ;
end if ;
-- dummy skip
when 1 => iSTATE <= "11" ;
-- wait trigger
when 3 => if ( iTRG = '1' ) then
iSTATE <= "10" ;
else
iSTATE <= "11" ;
end if ;
-- return first state
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
iENABLE <= iSTATE(0) ;
-- decoder
iLOUTX <= iCNT(20) when ( iENABLE = '1' ) else '0' ;
iLOUT <= iCNT(27 downto 20) ;
end Behavioral;
ピンアサインは、次のようにします。
BLOCK RESETPATHS;
BLOCK ASYNCPATHS;
#
BANK 0 VCCIO 3.3 V;
BANK 1 VCCIO 3.3 V;
BANK 2 VCCIO 3.3 V;
BANK 3 VCCIO 3.3 V;
IOBUF ALLPORTS IO_TYPE=LVCMOS33 ;
# system
LOCATE COMP "nRESET" SITE "109" ;
LOCATE COMP "CLOCK" SITE "50" ; # 10MHz
# trigger input
LOCATE COMP "TRG" SITE "143" ;
# LED output
LOCATE COMP "LOUTX" SITE "142" ;
# monitor
LOCATE COMP "LOUT[0]" SITE "97" ;
LOCATE COMP "LOUT[1]" SITE "98" ;
LOCATE COMP "LOUT[2]" SITE "99" ;
LOCATE COMP "LOUT[3]" SITE "100" ;
LOCATE COMP "LOUT[4]" SITE "104" ;
LOCATE COMP "LOUT[5]" SITE "105" ;
LOCATE COMP "LOUT[6]" SITE "106" ;
LOCATE COMP "LOUT[7]" SITE "107" ;
目次
前
次