FC2カウンター FPGAの部屋 AXI VDMAのドライバによるレジスタの設定値(S2MMの設定)

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

FPGAの部屋

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

AXI VDMAのドライバによるレジスタの設定値(S2MMの設定)

AXI VDMAのドライバによるレジスタの設定値”でAXI VDMA のS2MM を使用する場合のベアメタル・ドライバの設定値をVivado Analyzer を使って解析した。
それでも、前回解析したのは動作しなかった場合で、フレームバッファが 1 面の時だったので、動作するようになった 3 面のフレームバッファの場合の解析をしてみる。

使用するソフトウェアは、”並列ステレオカメラによる距離の測定6(ZYBO 0 のハードウェア5)完成”で表示された元画像だが、元画像のソフトウェアは、AXI VDMA を設定する場所が分散している。そこで、AXI VDMA の設定を集めた cam_disp2.c を作製して、それを動作させることにした。
cam_disp.c を下に示す。

// cam_disp2.c
// 2015/12/02 by marsee
//
// Refered to Xilinx\SDK\2015.1\data\embeddedsw\XilinxProcessorIPLib\drivers\axivdma_v5_1\doc\html\api
// Refered to https://github.com/elitezhe/Atyls-VDMA-one-in-one-out/blob/master/SDK/colorbar/src/helloworld.c
// Refered to http://www.xilinx.com/support/documentation/ip_documentation/axi_vdma/v6_2/pg020_axi_vdma.pdf
// Refered to http://forums.xilinx.com/t5/Embedded-Processor-System-Design/Axi-VDMA-on-Digilent-Atlys/td-p/297019/page/2
//
// normal camera out
//

#include <stdio.h>
#include <stdlib.h>
#include "xaxivdma.h"
#include "xil_io.h"
#include "xparameters.h"
#include "sleep.h"

#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS    800
#define VERTICAL_LINES        600
#define PIXEL_NUM_OF_BYTES    4

#define FRAME_BUFFER_ADDRESS 0x10000000

static XAxiVdma_DmaSetup Vdma0_WriteCfg;

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2; // reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1; // enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main(){
    // malloc frame buffer
    // unsigned int *frame_buffer = (unsigned int *)malloc(HORIZONTAL_PIXELS * VERTICAL_LINES * PIXEL_NUM_OF_BYTES * NUMBER_OF_WRITE_FRAMES);

    // AXI VDMA Initialization sequence
    XAxiVdma_Config *XAxiVdma0_Config;
    XAxiVdma XAxiVdma0;
    int XAxiVdma0_Status;

    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x40), 0x0);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR+0x44), 0x80000000); // disable
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_1_BASEADDR), 0x2); // Commit registers

    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR+0x40), 0x0);
    Xil_Out32((XPAR_CAMERA_INTERFACE_AXIS_SWITCH_0_BASEADDR), 0x2); // Commit registers

    XAxiVdma0_Config = XAxiVdma_LookupConfig(XPAR_CAMERA_INTERFACE_AXI_VDMA_0_DEVICE_ID); // Look up the hardware configuration for a device instance
    if (XAxiVdma0_Config == NULL){
        fprintf(stderr, "No AXI VDMA found\n");
        return(-1);
    }

    XAxiVdma0_Status = XAxiVdma_CfgInitialize(&XAxiVdma0, XAxiVdma0_Config, XAxiVdma0_Config->BaseAddress); // Initialize the driver with hardware configuration
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_CfgInitialize() failed\n");
        return(-1);
    }

    XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_WRITE);
    while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_WRITE)) ;

    XAxiVdma0_Status = XAxiVdma_SetFrmStore(&XAxiVdma0, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_WRITE); // Set the number of frame store buffers to use.

    Vdma0_WriteCfg.VertSizeInput = VERTICAL_LINES;
    Vdma0_WriteCfg.HoriSizeInput = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES;
    Vdma0_WriteCfg.Stride = HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES; // Indicates the number of address bytes between the first pixels of each video line.
    Vdma0_WriteCfg.FrameDelay = 0; // Indicates the minimum number of frame buffers the Genlock slave is to be behind the locked master. This field is only used if the channel is enabled for Genlock Slave operations. This field has no meaning in other Genlock modes.
    Vdma0_WriteCfg.EnableCircularBuf = 1; // Indicates frame buffer Circular mode or frame buffer Park mode.  1 = Circular Mode Engine continuously circles through frame buffers.
    Vdma0_WriteCfg.EnableSync = 0; // Enables Genlock or Dynamic Genlock Synchronization. 0 = Genlock or Dynamic Genlock Synchronization disabled.
    Vdma0_WriteCfg.PointNum = 0; // No Gen-Lock
    Vdma0_WriteCfg.EnableFrameCounter = 0; // Endless transfers
    Vdma0_WriteCfg.FixedFrameStoreAddr = 0; // We are not doing parking

    XAxiVdma0_Status = XAxiVdma_DmaConfig(&XAxiVdma0, XAXIVDMA_WRITE, &Vdma0_WriteCfg);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaConfig() failed\n");
        return(-1);
    }

    // Frame buffer address set
    unsigned int frame_addr = (unsigned int)FRAME_BUFFER_ADDRESS;
    int i;
    for (i=0; i<NUMBER_OF_WRITE_FRAMES; i++){
        Vdma0_WriteCfg.FrameStoreStartAddr[i] = frame_addr;
        frame_addr += HORIZONTAL_PIXELS * PIXEL_NUM_OF_BYTES * VERTICAL_LINES;
    }

    XAxiVdma0_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma0, XAXIVDMA_WRITE, Vdma0_WriteCfg.FrameStoreStartAddr);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaSetBufferAddr() failed\n");
        return(-1);
    }

    // VDMA start
    XAxiVdma0_Status = XAxiVdma_DmaStart(&XAxiVdma0, XAXIVDMA_WRITE);
    if (XAxiVdma0_Status != XST_SUCCESS){
        fprintf(stderr, "XAxiVdma_DmaStart() failed\n");
        return(-1);
    }

    // mt9d111_inf_axis_0, axi_iic_0, bitmap_disp_cntrler_axi_master_0
    volatile unsigned int *bmdc0_axi_lites;
    volatile unsigned int *bmdc1_axi_lites;
    volatile unsigned int *mt9d111_axi_lites;
    volatile unsigned int *mt9d111_i2c_axi_lites;

    bmdc0_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_0_BASEADDR;
    bmdc1_axi_lites = (volatile unsigned *)XPAR_BITMAP_DISP_CNTRLER_AXI_MASTER_1_BASEADDR;
    mt9d111_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_MT9D111_INF_AXIS_0_BASEADDR;
    mt9d111_i2c_axi_lites = (volatile unsigned *)XPAR_CAMERA_INTERFACE_AXI_IIC_0_BASEADDR;

    bmdc0_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller 0 start
    bmdc1_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Bitmap Display Controller 1 start
    mt9d111_axi_lites[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(mt9d111_i2c_axi_lites);

    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0xf0, 0x1);      // Changed regster map to IFP page 1
    cam_i2c_write(mt9d111_i2c_axi_lites, 0xba, 0x97, 0x20);        // RGB Mode, RGB565

    mt9d111_axi_lites[1] = 0; // One_shot_mode is disabled

    return(0);
}


まずは、Vivado で AXI VDMA のS_AXI_LITE ポートにMark Debug した。
StereoCam_123_151202.png

論理合成、インプリメント、ビットストリームの生成をやり直した。
StereoCam_124_151202.png

ハードウェアをエクスポートして、SDKを起動した。

SDKから Program FPGA して、Run AS で cam_disp2.elf を一旦起動した。こうしないとPS がコンフィギュレーションされないので、PLへのクロックが出力されない。

Vivado で Program and Debug -> Open Hardware Manager -> Open Target をクリックしてVivado Analyzer で解析を行った。
StereoCam_116_151202.png

最初の波形を示す。(2015/12/06 追加: 最初の波形を変更。最初は、AXI4 Lite Slave Read からだった)
StereoCam_128_151206.png

Read : 0x2C 番地をRead した。値は、0x62000005。VDMA_VERSION。Major Version は 6 、Minor Version は 2 、Xilinx Internal は 5 だった。

Read : 0x4C 番地をRead した。値は、0x0。C_ENABLE_DEBUG_INFO_9 = 1 の時に、 enable S2MM_THRESHOLD (0x4C) register.

たぶん、XAxiVdma_CfgInitialize(&XAxiVdma0, XAxiVdma0_Config, XAxiVdma0_Config->BaseAddress) でRead されいるのだろう?

StereoCam_117_151202.png
Write : 0x30 番地に 0x4 をWrite した。これは、S2MM_VDMACR (S2MM VDMA Control Register – Offset 30h) が 0x4 なので、Reset のビットのみ立っている。リセットしているようだ。
XAxiVdma_Reset(&XAxiVdma0, XAXIVDMA_WRITE);

Read : 0x30 番地をRead した。S2MM_VDMACR。値は0x00010002 で、IRQFrameCount が 0x1、Circular_Park が 1 で後は全て 0 だった。2ビット目0x4 のResetが 1 の時は、リセット処理が進んでいるので、2ビット目が 0 であることを見ているようだ。
while(XAxiVdma_ResetNotDone(&XAxiVdma0, XAXIVDMA_WRITE)) ;

Write : もう一度、0x30 番地に 0x4 をWrite した。これは、S2MM_VDMACR のReset ビットのみ 1 にしている。2回リセットしている。

Read : もう一度、0x30 番地をRead した。S2MM_VDMACR。値は0x00010002 で、IRQFrameCount が 0x1、Circular_Park が 1 で後は全て 0 だった。。2ビット目0x4 のResetが 1 の時は、リセット処理が進んでいるので、2ビット目が 0 であることを見ているようだ。
上の2つのリセット、確認は要らない気がする?

StereoCam_118_151202.png
Read : 0x34をRead した。 S2MM VDMA Status Register(S2MM_VDMASR)。値は0x00010001 で、IRQFrameCntSts が 0x1、 Halted が 1 となっている。
もしかしたら、下の XAxiVdma_SetFrmStore() でステータスを返しているのかもしれない?(要らないかも?)

Write : 0x48 に 0x3 をWrite した。0x48は、”AXI Video Direct Memory Access v6.2 LogiCORE IP Product Guide Vivado Design Suite PG020 November 18, 2015”では、Reserved となっている。
しかし、75ページの C_ENABLE_DEBUG_INFO_13 が 1 の時は Enables S2MM_FRMSTORE (0x48) registerと書いてあるので、どうやら 0x48 にレジスタがあるようだ。
XAxiVdma0_Status = XAxiVdma_SetFrmStore(&XAxiVdma0, NUMBER_OF_WRITE_FRAMES, XAXIVDMA_WRITE);
上の XAxiVdma_SetFrmStore() をコメントアウトしても画面が表示されたので、必須ではないようです。

StereoCam_119_151202.png
Read : 0x30 番地をRead した。S2MM_VDMACR。値は0x00010002 で、IRQFrameCount が 0x1、Circular_Park が 1 で後は全て 0 だった。

Read : 0x30 番地をRead した。S2MM_VDMACR。値は0x00010002 で、IRQFrameCount が 0x1、Circular_Park が 1 で後は全て 0 だった。
上の2つのRead は XAxiVdma_DmaConfig()の時にステータスをReadしたのかもしれない?要らないかも知れない?

Write : 0x30 番地に 0x00010002 をWrite した。これは、S2MM_VDMACR のIRQFrameCount が 0x1、Circular_Park が 1 で後は全て 0 だった。リセット解除?

Write : 0xA4 番地に 0x00000c80 を Write した。 S2MM Horizontal Size Register(S2MM_HSIZE)。10進数で3200 = 800 x 4バイト。

Write : 0xA8 番地に 0x00000c80 を Write した。 S2MM Frame Delay and Stride Register(S2MM_FRMDLY_STRIDE)。10進数で3200 = 800 x 4バイト。
XAxiVdma0_Status = XAxiVdma_DmaConfig(&XAxiVdma0, XAXIVDMA_WRITE, &Vdma0_WriteCfg);

StereoCam_120_151202.png
Write : 0xAC 番地に 0x10000000 をWrite した。(S2MM Start Address 1) 1フレーム目のアドレスに先頭アドレスの 0x10000000 を書いた。

Write : 0xB0 番地に 0x101d4c00 をWrite した。(S2MM Start Address 2) の2フレーム目の先頭アドレスの 0x101d4c00 を書いた。

Write : 0xB4 番地に 0x103a9800 をWrite した。(S2MM Start Address 2) の2フレーム目の先頭アドレスの 0x101d4c00 を書いた。
XAxiVdma0_Status = XAxiVdma_DmaSetBufferAddr(&XAxiVdma0, XAXIVDMA_WRITE, Vdma0_WriteCfg.FrameStoreStartAddr);

Read : 0x34番地をRead した。 S2MM VDMA Status Register(S2MM_VDMASR)。値は0x00010001 で、IRQFrameCntSts が 0x1、 Halted が 1 となっている。
 XAxiVdma_DmaSetBufferAddr() の時のステータスReadかも知れない?

StereoCam_121_151202.png
Read : 0x30 番地をRead した。S2MM_VDMACR。値は0x00010002 で、IRQFrameCount が 0x1、Circular_Park が 1 で後は全て 0 だった。

Read : 0x30 番地をRead した。S2MM_VDMACR。値は0x00010002 で、IRQFrameCount が 0x1、Circular_Park が 1 で後は全て 0 だった。

Write : 0x30 番地(S2MM_VDMACR)に 0x00010003 をWrite した。これは、IRQFrameCount が 0x1、Circular_Park が 1 、Run/Stop が 1 で後は全て 0 だった。
XAxiVdma0_Status = XAxiVdma_DmaStart(&XAxiVdma0, XAXIVDMA_WRITE);

Read : 0x34番地をRead した。 S2MM VDMA Status Register(S2MM_VDMASR)。値は0x00010000 で、IRQFrameCntSts が 0x1のみだった。 Halted の 1 が解除されていた。
XAxiVdma_DmaStart() のステータスRead ではないか?と思う。

Read : 0x30 番地をRead した。S2MM_VDMACR。値は0x00010003 で、IRQFrameCount が 0x1、Circular_Park が 1 、Run/Stop が 1 で後は全て 0 だった。

StereoCam_121_151202.png
Write : 0xA0番地(S2MM Vertical Size (S2MM_VSIZE – Offset 0xA0))をWrite した。値は0x00000258 で10進数で 600 ラインだ。

これで終わりだ。0x48 が S2MM_FRMSTORE (0x48) というのが分かって良かった。
  1. 2015年12月02日 06:12 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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