目次
前
次
画像処理変更
デジタル回路で画像処理を実現するには
DualPortMemoryを利用するのが定石です。
DualPortMemoryのイメージは、下図です。
アクセスポートが2つあり、左右からデータを
リードライトできます。もうひとつのポートに
ついて考える必要はありません。
よく利用される使い方は、バッファです。
左はライト専用、右をリード専用として
画像取得と画像操作の回路を独立させます。
左右で相手のタイミングを考えずに、データ
を出し入れできるので、Workstation等の
BitMapDisplay用回路を高速化かつ単純化する
目的でよく利用されました。
ところが、現在DualPortMemoryは殆ど入手
できません。入手可能でも納期、費用は
それなりに覚悟しなければなりません。
現実的な選択肢は、FPGAの中に入っている
DualPortMemoryを使うことです。
今回利用するXilinxのFPGAは、Spartan3で
18kビットのDualPortMemoryを4個内蔵して
います。
2kバイトのDualPortMemoryで利用することを考え
コンポーネントRAMB16_S9_S9を組込んで、動作を
テストしました。
このコンポーネントを利用するためには、以下の
信号配置の意味を理解しなければなりません。
信号を7種類に分けて機能を理解します。
- CLOCKA CLOCKB 動作クロック
- ENA ENAB 動作クロックイネーブル
- WEA WEB データライトイネーブル
- DIA DIB 入力データ
- DIAP DIBP 入力パリティデータ
- DOA DOB 出力データ
- DOAP DOBP 出力パリティデータ
- SSRA SSRB 同期リセットイネーブル
デジタル回路の中で、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プロセッサのコマンドは、以下のように決め
テストしました。
- ? ヘルプ
- A ライト用8ビットアドレス設定
- D ライト用8ビットデータ設定
- W DualPortMemoryにデータライト
- L リード用8ビットアドレス設定
- S ライト用アドレス、データ、リード用アドレス表示
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は
レジスタを持ったプロセッサになります。
レジスタは、次のように割当てしています。
カッコ内は、リード、ライト、双方向の種別。
- register0(R/W) 前輪左右方向指定
- register1(R/W) 前輪回転DUTY比
- register2(R/W) 後輪左右方向指定
- register3(R/W) 後輪左右方向指定
- register4(R/W) (予約)
- register5(R/W) (予約)
- register6(R/W) (予約)
- register7(R/W) (予約)
- register8(R) TOPラインセンサーデータ
- register9(R) MIDDLEラインセンサーデータ
- registerA(R) BOTTOMラインセンサーデータ
- registerB(R/W) TOPライン位置
- registerC(R/W) MIDDLEライン位置
- registerD(R/W) BOTTOMライン位置
- registerE(R) パルスカウント(上位)
- registerF(R) パルスカウント(下位)
バスインタフェースの制御は、GP2の8ビット
を次のように割当してあります。
- GP2.7 カメラシャッタートリガー(CENA)
- GP2.6 データトリガー(TRG)
- GP2.5 バスライトイネーブル(WE)
- GP2.4 バスリードイネーブル(OE)
- GP2.3 レジスタアドレス3(LSEL3)
- GP2.2 レジスタアドレス2(LSEL2)
- GP2.1 レジスタアドレス1(LSEL1)
- GP2.0 レジスタアドレス0(LSEL0)
データ入出力は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ビットデータを保存します。
レジスタファイル中のパラメータは以下。
- register0(R/W) 前輪左右方向指定
- register1(R/W) 前輪回転DUTY比
- register2(R/W) 後輪左右方向指定
- register3(R/W) 後輪左右方向指定
- register4(R) TOPラインのライン幅
- register5(R) MIDDLEラインのライン幅
- register6(R) BOTTOMラインのライン幅
- register7(R) カメラデータ
- register8(R) TOPラインのコースライン位置
- register9(R) MIDDLEラインのコースライン位置
- registerA(R) BOTTOMラインのコースライン位置
- registerB(R/W) TOPライン位置
- registerC(R/W) MIDDLEライン位置
- registerD(R/W) BOTTOMライン位置
- registerE(R) パルスカウント(上位)
- registerF(R) パルスカウント(下位)
マイクロコンピュータから見ると、バスインタフェース
は、そのままで、内部レジスタ情報が変わったように
見えます。
ファームウエアは、コースラインの位置と幅の
2パラメータからセンサーデータを生成します。
カメラからラスター方向のデータを取得するたびに
差分を計算しているので、位置と幅を求める回路は
カメラデータ入力回路と並列に動きます。
差分計算用シーケンサをなくしたので、利用する
カウンタとレジスタの数を一気に減らせました。
目次
前
次