目次
前
次
最終ハードウエア
大会にもっていくハードウエアは、次の写真となりました。
カメラと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の方は信号処理後に出力と
しました。
目次
前
次