目次
前
次
画像処理下準備1
SCCBによるカメラの初期設定ができたので、FPGAに
入れる画像処理回路に必要となるVHDLコードを用意します。
FPGAは、mugen2012を動かしたSpratan3を使います。
Spratan3には、デュアルポートSRAMが内蔵されている
ので、FIFOなしカメラから転送された、画像データを
保存します。
XilinxのISEには、VHDLコードのテンプレートが用意
されているので、18kビットのデュアルポートSRAMに
データを書込み、読出す処理で、動作をテストします。
VHDLコードから抽出した信号名は、次のように
なっていました。
FPGA内部での同期に、クロックを利用します。
デュアルポートというので、A、Bの2つのポート
がありますが、個別に動作させられます。
データは、18ビットの入力、出力が基本ですが
パリティとデータに分けて扱います。
パリティと言っても、データ中の1の個数に関連した
情報を扱うのではなく、単純にデータへの付加情報と
して扱います。
パリティは1ビットであっても、バスで扱う仕様に
なっています。今回は、16ビットで1データを扱い
2ビットパリティ、16ビットデータにします。
デュアルポートなので、Aポート、Bポートに分けて
次のように扱います。
- Aポートは、書込みだけに利用
- Aポートの読出しは、利用しない
- Aポートの書込みパリティは、常に00とする
- Bポートは、読出しだけに利用
- Bポートの書込みは、利用しない
- Bポートは、読出したパリティは、無視
書込み、読出しには制御信号が必要になりますが
WEが対応します。他に、SSRがありますが、この
信号は、メモリデータを全セットかリセットする
同期処理をしたい場合に使います。
仕様で決めた内容を、信号に反映させると以下。
- ENA 1
- WEA pulse
- SSRA 0
- ENB 1
- WEB 0
- SSRB 0
テストであっても、実処理に近い内容で動作させ
たいので、次のように仕様を決めました。
- 1ワードを16ビットとして扱う
- Aポートから、1024ワードのデータを書込み
- 書込みデータは、上位8ビットが0xAA、0x55で下位8ビットは0〜255のいずれか
- 上位8ビットは、アドレスのLSBが0なら0xAA、それ以外は0x55
- 下位8ビットは、アドレスの下位8ビットと同じ
- Bポートから、1024ワードのデータを読出し
- 読出しアドレスは、FPGA内部で生成
- 読出しアドレスは、FPGA外部からの制御信号でリセット、インクリメント
- Bポートからの読出しデータは、LEDで確認
上の仕様をまとめると、次の動作確認ブロック図になります。
デュアルポートSRAMのAポートから、1ワード
データを書込むために、シーケンサを用意します。
トリガーを捕捉後、アドレスとデータを変えながら
Aポートから、SRAM内部にデータを書込みます。
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iASTATE <= "000" ;
iAADR <= (others => '0') ;
elsif rising_edge(iSCLK) then
case conv_integer(iASTATE) is
-- wait trigger
when 0 => if ( iATRG = '1' ) then
iASTATE <= "001" ;
iAADR <= (others => '0') ;
else
iASTATE <= "000" ;
end if ;
-- judge
when 1 => if ( iAADR(10) = '1' ) then
iASTATE <= "100" ;
else
iASTATE <= "011" ;
end if ;
-- generate data
when 3 => iASTATE <= "111" ;
iADAT( 7 downto 0) <= iAADR( 7 downto 0) ;
if ( iAADR(0) = '1' ) then
iADAT(15 downto 8) <= X"55" ;
else
iADAT(15 downto 8) <= X"AA" ;
end if ;
-- enable AWE
when 7 => iASTATE <= "110" ;
-- address counter increment
when 6 => iASTATE <= "001" ;
iAADR <= iAADR + '1' ;
-- return first state
when 4 => iASTATE <= "000" ;
when others =>
iASTATE <= "000" ;
end case ;
end if ;
end process ;
iAWE <= '1' when ( iASTATE = "111" ) else '0' ;
デュアルポートSRAMのBポートから、1ワード
データを読出すために、シーケンサを用意します。
トリガーを捕捉後、アドレスとデータを変えながら
Bポートから、SRAM内部のデータを読込みます。
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iBSTATE <= "00" ;
iBADR <= (others => '0') ;
elsif rising_edge(iSCLK) then
case conv_integer(iBSTATE) is
-- wait trigger
when 0 => if ( iBTRG = '1' ) then
iBSTATE <= "01" ;
elsif ( iBADRC = '1' ) then
iBSTATE <= "10" ;
iBADR <= (others => '0') ;
elsif ( iBADRI = '1' ) then
iBSTATE <= "10" ;
iBADR <= iBADR + '1' ;
else
iBSTATE <= "00" ;
end if ;
-- enable BOE
when 1 => iBSTATE <= "11" ;
-- get data
when 3 => iBSTATE <= "10" ;
-- return first state
when 2 => iBSTATE <= "00" ;
when others =>
iBSTATE <= "00" ;
end case ;
end if ;
end process ;
デュアルポートSRAMの処理をまとめると、以下と
なります。
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 sramtst is
generic (
TOPX : integer := 5 ;
XMAX : integer := 24 ;
TOPY : integer := 14 ;
YMAX : integer := 10000 --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
ATRG : in std_logic ;
BTRG : in std_logic ;
BADRC : in std_logic ;
BADRI : in std_logic ;
-- port B data
BDAT : out std_logic_vector(15 downto 0) ;
-- port B data dummy
BDATD : out std_logic_vector( 1 downto 0) ;
MDOUTA : out std_logic_vector(17 downto 0) --;
);
end sramtst ;
architecture Behavioral of sramtst is
-- component clock generator
component clkgenx is
generic (
TOPX : integer ;
RMAX : integer --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
CLKOUT : out std_logic -- ;
);
end component ;
-- internal clock
signal iSCLK : std_logic ;
signal iTCLK : std_logic ;
-- SRAM
signal iDOA : std_logic_vector(15 downto 0); -- Port A 16-bit Data Output
signal iBDAT : std_logic_vector(15 downto 0); -- Port B 16-bit Data Output
signal iDOPA : std_logic_vector( 1 downto 0); -- Port A 2-bit Parity Output
signal iDOPB : std_logic_vector( 1 downto 0); -- Port B 2-bit Parity Output
signal iBADR : std_logic_vector( 9 downto 0); -- Port B 10-bit Address Input
signal iCLKA : std_logic ; -- Port A Clock
signal iCLKB : std_logic ; -- Port B Clock
signal iADAT : std_logic_vector(15 downto 0); -- Port A 16-bit Data Input
signal iAWE : std_logic ; -- Port A Write Enable Input
-- trigger
signal iATRG_SFT : std_logic_vector(2 downto 0) ;
signal iATRG : std_logic ;
signal iBTRG_SFT : std_logic_vector(2 downto 0) ;
signal iBTRG : std_logic ;
signal iBADRC_SFT : std_logic_vector(2 downto 0);
signal iBADRC : std_logic ;
signal iBADRI_SFT : std_logic_vector(2 downto 0);
signal iBADRI : std_logic ;
-- address and data (port A)
signal iAADR : std_logic_vector(10 downto 0);
signal iASTATE : std_logic_vector( 2 downto 0);
-- address (port B)
signal iBSTATE : std_logic_vector( 1 downto 0);
begin
-- component
CLKX : clkgenx generic map (TOPX,XMAX) port map (nRESET,CLOCK,iSCLK); -- 1MHz
CLKY : clkgenx generic map (TOPY,YMAX) port map (nRESET,iSCLK,iTCLK); -- 100Hz
-- output
BDAT <= not iBDAT ;
-- dummy output
BDATD <= not iDOPB ;
MDOUTA <= not (iDOPA & iDOA) ;
-- SRAM
RAMB16_S18_S18_inst : RAMB16_S18_S18
generic map (
INIT_A => X"00000", -- Value of output RAM registers on Port A at startup
INIT_B => X"00000", -- Value of output RAM registers on Port B at startup
SRVAL_A => X"00000", -- Port A ouput value upon SSR assertion
SRVAL_B => X"00000", -- 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 follosing INIT_xx declarations specify the intiial contents of the RAM
-- Address 0 to 255
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 256 to 511
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 512 to 767
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 768 to 1023
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 255
INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000",
INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000",
-- Address 256 to 511
INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000",
INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000",
-- Address 512 to 767
INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000",
INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000",
-- Address 768 to 1023
INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000",
INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000"
)
port map (
DOA => iDOA, -- Port A 16-bit Data Output
DOB => iBDAT, -- Port B 16-bit Data Output
DOPA => iDOPA, -- Port A 2-bit Parity Output
DOPB => iDOPB, -- Port B 2-bit Parity Output
ADDRA => iAADR(9 downto 0), -- Port A 10-bit Address Input
ADDRB => iBADR, -- Port B 10-bit Address Input
CLKA => iCLKA, -- Port A Clock
CLKB => iCLKB, -- Port B Clock
DIA => iADAT, -- Port A 16-bit Data Input
DIB => X"FFFF", -- Port B 16-bit Data Input
DIPA => "11", -- Port A 2-bit parity Input
DIPB => "11", -- Port-B 2-bit parity Input
ENA => '1', -- Port A RAM Enable Input
ENB => '1', -- PortB RAM Enable Input
SSRA => '0', -- Port A Synchronous Set/Reset Input
SSRB => '0', -- Port B Synchronous Set/Reset Input
WEA => iAWE, -- Port A Write Enable Input
WEB => '0' -- Port B Write Enable Input
);
-- trigger
process (nRESET,iTCLK)
begin
if ( nRESET = '0' ) then
iATRG_SFT <= "000" ;
iBTRG_SFT <= "000" ;
iBADRC_SFT <= "000" ;
iBADRI_SFT <= "000" ;
elsif rising_edge(iTCLK) then
iATRG_SFT <= iATRG_SFT(1 downto 0) & ATRG ;
iBTRG_SFT <= iBTRG_SFT(1 downto 0) & BTRG ;
iBADRC_SFT <= iBADRC_SFT(1 downto 0) & BADRC ;
iBADRI_SFT <= iBADRI_SFT(1 downto 0) & BADRI ;
end if ;
end process ;
iATRG <= '1' when ( iATRG_SFT = "011" or iATRG_SFT = "001" ) else '0' ;
iBTRG <= '1' when ( iBTRG_SFT = "011" or iBTRG_SFT = "001" ) else '0' ;
iBADRC <= '1' when ( iBADRC_SFT = "011" or iBADRC_SFT = "001" ) else '0' ;
iBADRI <= '1' when ( iBADRI_SFT = "011" or iBADRI_SFT = "001" ) else '0' ;
iCLKA <= iSCLK ;
iCLKB <= iSCLK ;
-- sequencer B
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iBSTATE <= "00" ;
iBADR <= (others => '0') ;
elsif rising_edge(iSCLK) then
case conv_integer(iBSTATE) is
-- wait trigger
when 0 => if ( iBTRG = '1' ) then
iBSTATE <= "01" ;
elsif ( iBADRC = '1' ) then
iBSTATE <= "10" ;
iBADR <= (others => '0') ;
elsif ( iBADRI = '1' ) then
iBSTATE <= "10" ;
iBADR <= iBADR + '1' ;
else
iBSTATE <= "00" ;
end if ;
-- enable BOE
when 1 => iBSTATE <= "11" ;
-- get data
when 3 => iBSTATE <= "10" ;
-- return first state
when 2 => iBSTATE <= "00" ;
when others =>
iBSTATE <= "00" ;
end case ;
end if ;
end process ;
-- sequencer A
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iASTATE <= "000" ;
iAADR <= (others => '0') ;
elsif rising_edge(iSCLK) then
case conv_integer(iASTATE) is
-- wait trigger
when 0 => if ( iATRG = '1' ) then
iASTATE <= "001" ;
iAADR <= (others => '0') ;
else
iASTATE <= "000" ;
end if ;
-- judge
when 1 => if ( iAADR(10) = '1' ) then
iASTATE <= "100" ;
else
iASTATE <= "011" ;
end if ;
-- generate data
when 3 => iASTATE <= "111" ;
iADAT( 7 downto 0) <= iAADR( 7 downto 0) ;
if ( iAADR(0) = '1' ) then
iADAT(15 downto 8) <= X"55" ;
else
iADAT(15 downto 8) <= X"AA" ;
end if ;
-- enable AWE
when 7 => iASTATE <= "110" ;
-- address counter increment
when 6 => iASTATE <= "001" ;
iAADR <= iAADR + '1' ;
-- return first state
when 4 => iASTATE <= "000" ;
when others =>
iASTATE <= "000" ;
end case ;
end if ;
end process ;
iAWE <= '1' when ( iASTATE = "111" ) else '0' ;
end Behavioral;
動作を確認するために、マイコンを利用した
環境を使いました。
シリアルインタフェースを扱うファームウエアは
以下です。
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
#define MASKFF 0xff
#define OFF 0
#define ON OFF+1
#define FOSC 12000000
#define BAUD 9600
#define MYUBRR (FOSC/16/BAUD)-1
#define BUFSIZE 4
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
typedef signed char SBYTE ;
typedef signed short SWORD ;
volatile UBYTE uflag ;
volatile UBYTE sbuf[BUFSIZE] ;
volatile UBYTE sindex;
volatile UBYTE cnt ;
volatile UWORD cntx ;
volatile UBYTE cmd ;
const prog_char msg_h[] PROGMEM = "? help" ;
const prog_char msg_a[] PROGMEM = "A pulse" ;
const prog_char msg_b[] PROGMEM = "B pulse" ;
const prog_char msg_r[] PROGMEM = "R reset pulse" ;
const prog_char msg_i[] PROGMEM = "I increment pulse" ;
/*****************/
/* user function */
/*****************/
void init_io(void);
void usart_putchar(UBYTE x);
void usart_puts(UBYTE *x);
void crlf(void);
void show_help(void);
UBYTE get_hex(UBYTE x);
void send_pulse(UBYTE x);
#define CMD_A 0
#define CMD_B 1
#define CMD_R 2
#define CMD_I 3
/*------*/
/* main */
/*------*/
int main(void)
{
/* initialize */
init_io();
/* enable interrupt */
sei();
/* endless loop */
while ( ON ) {
/* UART handling */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* get command */
cmd = *(sbuf+0) ;
/* command interpreter */
if ( cmd == '?' ) { show_help() ; }
if ( cmd == 'A' ) { send_pulse(CMD_A) ; }
if ( cmd == 'B' ) { send_pulse(CMD_B) ; }
if ( cmd == 'R' ) { send_pulse(CMD_R) ; }
if ( cmd == 'I' ) { send_pulse(CMD_I) ; }
}
}
/* dummy */
return 0 ;
}
void init_io(void)
{
/* set I/O initial values */
PORTB = 0b00000000 ; /* 00000000 */
PORTD = 0b11111101 ; /* pull up */
/* set I/O directions */
DDRB = 0b11111111 ; /* all output */
DDRD = 0b11111110 ; /* */
/* clear registers */
sindex = 0 ;
cnt = 0 ;
cntx = 0 ;
/* clear flags */
uflag = OFF ;
/* initialize UART */
{
/* set Baud Rate Registers */
UBRRL = MYUBRR ;
/* Enable receive interrupt , receive module and transmit module */
UCSRB = (1 << RXCIE) | (1 << RXEN) | (1 << TXEN) ;
}
}
void usart_putchar(UBYTE x)
{
while ( !(UCSRA & (1 << UDRE)) ) {}
UDR = x ;
}
void usart_puts(UBYTE *x)
{
while ( *x != '\0' ) {
usart_putchar( *x ) ;
x++ ;
}
crlf();
}
void crlf(void)
{
usart_putchar('\r');
usart_putchar('\n');
}
void show_help(void)
{
char msg[32];
strcpy_P(msg,msg_h); usart_puts((UBYTE *)msg);
strcpy_P(msg,msg_a); usart_puts((UBYTE *)msg);
strcpy_P(msg,msg_b); usart_puts((UBYTE *)msg);
strcpy_P(msg,msg_r); usart_puts((UBYTE *)msg);
strcpy_P(msg,msg_i); usart_puts((UBYTE *)msg);
}
UBYTE get_hex(UBYTE x)
{
UBYTE result ;
/* default */
result = 0 ;
/* conversion */
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 ;
}
/* send pulse */
void send_pulse(UBYTE x)
{
volatile UBYTE i ;
/* judge */
if ( x > CMD_I ) return ;
/* send H */
PORTB |= (1 << x);
/* delay */
for ( i = 0 ; i < 128 ; i++ ) ;
/* send L */
PORTB &= ~(1 << x) ;
}
/* UART receive interrupt */
ISR(USART_RX_vect)
{
volatile UBYTE ch ;
/* get 1 charactoer */
ch = UDR ;
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
目次
前
次