目次

シングル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" ;


目次

inserted by FC2 system