シングルPLDでの実現
マルチPLD構想で、2つのCPLDを利用してMCR-VCマシン
の移動処理を実現しました。
CoolRunnerIIのゲート数には、余裕があったので
移動関連部分を合体させられるかやってみました。
問題なく入ります。
マルチPLD構想の中で、2個のモータに与えるDUTY比の
処理をXC9572XLに担当させていました。
これをCoolRunnerIIに入れます。
モータへのPWM波形出力は、別途VHDLコードを定義し
それを使う設計にしました。
DUTY比は、最高でも50%として、左右に各7ビットを
割当てます。
VHDLコードの定義は以下です。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity pwmx is
port(
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- input
PRATER : in std_logic_vector(5 downto 0) ;
PRATEL : in std_logic_vector(5 downto 0) ;
-- output
POUTR : out std_logic ;
POUTL : out std_logic --;
);
end pwmx ;
architecture Behavioral of pwmx is
signal iPCNT : integer range 0 to 100 ;
signal iPOUT : std_logic_vector(1 downto 0) ;
signal iPRATER : std_logic_vector(5 downto 0) ;
signal iPRATEL : std_logic_vector(5 downto 0) ;
begin
-- output
POUTR <= not iPOUT(0) ;
POUTL <= not iPOUT(1) ;
-- comparetor
iPOUT(0) <= '1' when ( iPCNT < conv_integer( iPRATER ) ) else '0' ;
iPOUT(1) <= '1' when ( iPCNT < conv_integer( iPRATEL ) ) else '0' ;
-- counter
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iPCNT <= 0 ;
iPRATER <= "000000" ;
iPRATEL <= "000000" ;
elsif rising_edge( CLOCK ) then
if ( iPCNT = 100 ) then
iPCNT <= 0 ;
iPRATER <= PRATER ;
iPRATEL <= PRATEL ;
else
iPCNT <= iPCNT + 1 ;
end if ;
end if ;
end process ;
end Behavioral;
クロックには、100kHzを与えます。周期は10usになるので
0〜99のDUTY比を与えるとすると、パルス幅は0〜9.9msに
なります。
実際の制御回路は、次の写真でわかるように2個のスイッチ
と4個のLEDをつけてあります。
PWM波形が入力されているかを示すため、2個のLEDをフォト
カプラに接続しています(ポカよけです)。
DUTY比を与える処理を削除し、2つのスイッチとLEDを
扱う部分を付け加えていきます。
2つのスイッチの一方は、スタートトリガーなので
シフトレジスタを利用して、チャタリング除去します。
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iSETRG_SFT <= "000" ;
elsif rising_edge(iMCLK) then
iSETRG_SFT <= iSETRG_SFT(1 downto 0) & iSETRG ;
end if ;
end process ;
iTRG_R <= '1' when ( iSETRG_SFT = "011" or iSETRG_SFT = "001" ) else '0' ;
iTRG_F <= '1' when ( iSETRG_SFT = "110" or iSETRG_SFT = "100" ) else '0' ;
2個のLEDのうち、緑LEDはCPLDが移動処理動作
実行中を示すインディケータにします。
ステートマシンを動かすカウンタ値をデコード
して点灯させます。
iGLED <= '1' when ( iPSTATE(0) = '1' or iPSTATE = "110" ) else '0' ;
テスト、デバッグに利用する目的で赤LEDを用意
しています。赤LEDはセンサーが白線を検出した
ときに、点灯させます。
iRLED <= '1' when ( iJSENSOR = X"FF" ) else '0' ;
必要な処理を入れ、VHDLコードは以下のようになりました。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity mcrx6 is
generic (
TOPX : integer := 4 ;
RMAX : integer := 9 --;
) ;
Port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- sensor inputs
SENSOR : in std_logic_vector(7 downto 0) ;
-- trigger input
SETRG : in std_logic ; -- start or exit flag
-- turn input
TURN : in std_logic ; -- direction
-- OUTPUT
POUTR : out std_logic ; -- right motor duty ratio
POUTL : out std_logic ; -- left motor duty ratio
GLED : out std_logic ; -- run
RLED : out std_logic ; -- cross white line
STATUS : out std_logic_vector(7 downto 0) ;
SOUT : out std_logic_vector(7 downto 0) ;
LED : out std_logic --;
);
end mcrx6;
architecture behavioral of mcrx6 is
-- clock generator
component clkgenx is
generic (
TOPX : integer ;
RMAX : integer --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
CLKOUT : out std_logic -- ;
);
end component ;
-- judge
component judge is
port (
-- input
DIN : in std_logic_vector(7 downto 0) ;
-- output
JOUT : out std_logic_vector(3 downto 0) --;
);
end component ;
-- judge
component pwmx is
port(
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- input
PRATER : in std_logic_vector(5 downto 0) ;
PRATEL : in std_logic_vector(5 downto 0) ;
-- output
POUTR : out std_logic ;
POUTL : out std_logic --;
);
end component ;
-- clock
signal iMCLK : std_logic ;
-- parent sequencer
signal iPSTATE : std_logic_vector(2 downto 0) ;
signal iBTRG : std_logic ; -- blind run trigger
signal iBFLAG : std_logic ; -- blind run flag
signal iJTRG : std_logic ; -- judge run trigger
-- blind run sequencer
signal iBSTATE : integer range 0 to 7 ;
signal iBCNT : integer range 0 to 300000 ;
signal iBDUTY : integer range 0 to 63 ;
-- judge run sequencer
signal iJSTATE : std_logic_vector(2 downto 0) ;
signal iJRDUTYX : integer range 0 to 63 ;
signal iJLDUTYX : integer range 0 to 63 ;
signal iJRDUTY : std_logic_vector(5 downto 0) ;
signal iJLDUTY : std_logic_vector(5 downto 0) ;
signal iJSENSOR : std_logic_vector(7 downto 0) ;
signal iSENSOR : std_logic_vector(7 downto 0) ;
signal iJOUT : std_logic_vector(3 downto 0) ;
signal iMODE : integer range 0 to 3 ;
signal iJCNT : integer range 0 to 100000 ;
--
signal iSTATUS : std_logic_vector(7 downto 0) ;
-- trigger
signal iSETRG : std_logic ;
signal iSETRG_SFT : std_logic_vector(2 downto 0) ;
signal iTRG_R : std_logic ;
signal iTRG_F : std_logic ;
-- PWM
signal iPOUTR : std_logic ;
signal iPOUTL : std_logic ;
-- LED
signal iGLED : std_logic ;
signal iRLED : std_logic ;
begin
-- clock
CLKX : clkgenx generic map (TOPX,RMAX) port map (nRESET,CLOCK,iMCLK) ;
-- judge
JUDGEX : judge port map (iSENSOR,iJOUT) ;
-- pwm
PWM : pwmx port map (nRESET,iMCLK,iJRDUTY,iJLDUTY,iPOUTR,iPOUTL);
-- input
iJSENSOR <= not SENSOR ;
iSETRG <= not SETRG ;
-- output
POUTR <= iPOUTR ;
POUTL <= iPOUTL ;
GLED <= iGLED ;
RLED <= iRLED ;
-- monitor
LED <= not TURN ;
SOUT <= not iJSENSOR ;
STATUS <= not iSTATUS ;
iGLED <= '1' when ( iPSTATE(0) = '1' or iPSTATE = "110" ) else '0' ;
iRLED <= '1' when ( iJSENSOR = X"FF" ) else '0' ;
-- internal status
iSTATUS(3 downto 0) <= "1000" when ( iBSTATE = 1 ) else -- duty 5%
"0100" when ( iBSTATE = 3 ) else -- duty 15%
"0010" when ( iBSTATE = 5 ) else -- duty 30%
"0001" when ( iBSTATE = 7 ) else -- duty 50%
"0000" ;
iSTATUS(7 downto 4) <= "1000" when ( iMODE = 0 ) else -- NORMAL
"0100" when ( iMODE = 3 ) else -- CRANK
"0010" when ( iMODE = 1 ) else -- LANE RIGHT
"0001" when ( iMODE = 2 ) else -- LANE LEFT
"0000" ;
-- trigger sequencer
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iSETRG_SFT <= "000" ;
elsif rising_edge(iMCLK) then
iSETRG_SFT <= iSETRG_SFT(1 downto 0) & iSETRG ;
end if ;
end process ;
iTRG_R <= '1' when ( iSETRG_SFT = "011" or iSETRG_SFT = "001" ) else '0' ;
iTRG_F <= '1' when ( iSETRG_SFT = "110" or iSETRG_SFT = "100" ) else '0' ;
-- parent sequencer
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iPSTATE <= "000" ;
elsif rising_edge(iMCLK) then
case conv_integer(iPSTATE) is
-- wait RFLAG rising edge
when 0 => if ( iTRG_R = '1' ) then
iPSTATE <= "001" ;
end if ;
-- send blind run trigger
when 1 => iPSTATE <= "011" ;
-- wait blind run flag
when 3 => if ( iBFLAG = '1' ) then
iPSTATE <= "111" ;
end if ;
-- send judge run trigger
when 7 => iPSTATE <= "110" ;
-- wait RFLAG falling edge
when 6 => if ( iTRG_F = '1' ) then
iPSTATE <= "100" ;
end if ;
-- return first state
when 4 => iPSTATE <= "000" ;
-- default
when others =>
iPSTATE <= "000" ;
end case ;
end if ;
end process ;
iBTRG <= '1' when ( iPSTATE = "001" ) else '0' ;
iJTRG <= '1' when ( iPSTATE = "111" ) else '0' ;
-- blind run sequencer
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iBSTATE <= 0 ;
iBCNT <= 0 ;
iBDUTY <= 0 ;
elsif rising_edge(iMCLK) then
case iBSTATE is
-- wait trigger
when 0 => if ( iBTRG = '1' ) then
iBSTATE <= 1 ;
end if ;
-- set duty ratio (5%)
when 1 => iBSTATE <= 2 ;
iBCNT <= 100000 ;
iBDUTY <= 5 ;
-- delay
when 2 => if ( iBCNT = 0 ) then
iBSTATE <= 3 ;
else
iBCNT <= iBCNT - 1 ;
end if ;
-- set duty ratio (15%)
when 3 => iBSTATE <= 4 ;
iBCNT <= 200000 ;
iBDUTY <= 15 ;
-- delay
when 4 => if ( iBCNT = 0 ) then
iBSTATE <= 5 ;
else
iBCNT <= iBCNT - 1 ;
end if ;
-- set duty ratio (30%)
when 5 => iBSTATE <= 6 ;
iBCNT <= 200000 ;
iBDUTY <= 30 ;
-- delay
when 6 => if ( iBCNT = 0 ) then
iBSTATE <= 7 ;
else
iBCNT <= iBCNT - 1 ;
end if ;
-- set duty ratio (50%)
when 7 => iBSTATE <= 0 ;
iBDUTY <= 50 ;
-- default
when others =>
iBSTATE <= 0 ;
end case ;
end if ;
end process ;
iBFLAG <= '1' when ( iBSTATE = 7 ) else '0' ;
-- judge run sequencer
process (nRESET,iMCLK)
begin
if ( nRESET = '0' ) then
iJSTATE <= "000" ;
iJRDUTY <= (others => '0') ; -- right duty
iJLDUTY <= (others => '0') ; -- left duty
iJRDUTYX <= 0 ; -- right duty
iJLDUTYX <= 0 ; -- left duty
iJCNT <= 0 ; -- delay counter
iMODE <= 0 ; -- NORMAL 0 / LANE_RIGHT 1 / LANE_LEFT 2 / CRANK 3
elsif rising_edge(iMCLK) then
if ( iJTRG = '1' ) then
case conv_integer(iJSTATE) is
-- get sensor data
when 0 => iJSTATE <= "001" ;
iSENSOR <= iJSENSOR ;
-- convert
when 1 => iJSTATE <= "011" ;
case conv_integer(iJOUT) is
-- all_black
when 0 => if ( iMODE = 2 ) then -- LANE_LEFT
iJRDUTYX <= 25 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
iJCNT <= 100000 ; -- 1000ms = 100000 x 10us
elsif ( iMODE = 1 ) then -- LANE_RIGHT
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 25 ; -- left duty
iJCNT <= 100000 ; -- 1000ms = 100000 x 10us
elsif ( iMODE = 3 ) then -- CRANK
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
else
iJRDUTYX <= 0 ; -- right duty
iJLDUTYX <= 0 ; -- left duty
end if ;
-- tiny_right
when 1 => if ( iMODE = 0 ) then -- NORMAL
iJRDUTYX <= 20 ; -- right duty
iJLDUTYX <= 27 ; -- left duty
iJCNT <= 25 ;
else
iJRDUTYX <= 20 ; -- right duty
iJLDUTYX <= 25 ; -- left duty
iJCNT <= 23 ;
end if ;
-- right
when 2 => if ( iMODE = 0 ) then -- NORMAL
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 25 ; -- left duty
iJCNT <= 20 ;
else
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 25 ; -- left duty
iJCNT <= 22 ;
end if ;
-- big_right
when 3 => if ( iMODE = 0 ) then -- NORMAL
iJRDUTYX <= 5 ; -- right duty
iJLDUTYX <= 30 ; -- left duty
iJCNT <= 15 ;
else
iJRDUTYX <= 5 ; -- right duty
iJLDUTYX <= 30 ; -- left duty
iJCNT <= 17 ;
end if ;
-- center
when 4 => if ( iMODE = 2 ) then -- LANE_LEFT
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 35 ; -- left duty
iJCNT <= 100000 ;
iMODE <= 0 ; -- change normal
elsif ( iMODE = 1 ) then -- LANE_RIGHT
iJRDUTYX <= 35 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
iJCNT <= 100000 ;
iMODE <= 0 ; -- change normal
elsif ( iMODE = 3 ) then -- CRANK
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
iJCNT <= 5 ;
else
iJRDUTYX <= 35 ; -- right duty
iJLDUTYX <= 35 ; -- left duty
iJCNT <= 10 ;
end if ;
-- tiny_left
when 5 => if ( iMODE = 0 ) then -- NORMAL
iJRDUTYX <= 25 ; -- right duty
iJLDUTYX <= 20 ; -- left duty
iJCNT <= 25 ;
else
iJRDUTYX <= 25 ; -- right duty
iJLDUTYX <= 20 ; -- left duty
iJCNT <= 27 ;
end if ;
-- left
when 6 => if ( iMODE = 0 ) then -- NORMAL
iJRDUTYX <= 25 ; -- right duty
iJLDUTYX <= 10 ; -- left duty
iJCNT <= 20 ;
else
iJRDUTYX <= 25 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
iJCNT <= 23 ;
end if ;
-- big_left
when 7 => if ( iMODE = 0 ) then -- NORMAL
iJRDUTYX <= 30 ; -- right duty
iJLDUTYX <= 5 ; -- left duty
iJCNT <= 15 ;
else
iJRDUTYX <= 30 ; -- right duty
iJLDUTYX <= 5 ; -- left duty
iJCNT <= 17 ;
end if ;
-- right_white
when 8 => if ( iMODE = 2 ) then -- LANE_LEFT
iJRDUTYX <= 5 ; -- right duty
iJLDUTYX <= 55 ; -- left duty
iJCNT <= 1000 ;
iMODE <= 0 ; -- change NORMAL
elsif ( iMODE = 1 ) then -- LANE_RIGHT
iJRDUTYX <= 55 ; -- right duty
iJLDUTYX <= 5 ; -- left duty
iJCNT <= 1000 ;
iMODE <= 0 ; -- change NORMAL
elsif ( iMODE = 3 ) then -- CRANK
iJRDUTYX <= 5 ; -- right duty
iJLDUTYX <= 55 ; -- left duty
iJCNT <= 45 ;
iMODE <= 0 ; -- change NORMAL
else
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
iJCNT <= 10000 ;
iMODE <= 1 ; -- change LANE (right)
end if ;
-- left_white
when 9 => if ( iMODE = 2 ) then -- LANE_LEFT
iJRDUTYX <= 55 ; -- right duty
iJLDUTYX <= 5 ; -- left duty
iJCNT <= 1000 ;
iMODE <= 0 ; -- change NORMAL
elsif ( iMODE = 1 ) then -- LANE_RIGHT
iJRDUTYX <= 5 ; -- right duty
iJLDUTYX <= 55 ; -- left duty
iJCNT <= 1000 ;
iMODE <= 0 ; -- change NORMAL
elsif ( iMODE = 3 ) then -- CRANK
iJRDUTYX <= 55 ; -- right duty
iJLDUTYX <= 5 ; -- left duty
iJCNT <= 45 ;
iMODE <= 0 ; -- change NORMAL
else
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
iJCNT <= 10000 ;
iMODE <= 2 ; -- change LANE (left)
end if ;
-- all_white
when 10 => if ( iMODE = 3 ) then -- CRANK
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
iJCNT <= 100 ;
elsif ( iMODE = 0 ) then -- NORMAL
iJRDUTYX <= 15 ; -- right duty
iJLDUTYX <= 15 ; -- left duty
iJCNT <= 10000 ;
iMODE <= 3 ; -- change CRANK
else -- LANE_LEFT / LANE_RIGHT
end if ;
when others => NULL ;
end case ;
-- latch
when 3 => iJSTATE <= "111" ;
iJRDUTY <= conv_std_logic_vector(iJRDUTYX,7) ; -- right duty
iJLDUTY <= conv_std_logic_vector(iJLDUTYX,7) ; -- left duty
-- delay
when 7 => if ( iJCNT = 0 ) then
iJSTATE <= "110" ;
else
iJCNT <= iJCNT - 1 ;
end if ;
-- dummy (auto skip)
when 6 => iJSTATE <= "100" ;
-- return first state
when 4 => iJSTATE <= "000" ;
-- default
when others =>
iJSTATE <= "000" ;
end case ;
else
iJRDUTY <= (others => '0') ; -- right duty
iJLDUTY <= (others => '0') ; -- left duty
end if ;
end if ;
end process ;
end behavioral;
ピンアサインは、以下です。
# system
NET "CLOCK" LOC = "P38" ;
NET "LED" LOC = "P92" ;
NET "nRESET" LOC = "P143" ;
# output group A (J6)
NET "RLED" LOC = "P87" ;
NET "GLED" LOC = "P88" ;
NET "TURN" LOC = "P85" ;
NET "SETRG" LOC = "P86" ;
NET "POUTL" LOC = "P83" ;
NET "POUTR" LOC = "P81" ;
# output group A (J4)
NET "SENSOR<7>" LOC = "P142" ;
NET "SENSOR<6>" LOC = "P140" ;
NET "SENSOR<5>" LOC = "P139" ;
NET "SENSOR<4>" LOC = "P138" ;
NET "SENSOR<3>" LOC = "P137" ;
NET "SENSOR<2>" LOC = "P136" ;
NET "SENSOR<1>" LOC = "P135" ;
NET "SENSOR<0>" LOC = "P134" ;
# output group B (J4)
NET "SOUT<7>" LOC = "P133" ;
NET "SOUT<6>" LOC = "P132" ;
NET "SOUT<5>" LOC = "P131" ;
NET "SOUT<4>" LOC = "P130" ;
NET "SOUT<3>" LOC = "P129" ;
NET "SOUT<2>" LOC = "P128" ;
NET "SOUT<1>" LOC = "P126" ;
NET "SOUT<0>" LOC = "P125" ;
# output group C (J4)
NET "STATUS<7>" LOC = "P124" ;
NET "STATUS<6>" LOC = "P121" ;
NET "STATUS<5>" LOC = "P120" ;
NET "STATUS<4>" LOC = "P119" ;
NET "STATUS<3>" LOC = "P118" ;
NET "STATUS<2>" LOC = "P117" ;
NET "STATUS<1>" LOC = "P116" ;
NET "STATUS<0>" LOC = "P115" ;
目次
前
次