FC2カウンター FPGAの部屋 2009年11月19日
FC2ブログ

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

FPGAの部屋

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

”CMOSカメラから画像を入力してディスプレイへ出力”のSRAMのデータ出力イネーブル用FFをIOBへ入れる

CMOSカメラから画像を入力してディスプレイへ出力15(できた!!!)”でCMOSカメラからの画像をディスプレイに出力することができた。そこから画像のいろいろなエッジ検出を試みてきた。今までは、動作周波数が低いので、あまりIOBにFFを入れるとか考慮していなかったので、やってみようと思った。
一番問題なのは、SRAMへのデータをWriteしてから、すぐにリードなので、FPGAの出力用ドライバーをすぐにOFFする必要があることだ。”CMOSカメラから画像を入力してディスプレイへ出力16(VHDLソースを公開)”を元にすると、SRAM_Controller.vhd から出力されたmem_data_oe が、最上位のCamDispCntrl_SRAM.vhd のIOBUF のT 入力に反転されて入力され、SRAMへのデータ出力イネーブルとなっている。その部分のソースを下に示す。

    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;


mem_data_oe はどうやって出力しているかというと、SRAM_Controller.vhd の中にあるステートマシンの出力だ。その部分のソースを下に示す。

    -- n_mem_we, mem_data_oe を生成する。48MHzのステートマシンで出力
    process(clk48) begin
        if clk48'event and clk48='1' then
            if reset='1' then
                cs_we <= idle_we;
            else
                cs_we <= ns_we;
            end if;
        end if;
    end process;
    
    process(cs_we, r_w, cam_href_3d) begin
        case cs_we is
            when idle_we =>
                n_mem_we_node <= '1';
                mem_data_oe <= '0';
                if r_w='0' and cam_href_3d='1' then -- hrefの間だけSRAMにWriteする
                    ns_we <= we_active;
                else
                    ns_we <= idle_we;
                end if;
            when we_active => -- r_w が1時48MHzクロック1クロック間だけ n_mem_we を0にする
                n_mem_we_node <= '0';
                mem_data_oe <= '1';
                ns_we <= we_holdoff;
            when we_holdoff => -- この時はまだr_wが0
                n_mem_we_node <= '1';
                mem_data_oe <= '0';
                ns_we <= idle_we;
        end case;
    end process;
    n_mem_we <= n_mem_we_node;


次にFPGA Editor でSRAMのデータ入出力パッドを見てみよう。下にその図を示す。
iob_ff_1_091119.jpg

やはり出力用バッファのアウトプットイネーブルで、IOBのFFは使用されていない。これを使用するようにVHDLソースを書き換えましょうというのが、今回の趣旨だ。
さて、mem_data_oe を1つのFFということで、別に定義してみよう。ステートマシンの方にはnext_mem_data_oe という、mem_data_oe の1クロック前の状態を表すsignal を定義することにする。SRAMへのデータ出力イネーブルmem_data_oe はSRAMのデータ出力パッド1個に対して1個必要なため、16個宣言した。さらに、IOB制約をVHDLコード上に書いた。下にSRAM_Controller.vhdの一部を示す。

signal mem_data_node : std_logic_vector(15 downto 0);
signal next_mem_data_oe : std_logic;

attribute iob : string;
attribute iob of n_mem_data_oe : signal is "TRUE";
attribute keep : string;
attribute keep of n_mem_data_oe : signal is "TRUE";
attribute keep of next_mem_data_oe : signal is "TRUE";
begin

.....

    -- n_mem_we, mem_data_oe を生成する。48MHzのステートマシンで出力
    process(clk48) begin
        if clk48'event and clk48='1' then
            if reset='1' then
                cs_we <= idle_we;
            else
                cs_we <= ns_we;
            end if;
        end if;
    end process;
    
    process(cs_we, r_w, cam_href_3d) begin
        case cs_we is
            when idle_we =>
                n_mem_we_node <= '1';
                if r_w='0' and cam_href_3d='1' then -- hrefの間だけSRAMにWriteする
                    ns_we <= we_active;
                    next_mem_data_oe <= '1';
                else
                    ns_we <= idle_we;
                    next_mem_data_oe <= '0';
                end if;
            when we_active => -- r_w が1時48MHzクロック1クロック間だけ n_mem_we を0にする
                n_mem_we_node <= '0';
                ns_we <= we_holdoff;
                next_mem_data_oe <= '0';
            when we_holdoff => -- この時はまだr_wが0
                n_mem_we_node <= '1';
                ns_we <= idle_we;
                next_mem_data_oe <= '0';
            when others =>
                n_mem_we_node <= '1';
                ns_we <= idle_we;
                next_mem_data_oe <= '0';
        end case;
    end process;
    n_mem_we <= n_mem_we_node;
    
    -- mem_data_oeの出力
    process(clk48) begin
        if clk48'event and clk48='1' then
            if reset='1' then
                n_mem_data_oe <= (others => '1');
            else
                for i in 15 downto 0 loop
                    n_mem_data_oe(i) <= not next_mem_data_oe;
                end loop;
            end if;
        end if;
    end process;


最上位のCamDispCntrl_SRAM.vhd のIOBUF にn_mem_data_oe を1本ずつ入れた。

    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(i)
        );
    end generate MEM_DATA_GEN;


これをインプリメントしたところ無事にmem_data のIOBに出力イネーブル用のFFが入った。mem_data<0> の様子を下図に示す。
iob_ff_2_091119.png

これでSRAMへの出力データのドライブオン、ドライブオフ時間が最短になることと思う。

(2009/11/20: 追記)
keep制約をかけないとIOBにn_mem_data_oe が入らないときがあるので追加しました。
  1. 2009年11月19日 21:25 |
  2. FPGAチップ内の配線方法
  3. | トラックバック:0
  4. | コメント:0