目次
前
次
Altera FPGA
知り合いが、AlteraのFPGAを利用したトレーニング基板
を設計、開発したので、使わせて貰いました。
この基板には、ダウンロード用回路ByteBlaster互換品が
実装されており、USBで回路情報をアップロードできます。
CQ出版の雑誌付録であった基板では、ByteBlasterMV相当の
回路を作成し、利用しました。
Altera社が公開している回路では、74HC244を利用していますが
手持ちがなかったので、74HC04、74HC125を使いました。
ByteBlasterMV相当の回路を接続したFPGA基板は、以下です。
トレーニング基板の写真を見ると、周辺は
次のデバイスになっています。
- DIPスイッチ
- プッシュスイッチ
- LED
- 7セグメントLED
- 圧電ブザー
- モータードライバ
- A/Dコンバータ
- D/Aコンバータ
これらのデバイスを利用し、このFPGA(CycloneIV)を
動かしてみます。
漠然と考えても、動作は完成しないので、次の処理を
考えました。
- プッシュスイッチの状態をLEDに反映
- DIPスイッチの設定値で7セグメントLEDの表示変更
- クロック分周で圧電ブザーから音出し
- プッシュスイッチを押すと、LEDで方向指示(2LED処理)
- プッシュスイッチを押すと、LEDで方向指示(8LED処理)
- プッシュスイッチを押すと、モータを正転、逆転
A/D、D/Aコンバータは、上の3動作が完成して
テーマを考え、動かします。
各デバイスとFPGAピンの接続を回路図から確認しました。
プッシュスイッチ
2つあり、信号名はSW3、SW4とされています。
SW3 66
SW4 67
DIPスイッチ
2つあり、信号名はSW1、SW2とされています。
SW1_1 53
SW1_2 54
SW1_3 55
SW1_4 58
SW2_1 59
SW2_2 60
SW2_3 64
SW2_4 65
LED
8つのLEDがあり、信号名はLED1〜LED8とされています。
LED1 3
LED2 2
LED3 1
LED4 144
LED5 143
LED6 142
LED7 141
LED8 138
7セグメントLED
2つあり、信号名は7SEG1、7SEG2とされています。
7SEG1_A 33
7SEG1_B 34
7SEG1_C 38
7SEG1_D 28
7SEG1_E 30
7SEG1_F 31
7SEG1_G 32
7SEG1_DP 39
7SEG2_A 49
7SEG2_B 50
7SEG2_C 51
7SEG2_D 42
7SEG2_E 43
7SEG2_F 44
7SEG2_G 46
7SEG2_DP 52
圧電ブザー
音出力になっているので、SOUNDとしてあります。
SOUND 7
モータドライバ
2つあり、信号名はMT1、MT2とされています。
MT1_RIN 68
MT1_VREF 69
MT1_FIN 70
MT1_CLK 74
MT2_RIN 71
MT2_VREF 72
MT2_FIN 73
MT2_CLK 75
A/Dコンバータ
1チャネル8ビットの入力で、信号名はADCVです。
ADCV_D0 121
ADCV_D1 124
ADCV_D2 125
ADCV_D3 126
ADCV_D4 127
ADCV_D5 128
ADCV_D6 129
ADCV_D7 132
ADCV_ENCODE 133
ADCV_PWRDWN 135
10ピンコネクタに、AINが接続されています。
D/Aコンバータ
1チャネル12ビットになっています。信号名はDACV_DB。
DACV_DB0 76
DACV_DB1 77
DACV_DB2 82
DACV_DB3 83
DACV_DB4 84
DACV_DB5 85
DACV_DB6 100
DACV_DB7 100
DACV_DB8 100
DACV_DB9 100
DACV_DB10 100
DACV_DB11 110
DACV_RW 111
DACV_CSn 112
DACV_STBn 113
20ピンコネクタには、DACV_DBが出力されています。
10ピンコネクタに、2チャネルのD/A出力を接続して
あります。
拡張ピン
自由に利用できる拡張ピンが用意されています。
信号名はEXPです。
EXP_0 114
EXP_1 115
EXP_2 119
EXP_3 120
EXP_4 136
EXP_5 137
20ピンコネクタには、EXP_0〜EXP_3が抵抗を
挟んで接続されています。出力で利用します。
10ピンコネクタに、EXP_4、EXP_5が接続されて
います。入力で利用します。
クロック入力
クロック入力は7本あります。
20MHzか1Hzが入力されています。
CLK1 23 (20MHz)
CLK2 24 (20MHz)
CLK3 25 (1Hz)
CLK4 91 (1Hz)
CLK5 90 (1Hz)
CLK6 89 (1Hz)
CLK7 88 (1Hz)
開発環境はAlteraの場合、QuartusIIなので
ライセンス不要のWebエディションをダウン
ロードして、インストールします。
Alteraのページでユーザー登録してから、開発ソフトウエア
のページに移ってから、ダウンロードします。
ユーザー登録は無料ですが、ダウンロードには時間が
かかります。気長に待つことができる時にダウンロード
するとよいでしょう。
実際の動作時に使い方をマスターしていきます。
プッシュスイッチの状態をLEDに反映
FPGA基板には、2つのプッシュスイッチと8個のLEDが
あります。プッシュスイッチの状態を2個のLEDに反映
させるVHDLコードを考えます。
図で動作を考えます。
entityでスイッチとLEDを指定します。
entity swtst1 is
port (
-- input
PS : in std_logic_vector(1 downto 0) ;
-- output
LEDX : out std_logic_vector(1 downto 0) ;
LEDY : out std_logic_vector(1 downto 0) -- ;
);
end swtst1 ;
スイッチが正論理、負論理があるので、2ビット
ずつ出力してみます。
-- pin
LEDX <= iLEDX ;
LEDY <= iLEDY ;
-- output
iLEDX <= iPS ;
iLEDY <= not iPS ;
-- input
iPS <= PS ;
RTLあるいはBehavioralでまとめます。
architecture Behavioral of swtst1 is
-- internal registers
signal iLEDX : std_logic_vector(1 downto 0) ;
signal iLEDY : std_logic_vector(1 downto 0) ;
-- input buffer
signal iPS : std_logic_vector(1 downto 0) ;
begin
-- pin
LEDX <= iLEDX ;
LEDY <= iLEDY ;
-- output
iLEDX <= iPS ;
iLEDY <= not iPS ;
-- input
iPS <= PS ;
end Behavioral;
LEDとスイッチのピンアサインを決めます。
Alteraの開発環境では、拡張子が「qsf」のファイル中に
ピンアサインを格納します。
スイッチとLEDの対応は、次のように定義すれば充分。
set_location_assignment PIN_67 -to PS[0]
set_location_assignment PIN_66 -to PS[1]
set_location_assignment PIN_3 -to LEDX[1]
set_location_assignment PIN_138 -to LEDX[0]
set_location_assignment PIN_2 -to LEDY[1]
set_location_assignment PIN_141 -to LEDY[0]
拡張子が「qsf」のファイルの中には、次の
情報も入れます。
Family:Cyclone IV E
Package:TQFP 144
Device:EP4CE6E22I7
これらは、開発環境がプロジェクトを作成するとき
情報として含まれています。ファイルの中には、次
のように定義されていました。
set_global_assignment -name FAMILY "Cyclone IV E"
set_global_assignment -name DEVICE EP4CE6E22I7
set_global_assignment -name TOP_LEVEL_ENTITY swtst1
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name PROJECT_CREATION_TIME_DATE "19:06:50 NOVEMBER 08, 2013"
set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name VHDL_FILE swtst1.vhd
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
デバイスの種別、パッケージ、ピン数、グレード等は
プロジェクトを作成するときに、決めておけば充分と
考えられますが、最近のICでは、3.3V、2.5V等の信号
電圧や差動信号の指定が必要になります。
信号に関係する情報は、次のように指定しておかないと
実用に耐えるデバイスにはならないでしょう。
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDX
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDY
これらをQuartusIIのPin Planner(ピンプランナー)で
チマチマ指定するのは、面倒です。
CUIで使えるスクリプトを作り対応します。
テキストファイルに入れたピン番号と信号名から
QSFファイルに格納する定義を生成するスクリプト
をAWKで記述しました。
非常に単純で、10行に満たないコードです。
# mkpin.awk
{
printf("set_location_assignment PIN_");
printf("%d -to %s\n",$1,$2);
}
テキストファイルは、次のように単純に記述します。
67 PS[0]
66 PS[1]
3 LEDX[1]
138 LEDX[0]
2 LEDY[1]
141 LEDY[0]
AWKが動作する環境で、次のようにタイプすると
画面に結果を表示します。I/Oリダイレクトでの
テキストファイルへ保存で簡単にピンアサインを
QSFファイル中に入れる定義として取得できます。
gawk -f mkpin.awk tt.dat{enter}
作成した回路情報を、ByteBlasterMVもどきで
アップロードして、動作確認すると設計通りに
動きました。
スイッチを押していない状態。
左スイッチを押した状態。
(赤LEDの点灯位置が変わってます)
左スイッチを押した状態。
(緑LEDの点灯位置が変わってます)
LEDで方向指示器実現
20MHzのクロックが入力されているので
DIPスイッチの状態を見て、左か右への
方向指示をしてみます。
仕様は、次のようにします。
左のスイッチを上げたとき
右から左に向けて、順次LEDを点灯します。
10セット分点灯したなら、全LEDを消灯します。
右のスイッチを上げたとき
左から右に向けて、順次LEDを点灯します。
10セット分点灯したなら、全LEDを消灯します。
入力と出力を決めておきます。
仕様を決めたので、カウンタ値で、出力パターンを
定義します。
iLEFT <= X"01" when ( iCNT = 1 ) else
X"03" when ( iCNT = 2 ) else
X"07" when ( iCNT = 3 ) else
X"0f" when ( iCNT = 4 ) else
X"1f" when ( iCNT = 5 ) else
X"3f" when ( iCNT = 6 ) else
X"7f" when ( iCNT = 7 ) else
X"ff" when ( iCNT = 8 ) else
X"00" ;
iRIGHT <= X"80" when ( iCNT = 1 ) else
X"c0" when ( iCNT = 2 ) else
X"e0" when ( iCNT = 3 ) else
X"f0" when ( iCNT = 4 ) else
X"f8" when ( iCNT = 5 ) else
X"fc" when ( iCNT = 6 ) else
X"fe" when ( iCNT = 7 ) else
X"ff" when ( iCNT = 8 ) else
X"00" ;
DIPスイッチの状態で、どちらのパターンを
出力するかを選びます。
LEDX <= not iLEDX ;
iLEDX <= iLEFT when ( iSWD = "01" ) else
iRIGHT when ( iSWD = "10" ) else
X"00" ;
'0'出力で点灯する負論理で動かすため、iLEDXを
バッファで利用します。
出力パターンは、カウント値で決めているので
カウンタを作成します。
process (nRESET,iCLKX)
begin
if ( nRESET = '0' ) then
iSTATE <= 0 ;
iCNT <= CNTLAST ;
elsif rising_edge( iCLKX ) then
case iSTATE is
-- wait trigger
when 0 => if ( iCTRG = '1' ) then
iSTATE <= 1 ;
else
iSTATE <= 0 ;
end if ;
-- initialize counter
when 1 => iCNT <= 0 ;
iSTATE <= 2 ;
-- judge
when 2 => if ( iCNT = CNTLAST ) then
iSTATE <= 4 ;
else
iSTATE <= 3 ;
end if ;
-- counter increment
when 3 => iCNT <= iCNT + 1 ;
iSTATE <= 2 ;
-- return first state
when 4 => iSTATE <= 0 ;
-- default
when others =>
iSTATE <= 0 ;
end case ;
end if ;
end process ;
iCBUSY <= '1' when ( iSTATE = 2 ) else
'1' when ( iSTATE = 3 ) else
'0' ;
トリガーを与えると、最大値までカウントアップし自動停止
させます。カウンタが動作中か否かを示すために、フラグの
iCBUSYを使います。
カウンタを複数回にわたって動かすための
ステートマシンを用意しておきます。
process (nRESET,iCLKX)
begin
if ( nRESET = '0' ) then
iBSTATE <= 0 ;
iBCNT <= 0 ;
elsif rising_edge( iCLKX ) then
case iBSTATE is
-- wait trigger
when 0 => if ( iTRG = '1' ) then
iBSTATE <= 1 ;
else
iBSTATE <= 0 ;
end if ;
-- initialize counter
when 1 => iBCNT <= BCNTLAST ;
iBSTATE <= 2 ;
-- judge
when 2 => if ( iBCNT = 0 ) then
iBSTATE <= 8 ;
else
iBSTATE <= 3 ;
end if ;
-- send trigger
when 3 => iBSTATE <= 4 ;
-- synchronize wait
when 4 => iBSTATE <= 5 ;
-- wait complete
when 5 => if ( iCBUSY = '0' ) then
iBSTATE <= 7 ;
else
iBSTATE <= 6 ;
end if ;
-- loop
when 6 => iBSTATE <= 5 ;
-- update counter
when 7 => iBCNT <= iBCNT - 1 ;
iBSTATE <= 2 ;
-- return first state
when 8 => iBSTATE <= 0 ;
-- default
when others =>
iBSTATE <= 0 ;
end case ;
end if ;
end process ;
iCTRG <= '1' when ( iBSTATE = 3 ) else '0' ;
トリガーを与えると、カウンタに動作を開始させ
自動停止を確認します。動作か停止かは、フラグ
iCBUSYで判断。開始トリガーは、iCTRGと使います。
ステートマシンを動かすのは、TRGを利用し
外部から通知します。
TRGは、スイッチに接続しているので、チャタリング
除去が必要になります。シフトレジスタを使い、処理
します。
process (nRESET,iCLKX)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge( iCLKX ) 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' ;
ステートマシンやカウンタを動かすため
20MHzのクロックを分周して使います。
-- divider 20MHz -> 1kHz (generate 1kHz)
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iDCNT <= 0 ;
elsif rising_edge( CLOCK ) then
if ( iDCNT = DCNTMAX ) then
iDCNT <= 0 ;
else
iDCNT <= iDCNT + 1 ;
end if ;
end if ;
end process ;
iCLK <= '1' when ( iDCNT = 0 ) else '0' ;
-- divider 1kHz -> 50Hz (generate 50Hz)
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iDCNTX <= 0 ;
elsif rising_edge( iCLK ) then
if ( iDCNTX = DCNTXMAX ) then
iDCNTX <= 0 ;
else
iDCNTX <= iDCNTX + 1 ;
end if ;
end if ;
end process ;
iCLKX <= '1' when ( iDCNTX = 0 ) else '0' ;
VHDLコードにまとめると、次のようになります。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ltstx is
port (
-- system
nRESET : in std_logic;
CLOCK : in std_logic;
-- trigger input
TRG : in std_logic;
-- DIP switch input
SWD : in std_logic_vector(1 downto 0) ;
-- LED output
LEDX : out std_logic_vector(7 downto 0) -- ;
);
end ltstx;
architecture Behavioral of ltstx is
-- constant values
constant DCNTMAX : integer := 19999 ;
constant DCNTXMAX : integer := 99 ;
constant STATEMAX : integer := 4 ;
constant CNTLAST : integer := 12 ;
constant BSTATEMAX : integer := 8 ;
constant BCNTLAST : integer := 5 ;
-- output
signal iLEDX : std_logic_vector(7 downto 0) ;
-- input
signal iSWD : std_logic_vector(1 downto 0) ;
-- trigger
signal iTRG_SFT : std_logic_vector(2 downto 0) ;
signal iTRG : std_logic ;
-- internal output
signal iLEFT : std_logic_vector(7 downto 0) ;
signal iRIGHT : std_logic_vector(7 downto 0) ;
-- divider 0 (generate 1kHz)
signal iDCNT : integer range 0 to DCNTMAX ;
signal iCLK : std_logic ;
-- divider 1 (generate 10Hz)
signal iDCNTX : integer range 0 to DCNTXMAX ;
signal iCLKX : std_logic ;
-- blink counter
signal iSTATE : integer range 0 to STATEMAX ;
signal iCNT : integer range 0 to CNTLAST ;
signal iCBUSY : std_logic ;
-- blink manager
signal iBSTATE : integer range 0 to BSTATEMAX ;
signal iBCNT : integer range 0 to BCNTLAST ;
signal iCTRG : std_logic ;
begin
-- output
LEDX <= not iLEDX ;
-- input
iSWD <= not SWD ;
-- internal output
iLEDX <= iLEFT when ( iSWD = "01" ) else
iRIGHT when ( iSWD = "10" ) else
X"00" ;
-- decoder
iLEFT <= X"01" when ( iCNT = 1 ) else
X"03" when ( iCNT = 2 ) else
X"07" when ( iCNT = 3 ) else
X"0f" when ( iCNT = 4 ) else
X"1f" when ( iCNT = 5 ) else
X"3f" when ( iCNT = 6 ) else
X"7f" when ( iCNT = 7 ) else
X"ff" when ( iCNT = 8 ) else
X"00" ;
iRIGHT <= X"80" when ( iCNT = 1 ) else
X"c0" when ( iCNT = 2 ) else
X"e0" when ( iCNT = 3 ) else
X"f0" when ( iCNT = 4 ) else
X"f8" when ( iCNT = 5 ) else
X"fc" when ( iCNT = 6 ) else
X"fe" when ( iCNT = 7 ) else
X"ff" when ( iCNT = 8 ) else
X"00" ;
-- divider 20MHz -> 1kHz (generate 1kHz)
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iDCNT <= 0 ;
elsif rising_edge( CLOCK ) then
if ( iDCNT = DCNTMAX ) then
iDCNT <= 0 ;
else
iDCNT <= iDCNT + 1 ;
end if ;
end if ;
end process ;
iCLK <= '1' when ( iDCNT = 0 ) else '0' ;
-- divider 1kHz -> 50Hz (generate 50Hz)
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iDCNTX <= 0 ;
elsif rising_edge( iCLK ) then
if ( iDCNTX = DCNTXMAX ) then
iDCNTX <= 0 ;
else
iDCNTX <= iDCNTX + 1 ;
end if ;
end if ;
end process ;
iCLKX <= '1' when ( iDCNTX = 0 ) else '0' ;
-- trigger input
process (nRESET,iCLKX)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge( iCLKX ) 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' ;
-- blink counter
process (nRESET,iCLKX)
begin
if ( nRESET = '0' ) then
iSTATE <= 0 ;
iCNT <= CNTLAST ;
elsif rising_edge( iCLKX ) then
case iSTATE is
-- wait trigger
when 0 => if ( iCTRG = '1' ) then
iSTATE <= 1 ;
else
iSTATE <= 0 ;
end if ;
-- initialize counter
when 1 => iCNT <= 0 ;
iSTATE <= 2 ;
-- judge
when 2 => if ( iCNT = CNTLAST ) then
iSTATE <= 4 ;
else
iSTATE <= 3 ;
end if ;
-- counter increment
when 3 => iCNT <= iCNT + 1 ;
iSTATE <= 2 ;
-- return first state
when 4 => iSTATE <= 0 ;
-- default
when others =>
iSTATE <= 0 ;
end case ;
end if ;
end process ;
iCBUSY <= '1' when ( iSTATE = 2 ) else
'1' when ( iSTATE = 3 ) else
'0' ;
-- blink manager
process (nRESET,iCLKX)
begin
if ( nRESET = '0' ) then
iBSTATE <= 0 ;
iBCNT <= 0 ;
elsif rising_edge( iCLKX ) then
case iBSTATE is
-- wait trigger
when 0 => if ( iTRG = '1' ) then
iBSTATE <= 1 ;
else
iBSTATE <= 0 ;
end if ;
-- initialize counter
when 1 => iBCNT <= BCNTLAST ;
iBSTATE <= 2 ;
-- judge
when 2 => if ( iBCNT = 0 ) then
iBSTATE <= 8 ;
else
iBSTATE <= 3 ;
end if ;
-- send trigger
when 3 => iBSTATE <= 4 ;
-- synchronize wait
when 4 => iBSTATE <= 5 ;
-- wait complete
when 5 => if ( iCBUSY = '0' ) then
iBSTATE <= 7 ;
else
iBSTATE <= 6 ;
end if ;
-- loop
when 6 => iBSTATE <= 5 ;
-- update counter
when 7 => iBCNT <= iBCNT - 1 ;
iBSTATE <= 2 ;
-- return first state
when 8 => iBSTATE <= 0 ;
-- default
when others =>
iBSTATE <= 0 ;
end case ;
end if ;
end process ;
iCTRG <= '1' when ( iBSTATE = 3 ) else '0' ;
end Behavioral;
ピンアサインは、以下としました。
(これらは、QSFファイルをコピーしてテキストエディタで
必要な部分だけを変更しています。)
set_global_assignment -name FAMILY "Cyclone IV E"
set_global_assignment -name DEVICE EP4CE6E22I7
set_global_assignment -name TOP_LEVEL_ENTITY ltstx
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name PROJECT_CREATION_TIME_DATE "14:00:22 NOVEMBER 11, 2013"
set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name VHDL_FILE ltstx.vhd
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
set_location_assignment PIN_67 -to nRESET
set_location_assignment PIN_23 -to CLOCK
set_location_assignment PIN_66 -to TRG
set_location_assignment PIN_55 -to SWD[0]
set_location_assignment PIN_58 -to SWD[1]
set_location_assignment PIN_3 -to LEDX[7]
set_location_assignment PIN_2 -to LEDX[6]
set_location_assignment PIN_1 -to LEDX[5]
set_location_assignment PIN_144 -to LEDX[4]
set_location_assignment PIN_143 -to LEDX[3]
set_location_assignment PIN_142 -to LEDX[2]
set_location_assignment PIN_141 -to LEDX[1]
set_location_assignment PIN_138 -to LEDX[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDX
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLOCK
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to nRESET
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TRG
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to SWD
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
DIPスイッチの設定で7セグメントLEDに16進表示
1Hzのクロックが入力されているので
DIPスイッチの状態を利用して、2個
の7セグメントLEDに16進表示させて
みます。
1秒ごとに2個のDIPスイッチの状態を入力し
デコード後、2個の7セグメントLEDに、各々
16進表示する仕様にします。
入力と出力を決めておきます。
図からentityを記述できます。
entity adecx is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- DIP switch inputs
SWDX : in std_logic_vector(3 downto 0) ;
SWDY : in std_logic_vector(3 downto 0) ;
-- LED output
LEDX : out std_logic_vector(7 downto 0) ;
LEDY : out std_logic_vector(7 downto 0) -- ;
);
end adecx;
1秒ごとにDIPスイッチの状態を入力します。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iREGX <= "0000" ;
iREGY <= "0000" ;
elsif rising_edge( CLOCK ) then
iREGX <= iSWDX ;
iREGY <= iSWDY ;
end if ;
end process ;
内部レジスタの値をデコードし、7セグメントLEDの
ビットパターンを生成します。
iLEDX <= "01100000" when ( conv_integer(iREGX) = 1 ) else
"11011010" when ( conv_integer(iREGX) = 2 ) else
"11110010" when ( conv_integer(iREGX) = 3 ) else
"01100110" when ( conv_integer(iREGX) = 4 ) else
"10110110" when ( conv_integer(iREGX) = 5 ) else
"10111110" when ( conv_integer(iREGX) = 6 ) else
"11100100" when ( conv_integer(iREGX) = 7 ) else
"11111110" when ( conv_integer(iREGX) = 8 ) else
"11110110" when ( conv_integer(iREGX) = 9 ) else
"11101110" when ( conv_integer(iREGX) = 10 ) else
"00111110" when ( conv_integer(iREGX) = 11 ) else
"10011100" when ( conv_integer(iREGX) = 12 ) else
"01111010" when ( conv_integer(iREGX) = 13 ) else
"10011110" when ( conv_integer(iREGX) = 14 ) else
"10001110" when ( conv_integer(iREGX) = 15 ) else
"11111100" ;
iLEDY <= "01100000" when ( conv_integer(iREGY) = 1 ) else
"11011010" when ( conv_integer(iREGY) = 2 ) else
"11110010" when ( conv_integer(iREGY) = 3 ) else
"01100110" when ( conv_integer(iREGY) = 4 ) else
"10110110" when ( conv_integer(iREGY) = 5 ) else
"10111110" when ( conv_integer(iREGY) = 6 ) else
"11100100" when ( conv_integer(iREGY) = 7 ) else
"11111110" when ( conv_integer(iREGY) = 8 ) else
"11110110" when ( conv_integer(iREGY) = 9 ) else
"11101110" when ( conv_integer(iREGY) = 10 ) else
"00111110" when ( conv_integer(iREGY) = 11 ) else
"10011100" when ( conv_integer(iREGY) = 12 ) else
"01111010" when ( conv_integer(iREGY) = 13 ) else
"10011110" when ( conv_integer(iREGY) = 14 ) else
"10001110" when ( conv_integer(iREGY) = 15 ) else
"11111100" ;
主要な部分を定義したので、ソースコードにまとめます。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity adecx is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- DIP switch inputs
SWDX : in std_logic_vector(3 downto 0) ;
SWDY : in std_logic_vector(3 downto 0) ;
-- LED output
LEDX : out std_logic_vector(7 downto 0) ;
LEDY : out std_logic_vector(7 downto 0) -- ;
);
end adecx;
architecture Behavioral of adecx is
-- outputs
signal iLEDX : std_logic_vector(7 downto 0) ;
signal iLEDY : std_logic_vector(7 downto 0) ;
-- inputs
signal iSWDX : std_logic_vector(3 downto 0) ;
signal iSWDY : std_logic_vector(3 downto 0) ;
-- registers
signal iREGX : std_logic_vector(3 downto 0) ;
signal iREGY : std_logic_vector(3 downto 0) ;
begin
-- output
LEDX <= iLEDX ;
LEDY <= iLEDY ;
-- input
iSWDX <= not SWDX ;
iSWDY <= not SWDY ;
-- latch
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iREGX <= "0000" ;
iREGY <= "0000" ;
elsif rising_edge( CLOCK ) then
iREGX <= iSWDX ;
iREGY <= iSWDY ;
end if ;
end process ;
-- decoder abcdefgDp
iLEDX <= "01100000" when ( conv_integer(iREGX) = 1 ) else
"11011010" when ( conv_integer(iREGX) = 2 ) else
"11110010" when ( conv_integer(iREGX) = 3 ) else
"01100110" when ( conv_integer(iREGX) = 4 ) else
"10110110" when ( conv_integer(iREGX) = 5 ) else
"10111110" when ( conv_integer(iREGX) = 6 ) else
"11100100" when ( conv_integer(iREGX) = 7 ) else
"11111110" when ( conv_integer(iREGX) = 8 ) else
"11110110" when ( conv_integer(iREGX) = 9 ) else
"11101110" when ( conv_integer(iREGX) = 10 ) else
"00111110" when ( conv_integer(iREGX) = 11 ) else
"10011100" when ( conv_integer(iREGX) = 12 ) else
"01111010" when ( conv_integer(iREGX) = 13 ) else
"10011110" when ( conv_integer(iREGX) = 14 ) else
"10001110" when ( conv_integer(iREGX) = 15 ) else
"11111100" ;
iLEDY <= "01100000" when ( conv_integer(iREGY) = 1 ) else
"11011010" when ( conv_integer(iREGY) = 2 ) else
"11110010" when ( conv_integer(iREGY) = 3 ) else
"01100110" when ( conv_integer(iREGY) = 4 ) else
"10110110" when ( conv_integer(iREGY) = 5 ) else
"10111110" when ( conv_integer(iREGY) = 6 ) else
"11100100" when ( conv_integer(iREGY) = 7 ) else
"11111110" when ( conv_integer(iREGY) = 8 ) else
"11110110" when ( conv_integer(iREGY) = 9 ) else
"11101110" when ( conv_integer(iREGY) = 10 ) else
"00111110" when ( conv_integer(iREGY) = 11 ) else
"10011100" when ( conv_integer(iREGY) = 12 ) else
"01111010" when ( conv_integer(iREGY) = 13 ) else
"10011110" when ( conv_integer(iREGY) = 14 ) else
"10001110" when ( conv_integer(iREGY) = 15 ) else
"11111100" ;
end Behavioral;
VHDLコードに続き、ピンアサインを定義します。
set_global_assignment -name FAMILY "Cyclone IV E"
set_global_assignment -name DEVICE EP4CE6E22I7
set_global_assignment -name TOP_LEVEL_ENTITY adecx
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:07:49 NOVEMBER 11, 2013"
set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name VHDL_FILE adecx.vhd
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
set_location_assignment PIN_67 -to nRESET
set_location_assignment PIN_88 -to CLOCK
set_location_assignment PIN_58 -to SWDX[0]
set_location_assignment PIN_55 -to SWDX[1]
set_location_assignment PIN_54 -to SWDX[2]
set_location_assignment PIN_53 -to SWDX[3]
set_location_assignment PIN_65 -to SWDY[0]
set_location_assignment PIN_64 -to SWDY[1]
set_location_assignment PIN_60 -to SWDY[2]
set_location_assignment PIN_59 -to SWDY[3]
set_location_assignment PIN_39 -to LEDX[0]
set_location_assignment PIN_32 -to LEDX[1]
set_location_assignment PIN_31 -to LEDX[2]
set_location_assignment PIN_30 -to LEDX[3]
set_location_assignment PIN_28 -to LEDX[4]
set_location_assignment PIN_38 -to LEDX[5]
set_location_assignment PIN_34 -to LEDX[6]
set_location_assignment PIN_33 -to LEDX[7]
set_location_assignment PIN_52 -to LEDY[0]
set_location_assignment PIN_46 -to LEDY[1]
set_location_assignment PIN_44 -to LEDY[2]
set_location_assignment PIN_43 -to LEDY[3]
set_location_assignment PIN_42 -to LEDY[4]
set_location_assignment PIN_51 -to LEDY[5]
set_location_assignment PIN_50 -to LEDY[6]
set_location_assignment PIN_49 -to LEDY[7]
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to nRESET
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLOCK
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to SWDX
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to SWDY
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
この動作を基板に転送して、動作確認すると
DIPスイッチの1ビットの半田付け不良を発見
できました。
2つのDIPスイッチの設定で、7セグメントLEDに
16進が表示されているのがわかります。
ブザーで音出し
基板上にブザーがあるので、可聴帯域の周波数を
切り替えて、音を出してみます。
入出力を図示して考えます。
人間の可聴帯域は、20Hz〜20kHzとなっていますが
ブザーにトランジスタが接続されているため、高い
周波数は使わないようにします。
50Hz、100Hz、200Hz、400Hz、800Hz、1.6kHz、3.2kHz
6.4kHzの8種の周波数を選べるようにします。
7セグメントLEDのテストで作ったコードを流用し
DIPスイッチのビットをONすると、その周波数が
出力される仕様に。
20MHzから12.8kHzを生成して、バイナリーカウンタを
動かします。バイナリーカウンタの各ビットを出力し
必要な周波数にします。
-- iSCLK = 12.8kHz
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= (others => '0') ;
elsif rising_edge( iSCLK ) then
iSCNT <= iSCNT + '1' ;
end if ;
end process ;
8種の周波数を出力するためには、セレクタを使います。
iBEEPX <= iSCNT(0) when ( conv_integer(iREGX) = 8 ) else
iSCNT(1) when ( conv_integer(iREGX) = 4 ) else
iSCNT(2) when ( conv_integer(iREGX) = 2 ) else
iSCNT(3) when ( conv_integer(iREGX) = 1 ) else
iSCNT(4) when ( conv_integer(iREGY) = 8 ) else
iSCNT(5) when ( conv_integer(iREGY) = 4 ) else
iSCNT(6) when ( conv_integer(iREGY) = 2 ) else
iSCNT(7) when ( conv_integer(iREGY) = 1 ) else
'0' ;
セレクタにはレジスタを利用しているので、DIPスイッチから
情報を入力します。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iREGX <= "0000" ;
iREGY <= "0000" ;
elsif rising_edge( CLOCK ) then
iREGX <= iSWDX ;
iREGY <= iSWDY ;
end if ;
end process ;
DIPスイッチの状態を、8個の個別LEDに反映させて
わかりやすくしておきます。
GLED <= not iREGX ;
RLED <= not iREGY ;
12.8kHzを生成するには、次の分周回路を利用します。
process (nRESET,CLOCK7)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge( CLOCK7 ) then
if ( iCNT = 1562 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iSCLK <= '1' when ( iCNT = 0 ) else '0' ;
ソースコードにまとめると、次のようになります。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity abeep is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
CLOCK7 : in std_logic ;
-- DIP switch inputs
SWDX : in std_logic_vector(3 downto 0) ;
SWDY : in std_logic_vector(3 downto 0) ;
-- BEEP
BEEPX : out std_logic ;
-- green and red LEDs output
GLED : out std_logic_vector(3 downto 0) ;
RLED : out std_logic_vector(3 downto 0) -- ;
);
end abeep;
architecture Behavioral of abeep is
-- outputs
signal iLEDX : std_logic_vector(7 downto 0) ;
signal iLEDY : std_logic_vector(7 downto 0) ;
-- inputs
signal iSWDX : std_logic_vector(3 downto 0) ;
signal iSWDY : std_logic_vector(3 downto 0) ;
-- registers
signal iREGX : std_logic_vector(3 downto 0) ;
signal iREGY : std_logic_vector(3 downto 0) ;
-- divider
signal iCNT : integer range 0 to 1562 ;
signal iSCLK : std_logic;
signal iSCNT : std_logic_vector(7 downto 0) ;
signal iBEEPX : std_logic ;
begin
-- output
GLED <= not iREGX ;
RLED <= not iREGY ;
BEEPX <= iBEEPX ;
-- input
iSWDX <= not SWDX ;
iSWDY <= not SWDY ;
-- latch
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iREGX <= "0000" ;
iREGY <= "0000" ;
elsif rising_edge( CLOCK ) then
iREGX <= iSWDX ;
iREGY <= iSWDY ;
end if ;
end process ;
-- divider
process (nRESET,CLOCK7)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge( CLOCK7 ) then
if ( iCNT = 1562 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iSCLK <= '1' when ( iCNT = 0 ) else '0' ;
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iSCNT <= (others => '0') ;
elsif rising_edge( iSCLK ) then
iSCNT <= iSCNT + '1' ;
end if ;
end process ;
-- select
iBEEPX <= iSCNT(0) when ( conv_integer(iREGX) = 8 ) else
iSCNT(1) when ( conv_integer(iREGX) = 4 ) else
iSCNT(2) when ( conv_integer(iREGX) = 2 ) else
iSCNT(3) when ( conv_integer(iREGX) = 1 ) else
iSCNT(4) when ( conv_integer(iREGY) = 8 ) else
iSCNT(5) when ( conv_integer(iREGY) = 4 ) else
iSCNT(6) when ( conv_integer(iREGY) = 2 ) else
iSCNT(7) when ( conv_integer(iREGY) = 1 ) else
'0' ;
end Behavioral;
ピンアサインを決めます。
set_global_assignment -name FAMILY "Cyclone IV E"
set_global_assignment -name DEVICE EP4CE6E22I7
set_global_assignment -name TOP_LEVEL_ENTITY abeep
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:07:49 NOVEMBER 11, 2013"
set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
set_location_assignment PIN_67 -to nRESET
set_location_assignment PIN_88 -to CLOCK
set_location_assignment PIN_23 -to CLOCK7
set_location_assignment PIN_7 -to BEEPX
set_location_assignment PIN_58 -to SWDX[0]
set_location_assignment PIN_55 -to SWDX[1]
set_location_assignment PIN_54 -to SWDX[2]
set_location_assignment PIN_53 -to SWDX[3]
set_location_assignment PIN_65 -to SWDY[0]
set_location_assignment PIN_64 -to SWDY[1]
set_location_assignment PIN_60 -to SWDY[2]
set_location_assignment PIN_59 -to SWDY[3]
set_location_assignment PIN_3 -to GLED[3]
set_location_assignment PIN_2 -to GLED[2]
set_location_assignment PIN_1 -to GLED[1]
set_location_assignment PIN_144 -to GLED[0]
set_location_assignment PIN_143 -to RLED[3]
set_location_assignment PIN_142 -to RLED[2]
set_location_assignment PIN_141 -to RLED[1]
set_location_assignment PIN_138 -to RLED[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to nRESET
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLOCK
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLOCK7
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to SWDX
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to SWDY
set_global_assignment -name VHDL_FILE abeep.vhd
set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF
set_global_assignment -name RESERVE_ALL_UNUSED_PINS_WEAK_PULLUP "AS OUTPUT DRIVING GROUND"
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
モータ制御チップ処理
基板上に、DCモータ制御チップが用意されています。
データシートで必要情報を見て、動作を考えます。
方向制御は、正転、逆転を、Fin、Rinで制御できる
ようです。また、回転制御は、Fin、RinにPWM波形
を入れると読めます。
ドライブICの電源入力が、別にあるので、マブチ
モータRE140、RE160等は、接続してPWM波形を与え
簡単に動かせそうです。
正転、逆転は、Fin、RinのどちらにPWM波形を与えるか
切り替えるように、プッシュスイッチで制御します。
FPGA内部に状態変数を2つもてば回転方向の設定と
PWM波形を出力するか停止するかを制御できます。
大まかなVHDLコードを考えると以下です。
iOUTX <= '1' when ( iPCNT < iDUTY ) else
'1' when ( iDUTY = 100 ) else
'0' ;
iFinRin <= ('0' & iOUTX) when ( iREGX(2 downto 1) = "01" ) else
(iOUTX & '0') when ( iREGX(2 downto 1) = "10" ) else
"00" ;
方向設定とPWM波形出力制御は、4ビットのDIP
スイッチ中の2ビットで設定します。
DUTY比は、4ビットのDIPスイッチで設定します。
次のように、DUTY比を固定としておきます。
0001 -> 5%
0011 -> 25%
0111 -> 50%
1111 -> 100%
DIPスイッチは次のように設定します。
左のDIPスイッチの3ビットは、プッシュスイッチを
押し、トリガーを入れたときだけ内部に記憶します。
次のように、トリガーを捕らえてレジスタに値を格納します。
-- trigger input
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge( CLOCK ) 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' ;
-- latch
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iREGX <= "000" ;
iREGY <= "0000" ;
elsif rising_edge( CLOCK ) then
if ( iTRG = '1' ) then
iREGX <= iSWDX(2 downto 0) ;
end if ;
iREGY <= iSWDY ;
end if ;
end process ;
DUTY比は、常に更新します。
iDUTY <= 5 when ( iREGY = "0001" ) else
25 when ( iREGY = "0011" ) else
50 when ( iREGY = "0111" ) else
100 when ( iREGY = "1111" ) else
0 ;
PWMの元周波数は、100kHzにします。
process (nRESET,CLOCK7)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge( CLOCK7 ) then
if ( iCNT = 199 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iSCLK <= '1' when ( iCNT = 0 ) else '0' ;
0〜99までカウントしPWMの1周期を10kHzにします。
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iPCNT <= 0 ;
elsif rising_edge( iSCLK ) then
if ( iPCNT = 99 ) then
iPCNT <= 0 ;
else
iPCNT <= iPCNT + 1 ;
end if ;
end if ;
end process ;
DUTY比によるパルス幅は、カウンタとレジスタ値を
比較して確定します。
iOUTX <= '1' when ( iPCNT < iDUTY ) else
'1' when ( iDUTY = 100 ) else
'0' ;
ソースコードにまとめると、以下。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity amotor is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
CLOCK7 : in std_logic ;
-- trigger inputs
TRG : in std_logic ;
-- DIP switch inputs
SWDX : in std_logic_vector(3 downto 0) ;
SWDY : in std_logic_vector(3 downto 0) ;
-- PWM
FinRin : out std_logic_vector(1 downto 0) ;
OUTX : out std_logic ;
-- green and red LEDs output
GLED : out std_logic_vector(3 downto 0) ;
RLED : out std_logic_vector(3 downto 0) -- ;
);
end amotor;
architecture Behavioral of amotor is
-- outputs
signal iRLED : std_logic_vector(1 downto 0) ;
signal iOUTX : std_logic ;
-- trigger input
signal iTRG_SFT : std_logic_vector(2 downto 0) ;
signal iTRG : std_logic ;
-- inputs
signal iSWDX : std_logic_vector(3 downto 0) ;
signal iSWDY : std_logic_vector(3 downto 0) ;
-- registers
signal iREGX : std_logic_vector(2 downto 0) ;
signal iREGY : std_logic_vector(3 downto 0) ;
-- divider (100kHz)
signal iCNT : integer range 0 to 199 ;
signal iSCLK : std_logic ;
-- PWM
signal iDUTY : integer range 0 to 100 ;
signal iPCNT : integer range 0 to 99 ;
signal iFinRin : std_logic_vector(1 downto 0) ;
begin
-- output
RLED <= not ('0' & iREGX) ;
GLED <= not iREGY ;
FinRin <= iFinRin ;
OUTX <= iREGX(0) ;
-- input
iSWDX <= not SWDX ;
iSWDY <= not SWDY ;
-- trigger input
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge( CLOCK ) 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' ;
-- latch
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iREGX <= "000" ;
iREGY <= "0000" ;
elsif rising_edge( CLOCK ) then
if ( iTRG = '1' ) then
iREGX <= iSWDX(2 downto 0) ;
end if ;
iREGY <= iSWDY ;
end if ;
end process ;
-- divider
process (nRESET,CLOCK7)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge( CLOCK7 ) then
if ( iCNT = 199 ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iSCLK <= '1' when ( iCNT = 0 ) else '0' ;
-- PWM counter
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iPCNT <= 0 ;
elsif rising_edge( iSCLK ) then
if ( iPCNT = 99 ) then
iPCNT <= 0 ;
else
iPCNT <= iPCNT + 1 ;
end if ;
end if ;
end process ;
-- select
iDUTY <= 5 when ( iREGY = "0001" ) else
25 when ( iREGY = "0011" ) else
50 when ( iREGY = "0111" ) else
100 when ( iREGY = "1111" ) else
0 ;
iOUTX <= '1' when ( iPCNT < iDUTY ) else
'1' when ( iDUTY = 100 ) else
'0' ;
iFinRin <= ('0' & iOUTX) when ( iREGX(2 downto 1) = "01" ) else
(iOUTX & '0') when ( iREGX(2 downto 1) = "10" ) else
"00" ;
end Behavioral;
ピンアサインをQSFファイルに書き出します。
set_global_assignment -name FAMILY "Cyclone IV E"
set_global_assignment -name DEVICE EP4CE6E22I7
set_global_assignment -name TOP_LEVEL_ENTITY amotor
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:07:49 NOVEMBER 11, 2013"
set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
set_location_assignment PIN_67 -to nRESET
set_location_assignment PIN_88 -to CLOCK
set_location_assignment PIN_23 -to CLOCK7
set_location_assignment PIN_66 -to TRG
set_location_assignment PIN_69 -to OUTX
set_location_assignment PIN_68 -to FinRin[0]
set_location_assignment PIN_70 -to FinRin[1]
set_location_assignment PIN_58 -to SWDX[0]
set_location_assignment PIN_55 -to SWDX[1]
set_location_assignment PIN_54 -to SWDX[2]
set_location_assignment PIN_53 -to SWDX[3]
set_location_assignment PIN_65 -to SWDY[0]
set_location_assignment PIN_64 -to SWDY[1]
set_location_assignment PIN_60 -to SWDY[2]
set_location_assignment PIN_59 -to SWDY[3]
set_location_assignment PIN_3 -to RLED[3]
set_location_assignment PIN_2 -to RLED[2]
set_location_assignment PIN_1 -to RLED[1]
set_location_assignment PIN_144 -to RLED[0]
set_location_assignment PIN_143 -to GLED[3]
set_location_assignment PIN_142 -to GLED[2]
set_location_assignment PIN_141 -to GLED[1]
set_location_assignment PIN_138 -to GLED[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to nRESET
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLOCK
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLOCK7
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to SWDX
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to SWDY
set_global_assignment -name VHDL_FILE amotor.vhd
set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF
set_global_assignment -name RESERVE_ALL_UNUSED_PINS_WEAK_PULLUP "AS OUTPUT DRIVING GROUND"
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
set_global_assignment -name SOURCE_FILE amotor.qsf
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
動作は、2つのLEDのアノードとカソードを交互に
接続した回路でテストしました。
方向を正転とし、DUTY比を5%にし、LEDの点灯を
テストすると、次のようになります。
方向を逆転とし、DUTY比を100%とすると、以下の
ようになりました。
接続は、次のようにしてあります。
目次
前
次