FC2カウンター FPGAの部屋 並列ステレオカメラによる距離の測定5(ZYBO 0 のハードウェア4)
fc2ブログ

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

FPGAの部屋

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

並列ステレオカメラによる距離の測定5(ZYBO 0 のハードウェア4)

並列ステレオカメラによる距離の測定4(ZYBO 0 のハードウェア3)”の続き。

前回はタイミング違反を修正して、再度ビットストリームを生成し、SDKを立ち上げた。
今回は、SDK上でアプリケーション・プロジェクトを作製して、ソフトウェアを作り、ZYBO上で動かしてみよう。

SDK の File メニューからNew -> Application Project を選択する。

Project name に cam_disp と入力した。Next > ボタンをクリックした。OS Platform は取りあえず、ベアメタル・アプリケーションとするので、デフォルトの standalone に設定した。
StereoCam_37_151118.png

Available Templates から Empty Application を選択する。Finish ボタンをクリックした。
StereoCam_38_151118.png

今、使用しているVivado のバージョンは 2015.3 だが、2015.1 の時の Templates から明らかに項目が増えている。OpenAMP 関連の項目や、MPSoC 関連の項目が増えているようだ。Vivado 2015.1 の時のAvailable Templates 画面を下に示す。
V_ZYBO_CAMD_151_63_150612.png

cam_disp Application Project と cam_disp_bsp Board Support Package が生成された。
StereoCam_39_151118.png

次に、カメラ画像を表示されるソフトウェア cam_disp_aixs.c を作る。

cam_disp Application Project の src フォルダから 右クリックし、右クリックメニューから New -> Source File を選択した。
StereoCam_40_151119.png

New Source File ダイアログで Source file に cam_disp_axis.c を入力して、Finish ボタンをクリックした。
StereoCam_41_151119.png

cam_disp_axis.c は、”AXI4-Stream版ラプラシアンフィルタIPのカメラ表示システム9(カメラ画像表示は完成)”のCソースコードを元に、bitmap_disp_cntrler_axi_master_1 の処理を追加した。
StereoCam_42_151119.png
セーブするとビルドされ、elf ファイルが自動的に生成された。

SDK のXilinx Tools -> Program FPGA を選択した。

Program FPGA ダイアログが表示され、Program ボタンをクリックした。
StereoCam_43_151119.png

Zynq へのFPGA コンフィギュレーション・データのダウンロードが成功した。
StereoCam_44_151119.png

cam_disp.elf バイナリを起動する。

cam_disp.elf を右クリックし、右クリックメニューから Run AS -> Launch on Hardware (GDB) を選択した。
StereoCam_45_151119.png

VGAポートにカメラ画像が表示されたが、フレームレートが遅すぎる。
フレームレートは15fps / 3 = 5 fps 程度と思われる。これは、AXI VDMAで 3 画面分のフレームバッファを取っているけれども私の作ったビットマップ・ディスプレイ・コントローラのフレームバッファが1フレームであるので、15 fps のカメラ画像の更新頻度が 1/3 になってしまうためである。
StereoCam_46_151119.jpg

HDMIポートにもXGA画像が表示されているが、予想通り、時々消えてしまう。
StereoCam_47_151119.jpg

フレームレートが遅いのが我慢出来ないので、ビットマップ・ディスプレイ・コントローラのAXI4 Stream 版を作って、AXI VDMAからもらったカメラ画像のAXI4 Stream を使って表示ししてみたい。それに、HDMI へのXGA 出力はDigilent 社から配っている rgb2dvi IPを使用したい。

最後に、cam_disp_axis.c を貼っておく。

// cam_disp_axis.c
// 2015/11/19 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;
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);
}
// 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
// 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);
}

  1. 2015年11月19日 05:23 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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