FC2カウンター FPGAの部屋 ZYBO用の Linaro Ubuntu のPL部にカメラ・コントローラを搭載する2(IPのシミュレーション)
FC2ブログ

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

FPGAの部屋

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

ZYBO用の Linaro Ubuntu のPL部にカメラ・コントローラを搭載する2(IPのシミュレーション)

ZYBO用の Linaro Ubuntu のPL部にカメラ・コントローラを搭載する1(準備編)”の続き。

以前作ったZedBoard用カメラ・コントローラIPを流用した。pixel_fifo はその通りにIP Catalog の FIFO Generator で生成した。

mt9d111_axi_lite_slave.v にレジスタを作って、機能を追加した。

オフセット0番地: フレーム・バッファの先頭アドレス

はもう実装されていたので、それを使用した。

オフセット4番地: 0 ビット目が 0 の時動画、0 ビット目に 1 の時に、ワンショットで取得した1フレームのカメラ画像を表示
            1 ビット目に 1 を Write した時に、ワンショットで1フレームの画像をフレーム・バッファに保存

を実装した。
”1 ビット目に 1 を Write した時に、ワンショットで1フレームの画像をフレーム・バッファに保存”という仕様なので、つまり、1 が書かれている時に 1 を書いてもワンショットパルスを出す仕様なのだ。それでステートマシンが長くなってしまった。AXIバスはアドレス転送とデータ転送が分かれているので、それでも大丈夫なようにステートマシンを組んだつもりだ。
オフセット4番地の 0 ビット目の値は、one_shot_state に割り当てた。
オフセット4番地の 1 ビット目に 1 を書いた時のワンショット・パルスは、one_shot_trigger に割り当てた。
そのコードを仕手に示す。

    // one_shot_reg
    always @(posedge aclk) begin
        if (reset)
            one_shot_reg <= 32'd0;    // default is continuous display mode
        else
            if (s_axi_lite_wvalid==1'b1 && s_axi_lite_awaddr[2]==1'b1)
                one_shot_reg <= s_axi_lite_wdata;
    end
    assign one_shot_state = one_shot_reg[0];

    // one_shot_tsm(State Machine for one_shot_trgger)
    always @(posedge aclk) begin
        if (reset) begin
            one_shot_tsm <= IDLE_TSM;
            one_shot_trigger <= 1'b0;
        end else begin
            case (one_shot_tsm)
                IDLE_TSM :
                    if (s_axi_lite_awvalid & awready & s_axi_lite_awaddr[2]) begin // one_shot_reg address
                        if (s_axi_lite_wvalid) begin // s_axi_wready is always 1
                            if (s_axi_lite_wdata[1]) begin // one_shot was triggered
                                one_shot_tsm <= ONE_SHOT_TRIG;
                                one_shot_trigger <= 1'b1;
                            end else begin // is not trigger
                                one_shot_tsm <= IDLE_TSM;
                                one_shot_trigger <= 1'b0;
                            end
                        end else begin // s_axi_lite_wvalid is not asserted
                            one_shot_tsm <= WAIT_ONE_SHOT;
                            one_shot_trigger <= 1'b0;
                        end
                    end
                WAIT_ONE_SHOT :
                    if (s_axi_lite_wvalid) begin // s_axi_wready is always 1
                        if (s_axi_lite_wdata[1]) begin // one_shot was triggered
                            one_shot_tsm <= ONE_SHOT_TRIG;
                            one_shot_trigger <= 1'b1;
                        end else begin // is not trigger
                            one_shot_tsm <= IDLE_TSM;
                            one_shot_trigger <= 1'b0;
                        end
                    end
                ONE_SHOT_TRIG : begin
                    one_shot_tsm <= ONE_SHOT_HOLD_OFF;
                    one_shot_trigger <= 1'b0;
                end
                ONE_SHOT_HOLD_OFF :
                    if (!awready) begin
                        one_shot_tsm <= IDLE_TSM;
                        one_shot_trigger <= 1'b0;
                    end
            endcase
        end
    end


mt9d111_cam_cont.v に mt9d111_axi_lite_slave.v から入力される one_shot_state, one_shot_trigger の入力ポートを追加した。one shot state machine を作って、one_shot_state がアサートされてもも、frame_valid がディアサートされるまでは画面を描画するようにした。また、one_shot_trigger がアサートされた時は、frame_valid がディアサートされるまで待っていて、1画面をチャプチャするようになっている。(つもりだ)
下に、one shot state machine を示す。(角ハイボールで酔っ払っている時に作ったので、間違っているかも?w)

    // one shot state machine
    // frame_valid_1d_oh を生成する
    always @(posedge pclk) begin
        if (preset) begin
            one_shot_sm <= IDLE_OS;
            frame_valid_1d_oh <= frame_valid_1d;
        end else begin
            case (one_shot_sm)
                IDLE_OS :
                    if (one_shot_state) begin
                        one_shot_sm <= WAIT_FRAME_VALID_END;
                        frame_valid_1d_oh <= frame_valid_1d;
                    end
                WAIT_FRAME_VALID_END :
                    if (!frame_valid_1d) begin
                        one_shot_sm <= HOLD_PICTURE;
                        frame_valid_1d_oh <= 1'b0;
                    end
                HOLD_PICTURE :
                    if (one_shot_trigger) begin
                        one_shot_sm <= WAIT_FRAME_VALID_LOW;
                        frame_valid_1d_oh <= 1'b0;
                    end else if (~one_shot_state & ~frame_valid_1d) begin
                        one_shot_sm <= IDLE_OS;
                        frame_valid_1d_oh <= frame_valid_1d;
                    end
                WAIT_FRAME_VALID_LOW :
                    if (!frame_valid_1d) begin
                        one_shot_sm <= WAIT_FRAME_VALID_HIGH;
                        frame_valid_1d_oh <= frame_valid_1d;
                    end
                WAIT_FRAME_VALID_HIGH :
                    if (frame_valid_1d) begin
                        one_shot_sm <= WAIT_FRAME_VALID_END;
                        frame_valid_1d_oh <= frame_valid_1d;
                    end
            endcase
        end
    end

(2014/11/12:追記 上の2つの Verilog HDL コードにはバグがありました。詳しくは、”ZYBO用の Linaro Ubuntu のPL部にカメラ・コントローラを搭載する10(デバック2)”を参照して下さい)

シミュレーションを行った。最初は、カメラのピクセル値をDDR3 SDRAMへWrite するためのAXI4 Write Transction だ。
ZYBO_Cam_Linux_1_141109.png

AXI4 Lite Slave に設けたレジスタをテストするのに下の様なスティミュラスを作った。

        // Add stimulus here
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0000, 32'h1200_0000);
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_RADC1(32'h0000_0000);
        #DELAY;
        
        @(posedge ACLK);    // 次のクロックへ        
        #DELAY;
        AXI_MASTER_WADC2(32'h0000_0004, 32'h0000_0001);    // one_shot mode
        @(posedge ACLK);    // 次のクロックへ        
        #DELAY;
        AXI_MASTER_RADC2(32'h0000_0004);
        
        @(posedge ACLK);    // 次のクロックへ        
        #DELAY;
        AXI_MASTER_WADC2(32'h0000_0004, 32'h0000_0003); // one_shot trigger
        @(posedge ACLK);    // 次のクロックへ        
        #DELAY;
        AXI_MASTER_RADC2(32'h0000_0004);
    end
            
    // Write Transcation 1
    task AXI_MASTER_WADC1;
        input    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    awaddr;
        input    [C_S_AXI_LITE_DATA_WIDTH-1:0]    wdata;
        begin
            s_axi_lite_awaddr    = awaddr;
            s_axi_lite_awvalid    = 1'b1;
            
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
            
            s_axi_lite_awvalid = 1'b0;
            s_axi_lite_wdata = wdata;
            s_axi_lite_wvalid = 1'b1;
            @(posedge ACLK);    // 次のクロックへ, s_axi_lite_wready は常に 1
            
            #DELAY;
            s_axi_lite_wvalid = 1'b0;
            s_axi_lite_bready = 1'b1;
            
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
                
            s_axi_lite_bready = 1'b0;
        end
    endtask

    // Write Transcation 2
    task AXI_MASTER_WADC2;
        input    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    awaddr;
        input    [C_S_AXI_LITE_DATA_WIDTH-1:0]    wdata;
        begin
            s_axi_lite_awaddr    = awaddr;
            s_axi_lite_awvalid    = 1'b1;
            
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
            
            s_axi_lite_awvalid = 1'b0;
            s_axi_lite_wdata = wdata;
            s_axi_lite_wvalid = 1'b1;
            @(posedge ACLK);    // 次のクロックへ, s_axi_lite_wready は常に 1
            
            #DELAY;
            s_axi_lite_wvalid = 1'b0;        
            @(posedge ACLK);    // 次のクロックへ
            
            #DELAY;        
            s_axi_lite_bready = 1'b1;
            
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
                
            s_axi_lite_bready = 1'b0;
        end
    endtask
    
    // Read Transcation 1    
    task AXI_MASTER_RADC1;
        input    [31:0]    araddr;
        begin
            s_axi_lite_araddr    = araddr;
            s_axi_lite_arvalid     = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
            
            s_axi_lite_araddr    = 0;
            s_axi_lite_arvalid     = 1'b0;
            s_axi_lite_rready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_rready = 1'b0;
        end
    endtask


そのシミュレーションを下に示す。one_shot_state が 1 にアサートされて、ワンショット・パルス one_shot_trigger も1クロックだけアサートされているのを見て欲しい。
ZYBO_Cam_Linux_2_141109.png

frame_valid がディアサートされて、one_shot_state が 1 にアサートされた時に、画像が保持されるのをシミュレーションで見ていないが、シミュレーションをすると長いので、実機で確かめることにする。

ZYBO用の Linaro Ubuntu のPL部にカメラ・コントローラを搭載する3(IP化)”に続く。
  1. 2014年11月09日 07:50 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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