目次
前
落ち葉ひろい
mugen2013マシンは、ARM+FPGAのコラボレーションで
制御を実現しました。
ARMは32ビットプロセッサなので、ネットサーフィン
すれば、必要情報の入手は比較的楽でした。
FPGAはデジタル回路を設計し、それを封入するのが
前提です。動作確認に、3つのVHDLコードを作成した
ので、備忘録として残しておきます。
作成VHDLコードのリストは、以下です。
- DualPortMemory動作テスト
- 閾値計算
- 2値化
上のVHDLコードのテストに利用したFPGAは
mugen2013で使った基板です。
クロックは48MHz、Spartan3の200kゲートタイプ
大阪のヒューマンデータから入手しました。
FPGA基板にマザーボードを用意し、マザーボード
からコネクタ、ケーブルを介してマイコン、他の
基板に接続できるようにしてあります。
FPGAの内部状態確認のため、スイッチとLEDが
ついたモニタ基板を使います。
ARMとFPGAは、10ピンケーブルで接続します。
各VHDLコードに関して説明していきます。
DualPortMemory動作テスト
OV7670が出力してくる画像データを保存するため
FPGA内部にあるDualPortMemoryを使いました。
DualPortMemoryは、A、Bの2ポートをもつので
Aポートを入力、Bポートを出力にしています。
使い方は、AポートにOV7670を接続し、Bポートに
ARMを接続しますが、動作確認では2ポートともに
ARMに接続します。
動作テストは、ARMからAポートを使いメモリに
データを書込み、Bポートからメモリデータを
読出す処理としました。
動作テストは、ARMからAポートを使いメモリに
データを書込み、Bポートからメモリデータを
読出す処理としました。
ARMのファームウエアに、次の機能を用意します。
- Aポートのアドレスをゼロクリア
- Aポートのアドレスを+1
- Aポートへデータ転送(メモリへのデータ書込み)
- Bポートのアドレスをゼロクリア
- Bポートのアドレスを+1
- Bポートからデータ転送(メモリからデータ読出し)
ARMとPCは、シリアルケーブルで接続し
端末ソフトで、コマンドを与えながら
上の機能を実現します。
ARMとFPGAは、8ビットバスを2ポート利用し
接続します。1ポートは、データバスとして
他のポートは制御バスに使います。
コマンドは、次のように決めました。
- A0 Aポートのアドレスをゼロクリア
- A1 Aポートのアドレスを+1
- W?? Aポートへデータ転送(メモリへのデータ書込み)
- A2 Bポートのアドレスをゼロクリア
- A3 Bポートのアドレスを+1
- R Bポートからデータ転送(メモリからデータ読出し)
- M A、Bポートの現在のアドレス表示
アドレスに関連するコマンドは、すべて'A'コマンドに
集約します。コマンドに続けるパラメータで、処理と
ポートを指定します。
データ書込みは'W'コマンドを使い、続けるパラメータを
16進2バイトとします。
データ読込みは'R'コマンドを使います。
A、Bポートの現在のアドレスを表示することで
データライト時のアドレス確認が楽になるように
しました。
仕様を決めたので、PCとARM間の通信関係パラメータを
以下のようにまとめます。
- データ転送速度 19200bps
- 調歩同期
- ストップビット1ビット
- パリティなし
- フロー制御なし
- 3ピンのストレート接続
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
#define ASFT 16
#define WSFT 17
#define RSFT 18
#define ATRG 1
#define WTRG 2
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_100us(UWORD x);
void read_loop(void);
void put_fpga(UWORD x);
UBYTE get_fpga(void);
void show_memory_address(void);
/* global variables */
volatile UBYTE uflag ;
volatile UBYTE sbuf[16] ;
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 UWORD madra ;
volatile UWORD madrb ;
#define ALAST 160
int main(void)
{
UBYTE tmp ;
/* 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' ) {
/* get parameter */
tmp = get_hex( *(sbuf+1) );
/* send command */
put_fpga( (ATRG << 8) | tmp ) ;
/* update local address */
if ( tmp == 0 ) { madra = 0 ; }
if ( tmp == 2 ) { madrb = 0 ; }
if ( tmp == 1 ) { madra++ ; }
if ( tmp == 3 ) { madrb++ ; }
}
/* show memory address */
if ( cmd == 'M' ) { show_memory_address() ; }
/* store data from A port */
if ( cmd == 'W' ) {
/* get data */
dat = get_hex( *(sbuf+1) ); /* get upper nibble */
dat <<= 4 ;
dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */
/* send data */
put_fpga( (WTRG << 8) | dat ) ;
}
/* read B port data */
if ( cmd == 'R' ) { read_loop(); }
}
}
/* 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 ;
}
/* */
madra = 0 ;
madrb = 0 ;
dat = 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 handling address") ; crlf();
rs_puts(" A0 clear A port address") ; crlf();
rs_puts(" A1 increase A port address") ; crlf();
rs_puts(" A2 clear B port address") ; crlf();
rs_puts(" A3 increase B port address") ; crlf();
rs_puts("W write value to A port ") ; crlf();
rs_puts("R read B port data") ; crlf();
rs_puts("M show memory address") ; crlf();
}
void delay_100us(UWORD x)
{
ULONG last ;
/* calculate */
last = timcnt + x ;
/* wait */
while ( timcnt < last ) ;
}
void read_loop(void)
{
UBYTE result ;
UBYTE madr[6] ;
UBYTE i ;
/* default */
*(madr+4) = ':';
*(madr+5) = '\0';
/* clear address */
put_fpga((ATRG < 8) | 0x02);
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) {
/* show address */
if ( (i & MASK0F) == 0 ) {
/* calculate address */
*(madr+0) = ((i >> 12) & MASK0F) ;
*(madr+1) = ((i >> 8) & MASK0F) ;
*(madr+2) = ((i >> 4) & MASK0F) ;
*(madr+3) = (i & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
*(madr+2) = asc_hex[*(madr+2)] ;
*(madr+3) = asc_hex[*(madr+3)] ;
/* show */
rs_puts( madr );
}
/* get data */
result = get_fpga() ;
/* show */
rs_putchar(asc_hex[(result >> 4) & MASK0F]);
rs_putchar(asc_hex[result & MASK0F]);
rs_putchar(' ');
/* judge new line */
if ( (i & MASK0F) == 15 ) { crlf(); }
/* address increment */
put_fpga((ATRG << 8) | 0x03);
}
/* clear address */
put_fpga((ATRG << 8) | 0x02);
/* new line */
crlf();
}
void put_fpga(UWORD x)
{
UBYTE xcmd ;
UBYTE xsft ;
/* impress data to GP3 */
GP3DAT &= 0xFF00FFFF ;
GP3DAT |= ((x & MASKFF) << 16) ;
/* judge trigger */
xcmd = (x >> 8) & MASKFF ;
if ( xcmd == ATRG ) { xsft = ASFT ; }
if ( xcmd == WTRG ) { xsft = WSFT ; }
/* trigger */
GP2DAT &= 0xFF00FFFF ;
GP2DAT |= (1 << xsft) ;
GP2DAT &= 0xFF00FFFF ;
}
UBYTE get_fpga(void)
{
UBYTE result ;
/* change GP3 input */
GP3DAT &= 0x00FFFFFF ;
/* enable OE */
GP2DAT &= 0xFF00FFFF ;
GP2DAT |= (1 << RSFT) ;
/* delay */
delay_100us(2);
/* get data */
result = GP3DAT & MASKFF ;
/* disable OE */
GP2DAT &= 0xFF00FFFF ;
/* change GP3 output */
GP3DAT |= 0xFF000000 ;
return result ;
}
void show_memory_address(void)
{
UBYTE madr[6] ;
UBYTE loop ;
UWORD tmp ;
/* default */
*(madr+4) = ':';
*(madr+5) = '\0';
/* loop */
for ( loop = 0 ; loop < 2 ; loop++ ) {
/* get address */
tmp = madra ;
if ( loop ) { tmp = madrb ; }
/* calculate address */
*(madr+0) = ((tmp >> 12) & MASK0F) ;
*(madr+1) = ((tmp >> 8) & MASK0F) ;
*(madr+2) = ((tmp >> 4) & MASK0F) ;
*(madr+3) = (tmp & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
*(madr+2) = asc_hex[*(madr+2)] ;
*(madr+3) = asc_hex[*(madr+3)] ;
/* show */
rs_puts( madr );
/* new line */
crlf();
}
}
FPGA内のDualPortMemoryを操作する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 dpmtsty is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
ATRG : in std_logic ;
WTRG : in std_logic ;
RTRG : in std_logic ;
-- data BUS
ADBUS : inout std_logic_vector(7 downto 0) ;
-- address monitor
SEL : in std_logic ;
ROUT : out std_logic_vector(7 downto 0) ;
GOUT : out std_logic_vector(2 downto 0) ;
MCLKX : out std_logic -- ;
);
end dpmtsty;
architecture Behavioral of dpmtsty is
-- clock (input)
signal iCLK0_OUT : std_logic ;
signal iCLKFX : std_logic ;
signal iCLKFB_IN : std_logic ;
signal iCLKIN_IBUFG : std_logic ;
signal iCLKFX_OUT : std_logic ;
-- trigger
signal iATRG_SFT : std_logic_vector(2 downto 0) ;
signal iWTRG_SFT : std_logic_vector(2 downto 0) ;
signal iATRG : std_logic ;
signal iWTRG : std_logic ;
-- address sequencer
signal iASTATE : std_logic_vector(1 downto 0) ;
signal iAREG : std_logic_vector(1 downto 0) ;
-- data sequencer
signal iWSTATE : std_logic_vector(1 downto 0) ;
-- internal registers (A port)
signal iADRA : std_logic_vector(10 downto 0) ;
signal iDIA : std_logic_vector( 7 downto 0) ;
signal iWEA : std_logic ;
-- internal registers (Bport)
signal iDOB : std_logic_vector( 7 downto 0) ;
signal iADRB : std_logic_vector(10 downto 0) ;
begin
-- input clock buffer handling
IBUFG_inst : IBUFG
generic map (IOSTANDARD => "DEFAULT")
port map (
O => iCLKIN_IBUFG, -- Clock buffer output
I => CLOCK -- Clock buffer input (connect directly to top-level port)
);
-- output clock buffer handling
BUFG_inst : BUFG
port map (
O => iCLKFB_IN, -- Clock buffer output
I => iCLK0_OUT -- Clock buffer input
);
-- output clock buffer handling
BUFG_instX : BUFG
port map (
O => iCLKFX_OUT , -- Clock buffer output
I => iCLKFX -- Clock buffer input
);
-- DCM (48MHz/4 = 12MHz)
-- MULTIPLY 2
-- DIVIDE 8
-- (2 / 4) * 24 = (1 / 2) * 24 = 12
DCM_inst : DCM
generic map (
CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
-- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
CLKFX_DIVIDE => 4, -- Can be any integer from 1 to 32
CLKFX_MULTIPLY => 2, -- Can be any integer from 2 to 32
CLKIN_DIVIDE_BY_2 => TRUE, -- TRUE/FALSE to enable CLKIN divide by two feature
CLKIN_PERIOD => 20.833, -- Specify period of input clock
CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift of NONE, FIXED or VARIABLE
CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE, 1X or 2X
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
-- an integer from 0 to 15
DFS_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for frequency synthesis
DLL_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for DLL
DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE
FACTORY_JF => X"C080", -- FACTORY JF Values
PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255
SIM_MODE => "SAFE", -- Simulation: "SAFE" vs "FAST", see "Synthesis and Simulation
-- Design Guide" for details
STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE
port map (
CLK0 => iCLK0_OUT, -- 0 degree DCM CLK ouptput
CLK180 => open, -- 180 degree DCM CLK output
CLK270 => open, -- 270 degree DCM CLK output
CLK2X => open, -- 2X DCM CLK output
CLK2X180 => open, -- 2X, 180 degree DCM CLK out
CLK90 => open, -- 90 degree DCM CLK output
CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE)
CLKFX => iCLKFX, -- DCM CLK synthesis out (M/D)
CLKFX180 => open, -- 180 degree CLK synthesis out
LOCKED => open, -- DCM LOCK status output
PSDONE => open, -- Dynamic phase adjust done output
STATUS => open, -- 8-bit DCM status bits output
CLKFB => iCLKFB_IN, -- DCM clock feedback
CLKIN => iCLKIN_IBUFG, -- Clock input (from IBUFG, BUFG or DCM)
PSCLK => '0', -- Dynamic phase adjust clock input
PSEN => '0', -- Dynamic phase adjust enable input
PSINCDEC => '0', -- Dynamic phase adjust increment/decrement
RST => '0' -- DCM asynchronous reset input
);
RAMB16_S9_S9_instA : 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 => iADRA, -- Port A 11-bit Address Input
ADDRB => iADRB, -- Port B 11-bit Address Input
CLKA => iCLKFX_OUT, -- Port A Clock
CLKB => iCLKFX_OUT, -- 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
MCLKX <= not iCLKFX_OUT ;
ROUT <= (not iADRB(7 downto 0)) when ( SEL = '1' ) else
(not iADRA(7 downto 0)) ;
GOUT <= (not iADRB(10 downto 8)) when ( SEL = '1' ) else
(not iADRA(10 downto 8)) ;
-- output
ADBUS <= iDOB when ( RTRG = '1' ) else (others => 'Z');
-- trigger
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iATRG_SFT <= "000" ;
iWTRG_SFT <= "000" ;
elsif rising_edge(iCLKFX_OUT) then
iATRG_SFT <= iATRG_SFT(1 downto 0) & ATRG ;
iWTRG_SFT <= iWTRG_SFT(1 downto 0) & WTRG ;
end if ;
end process ;
iATRG <= '1' when ( iATRG_SFT = "011" or iATRG_SFT = "001" ) else '0' ;
iWTRG <= '1' when ( iWTRG_SFT = "011" or iWTRG_SFT = "001" ) else '0' ;
-- sequencer (address handling)
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iASTATE <= "00" ;
iADRA <= (others => '0') ;
iADRB <= (others => '0') ;
elsif rising_edge(iCLKFX_OUT) then
case conv_integer(iASTATE) is
-- wait trigger
when 0 => if ( iATRG = '1' ) then
iASTATE <= "01" ;
else
iASTATE <= "00" ;
end if ;
-- transfer
when 1 => iASTATE <= "11" ;
iAREG <= ADBUS(1 downto 0) ;
-- decode
when 3 => iASTATE <= "10" ;
-- clear A port address
if ( iAREG = "00" ) then
iADRA <= (others => '0') ;
end if ;
-- increase A port address
if ( iAREG = "01" ) then
iADRA <= iADRA + '1' ;
end if ;
-- clear B port address
if ( iAREG = "10" ) then
iADRB <= (others => '0') ;
end if ;
-- increase B port address
if ( iAREG = "11" ) then
iADRB <= iADRB + '1' ;
end if ;
-- return first state
when 2 => iASTATE <= "00" ;
-- default
when others =>
iASTATE <= "00" ;
end case ;
end if ;
end process ;
-- sequencer (write handling)
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iWSTATE <= "00" ;
iDIA <= (others => '0') ;
elsif rising_edge(iCLKFX_OUT) then
case conv_integer(iWSTATE) is
-- wait trigger
when 0 => if ( iWTRG = '1' ) then
iWSTATE <= "01" ;
else
iWSTATE <= "00" ;
end if ;
-- get data
when 1 => iWSTATE <= "11" ;
iDIA <= ADBUS ;
-- send trigger
when 3 => iWSTATE <= "10" ;
-- return first state
when 2 => iWSTATE <= "00" ;
-- default
when others =>
iWSTATE <= "00" ;
end case ;
end if ;
end process ;
iWEA <= '1' when ( iWSTATE = "11" ) else '0' ;
end Behavioral;
DCMを利用し48MHzから12MHzを生成し、このクロックで
内部回路を動かします。12MHzを選択したのは、ARMが
約11MHzで動作しているので、このクロックに近づける
意図があります。
2ポートのアドレス処理、データライトにそれぞれ
シーケンサを用意して、単純な動作になるように
回路を分けています。
メモリからのデータ取得は、8ビットバスを入力から
出力の方向切替えで対応しています。
バスは通常、入力としておき、信号RTRGにより
出力に切替えます。
ピンアサインは、以下。
# 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 "WTRG" LOC = "P12" | IOSTANDARD = LVCMOS33 ;
NET "RTRG" LOC = "P13" | IOSTANDARD = LVCMOS33 ;
# G0B
NET "ROUT<0>" LOC = "P141" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<1>" LOC = "P140" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<2>" LOC = "P137" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<3>" LOC = "P135" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<4>" LOC = "P132" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<5>" LOC = "P131" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<6>" LOC = "P130" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<7>" LOC = "P129" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
# G1B
NET "GOUT<0>" LOC = "P116" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<1>" LOC = "P113" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<2>" LOC = "P119" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "MCLKX" LOC = "P124" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
# G2B
NET "SEL" LOC = "P103" | IOSTANDARD = LVCMOS33 ;
閾値計算
DualPortMemoryにデータを入力できると
OV7670から取得したデータとみなし、その
最大値、最小値を求め、閾値を計算できます。
元となるデータをFPGA内部のメモリに転送しなければ
動作試験ができないので、ARMの中に配列を用意して
その内容をFPGAに転送します。
ARMの配列中にデータを設定するために
コマンドを考え、次のようにします。
- D 配列内のデータを16進2けたで表示
- F 配列内の全データを指定した16進2けたに
- E 配列の添字を指定して、16進数2けたデータをひとつ設定
ARMの配列内のデータをFPGAに転送、計算、取得
するためのコマンドも必要です。
次のように、決めました。
- T データをFPGAに転送
- C DualPortMemory中のデータから最大値、最小値、閾値を求める
- B 2値化指示
- X 2値化したデータを取得し表示
コマンドを決めたので、ファームウエアを定義します。
#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
#define ASFT 16
#define WSFT 17
#define CSFT 18
#define BSFT 19
#define RSFT 20
#define ATRG 1
#define WTRG 2
#define CTRG 4
#define BTRG 8
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_100us(UWORD x);
void read_loop(void);
void write_loop(void);
void put_fpga(UWORD x);
UBYTE get_fpga(UBYTE x);
void show_memory_address(void);
void dump_array(void);
void fill_array(UBYTE x);
void read_binary(void);
/* global variables */
volatile UBYTE uflag ;
volatile UBYTE sbuf[16] ;
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 UWORD madra ;
volatile UWORD madrb ;
#define ALAST 160
volatile UBYTE gdat[ALAST] ;
int main(void)
{
UBYTE tmp ;
/* 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' ) {
/* get parameter */
tmp = get_hex( *(sbuf+1) );
/* send command */
put_fpga( (ATRG << 8) | tmp ) ;
/* update local address */
if ( tmp == 0 ) { madra = 0 ; }
if ( tmp == 2 ) { madrb = 0 ; }
if ( tmp == 1 ) { madra++ ; }
if ( tmp == 3 ) { madrb++ ; }
}
/* show memory address */
if ( cmd == 'M' ) { show_memory_address() ; }
/* transfer data to A port */
if ( cmd == 'T' ) { write_loop() ; }
/* send calculate trigger */
if ( cmd == 'C' ) { put_fpga( (CTRG << 8) | 0x00 ); }
/* dump SRAM contents */
if ( cmd == 'D' ) { dump_array(); }
/* store data to SRAM */
if ( cmd == 'E' ) {
/* get address */
tmp = get_hex( *(sbuf+1) ); /* get upper nibble */
tmp <<= 4 ;
tmp |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */
/* get data */
dat = get_hex( *(sbuf+3) ); /* get upper nibble */
dat <<= 4 ;
dat |= get_hex( *(sbuf+4) ); /* concatenate lower nibble */
/* store */
*(gdat+tmp) = dat ;
}
/* fill SRAM */
if ( cmd == 'F' ) {
/* get data */
dat = get_hex( *(sbuf+1) ); /* get upper nibble */
dat <<= 4 ;
dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */
/* store */
fill_array(dat);
}
/* send binary conversion trigger */
if ( cmd == 'B' ) { put_fpga( (BTRG << 8) | 0x00 ); }
/* show binary data */
if ( cmd == 'X' ) { read_binary() ; }
/* store data from A port */
if ( cmd == 'W' ) {
/* get data */
dat = get_hex( *(sbuf+1) ); /* get upper nibble */
dat <<= 4 ;
dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */
/* send data */
put_fpga( (WTRG << 8) | dat ) ;
}
/* read B port data */
if ( cmd == 'R' ) { read_loop(); }
}
}
/* 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 ;
}
/* */
madra = 0 ;
madrb = 0 ;
dat = 0 ;
fill_array( 0x00 );
/* 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 handling address") ; crlf();
rs_puts(" A0 clear A port address") ; crlf();
rs_puts(" A1 increase A port address") ; crlf();
rs_puts(" A2 clear B port address") ; crlf();
rs_puts(" A3 increase B port address") ; crlf();
rs_puts("W write value to A port ") ; crlf();
rs_puts("R read B port data") ; crlf();
rs_puts("M show memory address") ; crlf();
rs_puts("T transfer data") ; crlf();
rs_puts("C calculate") ; crlf();
rs_puts("D dump SRAM contents") ; crlf();
rs_puts("F fill SRAM") ; crlf();
rs_puts("E store data to SRAM") ; crlf();
rs_puts("B binary convert") ; crlf();
rs_puts("X read binary data") ; crlf();
}
void delay_100us(UWORD x)
{
ULONG last ;
/* calculate */
last = timcnt + x ;
/* wait */
while ( timcnt < last ) ;
}
void dump_array(void)
{
UBYTE result ;
UBYTE madr[4] ;
UBYTE i ;
/* default */
*(madr+2) = ':';
*(madr+3) = '\0';
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) {
/* show address */
if ( (i & MASK0F) == 0 ) {
/* calculate address */
*(madr+0) = ((i >> 4) & MASK0F);
*(madr+1) = (i & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
/* show */
rs_puts( madr );
}
/* get data */
result = *(gdat+i) ;
/* show */
rs_putchar(asc_hex[(result >> 4) & MASK0F]);
rs_putchar(asc_hex[result & MASK0F]);
rs_putchar(' ');
/* judge new line */
if ( (i & MASK0F) == 15 ) { crlf(); }
}
/* new line */
crlf();
}
void fill_array(UBYTE x)
{
UBYTE i ;
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) { *(gdat+i) = x ; }
}
void read_loop(void)
{
UBYTE result ;
UBYTE madr[6] ;
UBYTE i ;
/* default */
*(madr+4) = ':';
*(madr+5) = '\0';
/* clear B port address */
put_fpga((ATRG << 8) | 0x02);
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) {
/* show address */
if ( (i & MASK0F) == 0 ) {
/* calculate address */
*(madr+0) = ((i >> 12) & MASK0F) ;
*(madr+1) = ((i >> 8) & MASK0F) ;
*(madr+2) = ((i >> 4) & MASK0F) ;
*(madr+3) = (i & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
*(madr+2) = asc_hex[*(madr+2)] ;
*(madr+3) = asc_hex[*(madr+3)] ;
/* show */
rs_puts( madr );
}
/* get data */
result = get_fpga(0) ;
/* show */
rs_putchar(asc_hex[(result >> 4) & MASK0F]);
rs_putchar(asc_hex[result & MASK0F]);
rs_putchar(' ');
/* judge new line */
if ( (i & MASK0F) == 15 ) { crlf(); }
/* address increment */
put_fpga((ATRG << 8) | 0x03);
}
/* new line */
crlf();
/* clear address */
put_fpga((ATRG << 8) | 0x02);
/* minimum */
{
result = get_fpga(1) ;
rs_puts("Minimum = ");
rs_putchar(asc_hex[(result >> 4) & MASK0F]);
rs_putchar(asc_hex[result & MASK0F]);
crlf();
}
/* maximum */
{
result = get_fpga(2) ;
rs_puts("Maximum = ");
rs_putchar(asc_hex[(result >> 4) & MASK0F]);
rs_putchar(asc_hex[result & MASK0F]);
crlf();
}
/* threshold */
{
result = get_fpga(3) ;
rs_puts("Threshold = ");
rs_putchar(asc_hex[(result >> 4) & MASK0F]);
rs_putchar(asc_hex[result & MASK0F]);
crlf();
}
}
void write_loop(void)
{
UBYTE tmp ;
UBYTE i ;
/* clear A port address */
put_fpga((ATRG << 8) | 0x00);
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) {
/* get data */
tmp = *(gdat+i) ;
/* send */
put_fpga((WTRG << 8) | tmp) ;
/* A port address increment */
put_fpga((ATRG << 8) | 0x01);
}
/* clear A port address */
put_fpga((ATRG << 8) | 0x00);
/* new line */
crlf();
}
void put_fpga(UWORD x)
{
UBYTE xcmd ;
UBYTE xsft ;
/* impress data to GP3 */
GP3DAT &= 0xFF00FFFF ;
GP3DAT |= ((x & MASKFF) << 16) ;
/* judge trigger */
xcmd = (x >> 8) & MASKFF ;
if ( xcmd == ATRG ) { xsft = ASFT ; }
if ( xcmd == WTRG ) { xsft = WSFT ; }
if ( xcmd == CTRG ) { xsft = CSFT ; }
if ( xcmd == BTRG ) { xsft = BSFT ; }
/* trigger */
GP2DAT &= 0xFF00FFFF ;
GP2DAT |= (1 << xsft) ;
GP2DAT &= 0xFF00FFFF ;
}
UBYTE get_fpga(UBYTE x)
{
UBYTE result ;
/* change GP3 input */
GP3DAT &= 0x00FFFFFF ;
/* enable OE */
GP2DAT &= 0xFF00FFFF ;
GP2DAT |= ((x << 21) | (1 << RSFT));
/* RSEL2 RSEL1 RSEL0 RTRG = 23 22 21 20 */
/* delay */
delay_100us(2);
/* get data */
result = GP3DAT & MASKFF ;
/* disable OE */
GP2DAT &= 0xFF00FFFF ;
/* change GP3 output */
GP3DAT |= 0xFF000000 ;
return result ;
}
void show_memory_address(void)
{
UBYTE madr[6] ;
UBYTE loop ;
UWORD tmp ;
/* default */
*(madr+4) = ':';
*(madr+5) = '\0';
/* loop */
for ( loop = 0 ; loop < 2 ; loop++ ) {
/* get address */
tmp = madra ;
if ( loop ) { tmp = madrb ; }
/* calculate address */
*(madr+0) = ((tmp >> 12) & MASK0F) ;
*(madr+1) = ((tmp >> 8) & MASK0F) ;
*(madr+2) = ((tmp >> 4) & MASK0F) ;
*(madr+3) = (tmp & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
*(madr+2) = asc_hex[*(madr+2)] ;
*(madr+3) = asc_hex[*(madr+3)] ;
/* show */
rs_puts( madr );
/* new line */
crlf();
}
}
void read_binary(void)
{
UBYTE result ;
UBYTE madr[4] ;
UBYTE i ;
/* default */
*(madr+2) = ':';
*(madr+3) = '\0';
/* clear shift register address address */
put_fpga((ATRG << 8) | 0x04);
/* loop */
for ( i = 0 ; i < 20 ; i++ ) {
/* show address */
if ( (i % 8) == 0 ) {
/* calculate address */
*(madr+0) = ((i >> 4) & MASK0F);
*(madr+1) = (i & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
/* show */
rs_puts( madr );
}
/* get data */
result = get_fpga(4) ;
/* show */
rs_putchar( ((result >> 7) & 1) + '0' );
rs_putchar( ((result >> 6) & 1) + '0' );
rs_putchar( ((result >> 5) & 1) + '0' );
rs_putchar( ((result >> 4) & 1) + '0' );
rs_putchar( ((result >> 3) & 1) + '0' );
rs_putchar( ((result >> 2) & 1) + '0' );
rs_putchar( ((result >> 1) & 1) + '0' );
rs_putchar( (result & 1) + '0' );
/* judge new line */
if ( (i % 8) == 7 ) { crlf(); }
/* shift register increment */
put_fpga((ATRG << 8) | 0x05);
}
/* new line */
crlf();
/* clear shift register address address */
put_fpga((ATRG << 8) | 0x04);
}
HyperTerminalを利用し、ARMだけで完結する動作を
テストしました。
'D'(dump)コマンドのテスト。
'F'(fill)、'D'(dump)、'E'(enter)コマンドのテスト。
'E'(enter)、'D'(dump)コマンドのテスト。
FPGAを接続し、'C'(calcualte)、'R'(read)コマンドのテスト。
最大値、最小値、閾値を求める処理は、正しく動いて
いることを確認できました。
FPGA内部にあるトリガーを与えて、最大値、最小値、閾値を
求めるためのシーケンサは、以下のように定義。
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iCSTATE <= 0 ;
iCREG <= "00" ;
iCMAX <= (others => '0') ;
iCMIN <= (others => '0') ;
iCCOUNT <= 0 ;
iCTHV <= 0 ;
elsif rising_edge(iCLKFX_OUT) then
case iCSTATE is
-- wait trigger
when 0 => if ( iCTRG = '1' ) then
iCSTATE <= 1 ;
else
iCSTATE <= 0 ;
end if ;
-- clear B port address
when 1 => iCSTATE <= 2 ;
iCREG <= "10" ;
-- send trigger
when 2 => iCSTATE <= 3 ;
-- delay
when 3 => iCSTATE <= 4 ;
-- wait complete
when 4 => if ( iASTATE = "00" ) then
iCSTATE <= 5 ; -- next
else
iCSTATE <= 4 ; -- stay
end if ;
-- set MAX and MIN
when 5 => iCSTATE <= 6 ; -- next
iCMAX <= iDOB ; -- maximum
iCMIN <= iDOB ; -- minimum
iCCOUNT <= 0 ;
-- increse B port address
when 6 => iCSTATE <= 7 ;
iCREG <= "11" ;
iCCOUNT <= iCCOUNT + 1 ;
-- send trigger
when 7 => iCSTATE <= 8 ;
-- delay
when 8 => iCSTATE <= 9 ;
-- wait complete
when 9 => if ( iASTATE = "00" ) then
iCSTATE <= 10 ; -- next
else
iCSTATE <= 9 ; -- stay
end if ;
-- compare
when 10 => iCSTATE <= 11 ;
if ( conv_integer(iCMAX) < conv_integer(iDOB) ) then
iCMAX <= iDOB ;
end if ;
if ( conv_integer(iCMIN) > conv_integer(iDOB) ) then
iCMIN <= iDOB ;
end if ;
-- judge
when 11 => if ( iCCOUNT = PIXEL_LAST ) then
iCSTATE <= 12 ; -- exit
else
iCSTATE <= 6 ; -- loop
end if ;
-- return first state
when 12 => iCSTATE <= 0 ;
iCTHV <= (conv_integer(iCMAX)+conv_integer(iCMIN)) / 2 ;
-- default
when others =>
iCSTATE <= 0 ;
end case ;
end if ;
end process ;
iAXTRG <= '1' when ( iCSTATE = 2 or iCSTATE = 7 ) else '0' ;
iCTHVX <= conv_std_logic_vector(iCTHV,8) ;
トリガーを与えられたなら、Bポートからアドレス0のデータを
取出して、仮の最大値、最小値とします。残り159個のデータを
取出しては、比較し、最大値、最小値を求めます。
すべて比較し終えたなら、閾値を求めます。
DualPortMemoryのA、Bポートのアドレスを操作するため
アドレス処理シーケンサを、定義し直しました。
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iASTATE <= "00" ;
iADRA <= (others => '0') ;
iADRB <= (others => '0') ;
iASEL <= "00" ;
iBPTR <= 0 ;
elsif rising_edge(iCLKFX_OUT) then
case conv_integer(iASTATE) is
-- wait trigger
when 0 => if ( iATRG = '1' ) then
iASTATE <= "01" ;
elsif ( iAXTRG = '1' ) then
iASTATE <= "01" ;
iASEL <= "01" ;
elsif ( iAYTRG = '1' ) then
iASTATE <= "01" ;
iASEL <= "10" ;
else
iASTATE <= "00" ;
end if ;
-- transfer
when 1 => iASTATE <= "11" ;
if ( iASEL(0) = '1' ) then
iAREG <= '0' & iCREG ;
elsif ( iASEL(1) = '1' ) then
iAREG <= '0' & iBREG ;
else
iAREG <= ADBUS(2 downto 0) ;
end if ;
-- decode
when 3 => iASTATE <= "10" ;
-- clear A port address
if ( iAREG = "000" ) then
iADRA <= (others => '0') ;
end if ;
-- increase A port address
if ( iAREG = "001" ) then
iADRA <= iADRA + '1' ;
end if ;
-- clear B port address
if ( iAREG = "010" ) then
iADRB <= (others => '0') ;
end if ;
-- increase B port address
if ( iAREG = "011" ) then
iADRB <= iADRB + '1' ;
end if ;
-- clear shift register pointer
if ( iAREG = "100" ) then
iBPTR <= 0 ;
end if ;
-- increase shift register pointer
if ( iAREG = "101" ) then
iBPTR <= iBPTR + 1 ;
end if ;
-- return first state
when 2 => iASTATE <= "00" ;
iASEL <= "00" ;
-- default
when others =>
iASTATE <= "00" ;
end case ;
end if ;
end process ;
A、Bポートのアドレスをクリア、+1する指示を
ARMマイコンから与える他、最大値、最小値、閾値
を計算させるシーケンサから、Bポートアドレスを
クリア、+1する処理を加えました。
さらに、2値化を担当するシーケンサから、Bポート
のアドレスを操作する処理も加えました。
トリガーを加えFPGAから読み出すデータが
増えたので、8ビットの制御ピンの扱いを
次のように変更しました。
- GP27 RSEL<2>
- GP26 RSEL<1>
- GP25 RSEL<0>
- GP24 RTRG
- GP23 BTRG
- GP22 CTRG
- GP21 WTRG
- GP20 ATRG
2値化
最大値、最小値、閾値を求められたなら
閾値を使い、データを2値化します。
2値化を担当するシーケンサを定義します。
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iBSTATE <= 0 ;
iBCOUNT <= 0 ;
iBREG <= "00" ;
iBDAT <= (others => '0') ;
elsif rising_edge(iCLKFX_OUT) then
case iBSTATE is
-- wait trigger
when 0 => if ( iBTRG = '1' ) then
iBSTATE <= 1 ;
else
iBSTATE <= 0 ;
end if ;
-- clear counter
when 1 => iBSTATE <= 2 ;
iBCOUNT <= 0 ;
-- set B port address zero
when 2 => iBSTATE <= 3 ;
iBREG <= "10" ;
-- send trigger
when 3 => iBSTATE <= 4 ;
-- delay
when 4 => iBSTATE <= 5 ;
-- wait complete
when 5 => if ( iASTATE = "00" ) then
iBSTATE <= 6 ;
else
iBSTATE <= 5 ;
end if ;
-- get memory data
when 6 => iBSTATE <= 7 ;
iBDAT <= iDOB ;
-- compare and store
when 7 => iBSTATE <= 8 ;
if ( conv_integer(iBDAT) > iCTHV ) then
iBSFT(iBCOUNT) <= '1' ;
else
iBSFT(iBCOUNT) <= '0' ;
end if ;
-- counter increment
when 8 => iBSTATE <= 9 ;
iBCOUNT <= iBCOUNT + 1 ;
-- judge complete
when 9 => if ( iBCOUNT = PIXEL_MAX ) then
iBSTATE <= 10 ; -- exit
else
iBSTATE <= 3 ; -- loop
iBREG <= "11" ; -- increse B port address
end if ;
-- set B port address zero
when 10 => iBSTATE <= 11 ;
iBREG <= "10" ;
-- send trigger
when 11 => iBSTATE <= 12 ;
-- return first state
when 12 => iBSTATE <= 0 ;
-- default
when others =>
iBSTATE <= 0 ;
end case ;
end if ;
end process ;
iAYTRG <= '1' when ( iBSTATE = 3 or iBSTATE = 11 ) else '0' ;
トリガーで動作開始を指示されると、Bポートアドレスを
クリア、+1しながら、閾値とデータを比較します。
比較の結果で1か0を確定し、結果をレジスタに保存します。
レジスタのビット数は、160とします。
160ビットのレジスタ値を8ビットに区切って出力する
ように、バス出力を次のようにしました。
iBSFTV <= iBSFT(8*iBPTR to 8*iBPTR+7);
ADBUS <= iDOB when ( RTRG = '1' and RSEL = "000" ) else -- B port data
iCMIN when ( RTRG = '1' and RSEL = "001" ) else -- min
iCMAX when ( RTRG = '1' and RSEL = "010" ) else -- max
iCTHVX when ( RTRG = '1' and RSEL = "011" ) else -- threshold
iBSFTV when ( RTRG = '1' and RSEL = "100" ) else -- binary data
(others => 'Z');
iBPTRの値は、アドレスを扱う回路でクリアと+1するように
定義してあります。
ファームウエアからの指示で、動作を確認しました。
端末では、次の操作をしました。
- 'R'コマンドで、DualPortMemoryの内容確認
- 'C'コマンドで、最大値、最小値、閾値を計算
- 'B'コマンドで、2値化しレジスタに保存
- 'X'コマンドで、2値化した値を表示
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 dpmtsty is
generic (
PIXEL_MAX : integer := 160 ;
PIXEL_LAST : integer := 159 --;
) ;
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
ATRG : in std_logic ;
WTRG : in std_logic ;
RTRG : in std_logic ;
CTRG : in std_logic ;
BTRG : in std_logic ;
RSEL : in std_logic_vector(2 downto 0) ;
-- data BUS
ADBUS : inout std_logic_vector(7 downto 0) ;
-- address monitor
SEL : in std_logic ;
ROUT : out std_logic_vector(7 downto 0) ;
GOUT : out std_logic_vector(2 downto 0) ;
MCLKX : out std_logic -- ;
);
end dpmtsty;
architecture Behavioral of dpmtsty is
-- clock (input)
signal iCLK0_OUT : std_logic ;
signal iCLKFX : std_logic ;
signal iCLKFB_IN : std_logic ;
signal iCLKIN_IBUFG : std_logic ;
signal iCLKFX_OUT : std_logic ;
-- trigger
signal iATRG_SFT : std_logic_vector(2 downto 0) ;
signal iWTRG_SFT : std_logic_vector(2 downto 0) ;
signal iCTRG_SFT : std_logic_vector(2 downto 0) ;
signal iBTRG_SFT : std_logic_vector(2 downto 0) ;
signal iATRG : std_logic ;
signal iWTRG : std_logic ;
signal iCTRG : std_logic ;
signal iBTRG : std_logic ;
-- address sequencer
signal iASTATE : std_logic_vector(1 downto 0) ;
signal iAREG : std_logic_vector(2 downto 0) ;
signal iASEL : std_logic_vector(1 downto 0) ;
-- data sequencer
signal iWSTATE : std_logic_vector(1 downto 0) ;
-- calculate sequencer
signal iCSTATE : integer range 0 to 12 ;
signal iCREG : std_logic_vector(1 downto 0) ;
signal iAXTRG : std_logic ;
signal iCMAX : std_logic_vector( 7 downto 0) ;
signal iCMIN : std_logic_vector( 7 downto 0) ;
signal iCCOUNT : integer range 0 to PIXEL_LAST ;
signal iCTHV : integer range 0 to 255 ;
signal iCTHVX : std_logic_vector( 7 downto 0) ;
-- binary conversion sequencer
signal iBSTATE : integer range 0 to 12 ;
signal iBREG : std_logic_vector(1 downto 0) ;
signal iBDAT : std_logic_vector(7 downto 0) ;
signal iAYTRG : std_logic ;
signal iBCOUNT : integer range 0 to PIXEL_LAST ;
signal iBSFT : std_logic_vector(0 to PIXEL_LAST) ;
signal iBPTR : integer range 0 to 21 ;
signal iBSFTV : std_logic_vector(0 to 7) ;
-- internal registers (A port)
signal iADRA : std_logic_vector(10 downto 0) ;
signal iDIA : std_logic_vector( 7 downto 0) ;
signal iWEA : std_logic ;
-- internal registers (Bport)
signal iDOB : std_logic_vector( 7 downto 0) ;
signal iADRB : std_logic_vector(10 downto 0) ;
begin
-- input clock buffer handling
IBUFG_inst : IBUFG
generic map (IOSTANDARD => "DEFAULT")
port map (
O => iCLKIN_IBUFG, -- Clock buffer output
I => CLOCK -- Clock buffer input (connect directly to top-level port)
);
-- output clock buffer handling
BUFG_inst : BUFG
port map (
O => iCLKFB_IN, -- Clock buffer output
I => iCLK0_OUT -- Clock buffer input
);
-- output clock buffer handling
BUFG_instX : BUFG
port map (
O => iCLKFX_OUT , -- Clock buffer output
I => iCLKFX -- Clock buffer input
);
-- DCM (48MHz/4 = 12MHz)
-- MULTIPLY 2
-- DIVIDE 8
-- (2 / 4) * 24 = (1 / 2) * 24 = 12
DCM_inst : DCM
generic map (
CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
-- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
CLKFX_DIVIDE => 4, -- Can be any integer from 1 to 32
CLKFX_MULTIPLY => 2, -- Can be any integer from 2 to 32
CLKIN_DIVIDE_BY_2 => TRUE, -- TRUE/FALSE to enable CLKIN divide by two feature
CLKIN_PERIOD => 20.833, -- Specify period of input clock
CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift of NONE, FIXED or VARIABLE
CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE, 1X or 2X
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
-- an integer from 0 to 15
DFS_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for frequency synthesis
DLL_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for DLL
DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE
FACTORY_JF => X"C080", -- FACTORY JF Values
PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255
SIM_MODE => "SAFE", -- Simulation: "SAFE" vs "FAST", see "Synthesis and Simulation
-- Design Guide" for details
STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE
port map (
CLK0 => iCLK0_OUT, -- 0 degree DCM CLK ouptput
CLK180 => open, -- 180 degree DCM CLK output
CLK270 => open, -- 270 degree DCM CLK output
CLK2X => open, -- 2X DCM CLK output
CLK2X180 => open, -- 2X, 180 degree DCM CLK out
CLK90 => open, -- 90 degree DCM CLK output
CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE)
CLKFX => iCLKFX, -- DCM CLK synthesis out (M/D)
CLKFX180 => open, -- 180 degree CLK synthesis out
LOCKED => open, -- DCM LOCK status output
PSDONE => open, -- Dynamic phase adjust done output
STATUS => open, -- 8-bit DCM status bits output
CLKFB => iCLKFB_IN, -- DCM clock feedback
CLKIN => iCLKIN_IBUFG, -- Clock input (from IBUFG, BUFG or DCM)
PSCLK => '0', -- Dynamic phase adjust clock input
PSEN => '0', -- Dynamic phase adjust enable input
PSINCDEC => '0', -- Dynamic phase adjust increment/decrement
RST => '0' -- DCM asynchronous reset input
);
RAMB16_S9_S9_instA : 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 => iADRA, -- Port A 11-bit Address Input
ADDRB => iADRB, -- Port B 11-bit Address Input
CLKA => iCLKFX_OUT, -- Port A Clock
CLKB => iCLKFX_OUT, -- 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
MCLKX <= not iCLKFX_OUT ;
ROUT <= (not iADRB(7 downto 0)) when ( SEL = '1' ) else
(not iADRA(7 downto 0)) ;
GOUT <= (not iADRB(10 downto 8)) when ( SEL = '1' ) else
(not iADRA(10 downto 8)) ;
-- output
ADBUS <= iDOB when ( RTRG = '1' and RSEL = "000" ) else -- B port data
iCMIN when ( RTRG = '1' and RSEL = "001" ) else -- min
iCMAX when ( RTRG = '1' and RSEL = "010" ) else -- max
iCTHVX when ( RTRG = '1' and RSEL = "011" ) else -- threshold
iBSFTV when ( RTRG = '1' and RSEL = "100" ) else -- binary data
(others => 'Z');
-- trigger
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iATRG_SFT <= "000" ;
iWTRG_SFT <= "000" ;
iCTRG_SFT <= "000" ;
iBTRG_SFT <= "000" ;
elsif rising_edge(iCLKFX_OUT) then
iATRG_SFT <= iATRG_SFT(1 downto 0) & ATRG ;
iWTRG_SFT <= iWTRG_SFT(1 downto 0) & WTRG ;
iCTRG_SFT <= iCTRG_SFT(1 downto 0) & CTRG ;
iBTRG_SFT <= iBTRG_SFT(1 downto 0) & BTRG ;
end if ;
end process ;
iATRG <= '1' when ( iATRG_SFT = "011" or iATRG_SFT = "001" ) else '0' ;
iWTRG <= '1' when ( iWTRG_SFT = "011" or iWTRG_SFT = "001" ) else '0' ;
iCTRG <= '1' when ( iCTRG_SFT = "011" or iCTRG_SFT = "001" ) else '0' ;
iBTRG <= '1' when ( iBTRG_SFT = "011" or iBTRG_SFT = "001" ) else '0' ;
-- sequencer (address handling)
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iASTATE <= "00" ;
iADRA <= (others => '0') ;
iADRB <= (others => '0') ;
iASEL <= "00" ;
iBPTR <= 0 ;
elsif rising_edge(iCLKFX_OUT) then
case conv_integer(iASTATE) is
-- wait trigger
when 0 => if ( iATRG = '1' ) then
iASTATE <= "01" ;
elsif ( iAXTRG = '1' ) then
iASTATE <= "01" ;
iASEL <= "01" ;
elsif ( iAYTRG = '1' ) then
iASTATE <= "01" ;
iASEL <= "10" ;
else
iASTATE <= "00" ;
end if ;
-- transfer
when 1 => iASTATE <= "11" ;
if ( iASEL(0) = '1' ) then
iAREG <= '0' & iCREG ;
elsif ( iASEL(1) = '1' ) then
iAREG <= '0' & iBREG ;
else
iAREG <= ADBUS(2 downto 0) ;
end if ;
-- decode
when 3 => iASTATE <= "10" ;
-- clear A port address
if ( iAREG = "000" ) then
iADRA <= (others => '0') ;
end if ;
-- increase A port address
if ( iAREG = "001" ) then
iADRA <= iADRA + '1' ;
end if ;
-- clear B port address
if ( iAREG = "010" ) then
iADRB <= (others => '0') ;
end if ;
-- increase B port address
if ( iAREG = "011" ) then
iADRB <= iADRB + '1' ;
end if ;
-- clear shift register pointer
if ( iAREG = "100" ) then
iBPTR <= 0 ;
end if ;
-- increase shift register pointer
if ( iAREG = "101" ) then
iBPTR <= iBPTR + 1 ;
end if ;
-- return first state
when 2 => iASTATE <= "00" ;
iASEL <= "00" ;
-- default
when others =>
iASTATE <= "00" ;
end case ;
end if ;
end process ;
-- sequencer (write handling)
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iWSTATE <= "00" ;
iDIA <= (others => '0') ;
elsif rising_edge(iCLKFX_OUT) then
case conv_integer(iWSTATE) is
-- wait trigger
when 0 => if ( iWTRG = '1' ) then
iWSTATE <= "01" ;
else
iWSTATE <= "00" ;
end if ;
-- get data
when 1 => iWSTATE <= "11" ;
iDIA <= ADBUS ;
-- send trigger
when 3 => iWSTATE <= "10" ;
-- return first state
when 2 => iWSTATE <= "00" ;
-- default
when others =>
iWSTATE <= "00" ;
end case ;
end if ;
end process ;
iWEA <= '1' when ( iWSTATE = "11" ) else '0' ;
-- sequencer (calculate)
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iCSTATE <= 0 ;
iCREG <= "00" ;
iCMAX <= (others => '0') ;
iCMIN <= (others => '0') ;
iCCOUNT <= 0 ;
iCTHV <= 0 ;
elsif rising_edge(iCLKFX_OUT) then
case iCSTATE is
-- wait trigger
when 0 => if ( iCTRG = '1' ) then
iCSTATE <= 1 ;
else
iCSTATE <= 0 ;
end if ;
-- clear B port address
when 1 => iCSTATE <= 2 ;
iCREG <= "10" ;
-- send trigger
when 2 => iCSTATE <= 3 ;
-- delay
when 3 => iCSTATE <= 4 ;
-- wait complete
when 4 => if ( iASTATE = "00" ) then
iCSTATE <= 5 ; -- next
else
iCSTATE <= 4 ; -- stay
end if ;
-- set MAX and MIN
when 5 => iCSTATE <= 6 ; -- next
iCMAX <= iDOB ; -- maximum
iCMIN <= iDOB ; -- minimum
iCCOUNT <= 0 ;
-- increse B port address
when 6 => iCSTATE <= 7 ;
iCREG <= "11" ;
iCCOUNT <= iCCOUNT + 1 ;
-- send trigger
when 7 => iCSTATE <= 8 ;
-- delay
when 8 => iCSTATE <= 9 ;
-- wait complete
when 9 => if ( iASTATE = "00" ) then
iCSTATE <= 10 ; -- next
else
iCSTATE <= 9 ; -- stay
end if ;
-- compare
when 10 => iCSTATE <= 11 ;
if ( conv_integer(iCMAX) < conv_integer(iDOB) ) then
iCMAX <= iDOB ;
end if ;
if ( conv_integer(iCMIN) > conv_integer(iDOB) ) then
iCMIN <= iDOB ;
end if ;
-- judge
when 11 => if ( iCCOUNT = PIXEL_LAST ) then
iCSTATE <= 12 ; -- exit
else
iCSTATE <= 6 ; -- loop
end if ;
-- return first state
when 12 => iCSTATE <= 0 ;
iCTHV <= (conv_integer(iCMAX)+conv_integer(iCMIN)) / 2 ;
-- default
when others =>
iCSTATE <= 0 ;
end case ;
end if ;
end process ;
iAXTRG <= '1' when ( iCSTATE = 2 or iCSTATE = 7 ) else '0' ;
iCTHVX <= conv_std_logic_vector(iCTHV,8) ;
-- sequencer (binary conversion)
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iBSTATE <= 0 ;
iBCOUNT <= 0 ;
iBREG <= "00" ;
iBDAT <= (others => '0') ;
elsif rising_edge(iCLKFX_OUT) then
case iBSTATE is
-- wait trigger
when 0 => if ( iBTRG = '1' ) then
iBSTATE <= 1 ;
else
iBSTATE <= 0 ;
end if ;
-- clear counter
when 1 => iBSTATE <= 2 ;
iBCOUNT <= 0 ;
-- set B port address zero
when 2 => iBSTATE <= 3 ;
iBREG <= "10" ;
-- send trigger
when 3 => iBSTATE <= 4 ;
-- delay
when 4 => iBSTATE <= 5 ;
-- wait complete
when 5 => if ( iASTATE = "00" ) then
iBSTATE <= 6 ;
else
iBSTATE <= 5 ;
end if ;
-- get memory data
when 6 => iBSTATE <= 7 ;
iBDAT <= iDOB ;
-- compare and store
when 7 => iBSTATE <= 8 ;
if ( conv_integer(iBDAT) > iCTHV ) then
iBSFT(iBCOUNT) <= '1' ;
else
iBSFT(iBCOUNT) <= '0' ;
end if ;
-- counter increment
when 8 => iBSTATE <= 9 ;
iBCOUNT <= iBCOUNT + 1 ;
-- judge complete
when 9 => if ( iBCOUNT = PIXEL_MAX ) then
iBSTATE <= 10 ; -- exit
else
iBSTATE <= 3 ; -- loop
iBREG <= "11" ; -- increse B port address
end if ;
-- set B port address zero
when 10 => iBSTATE <= 11 ;
iBREG <= "10" ;
-- send trigger
when 11 => iBSTATE <= 12 ;
-- return first state
when 12 => iBSTATE <= 0 ;
-- default
when others =>
iBSTATE <= 0 ;
end case ;
end if ;
end process ;
iAYTRG <= '1' when ( iBSTATE = 3 or iBSTATE = 11 ) else '0' ;
iBSFTV <= iBSFT(8*iBPTR to 8*iBPTR+7);
end Behavioral;
160ビットのレジスタを、DualPortMemoryをもう1ブロック
利用して実現した方が、内部デジタル回路を入れる領域を
消費しないのでよいかも知れませんが、動作するか否かを
チェックするので、ここまでとしています。
最終ピンアサインは、以下です。
# 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 "WTRG" LOC = "P12" | IOSTANDARD = LVCMOS33 ;
NET "CTRG" LOC = "P13" | IOSTANDARD = LVCMOS33 ;
NET "BTRG" LOC = "P14" | IOSTANDARD = LVCMOS33 ;
NET "RTRG" LOC = "P15" | IOSTANDARD = LVCMOS33 ;
NET "RSEL<0>" LOC = "P17" | IOSTANDARD = LVCMOS33 ;
NET "RSEL<1>" LOC = "P18" | IOSTANDARD = LVCMOS33 ;
NET "RSEL<2>" LOC = "P20" | IOSTANDARD = LVCMOS33 ;
# G0B
NET "ROUT<0>" LOC = "P141" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<1>" LOC = "P140" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<2>" LOC = "P137" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<3>" LOC = "P135" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<4>" LOC = "P132" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<5>" LOC = "P131" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<6>" LOC = "P130" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<7>" LOC = "P129" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
# G1B
NET "GOUT<0>" LOC = "P116" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<1>" LOC = "P113" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<2>" LOC = "P119" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "MCLKX" LOC = "P124" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
# G2B
NET "SEL" LOC = "P103" | IOSTANDARD = LVCMOS33 ;
特異点抽出
2値化ができたなら、0→1、1→0の特異点が
ピクセル中のどこにあるのかを求められます。
特異点を求めるVHDLコードは、次のように定義しました。
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iSSTATE <= "000" ;
iSCOUNT <= 0 ;
iSPLH <= 255 ;
iSPHL <= 255 ;
iSPLHOUT <= (others => '1') ;
iSPHLOUT <= (others => '1') ;
elsif rising_edge(iCLKFX) then
case conv_integer(iSSTATE) is
-- wait trigger
when 0 => if ( iSTRG = '1' ) then
iSSTATE <= "001" ;
else
iSSTATE <= "000" ;
end if ;
-- initialize
when 1 => iSSTATE <= "011" ;
iSCOUNT <= 0 ;
iSTMP <= iBSFT(0 to 1);
iSPLH <= 255 ;
iSPHL <= 255 ;
iSPLHOUT <= (others => '1') ;
iSPHLOUT <= (others => '1') ;
-- compare
when 3 => iSSTATE <= "111" ;
if ( iSTMP = SLHV ) then
iSPLH <= iSCOUNT ;
end if ;
if ( iSTMP = SHLV ) then
iSPHL <= iSCOUNT ;
end if ;
-- counter increment
when 7 => iSSTATE <= "110" ;
iSCOUNT <= iSCOUNT + 1 ;
-- judge
when 6 => if ( iSCOUNT = PIXEL_LAST ) then
iSSTATE <= "100" ;
else
iSSTATE <= "011" ;
iSTMP <= iSTMP(0) & iBSFT(iSCOUNT+1) ;
end if ;
-- return first state
when 4 => iSSTATE <= "000" ;
iSPLHOUT <= conv_std_logic_vector(iSPLH,8) ;
iSPHLOUT <= conv_std_logic_vector(iSPHL,8) ;
-- default
when others =>
iSSTATE <= "000" ;
end case ;
end if ;
end process ;
トリガーが来たら、カウンタ、特異点位置を初期化し
2値化されたレジスタの値を2ビットずつ"01"と"10"
照合します。
ビットバターンが一致したとき、カウンタ値を特異点
の位置として更新します。
高速動作が可能になるよう、ジョンソンカウンタで
状態遷移させます。2値化された値を格納している
レジスタから、2ビットずつシフトレジスタに入れ
照合します。照合が終わると、レジスタの1ビット
を取り出して、対象となる2ビットを更新です。
ARMが読出しやすいよう、特異点位置を出力バッファに
保存してから、終了にしました。
特異点位置を見つけるシーケンサの動作開始には
トリガーを使います。2値化担当のシーケンサが
開始トリガーを出力することに。
トリガーは、2値化担当シーケンサのステート値
をデコードして生成できるます。
iSTRG <= '1' when ( iBSTATE = 11 ) else '0' ;
ARMから画像データに相当する値を、DualPortMemoryに
転送したなら、計算開始トリガーを出し特異点位置まで
一気に求めた方が楽です。そこで、3つのシーケンサが
ドミノ倒しの要領で動くように、トリガーを決めます。
計算開始トリガーを与えてから、どのくらいの時間で
処理完了になるのかを計測できるように、カウンタを
使います。
-- measure calcualte time sequencer
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iTSTATE <= "00" ;
iTCOUNT <= (others => '0') ;
elsif rising_edge(iCLKFX) then
case conv_integer(iTSTATE) is
-- wait start (iCTRG) trigger
when 0 => if ( iCTRG = '1' ) then
iTSTATE <= "01" ;
else
iTSTATE <= "00" ;
end if ;
-- initialize counter
when 1 => iTSTATE <= "11" ;
iTCOUNT <= (others => '0') ;
-- wait exit (iSEXIT) trigger
when 3 => if ( iSEXIT = '1' ) then
iTSTATE <= "10" ;
else
iTSTATE <= "11" ;
iTCOUNT <= iTCOUNT + '1' ;
end if ;
-- return first state
when 2 => iTSTATE <= "00" ;
-- default
when others =>
iTSTATE <= "00" ;
end case ;
end if ;
end process ;
計算開始トリガーと終了フラグを使い、その間の
カウントで、時間を等価カウントに置き換えます。
実際に計算開始トリガーを与えて計測すると
等価カウントは、897でした。
12MHzで動かしたので、所要時間は約74usです。
1ラインで約100usの所要時間とすると、3ライン
では、300us程度になります。
OV7570は、30フレーム程度の画像データ更新が最高
なので、1フレームの取得時間は33ms。3ライン分
の画像データを処理して、特異点を見つけたとして
34msごとに、新しい特異点を取得できます。
これが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 dpmtsty is
generic (
PIXEL_MAX : integer := 160 ;
PIXEL_LAST : integer := 159 ;
ADRACLR : std_logic_vector(2 downto 0) := "000" ;
ADRAINC : std_logic_vector(2 downto 0) := "001" ;
ADRBCLR : std_logic_vector(2 downto 0) := "010" ;
ADRBINC : std_logic_vector(2 downto 0) := "011" ;
SFTACLR : std_logic_vector(2 downto 0) := "100" ;
SFTAINC : std_logic_vector(2 downto 0) := "101" ;
SHLV : std_logic_vector(1 downto 0) := "10" ;
SLHV : std_logic_vector(1 downto 0) := "01" --;
) ;
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
ATRG : in std_logic ;
WTRG : in std_logic ;
CTRG : in std_logic ;
RTRG : in std_logic ;
RSEL : in std_logic_vector(2 downto 0) ;
-- data BUS
ADBUS : inout std_logic_vector(7 downto 0) ;
-- address monitor
SEL : in std_logic ;
ROUT : out std_logic_vector(7 downto 0) ;
GOUT : out std_logic_vector(7 downto 0) ;
MCLKX : out std_logic -- ;
);
end dpmtsty;
architecture Behavioral of dpmtsty is
-- clock (input)
signal iCLK0_OUT : std_logic ;
signal iCLKFX : std_logic ;
signal iCLKFB_IN : std_logic ;
signal iCLKIN_IBUFG : std_logic ;
-- trigger
signal iATRG_SFT : std_logic_vector(2 downto 0) ;
signal iWTRG_SFT : std_logic_vector(2 downto 0) ;
signal iCTRG_SFT : std_logic_vector(2 downto 0) ;
signal iATRG : std_logic ;
signal iWTRG : std_logic ;
signal iCTRG : std_logic ;
signal iBTRG : std_logic ;
-- address sequencer
signal iASTATE : std_logic_vector(1 downto 0) ;
signal iAREG : std_logic_vector(2 downto 0) ;
signal iASEL : std_logic_vector(1 downto 0) ;
-- data sequencer
signal iWSTATE : std_logic_vector(1 downto 0) ;
-- calculate sequencer
signal iCSTATE : integer range 0 to 12 ;
signal iCREG : std_logic_vector(1 downto 0) ;
signal iAXTRG : std_logic ;
signal iCMAX : std_logic_vector(7 downto 0) ;
signal iCMIN : std_logic_vector(7 downto 0) ;
signal iCCOUNT : integer range 0 to PIXEL_LAST ;
signal iCTHV : integer range 0 to 255 ;
signal iCTHVX : std_logic_vector(7 downto 0) ;
-- binary conversion sequencer
signal iBSTATE : integer range 0 to 12 ;
signal iBREG : std_logic_vector(1 downto 0) ;
signal iBDAT : std_logic_vector(7 downto 0) ;
signal iAYTRG : std_logic ;
signal iBCOUNT : integer range 0 to PIXEL_LAST ;
signal iBSFT : std_logic_vector(0 to PIXEL_LAST) ;
signal iBPTR : integer range 0 to 21 ;
signal iBSFTV : std_logic_vector(0 to 7) ;
-- internal registers (A port)
signal iADRA : std_logic_vector(10 downto 0) ;
signal iDIA : std_logic_vector( 7 downto 0) ;
signal iWEA : std_logic ;
-- internal registers (Bport)
signal iDOB : std_logic_vector( 7 downto 0) ;
signal iADRB : std_logic_vector(10 downto 0) ;
-- scan sequencer
signal iSSTATE : std_logic_vector(2 downto 0) ;
signal iSTRG : std_logic ;
signal iSEXIT : std_logic ;
signal iSTMP : std_logic_vector(1 downto 0) ;
signal iSCOUNT : integer range 0 to PIXEL_LAST ;
signal iSPLH : integer range 0 to 255 ;
signal iSPHL : integer range 0 to 255 ;
signal iSPLHOUT : std_logic_vector(7 downto 0) ;
signal iSPHLOUT : std_logic_vector(7 downto 0) ;
-- measure time sequencer
signal iTSTATE : std_logic_vector( 1 downto 0) ;
signal iTCOUNT : std_logic_vector(15 downto 0) ;
begin
-- input clock buffer handling
IBUFG_inst : IBUFG
generic map (IOSTANDARD => "DEFAULT")
port map (
O => iCLKIN_IBUFG, -- Clock buffer output
I => CLOCK -- Clock buffer input (connect directly to top-level port)
);
-- output clock buffer handling
BUFG_inst : BUFG
port map (
O => iCLKFB_IN, -- Clock buffer output
I => iCLK0_OUT -- Clock buffer input
);
-- DCM (48MHz/4 = 12MHz)
-- MULTIPLY 2
-- DIVIDE 8
-- (2 / 4) * 24 = (1 / 2) * 24 = 12
DCM_inst : DCM
generic map (
CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
-- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
CLKFX_DIVIDE => 4, -- Can be any integer from 1 to 32
CLKFX_MULTIPLY => 2, -- Can be any integer from 2 to 32
CLKIN_DIVIDE_BY_2 => TRUE, -- TRUE/FALSE to enable CLKIN divide by two feature
CLKIN_PERIOD => 20.833, -- Specify period of input clock
CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift of NONE, FIXED or VARIABLE
CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE, 1X or 2X
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
-- an integer from 0 to 15
DFS_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for frequency synthesis
DLL_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for DLL
DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE
FACTORY_JF => X"C080", -- FACTORY JF Values
PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255
SIM_MODE => "SAFE", -- Simulation: "SAFE" vs "FAST", see "Synthesis and Simulation
-- Design Guide" for details
STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE
port map (
CLK0 => iCLK0_OUT, -- 0 degree DCM CLK ouptput
CLK180 => open, -- 180 degree DCM CLK output
CLK270 => open, -- 270 degree DCM CLK output
CLK2X => open, -- 2X DCM CLK output
CLK2X180 => open, -- 2X, 180 degree DCM CLK out
CLK90 => open, -- 90 degree DCM CLK output
CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE)
CLKFX => iCLKFX, -- DCM CLK synthesis out (M/D)
CLKFX180 => open, -- 180 degree CLK synthesis out
LOCKED => open, -- DCM LOCK status output
PSDONE => open, -- Dynamic phase adjust done output
STATUS => open, -- 8-bit DCM status bits output
CLKFB => iCLKFB_IN, -- DCM clock feedback
CLKIN => iCLKIN_IBUFG, -- Clock input (from IBUFG, BUFG or DCM)
PSCLK => '0', -- Dynamic phase adjust clock input
PSEN => '0', -- Dynamic phase adjust enable input
PSINCDEC => '0', -- Dynamic phase adjust increment/decrement
RST => '0' -- DCM asynchronous reset input
);
RAMB16_S9_S9_instA : 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 => iADRA, -- Port A 11-bit Address Input
ADDRB => iADRB, -- Port B 11-bit Address Input
CLKA => iCLKFX, -- Port A Clock
CLKB => iCLKFX, -- 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
MCLKX <= not iCLKFX ;
ROUT <= (not iTCOUNT(7 downto 0)) when ( SEL = '0' ) else
(not iADRB(7 downto 0));
GOUT <= (not iTCOUNT(15 downto 8)) when ( SEL = '0') else
(not ("00000" & iADRB(10 downto 8))) ;
-- output
ADBUS <= iDOB when ( RTRG = '1' and RSEL = "000" ) else -- B port data
iCMIN when ( RTRG = '1' and RSEL = "001" ) else -- min
iCMAX when ( RTRG = '1' and RSEL = "010" ) else -- max
iCTHVX when ( RTRG = '1' and RSEL = "011" ) else -- threshold
iBSFTV when ( RTRG = '1' and RSEL = "100" ) else -- binary data
iSPLHOUT when ( RTRG = '1' and RSEL = "101" ) else -- position LH
iSPHLOUT when ( RTRG = '1' and RSEL = "110" ) else -- position HL
(others => 'Z');
-- trigger
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iATRG_SFT <= "000" ;
iWTRG_SFT <= "000" ;
iCTRG_SFT <= "000" ;
elsif rising_edge(iCLKFX) then
iATRG_SFT <= iATRG_SFT(1 downto 0) & ATRG ;
iWTRG_SFT <= iWTRG_SFT(1 downto 0) & WTRG ;
iCTRG_SFT <= iCTRG_SFT(1 downto 0) & CTRG ;
end if ;
end process ;
iATRG <= '1' when ( iATRG_SFT = "011" or iATRG_SFT = "001" ) else '0' ;
iWTRG <= '1' when ( iWTRG_SFT = "011" or iWTRG_SFT = "001" ) else '0' ;
iCTRG <= '1' when ( iCTRG_SFT = "011" or iCTRG_SFT = "001" ) else '0' ;
-- sequencer (address handling)
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iASTATE <= "00" ;
iADRA <= (others => '0') ;
iADRB <= (others => '0') ;
iASEL <= "00" ;
iBPTR <= 0 ;
elsif rising_edge(iCLKFX) then
case conv_integer(iASTATE) is
-- wait trigger
when 0 => if ( iATRG = '1' ) then
iASTATE <= "01" ;
elsif ( iAXTRG = '1' ) then
iASTATE <= "01" ;
iASEL <= "01" ;
elsif ( iAYTRG = '1' ) then
iASTATE <= "01" ;
iASEL <= "10" ;
else
iASTATE <= "00" ;
end if ;
-- transfer
when 1 => iASTATE <= "11" ;
if ( iASEL(0) = '1' ) then
iAREG <= '0' & iCREG ;
elsif ( iASEL(1) = '1' ) then
iAREG <= '0' & iBREG ;
else
iAREG <= ADBUS(2 downto 0) ;
end if ;
-- decode
when 3 => iASTATE <= "10" ;
-- clear A port address
if ( iAREG = ADRACLR ) then
iADRA <= (others => '0') ;
end if ;
-- increase A port address
if ( iAREG = ADRAINC ) then
iADRA <= iADRA + '1' ;
end if ;
-- clear B port address
if ( iAREG = ADRBCLR ) then
iADRB <= (others => '0') ;
end if ;
-- increase B port address
if ( iAREG = ADRBINC ) then
iADRB <= iADRB + '1' ;
end if ;
-- clear shift register pointer
if ( iAREG = SFTACLR ) then
iBPTR <= 0 ;
end if ;
-- increase shift register pointer
if ( iAREG = SFTAINC ) then
iBPTR <= iBPTR + 1 ;
end if ;
-- return first state
when 2 => iASTATE <= "00" ;
iASEL <= "00" ;
-- default
when others =>
iASTATE <= "00" ;
end case ;
end if ;
end process ;
-- sequencer (write handling)
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iWSTATE <= "00" ;
iDIA <= (others => '0') ;
elsif rising_edge(iCLKFX) then
case conv_integer(iWSTATE) is
-- wait trigger
when 0 => if ( iWTRG = '1' ) then
iWSTATE <= "01" ;
else
iWSTATE <= "00" ;
end if ;
-- get data
when 1 => iWSTATE <= "11" ;
iDIA <= ADBUS ;
-- send trigger
when 3 => iWSTATE <= "10" ;
-- return first state
when 2 => iWSTATE <= "00" ;
-- default
when others =>
iWSTATE <= "00" ;
end case ;
end if ;
end process ;
iWEA <= '1' when ( iWSTATE = "11" ) else '0' ;
-- sequencer (calculate)
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iCSTATE <= 0 ;
iCREG <= "00" ;
iCMAX <= (others => '0') ;
iCMIN <= (others => '0') ;
iCCOUNT <= 0 ;
iCTHV <= 0 ;
elsif rising_edge(iCLKFX) then
case iCSTATE is
-- wait trigger
when 0 => if ( iCTRG = '1' ) then
iCSTATE <= 1 ;
else
iCSTATE <= 0 ;
end if ;
-- clear B port address
when 1 => iCSTATE <= 2 ;
iCREG <= "10" ;
-- send trigger
when 2 => iCSTATE <= 3 ;
-- delay
when 3 => iCSTATE <= 4 ;
-- wait complete
when 4 => if ( iASTATE = "00" ) then
iCSTATE <= 5 ; -- next
else
iCSTATE <= 4 ; -- stay
end if ;
-- set MAX and MIN
when 5 => iCSTATE <= 6 ; -- next
iCMAX <= iDOB ; -- maximum
iCMIN <= iDOB ; -- minimum
iCCOUNT <= 0 ;
-- increse B port address
when 6 => iCSTATE <= 7 ;
iCREG <= "11" ;
iCCOUNT <= iCCOUNT + 1 ;
-- send trigger
when 7 => iCSTATE <= 8 ;
-- delay
when 8 => iCSTATE <= 9 ;
-- wait complete
when 9 => if ( iASTATE = "00" ) then
iCSTATE <= 10 ; -- next
else
iCSTATE <= 9 ; -- stay
end if ;
-- compare
when 10 => iCSTATE <= 11 ;
if ( conv_integer(iCMAX) < conv_integer(iDOB) ) then
iCMAX <= iDOB ;
end if ;
if ( conv_integer(iCMIN) > conv_integer(iDOB) ) then
iCMIN <= iDOB ;
end if ;
-- judge
when 11 => if ( iCCOUNT = PIXEL_LAST ) then
iCSTATE <= 12 ; -- exit
else
iCSTATE <= 6 ; -- loop
end if ;
-- return first state
when 12 => iCSTATE <= 0 ;
iCTHV <= (conv_integer(iCMAX)+conv_integer(iCMIN)) / 2 ;
-- default
when others =>
iCSTATE <= 0 ;
end case ;
end if ;
end process ;
iAXTRG <= '1' when ( iCSTATE = 2 or iCSTATE = 7 ) else '0' ;
iCTHVX <= conv_std_logic_vector(iCTHV,8) ;
iBTRG <= '1' when ( iCSTATE = 12 ) else '0' ;
-- sequencer (binary conversion)
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iBSTATE <= 0 ;
iBCOUNT <= 0 ;
iBREG <= "00" ;
iBDAT <= (others => '0') ;
elsif rising_edge(iCLKFX) then
case iBSTATE is
-- wait trigger
when 0 => if ( iBTRG = '1' ) then
iBSTATE <= 1 ;
else
iBSTATE <= 0 ;
end if ;
-- clear counter
when 1 => iBSTATE <= 2 ;
iBCOUNT <= 0 ;
-- set B port address zero
when 2 => iBSTATE <= 3 ;
iBREG <= "10" ;
-- send trigger
when 3 => iBSTATE <= 4 ;
-- delay
when 4 => iBSTATE <= 5 ;
-- wait complete
when 5 => if ( iASTATE = "00" ) then
iBSTATE <= 6 ;
else
iBSTATE <= 5 ;
end if ;
-- get memory data
when 6 => iBSTATE <= 7 ;
iBDAT <= iDOB ;
-- compare and store
when 7 => iBSTATE <= 8 ;
if ( conv_integer(iBDAT) > iCTHV ) then
iBSFT(iBCOUNT) <= '1' ;
else
iBSFT(iBCOUNT) <= '0' ;
end if ;
-- counter increment
when 8 => iBSTATE <= 9 ;
iBCOUNT <= iBCOUNT + 1 ;
-- judge complete
when 9 => if ( iBCOUNT = PIXEL_MAX ) then
iBSTATE <= 10 ; -- exit
else
iBSTATE <= 3 ; -- loop
iBREG <= "11" ; -- increse B port address
end if ;
-- set B port address zero
when 10 => iBSTATE <= 11 ;
iBREG <= "10" ;
-- send trigger
when 11 => iBSTATE <= 12 ;
-- return first state
when 12 => iBSTATE <= 0 ;
-- default
when others =>
iBSTATE <= 0 ;
end case ;
end if ;
end process ;
iAYTRG <= '1' when ( iBSTATE = 3 or iBSTATE = 11 ) else '0' ;
iBSFTV <= iBSFT(8*iBPTR to 8*iBPTR+7);
iSTRG <= '1' when ( iBSTATE = 11 ) else '0' ;
-- sequencer (scan)
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iSSTATE <= "000" ;
iSCOUNT <= 0 ;
iSPLH <= 255 ;
iSPHL <= 255 ;
iSPLHOUT <= (others => '1') ;
iSPHLOUT <= (others => '1') ;
elsif rising_edge(iCLKFX) then
case conv_integer(iSSTATE) is
-- wait trigger
when 0 => if ( iSTRG = '1' ) then
iSSTATE <= "001" ;
else
iSSTATE <= "000" ;
end if ;
-- initialize
when 1 => iSSTATE <= "011" ;
iSCOUNT <= 0 ;
iSTMP <= iBSFT(0 to 1);
iSPLH <= 255 ;
iSPHL <= 255 ;
iSPLHOUT <= (others => '1') ;
iSPHLOUT <= (others => '1') ;
-- compare
when 3 => iSSTATE <= "111" ;
if ( iSTMP = SLHV ) then
iSPLH <= iSCOUNT ;
end if ;
if ( iSTMP = SHLV ) then
iSPHL <= iSCOUNT ;
end if ;
-- counter increment
when 7 => iSSTATE <= "110" ;
iSCOUNT <= iSCOUNT + 1 ;
-- judge
when 6 => if ( iSCOUNT = PIXEL_LAST ) then
iSSTATE <= "100" ;
else
iSSTATE <= "011" ;
iSTMP <= iSTMP(0) & iBSFT(iSCOUNT+1) ;
end if ;
-- return first state
when 4 => iSSTATE <= "000" ;
iSPLHOUT <= conv_std_logic_vector(iSPLH,8) ;
iSPHLOUT <= conv_std_logic_vector(iSPHL,8) ;
-- default
when others =>
iSSTATE <= "000" ;
end case ;
end if ;
end process ;
iSEXIT <= '1' when ( iSSTATE = "100" ) else '0' ;
-- measure calcualte time sequencer
process (nRESET,iCLKFX)
begin
if ( nRESET = '0' ) then
iTSTATE <= "00" ;
iTCOUNT <= (others => '0') ;
elsif rising_edge(iCLKFX) then
case conv_integer(iTSTATE) is
-- wait start (iCTRG) trigger
when 0 => if ( iCTRG = '1' ) then
iTSTATE <= "01" ;
else
iTSTATE <= "00" ;
end if ;
-- initialize counter
when 1 => iTSTATE <= "11" ;
iTCOUNT <= (others => '0') ;
-- wait exit (iSEXIT) trigger
when 3 => if ( iSEXIT = '1' ) then
iTSTATE <= "10" ;
else
iTSTATE <= "11" ;
iTCOUNT <= iTCOUNT + '1' ;
end if ;
-- return first state
when 2 => iTSTATE <= "00" ;
-- default
when others =>
iTSTATE <= "00" ;
end case ;
end if ;
end process ;
end Behavioral;
ピン配置は、次のように変更しました。
# 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 "WTRG" LOC = "P12" | IOSTANDARD = LVCMOS33 ;
NET "CTRG" LOC = "P13" | IOSTANDARD = LVCMOS33 ;
NET "RTRG" LOC = "P15" | IOSTANDARD = LVCMOS33 ;
NET "RSEL<0>" LOC = "P17" | IOSTANDARD = LVCMOS33 ;
NET "RSEL<1>" LOC = "P18" | IOSTANDARD = LVCMOS33 ;
NET "RSEL<2>" LOC = "P20" | IOSTANDARD = LVCMOS33 ;
# G0B
NET "ROUT<0>" LOC = "P141" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<1>" LOC = "P140" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<2>" LOC = "P137" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<3>" LOC = "P135" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<4>" LOC = "P132" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<5>" LOC = "P131" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<6>" LOC = "P130" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "ROUT<7>" LOC = "P129" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
# G1B
NET "GOUT<0>" LOC = "P116" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<1>" LOC = "P113" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<2>" LOC = "P119" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<3>" LOC = "P118" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<4>" LOC = "P123" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<5>" LOC = "P122" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<6>" LOC = "P125" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "GOUT<7>" LOC = "P124" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
# G2B
NET "SEL" LOC = "P103" | IOSTANDARD = LVCMOS33 ;
NET "MCLKX" LOC = "P100" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
計算処理開始のトリガーをひとつにしたので
ARMのファームウエアもコマンドを次のように
絞りこみます。
- ? help
- A handling address
- W write value to A port
- R read B port data
- F fill SRAM
- E store data to SRAM
- D dump SRAM contents
- T transfer data
- C calculate
- X read binary data
変更したファームウエアで、FPGA内部のデジタル回路に
データ転送、計算させると、次のようになります。
'R'コマンドで、DualPortMemoryの内容表示。
'F'コマンドで、ARM内部の配列に値設定。
'E'コマンドで、配列の1バイトの内容変更。
'T'コマンドで、ARMからFPGAにデータ転送。
'C'コマンドで、特異点まで計算。
'X'コマンドで、2値化データと特異点位置を表示。
変更したファームウエアのソースコードは、以下です。
#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
#define ASFT 16
#define WSFT 17
#define CSFT 18
#define RSFT 20
#define ATRG 1
#define WTRG 2
#define CTRG 4
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_100us(UWORD x);
void read_loop(void);
void write_loop(void);
void put_fpga(UWORD x);
UBYTE get_fpga(UBYTE x);
void dump_array(void);
void fill_array(UBYTE x);
void read_binary(void);
void show_hex(UBYTE x,UBYTE chx);
/* 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 UWORD madra ;
volatile UWORD madrb ;
#define ALAST 160
volatile UBYTE gdat[ALAST] ;
int main(void)
{
UBYTE tmp ;
/* 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' ) {
/* get parameter */
tmp = get_hex( *(sbuf+1) );
/* send command */
put_fpga( (ATRG << 8) | tmp ) ;
/* update local address */
if ( tmp == 0 ) { madra = 0 ; }
if ( tmp == 2 ) { madrb = 0 ; }
if ( tmp == 1 ) { madra++ ; }
if ( tmp == 3 ) { madrb++ ; }
}
/* transfer data to A port */
if ( cmd == 'T' ) {
write_loop();
/* show internal array context */
dump_array();
/* show FPGA dual port memory context */
read_loop();
}
/* send calculate trigger */
if ( cmd == 'C' ) {
put_fpga( (CTRG << 8) | 0x00 );
/* delay */
delay_100us(100);
/* show FPGA dual port memory context */
read_loop();
}
/* dump SRAM contents */
if ( cmd == 'D' ) { dump_array(); }
/* store data to SRAM */
if ( cmd == 'E' ) {
/* get address */
tmp = get_hex( *(sbuf+1) ); /* get upper nibble */
tmp <<= 4 ;
tmp |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */
/* get data */
dat = get_hex( *(sbuf+3) ); /* get upper nibble */
dat <<= 4 ;
dat |= get_hex( *(sbuf+4) ); /* concatenate lower nibble */
/* store */
*(gdat+tmp) = dat ;
/* show internal array context */
dump_array();
}
/* fill SRAM */
if ( cmd == 'F' ) {
/* get data */
dat = get_hex( *(sbuf+1) ); /* get upper nibble */
dat <<= 4 ;
dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */
/* store */
fill_array(dat);
/* show */
dump_array();
}
/* show binary data */
if ( cmd == 'X' ) { read_binary() ; }
/* store data from A port */
if ( cmd == 'W' ) {
/* get data */
dat = get_hex( *(sbuf+1) ); /* get upper nibble */
dat <<= 4 ;
dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */
/* send data */
put_fpga( (WTRG << 8) | dat ) ;
}
/* read B port data */
if ( cmd == 'R' ) { read_loop(); }
}
}
/* 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 ;
}
/* */
madra = 0 ;
madrb = 0 ;
dat = 0 ;
fill_array( 0x00 );
/* 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 handling address") ; crlf();
rs_puts(" A0 clear A port address") ; crlf();
rs_puts(" A1 increase A port address") ; crlf();
rs_puts(" A2 clear B port address") ; crlf();
rs_puts(" A3 increase B port address") ; crlf();
rs_puts("W write value to A port ") ; crlf();
rs_puts("R read B port data") ; crlf();
rs_puts("T transfer data") ; crlf();
rs_puts("C calculate") ; crlf();
rs_puts("D dump SRAM contents") ; crlf();
rs_puts("F fill SRAM") ; crlf();
rs_puts("E store data to SRAM") ; crlf();
rs_puts("X read binary data") ; crlf();
}
void delay_100us(UWORD x)
{
ULONG last ;
/* calculate */
last = timcnt + x ;
/* wait */
while ( timcnt < last ) ;
}
void dump_array(void)
{
UBYTE result ;
UBYTE madr[4] ;
UBYTE i ;
/* default */
*(madr+2) = ':';
*(madr+3) = '\0';
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) {
/* show address */
if ( (i & MASK0F) == 0 ) {
/* calculate address */
*(madr+0) = ((i >> 4) & MASK0F);
*(madr+1) = (i & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
/* show */
rs_puts( madr );
}
/* get data */
result = *(gdat+i) ;
/* show */
show_hex( result , ' ' ) ;
/* judge new line */
if ( (i & MASK0F) == 15 ) { crlf(); }
}
/* new line */
crlf();
}
void fill_array(UBYTE x)
{
UBYTE i ;
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) { *(gdat+i) = x ; }
}
void read_loop(void)
{
UBYTE result ;
UBYTE madr[6] ;
UBYTE i ;
/* default */
*(madr+4) = ':';
*(madr+5) = '\0';
/* clear B port address */
put_fpga((ATRG << 8) | 0x02);
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) {
/* show address */
if ( (i & MASK0F) == 0 ) {
/* calculate address */
*(madr+0) = ((i >> 12) & MASK0F) ;
*(madr+1) = ((i >> 8) & MASK0F) ;
*(madr+2) = ((i >> 4) & MASK0F);
*(madr+3) = (i & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
*(madr+2) = asc_hex[*(madr+2)] ;
*(madr+3) = asc_hex[*(madr+3)] ;
/* show */
rs_puts( madr );
}
/* get data */
result = get_fpga(0) ;
/* show */
show_hex( result , ' ' ) ;
/* judge new line */
if ( (i & MASK0F) == 15 ) { crlf(); }
/* address increment */
put_fpga((ATRG << 8) | 0x03);
}
/* new line */
crlf();
/* clear address */
put_fpga((ATRG << 8) | 0x02);
/* minimum */
{
result = get_fpga(1) ;
rs_puts("Minimum = ");
show_hex( result , '\n' ) ;
}
/* maximum */
{
result = get_fpga(2) ;
rs_puts("Maximum = ");
show_hex( result , '\n' ) ;
}
/* threshold */
{
result = get_fpga(3) ;
rs_puts("Threshold = ");
show_hex( result , '\n' ) ;
}
}
void write_loop(void)
{
UBYTE tmp ;
UBYTE i ;
/* clear A port address */
put_fpga((ATRG << 8) | 0x00);
/* loop */
for ( i = 0 ; i < ALAST ; i++ ) {
/* get data */
tmp = *(gdat+i) ;
/* send */
put_fpga((WTRG << 8) | tmp) ;
/* A port address increment */
put_fpga((ATRG << 8) | 0x01);
}
/* clear A port address */
put_fpga((ATRG << 8) | 0x00);
/* new line */
crlf();
}
void put_fpga(UWORD x)
{
UBYTE xcmd ;
UBYTE xsft ;
/* impress data to GP3 */
GP3DAT &= 0xFF00FFFF ;
GP3DAT |= ((x & MASKFF) << 16) ;
/* judge trigger */
xcmd = (x >> 8) & MASKFF ;
if ( xcmd == ATRG ) { xsft = ASFT ; }
if ( xcmd == WTRG ) { xsft = WSFT ; }
if ( xcmd == CTRG ) { xsft = CSFT ; }
/* trigger */
GP2DAT &= 0xFF00FFFF ;
GP2DAT |= (1 << xsft) ;
GP2DAT &= 0xFF00FFFF ;
}
UBYTE get_fpga(UBYTE x)
{
UBYTE result ;
/* change GP3 input */
GP3DAT &= 0x00FFFFFF ;
/* enable OE */
GP2DAT &= 0xFF00FFFF ;
GP2DAT |= ((x << 21) | (1 << RSFT));
/* RSEL2 RSEL1 RSEL0 RTRG = 23 22 21 20 */
/* delay */
delay_100us(2);
/* get data */
result = GP3DAT & MASKFF ;
/* disable OE */
GP2DAT &= 0xFF00FFFF ;
/* change GP3 output */
GP3DAT |= 0xFF000000 ;
return result ;
}
void read_binary(void)
{
UBYTE result ;
UBYTE madr[4] ;
UBYTE i ;
/* default */
*(madr+2) = ':';
*(madr+3) = '\0';
/* clear shift register address address */
put_fpga((ATRG << 8) | 0x04);
/* loop */
for ( i = 0 ; i < 20 ; i++ ) {
/* show address */
if ( (i % 8) == 0 ) {
/* calculate bit address */
result = (i << 3);
*(madr+0) = ((result >> 4) & MASK0F);
*(madr+1) = (result & MASK0F) ;
/* convert */
*(madr+0) = asc_hex[*(madr+0)] ;
*(madr+1) = asc_hex[*(madr+1)] ;
/* show */
rs_puts( madr );
}
/* get data */
result = get_fpga(4) ;
/* show */
rs_putchar( ((result >> 7) & 1) + '0' );
rs_putchar( ((result >> 6) & 1) + '0' );
rs_putchar( ((result >> 5) & 1) + '0' );
rs_putchar( ((result >> 4) & 1) + '0' );
rs_putchar( ((result >> 3) & 1) + '0' );
rs_putchar( ((result >> 2) & 1) + '0' );
rs_putchar( ((result >> 1) & 1) + '0' );
rs_putchar( (result & 1) + '0' );
rs_putchar('_');
/* judge new line */
if ( (i % 8) == 7 ) { crlf(); }
/* shift register increment */
put_fpga((ATRG << 8) | 0x05);
}
/* new line */
crlf();
/* clear shift register address address */
put_fpga((ATRG << 8) | 0x04);
/* position L -> H */
{
result = get_fpga(5) ;
rs_puts("location(0->1) : ");
show_hex( result , '\n' ) ;
}
/* position H -> L */
{
result = get_fpga(6) ;
rs_puts("location(1->0) : ");
show_hex( result , '\n' ) ;
}
}
void show_hex(UBYTE x,UBYTE chx)
{
rs_putchar(asc_hex[(x >> 4) & MASK0F]);
rs_putchar(asc_hex[x & MASK0F]);
if ( chx == '\n' ) { crlf(); }
else { rs_putchar(chx) ;}
}
目次
前