FC2カウンター FPGAの部屋 CMOSカメラから画像を入力してディスプレイへ出力11(シミュレーション2)
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

CMOSカメラから画像を入力してディスプレイへ出力11(シミュレーション2)

今度は、CamDispCntrl_SRAM.vhd の内部タイミングを忘れないように書いておく。
まずは、前回、CamDispCntrl_SRAM から出力したcam_clk をCMOSカメラに出力して、CMOSカメラから入ってきたcam_pclk をDCMに入れて全体を如何させるクロックとする。
CMOSカメラからのcam_href, cam_vsync は一度IOBのFFを通して、cam_href_1d, cam_vsync_1d として、synchronizer.vhd に入力されてmaster_sync, r_wタイミングなどを生成する。
下に、synchronizer.vhd のソースを示す。

-- synchronizer
-- synchronizerが使用するのは、FPGAに入力されたcam_hrefやcam_vsyncからIOBのFFを通り1クロックディレイした信号。その他のモジュールは2クロック遅延した信号を用いる
-- cam_vsync_1d が1から0になった後の最初の cam_href_1d の立ち上がりで同期信号(master_sync)を出力する
-- 同時に出力するR_W信号を1(Read)にする

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;

entity synchronizer is
    port(
        clk : in std_logic;
        reset : in std_logic;
        cam_vsync_1d : in std_logic;
        cam_href_1d : in std_logic;
        master_sync : out std_logic;
        r_w : out std_logic
    );
end synchronizer;

architecture RTL of synchronizer is
type sync_state is (idle_sync, vsync_assert, vsync_deassert, sync_active);
signal cs_sync, ns_sync : sync_state;
type rw_state is (idle_rw, read_state, write_state);
signal cs_rw, ns_rw : rw_state;
signal msync : std_logic;
signal r_w_node : std_logic;

begin
    -- master_syncを出力するステートマシン
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_sync <= idle_sync;
            else
                cs_sync <= ns_sync;
            end if;
        end if;
    end process;
    
    process(cs_sync, cam_vsync_1d, cam_href_1d) begin
        msync <= '0';
        case cs_sync is
            when idle_sync =>
                if cam_vsync_1d='1' then
                    ns_sync <= vsync_assert;
                else
                    ns_sync <= idle_sync;
                end if;
            when vsync_assert =>
                if cam_vsync_1d='0' then
                    ns_sync <= vsync_deassert;
                else
                    ns_sync <= vsync_assert;
                end if;
            when vsync_deassert =>
                if cam_href_1d='1' then
                    ns_sync <= sync_active;
                else
                    ns_sync <= vsync_deassert;
                end if;
            when sync_active =>
                msync <= '1';
                ns_sync <= idle_sync;
        end case;
    end process;
    master_sync <= msync;
    
    -- r_wを出力するステートマシン
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_rw <= idle_rw;
            else
                cs_rw <= ns_rw;
            end if;
        end if;
    end process;
    
    -- その他のモジュールの動作は1クロック遅れるので、最初はwrite_stateとなる
    process(cs_rw, cs_sync, cam_href_1d) begin
        case cs_rw is
            when idle_rw =>
                r_w_node <= '1';
                if cs_sync=vsync_deassert and cam_href_1d='1' then
                    ns_rw <= write_state;
                else
                    ns_rw <= idle_rw;
                end if;
            when read_state =>
                r_w_node <= '1';
                if cs_sync=vsync_deassert and cam_href_1d='1' then
                    ns_rw <= read_state;
                else
                    ns_rw <= write_state;
                end if;
            when write_state =>
                r_w_node <= '0';
                if cs_sync=vsync_deassert and cam_href_1d='1' then
                    ns_rw <= read_state;
                else
                    ns_rw <= read_state;
                end if;
        end case;
    end process;
    r_w <= r_w_node;
end RTL;


下に、前回と同様なタイミング(cam_vsync が1になった後、最初のcam_hrefが1の時)でのタイミングチャートを下に示す。
Camera_Disp_20_091014.png

synchronizer.vhd で生成されたタイミングで各種モジュールが動作する。よって、その他のモジュールが使用する信号は、CMOSカメラの出力から2クロック遅れた信号となる。(cam_href_2d... など)

下にCamDispCntrl_SRAM.vhd のソースを示す。

--CamDisplay Contoroller with SRAM(トップモジュール)-- トップモジュールから全部作ることにする。
-- CMOSカメラから出てくるビデオ出力はUYVYとする
-- VSYNCは正論理、HREFも正論理
-- clk(48MHz)はそのまま使用して、PCLKをDCMで受けて使用する。
-- IOBにマップされるロジックはこのトップモジュールにインスタンシエーションする。
-- synchronizerでは_1dのデータを使用し、その他のモジュールでは_2dのデータを使用する
-- 全体のタイミングは_2dを基準とする

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;

-- pragma translate_off
library UNISIM;
use UNISIM.VComponents.all;
-- pragma translate_on

entity CamDispCntrl_SRAM is
    port (
        clk    : in std_logic;            -- 水晶発振器からの48MHzクロック
        cam_vsync : in std_logic;    -- CMOSカメラからのVSYNC
        cam_href : in std_logic;    -- CMOSカメラからのHREF
        cam_pclk : in std_logic;        -- CMOSカメラからのpclk
        cam_ydata : in std_logic_vector(7 downto 0); -- CMOSカメラからのYデータ
        -- cam_sio_c : out std_logic;    -- CMOSカメラのI2Cクロック
        -- cam_sio_d : inout std_logic; -- CMOSカメラのI2Cデータ
        cam_clk    : out std_logic;     -- CMOSカメラのクロック
        n_cam_reset    : out std_logic;     -- CMOSカメラのリセット(Lでリセットの予定)
        dac_red    : out std_logic_vector(7 downto 0);    -- DACへのRED出力
        dac_green : out std_logic_vector(7 downto 0); -- DACへのGREEN出力
        dac_blue : out std_logic_vector(7 downto 0); -- DACへのBLUE出力
        n_dac_blank : out std_logic; -- DACへのアクティブローBLANK
        dac_clk : out std_logic; -- DACクロック(24MHz)
        vga_vsync : out std_logic; -- VGAのVSYNC
        vga_hsync : out std_logic; -- VGAのHSYNC
        mem_data : inout std_logic_vector(15 downto 0);    -- SRAMのmemory data
        n_mem_we : out std_logic; -- SRAMのmemory write enable
        n_mem_rd : out std_logic; -- SRAMのmemory read enable
        n_mem_cs0 : out std_logic; -- SRAMのchip select 0
        n_mem_cs1 : out std_logic; -- SRAMのchip select 1
        n_mem_cs2 : out std_logic; -- SRAMのchip select 2
        n_mem_cs3 : out std_logic; -- SRAMのchip select 3
        n_mem_lowerB : out std_logic; -- SRAMのmemory lower byte enable
        n_mem_upperB : out std_logic; -- SRAMのmemory upper byte enable
        mem_addr : out std_logic_vector(17 downto 0) -- SRAMのmemory address
    );
end CamDispCntrl_SRAM;

architecture RTL of CamDispCntrl_SRAM is
component DCM_module_24MHz
    port(
        clk48MHz_in : in std_logic;
        clk48_out : out std_logic;
        cam_clk_out : out std_logic;
        pclk_in : in std_logic;
        mclk_out : out std_logic;
        cam_clk_locked : out std_logic;
        mclk_locked : out std_logic
    );
end component;
component ODDR2
 generic(

      DDR_ALIGNMENT : string := "NONE";
      INIT          : bit    := '0';
      SRTYPE        : string := "SYNC"
      );

  port(
      Q           : out std_ulogic;

      C0          : in  std_ulogic;
      C1          : in  std_ulogic;
      CE          : in  std_ulogic := 'H';
      D0          : in  std_ulogic;
      D1          : in  std_ulogic;
      R           : in  std_ulogic := 'L';
      S           : in  std_ulogic := 'L'
    );
end component;
component VGA_Display_Controller
    port(
        clk : in std_logic;
        reset : in std_logic;
        master_sync : in std_logic; -- 表示タイミングの同期信号
        pixel_y_data : in std_logic_vector(15 downto 0); -- Yのデータ、下のdata_enableが1の時に有効
        data_enable : in std_logic;
        h_count_out : out unsigned(9 downto 0); -- 水平カウンタのカウント出力
        v_count_out : out unsigned(9 downto 0); -- 垂直カウンタのカウント出力
        red_out : out std_logic_vector(7 downto 0); -- VGA出力
        green_out : out std_logic_vector(7 downto 0); -- VGA出力
        blue_out : out std_logic_vector(7 downto 0); -- VGA出力
        blank_out : out std_logic; -- BLANK出力
        h_syncx_out : out std_logic; -- 水平同期出力
        v_syncx_out : out std_logic; -- 垂直同期出力
        mem_addr : out std_logic_vector(18 downto 0) -- SRAMのアドレス、バイト単位
    );
end component;
component synchronizer
    port(
        clk : in std_logic;
        reset : in std_logic;
        cam_vsync_1d : in std_logic;
        cam_href_1d : in std_logic;
        master_sync : out std_logic;
        r_w : out std_logic
    );
end component;
component SRAM_Controller
    port(
        clk : in std_logic;
        clk48 : in std_logic;
        reset : in std_logic;
        r_w : in std_logic; -- Read or Write
        cam_href_3d : in std_logic; -- cam_href の3クロック遅れ、各モジュールで2クロック遅れの信号を使っているので、それよりも1クロック遅れている信号をweのイネーブルとして使用する。これはUYVYとデータが来るので、サンプルするのに1クロック遅れるから。
        master_sync : in std_logic;
        cam_mem_addr : in std_logic_vector(17 downto 0); -- CMOSカメラの書き込み用のアドレス
        cam_ydata_in : in std_logic_vector(7 downto 0); -- CMOSカメラのデータ
        vga_mem_addr : in std_logic_vector(18 downto 1); -- VGAコントローラー用読み出し用アドレス
        
        mem_data_out : out std_logic_vector(15 downto 0); -- SRAMのデータ出力。CMOSカメラのデータを2つ集めたもの。
        mem_data_oe : out std_logic; -- SRAMのmemory data出力のOutput Enable
        
        n_mem_we : out std_logic; -- SRAMのWE
        n_mem_cs0 : out std_logic; -- SRAMのchip select 0
        n_mem_cs1 : out std_logic; -- SRAMのchip select 1
        n_mem_cs2 : out std_logic; -- SRAMのchip select 2
        n_mem_cs3 : out std_logic; -- SRAMのchip select 3
        n_mem_lowerB : out std_logic; -- SRAMのmemory lower byte enable
        n_mem_upperB : out std_logic; -- SRAMのmemory upper byte enable
        mem_addr : out std_logic_vector(17 downto 0) -- SRAMのmemory address
    );
end component;
component Camera_Controller
    port(
        clk : in std_logic;
        reset : in std_logic;        
        cam_href_2d : in std_logic;    -- CMOSカメラからのHREFのラッチ出力
        master_sync : in std_logic; -- 同期信号
        mem_addr : out std_logic_vector(17 downto 0) -- CMOSカメラのデータを書き込むSRAMのアドレス
    );
end component;
component IOBUF
    port(
        O : out std_logic;
        IO : inout std_logic;
        I : in std_logic;
        T : in std_logic
    );
end component;

signal mclk : std_logic;
signal reset : std_logic;
signal mclk_locked : std_logic;
signal master_sync : std_logic;
signal r_w : std_logic;
signal cam_href_1d, cam_vsync_1d : std_logic;
signal cam_href_3d : std_logic;
signal cam_href_2d, cam_vsync_2d : std_logic;
signal cam_ydata_1d, cam_ydata_2d : std_logic_vector(7 downto 0);
signal w_r : std_logic;
signal vga_blank : std_logic;
signal vga_mem_addr : std_logic_vector(17 downto 0);
signal vga_mem_addr_19 : std_logic_vector(18 downto 0);
signal cam_mem_addr : std_logic_vector(17 downto 0);
signal clk48 : std_logic;
signal mem_data_out : std_logic_vector(15 downto 0); -- SRAMのデータ出力。CMOSカメラのデータを2つ集めたもの。
signal mem_data_oe : std_logic; -- SRAMのmemory data出力のOutput Enable
signal n_mem_data_oe : std_logic;
signal vga_ydata : std_logic_vector(15 downto 0);
signal input_mem_data : std_logic_vector(15 downto 0);
signal cam_clk_node, cam_clk_locked : std_logic;
signal n_cam_clk_node, cam_clk_reset : std_logic;
signal n_mclk : std_logic;

begin
    
    DCM_module_24MHz_inst : DCM_module_24MHz port map(
        clk48MHz_in => clk,
        clk48_out => clk48,
        cam_clk_out => cam_clk_node,
        pclk_in => cam_pclk,
        mclk_out => mclk,
        cam_clk_locked => cam_clk_locked,
        mclk_locked => mclk_locked
    );
    reset <= not mclk_locked;
    n_cam_reset <= cam_clk_locked; -- CMOSカメラ用のリセットを出力する
    
    -- CMOSカメラ用クロックの生成
    n_cam_clk_node <= not cam_clk_node;
    cam_clk_reset <= not cam_clk_locked;
    ODDR2_for_cam_clk : ODDR2 generic map(
        SRTYPE => "ASYNC"
    ) port map(
        Q => cam_clk,
        C0 => cam_clk_node,
        C1 => n_cam_clk_node,
        CE => '1',
        D0 => '1',
        D1 => '0',
        R => cam_clk_reset,
        S => '0'
    );
    
    -- DAC用クロックの生成
    n_mclk <= not mclk;
    ODDR2_for_dac_clk : ODDR2 generic map(
        SRTYPE => "ASYNC"
    ) port map(
        Q => dac_clk,
        C0 => mclk,
        C1 => n_mclk,
        CE => '1',
        D0 => '1',
        D1 => '0',
        R => reset,
        S => '0'
    );
    
    -- CMOSカメラからの入力は一度IOBのFFを通す
    process(mclk) begin
        if mclk'event and mclk='1' then
            if reset='1' then
                cam_vsync_1d <= '0';
                cam_href_1d <= '0';
                cam_ydata_1d <= (others => '0');
                cam_vsync_2d <= '0';
                cam_href_2d <= '0';
                cam_ydata_2d <= (others => '0');
                cam_href_3d <= '0';
            else
                cam_vsync_1d <= cam_vsync;
                cam_href_1d <= cam_href;
                cam_ydata_1d <= cam_ydata;
                cam_vsync_2d <= cam_vsync_1d;
                cam_href_2d <= cam_href_1d;
                cam_ydata_2d <= cam_ydata_1d;
                cam_href_3d <= cam_href_2d;
            end if;
        end if;
    end process;
    
    -- CMOSカメラの書き込みアドレスの生成
    
    synchronizer_inst : synchronizer port map(
        clk => mclk,
        reset => reset,
        cam_vsync_1d => cam_vsync_1d,
        cam_href_1d => cam_href_1d,
        master_sync => master_sync,
        r_w => r_w
    );
    
    -- mem_dataの入力FF
    process(mclk) begin
        if mclk'event and mclk='1' then
            if reset='1' then
                vga_ydata <= (others => '0');
            else
                vga_ydata <= input_mem_data;
            end if;
        end if;
    end process;
    w_r <= not r_w;
    
    VGA_Display_Controller_inst : VGA_Display_Controller port map(
        clk => mclk,
        reset => reset,
        master_sync => master_sync,
        pixel_y_data => vga_ydata,
        data_enable => w_r,
        h_count_out => open,
        v_count_out => open,
        red_out => dac_red,
        green_out => dac_green,
        blue_out => dac_blue,
        blank_out => vga_blank,
        h_syncx_out => vga_hsync,
        v_syncx_out => vga_vsync,
        mem_addr => vga_mem_addr_19
    );
    n_dac_blank <= not vga_blank;
    
    Camera_Controller_inst : Camera_Controller port map(
        clk => mclk,
        reset => reset,
        cam_href_2d => cam_href_2d,
        master_sync => master_sync,
        mem_addr => cam_mem_addr
    );
    
    vga_mem_addr <= vga_mem_addr_19(18 downto 1);
    SRAM_Controller_inst : SRAM_Controller port map(
        clk => mclk,
        clk48 => clk48,
        reset => reset,
        r_w => r_w,
        cam_href_3d => cam_href_3d,
        master_sync => master_sync,
        cam_mem_addr => cam_mem_addr,
        cam_ydata_in => cam_ydata_2d,
        vga_mem_addr => vga_mem_addr,
        mem_data_out => mem_data_out,
        mem_data_oe => mem_data_oe,
        n_mem_we => n_mem_we,
        n_mem_cs0 => n_mem_cs0,
        n_mem_cs1 => n_mem_cs1,
        n_mem_cs2 => n_mem_cs2,
        n_mem_cs3 => n_mem_cs3,
        n_mem_lowerB => n_mem_lowerB,
        n_mem_upperB => n_mem_upperB,
        mem_addr => mem_addr
    );
    n_mem_data_oe <= not mem_data_oe;
    
    MEM_DATA_GEN : for i in 15 downto 0 generate
        IOBUF_inst : IOBUF port map(
            O => input_mem_data(i),
            IO => mem_data(i),
            I => mem_data_out(i),
            T => n_mem_data_oe
        );
    end generate MEM_DATA_GEN;
    n_mem_rd <= not r_w;
end RTL;


前回と同様なタイミング(cam_vsync が1になった後、最初のcam_hrefが1の時)でのタイミングチャートは、下のようになる。(前回と同じもの)
Camera_Disp_19_091013.png

35ms シミュレーションして全体を表示すると下のようになる。
Camera_Disp_21_091014.png

vga_vsyncが2回出力されるうちに、cam_vsyncは1回出力されている。大体動いてきたと思うが、もう少し、モデルの出すデータ値を変更して、確実に動くかどうかを検証したい。
  1. 2009年10月14日 05:23 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/1258-1f29822d
この記事にトラックバックする(FC2ブログユーザー)