目次

最終ハードウエア

 大会にもっていくハードウエアは、次の写真となりました。



 カメラとLED照光器を接続すると、次のようになります。



 スタートゲートセンサーは、超音波センサーを
 モータとモータの間に配置。



 運搬用ケースに入るよう、横幅は限界まで狭めてます。

 下回りは、3点支持にしています。



 支持部材のひとつは、100円ショップで入手した
 家具の滑り材を積層しています。

 FPGAに接続する回路は、手持ちの部品だけで構成して
 あります。どれも、部品屋に行って購入できる部品で
 まとめました。

 超音波センサー、モータドライバ、BarCodeScanner等の
 回路は、以下。



 Arduinoを載せた基板の回路は、以下。



 FPGA内部に入れたVHDLコードは、次の構成に。



 トップレベルにmcr2015があり、ここからcomponent記述で
 サブブロックを呼び出しています。

 VHDLコードをリストします。

 mcr2015

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity mcr2015 is
   port (
     -- system
     nRESET : in  std_logic ;
     CLOCK  : in  std_logic ; -- 11MHz
     -- sensor selector 
     GSEL   : in  std_logic ;
     -- 2 minutes
     XTRG  : in  std_logic ;
     XRES  : out std_logic ;
     -- ultrasonic sensor
     TRG   : out std_logic ;
     ECHO  : in  std_logic ;
     SGATE : out std_logic ;
     -- motor drive
     LEFTP  : out std_logic ;
     RIGHTP : out std_logic ;
     -- SPI interface
     XSCK   : in  std_logic ;
     XMOSI  : in  std_logic ;
     XMISO  : out std_logic ;
     nXSS   : in  std_logic ;
     -- Bar Code Scanner
     START  : in  std_logic ;
     DOS    : in  std_logic ;
     CLKA   : in  std_logic ;
     CLKB   : in  std_logic ;
     -- LED
     LOUT   : out std_logic_vector(7 downto 0) ;
     -- Game Boy Camera
     GBCIN  : in  std_logic_vector(3 downto 0) ;
     -- moving MODE
     MMODE  : out std_logic_vector(1 downto 0) ;
     -- Sensor data output (Arduino)
     SEL    : in  std_logic ; 
     SDAT   : out std_logic_vector(3 downto 0) ;
     -- run monitor
     RUNOUT : out std_logic --;
   );
end mcr2015 ;

architecture behavior of mcr2015 is
  --
  component usensor 
    port (
      -- system
      nRESET : in  std_logic ;
      CLOCK  : in  std_logic ; -- 11MHz
      -- sensor handler signal
      UTRG   : out std_logic ; -- TRG
      URES   : in  std_logic ; -- ECHO
      -- gate status (0:close 1:open)
      GSTATE : out std_logic --;
    );
  end component ;

  -- motor drive
  signal iLEFT   : std_logic_vector(6 downto 0) ;
  signal iRIGHT  : std_logic_vector(6 downto 0) ;

  component pout
    port (
      -- system
      nRESET : in  std_logic ;
      CLOCK  : in  std_logic ; -- 11MHz
      -- sensor handler signal
      LEFTV  : in std_logic_vector(6 downto 0) ;
      RIGHTV : in std_logic_vector(6 downto 0) ;
      -- pulse out
      LPOUT  : out std_logic ;
      RPOUT  : out std_logic --;
    );
  end component ;

  -- SPI interface
  component xspi is
    port (
      -- system
      nRESET : in  std_logic ;
      CLOCK  : in  std_logic ; -- 11MHz
      -- SPI
      SCK    : in  std_logic ;
      MISO   : out std_logic ;
      MOSI   : in  std_logic ;
      nSS    : in  std_logic ;
      -- moving mode
      MMODE  : out std_logic_vector(1 downto 0) ;
      -- pulse out
      LPVAL  : out std_logic_vector(6 downto 0) ;
      RPVAL  : out std_logic_vector(6 downto 0) --;
    );
  end component ;

  component bcs
    port (
      -- system
      nRESET : in  std_logic ;
      CLOCK  : in  std_logic ; -- 11MHz
      -- BCS
      SH     : in  std_logic ;
      CLKA   : in  std_logic ;
      CLKB   : in  std_logic ;
      DOS    : in  std_logic ;
      -- register output
      REGOUT : out std_logic_vector(7 downto 0) --;
    );
  end component ;

  -- time out
  component xtimcnt
    port (
      -- system
      nRESET : in  std_logic ;
      CLOCK  : in  std_logic ; -- 11MHz
      -- start trigger
      TRG    : in  std_logic ;
      -- response
      ROUT   : out std_logic --;
    );
  end component ;

  -- decoder
  component sdec
    port (
      -- input
      Din  : in  std_logic_vector(7 downto 0) ;
      -- decode
      Dout : out std_logic_vector(3 downto 0) --;
    );
  end component ;

  -- monitor
  component xrtim
    port (
      -- system
      nRESET : in  std_logic ;
      CLOCK  : in  std_logic ; -- 11MHz
      -- 2Hz clock
      LOUT : out std_logic --;
    );
  end component ;

  -- encoder
  component senc 
    port (
      -- input
      Din  : in  std_logic_vector(3 downto 0) ;
      -- output
      Dout : out std_logic_vector(7 downto 0) --;
    );
  end component ;

  CONSTANT CNTMAX  : integer := 109999 ;
  CONSTANT CNTHALF : integer :=  55000 ;

  signal iREGOUT : std_logic_vector(7 downto 0) ;
  signal iSREG   : std_logic_vector(7 downto 0) ;

  signal iBCS  : std_logic_vector(3 downto 0) ;
  signal iGBC  : std_logic_vector(3 downto 0) ;
  signal iGBCV : std_logic_vector(7 downto 0) ;

  signal iLOUT : std_logic_vector(7 downto 0) ;

  signal iCNT : integer range 0 to CNTMAX ;
  signal iCLK : std_logic ;

  signal iMMODE : std_logic_vector(1 downto 0) ;
begin
  -- output
  SDAT  <= iSREG(7 downto 4) when ( SEL = '1' ) else iSREG(3 downto 0) ;
  LOUT  <= not iLOUT ;
  MMODE <= iMMODE ;

  -- input
  iGBC <= GBCIN ;

  -- internal selector
  iLOUT <= iGBCV when ( GSEL = '1' ) else (not iREGOUT);

  -- clock divider
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge(CLOCK) then
      if ( iCNT = CNTMAX ) then
        iCNT <= 0 ;
      else
        iCNT <= iCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iCLK <= '1' when ( iCNT < CNTHALF ) else '0' ;

  -- data latch with 100Hz
  process (nRESET,iCLK)
  begin
    if ( nRESET = '0' ) then
      iSREG <= X"00" ;
    elsif rising_edge(iCLK) then
      iSREG <= iGBC & iBCS ;
    end if ;
  end process ;

  -- ultrasonic 
  USENSORInst : usensor 
    port map (
      -- system
      nRESET => nRESET ,
      CLOCK  => CLOCK  ,
      -- sensor handler signal
      UTRG   => TRG  ,
      URES   => ECHO ,
      -- gate status (1:close 0:open)
      GSTATE => SGATE 
    );

   -- pulse out
  PULSEOUTInst : pout
    port map (
      -- system
      nRESET => nRESET ,
      CLOCK  => CLOCK  ,
      -- sensor handler signal
      LEFTV  => iLEFT  ,
      RIGHTV => iRIGHT ,
      -- pulse out
      LPOUT  => LEFTP  ,
      RPOUT  => RIGHTP -- ;
    );

  -- SPI interface
  XSPIinst : xspi 
    port map (
      -- system
      nRESET => nRESET ,
      CLOCK  => CLOCK  ,
      -- SPI
      SCK    => XSCK   ,
      MISO   => XMISO  ,
      MOSI   => XMOSI  ,
      nSS    => nXSS   ,
      -- moving mode
      MMODE  => iMMODE ,
      -- pulse out
      LPVAL  => iLEFT  ,
      RPVAL  => iRIGHT -- ;
    );

  BCSInst : bcs
    port map (
      -- system
      nRESET => nRESET ,
      CLOCK  => CLOCK  ,
      -- BCS
      SH     => START ,
      CLKA   => CLKA  ,
      CLKB   => CLKB  ,
      DOS    => DOS   ,
      -- register output
      REGOUT => iREGOUT -- ;
    );

  XTIMInst : xtimcnt
    port map (
      -- system
      nRESET => nRESET ,
      CLOCK  => CLOCK  ,
      -- start trigger
      TRG    => XTRG   ,
      -- response
      ROUT   => XRES   -- ;
    );

  -- decoder
  SDECInst : sdec
    port map (
      -- input
      Din  => iREGOUT ,
      -- decode
      Dout => iBCS 
    );

  -- encoder
  SENCInst : senc 
    port map (
      -- input
      Din  => iGBC ,
      -- output
      Dout => iGBCV --;
    );

  XRTIMInst : xrtim
    port map (
      -- system
      nRESET => nRESET ,
      CLOCK  => CLOCK  ,
      -- 2Hz clock
      LOUT   => RUNOUT --;
    );

end behavior;

  エンティティで信号ピンを指定し、コンポーネントに
  信号を振り分けるだけにしています。

 usensor

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity usensor is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 11MHz
    -- sensor handler signal
    UTRG   : out std_logic ; -- TRG
    URES   : in  std_logic ; -- ECHO
    -- gate status (1:close 0:open)
    GSTATE : out std_logic --;
  );
end usensor ;

architecture behavioral of usensor is
  -- values
  CONSTANT SCNTMAX   : integer :=    10 ; -- 1us
  CONSTANT SCNTHALF  : integer :=     5 ;
  CONSTANT TRGMAX    : integer :=    11 ;
  CONSTANT CNTMAX    : integer := 99999 ; -- 100ms
  CONSTANT CNTLAST   : integer := 99000 ; --  99ms
  CONSTANT CNTTARGET : integer :=  2000 ; --   2ms => 340mm
  -- 1us generator (1MHz)
  signal iSCNT : integer range 0 to SCNTMAX ;
  signal iSCLK : std_logic  ;
  -- 100ms counter
  signal iCNT : integer range 0 to CNTMAX ;
  -- trigger
  signal iUTRG : std_logic ;
  -- echo
  signal iURES_SFT : std_logic_vector(2 downto 0) ;
  signal iURES_HL  : std_logic ;
  signal iURES_LH  : std_logic ;
  -- detector
  signal iBEGINX : integer range 0 to CNTMAX ;
  signal iFINEX  : integer range 0 to CNTMAX ;
  -- sequencer
  signal iSTATE  : std_logic_vector(1 downto 0) ;
  signal iBEGIN  : integer range 0 to CNTMAX ;
  signal iFINE   : integer range 0 to CNTMAX ;
  signal iDIFF   : integer range 0 to CNTMAX ;
  signal iGSTATE : std_logic ; 
begin
  -- output
  UTRG   <= iUTRG ;
  GSTATE <= iGSTATE ;

  -- generate 1MHz (1us)
  process (CLOCK)
  begin
    if rising_edge(CLOCK) then
      if ( iSCNT = SCNTMAX ) then
        iSCNT <= 0 ;
      else
        iSCNT <= iSCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iSCLK <= '1' when ( iSCNT < SCNTHALF ) else '0' ;

  -- 100ms counter
  process (nRESET,iSCLK)
  begin
    if ( nRESET = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge(iSCLK) then
      if ( iCNT = CNTMAX ) then
        iCNT <= 0 ;
      else
        iCNT <= iCNT + 1 ;
      end if ;
    end if ;
  end process ;

  -- generate TRIGGER (10us)
  iUTRG <= '1' when ( iCNT < TRGMAX ) else '0' ;

  -- synchronizer
  process (nRESET,iSCLK)
  begin
    if ( nRESET = '0' ) then
      iURES_SFT <= "000" ;
    elsif rising_edge(iSCLK) then
      iURES_SFT <= iURES_SFT(1 downto 0) & URES ;
    end if ;
  end process ;
  iURES_LH <= '1' when ( iURES_SFT = "011" ) else '0' ;
  iURES_HL <= '1' when ( iURES_SFT = "110" ) else '0' ;

  -- detector
  process (iSCLK)
  begin
    if rising_edge(iSCLK) then
      -- clear
      if ( iCNT = CNTMAX ) then
        iBEGINX <= 0 ;
        iFINEX  <= 0 ;
      end if ;
      -- measure (L -> H)
      if ( iURES_LH = '1' ) then
        iBEGINX <= iCNT ;
      end if ;
      -- measure (H -> L)
      if ( iURES_HL = '1' ) then
        iFINEX  <= iCNT ;
      end if ;
    end if ;
  end process ;

  -- sequencer
  process (nRESET,iSCLK)
  begin
    if ( nRESET = '0' ) then
      iSTATE  <= "00" ;
      iDIFF   <= 0 ;
      iBEGIN  <= 0 ;
      iFINE   <= 0 ;
    elsif falling_edge(iSCLK) then
      case conv_integer(iSTATE) is
        -- clear counter
        when 0 => if ( iCNT = CNTLAST ) then
                    iSTATE <= "01" ;
                    iDIFF  <= 0 ;
                  else
                    iSTATE <= "00" ;
                  end if ;
        -- copy
        when 1 => iSTATE <= "11" ;
                  iBEGIN <= iBEGINX ;
                  iFINE  <= iFINEX  ;
        -- calculate
        when 3 => iSTATE <= "10" ;
                  if iFINE > iBEGIN then
                    iDIFF  <= (iFINE - iBEGIN) ;
                  end if ;
        -- return first state
        when 2 => iSTATE <= "00" ;
        -- default
        when others => 
                  iSTATE <= "00" ;
      end case ;
    end if ;
  end process ;
  iGSTATE <= '1' when ( iDIFF < CNTTARGET ) else '0' ;

end behavioral;

  100msごとにTRGを出力し、ECHOのrising_edge、falling_edgeを
  捉えて、時間差を求めています。

 pout

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity pout is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 11MHz
    -- sensor handler
    LEFTV  : in std_logic_vector(6 downto 0) ;
    RIGHTV : in std_logic_vector(6 downto 0) ;
    -- pulse out
    LPOUT  : out std_logic ;
    RPOUT  : out std_logic --;
  );
end pout ;

architecture behavioral of pout is
  --
  CONSTANT CNTMAX  : integer := 2749 ;
  CONSTANT CNTHALF : integer := 1375 ;
  CONSTANT PCNTMAX : integer :=   99 ;
  -- counter
  signal iPCNT   : integer range 0 to 99 ;
  signal iLEFTX  : integer range 0 to 99 ;
  signal iRIGHTX : integer range 0 to 99 ;
  -- clock divider
  signal iCNT  : integer range 0 to CNTMAX ;
  signal iPCLK : std_logic ;
begin
  -- output
  LPOUT <= '1' when ( iPCNT < iLEFTX  ) else '0' ;
  RPOUT <= '1' when ( iPCNT < iRIGHTX ) else '0' ;

  -- clock divider (generate 4kHz)
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge(CLOCK) then
      if ( iCNT = CNTMAX ) then
        iCNT <= 0 ;
      else
        iCNT <= iCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iPCLK <= '1' when ( iCNT < CNTHALF ) else '0' ;

  -- counter
  process (nRESET,iPCLK)
  begin
    if ( nRESET = '0' ) then
      iPCNT   <= 0 ;
      iLEFTX  <= 0 ;
      iRIGHTX <= 0 ;
    elsif rising_edge(iPCLK) then
      if ( iPCNT = PCNTMAX ) then
        iPCNT   <= 0 ;
        iLEFTX  <= conv_integer(LEFTV) ;
        iRIGHTX <= conv_integer(RIGHTV) ;
      else
        iPCNT <= iPCNT + 1 ;
      end if ;
    end if ;
  end process ;

end behavioral;

  左右のDUTY比を更新しながら、PWM波形を出力しています。

 bcs

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity bcs is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 11MHz
    -- BCS
    SH     : in  std_logic ;
    CLKA   : in  std_logic ;
    CLKB   : in  std_logic ;
    DOS    : in  std_logic ;
    -- monitor
    MLOUT  : out std_logic_vector(7 downto 0) ;
    -- register output
    REGOUT : out std_logic_vector(7 downto 0) --;
  );
end bcs ;

architecture behavioral of bcs is
  -- counters
  CONSTANT CNTLAST   : integer := 2048 ;
  CONSTANT CNTUPDATE : integer := 2080 ;
  -- latch location
  --   begin 128 displacement 256 1byte offset 32
  --   32 + N * 256 + 128 (N=0,1,2,3,4,5,6,7)
  --   N * 256 + 160 (N=0,1,2,3,4,5,6,7)  
--  CONSTANT SCNTLATCH0 : integer :=  160 ;
--  CONSTANT SCNTLATCH1 : integer :=  416 ;
--  CONSTANT SCNTLATCH2 : integer :=  672 ;
--  CONSTANT SCNTLATCH3 : integer :=  928 ;
--  CONSTANT SCNTLATCH4 : integer := 1184 ;
--  CONSTANT SCNTLATCH5 : integer := 1440 ;
--  CONSTANT SCNTLATCH6 : integer := 1696 ;
--  CONSTANT SCNTLATCH7 : integer := 1952 ;
--
--  i = range(4)
--  x = 1026
--  y = 1022
--  for e in i :
--    j = (e << 8)
--    print (x+j) , (y-j)
  CONSTANT SCNTLATCH0 : integer :=  254 ;
  CONSTANT SCNTLATCH1 : integer :=  510 ;
  CONSTANT SCNTLATCH2 : integer :=  766 ;
  CONSTANT SCNTLATCH3 : integer := 1022 ;
  CONSTANT SCNTLATCH4 : integer := 1026 ;
  CONSTANT SCNTLATCH5 : integer := 1282 ;
  CONSTANT SCNTLATCH6 : integer := 1538 ;
  CONSTANT SCNTLATCH7 : integer := 1794 ;
  --
  CONSTANT GCNTMAX  : integer := 19 ;
  CONSTANT GCNTHALF : integer := 10 ;
  -- BCS interface
  signal iSH  : std_logic ;
  signal iDOS : std_logic ;
  -- synchronizer
  signal iSFT   : std_logic_vector(2 downto 0) ;
  signal iCLKA  : std_logic ;
  signal iCLKB  : std_logic ;
  signal iGCNT  : integer range 0 to GCNTMAX ;
  signal iCLKAB : std_logic ;
  -- internal counter
  signal iCNT  : std_logic_vector(11 downto 0) ;
  -- latch
  signal iPREG : std_logic_vector(7 downto 0) ;
  signal iREG  : std_logic_vector(7 downto 0) ;
  signal iREGX : std_logic_vector(7 downto 0) ;
begin
  -- input
  iSH  <= SH ;
  iDOS <= not DOS ;

  -- output
  REGOUT <= iREG ;
  MLOUT  <= not iREG ;

  -- synchronizer
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSFT <= "000" ;
    elsif rising_edge(CLOCK) then
      iSFT <= iSFT(1 downto 0) & CLKA ;
    end if ;
  end process ;
  iCLKA <= '1' when ( iSFT = "011" and CLKB = '0' ) else '0' ;
  iCLKB <= '1' when ( iSFT = "100" and CLKB = '1' ) else '0' ;

  -- generate clock
  process (CLOCK)
  begin
    if rising_edge(CLOCK) then
      if ( iCLKA = '1' or iCLKB = '1' ) then
        iGCNT <= 0 ;
      else
        iGCNT <= iGCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iCLKAB <= '1' when ( 0 < iGCNT and iGCNT < GCNTHALF ) else '0' ;

  -- internal counter
  process (iCLKAB)
  begin
    if rising_edge(iCLKAB) then
      if ( iSH = '1' ) then
        iCNT <= (others => '0') ;
      else
        iCNT <= iCNT + '1' ;
      end if ;
    end if ;
  end process ;

  -- latch and shift 
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iPREG <= X"00" ;
      iREG  <= X"00" ;
      iREGX <= X"00" ;
    elsif rising_edge(CLOCK) then
      -- latch
      case conv_integer(iCNT) is
        -- MSB
        when SCNTLATCH0 => iREGX(7) <= iDOS ;
        -- 2^6
        when SCNTLATCH1 => iREGX(6) <= iDOS ;
        -- 2^5
        when SCNTLATCH2 => iREGX(5) <= iDOS ;
        -- 2^4
        when SCNTLATCH3 => iREGX(4) <= iDOS ;
        -- 2^3
        when SCNTLATCH4 => iREGX(3) <= iDOS ;
        -- 2^2
        when SCNTLATCH5 => iREGX(2) <= iDOS ;
        -- 2^1
        when SCNTLATCH6 => iREGX(1) <= iDOS ;
        -- LSB
        when SCNTLATCH7 => iREGX(0) <= iDOS ;
        -- copy
        when CNTLAST    => iPREG <= iREGX ;
        -- update
        when CNTUPDATE  => if ( iPREG /= iREG ) then
                            iREG <= iPREG ;
                          end if ; 
        -- default
        when others     => NULL ;
      end case ;
    end if ;
  end process ;

end behavioral;

  BarCodeScannerが出力してくるビット列から
  8ビットセンサーデータを生成します。

  Arduinoがより使いやすいように、8ビットデータを
  4ビット程度の数値に変換しますが、デコード処理
  は、別コンポーネントで定義します。

  BCSでは、次のタイミングチャートを使ってデータ
  を確実にサンプリングできるようにしました。



  CLKAとCLKBで、カウンタをインクリメントし2080で
  動作を終了しますが、偶数ピクセルだけを取出して
  処理しても問題がないので、CLKAだけを利用します。



    CLKA、CLKBで0から2080までカウントします。CLOCKで、CLKA
    CLKBがH状態で有効データが出ているときに、データを取得
    するタイミングを決めます。

  マシン走行に必要なのは8ビットなので、シフトレジスタを
  利用し、2048ピクセル中の8ピクセルを抜き出します。

  出力されるピクセル情報を確実に記憶するためCLKAの
  rising_edgeから、ずれた位置でデータ取得します。




  RSをピクセル情報の記憶に使えるか否かを実験しないと
  判断できなかったので、CLKAのrising_edgeでカウンタを
  動かし、指定カウント値になったらピクセル情報を取得
  するカラクリにしました。



  CLKA、CLKBのrising_edgeでカウンタをリセットし、カウンタが
  指定値になったときに、トリガーを出力します。

  エッジから指定時間経過後、トリガーを出力します。

  カウンタを利用すると、狙った時点で確実にトリガーを
  出力できます。また、エッジからの時間値を異なるよう
  にも、構成できます。

 xspi

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity xspi is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 11MHz
    -- SPI
    SCK    : in  std_logic ;
    MISO   : out std_logic ;
    MOSI   : in  std_logic ;
    nSS    : in  std_logic ;
    -- moving mode
    MMODE  : out std_logic_vector(1 downto 0) ;
    -- pulse out
    LPVAL  : out std_logic_vector(6 downto 0) ;
    RPVAL  : out std_logic_vector(6 downto 0) --;
  );
end xspi ;

architecture behavioral of xspi is
  -- internal registers
  signal iLEFT  : std_logic_vector(6 downto 0) ;
  signal iRIGHT : std_logic_vector(6 downto 0) ;
  -- SPI interface
  signal iSS   : std_logic ;
  signal iREG  : std_logic_vector(7 downto 0) ;
  signal iMOSI : std_logic ;
  -- moving mode register
  signal iMMODE : std_logic_vector(1 downto 0) ;
  -- synchronizer
  signal iTRG     : std_logic ;
  signal iTRG_SFT : std_logic_vector(2 downto 0) ;
  -- sequencer
  signal iSTATE : std_logic_vector(1 downto 0) ;
  signal iREGX  : std_logic_vector(7 downto 0) ;

begin
  -- input
  iSS   <= nSS ;
  iMOSI <= MOSI ;

  -- output
  LPVAL <= iLEFT  ;
  RPVAL <= iRIGHT ;
  MISO  <= iREG(7) ;
  MMODE <= iMMODE ;

  -- latch
  process (nRESET,SCK)
  begin
    if ( nRESET = '0' ) then
      iREG <= X"00" ;
    elsif rising_edge(SCK) then
      if ( iSS = '0' ) then
        iREG <= iREG(6 downto 0) & iMOSI ;
      end if ;
    end if ;
  end process ;

  -- synchronizer
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iTRG_SFT <= "000" ;
    elsif rising_edge(CLOCK) then
      iTRG_SFT <= iTRG_SFT(1 downto 0) & iSS ;
    end if ;
  end process ;
  iTRG  <= '1' when ( iTRG_SFT = "011" ) else '0' ;

  -- sequencer
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSTATE <= "00" ;
      iREGX  <= X"00" ;
      iLEFT  <= "0000000" ;
      iRIGHT <= "0000000" ;
      iMMODE <= "00" ;
    elsif rising_edge(CLOCK) then
      case conv_integer(iSTATE) is
        -- wait trigger
        when 0 => if ( iTRG = '1' ) then
                    iSTATE <= "01" ;
                  else
                    iSTATE <= "00" ;
                  end if ;
        -- copy
        when 1 => iSTATE <= "11" ;
                  iREGX  <= iREG ;
        -- distribute
        when 3 => iSTATE <= "10" ;
                  -- LEFT upper nibble
                  if ( iREGX(7 downto 4) = X"3" ) then
                    iLEFT(6 downto 4) <= iREGX(2 downto 0) ;
                  end if ;
                  -- LEFT lower nibble 
                  if ( iREGX(7 downto 4) = X"2" ) then
                    iLEFT(3 downto 0) <= iREGX(3 downto 0) ;
                  end if ;
                  -- RIGHT upper nibble
                  if ( iREGX(7 downto 4) = X"1" ) then
                    iRIGHT(6 downto 4) <= iREGX(2 downto 0) ;
                  end if ;
                  -- RIGHT lower nibble
                  if ( iREGX(7 downto 4) = X"0" ) then
                    iRIGHT(3 downto 0) <= iREGX(3 downto 0) ;
                  end if ;
                  -- moving mode
                  if ( iREGX(7 downto 4) = X"F" ) then
                    iMMODE <= iREGX(1 downto 0) ;
                  end if ;
        -- return first state
        when 2 => iSTATE <= "00" ;
        -- default
        when others =>
                  iSTATE <= "00" ;
      end case ;
    end if ;
  end process ;

end behavioral;

  ArduinoからSPIインタフェースで転送されるDUTY比を
  受取ります。内部レジスタの左右のDUTY比を格納する
  までを担当し、そのDUTY比を利用するのは、別回路に
  しました。FPGA内部では、次のタイミングチャートで
  示すように、シフトレジスタに1バイトを入れた後に
  指定レジスタにラッチさせるだけにしました。



  他の回路に与えるパラメータも指定したかったので
  DUTY比は、1バイトの上位4ビットを0から3で指定し
  右DUTY下位、右DUTY上位、左DUTY下位、左DUTY上位と
  4回転送する仕様に。また、現在どのモードで走行中
  かがわかるように、接続したモニタLEDへのパラメータ
  は、上位4ビットをすべて1に指定します。

 xtimcnt

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity xtimcnt is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 11MHz
    -- start trigger
    TRG    : in  std_logic ;
    -- response
    ROUT   : out std_logic --;
  );
end xtimcnt ;

architecture behavioral of xtimcnt is
  -- 
  CONSTANT CNTMAX : integer := 1_319_999_999 ;
  CONSTANT CNTSTA : integer := 1_310_000_000 ;
  -- synchronizer
  signal iSFT : std_logic_vector(2 downto 0) ;
  signal iTRG : std_logic ;
  -- sequencer
  signal iSTATE : std_logic_vector(1 downto 0) ;
  signal iENAX  : std_logic ;
  -- counter
  signal iCNT : integer range 0 to CNTMAX ;
begin
  -- output
  ROUT <= '1' when ( iCNT > CNTSTA ) else '0' ;

  -- synchronizer 
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSFT <= "000" ;
    elsif rising_edge(CLOCK) then
      iSFT <= iSFT(1 downto 0) & TRG ;
    end if ;
  end process ;
  iTRG <= '1' when ( iSFT = "011" ) else '0' ;

  -- sequencer
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSTATE <= "00" ;
    elsif rising_edge(CLOCK) then
      case conv_integer(iSTATE) is
        -- wait trigger
        when 0 => if ( iTRG = '1' ) then
                    iSTATE <= "01" ;
                  else
                    iSTATE <= "00" ;
                  end if ;
        -- enable counter
        when 1 => iSTATE <= "11" ;
        -- judge count up
        when 3 => if ( iCNT = CNTMAX-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 ;
  iENAX <= '1' when ( iSTATE(0) = '1' ) else '0' ;

  -- counter
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge(CLOCK) then
      if ( iENAX = '1' ) then
        iCNT <= iCNT + 1 ;
      else
        iCNT <= 0 ;
      end if ;
    end if ;
  end process ;

end behavioral;

  Arduinoからトリガーをもらい、120秒経過後
  パルスを出力します。内部カウンタを動かし
  指定値になったなら、出力信号をON、OFFする
  だけの簡単な処理にしました。



 xrtim

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity xrtim is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 11MHz
    -- 2Hz clock
    LOUT : out std_logic --;
  );
end xrtim ;

architecture behavioral of xrtim is
  -- counters
  CONSTANT CNTMAX   : integer := 10999 ;
  CONSTANT CNTHALF  : integer :=  5500 ;
  CONSTANT SCNTMAX  : integer :=   499 ;
  CONSTANT SCNTQUAD : integer :=   100 ;
  -- internal counter
  signal iCNT  : integer range 0 to CNTMAX ;
  signal iSCLK : std_logic ;
  -- generate monitor clock
  signal iSCNT : integer range 0 to SCNTMAX ;
  signal iLOUT : std_logic ;
begin
  -- output
  LOUT <= not iLOUT ;

  -- generate 1kHz
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iCNT <= 0 ;
    elsif rising_edge(CLOCK) then
      if ( iCNT = CNTMAX ) then
        iCNT <= 0 ;
      else
        iCNT <= iCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iSCLK <= '1' when ( iCNT < CNTHALF ) else '0' ;

  -- generate 2Hz
  process (nRESET,iSCLK)
  begin
    if ( nRESET = '0' ) then
      iSCNT <= 0 ;
    elsif rising_edge(iSCLK) then
      if ( iSCNT = SCNTMAX ) then
        iSCNT <= 0 ;
      else
        iSCNT <= iSCNT + 1 ;
      end if ;
    end if ;
  end process ;
  iLOUT <= '1' when ( iSCNT < SCNTQUAD ) else '0' ;

end behavioral;

  11MHzから2Hzのクロックを生成し、LEDを点滅します。

  FPGA動作中を示すindicatorに使います。

 sdec
  BarCodeScannerが出力する8ビットデータを、より扱い
  易い数値に変換します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity sdec is
  port (
    -- input
    Din  : in  std_logic_vector(7 downto 0) ;
    -- decode
    Dout : out std_logic_vector(3 downto 0) --;
  );
end sdec ;

architecture behavioral of sdec is
  --
  CONSTANT ALL_BLACK   : integer :=  0 ;
  CONSTANT ALL_WHITE   : integer :=  1 ;
  CONSTANT LEFT_WHITE  : integer :=  2 ;
  CONSTANT RIGHT_WHITE : integer :=  3 ;
  CONSTANT CENTER      : integer :=  4 ;
  CONSTANT BIG_RIGHT   : integer :=  5 ;
  CONSTANT RIGHTX      : integer :=  6 ;
  CONSTANT TINY_RIGHT  : integer :=  7 ;
  CONSTANT TINY_LEFT   : integer :=  8 ;
  CONSTANT LEFTX       : integer :=  9 ;
  CONSTANT BIG_LEFT    : integer := 10 ;
  CONSTANT BOTH_WHITE  : integer := 11 ;
  CONSTANT ILLEAGAL    : integer := 12 ;
  -- decode
  signal iDEC  : integer range 0 to 255 ;
  signal iDout : std_logic_vector(3 downto 0) ;
  signal iDin  : std_logic_vector(7 downto 0) ;

begin
  -- output
  Dout <= conv_std_logic_vector(iDEC,4) ;

  -- input
  iDin <= Din ;

  -- decode
  iDEC <= ALL_BLACK   when ( iDin = X"00" ) else
          ALL_WHITE   when ( iDin = X"ff" ) else
          LEFT_WHITE  when ( iDin = X"f0" ) else
          LEFT_WHITE  when ( iDin = X"f8" ) else
          RIGHT_WHITE when ( iDin = X"0f" ) else
          RIGHT_WHITE when ( iDin = X"1f" ) else
          CENTER      when ( iDin = X"18" ) else
          CENTER      when ( iDin = X"1c" ) else
          CENTER      when ( iDin = X"38" ) else
          BIG_RIGHT   when ( iDin = X"03" ) else
          RIGHTX      when ( iDin = X"06" ) else
          TINY_RIGHT  when ( iDin = X"0c" ) else
          TINY_LEFT   when ( iDin = X"30" ) else
          LEFTX       when ( iDin = X"60" ) else
          BIG_LEFT    when ( iDin = X"c0" ) else
          BOTH_WHITE  when ( iDin = X"c3" ) else
          BOTH_WHITE  when ( iDin = X"c1" ) else
          BOTH_WHITE  when ( iDin = X"83" ) else
          BOTH_WHITE  when ( iDin = X"81" ) else
          ILLEAGAL ;

end behavioral;

  Arduinoは、4ビットデータを取得するので、BCSか
  GBCのどちからから入力するのかSELで決めます。

 ピンアサインは、以下としました。

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 "55"  ;
LOCATE COMP "RUNOUT" SITE "42"  ;

# time out XRES -> PD2
LOCATE COMP "XTRG" SITE "48" ;
LOCATE COMP "XRES" SITE "50" ;

# sensor 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" ;

# ultrasonic sensor
LOCATE COMP "TRG"   SITE "142" ;
LOCATE COMP "ECHO"  SITE "143" ;

# start gate status
LOCATE COMP "SGATE" SITE "67"  ;

# Bar Code Scanner
LOCATE COMP "START"   SITE "121" ;
LOCATE COMP "DOS"     SITE "127" ;
LOCATE COMP "CLKA"    SITE "122" ;
LOCATE COMP "CLKB"    SITE "128" ;

# Game Boy Camerra
LOCATE COMP "GBCIN[0]" SITE "132" ;
LOCATE COMP "GBCIN[1]" SITE "133" ;
LOCATE COMP "GBCIN[2]" SITE "138" ;
LOCATE COMP "GBCIN[3]" SITE "139" ;

# Sensor data output (Arduino)
LOCATE COMP "SEL"     SITE "65" ;
LOCATE COMP "SDAT[0]" SITE "58" ;
LOCATE COMP "SDAT[1]" SITE "60" ;
LOCATE COMP "SDAT[2]" SITE "61" ;
LOCATE COMP "SDAT[3]" SITE "62" ;

# motor drive
LOCATE COMP "LEFTP"  SITE "111" ;
LOCATE COMP "RIGHTP" SITE "112" ;

# motor drive (Arduino)
LOCATE COMP "XSCK"   SITE "71" ;
LOCATE COMP "XMISO"  SITE "70" ;
LOCATE COMP "XMOSI"  SITE "69" ;
LOCATE COMP "nXSS"   SITE "68" ;

# moving mode
LOCATE COMP "MMODE[0]" SITE "57" ;
LOCATE COMP "MMODE[1]" SITE "59" ;


インタフェース  BarCodeScanner、超音波センサー、GameBoyCamera、は  ケーブルを使い基板と接続します。  BarCodeScanner   5年近く使っているので、表面実装の抵抗が破損しました。   バッファを入れてマイコンの出力信号を強化します。   バッファを別基板に入れて、BarCodeScannerの   上に貼り付けられるようにしました。   マイコン基板と反対側に、両面テープで貼り付けられます。  超音波センサー 超音波センサーは、4ピンのコネクタをつけ   フラットケーブルで、基板に接続します。  GameBoyCamera   GameBoyCameraは、画像情報をアナログ電圧で出力   してくるので、スマートセンサーとして扱える様   Arduinoで制御します。
PLD内部ブロック  FPGAは、並列に動作する回路で構成しました。  FPGA内部に用意したレジスタを使っているブロック  もあるので、マイコンと外部回路の信号処理と変換  がわかる図面を描いておきます。  モータ回転処理   モータを回転させるには、マイコンからSPIインタフェースで   受取ったDUTY比を内部レジスタに保存し、PWM波形生成回路が   定期的に読み出して、波形を出力します。  センサー情報変換   GBCは、スマートセンサーになっているので、送られた   情報をそのまま出力し、BCSの方は信号処理後に出力と   しました。  
目次

inserted by FC2 system