FC2カウンター FPGAの部屋 2015年01月31日
FC2ブログ

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

FPGAの部屋

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

ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れる3(Ubuntu Trusty 14.04 LTS)

ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れる2( Debian Wheezy 7.5)”の続き。

今回、もう一度、 Ubuntu Trusty 14.04 LTS のRoot File Systems を MicroSDカードの2nd パーティションにコピーして、1st パーティションは、Digilent Linux Kernel, BOOT.bin, devicetree.dtb をコピーした。
パソコンのVirtualBox上にインストールしたUbuntu 14.04 LTS で MicroSDカードにコピーをしたのだが、その際に ROOT_FS の /usr/bin/sudo に 4755 のパーティションを与えた。
sudo chmod 4755 /media/masaaki/ROOT_FS/usr/bin/sudo

MicroSDカードのマウントを外して、ZYBO に挿入して電源をONした。
すると、やはり、”* Starting OpenSSH server”まで進んだが、ここで停止してしまった。
ZYBO_ARMhf_11_150125.png

Debian と違って、所得したIPアドレスがわからない。適当に割り当てられていそうなIPアドレスを指定したら当たっていてログインできた。(ログイン名は ubuntu 、パスワードも ubuntu だった)
DHCPで割り当てられたIPアドレスがわからないと困る。そこで、/etc/rc.local に ifconfig コマンドを書くことにした。
sudo vi /etc/rc.local
ZYBO_ARMhf_26_150131.png

リブートする前に、ubuntu ユーザーのディレクトリのパーミッションを変更した。
cd /home
sudo chown -R -f ubuntu:ubuntu ubuntu


ここで、 sudo reboot コマンドで、リブートした。

起動すると、rc.local に書いた ifconfig コマンドが起動して、割り振られたIPアドレスが見えた。
ZYBO_ARMhf_27_150131.png

やった~。これでIPアドレスが分からないという問題が解消した。

次に、date コマンドを実行したら、例によって UTC だったので、
sudo ln -sf /usr/share/zoneinfo/Japan /etc/localtime で、タイムゾーンを JST に変更した。
ZYBO_ARMhf_25_150131.png

sudo apt-get install gedit で gedit をインストールした。相当時間がかかった。

sudo apt-get install nautilus で、Ubuntu のファイルマネージャーをインストールした。
nautilus & コマンドで起動した。
ZYBO_ARMhf_28_150131.png

一旦、sudo reboot して、SSHでログインして、top コマンドで使用メモリを確認したところ、59KB 程度だった。案外、メモリを消費していない。
ZYBO_ARMhf_29_150131.png

df をすると、MicroSDカードの容量の 13% を消費しているのが分かった。
ZYBO_ARMhf_30_150131.png
  1. 2015年01月31日 21:03 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:2

ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れる2( Debian Wheezy 7.5)

ZYBOのDigilent Linux Kernel にARMhfのRoot File Systemsを入れる”で、ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れてみたが、Ubuntu14.04 LTSのRoot File Systems も Debian Wheezy 7.5のRoot File Systems も立ち上がらないと思った。

今回、もう一度、 Debian Wheezy 7.5 のRoot File Systems を MicroSDカードの2nd パーティションに入れて、1st パーティションは、Digilent Linux Kernel, BOOT.bin, devicetree.dtb を入れた。
ブートしてみると、シリアルポート接続のTrea Termは、sshd でやはり止まった。
ZYBO_ARMhf_12_150131.png

しかし、DHCPで IP は取れている。現在は192.168.3.2 だ。

このIP を使用して、Tera Term で SSH 接続した。
ZYBO_ARMhf_13_150131.png

IDは debian パスワードも debian でログインできた。
ZYBO_ARMhf_14_150131.png

df コマンドを実行すると、5% ほど使用している。
ZYBO_ARMhf_15_150131.png

top コマンドを実行すると、52 KB ほどメモリを使用している。Linaro Ubuntu の 1/3 程度だが、デーモン(って今言わないのかな?)が動いていないせいもあるはず。。。
ZYBO_ARMhf_16_150131.png

sudo コマンドはエラーで実行できない。
ZYBO_ARMhf_17_150131.png

root でログインしようとしてもログインできない。”Ubuntu 12.04 LTS armhf preinstalled root password”によると、root のログインはデフォルトで禁止されているそうだ。確かに、/etc/shadow の最初の1行に

”root:*:15835:0:99999:7:::”

と書いてあった。
2.3 シャドウファイル /etc/shadow の構造”によると、第2フィールドが * だとログイン出来ないそうだ。* を消せばよいのだが、これはそのままにして、sudo コマンドを動作させるには、 chmod 4755 /usr/bin/sudo を実行すればよいのだが、これは root 権限で実装するしか無い。
そこで、パソコンのUbuntu 14.04 LTS で MicroSDカードをマウントして、そこで chmod コマンドを実行した。
ZYBO_ARMhf_18_150131.png

もう一度、MicroSDカードをZYBOに入れて、電源をONした。

SSHでログインして、sudo apt-get update を実行したら動作した。因みに、これは2度目で1度目は debian のパスワード (debian) を入力した。
ZYBO_ARMhf_19_150131.png

date コマンドを実行したら、時刻はあっているようだったが、タイムゾーンがUTC だった。
ln -sf /usr/share/zoneinfo/Japan /etc/localtime で、タイムゾーンを JST に変更した。
ZYBO_ARMhf_20_150131.png

sudo apt-get upgrade で既存のモジュールをアップデートした。

sudo apt-get insall gedit で gedit をインストールして、gedit を立ちあげたが、Xが立ち上がらなかった。

原因は、/home/debian のオーナーとグループが root だったことだ。
cd /home
sudo chown -R -f debian:debian debian

で、オーナーとグループが debian になった。
ZYBO_ARMhf_21_150131.png

logout して、もう一度、SSHで debian ユーザーでログインすると、.Xauthority が作られていた。
ZYBO_ARMhf_22_150131.png

gedit コマンドで、gedit を起動すると、今度は起動した。
ZYBO_ARMhf_23_150131.png

top コマンドを起動すると、77 KB 位だった。やはり、少し増えている。
ZYBO_ARMhf_24_150131.png

ZYBOで Debian Wheezy 7.5 も使うことができるようになった。
  1. 2015年01月31日 11:38 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする2

Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする1”の続き。

前回はC Synthesis アイコンで高位合成を行った。今回は、Export RTL アイコンで IP 化を行う。

Vivado HLS 2014.4 の Export RTL アイコンをクリックして、IP 化を行う。
Vivado_HLS_lap_filter_4_150130.jpg

Export RTL Dialog が出るので、Configurtarion... ボタンをクリックする。
Vivado_HLS_lap_filter_5_150130.jpg

Vendor を marsee に、Display Name を lap_filter_axim_hls に設定した。OKボタンをクリックした。
Vivado_HLS_lap_filter_6_150130.jpg

Export RTL Dialog に戻り、OKボタンをクリックした。
これで IP 化が終了した。
Vivado_HLS_lap_filter_7_150131.jpg

drivers フォルダ下の xlap_filter_axim_hw.h の内容を見てみると、cam_addr と lap_addr に制御信号が追加されていた。

// 0x1c : Control signal of cam_addr
//        bit 0  - cam_addr_ap_vld (Read/Write/COH)
//        bit 1  - cam_addr_ap_ack (Read)
//        others - reserved
// 0x24 : Control signal of lap_addr
//        bit 0  - lap_addr_ap_vld (Read/Write/SC)
//        others - reserved


下に xlap_filter_axim_hw.h 行のコメント行の全部を示す。

// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ==============================================================

// BUS_AXI4LS
// 0x00 : Control signals
//        bit 0  - ap_start (Read/Write/COH)
//        bit 1  - ap_done (Read/COR)
//        bit 2  - ap_idle (Read)
//        bit 3  - ap_ready (Read)
//        bit 7  - auto_restart (Read/Write)
//        others - reserved
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x10 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// 0x18 : Data signal of cam_addr
//        bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x1c : Control signal of cam_addr
//        bit 0  - cam_addr_ap_vld (Read/Write/COH)
//        bit 1  - cam_addr_ap_ack (Read)
//        others - reserved
// 0x20 : Data signal of lap_addr
//        bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x24 : Control signal of lap_addr
//        bit 0  - lap_addr_ap_vld (Read/Write/SC)
//        others - reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


次に、Vivado HLS 2014.1 で drivers フォルダ下の xlap_filter_axim_hw.h のコメント行のすべてを下に示す。

// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.1
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ==============================================================

// LiteS
// 0x00 : Control signals
//        bit 0  - ap_start (Read/Write/COH)
//        bit 1  - ap_done (Read/COR)
//        bit 2  - ap_idle (Read)
//        bit 3  - ap_ready (Read)
//        bit 7  - auto_restart (Read/Write)
//        others - reserved
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x10 : reserved
// 0x14 : Data signal of cam_addr
//        bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x18 : reserved
// 0x1c : Data signal of lap_addr
//        bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x20 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


同じCソース(pragmaは書き換えてあるが)なのに、違っている。考えてみれば、cam_addr には ap_hs インターフェース、lap_addr には、ap_vld インターフェースが割り当ててあるので、今回のほうが当然の結果である気がする。

cam_addr と lap_addr は、カメラのフレームバッファのベース・アドレスとラプラシアンフィルタのベース・アドレスを設定すれば良いので、1回設定したら当分変えることはない。つまりWrite したままで良く、制御信号はあまり必要無い。
よって、この2つのポートを ap_none インターフェースで定義することにした。

#pragma HLS INTERFACE ap_none port=cam_addr
#pragma HLS INTERFACE ap_none port=lap_addr

Vivado_HLS_lap_filter_8_150131.jpg

もう一度、 C Synthesis アイコンで高位合成を行ってから、Export RTL アイコンをクリックして、IP 化を行った。

// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ==============================================================

// BUS_AXI4LS
// 0x00 : Control signals
//        bit 0  - ap_start (Read/Write/COH)
//        bit 1  - ap_done (Read/COR)
//        bit 2  - ap_idle (Read)
//        bit 3  - ap_ready (Read)
//        bit 7  - auto_restart (Read/Write)
//        others - reserved
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x10 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// 0x18 : Data signal of cam_addr
//        bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of lap_addr
//        bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x24 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


最後に、laplacian_fillter.c を全文貼っておく。(注:下に示すラプラシアンフィルタのCソースコードはバグありコードで、使用できない)

(追記) Vivado HLS で合成したラプラシアンフィルタのバグの原因は、古いバグありラプラシアンフィルタのCソースコードを使用したためでした。正しいラプラシアンフィルタのCソースコードについては、”Vivado HLS 2014.4で生成したラプラシアンフィルタIPをシミュレーション3(原因が分かった)”をご覧ください。

// laplacian_filter.c
// lap_filter_axim()

#include <stdio.h>
#include <string.h>

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600
#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);

int lap_filter_axim(int *cam_addr, int *lap_addr, volatile int *cam_fb, volatile int *lap_fb)
{
    #pragma HLS INTERFACE s_axilite port=cam_addr bundle=BUS_AXI4LS
    #pragma HLS INTERFACE s_axilite port=lap_addr bundle=BUS_AXI4LS
    #pragma HLS INTERFACE s_axilite port=return bundle=BUS_AXI4LS
    #pragma HLS INTERFACE ap_none port=cam_addr
    #pragma HLS INTERFACE ap_none port=lap_addr
    
    #pragma HLS INTERFACE m_axi port=cam_fb depth=480000
    #pragma HLS INTERFACE m_axi port=lap_fb depth=480000

    unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
    unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
    int x, y;
    int lap_fil_val;
    int a, b;
    int fl, sl, tl;
    unsigned int offset;
    
    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
                lap_fil_val = 0;
            }else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
                lap_fil_val = 0;
            }else{
                if (x == 1){ // ラインの最初でラインの画素を読み出す
                    if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
                        for (a=0; a<3; a++){ // 3ライン分
                            offset = *cam_addr/sizeof(int);
                            memcpy(line_buf[a], (const int*)(cam_fb+offset+(a*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                            for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
                                line_buf[a][b] = conv_rgb2y(line_buf[a][b]);    // カラーから白黒へ
                            }
                        }
                    }
                } else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
                    offset = *cam_addr/sizeof(int);
                    memcpy(line_buf[(y+1)%3], (const int*)(cam_fb+offset+((y+1)*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                    for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
                        line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]);    // カラーから白黒へ
                    }
                }
                fl = (y-1)%3;    // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
                sl = y%3;        // 2番めのライン
                tl = (y+1)%3;    // 3番目のライン
                lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
            }
            lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
        }
        offset = *lap_addr/sizeof(int);
        memcpy((int *)(lap_fb+offset+(y*HORIZONTAL_PIXEL_WIDTH)), (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
    }
    return(1);
}

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    return(y);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}

  1. 2015年01月31日 05:09 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0