目次

GameBoyCamera Interface

 今回開発するCPLDに封入する回路は、H8のサブプロセッサ
 として、GBCの制御信号を生成します。
 H8からの命令されたならば、動く簡単な回路とします。

 GBCは、次のシーケンスで動かします。
  1. リセット
  2. 内部レジスタに8個のパラメータ設定
  3. スタート
  4. 画像撮影終了までクロック転送
  5. クロック同期で出力される画像データを保存
 各動作は、次のタイミングチャートで示されています。  上記タイミングチャートから、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;
目次

inserted by FC2 system