GameBoyCamera Interface
今回開発するCPLDに封入する回路は、H8のサブプロセッサ
として、GBCの制御信号を生成します。
H8からの命令されたならば、動く簡単な回路とします。
GBCは、次のシーケンスで動かします。
- リセット
- 内部レジスタに8個のパラメータ設定
- スタート
- 画像撮影終了までクロック転送
- クロック同期で出力される画像データを保存
各動作は、次のタイミングチャートで示されています。
上記タイミングチャートから、H8とCPLD、CPLDとGBCの
接続信号を定義します。
接続信号は、次のように使います。
リセット RTRGをL→H→Lとします。
このトリガー信号で、XCK、XRSTを出力します。
パラメータ設定は、DATA、ATRG、DTRG、PTRGを利用します。
DATAは、3ビットでGBCの内部レジスタ番号あるいは
8ビットのパラメータを指定します。
ATRGは、DATAに内部レジスタ番号を出力している場合の
ラッチ(記憶)トリガー信号です。
DTRGは、DATAにパラメータを出力している場合のラッチ
トリガー信号です。
PTRGは、CPLD内部に記憶しているレジスタ番号とパラメータを
XCK、SIN、LOADを利用してシリアル転送するためのトリガーに
利用します。
スタート STRGをL→H→Lとします。
このトリガー信号で、XCK、STARTを出力します。
画像取得 GTRGをL→H→Lとします。
このトリガー信号で、XCKを出力します。
GBCからのREAD信号を監視し、H8に対してデータ取得要求INFO
を転送します。
H8は、データを取得し終えるとMOKで応答します。
ADR信号は、画像データを取得した回数を外部に出力します。
この信号は、デバッグで使います。
CPLDの入出力信号を定義したので、H8のポートとの接続を決めます。
ポート7
2本をA/Dコンバータの入力とします。
P70 GBCの#AからのVoutを接続します。
P71 GBCの#BからのVoutを接続します。
ポートA
CPLDのトリガー、レスポンスを接続します。
PA0(output) ATRG
PA1(output) DTRG
PA2(output) PTRG
PA3(output) RTRG
PA4(output) STRG
PA5(output) GTRG
PA6(output) MOK
PA7(input) INFO
ポート4
レジスタ番号、パラメータ出力で利用します。
P40(output) <-> P47(output)
トップレベル
GBC、H8との接続信号を決めたので、CPLDの入出力信号を定義します。
さらに、内包するブロックの信号を定義します。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity gbc is
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- micom signals
ATRG : in std_logic ; -- address latch trigger
DTRG : in std_logic ; -- data latch trigger
PTRG : in std_logic ; -- parameter latch trigger
RTRG : in std_logic ; -- reset trigger
STRG : in std_logic ; -- start trigger
GTRG : in std_logic ; -- get data
MOK : in std_logic ; -- finish convert
INFO : out std_logic ; -- confirm data
DATA : in std_logic_vector(7 downto 0);
-- counter
ADR : out std_logic_vector(14 downto 0) ;
-- GBC control
START : out std_logic ;
SIN : out std_logic ;
LOAD : out std_logic ;
XRST : out std_logic ;
XCK : out std_logic ;
XRD : in std_logic --;
);
end gbc;
architecture Behavioral of gbc is
signal iPREG : std_logic_vector(10 downto 0);
-- reset start
component rs_seq
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
RST_TRG : in std_logic ; -- reset
START_TRG : in std_logic ; -- start
-- output signal
XRST : out std_logic ;
START : out std_logic ;
-- latch clock
XCKOUT: out std_logic --;
);
end component ;
signal iRSXCK : std_logic ;
-- send parameter sequencer
component send_seq
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
SEND_TRG : in std_logic ; -- reset
-- parameters
DATA : in std_logic_vector(10 downto 0) ;
-- output signal
SIN : out std_logic ;
LOAD: out std_logic ;
-- latch clock
XCKOUT : out std_logic --;
);
end component ;
signal iPXCK : std_logic ;
-- get_code
component get_code
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
GET_TRG : in std_logic ; -- reset
-- enable
XREAD : in std_logic ;
MOK : in std_logic ;
-- information
INFO : out std_logic ;
-- counter
ADR : out std_logic_vector(14 downto 0) ;
-- latch clock
XCKOUT: out std_logic --;
);
end component ;
signal iGXCK : std_logic ;
begin
-- address and data store
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iPREG <= (others => '0') ;
elsif rising_edge( CLOCK ) then
-- register address
if ( ATRG = '1' ) then
iPREG(10 downto 8) <= DATA(2 downto 0);
end if ;
-- register data
if ( DTRG = '1' ) then
iPREG(7 downto 0) <= DATA;
end if ;
end if ;
end process ;
-- reset start
RS_SEQP : rs_seq port map(nRESET,CLOCK,RTRG,STRG,XRST,START,iRSXCK) ;
-- send parameter sequencer
S_SEQ : send_seq port map (nRESET,CLOCK,PTRG,iPREG,SIN,LOAD,iPXCK) ;
-- get_code
G_SEQ : get_code port map (nRESET,CLOCK,GTRG,XRD,MOK,INFO,ADR,iGXCK);
-- XCK
XCK <= iRSXCK or iPXCK or iGXCK ;
end Behavioral;
GBCのレジスタ番号、パラメータを格納するレジスタへの
データ入力は、このVHDLコードが担当します。
XCKは、3つのブロックで独立して出力しておき、論理和で
まとめました。
リセット、スタート処理
タイミングチャートを見ると、XRST、STARTは似た処理を
しているので、ひとつのVHDLコードにまとめます。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity rs_seq is
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
RST_TRG : in std_logic ; -- reset
START_TRG : in std_logic ; -- start
-- output signal
XRST : out std_logic ;
START : out std_logic ;
-- latch clock
XCKOUT: out std_logic --;
);
end rs_seq;
architecture Behavioral of rs_seq is
type stype is (S0,S1,S2,S3) ;
signal iCURRENT : stype ;
signal iRESET_ENABLE : std_logic ;
signal iSTART_ENABLE : std_logic ;
begin
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iCURRENT <= S0 ;
iRESET_ENABLE <= '0' ;
iSTART_ENABLE <= '0' ;
elsif rising_edge( CLOCK ) then
case iCURRENT is
-- wait trigger
when S0 =>
if ( RST_TRG = '1' ) then
iRESET_ENABLE <= '1' ;
iCURRENT <= S1 ;
elsif ( START_TRG = '1' ) then
iSTART_ENABLE <= '1' ;
iCURRENT <= S1 ;
else
iRESET_ENABLE <= '0' ;
iSTART_ENABLE <= '0' ;
iCURRENT <= S0 ;
end if ;
-- send data
when S1 => iCURRENT <= S2 ;
-- clock : H
when S2 => iCURRENT <= S3 ;
-- return first state
when S3 => iCURRENT <= S0 ;
-- default
when others => iCURRENT <= S0 ;
end case ;
end if ;
end process ;
XCKOUT <= '1' when ( iCURRENT = S2 or iCURRENT = S3 ) else '0' ;
XRST <= '0' when ( iRESET_ENABLE = '1' and iCURRENT = S1 ) else
'0' when ( iRESET_ENABLE = '1' and iCURRENT = S2 ) else '1' ;
START <= '1' when ( iSTART_ENABLE = '1' and iCURRENT = S1 ) else
'1' when ( iSTART_ENABLE = '1' and iCURRENT = S2 ) else '0' ;
end Behavioral;
XRST、STARTともに、信号を出力後にXCKをL→H→Lと変化させます。
シーケンサ(ステートマシン)の利用で、簡潔に記述できます。
パラメータ設定
内部レジスタに格納されたデータを、PTRGトリガーにより
シーケンシャルに出力します。
シーケンサの中に、カウンタを用意し、SINに指定値を
出力できるようにしました。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity send_seq is
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
SEND_TRG : in std_logic ;
-- parameters
DATA : in std_logic_vector(10 downto 0) ;
-- output signal
SIN : out std_logic ;
LOAD: out std_logic ;
-- latch clock
XCKOUT: out std_logic --;
);
end send_seq;
architecture Behavioral of send_seq is
type stype is (S0,S1,S2,S3,S4,S5) ;
signal iCURRENT : stype ;
signal iCNT : std_logic_vector(3 downto 0) ;
signal iENABLE : std_logic ;
begin
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iCURRENT <= S0 ;
iCNT <= "0000" ;
elsif rising_edge( CLOCK ) then
case iCURRENT is
-- wait trigger
when S0 =>
if ( SEND_TRG = '1' ) then
iCNT <= "1011" ;
iCURRENT <= S1 ;
else
iCNT <= "0011" ;
iCURRENT <= S0 ;
end if ;
-- judge
when S1 =>
if ( conv_integer(iCNT) = 0 ) then
iCURRENT <= S5 ;
else
iCURRENT <= S2 ;
end if ;
-- send data
when S2 =>
iCURRENT <= S3 ;
-- clock : H
when S3 =>
iCURRENT <= S4 ;
-- decrement
when S4 => iCNT <= iCNT - 1 ;
iCURRENT <= S1 ;
-- return first state
when S5 => iCURRENT <= S0 ;
-- default
when others => iCURRENT <= S0 ;
end case ;
end if ;
end process ;
iENABLE <= '1' when ( iCURRENT > S0 ) else '0' ;
XCKOUT <= '1' when ( iCURRENT = S3 ) else '0' ;
SIN <= DATA(11 - conv_integer(iCNT)) when ( iENABLE = '1' ) else '0' ;
LOAD <= '1' when ( iCNT = "0001" ) else '0' ;
end Behavioral;
クロックXCKは、データ出力後にL→Hと変化する
よう、シーケンサを組みました。
データ取得
GTRGトリガーで動作を開始します。
内部カウンタを使い、128ピクセルx128ラインを転送
したならば、自動終了します。
タイミングチャートより、XCKのH→LでVoutにデータを
出力するので、このエッジを利用してH8にA/D変換開始
の合図をおくります。
A/D変換終了を、MOKを利用して通知してもらいます。
内部カウンタインクリメントは、XREADがHのときに限定します。
タイミングチャートで、READがHのときに画像データを出力する
ことが読み取れます。
READをイネーブル信号に使っています。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity get_code is
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
GET_TRG : in std_logic ;
-- enable
XREAD : in std_logic ;
MOK : in std_logic ;
-- information
INFO : out std_logic ;
-- counter
ADR : out std_logic_vector(14 downto 0) ;
-- latch clock
XCKOUT: out std_logic --;
);
end get_code;
architecture Behavioral of get_code is
type stype is (S0,S1,S2,S3,S4,S5,S6,S7) ;
signal iCURRENT : stype ;
signal iCNT : std_logic_vector(14 downto 0) ;
signal iINTS : std_logic_vector(1 downto 0) ;
begin
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iCURRENT <= S0 ;
iCNT <= (others => '0') ;
elsif rising_edge( CLOCK ) then
case iCURRENT is
-- wait trigger
when S0 =>
if ( GET_TRG = '1' ) then
iCNT <= (others => '0') ;
iCURRENT <= S1 ;
end if ;
-- judge
when S1 =>
if ( conv_integer(iCNT) = 16384 ) then
iCURRENT <= S7 ;
else
iCURRENT <= S2 ;
end if ;
-- clock : H
when S2 => iCURRENT <= S3 ;
-- clock : L
when S3 =>
if ( XREAD = '1' ) then
iCURRENT <= S4 ;
else
iCURRENT <= S6 ;
end if ;
-- information
when S4 =>
iCURRENT <= S5 ;
-- wait micom and inrement
when S5 =>
if ( MOK = '1' ) then
iCNT <= iCNT + 1 ;
iCURRENT <= S6 ;
else
iCURRENT <= S5 ;
end if ;
-- loop
when S6 => iCURRENT <= S1 ;
-- return first state
when S7 => iCURRENT <= S0 ;
-- default
when others =>
iCURRENT <= S0 ;
end case ;
end if ;
end process ;
XCKOUT <= '1' when ( iCURRENT = S3 ) else '0' ;
INFO <= '0' when ( iCURRENT = S4 ) else '1' ;
ADR <= iCNT ;
end Behavioral;
付加機能
GBCとのインタフェースは実装できたので、H8の負担を
軽くするための処理を入れました。
16ビットの中に含まれる1のビットが、いくつあるのか
をカウントする機能を追加しました。
GBCが出力してくる1ラインは、128バイトです。
このデータを、ある閾値を利用し2値化します。
2値化で、128ピクセルを128ビットに変換しました。
128ビットをさらに8グループに分割しました。
1グループを、16ビットとし、その中に含まれる1の個数を
数え上げ、センターラインがどのグループにあるかを、推定
します。
この処理をCPLDに手伝わせました。
16ビットを4ビットに分割して、4ビット中の1の個数を
テーブル参照で取得し、最後に加算します。
H8から16ビットを与えて、トリガーをかけます。
トリガーが与えられたならば、シーケンサを動かして
テーブルから数値を引き出し、4つの数値を加算します。
componentで利用するため、この機能を1つのブロックで
定義しました。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity dec is
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- in
DIN : in std_logic_vector(15 downto 0) ;
-- trigger
TRG : in std_logic ;
-- trigger
BUSY : out std_logic ;
-- result
DECOUT : out std_logic_vector(4 downto 0) --;
);
end dec;
architecture Behavioral of dec is
subtype DTYPE is std_logic_vector(3 downto 0) ;
type DEC is array(0 to 15) of DTYPE ;
constant DECX : DEC := (
"0000",
"0001",
"0001",
"0010",
"0001",
"0010",
"0010",
"0011",
"0001",
"0010",
"0010",
"0011",
"0010",
"0011",
"0011",
"0100"
) ;
type stype is (S0,S1,S2,S3,S4);
signal iCUR : stype ;
signal iDECOUT : std_logic_vector(4 downto 0);
signal iCT : std_logic_vector(3 downto 0);
signal iCNT : std_logic_vector(2 downto 0);
begin
DECOUT <= iDECOUT ;
BUSY <= '1' when ( iCUR > S0 ) else '0' ;
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iCUR <= S0 ;
iDECOUT <= "00000" ;
iCT <= "0000" ;
iCNT <= "000" ;
elsif rising_edge( CLOCK ) then
-- get logic level
case iCUR is
-- wati trigger
when S0 =>
if ( TRG = '1' ) then
iDECOUT <= "00000" ;
iCT <= "0000" ;
iCNT <= "000" ;
iCUR <= S1 ;
end if ;
-- judge
when S1 =>
if ( iCNT(2) = '0' ) then
iCUR <= S2 ;
else
iCUR <= S4 ;
end if ;
-- get data
when S2 =>
case iCNT is
when "000" => iCT <= DIN( 3 downto 0);
when "001" => iCT <= DIN( 7 downto 4);
when "010" => iCT <= DIN(11 downto 8);
when "011" => iCT <= DIN(15 downto 12);
when others => NULL ;
end case ;
iCNT <= iCNT + '1' ;
iCUR <= S3 ;
-- calculate
when S3 =>
iDECOUT <= iDECOUT + ('0' & DECX(conv_integer(iCT)) );
iCUR <= S1 ;
-- return first state
when S4 =>
iCUR <= S0 ;
-- default
when others =>
iCUR <= S0 ;
end case ;
end if ;
end process ;
end Behavioral;
16ビット中の1の個数をカウントする処理を入れても
CPLDの容量に余裕があったので、2値化処理も入れました。
2つの8ビット数値(DA,DB)を与えて、DA>DBで1を
それ以外では0を返す仕様です。
単純なマグニチュードコンパレータとしました。
componentとして利用するために、別ファイルで定義します。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity gbit is
Port (
-- in
DA : in std_logic_vector(7 downto 0) ;
DB : in std_logic_vector(7 downto 0) ;
-- result
BOUT : out std_logic --;
);
end gbit ;
architecture Behavioral of gbit is
begin
process ( DA , DB )
begin
if ( conv_integer(DA) < conv_integer(DB) ) then
BOUT <= '0' ;
else
BOUT <= '1' ;
end if ;
end process ;
end Behavioral;
2つのcomponentを利用するため、トップレベルの記述を
次のように、変更しました。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity gbc is
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- micom signals
ATRG : in std_logic ; -- address latch trigger
DTRG : in std_logic ; -- data latch trigger
PTRG : in std_logic ; -- parameter latch trigger
RTRG : in std_logic ; -- reset trigger
STRG : in std_logic ; -- start trigger
GTRG : in std_logic ; -- get data
DATA : in std_logic_vector(7 downto 0);
INFO : out std_logic ; -- confirm data
MOK : in std_logic ; -- finish convert
-- counter
ADR : out std_logic_vector(14 downto 0) ;
-- GBC control
START : out std_logic ;
SIN : out std_logic ;
LOAD : out std_logic ;
XRST : out std_logic ;
XCK : out std_logic ;
XRD : in std_logic ;
-- decode
DEC_LATCH_A : in std_logic ;
DEC_LATCH_B : in std_logic ;
DECTRG : in std_logic ;
DECBUSY : out std_logic ;
DECOUT : out std_logic_vector(4 downto 0) ;
-- convert
LATCH_A : in std_logic ;
LATCH_B : in std_logic ;
BIT1OUT : out std_logic --;
);
end gbc;
architecture Behavioral of gbc is
signal iPREG : std_logic_vector(10 downto 0);
-- reset start
component rs_seq
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
RST_TRG : in std_logic ; -- reset
START_TRG : in std_logic ; -- start
-- output signal
XRST : out std_logic ;
START : out std_logic ;
-- latch clock
XCKOUT: out std_logic --;
);
end component ;
signal iRSXCK : std_logic ;
-- send parameter sequencer
component send_seq
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
SEND_TRG : in std_logic ; -- reset
-- parameters
DATA : in std_logic_vector(10 downto 0) ;
-- output signal
SIN : out std_logic ;
LOAD: out std_logic ;
-- latch clock
XCKOUT : out std_logic --;
);
end component ;
signal iPXCK : std_logic ;
-- get_code
component get_code
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- trigger
GET_TRG : in std_logic ; -- reset
-- enable
XREAD : in std_logic ;
MOK : in std_logic ;
-- information
INFO : out std_logic ;
-- counter
ADR : out std_logic_vector(14 downto 0) ;
-- latch clock
XCKOUT: out std_logic --;
);
end component ;
signal iGXCK : std_logic ;
-- decode
component dec
Port (
-- system
nRESET : in std_logic ; -- system reset
CLOCK : in std_logic ; -- reference clock
-- in
DIN : in std_logic_vector(15 downto 0) ;
-- trigger
TRG : in std_logic ;
-- trigger
BUSY : out std_logic ;
-- result
DECOUT : out std_logic_vector(4 downto 0) --;
);
end component;
signal iREG_D : std_logic_vector(15 downto 0) ;
-- convert
component gbit
Port (
-- in
DA : in std_logic_vector(7 downto 0) ;
DB : in std_logic_vector(7 downto 0) ;
-- result
BOUT : out std_logic --;
);
end component ;
signal iREG_A : std_logic_vector(7 downto 0) ;
signal iREG_B : std_logic_vector(7 downto 0) ;
begin
-- address and data store
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iPREG <= (others => '0') ;
elsif rising_edge( CLOCK ) then
-- register address
if ( ATRG = '1' ) then
iPREG(10 downto 8) <= DATA(2 downto 0);
end if ;
-- register data
if ( DTRG = '1' ) then
iPREG(7 downto 0) <= DATA;
end if ;
end if ;
end process ;
-- reset start
RS_SEQP : rs_seq port map(nRESET,CLOCK,RTRG,STRG,XRST,START,iRSXCK) ;
-- send parameter sequencer
S_SEQ : send_seq port map (nRESET,CLOCK,PTRG,iPREG,SIN,LOAD,iPXCK) ;
-- get_code
G_SEQ : get_code port map (nRESET,CLOCK,GTRG,XRD,MOK,INFO,ADR,iGXCK);
-- XCK
XCK <= iRSXCK or iPXCK or iGXCK ;
-- decode
DECX : dec port map (nRESET,CLOCK,iREG_D,DECTRG,DECBUSY,DECOUT) ;
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iREG_D <= (others => '0') ;
elsif rising_edge( CLOCK ) then
-- register A
if ( DEC_LATCH_A = '1' ) then
iREG_D(15 downto 8) <= DATA ;
end if ;
-- register B (reference)
if ( DEC_LATCH_B = '1' ) then
iREG_D(7 downto 0) <= DATA ;
end if ;
end if ;
end process ;
-- convert
GBITP : gbit port map (iREG_A,iREG_B,BIT1OUT);
process ( nRESET , CLOCK )
begin
if ( nRESET = '0' ) then
iREG_A <= (others => '0') ;
iREG_B <= (others => '0') ;
elsif rising_edge( CLOCK ) then
-- register A
if ( LATCH_A = '1' ) then
iREG_A <= DATA ;
end if ;
-- register B (reference)
if ( LATCH_B = '1' ) then
iREG_B <= DATA ;
end if ;
end if ;
end process ;
end Behavioral;
目次
前
次