信号機エミュレータ
知人から信号機をエミュレーションする
CPLD基板を貰いました。
VHDLコードで通常の信号機とスクランブル
交差点を実現したそうです。製作は大学生
で、半田付けとHDLの演習に利用したとか。
スクランブル交差点を入れてみるかとFPGA上で
エミュレーションしてから、CPLDに回路を実装
してみます。
FPGA基板は、いつものSpartan3Eを利用します。
スクランブル交差点の動作を、次のように決めました。
動作から必要なブロックを抽出し、図を描きます。
スクランブル交差点の動作を確定するのは
ステートマシンなので、カウンタとしては
ジョンソンカウンタを利用して定義。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity xstate is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
DOUT : out std_logic_vector(3 downto 0) --;
);
end xstate ;
architecture Behavioral of xstate is
signal iSTATE : std_logic_vector(3 downto 0);
begin
-- output
Dout <= iSTATE ;
-- state machine
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSTATE <= "0000";
elsif rising_edge(CLOCK) then
case conv_integer(iSTATE) is
-- 001 001
when 0 => iSTATE <= "0001" ;
-- 001 001
when 1 => iSTATE <= "0011" ;
-- 100 001
when 3 => iSTATE <= "0111" ;
-- 010 001
when 7 => iSTATE <= "1111" ;
-- 001 001
when 15 => iSTATE <= "1110" ;
-- 001 100
when 14 => iSTATE <= "1100" ;
-- 001 010
when 12 => iSTATE <= "1000" ;
-- 001 001
when 8 => iSTATE <= "0000" ;
-- default
when others =>
iSTATE <= "0000" ;
end case ;
end if ;
end process ;
end Behavioral;
ステートマシンの状態を使い、東西南北の
信号機の状態を確定します。4入力6出力
の組合せ回路で定義。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity news is
port (
-- input
Din : in std_logic_vector(3 downto 0) ;
-- output
Dout : out std_logic_vector(5 downto 0) --;
);
end news ;
architecture Behavioral of news is
signal iDin : std_logic_vector(3 downto 0);
signal iDout : std_logic_vector(5 downto 0);
begin
-- output
Dout <= iDout ;
-- input
iDin <= Din ;
-- decoder
iDout <= "001001" when ( iDin = "0000" ) else
"001001" when ( iDin = "0001" ) else
"100001" when ( iDin = "0011" ) else
"010001" when ( iDin = "0111" ) else
"001001" when ( iDin = "1111" ) else
"001100" when ( iDin = "1110" ) else
"001010" when ( iDin = "1100" ) else
"001001" when ( iDin = "1000" ) else
"001001" ;
end Behavioral;
ステートマシンの状態を使い、歩行者の
信号機の状態を確定します。ブリンクに
クロックディバイダから来るクロックを
使えばよいと考えました。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity mwalk is
port (
-- system
CLOCK : in std_logic ;
-- input
Din : in std_logic_vector(3 downto 0) ;
-- output
Dout : out std_logic_vector(1 downto 0) --;
);
end mwalk ;
architecture Behavioral of mwalk is
-- input
signal iDin : std_logic_vector(3 downto 0);
-- output
signal iDout : std_logic_vector(1 downto 0);
begin
-- output
Dout <= iDout ;
-- input
iDin <= Din ;
-- decoder and selector
iDout <= "01" when ( iDin = "0000" ) else
('0' & CLOCK) when ( iDin = "0001" ) else
(CLOCK & '0') when ( iDin = "1000" ) else
"10" ;
end Behavioral;
FPGA基板には、50MHzクロックがあるので
分周して、ステートマシンを0.1Hzで動作
させます。また、点滅は0.3Hz程度にして
おきます。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity mdivider is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
COUT0 : out std_logic ;
COUT1 : out std_logic -- ;
);
end mdivider ;
architecture Behavioral of mdivider is
-- constant value
constant CNT1_MAX : integer := 49999999 ;
constant CNT2_MAX : integer := 9 ;
-- clock divider
signal iCNT : std_logic_vector(25 downto 0);
signal iCLK : std_logic ;
signal iCNT1 : integer range 0 to CNT1_MAX ;
signal iCNT2 : integer range 0 to CNT2_MAX ;
signal iSCLK : std_logic ;
signal iBLINK : std_logic ;
begin
-- output
COUT0 <= iSCLK ;
COUT1 <= iCLK ;
-- internal input
iDin <= iSTATE ;
--clock divider for flashing
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= (others => '0') ;
elsif rising_edge( CLOCK ) then
iCNT <= iCNT + '1' ;
end if ;
end process ;
iCLK <= iCNT(25) ;
--clock divider for blink
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT1 <= 0 ;
elsif rising_edge( CLOCK ) then
if ( iCNT1 = CNT1_MAX ) then
iCNT1 <= 0 ;
else
iCNT1 <= iCNT1 + 1;
end if;
end if ;
end process ;
iBLINK <= '1' when ( iCNT1 = 0 ) else '0';
--clock divider for state machine
process (nRESET,iBLINK)
begin
if ( nRESET = '0' ) then
iCNT2<= 0 ;
elsif rising_edge( iBLINK ) then
if ( iCNT2 = CNT2_MAX ) then
iCNT2 <= 0 ;
else
iCNT2 <= iCNT2 + 1 ;
end if;
end if ;
end process ;
iSCLK <= '1' when ( iCNT2 = 0 ) else '0';
end Behavioral;
トップレベルでは、各VHDLコードをコンポーネント
として利用します。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity scramble is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
DOUT : out std_logic_vector(7 downto 0) --;
);
end scramble ;
architecture Behavioral of scramble is
-- state machine component
component xstate is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
DOUT : out std_logic_vector(3 downto 0) --;
);
end component ;
-- automobile decoder component
component news is
port (
-- input
Din : in std_logic_vector(3 downto 0) ;
-- output
Dout : out std_logic_vector(5 downto 0) --;
);
end component ;
-- walker decoder and selector component
component mwalk is
port (
-- system
CLOCK : in std_logic ;
-- input
Din : in std_logic_vector(3 downto 0) ;
-- output
Dout : out std_logic_vector(1 downto 0) --;
);
end component ;
-- clock divider component
component mdivider is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
COUT0 : out std_logic ;
COUT1 : out std_logic -- ;
);
end component ;
-- decoder
signal iCAR : std_logic_vector(5 downto 0);
signal iWALK : std_logic_vector(1 downto 0);
-- state machine
signal iSTATE : std_logic_vector(3 downto 0);
-- clock divider
signal iSCLK : std_logic ;
signal iBLINK : std_logic ;
begin
-- state machine
STATEX : xstate port map (nRESET,iSCLK,iSTATE) ;
-- automobile decoder component
XNEWS : news port map (iSTATE,iCAR) ;
-- walker decoder and selector component
WALKER : mwalk port map (iBLINK,iSTATE,iWALK) ;
-- clock divider component
SDIVIER : mdivider port (nRESET,iSCLK,iBLINK) ;
-- output
Dout <= iCAR & iWALK;
end Behavioral;
エミュレーションするために、UCFファイルを作成します。
# system
NET "nRESET" LOC = "P107" ;
NET "CLOCK" LOC = "P56" ;
# sramble traffic signals
NET "Dout<0>" LOC = "P132" ;
NET "Dout<1>" LOC = "P124" ;
NET "Dout<2>" LOC = "P113" ;
NET "Dout<3>" LOC = "P112" ;
NET "Dout<4>" LOC = "P117" ;
NET "Dout<5>" LOC = "P116" ;
NET "Dout<6>" LOC = "P123" ;
NET "Dout<7>" LOC = "P122" ;
CPLD基板には、XC9572が実装されているので
Spartan3EからXC9572にリターゲットします。
さらに、クロックディバイダのカウント値を
変更して完成です。
目次
前
次