FC2カウンター FPGAの部屋 カメラ・インターフェース用AXI4-Stream IPの作製4(HDLソース1)
FC2ブログ

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

FPGAの部屋

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

カメラ・インターフェース用AXI4-Stream IPの作製4(HDLソース1)

カメラ・インターフェース用AXI4-Stream IPの作製3(シミュレーション)”でシミュレーションしたHDLソースを貼っておきます。なお、バグがあったら予告なく修正します。

まずは、mt9d111_cam_conts.v から下に示す。

// MT9D111 Camera Controller for AXI4-Stream
// mt9d111_cam_contss.v
// 2013/05/29
// 

`default_nettype none

module mt9d111_cam_conts (
    input    wire    pclk,
    input    wire    preset,
    input    wire    pclk_from_pll,
    output    wire    xclk,
    input    wire    line_valid,
    input    wire    frame_valid,
    input    wire    [7:0]    cam_data,
    output    wire    standby,
    output    wire    s2mm_fsync,
    output    wire    pfifo_empty,
    output    wire    pfifo_almost_empty,
    input    wire    pfifo_rd_en,
    output    wire    [24:0]    pfifo_dout,
    output    wire    pfifo_overflow,
    output    wire    pfifo_underflow
);
    
    reg        line_valid_1d, line_valid_2d;
    reg        frame_valid_1d, frame_valid_2d;
    reg        [7:0]    cam_data_1d;
    reg        line_valid_1d_odd;
    reg        line_v_1d_odd_1d, line_v_1d_odd_2d, line_v_1d_odd_3d;
    reg        [23:0]    rgb565, rgb565_2d;
    wire    [24:0]    pfifo_din;
    wire    pfifo_full, pfifo_almost_full;
    reg        s2mm_fsync_node;
    
    assign standby = 1'b0;
    
    // MT9D111 へのクロックを出力 (xclk)
    ODDR #(
        .DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE"
        .INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
        .SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
    ) ODDR_inst (
        .Q(xclk), // 1-bit DDR output
        .C(pclk_from_pll), // 1-bit clock input
        .CE(1'b1), // 1-bit clock enable input
        .D1(1'b1), // 1-bit data input (positive edge)
        .D2(1'b0), // 1-bit data input (negative edge)
        .R(1'b0), // 1-bit reset
        .S(1'b0) // 1-bit set
    );
    
    // 入力信号を一旦ラッチする
    always @(posedge pclk) begin
        if (preset) begin
            line_valid_1d <=    1'b0;
            line_valid_2d <=     1'b0;
            frame_valid_1d <=    1'b0;
            frame_valid_2d <=     1'b0;
            cam_data_1d <=        8'd0;
        end else begin
            line_valid_1d <=    line_valid;
            line_valid_2d <=     line_valid_1d;
            frame_valid_1d <=    frame_valid;
            frame_valid_2d <=    frame_valid_1d;
            cam_data_1d <=        cam_data;
        end
    end
    
    // line_valid_1d が偶数か奇数かをカウント
    always @(posedge pclk) begin
        if (preset)
            line_valid_1d_odd <= 1'b0;
        else begin
            if (line_valid_1d)
                line_valid_1d_odd <= ~line_valid_1d_odd;
            else
                line_valid_1d_odd <= 1'b0;
        end
    end
    
    // rgb565でラッチしているので、line_valid_1d_odd を1クロック遅延する
    always @(posedge pclk) begin
        if (preset) begin
            line_v_1d_odd_1d <= 1'b0;
            line_v_1d_odd_2d <= 1'b0;
            line_v_1d_odd_3d <= 1'b0;
        end else begin
            line_v_1d_odd_1d <= line_valid_1d_odd;
            line_v_1d_odd_2d <= line_v_1d_odd_1d;
            line_v_1d_odd_3d <= line_v_1d_odd_2d;
        end
    end
    
    // rgb565
    always @(posedge pclk) begin
        if (preset)
            rgb565 <= 24'd0;
        else begin
            if (~line_valid_1d_odd)
                rgb565[23:13] <= {cam_data_1d[7:3], 3'b000, cam_data_1d[2:0]};    // cam_data_1d = R7 R6 R5 R4 R3 G7 G6 G5
            else
                rgb565[12:0] <= {cam_data_1d[7:5], 2'b00, cam_data_1d[4:0], 3'b000};    // cam_data_1d = G4 G3 G2 B7 B6 B5 B4 B3
        end
    end
    
    // rgb565_2d, データを2クロック遅らせて、tlastを最後から1つ前のデータに付加する
    always @(posedge pclk) begin
        if (preset)
            rgb565_2d <= 24'd0;
        else begin
            if (line_v_1d_odd_1d)
                rgb565_2d <= rgb565;
        end
    end
    
    assign pfifo_din = {((line_valid_2d & ~line_valid_1d) ? 1'b1 : 1'b0), rgb565_2d}; // line_valid_1d の立ち下がりエッジ
    
    // pixel FIFO をインスタンスする
    pixel_fifo pfifo (
        .clk(pclk),
        .srst(preset), // input rst
        .din(pfifo_din), // input [24 : 0] din
        .wr_en(line_v_1d_odd_3d), // input wr_en
        .rd_en(pfifo_rd_en), // input rd_en
        .dout(pfifo_dout), // output [24 : 0] dout
        .full(pfifo_full), // output full
        .almost_full(pfifo_almost_full), // output almost_full
        .overflow(pfifo_overflow), // output overflow
        .empty(pfifo_empty), // output empty
        .almost_empty(pfifo_almost_empty), // output almost_empty
        .underflow(pfifo_underflow) // output underflow
    );

    // s2mm_fsync
    always @(posedge pclk) begin
        if (preset)
            s2mm_fsync_node <= 1'b0;
        else begin
            if (frame_valid_1d==1'b1 && frame_valid_2d==1'b0) // frame_valid_1d の立ち上がり
                s2mm_fsync_node <= 1'b1;
            else
                s2mm_fsync_node <= 1'b0;
        end
    end
    assign s2mm_fsync = s2mm_fsync_node;
endmodule

`default_nettype wire


トップのVHDLファイルの mt9d111_inf_axi_stream.vhd を下に示す。

-------------------------------------------------------------------------------
-- Filename:          mt9d111_inf_axi_stream.vhd
-- Description: An AXI Stream interface
--
-- VHDL-Standard:   VHDL'93
-------------------------------------------------------------------------------
-- Structure:
--                  mt9d111_inf_axi_stream.vhd
--
-- AXI4-Stream データの出力は2クロックに1回とする
-------------------------------------------------------------------------------

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

--library unisim;
--use unisim.vcomponents.all;

-------------------------------------------------------------------------------
entity mt9d111_inf_axi_stream is
  generic(
        -- Master AXI Stream Data Width
        C_M_AXIS_DATA_WIDTH : integer range 8 to 1024 := 24
    );
  port (
        s2mm_aclk    : out std_logic;
        s2mm_prmry_reset : in std_logic;
        s2mm_fsync        : out std_logic;

        -- Master Stream Ports
    --    m_axis_aresetn : out std_logic;
        m_axis_tdata   : out std_logic_vector(C_M_AXIS_DATA_WIDTH-1 downto 0);
        m_axis_tstrb   : out std_logic_vector((C_M_AXIS_DATA_WIDTH/8)-1 downto 0);
        m_axis_tvalid  : out std_logic;
        m_axis_tready  : in  std_logic;
        m_axis_tlast   : out std_logic;
        
        init_done        : in std_logic; -- PS部の初期化終了
        
        -- MT9D111 Camera Interface
        pclk_from_pll    : in    std_logic;    -- PLLからMT9D111のxck に出力するクロック
        pclk            : in     std_logic;    -- MT9D111からのピクセルクロック入力
        xck                : out    std_logic;    -- MT9D111へのピクセルクロック出力
        href            : in     std_logic;
        vsync            : in    std_logic;
        cam_data        : in    std_logic_vector(7 downto 0);
        standby            : out    std_logic;    -- STANDBY出力(ディスエーブル、0固定)
        pfifo_overflow    : out    std_logic;    -- pfifo overflow
        pfifo_underflow    : out    std_logic    -- pfifo underflow
    );

end mt9d111_inf_axi_stream;

-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of mt9d111_inf_axi_stream is
signal pfifo_empty : std_logic;
signal pfifo_almost_empty : std_logic;
signal pfifo_rd_en : std_logic;
signal pfifo_dout : std_logic_vector(24 downto 0);
signal rst_1d, rst_2d, reset : std_logic;
signal tlast : std_logic;
type tlast_state is (idle_tlast, tlast_assert);
signal tlast_sm : tlast_state;
signal tvalid : std_logic;
type tvalid_state is (idle_tvalid, tvalid_assert);
signal tvalid_sm : tvalid_state;
component mt9d111_cam_conts
    port (
        pclk                : in    std_logic;
        preset                : in    std_logic;
        pclk_from_pll        : in    std_logic;
        xclk                : out    std_logic;
        line_valid            : in    std_logic;
        frame_valid            : in    std_logic;
        cam_data            : in    std_logic_vector(7 downto 0);
        standby                : out    std_logic;
        s2mm_fsync            : out    std_logic;
        pfifo_empty            : out    std_logic;
        pfifo_almost_empty    : out    std_logic;
        pfifo_rd_en            : in    std_logic;
        pfifo_dout            : out    std_logic_vector(24 downto 0);
        pfifo_overflow        : out    std_logic;
        pfifo_underflow        : out    std_logic
    );
end component;
begin
    s2mm_aclk <= pclk;
    
    mt9d111_camc : mt9d111_cam_conts port map(
        pclk                => pclk,
        preset                => reset,
        pclk_from_pll        => pclk_from_pll,
        xclk                => xck,
        line_valid            => href,
        frame_valid            => vsync,
        cam_data            => cam_data,
        standby                => standby,
        s2mm_fsync            => s2mm_fsync,
        pfifo_empty            => pfifo_empty,
        pfifo_almost_empty    => pfifo_almost_empty,
        pfifo_rd_en            => pfifo_rd_en,
        pfifo_dout            => pfifo_dout,
        pfifo_overflow        => pfifo_overflow,
        pfifo_underflow        => pfifo_underflow
    );
    
    -- Synchronization by pclk
    process(pclk) begin
        rst_1d <= s2mm_prmry_reset or not init_done;
        rst_2d <= rst_1d;
    end process;
    reset <= rst_2d;
        
    -- State Machine for tlast
    process(pclk) begin
        if pclk'event and pclk='1' then
            if reset='1' then
                tlast_sm <= idle_tlast;
                tlast <= '0';
            else 
                case tlast_sm is
                    when idle_tlast =>
                        if pfifo_dout(24)='1' and tvalid='1' and m_axis_tready='1' and pfifo_empty='0' then
                            tlast_sm <= tlast_assert;
                            tlast <= '1';
                        end if;
                    when tlast_assert =>
                        if m_axis_tready='1' then
                            tlast_sm <= idle_tlast;
                            tlast <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    m_axis_tlast <= tlast;
    
    -- State Machine for tvalid            
    process(pclk) begin
        if pclk'event and pclk='1' then
            if reset='1' then
                tvalid_sm <= idle_tvalid;
                tvalid <= '0';
            else
                case tvalid_sm is
                    when idle_tvalid =>
                        if pfifo_empty='0' then -- pfifo にデータがある
                            tvalid_sm <= tvalid_assert;
                            tvalid <= '1';
                        end if;
                    when tvalid_assert =>
                        if m_axis_tready='1' and pfifo_almost_empty='1' then -- 次のデータがない場合はidle に戻る
                            tvalid_sm <= idle_tvalid;
                            tvalid <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    m_axis_tvalid <= tvalid;
    
    pfifo_rd_en <= tvalid and m_axis_tready;
    m_axis_tdata <= pfifo_dout(23 downto 0);
    m_axis_tstrb <= (others => '1');
    
end implementation;


pixel_fifo は、”カメラ・インターフェース用AXI4-Stream IPの作製2(pixel_fifo の生成)”を見て下さい。

  1. 2013年06月02日 04:27 |
  2. AXI4-Stream IPの作製
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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