FC2カウンター FPGAの部屋 ZYBO Z7

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

FPGAの部屋

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

ZYBO Z7-20上のUbuntu 14.04でカメラ画像をBMPファイルに変換する

ZYBO Z7-20上のUbuntu 14.04でカメラ画像を表示”の続き。

前回は、ZYBO Z7-20 のUbuntu 14.04 上でカメラ画像を表示することができた。今回は、カメラ画像からBMPファイルを生成する cam_capture_bmp を試してみた。

cam_capture_bmp.c は見たところ、ZYBO Z7-20 用に変更しなくとも今までのバイナリがそのまま動作するようだ。
cam_capture_bmp を試してみたところ、問題なくBMP ファイルを生成できた。具体的にはcam_capture_bmp を起動して、w コマンドを入力すると bmp_file0.bmp が生成される。もう一度、w を押すと bmp_file1.bmp が生成されるはずだ。
ZYBO_Z7_145_171017.png

ZYBO_Z7_146_171017.png

今日のXilinx のセミナではないけど、ffmpeg をインストールしてカメラ画像をストリーミングできれば面白いんだけどね。少し調べてみるか。。。独自のカメラ・システムから画像を流し込めるのかしら?

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

//
// cam_capture_bmp.cpp
// 2016/08/19 by marsee
//
// This software converts the left and right of the camera image to BMP file.
// -b : bmp file name
// -n : Start File Number
// -h : help
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

#include "bmp_header.h"

#define PIXEL_NUM_OF_BYTES    4

#define SVGA_HORIZONTAL_PIXELS  800
#define SVGA_VERTICAL_LINES     600
#define SVGA_ALL_DISP_ADDRESS   (SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define SVGA_3_PICTURES         (SVGA_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)

int WriteBMPfile(FILE *fbmp, volatile unsigned int *frame_buffer, BMP24FORMAT **bmp_data);

int main(int argc, char *argv[]){
    int opt;
    int c, help_flag=0;
    char bmp_fn[256] = "bmp_file";
    unsigned char  attr[1024];
    unsigned long  phys_addr;
    int i, j;
    int file_no = 0;
    FILE *fbmp;
    BMP24FORMAT **bmp_data; // 24 bits Date of BMP files (SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES)

    while ((opt=getopt(argc, argv, "b:n:h")) != -1){
        switch (opt){
            case 'b':
                strcpy(bmp_fn, optarg);
                break;
            case 'n':
                file_no = atoi(optarg);
                break;
            case 'h':
                help_flag = 1;
                break;
        }
    }

    if (help_flag == 1){ // help
        printf("Usage : cam_capture_bmp [-b <bmp file name>] [-n <Start File Number>] [-h]\n");
        exit(0);
    }

    // udmabuf0
    int fdf = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The cache is disabled. 
    if (fdf == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    volatile unsigned *frame_buffer = (volatile unsigned *)mmap(NULL, SVGA_ALL_DISP_ADDRESS, PROT_READ|PROT_WRITE, MAP_SHARED, fdf, 0);
    if (!frame_buffer){
        fprintf(stderr, "frame_buffer mmap error\n");
        exit(-1);
    }

    // phys_addr of udmabuf0
    int fdp = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fdp == -1){
        fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fdp, attr, 1024);
    sscanf((const char *)attr, "%lx", &phys_addr);  
    close(fdp);
    printf("phys_addr = %x\n", (unsigned int)phys_addr);

    // allocated the memory for bmp file
    if ((bmp_data=(BMP24FORMAT **)malloc(sizeof(BMP24FORMAT *)*SVGA_VERTICAL_LINES)) == NULL){
        fprintf(stderr, "Can not allocate memory of the first dimension of SVGA_VERTICAL_LINES of bmp_data\n");
        exit(1);
    }
    for (i=0; i<SVGA_VERTICAL_LINES; i++){
        if ((bmp_data[i]=(BMP24FORMAT *)malloc(sizeof(BMP24FORMAT) * SVGA_HORIZONTAL_PIXELS)) == NULL){
            fprintf(stderr, "Can not allocate %d th memory of the first dimension of bmp_data\n", i);
            exit(1);
        }
    }
   
    char bmp_file[256];

    // w - writed the left and right eye's bmp files.  q - exit.
    c = getc(stdin);
    while(c != 'q'){
        switch ((char)c) {
            case 'w' : // w - writed the left and right eye's bmp files.
                // writed the left and right eys's frame buffer
                sprintf(bmp_file, "%s%d.bmp", bmp_fn, file_no);
                if ((fbmp=fopen(bmp_file, "wb")) == NULL){
                    fprintf(stderr, "Cannot open %s in binary mode\n", bmp_file);
                    exit(1);
                }
                WriteBMPfile(fbmp, frame_buffer, bmp_data);
                fclose(fbmp);
                
                printf("file No. = %d\n", file_no);

                file_no++;
                break;
        }
        c = getc(stdin);
    }

    for(i=0; i<SVGA_VERTICAL_LINES; i++){
        free(bmp_data[i]);
    }
    free(bmp_data);
    munmap((void *)frame_buffer, (SVGA_ALL_DISP_ADDRESS));
    close(fdf);
    
    return(0);
}

int WriteBMPfile(FILE *fbmp, volatile unsigned *frame_buffer, BMP24FORMAT **bmp_data){
    BITMAPFILEHEADER bmpfh; // file header for a bmp file
    BITMAPINFOHEADER bmpih; // INFO header for BMP file

    // Copy the camera color data of the bmp_data (data of BMP when its starts from lower left)
    for (int i=0; i<SVGA_VERTICAL_LINES; i++){
        for (int j=0; j<SVGA_HORIZONTAL_PIXELS; j++){
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].red = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j]>>16)&0xff;
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].green = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j]>>8)&0xff;
            bmp_data[(SVGA_VERTICAL_LINES-1)-i][j].blue = (frame_buffer[i*SVGA_HORIZONTAL_PIXELS+j])&0xff;
        }
    }

    // Assign a value to the file header of the BMP file
    bmpfh.bfType = 0x4d42;
    bmpfh.bfSize = SVGA_HORIZONTAL_PIXELS*SVGA_VERTICAL_LINES*3+54;
    bmpfh.bfReserved1 = 0;
    bmpfh.bfReserved2 = 0;
    bmpfh.bfOffBits = 0x36;

    // Assign a value to the INFO header of the BMP file
    bmpih.biSize = 0x28;
    bmpih.biWidth = SVGA_HORIZONTAL_PIXELS;
    bmpih.biHeight = SVGA_VERTICAL_LINES;
    bmpih.biPlanes = 0x1;
    bmpih.biBitCount = 24;
    bmpih.biCompression = 0;
    bmpih.biSizeImage = 0;
    bmpih.biXPixPerMeter = 3779;
    bmpih.biYPixPerMeter = 3779;
    bmpih.biClrUsed = 0;
    bmpih.biClrImporant = 0;

    // Writing of BMP file header
    fwrite(&bmpfh.bfType, sizeof(char), 2, fbmp);
    fwrite(&bmpfh.bfSize, sizeof(long), 1, fbmp);
    fwrite(&bmpfh.bfReserved1, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfReserved2, sizeof(short), 1, fbmp);
    fwrite(&bmpfh.bfOffBits, sizeof(long), 1, fbmp);

    // Writing of BMP INFO header
    fwrite(&bmpih, sizeof(BITMAPINFOHEADER), 1, fbmp);

    // Writing of bmp_data
    for (int i=0; i<SVGA_VERTICAL_LINES; i++) {
        for (int j=0; j<SVGA_HORIZONTAL_PIXELS; j++) {
            fputc((int)bmp_data[i][j].blue, fbmp);
            fputc((int)bmp_data[i][j].green, fbmp);
            fputc((int)bmp_data[i][j].red, fbmp);
        }
    }
}

  1. 2017年10月18日 04:30 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

ZYBO Z7-20上のUbuntu 14.04でカメラ画像を表示

”白線間走行畳み込みニューラルネットワーク・システムをZYBO Z7-20で動作させる3(ガボール・フィルタの追加)”でガボール・フィルタを追加したZYBO Z7-20 のZYBO_Z7_0 プロジェクトが出来上がって、Ubuntu 14.04 が起動したので、今回は、Ubuntu 14.04 上でカメラ画像が表示してみようと思う。

Ubuntu 上で nautilus を起動した。
ZYBO_Z7_139_171017.png

cam_disp_dmaw.c を編集する前に、UIO の番号を調べるために、デバイスツリーにUIO の番号を書いた。
ZYBO_Z7_140_171017.png

cam_disp_dmaw.c を編集した。ガボール・フィルタのUIO 番号を変更して、ビットマップ・ディスプレイ・コントローラ1 を削除した。
ZYBO_Z7_141_171017.png

cam_disp_dmaw.c をコンパイルして、udmabuf_insmod を起動した。
udmabuf はリコンパイルしなくても動作した。
cam_disp_dmaw を起動した。
ZYBO_Z7_142_171017.png

画像が表示された。良かった。。。
ZYBO_Z7_149_171017.jpg

top コマンドを実行した結果を示す。メモリは 1 GB 認識されているようだ。
ZYBO_Z7_143_171017.png

df コマンドを実行した結果を示す。57 % 使用している。
ZYBO_Z7_144_171017.png

cam_disp_dmaw.c を貼っておく。

//
// cam_disp_dmaw.c
// Created on: 2016/09/28
//      Author: marsee
// 2016/01/23 : udmabuf version
// 2016/08/09 : Gabor Filter version
// 2016/09/28 : DMAW4Gabor version
// 2017/10/17 : for ZYBO Z7-20
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>

#define CMA_START_ADDRESS 0x17800000
#define VIDEO_BUFFER_START_ADDRESS  0x18000000    // Limit 0x18800000, 800*600*4 = 2MBytes * 2

#define HORIZONTAL_PIXEL    800
#define ALL_CHAR_OF_1LINE   (HORIZONTAL_PIXEL/8)
#define VERTICAL_PIXEL      600
#define ALL_CHAR_OF_ROW     (VERTICAL_PIXEL/8)
#define ALL_DISP_ADDRESS    (HORIZONTAL_PIXEL*VERTICAL_PIXEL*4)
#define ALL_DISP_CHARACTOR  (HORIZONTAL_PIXEL*VERTICAL_PIXEL)

void cam_i2c_init(volatile unsigned *mt9d111_axi_iic) {
    mt9d111_axi_iic[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_axi_iic[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_axi_iic, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_axi_iic[66] = 0x100 | (device_addr & 0xfe);    // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_axi_iic[66] = write_addr;
    mt9d111_axi_iic[66] = (write_data >> 8)|0xff;            // first data
    mt9d111_axi_iic[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main()
{
    int fd0, fd1, fd2, fd3, fd4, fd5, fd6, fd8, fd9, fd10;
    volatile unsigned *bmdc_axi_lites0;
    volatile unsigned *dmaw4gabor_0;
    volatile unsigned *axis_switch_0, *axis_switch_1;
    volatile unsigned *mt9d111_inf_axis_0;
    volatile unsigned *mt9d111_axi_iic;
    volatile unsigned *axi_gpio_0;
    volatile unsigned *frame_buffer_bmdc;
    unsigned char  attr[1024];
    unsigned long  phys_addr;
    int i;

    // Bitmap Display Controller 0 AXI4 Lite Slave (UIO6)
    fd6 = open("/dev/uio6", O_RDWR); // bitmap_display_controller 0 axi4 lite
    if (fd6 < 1){
        fprintf(stderr, "/dev/uio6 (bitmap_disp_cntrler_axi_master_0) open error\n");
        exit(-1);
    }
    bmdc_axi_lites0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd6, 0);
    if (!bmdc_axi_lites0){
        fprintf(stderr, "bmdc_axi_lites0 mmap error\n");
        exit(-1);
    }
    
    // dmaw4gabor_0 (UIO1)
    fd1 = open("/dev/uio1", O_RDWR); // dmaw4gabor_0 interface AXI4 Lite Slave
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (dmaw4gabor_0) open error\n");
        exit(-1);
    }
    dmaw4gabor_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!dmaw4gabor_0){
        fprintf(stderr, "dmaw4gabor_0 mmap error\n");
        exit(-1);
    }
    
    // mt9d111 i2c AXI4 Lite Slave (UIO0)
    fd0 = open("/dev/uio0", O_RDWR); // mt9d111 i2c AXI4 Lite Slave
    if (fd0 < 1){
        fprintf(stderr, "/dev/uio0 (mt9d111_axi_iic) open error\n");
        exit(-1);
    }
    mt9d111_axi_iic = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd0, 0);
    if (!mt9d111_axi_iic){
        fprintf(stderr, "mt9d111_axi_iic mmap error\n");
        exit(-1);
    }

    // mt9d111 inf axis AXI4 Lite Slave (UIO5)
    fd5 = open("/dev/uio5", O_RDWR); // mt9d111 inf axis AXI4 Lite Slave
    if (fd5 < 1){
        fprintf(stderr, "/dev/uio5 (mt9d111_inf_axis_0) open error\n");
        exit(-1);
    }
    mt9d111_inf_axis_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd5, 0);
    if (!mt9d111_inf_axis_0){
        fprintf(stderr, "mt9d111_inf_axis_0 mmap error\n");
        exit(-1);
    }

    // axis_switch_0 (UIO2)
    fd2 = open("/dev/uio2", O_RDWR); // axis_switch_0 interface AXI4 Lite Slave
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (axis_switch_0) open error\n");
        exit(-1);
    }
    axis_switch_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!axis_switch_0){
        fprintf(stderr, "axis_switch_0 mmap error\n");
        exit(-1);
    }
    
    // axis_switch_1 (UIO3)
    fd3 = open("/dev/uio3", O_RDWR); // axis_switch_1 interface AXI4 Lite Slave
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (axis_switch_1) open error\n");
        exit(-1);
    }
    axis_switch_1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!axis_switch_1){
        fprintf(stderr, "axis_switch_1 mmap error\n");
        exit(-1);
    }
    
    // axi_gpio_0 (UIO8)
    fd8 = open("/dev/uio8", O_RDWR); // axi_gpio_0 interface AXI4 Lite Slave
    if (fd8 < 1){
        fprintf(stderr, "/dev/uio8 (axi_gpio_0) open error\n");
        exit(-1);
    }
    axi_gpio_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd8, 0);
    if (!axi_gpio_0){
        fprintf(stderr, "axi_gpio_8 mmap error\n");
        exit(-1);
    }
    
    // udmabuf0
    fd9 = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled. 
    if (fd9 == -1){
        fprintf(stderr, "/dev/udmabuf0 open error\n");
        exit(-1);
    }
    frame_buffer_bmdc = (volatile unsigned *)mmap(NULL, 5760000, PROT_READ|PROT_WRITE, MAP_SHARED, fd9, 0);
    if (!frame_buffer_bmdc){
        fprintf(stderr, "frame_buffer_bmdc mmap error\n");
        exit(-1);
    }

    // axis_switch_1, 1to2 ,Select M00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_1[16] = 0x0// 0x40 = 0
    axis_switch_1[17] = 0x80000000// 0x44 = 0x80000000, disable
    axis_switch_1[18] = 0x80000000// 0x48 = 0x80000000, disable
    axis_switch_1[0] = 0x2// Comit registers
    
    // axis_switch_0, 2to1, Select S00_AXIS
    // Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
    axis_switch_0[16] = 0x0// 0x40 = 0;
    axis_switch_0[0] = 0x2// Comit registers
    
    // phys_addr of udmabuf0
    fd10 = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
    if (fd10 == -1){
        fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
        exit(-1);
    }
    read(fd10, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd10);
    printf("phys_addr = %x\n", (int)phys_addr);
    
    // DMAW4Gabor Initialization sequence
    dmaw4gabor_0[6] = (int)phys_addr; // Data signal of frame_buffer0
    dmaw4gabor_0[8] = (int)phys_addr; // Data signal of frame_buffer1
    dmaw4gabor_0[0] = 0x1// ap_start = 1
    dmaw4gabor_0[0] = 0x80// auto_restart = 1

    // bitmap display controller settings
    bmdc_axi_lites0[0] = (int)phys_addr; // Bitmap Display Controller 0 start
    mt9d111_inf_axis_0[0] = (int)phys_addr; // Camera Interface start (Address is dummy)

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(mt9d111_axi_iic);
    
    for (i=0; i<100; i++){
        cam_i2c_write(mt9d111_axi_iic, 0xba, 0xf00x1);        // Changed regster map to IFP page 1
        cam_i2c_write(mt9d111_axi_iic, 0xba, 0x970x20);    // RGB Mode, RGB565
    }

    mt9d111_inf_axis_0[1] = 0;
    
    munmap((void *)bmdc_axi_lites0, 0x10000);
    munmap((void *)dmaw4gabor_0, 0x10000);
    munmap((void *)mt9d111_inf_axis_0, 0x10000);
    munmap((void *)mt9d111_axi_iic, 0x10000);
    munmap((void *)axis_switch_0, 0x10000);
    munmap((void *)axis_switch_1, 0x10000);
    munmap((void *)axi_gpio_0, 0x10000);
    munmap((void *)frame_buffer_bmdc, 576000);
    
    close(fd0);
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    close(fd5);
    close(fd6);
    close(fd8);
    close(fd9);
    
    return(0);
}

  1. 2017年10月17日 04:50 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

白線間走行畳み込みニューラルネットワーク・システムをZYBO Z7-20で動作させる3(ガボール・フィルタの追加)

白線間走行畳み込みニューラルネットワーク・システムをZYBO Z7-20で動作させる2”の続き。

前回でFPGAのハードウェアをフィックスしたつもりだったが、やはり、ガボール・フィルタを入れてみたいということで、入れてみた。更にFSBL を作ってからBOOT.bin を作成した。デバイスツリーも作成して、ZYBO Z7-20 に入れてUbuntu 14.04 をブートした。

まずは、camera_module に gabor_filter_lh IP をAdd IP した。
ZYBO_Z7_128_171015.png

全体のブロックデザインを示す。AXI Interconnect のポートが 1 つ増えて 18 になった。
ZYBO_Z7_129_171015.png

アドレス・マップを示す。
ZYBO_Z7_130_171015.png

これで、論理合成、インプリメント、ビットストリームの生成を行った。
結果を示す。
ZYBO_Z7_131_171015.png
ZYBO_Z7_132_171015.png

やはり、DSPが 45 % でかなり使われているが、問題なさそうだ。

ハードウェアをエクスポートし、SDK を立ち上げて、cam_disp3_axis プロジェクトを作成した。
ZYBO_Z7_133_171015.png

cam_disp3_axis.elf を起動するとカメラ画像が表示された。

FSBL プロジェクトを作って、Create Boot Image を起動した。
ZYBO_Z7_134_171015.png

BOOT.bin が生成された。
ZYBO_Z7_135_171015.png

次に、devicetree.dtb を作成しよう。
zynq_zybo_z7.dts を編集した。

/*
 * Device Tree for Zybo Z7 board
 * Partially generated by Device Tree Generator 1.1
 *
 * (C) Copyright 2007-2013 Xilinx, Inc.
 * (C) Copyright 2007-2013 Michal Simek
 * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd
 * (C) Copyright 2014 Digilent, Inc. 
 *
 * Michal SIMEK <monstr@monstr.eu>
 * Tinghui Wang <steven.wang@digilentinc.com> 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */
 /* for ZYBO Z7 by marsee 2017/09/29 */

/dts-v1/;
/ {
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "xlnx,zynq-7000";
    model = "Xilinx Zynq";
    aliases {
        ethernet0 = &ps7_ethernet_0;
        serial0 = &ps7_uart_1;

        spi0 = &ps7_qspi_0;
    } ;
    chosen {
/*        bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; */
        bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1 coherent_pool=16M";
        linux,stdout-path = "/amba@0/serial@e0001000";
    } ;
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        ps7_cortexa9_0: cpu@0 {
            bus-handle = <&ps7_axi_interconnect_0>;
            clock-latency = <1000>;
            clocks = <&clkc 3>;
            compatible = "arm,cortex-a9";
            device_type = "cpu";
            interrupt-handle = <&ps7_scugic_0>;
            operating-points = <666667 1000000 333334 1000000 >;
            /* operating-points = <650000 1000000 >; */
            reg = <0x0>;
        } ;
        ps7_cortexa9_1: cpu@1 {
            bus-handle = <&ps7_axi_interconnect_0>;
            clocks = <&clkc 3>;
            compatible = "arm,cortex-a9";
            device_type = "cpu";
            interrupt-handle = <&ps7_scugic_0>;
            reg = <0x1>;
        } ;
    } ;
    pmu {
        compatible = "arm,cortex-a9-pmu";
        interrupt-parent = <&ps7_scugic_0>;
        interrupts = <0 5 4>, <0 6 4>;
        reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>;
        reg-names = "cpu0", "cpu1";
    } ;
    ps7_ddr_0: memory@0 {
        device_type = "memory";
        reg = <0x0 0x40000000>;
    } ;
    ps7_axi_interconnect_0: amba@0 {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus";
        ranges ;
        ps7_afi_0: ps7-afi@f8008000 {
            compatible = "xlnx,ps7-afi-1.00.a";
            reg = <0xf8008000 0x1000>;
        } ;
        ps7_afi_1: ps7-afi@f8009000 {
            compatible = "xlnx,ps7-afi-1.00.a";
            reg = <0xf8009000 0x1000>;
        } ;
        ps7_afi_2: ps7-afi@f800a000 {
            compatible = "xlnx,ps7-afi-1.00.a";
            reg = <0xf800a000 0x1000>;
        } ;
        ps7_afi_3: ps7-afi@f800b000 {
            compatible = "xlnx,ps7-afi-1.00.a";
            reg = <0xf800b000 0x1000>;
        } ;
        ps7_ddrc_0: ps7-ddrc@f8006000 {
            compatible = "xlnx,zynq-ddrc-1.0";
            reg = <0xf8006000 0x1000>;
            xlnx,has-ecc = <0x0>;
        } ;
        ps7_dev_cfg_0: ps7-dev-cfg@f8007000 {
            clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
            clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>;
            compatible = "xlnx,zynq-devcfg-1.0";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 8 4>;
            reg = <0xf8007000 0x100>;
        } ;
        ps7_dma_s: ps7-dma@f8003000 {
            #dma-cells = <1>;
            #dma-channels = <8>;
            #dma-requests = <4>;
            clock-names = "apb_pclk";
            clocks = <&clkc 27>;
            compatible = "arm,primecell", "arm,pl330";
            interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
                "dma4", "dma5", "dma6", "dma7";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>;
            reg = <0xf8003000 0x1000>;
        } ;
        ps7_ethernet_0: ps7-ethernet@e000b000 {
            #address-cells = <1>;
            #size-cells = <0>;
            clock-names = "ref_clk", "aper_clk";
            clocks = <&clkc 13>, <&clkc 30>;
            compatible = "xlnx,ps7-ethernet-1.00.a";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 22 4>;
            phy-handle = <&phy0>;
            phy-mode = "rgmii-id";
            reg = <0xe000b000 0x1000>;
            xlnx,eth-mode = <0x1>;
            xlnx,has-mdio = <0x1>;
            xlnx,ptp-enet-clock = <108333336>;
            mdio {
                #address-cells = <1>;
                #size-cells = <0>;
                phy0: phy@1 {
                    compatible = "realtek,RTL8211E";
                    device_type = "ethernet-phy";
                    reg = <1>;
                } ;
            } ;
        } ;
        ps7_globaltimer_0: ps7-globaltimer@f8f00200 {
            clocks = <&clkc 4>;
            compatible = "arm,cortex-a9-global-timer";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <1 11 0x301>;
            reg = <0xf8f00200 0x100>;
        } ;
        ps7_gpio_0: ps7-gpio@e000a000 {
            #gpio-cells = <2>;
            clocks = <&clkc 42>;
            compatible = "xlnx,zynq-gpio-1.0";
            emio-gpio-width = <64>;
            gpio-controller ;
            gpio-mask-high = <0xc0000>;
            gpio-mask-low = <0xfe81>;
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 20 4>;
            reg = <0xe000a000 0x1000>;
        } ;
        ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 {
            compatible = "xlnx,ps7-iop-bus-config-1.00.a";
            reg = <0xe0200000 0x1000>;
        } ;
        ps7_ocmc_0: ps7-ocmc@f800c000 {
            compatible = "xlnx,zynq-ocmc-1.0";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 3 4>;
            reg = <0xf800c000 0x1000>;
        } ;
        ps7_pl310_0: ps7-pl310@f8f02000 {
            arm,data-latency = <3 2 2>;
            arm,tag-latency = <2 2 2>;
            cache-level = <2>;
            cache-unified ;
            compatible = "arm,pl310-cache";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 2 4>;
            reg = <0xf8f02000 0x1000>;
        } ;
        ps7_qspi_0: ps7-qspi@e000d000 {
            clock-names = "ref_clk", "pclk";
            clocks = <&clkc 10>, <&clkc 43>;
            compatible = "xlnx,zynq-qspi-1.0";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 19 4>;
            is-dual = <0>;
            num-cs = <1>;
            reg = <0xe000d000 0x1000>;
            xlnx,fb-clk = <0x1>;
            xlnx,qspi-mode = <0x0>;
            #address-cells = <1>;
            #size-cells = <0>;
            flash@0 {
                compatible = "n25q128";
                reg = <0x0>;
                spi-tx-bus-width = <1>;
                spi-rx-bus-width = <4>;
                spi-max-frequency = <33333333>;
                #address-cells = <1>;
                #size-cells = <1>;
                partition@qspi-fsbl-uboot {
                    label = "qspi-fsbl-uboot";
                    reg = <0x0 0x400000>;
                };
                partition@qspi-linux {
                    label = "qspi-linux";
                    reg = <0x400000 0x500000>;
                };
                partition@qspi-device-tree {
                    label = "qspi-device-tree";
                    reg = <0x900000 0x20000>;
                };
                partition@qspi-user {
                    label = "qspi-user";
                    reg = <0x920000 0x6E0000>;
                };
            };

        } ;
        ps7_qspi_linear_0: ps7-qspi-linear@fc000000 {
            clock-names = "ref_clk", "aper_clk";
            clocks = <&clkc 10>, <&clkc 43>;
            compatible = "xlnx,ps7-qspi-linear-1.00.a";
            reg = <0xfc000000 0x1000000>;
        } ;
        ps7_scugic_0: ps7-scugic@f8f01000 {
            #address-cells = <2>;
            #interrupt-cells = <3>;
            #size-cells = <1>;
            compatible = "arm,cortex-a9-gic", "arm,gic";
            interrupt-controller ;
            num_cpus = <2>;
            num_interrupts = <96>;
            reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>;
        } ;
        ps7_scutimer_0: ps7-scutimer@f8f00600 {
            clocks = <&clkc 4>;
            compatible = "arm,cortex-a9-twd-timer";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <1 13 0x301>;
            reg = <0xf8f00600 0x20>;
        } ;
        ps7_scuwdt_0: ps7-scuwdt@f8f00620 {
            clocks = <&clkc 4>;
            compatible = "xlnx,ps7-scuwdt-1.00.a";
            device_type = "watchdog";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <1 14 0x301>;
            reg = <0xf8f00620 0xe0>;
        } ;
        ps7_sd_0: ps7-sdio@e0100000 {
            clock-frequency = <33333333>;
            clock-names = "clk_xin", "clk_ahb";
            clocks = <&clkc 21>, <&clkc 32>;
            compatible = "arasan,sdhci-8.9a";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 24 4>;
            reg = <0xe0100000 0x1000>;
            xlnx,has-cd = <0x1>;
            xlnx,has-power = <0x0>;
            xlnx,has-wp = <0x1>;
        } ;
        ps7_slcr_0: ps7-slcr@f8000000 {
            #address-cells = <1>;
            #size-cells = <1>;
            compatible = "xlnx,zynq-slcr", "syscon";
            ranges ;
            reg = <0xf8000000 0x1000>;
            clkc: clkc@100 {
                #clock-cells = <1>;
                clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x",
                    "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci",
                    "lqspi", "smc", "pcap", "gem0", "gem1",
                    "fclk0", "fclk1", "fclk2", "fclk3", "can0",
                    "can1", "sdio0", "sdio1", "uart0", "uart1",
                    "spi0", "spi1", "dma", "usb0_aper", "usb1_aper",
                    "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper",
                    "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper",
                    "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper",
                    "swdt", "dbg_trc", "dbg_apb";
                compatible = "xlnx,ps7-clkc";
                fclk-enable = <0xf>;
                ps-clk-frequency = <33333333>;
                reg = <0x100 0x100>;
            } ;
        } ;
        ps7_ttc_0: ps7-ttc@f8001000 {
            clocks = <&clkc 6>;
            compatible = "cdns,ttc";
            interrupt-names = "ttc0", "ttc1", "ttc2";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
            reg = <0xf8001000 0x1000>;
        } ;
        ps7_uart_1: serial@e0001000 {
            clock-names = "uart_clk", "pclk";
            clocks = <&clkc 24>, <&clkc 41>;
            compatible = "xlnx,xuartps", "cdns,uart-r1p8";
            current-speed = <115200>;
            device_type = "serial";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 50 4>;
            port-number = <0>;
            reg = <0xe0001000 0x1000>;
            xlnx,has-modem = <0x0>;
        } ;
        ps7_usb_0: ps7-usb@e0002000 {
            clocks = <&clkc 28>;
            compatible = "xlnx,ps7-usb-1.00.a", "xlnx,zynq-usb-1.00.a";
            dr_mode = "host";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 21 4>;
            phy_type = "ulpi";
            reg = <0xe0002000 0x1000>;
            xlnx,usb-reset = "MIO 46";
        } ;
        ps7_xadc: ps7-xadc@f8007100 {
            clocks = <&clkc 12>;
            compatible = "xlnx,zynq-xadc-1.00.a";
            interrupt-parent = <&ps7_scugic_0>;
            interrupts = <0 7 4>;
            reg = <0xf8007100 0x20>;
        } ;
        
        mt9d111_axi_iic@0x41600000 {
            compatible = "generic-uio";
            reg = < 0x41600000 0x10000>;
        };
        dmaw4gabor_0@43cb0000 {
            compatible = "generic-uio";
            reg = < 0x43cb0000 0x10000 >;
        };
        axis_switch_0@0x43c10000 {
            compatible = "generic-uio";
            reg = < 0x43c10000 0x10000 >;
        };
        axis_switch_1@0x43c20000 {
            compatible = "generic-uio";
            reg = < 0x43c20000 0x10000 >;
        };
        lap_filter_axis_0@0x43c30000 {
            compatible = "generic-uio";
            reg = < 0x43c30000 0x10000>;
        };    
        mt9d111_inf_axis_0@0x43C40000 {
            compatible = "generic-uio";
            reg = < 0x43C40000 0x10000>;
        };
        bitmap_disp_cntrler_axi_master_0@0x43c00000 {
            compatible = "generic-uio";
            reg = < 0x43c00000 0x10000>;
        };
        gabor_filter_lh_0@0x43c50000 {
            compatible = "generic-uio";
            reg = < 0x43c50000 0x10000>;
        };
        axi_gpio_0@0x41200000 {
            compatible = "generic-uio";
            reg = < 0x41200000 0x10000>;
        };
        frame_buffer_bmdc@0x17800000 {
            compatible = "generic-uio";
            reg = < 0x17800000 0x1000000>;
        };
        pwm_0@0x43c60000 {
            compatible = "generic-uio";
            reg = < 0x43c60000 0x10000>;
        };
        pwm_1@0x43c70000 {
            compatible = "generic-uio";
            reg = < 0x43c70000 0x10000>;
        };
        motor_monitor_0@0x43c80000 {
            compatible = "generic-uio";
            reg = < 0x43c80000 0x10000>;
        };
        motor_monitor_1@0x43c90000 {
            compatible = "generic-uio";
            reg = < 0x43c90000 0x10000>;
        };
        dmar4resize_gray_0@0x43ca0000 {
            compatible = "generic-uio";
            reg = < 0x43ca0000 0x10000>;
        };
        rgb2hsv_0@0x43cc0000 {
            compatible = "generic-uio";
            reg = < 0x43cc0000 0x10000>;
        };
        ultrasoninc_sensor_inf_0@0x43cd0000 {
            compatible = "generic-uio";
            reg = < 0x43cd0000 0x10000>;
        };
        resize_gray_0@0x43ce0000 {
            compatible = "generic-uio";
            reg = < 0x43ce0000 0x10000>;
        };
        straight_conv_nn2_axis2_0@0x43cf0000 {
            compatible = "generic-uio";
            reg = < 0x43cf0000 0x10000>;
        };
    } ;
} ;


dtc -I dts -O dtb -o devicetree.dtb zynq_zybo_z7.dts
ZYBO_Z7_136_171015.png

devicetree.dtb が生成された。

BOOT.bin と devicetree.dtb をZYBO Z7-20 のMicro SD カードにコピー&ペーストして、ZYBO Z7-20 に入れてブートした。
Ubuntu 14.04 が立ち上がった。
ZYBO_Z7_137_171015.png

/sys/devices/amba.0 を見るとデバイスツリーに記述したIP が入っている。
ZYBO_Z7_138_171015.png

成功だ。。。
  1. 2017年10月15日 07:11 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

白線間走行畳み込みニューラルネットワーク・システムをZYBO Z7-20で動作させる2

白線間走行畳み込みニューラルネットワーク・システムをZYBO Z7-20で動作させる1”の続き。

前回は、カメラ・インタフェースIP のAXI4 Lite Slave インターフェースから接続されているAXI Interconnect のAXI4 Master ポートに空きがあったので、空きを無くしたらカメラ・インタフェースIP が動作することが分かった。しかし、今度はカメラ制御用のI2C インタフェースIP がおかしくなっているようだ。今回はカメラ制御用のI2C インタフェースIP を調査する。

カメラ制御用のI2C インタフェースIP (axi_iic_0)のAXI4 Lite Slave の配線(S_AXI)にDebug を指定した。
ZYBO_Z7_118_171013.png

論理合成、インプリメント、ビットストリームの生成を行った。
ハードウェアをエクスポートし、SDK を立ち上げて、HelloWorld プロジェクトと cam_disp3_axis プロジェクトを作成した。
ビットファイルをダウンロードしてから、HelloWorld プロジェクトを起動した。これでPS のクロックが出たので、Vivado 2017.2 でVivado Analyzer を起動した(Open Hardware Manager を開いてOpen Target をクリックし、Auto Target を選択した)。
axi_iic_0 のAXI4 Lite Slave インターフェースのAWVALID にトリガを掛けた。
cam_disp3_axis プロジェクトを起動しても、トリガがかからなかった。
ZYBO_Z7_117_171013.png

これは、もうAXI Interconnect がおかしいとしか考えられない。ということでAXI Interconnect を交換することにした。
AXI Interconnect を削除する前に各IP のアドレスを確認した。
ZYBO_Z7_119_171013.png

このAXI Interconnect を指定する。
ZYBO_Z7_120_171013.png

AXI Interconnect を削除した。
オートではAXI SmartConnect がインスタンスされるが16個しか接続できないため、1個が接続できない。そこで、AXI Interconnect を自分でAdd IP しておいて、1つのIP だけ手動で配線した。そして、そこからオートで配線したら、AXI Interconnect を使ってくれた。配線後の様子を下の図に示す。といってもあまり変わりはない。
ZYBO_Z7_121_171013.png

その後同様にVivado Analyzer を使用して、axi_iic_0 のAXI4 Lite Slave インタフェースをプローブしたところ、波形が表示された。
ZYBO_Z7_122_171013.png

拡大図。
ZYBO_Z7_123_171013.png

カメラ画像の表示は正常になった。
ZYBO_Z7_127_171014.jpg

良かった。。。これで成功した。。。

Debug 用のsystem_ila が入っているので、それを全部削除した。
ブロックデザイン全体を示す。
ZYBO_Z7_124_171013.png

論理合成、インプリメント、ビットストリームの生成を行った。結果を示す。
ZYBO_Z7_125_171013.png
ZYBO_Z7_126_171013.png

この後、カメラ画像を表示してみたがOKだった。問題ない。

しかし、これだとガボール・フィルタも入るな。。。
  1. 2017年10月14日 04:33 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

白線間走行畳み込みニューラルネットワーク・システムをZYBO Z7-20で動作させる1

前回は、”ビットマップ・ディスプレイ・コントローラIPとカメラ・インタフェースIPのAXI4 Lite Slaveのバグをフィックス”で、ビットマップ・ディスプレイ・コントローラIPとカメラ・インタフェースIPのAXI4 Lite Slave のデータのWrite がアドレスのWrite よりも先に来てしまったときのバグを修正した。
その結果、ビットマップ・ディスプレイ・コントローラIP は動作したが、カメラ・インタフェースIP が動作していなかった。カメラ・インタフェースIP のAXI4 Lite Slave インターフェースから接続されているAXI Interconnect のAXI4 Master ポートに空きがあったので、空きを無くしてカメラ・インタフェースIP が動作するかどうか?を確かめてみることにした。

まずは、ps7_0_axi_periph のM18_AXI を削除して、空いていたM6_AXI ポートに接続した。
ZYBO_Z7_114_171012.png

論理合成、インプリメント、ビットストリームの生成を行った。
ハードウェアをエクスポートし、SDK を立ち上げて、HelloWorld プロジェクトと cam_disp3_axis プロジェクトを作成した。
ビットファイルをダウンロードしてから、HelloWorld プロジェクトを起動した。これでPS のクロックが出たので、Vivado 2017.2 でVivado Analyzer を起動した(Open Hardware Manager を開いてOpen Target をクリックし、Auto Target を選択した)。
カメラ・インタフェースのAXI4 Lite Slave インターフェースのAWVALID にトリガを掛けた。
cam_disp3_axis プロジェクトを起動すると、トリガがかかった。波形を示す。(M14_AXI )
ZYBO_Z7_106_171012.png

M5_AXI との位置関係を示すと、M14_AXI のほうがソフトウェア的に後ろだ。
ZYBO_Z7_107_171012.png

camera_interface の dmaw4gabor_0 のAXI4 Master ポートを見ると、DMA されていた。
ZYBO_Z7_108_171012.png

拡大してみた。
ZYBO_Z7_109_171012.png

次に、カメラ・インタフェースIP のAXI4 Stream 出力を見てみよう。正常に出力されている。下の図の一番下の信号がそうだ。
ZYBO_Z7_110_171012.png

拡大してみた。
ZYBO_Z7_111_171012.png

ビットマップ・ディスプレイ・コントローラIP も動作している。
ZYBO_Z7_112_171012.png

ZYBO_Z7_113_171012.png

これは、やったか?できたかな?
と画像出力を見たら。。。
ZYBO_Z7_116_171012.jpg

この画像はYUV でRGB になっていない画像だ。ということは、I2C がおかしいのかもしれない?
  1. 2017年10月13日 05:20 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラIPとカメラ・インタフェースIPのAXI4 Lite Slaveのバグをフィックス

Zybo Z7-20上の白線間走行CNNシステムのプロジェクトが動作しないバグ”で、ビットマップ・ディスプレイ・コントローラIPとカメラ・インタフェースIPのAXI4 Lite Slave インターフェース回路にバグがあることが分かった。
今回はそのバグをフィックスする。

ビットマップ・ディスプレイ・コントローラIP とカメラ・インタフェースIP はAXI4 バスを作り始めた初期のころに作成したAXI4 Lite Slave インターフェース回路で、まだAXI4 バスのWrite トランザクションでは、アドレスとデータの依存関係はないということが分かっていなかった。よって、Write トランザクションを1つのステートマシンで作成してしまった。アドレス処理するステートマシンとデータの処理をするステートマシンに分ける必要がある。
ビットマップ・ディスプレイ・コントローラIP のAXI4 Lite Slave インターフェース回路 bm_disp_cntrler_axi_lite_slave.v を変更した。下に貼っておく。

// bm_disp_cntrler_axi_lite_slave.v
// bitmap_disp_cntrler_axi_master のAXI Lite Slave モジュール。Frame Buffer のスタートアドレス・レジスタを持つ。
//
// Addr 0x0 - frame buffer start address
//

`default_nettype none

module bm_disp_cntrler_axi_lite_slave # (
    parameter integer C_S_AXI_LITE_ADDR_WIDTH = 9, // Address width of the AXI Lite Interface
    parameter integer C_S_AXI_LITE_DATA_WIDTH = 32, // Data width of the AXI Lite Interface

    parameter [31:0] C_DISPLAY_START_ADDRESS = 32'h1A00_0000
)(
    input    wire                                    s_axi_lite_aclk,
    input    wire                                    axi_resetn,

    // AXI Lite Write Address Channel
    input    wire                                    s_axi_lite_awvalid,
    output    wire                                    s_axi_lite_awready,
    input    wire    [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_awaddr,

    // AXI Lite Write Data Channel
    input    wire                                    s_axi_lite_wvalid,
    output    wire                                    s_axi_lite_wready,
    input    wire    [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_wdata,

    // AXI Lite Write Response Channel
    output    wire    [1:0]                            s_axi_lite_bresp,
    output    wire                                    s_axi_lite_bvalid,
    input    wire                                    s_axi_lite_bready,

    // AXI Lite Read Address Channel
    input    wire                                    s_axi_lite_arvalid,
    output    wire                                    s_axi_lite_arready,
    input    wire    [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_araddr,

    // AXI Lite Read Data Channel
    output    wire                                    s_axi_lite_rvalid,
    input    wire                                    s_axi_lite_rready,
    output    wire    [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_rdata,
    output    wire    [1:0]                            s_axi_lite_rresp,

    output    wire    [31:0]                            fb_start_address,    // Frame Buffer のスタートアドレス
    output    reg                                        init_done            // PS部の初期化終了
);

    // RESP の値の定義
    parameter    RESP_OKAY =        2'b00;
    parameter    RESP_EXOKAY =    2'b01;
    parameter    RESP_SLVERR =     2'b10;
    parameter    RESP_DECERR =    2'b11;

    parameter  IDLE_WRA =           1'b0,
                 ADDR_ASERT =        1'b1;
                 
    parameter  IDLE_WRD =          1'b0,
                 BREADY_ASSERT =    1'b1;

    parameter    IDLE_RD    =        1'b0,            //  for rdt_cs
                AR_DATA_WAIT =    1'b1;

    reg    wrta_cs = IDLE_WRA;
    reg    wrtd_cs = IDLE_WRD;

    reg        [31:0]    fb_start_addr_reg = C_DISPLAY_START_ADDRESS;

    reg        rdt_cs = IDLE_RD;

    reg        reset_1d = 1'b0;
    reg        reset = 1'b0;
    reg        awready = 1'b1;
    reg        bvalid = 1'b0;
    reg        arready = 1'b1;
    reg        rvalid = 1'b0;
    wire    aclk;

    assign aclk = s_axi_lite_aclk;
    // Synchronization of axi_resetn
    always @(posedge aclk) begin
        reset_1d <= ~axi_resetn;
        reset <= reset_1d;
    end

    // AXI4 Lite Slave Write Transaction State Machine
    always @(posedge aclk) begin
        if (reset) begin
            wrta_cs <= IDLE_WRA;
            awready <= 1'b1;
        end else begin
            case (wrta_cs)
                IDLE_WRA :
                    if (s_axi_lite_awvalid) begin
                        wrta_cs <= ADDR_ASERT;
                        awready <= 1'b0;
                    end
                ADDR_ASERT :
                begin
                    wrta_cs <= IDLE_WRA;
                    awready <= 1'b1;
                end
            endcase
        end
    end
                        
    always @(posedge aclk) begin
        if (reset) begin
            wrtd_cs <= IDLE_WRD;
            bvalid <= 1'b0;
        end else begin
            case (wrtd_cs)
                IDLE_WRD :
                    if (s_axi_lite_wvalid) begin    // Write Transaction Start with data
                        wrtd_cs <= BREADY_ASSERT;
                        bvalid <= 1'b1;
                    end
                BREADY_ASSERT :
                    if (s_axi_lite_bready) begin    // The write transaction was terminated.
                        wrtd_cs <= IDLE_WRD;
                        bvalid <= 1'b0;
                    end
            endcase
        end
    end
    assign s_axi_lite_awready = awready;
    assign s_axi_lite_bvalid = bvalid;
    assign s_axi_lite_wready = 1'b1;
    assign s_axi_lite_bresp = RESP_OKAY;

    // AXI4 Lite Slave Read Transaction State Machine
    always @(posedge aclk) begin
        if (reset) begin
            rdt_cs <= IDLE_RD;
            arready <= 1'b1;
            rvalid <= 1'b0;
        end else begin
            case (rdt_cs)
                IDLE_RD :
                    if (s_axi_lite_arvalid) begin
                        rdt_cs <= AR_DATA_WAIT;
                        arready <= 1'b0;
                        rvalid <= 1'b1;
                    end
                AR_DATA_WAIT :
                    if (s_axi_lite_rready) begin
                        rdt_cs <= IDLE_RD;
                        arready <= 1'b1;
                        rvalid <= 1'b0;
                    end
            endcase
        end
    end
    assign s_axi_lite_arready = arready;
    assign s_axi_lite_rvalid = rvalid;
    assign s_axi_lite_rresp = RESP_OKAY;

    // fb_start_addr_reg
    always @(posedge aclk) begin
        if (reset)
            fb_start_addr_reg <= C_DISPLAY_START_ADDRESS;
        else
            if (s_axi_lite_wvalid)
                fb_start_addr_reg <= s_axi_lite_wdata;
    end
    assign fb_start_address = fb_start_addr_reg;
    assign s_axi_lite_rdata = fb_start_addr_reg;

    // generated init_done
    always @(posedge aclk) begin
        if(reset) begin
            init_done <= 1'b0;
        end else if(wrtd_cs==BREADY_ASSERT) begin
            init_done <= 1'b1;
        end
    end
endmodule

`default_nettype wire


これは、ビットマップ・ディスプレイ・コントローラの全アドレス空間に 1 つのレジスタしかない例だが、いささか乱暴な気もするが、面倒なので、これで行こうと思う。もし複数レジスタがある場合には、アドレスが後なので、テンポラリなレジスタに一旦、Write データを入れておいて、アドレスが来た時に指定されたアドレスのレジスタに入れる必要がある。。。それは面倒だ。
カメラ・インタフェースIP も同様に変更した。
論理合成、インプリメント、ビットストリームの生成を行った。
ハードウェアをエクスポートして、SDKを立ち上げた。
そういえば、SDKのハードウェア・プラットフォームを残しておくと、変更が反映されない感じなので、SDK のプロジェクトとハードウェア・プラットフォームは全消去している。
と言う訳で、HelloWorld プロジェクトと cam_disp3_axis プロジェクトは作り直した。

SDK でZYBO Z7 をコンフィギュレーションして、HelloWorld プロジェクトを走らせた。前回も書いたようにPS のクロックが出力されたので、Vivado 2017.2 でVivado Analyzer を起動した(Open Hardware Manager を開いてOpen Target をクリックし、Auto Target を選択した)。ビットマップ・ディスプレイ・コントローラ のAXI4 Lite Slave インタフェースのAWVALID にトリガを仕掛けて、SDK で cam_disp3_axis.elf を起動するとトリガがかかった。
ZYBO_Z7_102_171012.png

今度はビットマップ・ディスプレイ・コントローラIP のAXI4 Master インタフェースにRead トランザクションが発生している。成功の様だ。
ZYBO_Z7_103_171012.png

だが、表示は下の写真のようになった。
ZYBO_Z7_115_171012.jpg

カメラ・インタフェースのAXI4 Lite Slave インターフェース回路の動作を確認する。
AXI4 Lite Slave インターフェース回路のAWVALID にトリガを掛けるが、SDK で cam_disp3_axis.elf を起動してもトリガがかからない。
ZYBO_Z7_104_171012.png

カメラ・インタフェースのAXI4 Lite Slave インターフェース回路のアドレスにWrite しているのだが、AWVALID のトリガかからないとはどうした訳なのか?

もしかして、AXI インターコネクトのポートを空けているところがあるのがまずいのか?
ZYBO_Z7_105_171012.png

M06_AXI が空いているのが分かると思う。ビットマップ・ディスプレイ・コントローラIP はM05_AXI に接続されている。カメラ・インタフェースIP はM14_AXI に接続されている。
  1. 2017年10月12日 05:35 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0

Zybo Z7-20上の白線間走行CNNシステムのプロジェクトが動作しないバグ

Zybo Z7-20上の白線間走行CNNシステムのプロジェクトでUbuntu 14.04 起動”でZybo Z7-20上の白線間走行CNNシステムのVivado 2017.2 プロジェクトを使用してUbuntu 14.04 を起動することができたが、肝心のZybo Z7-20上の白線間走行CNNシステムのVivado 2017.2 プロジェクトがベアメタル・アプリケーションとして動作しない。これはなぜなのか?をVivado Analyzer で確認してみた。

プローブを仕掛けたのは、カメラの入力の cam_data{7:0] (ただし cam_data_1 の1ビットのみとなってしまった。8ビット全部にプローブしたつもりなのだが、これはVivado 2017.2 のバグなのかもしれない?)、href, vsync とビットマップ・ディスプレイ・コントローラのレジスタ設定用AXI4 Lite Slave、カメラ・インタフェースのレジスタ設定用AXI4 Lite Slave、ビットマップ・ディスプレイ・コントローラのAXI4 Master、カメラ・インタフェースのAXI4 Master だ。

なお、特にレジスタ設定用AXI4 Lite Slave を見る場合は、最初だけしかアクセスが来ない。その場合は、FPGA部分をコンフィギュレーションしてもPS からのクロックが来ないのでVivado Analyzer で見ることができない。その対策としては、本命の cam_disp3_axis プロジェクトのほかにHelloWorld プロジェクトを作っておいて、HelloWorld を起動してPS のクロックを起動してから、Vivado Analyzer のトリガを仕掛けて、そして本命の cam_disp3_axis を起動すれば良い。
ZYBO_Z7_97_171011.png

Vivado Analyzer を起動し、トリガを掛けて、表示されたところを示す。
ZYBO_Z7_95_171011.png

波形のみを示す。
ZYBO_Z7_96_171011.png

む。。。これは。。。WVALID のアサートが AWVALID よりも前に来ている。AXI プロトコル的にはこれであっているが、自作のAXI4 Lite Slave インタフェースはどうだったか?
下の図のAXI4 Lite Slave Write Transaction State Machine を見ると、Write が 1 つのステートマシンになってしまっている。これではだめだ。。。orz
WVALID がAWVALID の前ではバグってしまう。。。
ZYBO_Z7_101_171011.png

少なくともアドレスを処理するステートマシンとデータを処理するステートマシンに分ける必要がある。
ちなみにRead はシーケンシャルに処理すれば良いので、ステートマシンは 1 つでよい。
しかしなぜ、ZYBO Z7 からこうなったのだろう?ZYBO でもPYNQ でもビットマップ・ディスプレイ・コントローラもカメラ・インタフェースも動作していたので、WVALID はAWVALID の後だったはずだ。ZYBO Z7 からPS のリビジョンが変わっていたりして?

カメラ・インタフェースの入力の波形を示す。いずれもちゃんと出ていた。
cam_data_1
ZYBO_Z7_98_171011.png

href
ZYBO_Z7_99_171011.png

vsync
ZYBO_Z7_100_171011.png
  1. 2017年10月11日 05:10 |
  2. ZYBO Z7
  3. | トラックバック:0
  4. | コメント:0
»