目次

画像処理変更


 デジタル回路で画像処理を実現するには
 DualPortMemoryを利用するのが定石です。

 DualPortMemoryのイメージは、下図です。



 アクセスポートが2つあり、左右からデータを
 リードライトできます。もうひとつのポートに
 ついて考える必要はありません。

 よく利用される使い方は、バッファです。

 左はライト専用、右をリード専用として
 画像取得と画像操作の回路を独立させます。



 左右で相手のタイミングを考えずに、データ
 を出し入れできるので、Workstation等の
 BitMapDisplay用回路を高速化かつ単純化する
 目的でよく利用されました。

 ところが、現在DualPortMemoryは殆ど入手
 できません。入手可能でも納期、費用は
 それなりに覚悟しなければなりません。

 現実的な選択肢は、FPGAの中に入っている
 DualPortMemoryを使うことです。

 今回利用するXilinxのFPGAは、Spartan3で
 18kビットのDualPortMemoryを4個内蔵して
 います。

 2kバイトのDualPortMemoryで利用することを考え
 コンポーネントRAMB16_S9_S9を組込んで、動作を
 テストしました。

 このコンポーネントを利用するためには、以下の
 信号配置の意味を理解しなければなりません。



 信号を7種類に分けて機能を理解します。

 デジタル回路の中で、FPGAは同期回路を扱うため
 内部メモリ(レジスタ)を動かすには、クロック
 を使わなければなりません。

 2つのポートを独立したクロックで動かすことが
 できるように、CLOCKA、CLOCKBがあります。
 クロックをDualPortMemory内部に伝達するため
 ENA、ENABを使います。

 入力データは、DIA、DIBを利用します。

 他に入力データとしてDIAP、DIBPがあります。
 入力パリティデータと呼ばれますが、単純に
 入力データに付加するビットという意味で
 使い方は、ユーザーに委ねられています。

 出力データは、DOA、DOBを利用します。

 他に出力パリティデータがありますが、入力と
 同様に、使い方はユーザに委ねられています。

 SSRA、SSRBはDualPortMemory内部を同期で
 リセット、セットするために使います。

 今回は、ポートAをライト専用、ポートBを
 リード専用に使うことにしてみます。



 利用クロックを共通とし、ポートAをライト
 ポートBをリードになるよう、機能設定して
 います。

 ライト専用にするには、アドレス、データを
 確定後、WEAを1クロックだけクロックに同期
 いてイネーブルにするシーケンサを着けます。
 リードは、WEAをディセーブルにして、アドレス
 を与えるだけなので、DOAを無視します。

 タイミングチャートは、以下です。



 DualPortMemoryの内部は、多数のフリップフロップを
 並べているので、アドレス、データにはセットアップ
 タイムとホールドタイムを与えないと、正しくライト
 できません。

 ライト用シーケンサは、次のように定義しました。

  process (nRESET,iMCLK)
  begin
    if ( nRESET = '0' ) then
      iASTATE <= "00" ;
      iADDRA  <= (others => '0') ;
    elsif rising_edge( iMCLK ) then
      case conv_integer(iASTATE) is
        -- wait trigger
        when 0 => if ( iWTRG = '1' ) then
                    iASTATE <= "01" ;
                  else
                    iASTATE <= "00" ;
                  end if ;
        -- transfer
        when 1 => iASTATE <= "11" ;
                  iADDRA  <= "000" & iMAR ;
                  iDIA    <= iMDR ; 
        -- enable
        when 3 => iASTATE <= "10" ;
        -- return first state
        when 2 => iASTATE <= "00" ;
        -- default
        when others =>
                  iASTATE <= "00" ;
      end case ;
    end if ;
  end process ;
  iWEA <= '1' when ( iASTATE = "11" ) else '0' ;

 データは、次のタイミングチャートのように
 アドレスが確定してから、1クロック遅れて
 出力されます。



 このタイミングチャートで、データを取得する
 ためには、次のシーケンスを利用します。

  process (nRESET,iMCLK)
  begin
    if ( nRESET = '0' ) then
      iBSTATE <= "00" ;
      iADDRB  <= (others => '0') ;
      iBDAT   <= (others => '1') ;
    elsif rising_edge( iMCLK ) then
      case conv_integer(iBSTATE) is
        -- wait trigger
        when 0 => if ( iRTRG = '1' ) then
                    iBSTATE <= "01" ;
                    iADDRB  <= "000" & iBADR ;
                  else
                    iBSTATE <= "00" ;
                  end if ;
        -- confirm address
        when 1 => iBSTATE <= "11" ;
        -- get data
        when 3 => iBSTATE <= "10" ;
                  iBDAT   <= iDOB ;
        -- return first state
        when 2 => iBSTATE <= "00" ;
        -- default
        when others =>
                  iBSTATE <= "00" ;
      end case ;
    end if ;
  end process ;

 FPGA内部にある、DualPortMemoryアクセスを
 確認するために、次のようなシステムを構成
 しました。(ブロック図)



 アドレスは赤LEDに、データは緑LEDに接続して
 動作をモニタできるようにします。

 LEDは、MCR大会用に作った基板上の8ビットLED
 を使いました。



 ARMプロセッサのコマンドは、以下のように決め
 テストしました。

 ARMのファームウエアは、以下です。

#include <ADuC7026.h>

#define OFF 0
#define ON  OFF+1

/* data definitions */
typedef unsigned char  UBYTE ;
typedef   signed char  SBYTE ;
typedef unsigned short UWORD ;
typedef   signed short SWORD ;
typedef unsigned long  ULONG ;
typedef   signed long  SLONG ;

void  IRQ_Handler(void) __irq;
void  init_usr(void);

#define MASKFF 0xFF
#define MASK0F 0x0F
#define MASKF0 0xF0
#define MASK80 0x80
#define MASK40 0x40
#define MASK20 0x20
#define MASK10 0x10
#define MASK08 0x08
#define MASK04 0x04
#define MASK02 0x02
#define MASK01 0x01

ULONG timcnt ;

void  rs_putchar(UBYTE x);
void  crlf(void);
void  rs_puts(UBYTE *x);
UBYTE get_hex(UBYTE x);
void  show_help(void);

void  delay_ms(UWORD x);
void  delay_100us(UWORD x);

void  send_fpga(UBYTE x,UBYTE y);
void  send_address(UBYTE x);
void  put_value(UBYTE x);

/* global variables */
volatile UBYTE uflag ;
volatile UBYTE sbuf[8] ;
volatile UBYTE sindex ;
volatile UBYTE cmd ;

volatile UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

volatile UBYTE oflag ;

volatile UBYTE dat ;
volatile UBYTE adr ;
volatile UBYTE badr ;

#define SCNT_MAX 20
#define MASK07   0x07

int main(void)
{
  /* initialize user */
  init_usr();	
  /* endless loop */
  while(ON)
  {
    /* opening message */
    if ( oflag == ON ) {
      /* clear flag */
      oflag = OFF ;
      /* show message */
      rs_puts("Hello");
      crlf();
    }
    /* command interrpreter */
    if ( uflag == ON ) {
      /* clear flag */
      uflag = OFF ;
      /* new line */
      crlf();
      /* judge */
      cmd = *(sbuf+0) ;
      if ( cmd == '?' ) { show_help(); }
      /* address */
      if ( cmd == 'A' ) {
        adr  = get_hex( *(sbuf+1) ); adr <<= 4 ;
        adr |= get_hex( *(sbuf+2) ); 
      }
      /* data */
      if ( cmd == 'D' ) {
        dat  = get_hex( *(sbuf+1) ); dat <<= 4 ;
        dat |= get_hex( *(sbuf+2) );
      }
      /* put values */
      if ( cmd == 'W' ) {
        send_fpga(adr,dat);
      }
      /* load address */
      if ( cmd == 'L' ) {
        badr  = get_hex( *(sbuf+1) ); badr <<= 4 ;
        badr |= get_hex( *(sbuf+2) );
      }
      /* read B port data */
      if ( cmd == 'R' ) {
        send_address(badr);
      }
      /* show values */
      if ( cmd == 'S' ) {
        rs_puts("Address = "); put_value( adr ) ;
        rs_puts("Data    = "); put_value( dat ) ;
        rs_puts("Load    = "); put_value( badr ) ;
      }
    }
  }
  /* dummy return */
  return (0);
}

void IRQ_Handler(void) __irq
{
  volatile UBYTE ch ;
  /* judge UART receive interruption */
  if ( (IRQSTA & UART_BIT) == UART_BIT ) {
    /* judge */
    if ( COMSTA0 & 1 ) {
      /* clear flag */
      ch = COMRX ;
      *(sbuf+sindex) = ch ;
      sindex++ ;      
      if ( ch == '\r' ) {
        sindex = 0 ;
        uflag  = ON ;
      }
    }
  }
  /* judge timer3 interruption (1ms) */
  if ( (IRQSTA & WATCHDOG_TIMER_BIT) == WATCHDOG_TIMER_BIT ) {
    /* clear timer3 interrupt flag */
    T3CLRI = 0xff ;
    /* increment */
    timcnt++ ;
    /* blink */
    if ( (timcnt & 0x3ff) == 1000 ) {
      GP4DAT ^= (1 << 23);
    }
  }
}

void init_usr(void)
{
  /* select clock 10.44MHz 
       initialized in start up routine
  */
  PLLKEY1 = 0xaa ;
  PLLCON  = 0x01 ;
  PLLKEY2 = 0x55 ;
  /* power control
       initialized in start up routine 
  */
  /* initialize flag */
  uflag = OFF ;
  oflag = ON ;
  /* clear counter */
  timcnt = 0 ;
  /* initialize UART */
  {
    /* set baud rate 19200 bps CD = 2 */
    COMCON0 = 0x80 ; /* select COMDIV1 and COMDIV0 */
    COMDIV0 = 0x11 ;
    COMDIV1 = 0x00 ;
    /* set conditions */
    COMCON0 = 0x03 ; /* select COMRX and COMTX , 8bit data , 1 stop bit , no parity */
    /* enable interrupt */
    COMIEN0 = 0x01 ; /* ERBFI */
  }
  /* P0 */
  {
    /* */
    GP0DAT = 0xDF000000 ;
  }
  /* P1 */
  {
    /* use UART */
    GP1CON = 0x00000011 ; 
    /* */
    GP1DAT = 0xfef00000 ;
  }
  /* P2 */
  {
    /* all bits outputs */
    GP2DAT = 0xff000000 ;
  }
  /* P3 */
  {
    /* all bits outputs */
    GP3DAT = 0xff000000 ;
  }
  /* P4 */
  {
    GP4DAT = 0xff000000 ;
  }
  /* */
  adr  = 0 ;
  dat  = 0 ;
  badr = 0 ;
  /* initialize timer 3 (1s) */
  {
    T3LD  = 33   ; /* (32.768kHz / 33) = about 1kHz */
    T3CON = 0xc0 ; /* enable , cyclic , 1/1 */ 
  }
  /* enable timer 3 interrupt and UART interrupt */
  IRQEN = WATCHDOG_TIMER_BIT | UART_BIT ;
}

/* UART putchar */
void  rs_putchar(UBYTE x)
{
  /* ? transmmit buffer empty */
  while( (COMSTA0 & 0x40) == 0 ) ;
  /* set value */
  COMTX = x ;
}

/* carriage return and line feed */
void  crlf(void)
{
  rs_putchar('\r');
  rs_putchar('\n');
}

/* UART puts */
void  rs_puts(UBYTE *x)
{
  while ( *x != '\0' ) {
    rs_putchar( *x ) ;
    x++ ;
  }
}

/* convert ASCII to number */
UBYTE get_hex(UBYTE x)
{
  UBYTE 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 ;
}

/* show help */
void  show_help(void)
{
  rs_puts("? help")         ; crlf();
  rs_puts("A set address")  ; crlf();
  rs_puts("D set data")     ; crlf();
  rs_puts("W write values") ; crlf();
  rs_puts("L load address") ; crlf();
  rs_puts("R read data")    ; crlf();
  rs_puts("S show values")  ; crlf();
}

void  delay_100us(UWORD x)
{
  ULONG last ;
  /* calculate */
  last = timcnt + x ;
  /* wait */
  while ( timcnt < last ) ;
}

void  delay_ms(UWORD x)
{
  ULONG last ;
  /* calculate */
  last = timcnt + 10 * x ;
  /* wait */
  while ( timcnt < last ) ;
}

void  send_fpga(UBYTE x,UBYTE y)
{
  /* clear */
  GP2DAT = 0xff000000 ;
  /* impress */
  GP3DAT &= 0xff00ffff ;
  delay_100us(2);
  GP3DAT |= (x << 16);
  delay_100us(2);
  /* trigger */
  GP2DAT |= (1 << 16);
  delay_100us(2);
  GP2DAT = 0xff000000 ;
  /* impress */
  GP3DAT &= 0xff00ffff ;
  delay_100us(2);
  GP3DAT |= (y << 16);
  delay_100us(2);
  /* trigger */
  GP2DAT |= (2 << 16);
  delay_100us(2);
  GP2DAT = 0xff000000 ;
  /* send write trigger */
  GP2DAT |= (4 << 16);
  delay_100us(2);
  GP2DAT = 0xff000000 ;
}

void  send_address(UBYTE x)
{
  /* clear */
  GP2DAT = 0xff000000 ;
  /* impress */
  GP3DAT &= 0xff00ffff ;
  delay_100us(2);
  GP3DAT |= (x << 16);
  delay_100us(2);
  /* trigger */
  GP2DAT |= (8 << 16);
  delay_100us(2);
  GP2DAT = 0xff000000 ;
  /* send read trigger */
  GP2DAT |= (16 << 16);
  delay_100us(2);
  GP2DAT = 0xff000000 ;
}


void  put_value(UBYTE x)
{
  UBYTE msg[2] ;
  /* separate */
  *(msg+0) = (x >> 4) & MASK0F ;
  *(msg+1) = (x & MASK0F) ;
  /* send charactor */
  rs_putchar( asc_hex[*(msg+0)] ) ;
  rs_putchar( asc_hex[*(msg+1)] ) ;
  /* new line */
  crlf();
}

 ARMからは、アドレス、データはトリガーにより
 FPGAに与えます。DualPortMemoryへのライトと
 リードもトリガーを与えて対応しています。

 シリアルでの操作は、HyperTerminalを利用しました。



 アドレス、データは、接続LEDで確認します。

 FPGAに格納したVHDLコードは、以下です。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Library UNISIM;
use UNISIM.vcomponents.all;

entity dpmtst is
  generic (
    TOPX : integer := 2 ;
    XMAX : integer := 3 --;
  );
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ;
    -- trigger
    ATRG : in  std_logic ;
    DTRG : in  std_logic ;
    WTRG : in  std_logic ;
    LTRG : in  std_logic ;
    RTRG : in  std_logic ;
    -- data BUS
    ADBUS : in  std_logic_vector(7 downto 0) ;
    -- monitor
    AOUT  : out std_logic_vector(7 downto 0) ;
    DOUT  : out std_logic_vector(7 downto 0) ;
    BAOUT : out std_logic_vector(7 downto 0) ;
    BDOUT : out std_logic_vector(7 downto 0) --;
  );
end dpmtst;

architecture Behavioral of dpmtst is
  -- component 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 ;
  -- clock
  signal iMCLK  : std_logic ;
  -- trigger
  signal iATRG_SFT : std_logic_vector(2 downto 0) ;
  signal iATRG     : std_logic ;
  signal iDTRG_SFT : std_logic_vector(2 downto 0) ;
  signal iDTRG     : std_logic ;
  signal iWTRG_SFT : std_logic_vector(2 downto 0) ;
  signal iWTRG     : std_logic ;
  signal iLTRG_SFT : std_logic_vector(2 downto 0) ;
  signal iLTRG     : std_logic ;
  signal iRTRG_SFT : std_logic_vector(2 downto 0) ;
  signal iRTRG     : std_logic ;
  -- internal registers
  signal iMAR : std_logic_vector(7 downto 0) ;
  signal iMDR : std_logic_vector(7 downto 0) ;
  -- internal registers (A port)
  signal iASTATE : std_logic_vector(1 downto 0) ;
  signal iDOA    : std_logic_vector(7 downto 0) ;
  signal iADDRA  : std_logic_vector(10 downto 0) ;
  signal iDIA    : std_logic_vector(7 downto 0) ;
  signal iDOPA   : std_logic_vector(0 downto 0) ;
  signal iWEA    : std_logic ;
  -- internal registers (Bport)
  signal iBSTATE : std_logic_vector(1 downto 0) ;
  signal iDOB    : std_logic_vector(7 downto 0) ;
  signal iADDRB  : std_logic_vector(10 downto 0) ;
  signal iDOPB   : std_logic_vector(0 downto 0) ;
  signal iBADR   : std_logic_vector(7 downto 0) ;
  signal iBDAT   : std_logic_vector(7 downto 0) ;
begin
  -- component clock generator (48MHz/6 = 8MHz)
  CLKX : clkgenx generic map (TOPX,XMAX) port map (nRESET,CLOCK,iMCLK);

  -- component dual port memory
  RAMB16_S9_S9_inst : RAMB16_S9_S9
    generic map (
      INIT_A  => X"000", --  Value of output RAM registers on Port A at startup
      INIT_B  => X"000", --  Value of output RAM registers on Port B at startup
      SRVAL_A => X"000", --  Port A ouput value upon SSR assertion
      SRVAL_B => X"000", --  Port B ouput value upon SSR assertion
      WRITE_MODE_A => "WRITE_FIRST", --  WRITE_FIRST, READ_FIRST or NO_CHANGE
      WRITE_MODE_B => "WRITE_FIRST", --  WRITE_FIRST, READ_FIRST or NO_CHANGE
      SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" 
      -- The following INIT_xx declarations specify the initial contents of the RAM
      -- Address 0 to 511
      INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000",
      -- Address 512 to 1023
      INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000",
      -- Address 1024 to 1535
      INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000",
      -- Address 1536 to 2047
      INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000",
      INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000",
      -- The next set of INITP_xx are for the parity bits
      -- Address 0 to 511
      INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000",
      -- Address 512 to 1023
      INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000",
      -- Address 1024 to 1535
      INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000",
      -- Address 1536 to 2047
      INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000",
      INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000")
   port map (
      DOA =>   iDOA,   -- Port A 8-bit Data Output
      DOB =>   iDOB,   -- Port B 8-bit Data Output
      DOPA =>  iDOPA,  -- Port A 1-bit Parity Output
      DOPB =>  iDOPB,  -- Port B 1-bit Parity Output
      ADDRA => iADDRA, -- Port A 11-bit Address Input
      ADDRB => iADDRB, -- Port B 11-bit Address Input
      CLKA =>  iMCLK,  -- Port A Clock
      CLKB =>  iMCLK,  -- Port B Clock
      DIA =>   iDIA,   -- Port A 8-bit Data Input
      DIB =>   X"FF",  -- Port B 8-bit Data Input
      DIPA =>  "1",    -- Port A 1-bit parity Input
      DIPB =>  "1",    -- Port B 1-bit parity Input
      ENA =>   '1',    -- Port A RAM Enable Input
      ENB =>   '1',    -- Port B RAM Enable Input
      SSRA =>  '0',    -- Port A Synchronous Set/Reset Input
      SSRB =>  '0',    -- Port B Synchronous Set/Reset Input
      WEA =>   iWEA,   -- Port A Write Enable Input
      WEB =>   '0'     -- Port B Write Enable Input
   );

  -- monitor output
  AOUT  <= not iMAR ;
  DOUT  <= not iMDR ;
  BAOUT <= not iBADR ;
  BDOUT <= not iBDAT ;

  -- trigger
  process (nRESET,iMCLK)
  begin
    if ( nRESET = '0' ) then
      iATRG_SFT <= "000" ;
      iDTRG_SFT <= "000" ;
      iWTRG_SFT <= "000" ;
      iLTRG_SFT <= "000" ;
      iRTRG_SFT <= "000" ;
    elsif rising_edge(iMCLK) then
      iATRG_SFT <= iATRG_SFT(1 downto 0) & ATRG ;
      iDTRG_SFT <= iDTRG_SFT(1 downto 0) & DTRG ;
      iWTRG_SFT <= iWTRG_SFT(1 downto 0) & WTRG ;
      iLTRG_SFT <= iLTRG_SFT(1 downto 0) & LTRG ;
      iRTRG_SFT <= iRTRG_SFT(1 downto 0) & RTRG ;
    end if ;
  end process ;
  iATRG <= '1' when ( iATRG_SFT = "011" or iATRG_SFT = "001" ) else '0' ;
  iDTRG <= '1' when ( iDTRG_SFT = "011" or iDTRG_SFT = "001" ) else '0' ;
  iWTRG <= '1' when ( iWTRG_SFT = "011" or iWTRG_SFT = "001" ) else '0' ;
  iLTRG <= '1' when ( iLTRG_SFT = "011" or iLTRG_SFT = "001" ) else '0' ;
  iRTRG <= '1' when ( iRTRG_SFT = "011" or iRTRG_SFT = "001" ) else '0' ;

  -- BUS interface
  process (nRESET,iMCLK)
  begin
    if ( nRESET = '0' ) then
      iMAR  <= (others => '0') ;
      iMDR  <= (others => '0') ;
      iBADR <= (others => '0') ;
    elsif rising_edge( iMCLK ) then
      if ( iATRG = '1' ) then
        iMAR <= ADBUS ;
      end if ;
      if ( iDTRG = '1' ) then
        iMDR <= ADBUS ;
      end if ;
      if ( iLTRG = '1' ) then
        iBADR <= ADBUS ;
      end if ;
    end if ;
  end process ;

  -- sequencer (A port)
  process (nRESET,iMCLK)
  begin
    if ( nRESET = '0' ) then
      iASTATE <= "00" ;
      iADDRA  <= (others => '0') ;
    elsif rising_edge( iMCLK ) then
      case conv_integer(iASTATE) is
        -- wait trigger
        when 0 => if ( iWTRG = '1' ) then
                    iASTATE <= "01" ;
                  else
                    iASTATE <= "00" ;
                  end if ;
        -- transfer
        when 1 => iASTATE <= "11" ;
                  iADDRA  <= "000" & iMAR ;
                  iDIA    <= iMDR ; 
        -- enable
        when 3 => iASTATE <= "10" ;
        -- return first state
        when 2 => iASTATE <= "00" ;
        -- default
        when others =>
                  iASTATE <= "00" ;
      end case ;
    end if ;
  end process ;
  iWEA <= '1' when ( iASTATE = "11" ) else '0' ;

  -- sequencer (B port)
  process (nRESET,iMCLK)
  begin
    if ( nRESET = '0' ) then
      iBSTATE <= "00" ;
      iADDRB  <= (others => '0') ;
      iBDAT   <= (others => '1') ;
    elsif rising_edge( iMCLK ) then
      case conv_integer(iBSTATE) is
        -- wait trigger
        when 0 => if ( iRTRG = '1' ) then
                    iBSTATE <= "01" ;
                    iADDRB  <= "000" & iBADR ;
                  else
                    iBSTATE <= "00" ;
                  end if ;
        -- confirm address
        when 1 => iBSTATE <= "11" ;
        -- get data
        when 3 => iBSTATE <= "10" ;
                  iBDAT   <= iDOB ;
        -- return first state
        when 2 => iBSTATE <= "00" ;
        -- default
        when others =>
                  iBSTATE <= "00" ;
      end case ;
    end if ;
  end process ;

end Behavioral;

 DualPortMemoryを利用するためには、パッケージの
 宣言が必要です。以下の宣言を先頭においています。

Library UNISIM;
use UNISIM.vcomponents.all;

 コンポーネントの宣言で、DualPortMemoryのゼロクリア
 をしていますが、この内容はテンプレートで用意されて
 いるので、Copy&Pasteしただけです。

 ピン割付とレジスタ幅にだけ注意します。

 コンポーネントでは、1ビットであっても、バス指定で
 ないとコンパイルするときに、エラーで撥ねられます。

 バス指定は、以下のようにします。

  signal iDOPA   : std_logic_vector(0 downto 0) ;
  signal iDOPB   : std_logic_vector(0 downto 0) ;

 バス指定で、値を直接指定する場合、’ではなく”で
 値を記述します。

  NG '0'
 OK "0"

 他にコンポーネントとして、分周処理を宣言して
 使っています。この分周処理のVHDLコードは以下。

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

entity clkgenx is
  generic (
    TOPX : integer ; 
    RMAX : integer --;
  );
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ;
    -- output
    CLKOUT : out std_logic -- ;
  );
end clkgenx;

architecture Behavioral of clkgenx is
  signal iSCNT : std_logic_vector(TOPX-1 downto 0);
  signal iCLK  : std_logic ;
begin
  -- output
  CLKOUT <= iCLK ;

  -- divider
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSCNT <= (others => '0') ;
      iCLK  <= '0' ;
    elsif rising_edge(CLOCK) then
      if ( conv_integer(iSCNT) = RMAX-1 ) then
        iSCNT <= (others => '0') ;
        iCLK  <= not iCLK ;
      else
        iSCNT <= iSCNT + '1' ;
      end if ;
    end if ;
  end process ;

end Behavioral;

 ARM、LEDと接続するためのピンアサインは
 次のUCFファイルで指定です。

# system
NET "CLOCK"     LOC = "P55" | IOSTANDARD = LVCMOS33 ;
NET "nRESET"    LOC = "P73" | IOSTANDARD = LVCMOS33 ;

# G0 
NET "ADBUS<0>" LOC = "P1"  | IOSTANDARD = LVCMOS33 ;
NET "ADBUS<1>" LOC = "P2"  | IOSTANDARD = LVCMOS33 ;
NET "ADBUS<2>" LOC = "P4"  | IOSTANDARD = LVCMOS33 ;
NET "ADBUS<3>" LOC = "P5"  | IOSTANDARD = LVCMOS33 ;
NET "ADBUS<4>" LOC = "P6"  | IOSTANDARD = LVCMOS33 ;
NET "ADBUS<5>" LOC = "P7"  | IOSTANDARD = LVCMOS33 ;
NET "ADBUS<6>" LOC = "P8"  | IOSTANDARD = LVCMOS33 ;
NET "ADBUS<7>" LOC = "P10" | IOSTANDARD = LVCMOS33 ;

# G1
NET "ATRG" LOC = "P11" | IOSTANDARD = LVCMOS33 ;
NET "DTRG" LOC = "P12" | IOSTANDARD = LVCMOS33 ;
NET "WTRG" LOC = "P13" | IOSTANDARD = LVCMOS33 ;
NET "LTRG" LOC = "P14" | IOSTANDARD = LVCMOS33 ;
NET "RTRG" LOC = "P15" | IOSTANDARD = LVCMOS33 ;

# G0B
NET "AOUT<0>" LOC = "P141" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "AOUT<1>" LOC = "P140" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "AOUT<2>" LOC = "P137" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "AOUT<3>" LOC = "P135" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "AOUT<4>" LOC = "P132" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "AOUT<5>" LOC = "P131" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "AOUT<6>" LOC = "P130" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "AOUT<7>" LOC = "P129" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;

# G1B
NET "DOUT<0>" LOC = "P116" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "DOUT<1>" LOC = "P113" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "DOUT<2>" LOC = "P119" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "DOUT<3>" LOC = "P118" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "DOUT<4>" LOC = "P123" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "DOUT<5>" LOC = "P122" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "DOUT<6>" LOC = "P125" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "DOUT<7>" LOC = "P124" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;

# G2B 
NET "BAOUT<0>" LOC = "P112" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BAOUT<1>" LOC = "P108" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BAOUT<2>" LOC = "P107" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BAOUT<3>" LOC = "P105" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BAOUT<4>" LOC = "P104" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BAOUT<5>" LOC = "P103" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BAOUT<6>" LOC = "P102" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BAOUT<7>" LOC = "P100" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;

# G3B 
NET "BDOUT<0>" LOC = "P99" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BDOUT<1>" LOC = "P98" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BDOUT<2>" LOC = "P97" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BDOUT<3>" LOC = "P96" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BDOUT<4>" LOC = "P95" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BDOUT<5>" LOC = "P93" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BDOUT<6>" LOC = "P92" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "BDOUT<7>" LOC = "P90" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;

 DualPortMemoryの扱い方を理解したので
 カメラとのインタフェースを考えます。

 画像データは、160x120ですが、160x60として扱います。
 垂直方向は、上側の60ラインを利用します。



 60ライン中の3ラインを選んで、DualPortMemoryに
 ピクセルの輝度データを保存します。

 MCR-VCマシンを動かすために、必要なセンサー
 データが欲しいので、不必要な情報を極力廃す
 ようにします。

 DualPortMemoryの2つのポートには、カメラの
 インタフェース回路と画像処理回路を接続します。



 画像処理回路は、1ラインのピクセルデータから
 8ビットのセンサーデータを生成します。

 生成したセンサーデータは、3つの8ビットレジスタ
 に転送します。レジスタの内容をバスインタフェース
 で、マイクロコンピュータが取得します。

 カメラインタフェースと画像処理の回路を考えます。


カメラインタフェース  カメラから画像データを取得するには、次のタイミング  チャートに従って、1バイトずつ保存していきます。  カメラは、シャッターを押して画像データを取得  する方が自然なので、トリガーを与えてSRAMに  保存します。  一気にVHDLコードを記述するとデバッグが面倒  なので、一度Cで処理を記述します。 void cam_handler(void) { switch ( cstate ) { /* wait trigger */ case 0 : if ( ctrg == ON ) { ctrg = OFF ; cstate = 1 ; } else { cstate = 0 ; } break ; /* wait VSYNC */ case 1 : if ( vtrg == ON ) { pcnt = 0 ; lcnt = 0 ; cstate = 2 ; } else { cstate = 1 ; } break ; /* judge line counter */ case 2 : if ( lcnt == LCNT_MAX ) { cstate = 7 ; } else { cstate = 3 ; } break ; /* store even data */ case 3 : if ( ptrg == ON ) { cstate = 4 ; } else { cstate = 3 ; } break ; /* skip odd data */ case 4 : if ( ptrg == ON ) { cstate = 5 ; } else { cstate = 4 ; } break ; /* judge pixel counter */ case 5 : if ( pcnt == PCNT_MAX ) { pcnt = 0 ; lcnt++ ; cstate = 6 ; } else { pcnt++ ; cstate = 3 ; } break ; /* line loop */ case 6 : cstate = 2 ; break ; /* return first state */ case 7 : cstate = 0 ; break ; /* */ default : break ; } /* debug */ printf("state(%d) lcnt (%02d) pcnt(%02d)\n",cstate,lcnt,pcnt); }  シャッターをトリガーctrgで判断し、VSYNC  PCLKとHREFの論理積によるトリガーをvtrg、  ptrgとして、シーケンスを記述しました。  関数の動作をクロック同期でテストするドライブ  処理は、次のように記述しています。 for ( i = 0 ; i < LMAX ; i++ ) { ctrg = OFF ; vtrg = OFF ; ptrg = OFF ; if ( i == 1 ) { ctrg = ON ; } if ( i == 2 ) { vtrg = ON ; } if ( (i % 4) == 3 ) { ptrg = ON ; } printf("%04d ptrg(%d) \t",i,ptrg); cam_handler(); }  カメラインタフェースとデータ保存シーケンサ  に分けて、定義します。  CUIの環境で、上記関数の動作を確認したので  VHDLコードに変換します。 process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iCSTATE <= "000" ; iLCNT <= (others => '0') ; iPCNT <= (others => '0') ; iCDATA <= (others => '0') ; iATRG_SFT <= "00" ; elsif rising_edge(iMCLK) then case conv_integer(iCSTATE) is -- wait trigger from micom when 0 => if ( iCTRG = '1' ) then iCSTATE <= "001" ; -- next else iCSTATE <= "000" ; -- stay end if ; -- wait VSYNC trigger when 1 => if ( iVSTRG = '1' ) then iCSTATE <= "010" ; -- next iLCNT <= (others => '0') ; iLCNT <= (others => '0') ; iCDATA <= (others => '0') ; else iCSTATE <= "001" ; -- stay end if ; -- judge line counter when 2 => if ( conv_integer(iLCNT) = LCNT_MAX ) then iCSTATE <= "111" ; -- exit else iCSTATE <= "011" ; -- loop end if ; -- store even data (Y) when 3 => if ( iPTRG = '1' ) then iCSTATE <= "100" ; -- next iCDATA <= CDAT ; iATRG_SFT <= iATRG_SFT(0) & '1' ; else iCSTATE <= "011" ; -- stay end if ; -- skip odd data (U or V) when 4 => if ( iPTRG = '1' ) then iCSTATE <= "101" ; -- next iATRG_SFT <= iATRG_SFT(0) & '1' ; else iCSTATE <= "100" ; -- state : 4 end if ; -- judge pixel counter when 5 => if ( conv_integer(iPCNT) = PCNT_MAX ) then iCSTATE <= "110" ; -- state : 6 iPCNT <= (others => '0'); iLCNT <= iLCNT + '1' ; else iPCNT <= iPCNT + '1' ; iCSTATE <= "011" ; -- state : 3 end if ; iATRG_SFT <= "00" ; -- new line handling when 6 => iCSTATE <= "010" ; -- state : 2 -- return first state when 7 => iCSTATE <= "000" ; -- state : 0 -- default when others => iCSTATE <= "000" ; end case ; end if ; end process ;  これだけでは、データをSRAMに保存する回路を  動かせないので、シーケンサからトリガーを  出力します。  3ラインを判定するためのデコーダを用意します。 iTARGET_L <= '1' when ( iLCNT = conv_integer(iTLTOP) ) else '1' when ( iLCNT = conv_integer(iTLMIDDLE) ) else '1' when ( iLCNT = conv_integer(iTLBOTTOM) ) else '0' ;  該当ラインになっているときに、1バイトずつ  SRAMにデータを保存するためのトリガーを生成  します。シフトレジスタを利用して、輝度信号  だけをSRAMに保存します。 iATRG <= iATRG_SFT(1) and iATRG_SFT(0) ;  トリガーが出来れば、画像データをSRAMに保存  するシーケンサを定義します。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iASTATE <= "000" ; iADDRA <= (others => '0') ; elsif rising_edge(CLOCK) then case conv_integer(iASTATE) is -- wait trigger when 0 => if ( iATRG = '1' and iTARGET_L = '1' ) then iASTATE <= "001" ; -- state : 1 else iASTATE <= "000" ; -- state : 0 end if ; -- transfer data when 1 => iDIA <= iCDATA ; iASTATE <= "011" ; -- state : 3 -- send write trigger when 3 => iASTATE <= "111" ; -- state : 7 -- address increment when 7 => iADDRA <= iADDRA + '1' ; iASTATE <= "110" ; -- state : 6 -- judge when 6 => if ( conv_integer(iADDRA) = QMAX ) then iASTATE <= "100" ; -- state : 4 else iASTATE <= "000" ; -- state : 0 end if ; -- return first state when 4 => iASTATE <= "000" ; -- state : 0 iADDRA <= (others => '0') ; -- default when others => iASTATE <= "000" ; end case ; end if ; end process ;  画像データを保存したなら、画像処理させます。  指定ラインのデータを保存後、次のデータを保存するまで  ある程度の時間があります。  指定ラインの次のラインを判断し、そのラインのデータが  が着ているときに、画像処理できるようにします。  指定ラインの次ラインを判定して、フラグをセットします。 iTARGET_N <= '1' when ( iLCNT = conv_integer(iTLTOP+1) ) else '1' when ( iLCNT = conv_integer(iTLMIDDLE+1) ) else '1' when ( iLCNT = conv_integer(iTLBOTTOM+1) ) else '0' ;  画像処理用シーケンサに対してのトリガーも定義します。 iBTRG <= '1' when ( iCSTATE = "110" ) else '0' ;
画像処理  カメラインタフェースの2シーケンサで  指定ラインデータを取得し、次のライン  で画像処理実行のトリガーを出す仕様に  しました。  画像処理は、1ライン中の隣合う2データの  差分を求め、差分の最大、最小をとるピクセル  位置を取得します。2つのピクセルの位置の  相加平均を計算し、センターライン白線の中央  位置とします。  このアルゴリズムでは、コースがセンターライン  を中心に、左右対称になっているとの条件が必要  になります。  全白、片側白のような場合、中央から最大値  最小値の位置までの距離を利用し、センサー  データを新たに生成します。  ブロック図で、以下のようなシーケンサと  DualPortMemoryを2つ並べた構成とします。  DualPortMemoryに保存されているラインデータから  差分を計算し、他のメモリに保存するシーケンサを  考えます。  デジタル回路にする前に、C言語の関数で  動作を確認しました。 void save_handler(void) { switch ( bstate ) { /* wait trigger */ case 0 : if ( btrg == ON ) { bstate = 1 ; bcnt = 160 ; } else { bstate = 0 ; } break ; /* judge */ case 1 : if ( bcnt == 0 ) { bstate = 5 ; } else { bstate = 2 ; } break ; /* get data */ case 2 : bstate = 3 ; if ( bcnt == 160 ) { now_data = 0 ; pre_data = dob ; } else { now_data = dob - pre_data ; pre_data = dob ; } break ; /* store data to memory */ case 3 : bstate = 4 ; break ; /* update */ case 4 : addrb++ ; bufadra++ ; bcnt-- ; bstate = 1 ; break ; /* send trigger */ case 5 : bstate = 6 ; bflag++ ; break ; /* return first state */ case 6 : bstate = 0 ; if ( bflag == 3 ) { bflag = 0 ; addrb = 0 ; bufadra = 0 ; } break ; /* */ default : break ; } /* debug */ printf("state(%d) bflag(%d) bcnt(%03d) ",bstate,bflag,bcnt,addrb); printf("address(%03d) bufaddress(%03d)\n",addrb,bufadra); }  関数の動作をクロック同期でテストするドライブ  処理は、次のように記述しました。 for ( i = 0 ; i < LMAX ; i++ ) { btrg = OFF ; if ( i == 5 ) { btrg = ON ; } if ( i == 700 ) { btrg = ON ; } if ( i == 1400 ) { btrg = ON ; } if ( i == 2048 ) { btrg = ON ; } printf("%04d : ",i); save_handler(); }  CUI上での動作を確認したので、VHDLコードに  よるシーケンサを記述します。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iBSTATE <= 0 ; iBCNT <= 0 ; iBFLAG <= 0 ; iNOW_DATA <= (others => '0') ; iADDRB <= (others => '0') ; iBUFADRA <= (others => '0') ; iBUFA <= (others => '0') ; elsif rising_edge(CLOCK) then case iBSTATE is -- wait trigger when 0 => if ( iBTRG = '1' and iTARGET_N = '1' ) then iBSTATE <= 1 ; iBCNT <= PCNT_MAX ; else iBSTATE <= 0 ; end if ; -- judge when 1 => if ( iBCNT = 0 ) then iBSTATE <= 5 ; else iBSTATE <= 2 ; end if ; -- get data when 2 => iBSTATE <= 3 ; if ( iBCNT = PCNT_MAX ) then iBUFA <= (others => '0'); iNOW_DATA <= iDOB ; else iBUFA <= iNOW_DATA - iDOB ; iNOW_DATA <= iDOB ; end if ; -- store data with trigger when 3 => iBSTATE <= 4 ; -- update when 4 => iADDRB <= iADDRB + '1' ; iBUFADRA <= iBUFADRA + '1' ; iBCNT <= iBCNT - 1 ; iBSTATE <= 1 ; -- send trigger when 5 => iBSTATE <= 6 ; iBFLAG <= iBFLAG + 1 ; -- judge exit when 6 => iBSTATE <= 7 ; if ( iBFLAG = 3 ) then iBFLAG <= 0 ; iADDRB <= (others => '0') ; iBUFADRA <= (others => '0') ; end if ; -- return first state when 7 => iBSTATE <= 0 ; -- default when others => iBSTATE <= 0 ; end case ; end if ; end process ;  シーケンサは、指定ラインの次ラインを処理している  場合、トリガーが来ると動作を始め、自動停止します。  ピクセル1から159までの差分を計算し、バッファに  保存します。  バッファへの保存制御トリガーは、シーケンサの  ステートが3のとき、出力します。 iBWEA <= '1' when ( iBSTATE = 3 ) else '0' ;  対象とする全ラインの差分保存が終わったなら  ラインデータをセンサーデータに変換する回路  を動かします。 iHTRG <= '1' when ( iBSTATE = 5 ) else '0' ;  差分データから、特異点(最大値と最小値)の存在  する位置を割出し、センサーデータ生成回路に渡す  シーケンサ動作を考えます。  デジタル回路にする前に、C言語の関数で  動作を確認します。 void gens_handler(void) { switch ( hstate ) { /* wait trigger */ case 0 : if ( htrg == ON ) { hstate = 1 ; hcnt = 0 ; } else { hstate = 0 ; } break ; /* judge */ case 1 : if ( hcnt == 160 ) { hstate = 5 ; } else { hstate = 2 ; } break ; /* get data */ case 2 : hstate = 3 ; htmp = bufb ; break ; /* update pointer */ case 3 : hstate = 4 ; bufadrb++ ; if ( hcnt > 0 ) { if ( htmp > xmax ) { xmax = htmp ; lmax = hcnt ; } if ( htmp < xmin ) { xmin = htmp ; lmin = hcnt ; } } break ; /* update */ case 4 : hcnt++ ; hstate = 1 ; break ; /* set parameters */ case 5 : hstate = 6 ; hcnt = 0 ; p0 = lmax ; p1 = lmin ; break ; /* get result */ case 6 : hstate = 7 ; if ( hflag == 0 ) { puts(" TOP sensor") ; } if ( hflag == 1 ) { puts(" MIDDLE sensor") ; } if ( hflag == 2 ) { puts(" BOTTOM sensor") ; } break ; /* update line */ case 7 : hstate = 8 ; hflag++ ; break ; /* judge */ case 8 : if ( hflag == 3 ) { hstate = 9 ; bufadrb = 0 ; hflag = 0 ; } else { hstate = 1 ; xmax = 0 ; xmin = 0 ; lmax = 0 ; lmin = 0 ; } break ; /* return first state */ case 9 : hstate = 0 ; break ; /* */ default : break ; } /* debug */ printf("hstate(%d) hflag(%d) hcnt(%03d) bufadrb(%03d)\n",hstate,hflag,hcnt,bufadrb); }  シーケンサなので、switch文を利用し、デジタル回路と  等価な動作をする関数を定義します。センサーデータの  生成回路は、別途考えるとして、特異点位置を与えて  結果を引出す処理まで、確認できます。  ドライブ処理は、次のfor文で確認しました。 for ( i = 0 ; i < LMAX ; i++ ) { htrg = OFF ; if ( i == 5 ) { htrg = ON ; } if ( i == 1000 ) { htrg = ON ; } if ( i == 2000 ) { htrg = ON ; } printf("%04d : ",i); gens_handler(); }  C言語の記述から、VHDLコードを定義します。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iHSTATE <= 0 ; iHCNT <= 0 ; iHFLAG <= 0 ; iSMAX <= (others => '0') ; iSMIN <= (others => '0') ; iSMAXL <= (others => '0') ; iSMINL <= (others => '0') ; iBUFADRB <= (others => '0') ; iPX <= (others => '0') ; iPY <= (others => '0') ; elsif rising_edge(CLOCK) then case iHSTATE is -- wait trigger when 0 => if ( iHTRG = '1' ) then iHSTATE <= 1 ; iHCNT <= 0 ; else iHSTATE <= 0 ; end if ; -- judge when 1 => if ( iHCNT = PCNT_MAX ) then iHSTATE <= 5 ; else iHSTATE <= 2 ; end if ; -- get data when 2 => iHSTATE <= 3 ; iTDAT <= iBUFOB ; -- update pointer when 3 => iHSTATE <= 4 ; iBUFADRB <= iBUFADRB + '1' ; if ( iHCNT /= 0 ) then if ( conv_integer(iTDAT) > conv_integer(iSMAX) ) then iSMAX <= iTDAT ; iSMAXL <= conv_std_logic_vector(iHCNT,8) ; end if ; if ( conv_integer(iTDAT) < conv_integer(iSMIN) ) then iSMIN <= iTDAT ; iSMINL <= conv_std_logic_vector(iHCNT,8) ; end if ; end if ; -- update when 4 => iHCNT <= iHCNT + 1 ; iHSTATE <= 1 ; -- set parameters when 5 => iHSTATE <= 6 ; iPX <= iSMAXL ; iPY <= iSMINL ; -- get result when 6 => iHSTATE <= 7 ; if ( iHFLAG = 0 ) then iLTOP <= iSRESULT ; end if ; if ( iHFLAG = 1 ) then iLMIDDLE <= iSRESULT ; end if ; if ( iHFLAG = 2 ) then iLBOTTOM <= iSRESULT ; end if ; -- update line when 7 => iHSTATE <= 8 ; iHFLAG <= iHFLAG + 1 ; -- judge when 8 => if ( iHFLAG = 3 ) then iHSTATE <= 9 ; iBUFADRB <= (others => '0') ; iHFLAG <= 0 ; else iHSTATE <= 1 ; iSMAX <= (others => '0') ; iSMIN <= (others => '0') ; iSMAXL <= (others => '0') ; iSMINL <= (others => '0') ; end if ; -- return first state when 9 => iHSTATE <= 0 ; -- default when others => iHSTATE <= 0 ; end case ; end if ; end process ;  特異点からセンサーデータを生成する  回路は、別途定義します。
VHDLコード  最終のVHDLコードは、バスインタフェースをはじめ  として、画像処理、モータ制御、エンコーダなどを  含めています。  バスインタフェースを採用したので  画像処理対象の3ラインを0〜119の  範囲で指定できるようになりました。  マイクロコンピュータから見ると、FPGAは  レジスタを持ったプロセッサになります。  レジスタは、次のように割当てしています。  カッコ内は、リード、ライト、双方向の種別。  バスインタフェースの制御は、GP2の8ビット  を次のように割当してあります。  データ入出力はGP3を使いますが、外部から  レジスタにデータを与える時、トリガー(TRG)  を利用し、確実にレジスタに値が格納される  仕様にしました。  マイクロコンピュータは、データバスGP3とは  双方向に使えるポートを使うことになります。  VHDLコードは、以下です。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; Library UNISIM; use UNISIM.vcomponents.all; entity mcrvcxy is generic ( TOPX : integer := 9 ; XMAX : integer := 500 ; TOPY : integer := 5 ; YMAX : integer := 17 ; TOPZ : integer := 8 ; ZMAX : integer := 150 ; LCNT_MAX : integer := 60 ; PCNT_MAX : integer := 160 ; QMAX : integer := 480 --; ); port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- camera interface VS : in std_logic ; HREF : in std_logic ; PCLK : in std_logic ; CDAT : in std_logic_vector(7 downto 0) ; -- run output GLED : out std_logic ; -- run RLED : out std_logic ; -- cross white line -- MOTOR control FOUT : out std_logic_vector(1 downto 0) ; ROUT : out std_logic_vector(1 downto 0) ; -- encoder ENPULSE : in std_logic ; -- BUS interface control signals GP2 : in std_logic_vector(7 downto 0) ; -- BUS interface GP3 : inout std_logic_vector(7 downto 0) --; ); end mcrvcxy; architecture Behavioral of mcrvcxy is -- component 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 ; -- component PWM component pwmax is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- input DIR : in std_logic_vector(1 downto 0) ; -- duty ratio DUTY : in std_logic_vector(6 downto 0) ; -- output POUT : out std_logic_vector(1 downto 0) --; ); end component; -- generate sensor data component gen_senx is port ( -- input PINX : in std_logic_vector(7 downto 0); PINY : in std_logic_vector(7 downto 0); -- output POUTX : out std_logic_vector(7 downto 0) --; ) ; end component ; -- clock signal iMCLK : std_logic ; signal iPWMCLK : std_logic ; signal iSCLK : std_logic ; signal iICLK : std_logic ; signal iPCLK : std_logic ; -- camera sequencer signal iCSTATE : std_logic_vector(2 downto 0) ; signal iLCNT : std_logic_vector(5 downto 0); signal iPCNT : std_logic_vector(7 downto 0); signal iCDATA : std_logic_vector(7 downto 0) ; signal iCTRG : std_logic ; signal iVSTRG : std_logic ; signal iCTRG_SFT : std_logic_vector(2 downto 0) ; signal iPTRG : std_logic ; signal iVS_SFT : std_logic_vector(2 downto 0) ; signal iPCLK_SFT : std_logic_vector(2 downto 0) ; signal iTARGET_L : std_logic ; signal iTARGET_N : std_logic ; -- A port sequencer signal iATRG_SFT : std_logic_vector(1 downto 0) ; signal iATRG : std_logic ; signal iASTATE : std_logic_vector(2 downto 0) ; -- camera buffer memory signal iDOA : std_logic_vector( 7 downto 0) ; signal iDOB : std_logic_vector( 7 downto 0) ; signal iDOPA : std_logic_vector( 0 downto 0) ; signal iDOPB : std_logic_vector( 0 downto 0) ; signal iADDRA : std_logic_vector(10 downto 0) ; signal iADDRB : std_logic_vector(10 downto 0) ; signal iDIA : std_logic_vector( 7 downto 0) ; signal iWEA : std_logic ; -- B port sequencer signal iBTRG : std_logic ; signal iBSTATE : integer range 0 to 7 ; signal iBCNT : integer range 0 to 160 ; signal iBFLAG : integer range 0 to 3 ; signal iNOW_DATA : std_logic_vector(7 downto 0) ; signal iHTRG : std_logic ; -- buffer memory signal iBUFOA : std_logic_vector( 7 downto 0) ; signal iBUFOB : std_logic_vector( 7 downto 0) ; signal iBUFDOPA : std_logic_vector( 0 downto 0) ; signal iBUFDOPB : std_logic_vector( 0 downto 0) ; signal iBUFADRA : std_logic_vector(10 downto 0) ; signal iBUFADRB : std_logic_vector(10 downto 0) ; signal iBUFA : std_logic_vector( 7 downto 0) ; signal iBWEA : std_logic ; -- generate sensor data signal iHCNT : integer range 0 to 160 ; signal iHFLAG : integer range 0 to 3 ; signal iHSTATE : integer range 0 to 9 ; signal iSMAX : std_logic_vector(7 downto 0) ; signal iSMIN : std_logic_vector(7 downto 0) ; signal iSMAXL : std_logic_vector(7 downto 0) ; signal iSMINL : std_logic_vector(7 downto 0) ; signal iPX : std_logic_vector(7 downto 0) ; signal iPY : std_logic_vector(7 downto 0) ; signal iTDAT : std_logic_vector(7 downto 0) ; signal iSRESULT : std_logic_vector(7 downto 0) ; -- MOTOR control signal iFOUT : std_logic_vector(1 downto 0) ; signal iROUT : std_logic_vector(1 downto 0) ; -- BUS interface signal iDIRR : std_logic_vector(1 downto 0) ; signal iDIRF : std_logic_vector(1 downto 0) ; signal iDUTYF : std_logic_vector(6 downto 0) ; signal iDUTYR : std_logic_vector(6 downto 0) ; signal iDSTATE : std_logic_vector(1 downto 0) ; -- trigger signal iTRG : std_logic ; signal iTRG_SFT : std_logic_vector(2 downto 0) ; -- sensor register file signal iDAT : std_logic_vector(7 downto 0) ; signal iLTOP : std_logic_vector(7 downto 0) ; signal iLMIDDLE : std_logic_vector(7 downto 0) ; signal iLBOTTOM : std_logic_vector(7 downto 0) ; -- target line register file signal iTLTOP : std_logic_vector(7 downto 0) ; signal iTLMIDDLE : std_logic_vector(7 downto 0) ; signal iTLBOTTOM : std_logic_vector(7 downto 0) ; -- encoder counter signal iECNT : std_logic_vector(15 downto 0) ; signal iENPLS_SFT : std_logic_vector( 2 downto 0) ; signal iENPLS : std_logic ; begin -- component clock generator (10MHz/1000 = 10kHz) CLKZX: clkgenx generic map (TOPX,XMAX) port map (nRESET,iMCLK,iPWMCLK); -- component clock generator (10kHz/33 = about 300Hz) CLKY : clkgenx generic map (TOPY,YMAX) port map (nRESET,iMCLK,iSCLK); -- component clock generator (300Hz/300 = about 1Hz) CLKZ : clkgenx generic map (TOPZ,ZMAX) port map (nRESET,iSCLK,iICLK); -- front motor control FRONTX : pwmax port map (nRESET,iPWMCLK,iDIRF,iDUTYF,iFOUT); -- rear motor control REARX : pwmax port map (nRESET,iPWMCLK,iDIRR,iDUTYR,iROUT); -- generate sensor data GSENX : gen_senx port map (iPX,iPY,iSRESULT); -- generate master clock (10MHz) process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iMCLK <= '0' ; elsif rising_edge( CLOCK ) then iMCLK <= not iMCLK ; end if ; end process ; -- RAMB16_S9_S9: 2k x 8 + 1 Parity bit Dual-Port RAM -- graphic data buffer RAMB16_S9_S9_inst : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => iDOA, -- Port A 8-bit Data Output DOB => iDOB, -- Port B 8-bit Data Output DOPA => iDOPA, -- Port A 1-bit Parity Output DOPB => iDOPB, -- Port B 1-bit Parity Output ADDRA => iADDRA, -- Port A 11-bit Address Input ADDRB => iADDRB, -- Port B 11-bit Address Input CLKA => CLOCK, -- Port A Clock CLKB => CLOCK, -- Port B Clock DIA => iDIA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port-B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '0', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- RAMB16_S9_S9: 2k x 8 + 1 Parity bit Dual-Port RAM -- sensor buffer XBUFX : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => iBUFOA, -- Port A 8-bit Data Output DOB => iBUFOB, -- Port B 8-bit Data Output DOPA => iBUFDOPA, -- Port A 1-bit Parity Output DOPB => iBUFDOPB, -- Port B 1-bit Parity Output ADDRA => iBUFADRA, -- Port A 11-bit Address Input ADDRB => iBUFADRB, -- Port B 11-bit Address Input CLKA => CLOCK, -- Port A Clock CLKB => CLOCK, -- Port B Clock DIA => iBUFA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port-B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '0', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iBWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- monitor output GLED <= not iICLK ; RLED <= iICLK ; -- trigger process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iTRG_SFT <= "000" ; iCTRG_SFT <= "000" ; elsif rising_edge(CLOCK) then iTRG_SFT <= iTRG_SFT(1 downto 0) & GP2(6) ; iCTRG_SFT <= iCTRG_SFT(1 downto 0) & GP2(7) ; end if ; end process ; iTRG <= '1' when ( iTRG_SFT = "011" ) else '0' ; iCTRG <= '1' when ( iCTRG_SFT = "011" ) else '0' ; -- BUS interface (write from external circuit) process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iDSTATE <= "00" ; -- state control -- direction iDIRF <= "00" ; -- forward iDIRR <= "00" ; -- reverse -- duty ratio iDUTYF <= (others => '0') ; iDUTYR <= (others => '0') ; -- target line iTLTOP <= (others => '0') ; iTLMIDDLE <= (others => '0') ; iTLBOTTOM <= (others => '0') ; elsif rising_edge( CLOCK ) then case conv_integer(iDSTATE) is -- wait trigger when 0 => if ( iTRG = '1' ) then iDSTATE <= "01" ; else iDSTATE <= "00" ; end if ; -- latch when 1 => iDSTATE <= "11" ; -- direction forword if ( GP2(5 downto 0) = "10000" ) then iDIRF <= GP3(1 downto 0) ; end if ; -- forword duty if ( GP2(5 downto 0) = "10001" ) then iDUTYF <= GP3(6 downto 0) ; end if ; -- direction reverse if ( GP2(5 downto 0) = "10010" ) then iDIRR <= GP3(1 downto 0) ; end if ; -- reverse duty if ( GP2(5 downto 0) = "10001" ) then iDUTYR <= GP3(6 downto 0) ; end if ; -- target line TOP if ( GP2(5 downto 0) = "101011" ) then iTLTOP <= GP3 ; end if ; -- target line MIDDLE if ( GP2(5 downto 0) = "101100" ) then iTLMIDDLE <= GP3 ; end if ; -- target line BOTTOM if ( GP2(5 downto 0) = "101101" ) then iTLBOTTOM <= GP3 ; end if ; -- deliver when 3 => iDSTATE <= "10" ; -- return first state when 2 => iDSTATE <= "00" ; -- default when others => iDSTATE <= "00" ; end case ; end if ; end process ; -- motor control output FOUT <= iFOUT ; ROUT <= iROUT ; -- BUS interface data GP3 <= iDAT when ( GP2(5 downto 4) = "01" ) else (others => 'Z'); -- register file iDAT <= "000000" & iDIRF when ( GP2(3 downto 0) = "0000" ) else -- front direction '0' & iDUTYF when ( GP2(3 downto 0) = "0001" ) else -- front duty "000000" & iDIRR when ( GP2(3 downto 0) = "0010" ) else -- rear direction '0' & iDUTYR when ( GP2(3 downto 0) = "0011" ) else -- rear duty iLTOP when ( GP2(3 downto 0) = "1000" ) else -- TOP iLMIDDLE when ( GP2(3 downto 0) = "1001" ) else -- MIDDLE iLBOTTOM when ( GP2(3 downto 0) = "1010" ) else -- BOTTOM iTLTOP when ( GP2(3 downto 0) = "1011" ) else -- target line TOP iTLMIDDLE when ( GP2(3 downto 0) = "1100" ) else -- target line MIDDLE iTLBOTTOM when ( GP2(3 downto 0) = "1101" ) else -- target line BOTTOM iECNT(15 downto 8) when ( GP2(3 downto 0) = "1110" ) else -- encoder counter(high) iECNT( 7 downto 0) when ( GP2(3 downto 0) = "1111" ) else -- encoder counter(low) X"FF" ; -- dummy -- pixel clock iPCLK <= HREF and PCLK ; -- synchronizer process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iVS_SFT <= "000" ; iPCLK_SFT <= "000" ; elsif rising_edge(iMCLK) then iVS_SFT <= iVS_SFT(1 downto 0) & VS ; iPCLK_SFT <= iPCLK_SFT(1 downto 0) & iPCLK ; end if ; end process ; iVSTRG <= '1' when ( iVS_SFT = "011" or iVS_SFT = "001" ) else '0' ; iPTRG <= '1' when ( iPCLK_SFT = "011" or iPCLK_SFT = "001" ) else '0' ; -- camera sequencer process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iCSTATE <= "000" ; iLCNT <= (others => '0') ; iPCNT <= (others => '0') ; iCDATA <= (others => '0') ; iATRG_SFT <= "00" ; elsif rising_edge(iMCLK) then case conv_integer(iCSTATE) is -- wait trigger from micom when 0 => if ( iCTRG = '1' ) then iCSTATE <= "001" ; -- next else iCSTATE <= "000" ; -- stay end if ; -- wait VSYNC trigger when 1 => if ( iVSTRG = '1' ) then iCSTATE <= "010" ; -- next iLCNT <= (others => '0') ; iLCNT <= (others => '0') ; iCDATA <= (others => '0') ; else iCSTATE <= "001" ; -- stay end if ; -- judge line counter when 2 => if ( conv_integer(iLCNT) = LCNT_MAX ) then iCSTATE <= "111" ; -- exit else iCSTATE <= "011" ; -- loop end if ; -- store even data (Y) when 3 => if ( iPTRG = '1' ) then iCSTATE <= "100" ; -- next iCDATA <= CDAT ; iATRG_SFT <= iATRG_SFT(0) & '1' ; else iCSTATE <= "011" ; -- stay end if ; -- skip odd data (U or V) when 4 => if ( iPTRG = '1' ) then iCSTATE <= "101" ; -- next iATRG_SFT <= iATRG_SFT(0) & '1' ; else iCSTATE <= "100" ; -- state : 4 end if ; -- judge pixel counter when 5 => if ( conv_integer(iPCNT) = PCNT_MAX ) then iCSTATE <= "110" ; -- state : 6 iPCNT <= (others => '0'); iLCNT <= iLCNT + '1' ; else iPCNT <= iPCNT + '1' ; iCSTATE <= "011" ; -- state : 3 end if ; iATRG_SFT <= "00" ; -- new line handling when 6 => iCSTATE <= "010" ; -- state : 2 -- return first state when 7 => iCSTATE <= "000" ; -- state : 0 -- default when others => iCSTATE <= "000" ; end case ; end if ; end process ; -- store Y data trigger iATRG <= iATRG_SFT(1) and iATRG_SFT(0) ; -- target line flag iTARGET_L <= '1' when ( iLCNT = conv_integer(iTLTOP) ) else '1' when ( iLCNT = conv_integer(iTLMIDDLE) ) else '1' when ( iLCNT = conv_integer(iTLBOTTOM) ) else '0' ; -- target line flag iTARGET_N <= '1' when ( iLCNT = conv_integer(iTLTOP+1) ) else '1' when ( iLCNT = conv_integer(iTLMIDDLE+1) ) else '1' when ( iLCNT = conv_integer(iTLBOTTOM+1) ) else '0' ; -- wakeup B port sequencer iBTRG <= '1' when ( iCSTATE = "110" ) else '0' ; -- A port sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iASTATE <= "000" ; iADDRA <= (others => '0') ; elsif rising_edge(CLOCK) then case conv_integer(iASTATE) is -- wait trigger when 0 => if ( iATRG = '1' and iTARGET_L = '1' ) then iASTATE <= "001" ; -- state : 1 else iASTATE <= "000" ; -- state : 0 end if ; -- transfer data when 1 => iDIA <= iCDATA ; iASTATE <= "011" ; -- state : 3 -- send write trigger when 3 => iASTATE <= "111" ; -- state : 7 -- address increment when 7 => iADDRA <= iADDRA + '1' ; iASTATE <= "110" ; -- state : 6 -- judge when 6 => if ( conv_integer(iADDRA) = QMAX ) then iASTATE <= "100" ; -- state : 4 else iASTATE <= "000" ; -- state : 0 end if ; -- return first state when 4 => iASTATE <= "000" ; -- state : 0 iADDRA <= (others => '0') ; -- default when others => iASTATE <= "000" ; end case ; end if ; end process ; iWEA <= '1' when ( iASTATE = "111" ) else '0' ; -- B port sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iBSTATE <= 0 ; iBCNT <= 0 ; iBFLAG <= 0 ; iNOW_DATA <= (others => '0') ; iADDRB <= (others => '0') ; iBUFADRA <= (others => '0') ; iBUFA <= (others => '0') ; elsif rising_edge(CLOCK) then case iBSTATE is -- wait trigger when 0 => if ( iBTRG = '1' and iTARGET_N = '1' ) then iBSTATE <= 1 ; iBCNT <= PCNT_MAX ; else iBSTATE <= 0 ; end if ; -- judge when 1 => if ( iBCNT = 0 ) then iBSTATE <= 5 ; else iBSTATE <= 2 ; end if ; -- get data when 2 => iBSTATE <= 3 ; if ( iBCNT = PCNT_MAX ) then iBUFA <= (others => '0'); iNOW_DATA <= iDOB ; else iBUFA <= iNOW_DATA - iDOB ; iNOW_DATA <= iDOB ; end if ; -- store data with trigger when 3 => iBSTATE <= 4 ; -- update when 4 => iADDRB <= iADDRB + '1' ; iBUFADRA <= iBUFADRA + '1' ; iBCNT <= iBCNT - 1 ; iBSTATE <= 1 ; -- send trigger when 5 => iBSTATE <= 6 ; iBFLAG <= iBFLAG + 1 ; -- judge exit when 6 => iBSTATE <= 7 ; if ( iBFLAG = 3 ) then iBFLAG <= 0 ; iADDRB <= (others => '0') ; iBUFADRA <= (others => '0') ; end if ; -- return first state when 7 => iBSTATE <= 0 ; -- default when others => iBSTATE <= 0 ; end case ; end if ; end process ; -- store data with trigger iBWEA <= '1' when ( iBSTATE = 3 ) else '0' ; -- send trigger iHTRG <= '1' when ( iBSTATE = 5 ) else '0' ; -- sensor data generator sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iHSTATE <= 0 ; iHCNT <= 0 ; iHFLAG <= 0 ; iSMAX <= (others => '0') ; iSMIN <= (others => '0') ; iSMAXL <= (others => '0') ; iSMINL <= (others => '0') ; iBUFADRB <= (others => '0') ; iPX <= (others => '0') ; iPY <= (others => '0') ; elsif rising_edge(CLOCK) then case iHSTATE is -- wait trigger when 0 => if ( iHTRG = '1' ) then iHSTATE <= 1 ; iHCNT <= 0 ; else iHSTATE <= 0 ; end if ; -- judge when 1 => if ( iHCNT = PCNT_MAX ) then iHSTATE <= 5 ; else iHSTATE <= 2 ; end if ; -- get data when 2 => iHSTATE <= 3 ; iTDAT <= iBUFOB ; -- update pointer when 3 => iHSTATE <= 4 ; iBUFADRB <= iBUFADRB + '1' ; if ( iHCNT /= 0 ) then if ( conv_integer(iTDAT) > conv_integer(iSMAX) ) then iSMAX <= iTDAT ; iSMAXL <= conv_std_logic_vector(iHCNT,8) ; end if ; if ( conv_integer(iTDAT) < conv_integer(iSMIN) ) then iSMIN <= iTDAT ; iSMINL <= conv_std_logic_vector(iHCNT,8) ; end if ; end if ; -- update when 4 => iHCNT <= iHCNT + 1 ; iHSTATE <= 1 ; -- set parameters when 5 => iHSTATE <= 6 ; iPX <= iSMAXL ; iPY <= iSMINL ; -- get result when 6 => iHSTATE <= 7 ; if ( iHFLAG = 0 ) then iLTOP <= iSRESULT ; end if ; if ( iHFLAG = 1 ) then iLMIDDLE <= iSRESULT ; end if ; if ( iHFLAG = 2 ) then iLBOTTOM <= iSRESULT ; end if ; -- update line when 7 => iHSTATE <= 8 ; iHFLAG <= iHFLAG + 1 ; -- judge when 8 => if ( iHFLAG = 3 ) then iHSTATE <= 9 ; iBUFADRB <= (others => '0') ; iHFLAG <= 0 ; else iHSTATE <= 1 ; iSMAX <= (others => '0') ; iSMIN <= (others => '0') ; iSMAXL <= (others => '0') ; iSMINL <= (others => '0') ; end if ; -- return first state when 9 => iHSTATE <= 0 ; -- default when others => iHSTATE <= 0 ; end case ; end if ; end process ; -- encoder counter process (nRESET,iSCLK) begin if ( nRESET = '0' ) then iENPLS_SFT <= "000" ; elsif rising_edge(iSCLK) then iENPLS_SFT <= iENPLS_SFT(1 downto 0) & ENPULSE ; end if ; end process ; iENPLS <= '1' when ( iENPLS_SFT = "011" or iENPLS_SFT = "001" ) else '0' ; process (nRESET,iSCLK) begin if ( nRESET = '0' ) then iECNT <= (others => '0') ; elsif falling_edge(iSCLK) then if ( iENPLS = '1' ) then iECNT <= iECNT + '1' ; end if ; end if ; end process ; end Behavioral;  ピンアサインは、UCFファイルに記述です。 # Spartan3 50k gates # system NET "CLOCK" LOC = "P36" ; NET "nRESET" LOC = "P50" ; # G0 (motor control and rotary encoder pulse) NET "FOUT<0>" LOC = "P1" | DRIVE = 8 | SLEW = SLOW ; NET "FOUT<1>" LOC = "P2" | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<0>" LOC = "P4" | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<1>" LOC = "P5" | DRIVE = 8 | SLEW = SLOW ; NET "ENPULSE" LOC = "P11" ; # G1 (camera data) NET "CDAT<0>" LOC = "P13" | DRIVE = 8 | SLEW = SLOW ; NET "CDAT<1>" LOC = "P14" | DRIVE = 8 | SLEW = SLOW ; NET "CDAT<2>" LOC = "P15" | DRIVE = 8 | SLEW = SLOW ; NET "CDAT<3>" LOC = "P16" | DRIVE = 8 | SLEW = SLOW ; NET "CDAT<4>" LOC = "P17" | DRIVE = 8 | SLEW = SLOW ; NET "CDAT<5>" LOC = "P21" | DRIVE = 8 | SLEW = SLOW ; NET "CDAT<6>" LOC = "P22" | DRIVE = 8 | SLEW = SLOW ; NET "CDAT<7>" LOC = "P23" | DRIVE = 8 | SLEW = SLOW ; # group G2 (camera control signals) NET "PCLK" LOC = "P27" ; NET "VS" LOC = "P28" ; NET "HREF" LOC = "P30" ; # Bank 4 (2.5V) G3 NET "GLED" LOC = "P47" | DRIVE = 8 | SLEW = SLOW ; NET "RLED" LOC = "P49" | DRIVE = 8 | SLEW = SLOW ; # G3 (BUS data) NET "GP3<0>" LOC = "P55" ; NET "GP3<1>" LOC = "P59" ; NET "GP3<2>" LOC = "P60" ; NET "GP3<3>" LOC = "P61" ; NET "GP3<4>" LOC = "P62" ; NET "GP3<5>" LOC = "P63" ; NET "GP3<6>" LOC = "P64" ; NET "GP3<7>" LOC = "P65" ; # G4 NET "GP2<0>" LOC = "P67" ; NET "GP2<1>" LOC = "P68" ; NET "GP2<2>" LOC = "P71" ; NET "GP2<3>" LOC = "P72" ; NET "GP2<4>" LOC = "P74" ; NET "GP2<5>" LOC = "P75" ; NET "GP2<6>" LOC = "P79" ; NET "GP2<7>" LOC = "P80" ;  50kゲートのFPGAに、各回路を入れることが  できましたが、どの程度の容量を使っている  のかを、レポートファイルで見てみます。  論理ゲートは、50kの約半分で46%  DualPortMemoryは2ブロック利用  しているので、50%。  I/Oピンは、58%となり、まだ余裕  があります。  利用しているカメラは、QQVGAの画像サイズから  さらに切り出す区画を指定できるので、80x120で  動かすとして、レジスタやコンポーネント数を  減らせます。  画像サイズを80x120と仮定した場合、コードは  以下となります。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; -- Library UNISIM; use UNISIM.vcomponents.all; entity mcrvcxy is generic ( TOPX : integer := 9 ; XMAX : integer := 500 ; TOPY : integer := 5 ; YMAX : integer := 17 ; TOPZ : integer := 8 ; ZMAX : integer := 150 ; LCNT_MAX : integer := 60 ; PCNT_MAX : integer := 80 ; QMAX : integer := 240 --; ); port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- camera interface VS : in std_logic ; HREF : in std_logic ; PCLK : in std_logic ; CDAT : in std_logic_vector(7 downto 0) ; -- run output GLED : out std_logic ; -- run RLED : out std_logic ; -- cross white line -- MOTOR control FOUT : out std_logic_vector(1 downto 0) ; ROUT : out std_logic_vector(1 downto 0) ; -- encoder ENPULSE : in std_logic ; -- BUS interface control signals GP2 : in std_logic_vector(7 downto 0) ; -- BUS interface GP3 : inout std_logic_vector(7 downto 0) --; ); end mcrvcxy; architecture Behavioral of mcrvcxy is -- component 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 ; -- component PWM component pwmax is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- input DIR : in std_logic_vector(1 downto 0) ; -- duty ratio DUTY : in std_logic_vector(6 downto 0) ; -- output POUT : out std_logic_vector(1 downto 0) --; ); end component; -- clock signal iMCLK : std_logic ; signal iPWMCLK : std_logic ; signal iSCLK : std_logic ; signal iICLK : std_logic ; signal iPCLK : std_logic ; -- camera sequencer signal iCSTATE : integer range 0 to 7 ; signal iLCNT : integer range 0 to LCNT_MAX ; signal iPCNT : integer range 0 to PCNT_MAX ; signal iCDATA : std_logic_vector(7 downto 0) ; signal iCTRG : std_logic ; signal iVSTRG : std_logic ; signal iCTRG_SFT : std_logic_vector(2 downto 0) ; signal iPTRG : std_logic ; signal iVS_SFT : std_logic_vector(2 downto 0) ; signal iPCLK_SFT : std_logic_vector(2 downto 0) ; signal iTARGET_L : std_logic ; signal iTARGET_N : std_logic ; -- A port sequencer signal iATRG_SFT : std_logic_vector(1 downto 0) ; signal iATRG : std_logic ; signal iASTATE : std_logic_vector(2 downto 0) ; -- camera buffer memory signal iDOB : std_logic_vector( 7 downto 0) ; signal iADDRA : std_logic_vector(10 downto 0) ; signal iADDRB : std_logic_vector(10 downto 0) ; signal iDIA : std_logic_vector( 7 downto 0) ; signal iWEA : std_logic ; -- B port sequencer signal iBTRG : std_logic ; signal iBSTATE : integer range 0 to 7 ; signal iBCNT : integer range 0 to PCNT_MAX ; signal iBFLAG : integer range 0 to 3 ; signal iNOW_DATA : std_logic_vector(7 downto 0) ; signal iHTRG : std_logic ; -- buffer memory signal iBUFOB : std_logic_vector( 7 downto 0) ; signal iBUFADRA : std_logic_vector(10 downto 0) ; signal iBUFADRB : std_logic_vector(10 downto 0) ; signal iBUFA : std_logic_vector( 7 downto 0) ; signal iBWEA : std_logic ; -- store differencial data sequencer signal iHCNT : integer range 0 to PCNT_MAX ; signal iHFLAG : integer range 0 to 3 ; signal iHSTATE : integer range 0 to 10 ; signal iSMAX : std_logic_vector(7 downto 0) ; signal iSMIN : std_logic_vector(7 downto 0) ; signal iSMAXL : integer range 0 to PCNT_MAX ; signal iSMINL : integer range 0 to PCNT_MAX ; signal iTDAT : std_logic_vector(7 downto 0) ; signal iSRESULT : integer range 0 to 255 ; -- MOTOR control signal iFOUT : std_logic_vector(1 downto 0) ; signal iROUT : std_logic_vector(1 downto 0) ; -- BUS interface signal iDIRR : std_logic_vector(1 downto 0) ; signal iDIRF : std_logic_vector(1 downto 0) ; signal iDUTYF : std_logic_vector(6 downto 0) ; signal iDUTYR : std_logic_vector(6 downto 0) ; signal iDSTATE : std_logic_vector(1 downto 0) ; -- trigger signal iTRG : std_logic ; signal iTRG_SFT : std_logic_vector(2 downto 0) ; -- sensor register file signal iDAT : std_logic_vector(7 downto 0) ; signal iLTOP : std_logic_vector(7 downto 0) ; signal iLMIDDLE : std_logic_vector(7 downto 0) ; signal iLBOTTOM : std_logic_vector(7 downto 0) ; -- target line register file signal iTLTOP : std_logic_vector(7 downto 0) ; signal iTLMIDDLE : std_logic_vector(7 downto 0) ; signal iTLBOTTOM : std_logic_vector(7 downto 0) ; -- encoder counter signal iECNT : std_logic_vector(15 downto 0) ; signal iENPLS_SFT : std_logic_vector( 2 downto 0) ; signal iENPLS : std_logic ; begin -- component clock generator (10MHz/1000 = 10kHz) CLKX: clkgenx generic map (TOPX,XMAX) port map (nRESET,iMCLK,iPWMCLK); -- component clock generator (10kHz/33 = about 300Hz) CLKY : clkgenx generic map (TOPY,YMAX) port map (nRESET,iMCLK,iSCLK); -- component clock generator (300Hz/300 = about 1Hz) CLKZ : clkgenx generic map (TOPZ,ZMAX) port map (nRESET,iSCLK,iICLK); -- front motor control FRONTX : pwmax port map (nRESET,iPWMCLK,iDIRF,iDUTYF,iFOUT); -- rear motor control REARX : pwmax port map (nRESET,iPWMCLK,iDIRR,iDUTYR,iROUT); -- generate master clock (10MHz) process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iMCLK <= '0' ; elsif rising_edge( CLOCK ) then iMCLK <= not iMCLK ; end if ; end process ; -- RAMB16_S9_S9: 2k x 8 + 1 Parity bit Dual-Port RAM -- graphic data buffer RAMB16_S9_S9_inst : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => open, -- Port A 8-bit Data Output DOB => iDOB, -- Port B 8-bit Data Output DOPA => open, -- Port A 1-bit Parity Output DOPB => open, -- Port B 1-bit Parity Output ADDRA => iADDRA, -- Port A 11-bit Address Input ADDRB => iADDRB, -- Port B 11-bit Address Input CLKA => CLOCK, -- Port A Clock CLKB => CLOCK, -- Port B Clock DIA => iDIA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port-B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '0', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- RAMB16_S9_S9: 2k x 8 + 1 Parity bit Dual-Port RAM -- sensor buffer XBUFX : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => open, -- Port A 8-bit Data Output DOB => iBUFOB, -- Port B 8-bit Data Output DOPA => open, -- Port A 1-bit Parity Output DOPB => open, -- Port B 1-bit Parity Output ADDRA => iBUFADRA, -- Port A 11-bit Address Input ADDRB => iBUFADRB, -- Port B 11-bit Address Input CLKA => CLOCK, -- Port A Clock CLKB => CLOCK, -- Port B Clock DIA => iBUFA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port-B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '0', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iBWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- monitor output GLED <= not iICLK ; RLED <= iICLK ; -- trigger process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iTRG_SFT <= "000" ; iCTRG_SFT <= "000" ; elsif rising_edge(CLOCK) then iTRG_SFT <= iTRG_SFT(1 downto 0) & GP2(6) ; iCTRG_SFT <= iCTRG_SFT(1 downto 0) & GP2(7) ; end if ; end process ; iTRG <= '1' when ( iTRG_SFT = "011" ) else '0' ; iCTRG <= '1' when ( iCTRG_SFT = "011" ) else '0' ; -- BUS interface (write from external circuit) process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iDSTATE <= "00" ; -- state control -- direction iDIRF <= "00" ; -- forward iDIRR <= "00" ; -- reverse -- duty ratio iDUTYF <= (others => '0') ; iDUTYR <= (others => '0') ; -- target line iTLTOP <= (others => '0') ; iTLMIDDLE <= (others => '0') ; iTLBOTTOM <= (others => '0') ; elsif rising_edge( CLOCK ) then case conv_integer(iDSTATE) is -- wait trigger when 0 => if ( iTRG = '1' ) then iDSTATE <= "01" ; else iDSTATE <= "00" ; end if ; -- latch when 1 => iDSTATE <= "11" ; -- direction forword if ( GP2(5 downto 0) = "100000" ) then iDIRF <= GP3(1 downto 0) ; end if ; -- forword duty if ( GP2(5 downto 0) = "100001" ) then iDUTYF <= GP3(6 downto 0) ; end if ; -- direction reverse if ( GP2(5 downto 0) = "100010" ) then iDIRR <= GP3(1 downto 0) ; end if ; -- reverse duty if ( GP2(5 downto 0) = "100001" ) then iDUTYR <= GP3(6 downto 0) ; end if ; -- target line TOP if ( GP2(5 downto 0) = "101011" ) then iTLTOP <= GP3 ; end if ; -- target line MIDDLE if ( GP2(5 downto 0) = "101100" ) then iTLMIDDLE <= GP3 ; end if ; -- target line BOTTOM if ( GP2(5 downto 0) = "101101" ) then iTLBOTTOM <= GP3 ; end if ; -- deliver when 3 => iDSTATE <= "10" ; -- return first state when 2 => iDSTATE <= "00" ; -- default when others => iDSTATE <= "00" ; end case ; end if ; end process ; -- motor control output FOUT <= iFOUT ; ROUT <= iROUT ; -- BUS interface data GP3 <= iDAT when ( GP2(5 downto 4) = "01" ) else (others => 'Z'); -- register file iDAT <= "000000" & iDIRF when ( GP2(3 downto 0) = "0000" ) else -- front direction '0' & iDUTYF when ( GP2(3 downto 0) = "0001" ) else -- front duty "000000" & iDIRR when ( GP2(3 downto 0) = "0010" ) else -- rear direction '0' & iDUTYR when ( GP2(3 downto 0) = "0011" ) else -- rear duty iLTOP when ( GP2(3 downto 0) = "1000" ) else -- TOP iLMIDDLE when ( GP2(3 downto 0) = "1001" ) else -- MIDDLE iLBOTTOM when ( GP2(3 downto 0) = "1010" ) else -- BOTTOM iTLTOP when ( GP2(3 downto 0) = "1011" ) else -- target line TOP iTLMIDDLE when ( GP2(3 downto 0) = "1100" ) else -- target line MIDDLE iTLBOTTOM when ( GP2(3 downto 0) = "1101" ) else -- target line BOTTOM iECNT(15 downto 8) when ( GP2(3 downto 0) = "1110" ) else -- encoder counter(high) iECNT( 7 downto 0) when ( GP2(3 downto 0) = "1111" ) else -- encoder counter(low) X"FF" ; -- dummy -- pixel clock iPCLK <= HREF and PCLK ; -- synchronizer process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iVS_SFT <= "000" ; iPCLK_SFT <= "000" ; elsif rising_edge(iMCLK) then iVS_SFT <= iVS_SFT(1 downto 0) & VS ; iPCLK_SFT <= iPCLK_SFT(1 downto 0) & iPCLK ; end if ; end process ; iVSTRG <= '1' when ( iVS_SFT = "011" or iVS_SFT = "001" ) else '0' ; iPTRG <= '1' when ( iPCLK_SFT = "011" or iPCLK_SFT = "001" ) else '0' ; -- camera sequencer process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iCSTATE <= 0 ; iLCNT <= 0 ; iPCNT <= 0 ; iCDATA <= (others => '0') ; iATRG_SFT <= "00" ; elsif rising_edge(iMCLK) then case iCSTATE is -- wait trigger from micom when 0 => if ( iCTRG = '1' ) then iCSTATE <= 1 ; -- next else iCSTATE <= 0 ; -- stay end if ; -- wait VSYNC trigger when 1 => if ( iVSTRG = '1' ) then iCSTATE <= 2 ; -- next iLCNT <= 0 ; iCDATA <= (others => '0') ; else iCSTATE <= 1 ; -- stay end if ; -- judge line counter when 2 => if ( iLCNT = LCNT_MAX ) then iCSTATE <= 7 ; -- exit else iCSTATE <= 3 ; -- loop end if ; -- store even data (Y) when 3 => if ( iPTRG = '1' ) then iCSTATE <= 4 ; -- next iCDATA <= CDAT ; iATRG_SFT <= iATRG_SFT(0) & '1' ; else iCSTATE <= 3 ; -- stay end if ; -- skip odd data (U or V) when 4 => if ( iPTRG = '1' ) then iCSTATE <= 5 ; -- next iATRG_SFT <= iATRG_SFT(0) & '1' ; else iCSTATE <= 4 ; -- state : 4 end if ; -- judge pixel counter when 5 => if ( iPCNT = PCNT_MAX ) then iCSTATE <= 6 ; -- state : 6 iPCNT <= 0 ; iLCNT <= iLCNT + 1 ; else iPCNT <= iPCNT + 1 ; iCSTATE <= 3 ; -- state : 3 end if ; iATRG_SFT <= "00" ; -- new line handling when 6 => iCSTATE <= 2 ; -- state : 2 -- return first state when 7 => iCSTATE <= 0 ; -- state : 0 -- default when others => iCSTATE <= 0 ; end case ; end if ; end process ; -- store Y data trigger iATRG <= iATRG_SFT(1) and iATRG_SFT(0) ; -- target line flag iTARGET_L <= '1' when ( iLCNT = conv_integer(iTLTOP) ) else '1' when ( iLCNT = conv_integer(iTLMIDDLE) ) else '1' when ( iLCNT = conv_integer(iTLBOTTOM) ) else '0' ; -- target next line flag iTARGET_N <= '1' when ( iLCNT = conv_integer(iTLTOP+1) ) else '1' when ( iLCNT = conv_integer(iTLMIDDLE+1) ) else '1' when ( iLCNT = conv_integer(iTLBOTTOM+1) ) else '0' ; -- wakeup B port sequencer iBTRG <= '1' when ( iCSTATE = 6 ) else '0' ; -- A port sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iASTATE <= "000" ; iADDRA <= (others => '0') ; elsif rising_edge(CLOCK) then case conv_integer(iASTATE) is -- wait trigger when 0 => if ( iATRG = '1' and iTARGET_L = '1' ) then iASTATE <= "001" ; -- state : 1 else iASTATE <= "000" ; -- state : 0 end if ; -- transfer data when 1 => iDIA <= iCDATA ; iASTATE <= "011" ; -- state : 3 -- send write trigger when 3 => iASTATE <= "111" ; -- state : 7 -- address increment when 7 => iADDRA <= iADDRA + '1' ; iASTATE <= "110" ; -- state : 6 -- judge when 6 => if ( conv_integer(iADDRA) = QMAX ) then iASTATE <= "100" ; -- state : 4 else iASTATE <= "000" ; -- state : 0 end if ; -- return first state when 4 => iASTATE <= "000" ; -- state : 0 iADDRA <= (others => '0') ; -- default when others => iASTATE <= "000" ; end case ; end if ; end process ; iWEA <= '1' when ( iASTATE = "111" ) else '0' ; -- B port sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iBSTATE <= 0 ; iBCNT <= 0 ; iBFLAG <= 0 ; iNOW_DATA <= (others => '0') ; iADDRB <= (others => '0') ; iBUFADRA <= (others => '0') ; iBUFA <= (others => '0') ; elsif rising_edge(CLOCK) then case iBSTATE is -- wait trigger when 0 => if ( iBTRG = '1' and iTARGET_N = '1' ) then iBSTATE <= 1 ; iBCNT <= PCNT_MAX ; else iBSTATE <= 0 ; end if ; -- judge when 1 => if ( iBCNT = 0 ) then iBSTATE <= 5 ; else iBSTATE <= 2 ; end if ; -- get data when 2 => iBSTATE <= 3 ; if ( iBCNT = PCNT_MAX ) then iBUFA <= (others => '0'); iNOW_DATA <= iDOB ; else iBUFA <= iNOW_DATA - iDOB ; iNOW_DATA <= iDOB ; end if ; -- store data with trigger when 3 => iBSTATE <= 4 ; -- update when 4 => iADDRB <= iADDRB + '1' ; iBUFADRA <= iBUFADRA + '1' ; iBCNT <= iBCNT - 1 ; iBSTATE <= 1 ; -- send trigger when 5 => iBSTATE <= 6 ; iBFLAG <= iBFLAG + 1 ; -- judge exit when 6 => iBSTATE <= 7 ; if ( iBFLAG = 3 ) then iBFLAG <= 0 ; iBCNT <= 0 ; iADDRB <= (others => '0') ; iBUFADRA <= (others => '0') ; end if ; -- return first state when 7 => iBSTATE <= 0 ; -- default when others => iBSTATE <= 0 ; end case ; end if ; end process ; -- store data with trigger iBWEA <= '1' when ( iBSTATE = 3 ) else '0' ; -- send trigger iHTRG <= '1' when ( iBSTATE = 5 ) else '0' ; -- sensor data generator sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iHSTATE <= 0 ; iHCNT <= 0 ; iHFLAG <= 0 ; iSMAX <= (others => '0') ; iSMIN <= (others => '0') ; iBUFADRB <= (others => '0') ; iSMAXL <= 0 ; iSMINL <= 0 ; iSRESULT <= 0 ; elsif rising_edge(CLOCK) then case iHSTATE is -- wait trigger when 0 => if ( iHTRG = '1' ) then iHSTATE <= 1 ; iHCNT <= 0 ; else iHSTATE <= 0 ; end if ; -- judge when 1 => if ( iHCNT = PCNT_MAX ) then iHSTATE <= 5 ; else iHSTATE <= 2 ; end if ; -- get data when 2 => iHSTATE <= 3 ; iTDAT <= iBUFOB ; -- update pointer when 3 => iHSTATE <= 4 ; iBUFADRB <= iBUFADRB + '1' ; if ( iHCNT /= 0 ) then if ( conv_integer(iTDAT) > conv_integer(iSMAX) ) then iSMAX <= iTDAT ; iSMAXL <= iHCNT ; end if ; if ( conv_integer(iTDAT) < conv_integer(iSMIN) ) then iSMIN <= iTDAT ; iSMINL <= iHCNT ; end if ; end if ; -- update when 4 => iHCNT <= iHCNT + 1 ; iHSTATE <= 1 ; -- calculate when 5 => iHSTATE <= 6 ; iSRESULT <= iSMAXL + iSMINL ; -- set parameter when 6 => iHSTATE <= 7 ; iTDAT <= conv_std_logic_vector(iSRESULT,8) ; -- get result when 7 => iHSTATE <= 8 ; if ( iHFLAG = 0 ) then iLTOP <= iTDAT ; end if ; if ( iHFLAG = 1 ) then iLMIDDLE <= iTDAT ; end if ; if ( iHFLAG = 2 ) then iLBOTTOM <= iTDAT ; end if ; -- update line when 8 => iHSTATE <= 9 ; iHFLAG <= iHFLAG + 1 ; -- judge when 9 => if ( iHFLAG = 3 ) then iHSTATE <= 10 ; iBUFADRB <= (others => '0') ; iHFLAG <= 0 ; else iHSTATE <= 1 ; iSMAX <= (others => '0') ; iSMIN <= (others => '0') ; iSMAXL <= 0 ; iSMINL <= 0 ; end if ; -- return first state when 10 => iHSTATE <= 0 ; -- default when others => iHSTATE <= 0 ; end case ; end if ; end process ; -- encoder counter process (nRESET,iSCLK) begin if ( nRESET = '0' ) then iENPLS_SFT <= "000" ; elsif rising_edge(iSCLK) then iENPLS_SFT <= iENPLS_SFT(1 downto 0) & ENPULSE ; end if ; end process ; iENPLS <= '1' when ( iENPLS_SFT = "011" or iENPLS_SFT = "001" ) else '0' ; process (nRESET,iSCLK) begin if ( nRESET = '0' ) then iECNT <= (others => '0') ; elsif falling_edge(iSCLK) then if ( iENPLS = '1' ) then iECNT <= iECNT + '1' ; end if ; end if ; end process ; end Behavioral;  このVHDLコードが利用しているコンポーネントは  2つあります。clkgenx、pwmaxです。  コンポーネントclkgenxの内容は、以下です。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity clkgenx is generic ( TOPX : integer ; RMAX : integer --; ); port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- output CLKOUT : out std_logic -- ; ); end clkgenx; architecture Behavioral of clkgenx is signal iSCNT : std_logic_vector(TOPX-1 downto 0); signal iCLK : std_logic ; begin -- output CLKOUT <= iCLK ; -- divider process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSCNT <= (others => '0') ; iCLK <= '0' ; elsif rising_edge(CLOCK) then if ( conv_integer(iSCNT) = RMAX ) then iSCNT <= (others => '0') ; iCLK <= not iCLK ; else iSCNT <= iSCNT + '1' ; end if ; end if ; end process ; end Behavioral;  コンポーネントpwmaxの内容は、以下です。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity pwmax is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- input DIR : in std_logic_vector(1 downto 0) ; -- duty ratio DUTY : in std_logic_vector(6 downto 0) ; -- output POUT : out std_logic_vector(1 downto 0) --; ); end pwmax; architecture Behavioral of pwmax is signal iCNT : std_logic_vector(6 downto 0) ; signal iDUTY : std_logic_vector(6 downto 0) ; signal iOUT : std_logic ; signal iPOUT : std_logic_vector(1 downto 0) ; begin -- output POUT <= iPOUT ; -- internal iPOUT(0) <= iOUT when ( DIR = "01" ) else '0' ; iPOUT(1) <= iOUT when ( DIR = "10" ) else '0' ; iOUT <= '1' when ( conv_integer(iCNT) < conv_integer(iDUTY) ) else '0' ; -- counter process(nRESET,CLOCK) begin if ( nRESET = '0' ) then iCNT <= (others => '0') ; iDUTY <= (others => '0') ; elsif rising_edge( CLOCK ) then if ( conv_integer(iCNT) = 100 ) then iCNT <= (others => '0') ; iDUTY <= DUTY ; else iCNT <= iCNT + '1' ; end if ; end if; end process; end Behavioral;  センサーデータは、カメラで最初のコース状況を  撮影して得られるセンターライン位置を格納して  おき、それからの偏りで表現します。  上の場合、センターは81となります。  同じ方法でカメラから時々刻々変換する  コースを撮影して、新しいセンター位置  を求めます。81より小さいと車体は右に  あるので、左にステアリングを切ること  に。81より大きいと、右に切ります。  ファームウエアでは、スタートする前に  センター位置を確定しておきます。  差分処理でコースのセンターラインが左、中央、右に  見える時、どのような値をとるかをシミュレーション  してみます。 #include <stdio.h> #include <math.h> typedef unsigned char UBYTE ; typedef signed char SBYTE ; typedef unsigned short UWORD ; typedef signed short SWORD ; #define OFF 0 #define ON OFF+1 #define LMAX 60 #define PMAX 80 #define OFFSET 15 UBYTE pbegin ; UBYTE pend ; UBYTE gdat[PMAX] ; UBYTE dpm[PMAX] ; SBYTE dpmd[PMAX] ; void test_handler(void); void show_mem(SBYTE *x); void main(void) { int i ; int j ; /* loop */ for ( j = 0 ; j < 16 ; j++ ) { pbegin = 5 * j ; pend = pbegin + OFFSET ; /* initialize */ for ( i = 0 ; i < PMAX ; i++ ) { *(gdat+i) = 0 ; /* judge */ if ( pbegin <= i && i <= pend ) { *(gdat+i) = 250 ; } } /* processing */ test_handler(); /* show */ for ( i = 0 ; i < PMAX ; i++ ) { printf("%03d ",*(dpm+i)); if ( (i % 16) == 15 ) putchar('\n'); } putchar('\n'); show_mem( dpmd ); } } void test_handler(void) { int i ; UBYTE tmp ; SBYTE xtmp ; /* transfer */ xtmp = 0 ; for ( i = 0 ; i < PMAX ; i++ ) { /* camera data copy */ tmp = *(gdat+i) ; /* copy */ *(dpm+i) = tmp ; /* difference */ if ( i == 0 ) { *(dpmd+i) = tmp ; } else { *(dpmd+i) = xtmp - tmp; } xtmp = tmp ; } } void show_mem(SBYTE *x) { UBYTE i ; SBYTE max ; SBYTE min ; SBYTE lmax ; SBYTE lmin ; for ( i = 0 ; i < PMAX ; i++ ) { /* show */ printf("%03d ",*(x+i)); if ( (i % 16) == 15 ) putchar('\n'); /* judge */ if ( i == 0 ) { max = *(x+i) ; min = *(x+i) ; } else { if ( max < *(x+i) ) { max = *(x+i) ; lmax = i ; } if ( min > *(x+i) ) { min = *(x+i) ; lmin = i ; } } } printf("loc : %d %d sum : %d dis : %d \n",lmax,lmin,lmax+lmin,abs(lmax-lmin)); for ( i = 0 ; i < 64 ; i++ ) { putchar('-'); if ( i == 63 ) { putchar('\n'); } } }  I/Oリダイレクトで、画像データと差分によるライン  位置を示す値の変化を見ます。 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 1 80 sum : 81 dis : 79 ---------------------------------------------------------------- 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 5 21 sum : 26 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 10 26 sum : 36 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 15 31 sum : 46 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 20 36 sum : 56 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 25 41 sum : 66 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 30 46 sum : 76 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 35 51 sum : 86 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 40 56 sum : 96 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 45 61 sum : 106 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 50 66 sum : 116 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 000 000 000 000 000 loc : 55 71 sum : 126 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 -06 000 000 000 loc : 60 76 sum : 136 dis : 16 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 000 000 000 000 000 loc : 65 80 sum : 145 dis : 15 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 000 000 000 000 000 loc : 70 80 sum : 150 dis : 10 ---------------------------------------------------------------- 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 250 250 250 250 250 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 006 000 000 000 000 loc : 75 80 sum : 155 dis : 5 ----------------------------------------------------------------  シミュレーション結果から、左片側白線、右片側白線、全白線  については、別の判定が必要になることが分かります。  差分の最大値、最小値の位置の差を利用して  幅を求めます。この幅を、走行前のセンター  ラインを撮影しているときに計算して記憶し  利用します。記憶しているライン幅よりも大  なら、クランク、レーンチェンジ用マーカと  判断します。  シミュレーションから、カメラで画像データを取得すると  同時に、差分を計算してしまうと、より高速に画像を処理  できることがわかりました。  画像データ保存と同時に、差分求値の動作イメージは以下。  VHDLコードを、次のように変更します。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; Library UNISIM; use UNISIM.vcomponents.all; entity mcrvcxy is generic ( TOPX : integer := 9 ; XMAX : integer := 500 ; TOPY : integer := 5 ; YMAX : integer := 17 ; TOPZ : integer := 8 ; ZMAX : integer := 150 ; LCNT_MAX : integer := 60 ; PCNT_MAX : integer := 80 ; QMAX : integer := 240 --; 80pixel x 3line ); port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- camera interface VS : in std_logic ; HREF : in std_logic ; PCLK : in std_logic ; CDAT : in std_logic_vector(7 downto 0) ; -- run output GLED : out std_logic ; -- run RLED : out std_logic ; -- cross white line -- MOTOR control FOUT : out std_logic_vector(1 downto 0) ; ROUT : out std_logic_vector(1 downto 0) ; -- encoder ENPULSE : in std_logic ; -- BUS interface control signals GP2 : in std_logic_vector(7 downto 0) ; -- BUS interface GP3 : inout std_logic_vector(7 downto 0) --; ); end mcrvcxy; architecture Behavioral of mcrvcxy is -- component 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 ; -- component PWM component pwmax is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- input DIR : in std_logic_vector(1 downto 0) ; -- duty ratio DUTY : in std_logic_vector(6 downto 0) ; -- output POUT : out std_logic_vector(1 downto 0) --; ); end component; -- clock signal iMCLK : std_logic ; signal iPWMCLK : std_logic ; signal iSCLK : std_logic ; signal iICLK : std_logic ; signal iPCLK : std_logic ; -- camera sequencer signal iCSTATE : integer range 0 to 7 ; signal iLCNT : integer range 0 to LCNT_MAX ; signal iPCNT : integer range 0 to PCNT_MAX ; signal iCDATA : std_logic_vector(7 downto 0) ; signal iCDIF : std_logic_vector(7 downto 0) ; signal iCTMP : std_logic_vector(7 downto 0) ; signal iCTRG : std_logic ; signal iVSTRG : std_logic ; signal iCTRG_SFT : std_logic_vector(2 downto 0) ; signal iPTRG : std_logic ; signal iVS_SFT : std_logic_vector(2 downto 0) ; signal iPCLK_SFT : std_logic_vector(2 downto 0) ; signal iTARGET_L : std_logic ; signal iTARGET_N : std_logic ; -- A port sequencer signal iATRG_SFT : std_logic_vector(1 downto 0) ; signal iATRG : std_logic ; signal iASTATE : std_logic_vector(2 downto 0) ; -- camera buffer memory signal iADDRA : std_logic_vector(10 downto 0) ; signal iADDRB : std_logic_vector(10 downto 0) ; signal iDIA : std_logic_vector( 7 downto 0) ; signal iDOB : std_logic_vector( 7 downto 0) ; signal iWEA : std_logic ; signal iHTRG : std_logic ; -- buffer memory signal iBDOB : std_logic_vector( 7 downto 0) ; signal iBADRA : std_logic_vector(10 downto 0) ; signal iBADRB : std_logic_vector(10 downto 0) ; signal iBDIA : std_logic_vector( 7 downto 0) ; signal iBWEA : std_logic ; -- store differencial data sequencer signal iHCNT : integer range 0 to PCNT_MAX ; signal iHFLAG : integer range 0 to 3 ; signal iHSTATE : integer range 0 to 10 ; signal iHLOC : integer range 0 to 255 ; signal iHDISTANCE : integer range 0 to 127 ; signal iHDAT : std_logic_vector(7 downto 0) ; signal iSMAX : std_logic_vector(7 downto 0) ; signal iSMIN : std_logic_vector(7 downto 0) ; signal iSMAXL : integer range 0 to PCNT_MAX ; signal iSMINL : integer range 0 to PCNT_MAX ; -- MOTOR control signal iFOUT : std_logic_vector(1 downto 0) ; signal iROUT : std_logic_vector(1 downto 0) ; -- BUS interface signal iDIRR : std_logic_vector(1 downto 0) ; signal iDIRF : std_logic_vector(1 downto 0) ; signal iDUTYF : std_logic_vector(6 downto 0) ; signal iDUTYR : std_logic_vector(6 downto 0) ; signal iDSTATE : std_logic_vector(1 downto 0) ; -- trigger signal iTRG : std_logic ; signal iTRG_SFT : std_logic_vector(2 downto 0) ; -- sensor register file (location) signal iDAT : std_logic_vector(7 downto 0) ; signal iLTOP : std_logic_vector(7 downto 0) ; signal iLMIDDLE : std_logic_vector(7 downto 0) ; signal iLBOTTOM : std_logic_vector(7 downto 0) ; -- sensor register file (distance) signal iLTOPD : std_logic_vector(6 downto 0) ; signal iLMIDDLED : std_logic_vector(6 downto 0) ; signal iLBOTTOMD : std_logic_vector(6 downto 0) ; -- target line register file signal iTLTOP : std_logic_vector(7 downto 0) ; signal iTLMIDDLE : std_logic_vector(7 downto 0) ; signal iTLBOTTOM : std_logic_vector(7 downto 0) ; -- encoder counter signal iECNT : std_logic_vector(15 downto 0) ; signal iENPLS_SFT : std_logic_vector( 2 downto 0) ; signal iENPLS : std_logic ; begin -- component clock generator (10MHz/1000 = 10kHz) CLKX: clkgenx generic map (TOPX,XMAX) port map (nRESET,iMCLK,iPWMCLK); -- component clock generator (10kHz/33 = about 300Hz) CLKY : clkgenx generic map (TOPY,YMAX) port map (nRESET,iMCLK,iSCLK); -- component clock generator (300Hz/300 = about 1Hz) CLKZ : clkgenx generic map (TOPZ,ZMAX) port map (nRESET,iSCLK,iICLK); -- front motor control FRONTX : pwmax port map (nRESET,iPWMCLK,iDIRF,iDUTYF,iFOUT); -- rear motor control REARX : pwmax port map (nRESET,iPWMCLK,iDIRR,iDUTYR,iROUT); -- generate master clock (10MHz) process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iMCLK <= '0' ; elsif rising_edge( CLOCK ) then iMCLK <= not iMCLK ; end if ; end process ; -- RAMB16_S9_S9: 2k x 8 + 1 Parity bit Dual-Port RAM -- graphic data buffer RAMB16_S9_S9_inst : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => open, -- Port A 8-bit Data Output DOB => iDOB, -- Port B 8-bit Data Output DOPA => open, -- Port A 1-bit Parity Output DOPB => open, -- Port B 1-bit Parity Output ADDRA => iADDRA, -- Port A 11-bit Address Input ADDRB => iADDRB, -- Port B 11-bit Address Input CLKA => CLOCK, -- Port A Clock CLKB => CLOCK, -- Port B Clock DIA => iDIA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port-B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '0', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- RAMB16_S9_S9: 2k x 8 + 1 Parity bit Dual-Port RAM -- sensor buffer XBUFX : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => open, -- Port A 8-bit Data Output DOB => iBDOB, -- Port B 8-bit Data Output DOPA => open, -- Port A 1-bit Parity Output DOPB => open, -- Port B 1-bit Parity Output ADDRA => iBADRA, -- Port A 11-bit Address Input ADDRB => iBADRB, -- Port B 11-bit Address Input CLKA => CLOCK, -- Port A Clock CLKB => CLOCK, -- Port B Clock DIA => iBDIA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port-B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '0', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iBWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- monitor output GLED <= not iICLK ; RLED <= iICLK ; -- trigger process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iTRG_SFT <= "000" ; iCTRG_SFT <= "000" ; elsif rising_edge(CLOCK) then iTRG_SFT <= iTRG_SFT(1 downto 0) & GP2(6) ; iCTRG_SFT <= iCTRG_SFT(1 downto 0) & GP2(7) ; end if ; end process ; iTRG <= '1' when ( iTRG_SFT = "011" ) else '0' ; iCTRG <= '1' when ( iCTRG_SFT = "011" ) else '0' ; -- BUS interface (write from external circuit) process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iDSTATE <= "00" ; -- state control -- direction iDIRF <= "00" ; -- forward iDIRR <= "00" ; -- reverse -- duty ratio iDUTYF <= (others => '0') ; iDUTYR <= (others => '0') ; -- target line iTLTOP <= (others => '0') ; iTLMIDDLE <= (others => '0') ; iTLBOTTOM <= (others => '0') ; elsif rising_edge( CLOCK ) then case conv_integer(iDSTATE) is -- wait trigger when 0 => if ( iTRG = '1' ) then iDSTATE <= "01" ; else iDSTATE <= "00" ; end if ; -- latch when 1 => iDSTATE <= "11" ; -- direction forword if ( GP2(5 downto 0) = "100000" ) then iDIRF <= GP3(1 downto 0) ; end if ; -- forword duty if ( GP2(5 downto 0) = "100001" ) then iDUTYF <= GP3(6 downto 0) ; end if ; -- direction reverse if ( GP2(5 downto 0) = "100010" ) then iDIRR <= GP3(1 downto 0) ; end if ; -- reverse duty if ( GP2(5 downto 0) = "100001" ) then iDUTYR <= GP3(6 downto 0) ; end if ; -- target line TOP if ( GP2(5 downto 0) = "101011" ) then iTLTOP <= GP3 ; end if ; -- target line MIDDLE if ( GP2(5 downto 0) = "101100" ) then iTLMIDDLE <= GP3 ; end if ; -- target line BOTTOM if ( GP2(5 downto 0) = "101101" ) then iTLBOTTOM <= GP3 ; end if ; -- deliver when 3 => iDSTATE <= "10" ; -- return first state when 2 => iDSTATE <= "00" ; -- default when others => iDSTATE <= "00" ; end case ; end if ; end process ; -- motor control output FOUT <= iFOUT ; ROUT <= iROUT ; -- BUS interface data GP3 <= iDAT when ( GP2(5 downto 4) = "01" ) else (others => 'Z'); -- register file iDAT <= "000000" & iDIRF when ( GP2(3 downto 0) = "0000" ) else -- front direction '0' & iDUTYF when ( GP2(3 downto 0) = "0001" ) else -- front duty "000000" & iDIRR when ( GP2(3 downto 0) = "0010" ) else -- rear direction '0' & iDUTYR when ( GP2(3 downto 0) = "0011" ) else -- rear duty '0' & iLTOPD when ( GP2(3 downto 0) = "0100" ) else -- TOP distance '0' & iLMIDDLED when ( GP2(3 downto 0) = "0101" ) else -- MIDDLE distance '0' & iLBOTTOMD when ( GP2(3 downto 0) = "0110" ) else -- BOTTOM distance iDOB when ( GP2(3 downto 0) = "0111" ) else -- camera data iLTOP when ( GP2(3 downto 0) = "1000" ) else -- TOP iLMIDDLE when ( GP2(3 downto 0) = "1001" ) else -- MIDDLE iLBOTTOM when ( GP2(3 downto 0) = "1010" ) else -- BOTTOM iTLTOP when ( GP2(3 downto 0) = "1011" ) else -- target line TOP iTLMIDDLE when ( GP2(3 downto 0) = "1100" ) else -- target line MIDDLE iTLBOTTOM when ( GP2(3 downto 0) = "1101" ) else -- target line BOTTOM iECNT(15 downto 8) when ( GP2(3 downto 0) = "1110" ) else -- encoder counter(high) iECNT( 7 downto 0) when ( GP2(3 downto 0) = "1111" ) else -- encoder counter(low) X"FF" ; -- dummy -- pixel clock iPCLK <= HREF and PCLK ; -- synchronizer process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iVS_SFT <= "000" ; iPCLK_SFT <= "000" ; elsif rising_edge(iMCLK) then iVS_SFT <= iVS_SFT(1 downto 0) & VS ; iPCLK_SFT <= iPCLK_SFT(1 downto 0) & iPCLK ; end if ; end process ; iVSTRG <= '1' when ( iVS_SFT = "011" or iVS_SFT = "001" ) else '0' ; iPTRG <= '1' when ( iPCLK_SFT = "011" or iPCLK_SFT = "001" ) else '0' ; -- camera sequencer process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iCSTATE <= 0 ; iLCNT <= 0 ; iPCNT <= 0 ; iCDATA <= (others => '0') ; iCDIF <= (others => '0') ; iCTMP <= (others => '0') ; iATRG_SFT <= "00" ; elsif rising_edge(iMCLK) then case iCSTATE is -- wait trigger from micom when 0 => if ( iCTRG = '1' ) then iCSTATE <= 1 ; -- next else iCSTATE <= 0 ; -- stay end if ; -- wait VSYNC trigger when 1 => if ( iVSTRG = '1' ) then iCSTATE <= 2 ; -- next iLCNT <= 0 ; iCDATA <= (others => '0') ; iCDIF <= (others => '0') ; iCTMP <= (others => '0') ; else iCSTATE <= 1 ; -- stay end if ; -- judge line counter when 2 => if ( iLCNT = LCNT_MAX ) then iCSTATE <= 7 ; -- exit else iCSTATE <= 3 ; -- loop end if ; -- store even data (Y) when 3 => if ( iPTRG = '1' ) then iCSTATE <= 4 ; -- next iCDATA <= CDAT ; if ( iPCNT = 0 ) then iCDIF <= CDAT ; iCTMP <= CDAT ; else iCDIF <= iCTMP - CDAT ; iCTMP <= CDAT ; end if ; iATRG_SFT <= iATRG_SFT(0) & '1' ; else iCSTATE <= 3 ; -- stay end if ; -- skip odd data (U or V) and store data when 4 => if ( iPTRG = '1' ) then iCSTATE <= 5 ; -- next iATRG_SFT <= iATRG_SFT(0) & '1' ; else iCSTATE <= 4 ; -- state : 4 end if ; -- judge pixel counter when 5 => if ( iPCNT = PCNT_MAX ) then iCSTATE <= 6 ; -- state : 6 iPCNT <= 0 ; iLCNT <= iLCNT + 1 ; else iPCNT <= iPCNT + 1 ; iCSTATE <= 3 ; -- state : 3 end if ; iATRG_SFT <= "00" ; -- new line handling when 6 => iCSTATE <= 2 ; -- state : 2 -- return first state when 7 => iCSTATE <= 0 ; -- state : 0 -- default when others => iCSTATE <= 0 ; end case ; end if ; end process ; -- store Y data trigger iATRG <= iATRG_SFT(1) and iATRG_SFT(0) ; -- target line flag iTARGET_L <= '1' when ( iLCNT = conv_integer(iTLTOP) ) else '1' when ( iLCNT = conv_integer(iTLMIDDLE) ) else '1' when ( iLCNT = conv_integer(iTLBOTTOM) ) else '0' ; -- target next line flag iTARGET_N <= '1' when ( iLCNT = conv_integer(iTLTOP+1) ) else '1' when ( iLCNT = conv_integer(iTLMIDDLE+1) ) else '1' when ( iLCNT = conv_integer(iTLBOTTOM+1) ) else '0' ; -- A port sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iASTATE <= "000" ; iADDRA <= (others => '0') ; iADDRB <= (others => '0') ; iBADRA <= (others => '0') ; elsif rising_edge(CLOCK) then case conv_integer(iASTATE) is -- wait trigger when 0 => if ( iATRG = '1' and iTARGET_L = '1' ) then iASTATE <= "001" ; -- state : 1 else iASTATE <= "000" ; -- state : 0 end if ; -- transfer data when 1 => iDIA <= iCDATA ; iBDIA <= iCDIF ; iASTATE <= "011" ; -- state : 3 -- send write trigger when 3 => iASTATE <= "111" ; -- state : 7 -- address increment when 7 => iADDRA <= iADDRA + '1' ; iADDRB <= iADDRB + '1' ; iBADRA <= iBADRA + '1' ; iASTATE <= "110" ; -- state : 6 -- judge when 6 => if ( conv_integer(iADDRA) = QMAX ) then iASTATE <= "100" ; -- state : 4 else iASTATE <= "000" ; -- state : 0 end if ; -- return first state when 4 => iASTATE <= "000" ; -- state : 0 iADDRA <= (others => '0') ; iADDRB <= (others => '0') ; iBADRA <= (others => '0') ; -- default when others => iASTATE <= "000" ; end case ; end if ; end process ; -- camera data store trigger iWEA <= '1' when ( iASTATE = "111" ) else '0' ; -- diffrencial data store trigger iBWEA <= '1' when ( iASTATE = "111" ) else '0' ; -- calculate location trigger iHTRG <= '1' when ( iTARGET_N = '1' and iCSTATE = 6 ) else '0' ; -- sensor data generator sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iHSTATE <= 0 ; iHCNT <= 0 ; iHFLAG <= 0 ; iHDAT <= (others => '0') ; iSMAX <= (others => '0') ; iSMIN <= (others => '0') ; iBADRB <= (others => '0') ; iSMAXL <= 0 ; iSMINL <= 0 ; iHLOC <= 0 ; iHDISTANCE <= 0 ; elsif rising_edge(CLOCK) then case iHSTATE is -- wait trigger when 0 => if ( iHTRG = '1' ) then iHSTATE <= 1 ; -- next iHCNT <= 0 ; else iHSTATE <= 0 ; -- stay end if ; -- judge when 1 => if ( iHCNT = PCNT_MAX ) then iHSTATE <= 5 ; -- exit loop else iHSTATE <= 2 ; -- handling loop end if ; -- get data when 2 => iHSTATE <= 3 ; -- next iHDAT <= iBDOB ; -- compare when 3 => iHSTATE <= 4 ; -- next if ( iHCNT = 0 ) then iSMAX <= iHDAT ; iSMIN <= iHDAT ; iSMAXL <= iHCNT ; iSMINL <= iHCNT ; else if ( conv_integer(iHDAT) > conv_integer(iSMAX) ) then iSMAX <= iHDAT ; iSMAXL <= iHCNT ; end if ; if ( conv_integer(iHDAT) < conv_integer(iSMIN) ) then iSMIN <= iHDAT ; iSMINL <= iHCNT ; end if ; end if ; -- update pointer and address when 4 => iHSTATE <= 1 ; -- loop iHCNT <= iHCNT + 1 ; iBADRB <= iBADRB + '1' ; -- calculate location and distance when 5 => iHSTATE <= 6 ; -- next -- location iHLOC <= iSMAXL + iSMINL ; -- distance if ( iSMAXL > iSMINL ) then iHDISTANCE <= iSMAXL - iSMINL ; else iHDISTANCE <= iSMINL - iSMAXL ; end if ; -- store parameters when 6 => iHSTATE <= 7 ; -- next if ( iHFLAG = 0 ) then iLTOP <= conv_std_logic_vector(iHLOC,8) ; iLTOPD <= conv_std_logic_vector(iHDISTANCE,7) ; end if ; if ( iHFLAG = 1 ) then iLMIDDLE <= conv_std_logic_vector(iHLOC,8) ; iLMIDDLED <= conv_std_logic_vector(iHDISTANCE,7) ; end if ; if ( iHFLAG = 2 ) then iLBOTTOM <= conv_std_logic_vector(iHLOC,8) ; iLBOTTOMD <= conv_std_logic_vector(iHDISTANCE,7) ; end if ; -- update line when 7 => iHSTATE <= 8 ; -- next iHFLAG <= iHFLAG + 1 ; -- judge last line when 8 => iHSTATE <= 9 ; -- next if ( iHFLAG = 3 ) then iBADRB <= (others => '0') ; iHFLAG <= 0 ; end if ; -- return first state when 9 => iHSTATE <= 0 ; -- default when others => iHSTATE <= 0 ; end case ; end if ; end process ; -- encoder counter process (nRESET,iSCLK) begin if ( nRESET = '0' ) then iENPLS_SFT <= "000" ; elsif rising_edge(iSCLK) then iENPLS_SFT <= iENPLS_SFT(1 downto 0) & ENPULSE ; end if ; end process ; iENPLS <= '1' when ( iENPLS_SFT = "011" or iENPLS_SFT = "001" ) else '0' ; process (nRESET,iSCLK) begin if ( nRESET = '0' ) then iECNT <= (others => '0') ; elsif falling_edge(iSCLK) then if ( iENPLS = '1' ) then iECNT <= iECNT + '1' ; end if ; end if ; end process ; end Behavioral;  FPGA内部のレジスタファイル中に、位置と  ライン幅の各8ビットデータを保存します。  レジスタファイル中のパラメータは以下。  マイクロコンピュータから見ると、バスインタフェース  は、そのままで、内部レジスタ情報が変わったように  見えます。  ファームウエアは、コースラインの位置と幅の  2パラメータからセンサーデータを生成します。  カメラからラスター方向のデータを取得するたびに  差分を計算しているので、位置と幅を求める回路は  カメラデータ入力回路と並列に動きます。  差分計算用シーケンサをなくしたので、利用する  カウンタとレジスタの数を一気に減らせました。
目次

inserted by FC2 system