目次

インタフェース構成

 マイクロコンピュータとFPGAを接続し、必要な
 処理をFPGAの中に作りこんだデジタル回路で
 処理します。



 マイクロコンピュータには、Arduinoを使います。
 FPGAを接続する場合、汎用シリアルインタフェースを
 採用する方が楽です。

 Arduinoで使える汎用シリアルインタフェースには
 IIC、SPI、Firmataがあります。

 IICは、2ピンで処理できますが、データ線を
 入力と出力の入替えが必要になるので、FPGAの
 VHDLコードを記述するのが面倒。
 SPIでArduinoとFPGAを接続します。

 Arduinoは、SPIのマスターで利用し、DCモータの
 DUTY比を転送します。1バイト構成は、以下。



 DUTY比は0から99で、7ビットでまとめられること
 から、1バイト中のMSB(最上位ビット)を、チャネル
 指定に利用します。0で右、1で左とします。

 センサーデータは8ビットとし、ニブルで2回
 入力します。
 Arduinoは、利用できるピン数が少ないのでニブル
 で扱います。

 BarCodeScanner処理は、FPGA内部のデジタル回路に
 一任し、Arduinoはセンサーデータを使うことに専念
 します。

 スタートゲートの開閉で、動作を開始するので
 超音波センサーを利用します。

 ゲートの開閉状態を、論理値でFPGAから出力して
 マイコンが使えるようにします。


センサーデータ処理

 Arduinoからみてセンサーデータは8ビットですが  ピン数制約から、ニブルで2回入力します。  ArduinoのポートCを使います。  ポートCはアナログで使うのが基本ですが、今回は  デジタルで利用します。  信号割当ては、次のようにします。  センサーデータを入力する関数を定義します。 #define SEL_BIT 4 byte get_sensor(void) { byte result ; byte dh ; byte dl ; /* defalt */ result = 0 ; /* get upper nibble */ PORTC |= (1 << SEL_BIT); dh = PINC & 15 ; dh <<= 4 ; /* get lower nibble */ PORTC &= ~(1 << SEL_BIT); dl = PINC & 15 ; /* concatenate */ result = dh | dl ; return result ; }  ポートCの初期化は、以下。 PORTC = 0xff ; DDRC = 0x10 ;  BCSとFPGAのインタフェースでは、CLKAとCLKBを  論理和でまとめて、入力します。  VHDLコードは、以下。 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 START : in std_logic ; CLKAB : in std_logic ; DOS : in std_logic ; -- monitor MLOUT : out std_logic_vector(7 downto 0) ; -- selector SEL : in std_logic ; -- register output REGOUT : out std_logic_vector(3 downto 0) --; ); end bcs ; architecture behavioral of bcs is -- values CONSTANT SCNTMAX : integer := 2081 ; CONSTANT SCNTXMAX : integer := 2048 ; CONSTANT SCNTFINE : integer := 2080 ; CONSTANT SCNTFIRST : integer := 33 ; -- latch location CONSTANT SCNTLATCH0 : integer := 128 ; CONSTANT SCNTLATCH1 : integer := 384 ; CONSTANT SCNTLATCH2 : integer := 640 ; CONSTANT SCNTLATCH3 : integer := 896 ; CONSTANT SCNTLATCH4 : integer := 1152 ; CONSTANT SCNTLATCH5 : integer := 1408 ; CONSTANT SCNTLATCH6 : integer := 1664 ; CONSTANT SCNTLATCH7 : integer := 1920 ; -- BUS interface signal iSTART : std_logic ; signal iDOS : std_logic ; -- internal counter signal iSCNT : integer range 0 to SCNTMAX ; signal iSCNTX : integer range 0 to SCNTXMAX ; signal iSTRG : std_logic ; -- synchronizer signal iSTART_SFT : std_logic_vector(2 downto 0) ; signal iSTART_TRG : std_logic ; signal iCLKAB_SFT : std_logic_vector(2 downto 0) ; signal iCLKAB_TRG : std_logic ; -- internal shift register signal iREG_SFT : std_logic_vector(7 downto 0) ; -- internal register signal iSEL : std_logic ; signal iREG : std_logic_vector(7 downto 0) ; -- sequencer signal iSTATE : integer range 0 to 3 ; begin -- input iSTART <= START ; iDOS <= DOS ; iSEL <= SEL ; -- output REGOUT <= iREG(7 downto 4) when ( iSEL = '1' ) else iREG(3 downto 0) ; MLOUT <= not iREG ; -- internal counter process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSCNT <= 0 ; iSCNTX <= 0 ; elsif rising_edge(CLOCK) then if ( iCLKAB_TRG = '1' ) then -- total counter if ( iSTART = '1' or iSCNT = SCNTMAX ) then iSCNT <= 0 ; else iSCNT <= iSCNT + 1 ; end if ; -- sensing counter if ( iSTART = '1' or iSCNT < SCNTFIRST ) then iSCNTX <= 0 ; else iSCNTX <= iSCNTX + 1 ; end if ; end if ; end if ; end process ; iSTRG <= '1' when ( iSCNTX = SCNTLATCH0 ) else '1' when ( iSCNTX = SCNTLATCH1 ) else '1' when ( iSCNTX = SCNTLATCH2 ) else '1' when ( iSCNTX = SCNTLATCH3 ) else '1' when ( iSCNTX = SCNTLATCH4 ) else '1' when ( iSCNTX = SCNTLATCH5 ) else '1' when ( iSCNTX = SCNTLATCH6 ) else '1' when ( iSCNTX = SCNTLATCH7 ) else '0' ; -- synchronizer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTART_SFT <= "000" ; iCLKAB_SFT <= "000" ; elsif rising_edge(CLOCK) then iSTART_SFT <= iSTART_SFT(1 downto 0) & iSTART ; iCLKAB_SFT <= iCLKAB_SFT(1 downto 0) & CLKAB ; end if ; end process ; iSTART_TRG <= '1' when ( iSTART_SFT = "011" ) else '0' ; iCLKAB_TRG <= '1' when ( iCLKAB_SFT = "011" ) else '0' ; -- internal register process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iREG_SFT <= X"00" ; elsif rising_edge(CLOCK) then if ( iSTRG = '1' ) then iREG_SFT <= iREG_SFT(6 downto 0) & iDOS ; end if ; end if ; end process ; -- sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= 0 ; iREG <= X"00" ; elsif rising_edge(CLOCK) then case iSTATE is -- wait trigger when 0 => if ( iSTART_TRG = '1' ) then iSTATE <= 1 ; else iSTATE <= 0 ; end if ; -- complete data store when 1 => if ( iSCNT = SCNTFINE ) then iSTATE <= 3 ; else iSTATE <= 1 ; end if ; -- copy when 3 => iSTATE <= 2 ; iREG <= iREG_SFT ; -- return first state when 2 => iSTATE <= 0 ; -- default when others => iSTATE <= 0 ; end case ; end if ; end process ; end behavioral;  FPGAには、Lattice SemiconductorのMachXO2を利用します。

スタートゲート処理

 スタートゲートの開閉状態は、超音波センサーで  取得します。  FPGAが1ビットで状態値を出力するとして  Arudinoで利用する関数を定義します。 #define OPENED 0 #define CLOSED 1 #define START_BIT 5 byte get_start_status(void) { byte result ; /* defalt */ result = OPENED ; /* judge */ if ( PIND & (1 << START_BIT) ) { result = CLOSED ; } return result ; }  FPGA内に格納する回路のVHDLコードは、以下。 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 (0:close 1:open) GSTATE : out std_logic --; ); end usensor ; architecture behavioral of usensor is -- values CONSTANT SCNTMAX : integer := 65999 ; -- 60000us CONSTANT TRGMAX : integer := 110 ; -- 10us CONSTANT BFMAX : integer := 7000 ; -- > 200mm CONSTANT DIFFMAX : integer := 6468 ; -- 200mm CONSTANT DISMAX : integer := 12936 ; -- 400mm -- 60ms generator signal iSCNT : integer range 0 to SCNTMAX ; -- 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 ; -- sequencer signal iSTATE : std_logic_vector(2 downto 0) ; signal iBEGINX : integer range 0 to BFMAX ; signal iFINEX : integer range 0 to BFMAX ; signal iDIFF : integer range 0 to BFMAX ; signal iGSTATE : std_logic ; begin -- output UTRG <= iUTRG ; GSTATE <= iGSTATE ; -- counter process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSCNT <= 0 ; elsif rising_edge(CLOCK) then if ( iSCNT = SCNTMAX ) then iSCNT <= 0 ; else iSCNT <= iSCNT + 1 ; end if ; end if ; end process ; iUTRG <= '1' when ( iSCNT < TRGMAX ) else '0' ; -- synchronizer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iURES_SFT <= "000" ; elsif rising_edge(CLOCK) 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' ; -- sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= "000" ; iBEGINX <= 0 ; iFINEX <= 0 ; iDIFF <= 0 ; elsif falling_edge(CLOCK) then case conv_integer(iSTATE) is -- clear counter when 0 => if ( iSCNT = TRGMAX ) then iSTATE <= "001" ; iBEGINX <= 0 ; iFINEX <= 0 ; iDIFF <= 0 ; else iSTATE <= "000" ; end if ; -- wait trigger and store begin count when 1 => if ( iURES_LH = '1' ) then iSTATE <= "011" ; iBEGINX <= iSCNT ; elsif ( iSCNT > DISMAX ) then iSTATE <= "100" ; else iSTATE <= "001" ; end if ; -- skip when 3 => iSTATE <= "111" ; -- wait trigger and store fine count when 7 => if ( iURES_HL = '1' ) then iSTATE <= "110" ; iFINEX <= iSCNT ; else iSTATE <= "111" ; end if ; -- calculate when 6 => iSTATE <= "100" ; iDIFF <= (iFINEX - iBEGINX) ; -- return first state when 4 => iSTATE <= "000" ; -- default when others => iSTATE <= "000" ; end case ; end if ; end process ; iGSTATE <= '1' when ( iDIFF < DIFFMAX ) else '0' ; end behavioral;

モータ制御

 モータ制御はMOSFETを2つ接続し、パルスを  与えます。  MOSFETのゲートには、4V以上の電圧が必要なので  フォトカプラを入れます。CPLD/FPGAは3.3V動作  なので、波高値を大きくします。  FPGAは、SPIでDUTY比を受取り、LEFT、RIGHTに  パルスを出力します。  VHDLコードは、以下。 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 ; nSS : in std_logic ; MOSI : in std_logic ; MISO : out std_logic ; -- 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 -- BUS interface signal iSS : std_logic ; signal iMOSI : std_logic ; -- synchronizer signal iSS_SFT : std_logic_vector(2 downto 0) ; signal iSCK_SFT : std_logic_vector(1 downto 0) ; signal iSTRG : std_logic ; signal iSCK_TRG : std_logic ; -- internal shift register signal iMOSI_SFT : std_logic_vector(7 downto 0) ; -- internal register signal iREG : std_logic_vector(7 downto 0) ; signal iLEFT : std_logic_vector(6 downto 0) ; signal iRIGHT : std_logic_vector(6 downto 0) ; -- sequencer signal iSTATE : std_logic_vector(1 downto 0) ; begin -- input iSS <= not nSS ; iMOSI <= MOSI ; -- output MISO <= iMOSI_SFT(7) ; LPVAL <= iLEFT ; RPVAL <= iRIGHT ; -- synchronizer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSS_SFT <= "000" ; iSCK_SFT <= "00" ; elsif rising_edge(CLOCK) then iSS_SFT <= iSS_SFT(1 downto 0) & iSS ; iSCK_SFT <= iSCK_SFT(0) & SCK ; end if ; end process ; iSTRG <= '1' when ( iSS_SFT = "110" ) else '0' ; iSCK_TRG <= '1' when ( iSCK_SFT = "01" ) else '0' ; -- internal register process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iMOSI_SFT <= X"00" ; elsif rising_edge(CLOCK) then if ( iSS = '1' and iSCK_TRG = '1' ) then iMOSI_SFT <= iMOSI_SFT(6 downto 0) & iMOSI ; end if ; end if ; end process ; -- sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= "00" ; iREG <= X"00" ; iLEFT <= "0000000" ; iRIGHT <= "0000000" ; elsif rising_edge(CLOCK) then case conv_integer(iSTATE) is -- wait trigger when 0 => if ( iSTRG = '1' ) then iSTATE <= "01" ; iREG <= iMOSI_SFT ; else iSTATE <= "00" ; end if ; -- deliver when 1 => iSTATE <= "11" ; if ( iREG(7) = '1' ) then -- left register iLEFT <= iREG(6 downto 0) ; else iRIGHT <= iREG(6 downto 0) ; end if ; -- clear register when 3 => iSTATE <= "10" ; iREG <= X"00" ; -- return first state when 2 => iSTATE <= "10" ; -- default when others => iSTATE <= "00" ; end case ; end if ; end process ; end behavioral;  Arduinoは、SPIマスターとして左右のDUTY比を  FPGAに与えます。  SPIマスターにするとともに、シリアルデータを  MSBから出力するかLSBからにするかを決めます。  また、SCKの周波数を設定します。  MSBからデータ出力し、SCKをシステムクロックの  1/2に設定します。setup中で、パラメータ設定。 SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE1); SPI.setClockDivider(SPI_CLOCK_DIV2);  左右のDUTY比を一度に転送するため  ラッパー関数を用意します。 #define MASK7F 0x7f void set_duty(byte lx,byte rx) { byte xleft ; byte xright ; /* generate code */ xleft = 0x80 | (lx & MASK7F) ; xright = (rx & MASK7F) ; /* left motor duty ratio */ SPI.transfer( xleft ); /* right motor duty ratio */ SPI.transfer( xright ); }

Arduinoスケッチ

 移動処理を除いたArduinoスケッチを作成します。  シリアルインタフェースで、FPGAのテストが  できるようにしておきます。  コマンドインタプリタで利用する1文字コマンド  を定義します。  これらのコマンドは、Arduinoと接続するPersonalComputerで  pythonを利用したGUIで操作します。  スケッチは、以下。 #include <MsTimer2.h> #include <SPI.h> #define OFF 0 #define ON OFF+1 #define LED_BIT 1 #define SEL_BIT 4 #define START_BIT 5 #define OPENED 0 #define CLOSED 1 #define SYSMODE_IDLE 0 #define SYSMODE_RUN 1 #define NORMAL 0 #define CRANK NORMAL+1 #define LANE NORMAL+2 #define NONE 0 #define RIGHT_WHITE NONE+1 #define LEFT_WHITE NONE+2 #define ALL_WHITE NONE+3 #define MASK7F 0x7f /* variables */ byte strg ; byte strg_sft ; byte sysmode ; byte mode ; byte wcondition ; byte sensor ; byte sindex ; byte sbuf[16] ; byte sflag ; byte lduty ; byte rduty ; byte sensorx ; byte msg[8] ; /* function prototype */ void update_trigger(); void show_help(); void set_led(byte x); void set_duty(byte lx,byte rx); byte get_hex(byte x); byte get_sensor(); byte get_start_status(); void rs_putchar(char x); void rs_puts(char *ptr); void crlf(); void setup() { /* initialize serial */ Serial.begin(9600); sindex = 0 ; sflag = OFF ; /* initialize port values */ PORTB = 0xfd ; PORTC = 0xff ; PORTD = 0xff ; /* initialize port direction */ DDRB = 0xfe ; DDRC = 0x10 ; DDRD = 0xce ; /* set system mode */ sysmode = SYSMODE_IDLE ; /* set mode */ mode = NORMAL ; wcondition = NONE ; /* clear shift register */ strg_sft = 0 ; /* 100ms period */ MsTimer2::set(100,update_trigger); /* enable */ MsTimer2::start(); /* initialize SPI interface */ SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE1); SPI.setClockDivider(SPI_CLOCK_DIV2); set_duty(0,0); } void loop() { byte cmd ; byte i ; /* get sensor data */ sensor = get_sensor(); /* start trigger handling */ if ( strg == ON ) { /* clear flag */ strg = OFF ; /* change system mode */ if ( sysmode == SYSMODE_IDLE ) { sysmode = SYSMODE_RUN ; /* disable timer2 */ MsTimer2::stop(); } } /* start gate handling */ if ( get_start_status() == OPENED ) { /* change system mode */ if ( sysmode == SYSMODE_IDLE ) { sysmode = SYSMODE_RUN ; /* disable timer2 */ MsTimer2::stop(); } } /* serial handling */ if ( sflag == ON ) { /* clear flag */ sflag = OFF ; /* get command */ cmd = *(sbuf+0) ; /* help */ if ( cmd == '?' ) { show_help() ; } /* check LED */ if ( cmd == 'L' ) { if ( *(sbuf+1) == '1' ) { set_led(ON) ; } else { set_led(OFF); } } /* check motor */ if ( cmd == 'P' ) { /* get left duty */ lduty = get_hex( *(sbuf+1) ) ; lduty *= 10 ; lduty += get_hex( *(sbuf+2) ) ; /* get right duty */ rduty = get_hex( *(sbuf+3) ) ; rduty *= 10 ; rduty += get_hex( *(sbuf+4) ) ; /* impress */ set_duty(lduty,rduty); } /* system status */ if ( cmd == 'S' ) { if ( sysmode == SYSMODE_RUN ) { rs_puts("RUN"); } else { rs_puts("IDLE"); } crlf(); } /* start gate state */ if ( cmd == 'G' ) { if ( get_start_status() == OPENED ) { rs_puts("OPNED"); } else { rs_puts("CLOSED"); } crlf(); } /* show sensor data */ if ( cmd == 'D' ) { sensorx = sensor ; /* separate */ for ( i = 0 ; i < 8 ; i++ ) { /* get bit datum */ *(msg+7-i) = (sensorx & ON) + '0' ; /* shift */ sensorx >>= 1 ; } /* show */ for ( i = 0 ; i < 8 ; i++ ) { rs_putchar( *(msg+i) ); } crlf(); } } /* run */ if ( sysmode == SYSMODE_RUN ) { } } void update_trigger() { /* shift */ strg_sft <<= 1 ; /* mask */ strg_sft &= 0x03 ; /* judge trigger */ if ( (PINB & ON) == OFF ) { strg = ON ; } } void show_help() { rs_puts("? help"); crlf(); rs_puts("L led check"); crlf(); rs_puts("P set motor duty ratio"); crlf(); rs_puts("S show system status"); crlf(); rs_puts("G stat gate state"); crlf(); rs_puts("D show sensor data"); crlf(); } byte get_sensor() { byte result ; byte dh ; byte dl ; /* defalt */ result = 0 ; /* get upper nibble */ PORTC |= (1 << SEL_BIT); dh = PINC & 0x0f ; dh <<= 4 ; dh &= 0xf0 ; /* get lower nibble */ PORTC &= ~(1 << SEL_BIT); dl = PINC & 0x0f ; /* concatenate */ result = dh | dl ; return result ; } byte get_start_status() { byte result ; /* defalt */ result = OPENED ; /* judge */ if ( PIND & (1 << START_BIT) ) { result = CLOSED ; } return result ; } /* receive interrupt */ void serialEvent() { char ch; if ( Serial.available() > 0 ) { /* get 1 character */ ch = Serial.read(); /* store */ *(sbuf+sindex) = ch ; /* increment */ sindex++ ; /* judge */ if ( ch == '\r' ) { sindex = 0 ; sflag = ON ; } } } void set_led(byte x) { /* turn off */ PORTB &= ~(1 << LED_BIT) ; /* turn on */ if ( x ) { PORTB |= (1 << LED_BIT) ; } } void set_duty(byte lx,byte rx) { byte xleft ; byte xright ; /* generate code */ xleft = 0x80 | (lx & MASK7F) ; xright = (rx & MASK7F) ; /* left motor duty ratio */ SPI.transfer( xleft ); /* right motor duty ratio */ SPI.transfer( xright ); } byte get_hex(byte x) { byte result ; /* default */ result = 0 ; /* judge */ if ( '0' <= x && x <= '9' ) { result = x - '0' ; } if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; } if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; } return result ; } void rs_putchar(char x) { Serial.write( x ) ; } void rs_puts(char *ptr) { while ( *ptr ) { rs_putchar( *ptr ); ptr++ ; } } void crlf() { rs_putchar('\r'); rs_putchar('\n'); }

VHDLコード

 FPGAであるLattice Mach XO2のVHDLコードを  まとめます。  最上位のVHDLコードを、mcr2015としておき  他をコンポーネントで取り込んで使います。  コンポーネントにしたVHDLコードは、以下。  順番にリストを書いてみます。  mcr2015.vhdソースコード 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 -- 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 ; CLKAB : in std_logic ; LOUT : out std_logic_vector(7 downto 0) ; -- Sensor data output (Arduino) SEL : in std_logic ; SDAT : out std_logic_vector(3 downto 0) --; ); 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 ; nSS : in std_logic ; MOSI : in std_logic ; MISO : out std_logic ; -- 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 START : in std_logic ; CLKAB : in std_logic ; DOS : in std_logic ; -- monitor MLOUT : out std_logic_vector(7 downto 0) ; -- selector SEL : in std_logic ; -- register output REGOUT : out std_logic_vector(3 downto 0) --; ); end component ; begin -- 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 , nSS => nXSS , MOSI => XMOSI , MISO => XMISO , -- pulse out LPVAL => iLEFT , RPVAL => iRIGHT ); BCSInst : bcs port map ( -- system nRESET => nRESET , CLOCK => CLOCK , -- BCS START => START , CLKAB => CLKAB , DOS => DOS , -- monitor MLOUT => LOUT , -- selector SEL => SEL , -- register output REGOUT => SDAT ); end behavior;  超音波センサをスタートゲートの開閉に利用します。  usensor.vhdソースコード 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 (0:close 1:open) GSTATE : out std_logic --; ); end usensor ; architecture behavioral of usensor is -- values CONSTANT SCNTMAX : integer := 65999 ; -- 60000us CONSTANT TRGMAX : integer := 110 ; -- 10us CONSTANT BFMAX : integer := 7000 ; -- > 200mm CONSTANT DIFFMAX : integer := 6468 ; -- 200mm CONSTANT DISMAX : integer := 12936 ; -- 400mm -- 60ms generator signal iSCNT : integer range 0 to SCNTMAX ; -- 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 ; -- sequencer signal iSTATE : std_logic_vector(2 downto 0) ; signal iBEGINX : integer range 0 to BFMAX ; signal iFINEX : integer range 0 to BFMAX ; signal iDIFF : integer range 0 to BFMAX ; signal iGSTATE : std_logic ; begin -- output UTRG <= iUTRG ; GSTATE <= iGSTATE ; -- counter process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSCNT <= 0 ; elsif rising_edge(CLOCK) then if ( iSCNT = SCNTMAX ) then iSCNT <= 0 ; else iSCNT <= iSCNT + 1 ; end if ; end if ; end process ; iUTRG <= '1' when ( iSCNT < TRGMAX ) else '0' ; -- synchronizer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iURES_SFT <= "000" ; elsif rising_edge(CLOCK) 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' ; -- sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= "000" ; iBEGINX <= 0 ; iFINEX <= 0 ; iDIFF <= 0 ; elsif falling_edge(CLOCK) then case conv_integer(iSTATE) is -- clear counter when 0 => if ( iSCNT = TRGMAX ) then iSTATE <= "001" ; iBEGINX <= 0 ; iFINEX <= 0 ; iDIFF <= 0 ; else iSTATE <= "000" ; end if ; -- wait trigger and store begin count when 1 => if ( iURES_LH = '1' ) then iSTATE <= "011" ; iBEGINX <= iSCNT ; elsif ( iSCNT > DISMAX ) then iSTATE <= "100" ; else iSTATE <= "001" ; end if ; -- skip when 3 => iSTATE <= "111" ; -- wait trigger and store fine count when 7 => if ( iURES_HL = '1' ) then iSTATE <= "110" ; iFINEX <= iSCNT ; else iSTATE <= "111" ; end if ; -- calculate when 6 => iSTATE <= "100" ; iDIFF <= (iFINEX - iBEGINX) ; -- return first state when 4 => iSTATE <= "000" ; -- default when others => iSTATE <= "000" ; end case ; end if ; end process ; iGSTATE <= '1' when ( iDIFF < DIFFMAX ) else '0' ; end behavioral;  モータ制御のパルス出力を、SPIインタフェースと別に  定義して利用します。  pout.vhdソースコード 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 -- 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 1099 ; begin -- output LPOUT <= '1' when ( iPCNT < iLEFTX ) else '0' ; RPOUT <= '1' when ( iPCNT < iRIGHTX ) else '0' ; -- clock divider (generate 10kHz) process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iCNT <= 0 ; elsif rising_edge(CLOCK) then if ( iCNT = 1099 ) then iCNT <= 0 ; else iCNT <= iCNT + 1 ; end if ; end if ; end process ; -- counter process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iPCNT <= 0 ; iLEFTX <= 0 ; iRIGHTX <= 0 ; elsif rising_edge(CLOCK) then if ( iCNT = 0 ) then if ( iPCNT = 99 ) then iPCNT <= 0 ; iLEFTX <= conv_integer(LEFTV) ; iRIGHTX <= conv_integer(RIGHTV) ; else iPCNT <= iPCNT + 1 ; end if ; end if ; end if ; end process ; end behavioral;  SPIインタフェースで、2つのDCモータのDUTY比を取得します。  xspi.vhdソースコード 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 ; nSS : in std_logic ; MOSI : in std_logic ; MISO : out std_logic ; -- 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 -- BUS interface signal iSS : std_logic ; signal iMOSI : std_logic ; -- synchronizer signal iSS_SFT : std_logic_vector(2 downto 0) ; signal iSCK_SFT : std_logic_vector(1 downto 0) ; signal iSTRG : std_logic ; signal iSCK_TRG : std_logic ; -- internal shift register signal iMOSI_SFT : std_logic_vector(7 downto 0) ; -- internal register signal iREG : std_logic_vector(7 downto 0) ; signal iLEFT : std_logic_vector(6 downto 0) ; signal iRIGHT : std_logic_vector(6 downto 0) ; -- sequencer signal iSTATE : std_logic_vector(1 downto 0) ; begin -- input iSS <= not nSS ; iMOSI <= MOSI ; -- output MISO <= iMOSI_SFT(7) ; LPVAL <= iLEFT ; RPVAL <= iRIGHT ; -- synchronizer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSS_SFT <= "000" ; iSCK_SFT <= "00" ; elsif rising_edge(CLOCK) then iSS_SFT <= iSS_SFT(1 downto 0) & iSS ; iSCK_SFT <= iSCK_SFT(0) & SCK ; end if ; end process ; iSTRG <= '1' when ( iSS_SFT = "110" ) else '0' ; iSCK_TRG <= '1' when ( iSCK_SFT = "01" ) else '0' ; -- internal register process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iMOSI_SFT <= X"00" ; elsif rising_edge(CLOCK) then if ( iSS = '1' and iSCK_TRG = '1' ) then iMOSI_SFT <= iMOSI_SFT(6 downto 0) & iMOSI ; end if ; end if ; end process ; -- sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSTATE <= "00" ; iREG <= X"00" ; iLEFT <= "0000000" ; iRIGHT <= "0000000" ; elsif rising_edge(CLOCK) then case conv_integer(iSTATE) is -- wait trigger when 0 => if ( iSTRG = '1' ) then iSTATE <= "01" ; iREG <= iMOSI_SFT ; else iSTATE <= "00" ; end if ; -- deliver when 1 => iSTATE <= "11" ; if ( iREG(7) = '1' ) then -- left register iLEFT <= iREG(6 downto 0) ; else iRIGHT <= iREG(6 downto 0) ; end if ; -- clear register when 3 => iSTATE <= "10" ; iREG <= X"00" ; -- return first state when 2 => iSTATE <= "10" ; -- default when others => iSTATE <= "00" ; end case ; end if ; end process ; end behavioral;  信号の接続は、LPFファイルで指定します。 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 "69" ; LOCATE COMP "CLOCK" SITE "55" ; # 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 "122" ; LOCATE COMP "CLKAB" SITE "128" ; # Sensor data output (Arduino) LOCATE COMP "SEL" SITE "65" ; LOCATE COMP "SDAT[3]" SITE "62" ; LOCATE COMP "SDAT[2]" SITE "61" ; LOCATE COMP "SDAT[1]" SITE "60" ; LOCATE COMP "SDAT[0]" SITE "58" ; # motor drive LOCATE COMP "LEFTP" SITE "111" ; LOCATE COMP "RIGHTP" SITE "112" ; LOCATE COMP "XSCK" SITE "71" ; LOCATE COMP "XMISO" SITE "70" ; LOCATE COMP "XMOSI" SITE "69" ; LOCATE COMP "nXSS" SITE "68" ;
目次

inserted by FC2 system