昨日、スイッチサイエンスに頼んでいた
Raspberry Pi Zero がやっときました。忘れたころに届きましたが、製造元から届かなかったようです。
Raspberry Pi Zero の写真です。左端のアクリル板のRaspberry Pi Zero用ケースは、
アマゾンで購入 しました。
Raspberry Pi Zero を拡大してみます。
小さいです。
裏の写真です。
648円なので、夏休みの自由研究の題材に良さそうです。Scratch で初めてのプログラミングとか良さそうです。
試してみたいと思います。自由に買えるようになると良いのですが。。。
2017年03月31日 05:06 |
マイコン関連
| トラックバック:0
| コメント:0
”
”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる3(PYNQでテスト) ”の続き。
前回は、Micro SDカードのパーティションに必要なファイルをコピーして、PYNQに挿入してDebian をブートした。そして、Linux ヘッダ/イメージパッケージとデバイスドライバ パッケージのインストールを行った。今回は、そのPYNQのDebian 環境を整備しよう。
パッケージのアップデートからやってみる。
df して、Micro SDカードの使用率を見てみよう。
6% なので、ほとんど使っていない。
パッケージリストの更新を行う。
sudo apt-get update インストールされているパッケージの更新を行う。
sudo apt-get upgrade ifconfig コマンドは無いと言われてしまった。ネットで検索すると
ip addr show に変更になったようだ。
Tera Term をもう1つ起動して、調べた IP アドレスで入れた。
date を実行したが、JST になっていた。
次に、Ubuntu のファイル表示GUI の nautilus をインストールした。
sudo apt-get install nautilus nautilus & で起動したが、 cannot open display で起動しなかった。なお、パソコンには、Xming がインストールしてあるので、X画面を持ってこられる。
nautilus が起動しなかった件では、いろいろとツィッターで検討していただいてありがとうございました。おかげさまで、動作することができました。
もう一度、nautilus をインストールした。いろいろとやっていたので、パッケージが全部あるかどうか不安だったからだ。
次に、ikwzm さんに教えて頂いた xbase-clients と xterm をインストールした。
sudo apt-get install xbase-clients xterm nautilus & で起動した。
Opps が出てしまったが、nautilus が起動できた。
最後に geany をインストールした。
sudo apt-get install geany geany & で起動した。
geany が起動できた。
2017年03月29日 05:29 |
PYNQ
| トラックバック:0
| コメント:0
”
”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる2(Micro SDカードの準備) ”の続き。
前回は、Micro SDカードの準備を行った。今回は、そのMicro SDカードにファイルを書き込んで、PYNQに挿入してテストしてみよう。
Micro SDカードは、/media/masaaki の下に、PYNQ_BOO とROOT_FS がマウントされている。
FPGA-SoC-Linux/target/zynq-pynqz1/boot ディレクトリのすべてのファイルをPYNQ_BOO に書き込んだ。
cp target/zynq-pynqz1/boot/* /media/masaaki/PYNQ_BOO/ PYNQ_BOO のファイルを示す。
debian8-rootfs-vanilla.tgz を解凍して、/media/masaaki/ROOT_FS に書き込む。
sudo tar xfz debian8-rootfs-vanilla.tgz -C /media/masaaki/ROOT_FS/ sudo が必要だった。
ROOT_FS のファイルを示す。
FPGA-SoC-Linux の下の
fpga-soc-linux-drivers-4.8.17-armv7-fpga_0.0.3-1_armhf.deb linux-headers-4.8.17-armv7-fpga_4.8.17-armv7-fpga-1_armhf.deb linux-image-4.8.17-armv7-fpga_4.8.17-armv7-fpga-1_armhf.deb
をROOT_FS の下のhome/fpga ディレクトリにコピー&ペーストした。
ROOT_FS/home/fpgaを示す。
これで、Micro SDカードで行う作業は終了したので、上の図で「取り出し」ボタンをクリックした。
最後に、VirtualBox のデバイスメニューからUSB -> USB カード・リーダ・ライタを選択して、外した。
さて、いよいよ出来上がったMicro SDカードをPYNQ ボードに入れて電源をON してみよう。
PYNQ の電源をON したら、Linuxは起動したのだが、ボードのDONE LED が消えたままだった。これにはびっくり。そうかビットストリームがBOOT.bin に入ってなかったのね。。。
fpga ユーザーでログインしてみた。
ls で確認すると、コピーしておいた3つのファイルが見えた。
次に、Linux ヘッダ/イメージパッケージをインストールしよう。
sudo dpkg -i linux-image-4.8.17-armv7-fpga_4.8.17-armv7-fpga-1_armhf.deb sudo dpkg -i linux-headers-4.8.17-armv7-fpga_4.8.17-armv7-fpga-1_armhf.deb デバイスドライバ パッケージのインストールを行った。
sudo dpkg -i fpga-soc-linux-drivers-4.8.17-armv7-fpga_0.0.3-1_armhf.deb デバイスドライバパッケージがインストールされたかチェックしてみよう。
sudo lsmod sudo systemctl status device-tree-overlay.service sudo systemctl status fpga-manager.service sudo systemctl status udmabuf.service sudo systemctl status zptty.service
2017年03月28日 05:22 |
PYNQ
| トラックバック:0
| コメント:0
”
”FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応)”を試してみる1(FPGA-SoC-Linux のクローン) ”の続き。
前回は、FPGA-SoC-Linux をクローンした。今回は、Micro SDカードをフォーマットして、パーティションを切った。
最初に、
SDカードフォーマッター でMicro SDカードをフォーマットする。このMicro SDカードはPYNQ用のイメージを書いてあるので、上書きフォーマットで論理サイズ調整 ON でフォーマットする。
SDFormatter V4.0 を起動して、オプション設定ボタンをクリックする。
フォーマットオプション設定で、上書きフォーマットと論理サイズ調整 ON を指定してOKボタンをクリックする。
フォーマットボタンをクリックし、Micro SDカードのフォーマットを行う。
確認ダイアログが出るので、OKボタンをクリックした。
しばらくの間、フォーマットしていたが、フォーマットが終了した。
次にMicro SDカードにパーティションを作っていこう。
”
ZedBoard用のUbuntu Linuxをビルド6(SDカードを用意する) ”を参考にした。
なお、
FPGAマガジン No.5 の第3章”Zynq評価ボードZedBoardでLinuxを動かそう”という石原 ひでみさんの記事の中の48ページの”図17 SDカードのパーティション操作手順”を参考にさせて頂いています。
私の環境はWindows 10 でVirtualBoxを使用して、Ubuntu 16.04 をインストールしてある。
Micro SDカードは、秋月電子で購入した”
TOSHIBA マイクロSDカード(microSDHC)EXCERIA 16GB 48MB/s ”を使用している。このMicro SDカードは古いカード・リーダー・ライタでは認識できなかった。
Windows 10 のパソコンに挿入した Micro SDカードをVirtualBox 上のUbuntu にマウントするためにVirtualBox のデバイスメニュー -> USB -> USBリーダーの名前(Micro SDカードが装着してある)を選択した。
/media/masaaki/1BC2-1630 としてマウントされた。
lsblk コマンドを実行して、SDカードを検索した。
/dev/sdb がSDカードのようだ。
sudo umount /dev/sdb1 で sdb1 をアンマウントしておく。こうしないと後で
w コマンドで書き込むときにエラーになってしまう。
sudo fdisk /dev/sdb コマンドを実行してSDカードのフォーマットを開始した。
p コマンドで既存のパーティションを表示した。FAT32パーティションが生成されていた。
d コマンドでパーティションを削除した。
p コマンドで見ると、パーティションが消去されていた。
プライマリ・ディスクのパーティション番号1に100 MBの領域を確保する n コマンドで新たにパーティションを作製した。
p を押して、primary パーティションを指定した。
パーティション番号を
1 にセット。
First sector で、
リターンキー を入力した。
Last sector で、
+100M を入力して、100 MB の領域を確保した。
p コマンドででパーティションを表示した。
プライマリ・ディスクのパーティション番号2に残っている領域(14.3 GB)を確保する n コマンドで新たにパーティションを作製した。
p を押して、primary パーティションを指定した。
パーティション番号を
2 にセット。
First sector で、
リターンキー を入力した。
Last sector で、
リターンキー を入力した。
p コマンドででパーティションを表示した。
プライマリ・ディスクのパーティション番号1をFAT32にして、ブート可能フラグを付ける t コマンドを入力した。
パーティション番号に
1 を入力した。
16進コードに、
b を入力した。(W95 FAT32)
a コマンドを入力して、ブート可能フラグを付ける。
パーティション番号に
1 を入力した。
p コマンドででパーティションを表示した。
SDカードへの書き込み w コマンドを実行して、今まで設定してきたパーティション情報をMicro SDカードにWrite した。
lsblk を行うと、設定したパーティションが sdb1, sdb2 として見えている。
FPGAマガジン No.5 の第3章”Zynq評価ボードZedBoardでLinuxを動かそう”という石原 ひでみさんの記事を参考に、/dev/sdb1 に対して、
sudo mkfs.msdos -n PYNQ_BOO /dev/sdb1
を実行した。(PYNQ_BOOT としたかったが、PYNQ_BOO とタイポしてしまった)
PYNQ_BOO がマウントされた。
同様に、/dev/sdb2 に対して、
sudo mkfs.ext3 -L ROOT_FS /dev/sdb2
を実行した。(ファイルシステムは ext3 指定だった)
Writing superblocks and filesystem accounting infomation: で
リターン を入力した。
コマンドが終了した。
ROOT_FS がマウントされた。
これで、Micro SDカードの用意は終了した。
2017年03月27日 04:50 |
Linux
| トラックバック:0
| コメント:0
Vivado WebPACK 2016.1 からWebPACK では、ライセンスファイルは必要無くなりました。
ダウンロード時に登録は必要ですが、Vivado WebPACK 2016.1~は、インストールすればライセンスファイルを取得しなくても起動して普通に使えます。今のVivado WebPACK 2016.4 でも同様にラインセンスファイルは必要ありません。
詳しくは、”
Vivado Design Suite ユーザー ガイド リリース ノート 、 インストールおよびライセンス UG973 (v2016.4) 2016 年 11 月 30 日 ”の 80 ページ ”Vivado WebPACK をライセンス ファイルなしで使用可能”をご覧ください。
2017年03月26日 21:57 |
Vivado
| トラックバック:0
| コメント:0
ikwzm さんの”
FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応) ”を試してみようと思う。
Device Tree Overlay+FPGA Managerが使用できれば、SDSoC でビットストリームとアプリケーションソフトが作れれば、すでに動作しているLinux 上でリブートすること無しにいくらでも試すことができる。”
FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応) ”もこのままの状態で起動したら、Device Tree Overlay+FPGA Managerでハードウェアとそのデバイスツリーを使ってFPGA を使うことができるはずだ。つまりLinux は動作しながら、FPGAでアクセラレーションできるわけだ。という理由でやってみることにした。
参考資料
”FPGA+SoC+LinuxでDevice Tree Overlayを試してみた ””FPGA+SoC+LinuxでFPGA Managerを試してみた ”
まずは、”
FPGA+SoC+Linux+Device Tree Overlay+FPGA Manager(PYNQ-Z1対応) ”で指定されているように、Git LFS(Large File Storage)を自分のVirtualBox 上のUbuntu 16.04 に追加します。
sudo apt-get install git-lfs git-lfs が無いと言われてしまう。
GitHub のgit-lfs/git-lfs の Installation を見るとUbuntu での git-lfs のインストール方法が書いてあった。その手順に従ってUbuntu 16.04 上で git-lfs のインストールを行う。
sudo apt-get install python-software-properties Yをクリックしてインストールを進めると、python-software-properties がインストールできた。
sudo add-apt-repository ppa:git-core/ppa ppa をインストールすることができた。
この後で、
sudo apt-get update をするように書いてあるが、忘れてしまった。最後に
sudo apt-get update と
sudo apt-get upgrade を実行しておいたが、これで良いかどうか?よくわからない?
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash sudo apt-get install git-lfs git lfs install これで git lfs がインストールできた。
さて、ikwzm さんのFPGA-SoC-Linux をクローンする。
git clone git://github.com/ikwzm/FPGA-SoC-Linux cd FPGA-SoC-Linux ls FPGA-SoC-Linux ディレクトリの下には12個のファイルまたはディレクトリがあった。
git checkout v0.3.0 git lfs pull FPGA-SoC-Linux ディレクトリの下のファイルまたはディレクトリが 9 個に減った。
FPGA-SoC-Linux/target/zynq-pynqz1/boot ディレクトリのファイルを示す。
boot.bin や u-boot, デバイスツリーの dts と dtb, uEnv.txt, zImage などが入っていた。
2017年03月26日 06:01 |
Linux
| トラックバック:0
| コメント:0
Linux 上のISE のSDK からデバイスツリーのソース(DTS)を生成する方法は
”SDKでDevice Treeを生成する2(SDKでxilinx.dtsを生成) ”に書いた。今回は、Windows 10 上で、Vivado 2016.4 のSDKでデバイスツリーのソース(DTS)を生成してみよう。
自分のブログを参考しても良いのだが、ISE のSDK なので、”
blog 渓鉄 ”さんの”
Xilinx SDKでDevice Treeを生成する ”を参考にさせて頂きます。
SDK は、”
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム ”のSDK をそのまま使用する。
最初に、ブラウザで”
Xilinx/device-tree-xlnx ”を開く。
Clone of download ボタンをクリックして、Download ZIP ボタンをクリックする。
device-tree-xlnx-master.zip ファイルがダウンロードできるので、適当なフォルダを選択し、保存ボタンをクリックしてセーブする。
device-tree-xlnx-master.zip ファイルをダブルクリックすると、圧縮ファイル上のフォルダが見えるので、そのdevice-tree-xlnx-master フォルダを適当なフォルダにドラック&ドロップする。
SDK 2016.4 で、Xilinx Tools -> Repositories を選択する。
開いたダイアログのLocal Repositories で、New... ボタンをクリックする。
先ほどダウンロードして解凍したdevice-tree-xlnx-master フォルダを選択する。
Local Repositories にdevice-tree-xlnx-master フォルダのパスが入った。
OK ボタンをクリックするとSDK に戻った。
File メニューからNew -> Board Support Package を選択した。
Xilinx Board Support Package Project ダイアログが表示された。
Board Support Package OS にdevice_tree が増えているので、それを選択した。Finish ボタンをクリックした。
Board Support Package Settings が開いた。
最初はOverview 画面だ。
device_tree をクリックした。
DTS ファイルは分割されるようだ。
drivers をクリックした。
SDK に戻ると、device_tree_bsp_0 ができていて、下に示すファイルができていた。
pcw.dtsi pl.dtsi skeleton.dtsi system-top.dts system.dts zynq-7000.dts
2017年03月26日 04:38 |
Vivado
| トラックバック:0
| コメント:0
”
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム5(ILAコアの削除) ”の続き。
前回は、Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システムから 2 つの ILA コアを削除した。今回は、アプリケーションソフトを整備した後で、15 fps のカメラのフレームレートを 30 fps に変更する。
まずは、DMA_Read_addr IP の動作モードのDMA_WRITE_MODE はDMA_Write IP の書き込んでいる画像フレームの1つ前の画像フレームからDMA Read しているモードでこれは正常に動作している。問題は、FREE_RUM_MODE で、これは、3 つの画像フレームからフリーランで読んでるモードなのだが、15 fps でカメラがWrite していて、60 fps でビットマップ・ディスプレイ・コントローラがRead するので、画像フレームバッファが 3 つあると現在、過去が入り混じって画像がぶれてしまう。よって、FREE_RUM_MODE の場合は、画像フレームを 1 つにする必要があるようだ。そのように変更したところ、画像がぶれることは無くなった。
cam_disp_hls.c を貼っておく。
#include <stdio.h> #include <stdlib.h> #include "xil_io.h" #include "xdma_read_addr.h" #include "xdma_write.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 #define DMA_WRITE_MODE void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) { mt9d111_i2c_axi_lites[64 ] = 0x2 ; mt9d111_i2c_axi_lites[64 ] = 0x1 ; }void cam_i2x_write_sync(void ) { 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 & 0xf e); mt9d111_i2c_axi_lites[66 ] = write_addr; mt9d111_i2c_axi_lites[66 ] = (write_data >> 8 )|0xf f; mt9d111_i2c_axi_lites[66 ] = 0x200 | (write_data & 0xf f); cam_i2x_write_sync(); }int main(){ XDma_read_addr dmar, *dmarp; XDma_write dmaw, *dmawp; dmarp = &dmar; dmawp = &dmaw; if (XDma_read_addr_Initialize(dmarp, 0 ) != XST_SUCCESS){ fprintf(stderr,"DMA Read open error\n" ); exit(-1 ); } if (XDma_write_Initialize(dmawp, 0 ) != XST_SUCCESS){ fprintf(stderr,"DMA Write open error\n" ); exit(-1 ); } #ifdef DMA_WRITE_MODE XDma_read_addr_Set_frame_buffer0(&dmar, FRAME_BUFFER_ADDRESS); XDma_read_addr_Set_frame_buffer1(&dmar, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES); XDma_read_addr_Set_frame_buffer2(&dmar, FRAME_BUFFER_ADDRESS+2 *HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES); XDma_write_Set_frame_buffer0(&dmaw, FRAME_BUFFER_ADDRESS); XDma_write_Set_frame_buffer1(&dmaw, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES); XDma_write_Set_frame_buffer2(&dmaw, FRAME_BUFFER_ADDRESS+2 *HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);#else // FREE_RUN_MODE XDma_read_addr_Set_frame_buffer0(&dmar, FRAME_BUFFER_ADDRESS); XDma_read_addr_Set_frame_buffer1(&dmar, FRAME_BUFFER_ADDRESS); XDma_read_addr_Set_frame_buffer2(&dmar, FRAME_BUFFER_ADDRESS); XDma_write_Set_frame_buffer0(&dmaw, FRAME_BUFFER_ADDRESS); XDma_write_Set_frame_buffer1(&dmaw, FRAME_BUFFER_ADDRESS); XDma_write_Set_frame_buffer2(&dmaw, FRAME_BUFFER_ADDRESS);#endif #ifdef DMA_WRITE_MODE XDma_read_addr_Set_mode_V(&dmar, 0 ); #else // FREE_RUN_MODE XDma_read_addr_Set_mode_V(&dmar, 1 ); #endif volatile unsigned int *mt9d111_axiL; volatile unsigned int *cam_iic_axiL; volatile unsigned int *bmdc_axiL; mt9d111_axiL = (volatile unsigned int *)XPAR_MT9D111_INF_AXIS_0_BASEADDR; cam_iic_axiL = (volatile unsigned int *)XPAR_AXI_IIC_0_BASEADDR; bmdc_axiL = (volatile unsigned int *)XPAR_BITMAP_DISP_CONT_AXIS_0_BASEADDR; bmdc_axiL[0 ] = (volatile unsigned int )FRAME_BUFFER_ADDRESS; XDma_read_addr_DisableAutoRestart(&dmar); while (!XDma_read_addr_IsIdle(&dmar)) ; XDma_read_addr_Start(&dmar); XDma_read_addr_EnableAutoRestart(&dmar); XDma_write_DisableAutoRestart(&dmaw); while (!XDma_write_IsIdle(&dmaw)) ; XDma_write_Start(&dmaw); XDma_write_EnableAutoRestart(&dmaw); mt9d111_axiL[0 ] = (volatile unsigned int )FRAME_BUFFER_ADDRESS; cam_i2c_init(cam_iic_axiL); cam_i2c_write(cam_iic_axiL, 0x ba, 0xf0 , 0x1 ); cam_i2c_write(cam_iic_axiL, 0x ba, 0x97 , 0x20 ); mt9d111_axiL[1 ] = 0 ; return (0 ); }
これで、FREE_RUM_MODE も問題が無くなったので、次は、カメラのフレームレートを 15 fps から 30 fps に向上させることにした。
やり方は、
”MT9D111のフレームレートを 15 fps から 30 fps にした ”に書いておいた。
早い話が、カメラに供給するクロックを 36 MHz から倍の 72 MHz に変更するということだ。それに合わせて制約も変更する。
具体的には、PS からのクロックの FCLK_CLK2 の周波数設定を 36 MHz から 72 MHz に変更した。
もう一度、論理合成、インプリメント、ビットストリームの生成を行い、ハードウェアをエクスポートして、SDKを立ち上げた。
これで、画像のフレームレートが 15 fps から 30 fps に向上した。
このDMAWrite IPとDMA_Read_addr IP の組は使えそうだ。AXI VDMAの説明書を読まなくても簡単に使えるところが良いと思う。
願わくば、DMA_Read_addr IP を使うときのツールのバグが直ってほしいと思う。
2017年03月24日 05:17 |
ZYBO
| トラックバック:0
| コメント:0
”
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム4(ILAコアの挿入2) ”の続き。
前回、Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システムが動作した。しかし、ブロックデザイン上で挿入したILA コアとネットリストの信号を観察するため入れたILA コアが残ってしまっている。それを削除した。
まずは、ブロックデザイン上で挿入したILA コアを削除しよう。
Debug にマーキングされた配線を複数選択して、右クリックし、右クリックメニューからClear Debug を選択する。
ILA コアの system_ila が削除された。
これで、ブロックデザイン上で挿入したILA コアが削除された。
次に、ネットリストの信号を観察するため入れたILA コアを削除する。
論理合成を行って、成功後に表示されるSynthesis Completed ダイアログで Open Synthesized Design を選択した。
Synthesized Design が表示された。Tools -> Set Up Debug... を選択した。
Set Up Debug ダイアログが表示された。Next ボタンをクリックした。
Existing Debug Nets で、Disconnect all net and remove debug cores を選択した。
Set Up Debug Summary が表示された。Finish ボタンクリックした。
ネットリストの信号を観察するため入れたILA コアが削除された。
確か、制約ファイルの ILA コア関連の制約は削除されたが、1つ ILA コアの制約が残っていたので、手動で削除した。
インプリメント、ビットストリームの生成を行った。結果を示す。
ILA コアが入る前と同等のリソース使用量になった。
ハードウェアをエクスポートして、SDK を立ち上げて、カメラ画像をディスプレイに表示してみたところ正常に表示された。
2017年03月23日 04:58 |
ZYBO
| トラックバック:0
| コメント:0
”
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム3(ILAコアの挿入) ”の続き。
DMA_Read_addr_0 の m_axi_in_r と outs は波形が出ていて動作しているようだった。よって今回は、AXI4-Stream 版のビットマップ・ディスプレイ・コントローラの内部信号をVivado Analyzer で確認してみよう。
Flow Navigator -> Synthesis -> Open Synthesized Design をクリックして、Synthesized Design を開く。
Tools -> Set Up Debug... を選択する。
Set Up Debug ダイアログが開いた。
Nets to Debug でFind Nets to Add... をクリックする。
Find Nets で、h_count を検索してみた。
Add Nets to Debug で信号を選択する。
観察する信号を示す。
次は、ILA Core Options を設定する。
Set Up Debug Summary が表示された。
Debug 画面が表示された。
cam_disp_axis.xdc の制約ファイルに挿入したu_ila_0 の制約が追加された。
インプリメント、ビットストリームの生成を行った。結果を示す。
SDK でXilinx Tools -> Program FPGA を選択して、ビットストリームをZynq にダウンロードした。
SDK で、Hello_World を起動して、PL にクロックを供給した。
Flow Navigator -> Program and Debug -> Open Hardware Manager -> Auto Connect を選択した。
Hardware Manager が起動した。
Dashboard Optionsを開いて、hw_ila_2, hw_ila_3 のすべてにチェックを入れた。
hw_ila_1 のトリガをかけた。AXI4 バス。
hw_ila_2 のトリガをかけた。ビットマップ・ディスプレイ・コントローラのclk_disp ドメイン。
hw_ila_3 のトリガをかけた。ビットマップ・ディスプレイ・コントローラの clk_axi ドメイン。
SDK で cam_disp_hls.elf をRun した。
hw_ila_3 の波形を示す。diap_mode_ena が 1 にならない。しかも init_done_d1 が上がったときに、u_ila_1_war_data_count_1[7:0] が 00 ではなかった。となると、ビットマップ・ディスプレイ・コントローラを活かすのが遅いことが考えられる。
cam_disp_hls.c のアプリケーションソフトで、DMA_read_addr の起動の後で、ビットマップ・ディスプレイ・コントローラを活かしていたのだが、これでは、ビットマップ・ディスプレイ・コントローラを活かすのが遅い。ビットマップ・ディスプレイ・コントローラを生かす記述(ピンクの四角)を DMA_read_addr の起動(青の四角)の前に持ってきた。
これでうまくDMA Read の波形が出力された。
画像も表示された。
DMA Read とDMA Write が両方表示されている波形を示す。
2017年03月21日 04:08 |
ZYBO
| トラックバック:0
| コメント:0
”
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム1(プロジェクト作成) ”
”
Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム2(SDK) ”の続き。
前にやったのは半年くらい前だが、DMA Read IPが動作しないということで止まっていた。しかし、”
「Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版)」を使って合成後の機能シミュレーション3 ”で論理合成しても機能シミュレーションが問題なくなったということで、もう一度やってみようと思う。
cam_disp_axis_162 プロジェクトはVivado 2016.2 なので、”
Vivado 2016.2 からVivado 2016.4 へアップグレード ”を参照して、Vivado 2016.4 のcam_disp_axis プロジェクトを作成した。
当然、Target language はVHDL にしてある。
(2017/04/20 : 追記) この時点ではアプリケーションソフトがバグっていてディスプレイに表示できませんが、アプリケーションソフトのバグフィックス後に、Target language を Verilog にしても動作しました。論理合成後の機能シミュレーションを行うときに強瀬された EDIF からVerilog に変換するツールがバグっているようです。
論理合成、インプリメント、ビットストリームの生成を行ったところ、成功した。
リソース使用量は以前と変化が無い。今回のProject Summary はキャプチャするのを忘れてしまったので、以前のVivado 2016.2 のときのProject Summary を貼っておく。
ハードウェアをエクスポートして、SDKを立ち上げた。
cam_disp_hls プロジェクトを作成し、cam_disp_hls.c をコピー&ペーストした。
ビットストリームをZYBO にダウンロードして、cam_disp_hls.elf を起動したが、動作しなかった。
Vivado 2016.4 になって変わったVivado Analyzer を試してみようということで、ブロックデザインでDMA_Read_addr_0 のm_axi_in_r と outs とDMA_Write_0 の m_axi_out_r を選択して、右クリックし右クリックメニューからDebug を選択した。
選択したラインにデバックマークが付き、上に Run Connection Automation が出るので、クリックした。
Run Connection Automation が表示された。OK ボタンをクリックした。
system_ila が挿入された。ILA コアがブロックデザイン上に挿入されるようになった。
論理合成、インプリメント、ビットストリームの生成を行った。結果を示す。
全体的にリソース使用量が増えている。これはILA コアを入れたので、当然と言えば当然だ。
Vivado Analyzer はPL の回路にクロックが来ないと起動できない。ソフトウェアを起動しないと回路にクロックが供給されないので、Vivado Analyzer は起動しない。
と言う訳で、ZYBO にビットストリームをダウンロードしてから、cam_disp_hls.elf を起動した。
その後で、Flow Navigator -> Program and Debug -> Open Hardware Manager -> Auto Connect を選択した。
Hardware Manager が立ち上がった。
Status ペインで Run trigger immediate for this ILA core をクリックすると、すぐに波形がキャプチャされる。
Vivado 2016.4 では、AXI バスはステータスを表示してくれるようだ。トランザクションが全く見えなかった。
よくわからなかったので、DMA_Write_0 の ins も追加した。
論理合成、インプリメント、ビットストリームの生成を行った。成功した。
Project Summary を示す。
Hardware Manager で net_slot_3_axis_tvalid = R (DMA_Write_0 の ins)でトリガをかけて Run trigger for this ILA core をクリックした。
DMA_Write_0 の ins と m_axi_out_r は波形が出力されていることが分かった。
次に、net_slot_0_axi_arvalid = R (DMA_Read_addr_0 の m_axi_in_r)でトリガをかけたが掛からなかった。
これは、電源ON の少し間だけのみ DMA_Read_addr_0 の m_axi_in_r と outs が動作しているかもしれない。ということで、Hello_World プロジェクトを作成し、これを起動して、PL へクロックを供給してから cam_disp_hls.elf を起動することにした。
Hello_World プロジェクトを作成した。起動した。
Flow Navigator -> Program and Debug -> Open Hardware Manager -> Auto Connect を選択し、Hardware Manager を起動する。
net_slot_0_axi_arvalid = R (DMA_Read_addr_0 の m_axi_in_r)でトリガをかけた。
これで、SDK で、cam_disp_hls.elf を起動した。すると、トリガがかかってDMA_Read_addr_0 のm_axi_in_r と outs の波形が表示された。
これを見るときちんとDMA_Read_addr_0 の m_axi_in_r はAXI4 Master Read ができていて、AXI4-Stream の outs にもきちんと出力できているように見える。しかし、途中で tready が 1 から 0 になってしまっている。これは、AXI4-Stream 版のビットマップ・ディスプレイ・コントローラのピクセル用FIFO がフルになってしまっているからだと思われる。
AXI4-Stream 版のビットマップ・ディスプレイ・コントローラがおかしい可能性が出てきた。
2017年03月20日 07:16 |
ZYBO
| トラックバック:0
| コメント:0
”
「Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版)」を使って合成後の機能シミュレーション2 ”の続き。
前回は、Vivado HLS 2016.4 で Verilog でIP をExport RTL して、Vivado 2016.4 では、Target language を VHDL にしたら、Post-Synthesis Functional Simulation が正常になった。ここでは、IO ピンが足りるようにVirtex7 の xc7vx980tffg1928-2 を使用していたが、IO ピンが足りないZYBO (xc7z010clg400-1)ではどうか?を確かめてみた。ikzwm さんがやってくれたので、大丈夫とは思うが自分でも確かめてみる。
まずは、Vivado HLS 2016.4 で、”
Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版) ”のソースコードで、xc7z010clg400-1 をターゲットとして、Verilog でExport RTL を行った。
そのVivado HLS2016.4 のDMA Read IPを使用して、Project part を xc7z010clg400-1 に変更し、Project Settings のTarget language を VHDL にした Vivado 2016.4 プロジェクトを作った。
論理合成を行った。IO ピンはオーバーフローになっている。
Flow Navigator の Simulation -> Run Simulation -> Run Post-Synthesis Functional Simulation を選択して、論理合成後の機能シミュレーションを行った。
問題なく波形が出ている。
次に、念のため、Flow Navigator の Simulation -> Run Simulation -> Run Behavioral Simulation を選択して、論理シミュレーションを行った。
こっちも問題なく波形が出ている。
よって、ZYBO (xc7z010clg400-1)でも問題なく波形が出ている。
論理合成で IO ピンがオーバーフローでも Post-Synthesis Functional Simulation には影響ないことが分かった。
2017年03月19日 06:22 |
Vivado HLS
| トラックバック:0
| コメント:0
今日は、
ひるね姫(映画) を見てきました。とっても面白かったです。夢と日常が行ったり来たり。
しかし、自動運転のマスタコード?十数年もその価値を保っているとは思えないけど。。。作った人が超天才で、それ人でなければ作れないという設定なのか?
それに、予告編でも出てくるハンダ付けの場面はハンダ盛り過ぎなんじゃないか?と思う。
2017年03月18日 21:46 |
日記
| トラックバック:0
| コメント:0
”
「Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版)」を使って合成後の機能シミュレーション ”の続き。
ikwzm さんにVivado HLS のExport RTL のEvaluate Generated RTL をVHDL にしたら論理合成後の機能シミュレーションも動いたということでやってみたのだが、やはり結果は同様に動作していなかった。
Vivado RTL Synthesis のチェックを外して、Evaluate Generated RTL をVerilog でIP 化してやってみても同じだった。もう一度、Vivado RTL Synthesis のチェックを外して、Evaluate Generated RTL をVHDL でIP 化しても同様にダメだった。
ikwzm さんからもう一度、教えてもらったところ、「Vivado-HLS の Export RTL as IP は Verilog かつ、Vivado の Target Language を VHDL にした場合」とのことだった。
もう一度、Vivado HLS 2016.4 で
Evaluate Generated RTL をVerilog に設定して、Export RTL を行った。Vivado RTL Synthesis のチェックは外してあるが、IP になった後のファイルを見てみたところ、特に合成結果が入っているようには見えなかったので、やってみるだけなのだと思う。
Vivado 2016.4 で DMA Read IP をリプレースして
、Project Settings のTarget language を VHDL にした。 これで、論理合成(Run Synthesis)を行ってから、Flow Navigator の Simulation -> Run Simulation -> Run Post-Synthesis Functional Simulation を選択して、論理合成後の機能シミュレーションを行った。
やった~。波形が出た。。。 何でだろう?これで何で波形が出るの? ともかくよかった。これはXilinx社にバグレポートしないと。。。
論理シミュレーションも問題なく波形が表示されている。。。
2017年03月18日 05:15 |
Vivado HLS
| トラックバック:0
| コメント:0
”
Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版) ”の続き。
前回は絶対アドレス指定のDMA Read IPをVivado HLS 2016.4 で作成した。今回は、そのDMA Read IPをVivado で論理シミュレーションと合成後の機能シミュレーションを行った。
前回やったときの記事は、”
DMA Read IP を単体でシミュレーション3(DMA Read IP単体で論理合成後にシミュレーション) ”
このプロジェクトを使用した。
ただし新しく生成した DMA Read IPに入れ替えてある。それに、DMA Read IPのレジスタ設定を行う reg_write_read IP が一度設定を終了しても、また設定を繰り返し行っていたので、修正を行った。上に示す図は論理合成が終了している。
論理合成後のレポートを示す。
IOポートはすべて割り振られている。これで論理合成後の機能シミュレーションは問題ない。しかし、IOがオーバーフローしていても論理合成後の機能シミュレーションがうまく行くのかもしれない?確実に動作する回路で試していないので、よくわからない?
ブロックデザインを示す。
DMA Read IPとAXI Interconnect 2つだけのシンプルな構成だ。
Address Editor を示す。
テストベンチとして、DMA Read IPのレジスタを設定する reg_write_read IP と AXI4 Slave BFM をメモリとして接続している。そのブロック図を下に示す。
さて次に、論理シミュレーションを行う。
Flow Navigator の Simulation -> Run Simulation -> Run Behavioral Simulation を選択する。
論理シミュレーション結果の全体波形を示す。
波形1
波形2
波形の数が多いので、2つの画像になってしまった。最初の画像は主にDMA Read IPのAXI4 Master Read アクセスが表示されている。2つ目の波形には、DMA Read IPのレジスタを設定するAXI4-Lite Slave アクセスとAXI4-Stream 出力が表示されている。
最初の波形を拡大してみよう。
波形3
バーストに1クロックの Wait はあるがほとんどフルバーストでAXI4 Master Read が行われている。
次に、DMA Read IPを設定するのレジスタを設定するAXI4-Lite Slave アクセスを下に示す。
波形4
まずは、DMA Read IPのレジスタマップを示す。
//------------------------Address Info------------------- // 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 frame_buffer0 // bit 31~0 - frame_buffer0[31:0] (Read/Write) // 0x1c : reserved // 0x20 : Data signal of frame_buffer1 // bit 31~0 - frame_buffer1[31:0] (Read/Write) // 0x24 : reserved // 0x28 : Data signal of frame_buffer2 // bit 31~0 - frame_buffer2[31:0] (Read/Write) // 0x2c : reserved // 0x30 : Data signal of mode_V // bit 0 - mode_V[0] (Read/Write) // others - reserved // 0x34 : reserved // (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
レジスタを設定する
reg_write_read IP の設定を示す。
#define AD_ARRAY_LIMIT 256 #define REG_WRITE 0 #define REG_READ 1 #define R_W_FIELD 0 #define DELAY_FIELD 1 #define ADDRESS_FIELD 2 #define DATA_FIELD 3 const unsigned int reg_ad[AD_ARRAY_LIMIT][4 ]={ {0 , 0 , 0x44 A00018, 0x10000000 }, {0 , 0 , 0x44 A00020, 0x10000000 }, {0 , 0 , 0x44 A00028, 0x10000000 }, {0 , 0 , 0x44 A00030, 0 }, {1 , 0 , 0x44 A00000, 0 }, {0 , 0 , 0x44 A00000, 1 }, {0 , 0xf ffffffe, 0 , 0 }, {0 , 0xf fffffff, 0 , 0 },
つまり、0x44A00018、0x44A00020、0x44A00028 に 0x10000000 を書いているが、3つのフレームバッファのアドレスを書いている。
0x44A00030 でDMA Read IPのモードを書いている。 0 なので、DMA_WRITE_MODE だ。
0x44A00000 をRead してから、0x44A00000 に 1 を書いてDMA Read IPをスタートさせている。
DMA Read IPのAXI4-Stream 出力の波形を示す。
波形5
前に示した全体波形では、outs_tlast が時々 1 変化していたのが見えたと思うが、画像フレームのスタート時には、outs_tuser が 1 クロック間だけ 1 となっているのがわかる。
と言う訳で完全に動作しているようだ。
次に、論理合成後の機能シミュレーションを行う。
Flow Navigator の Simulation -> Run Simulation -> Run Post-Synthesis Functional Simulation を選択する。
Post-Synthesis Functional Simulation での全体波形を示す。
波形6
波形7
やはり、Post-Synthesis Functional Simulation で波形が出てこない。 DMA Read IPのレジスタを設定するAXI4-Lite Slave アクセスを拡大してみよう。
波形8
こちらは問題ないようだ。
2017年03月17日 05:32 |
Vivado HLS
| トラックバック:0
| コメント:0
”
Vivado HLS で DMA Read IP を作る(絶対アドレス指定版) ”の続き。
”
Vivado HLS で DMA Read IP を作る(絶対アドレス指定版) ”では、DMA Read IPを作成したが、”
Vivado HLSで作ったDMA Read IP を実機でテスト1(動作しない) ”で実機で動作を確認しても動作しなかった。
”
DMA Read IP を単体でシミュレーション3(DMA Read IP単体で論理合成後にシミュレーション) ”では、DMA Read IPを単体でシミュレーションしたが、論理シミュレーションはそれらしく動いても Post-Synthesis Fuctional Simulation では、動作しないという問題があった。これは、IOがオーバーフローしているからかもしれないということで、Vivado 2016.4 でテストしてすることにした。
DMA_Read_Addr_Virtex を示す。シミュレーション用のVivado 2016.4 プロジェクトを論理合成したときに、IOがオーバーフローしないように、Virtex7 の xc7vx980tffg1928-2 を使用している。
なお、”
Vivado HLS で DMA Read IP を作る(絶対アドレス指定版) ”では、3フレームを一度に処理していたのだが、今回は、1フレーム分の処理に変更した。
C シミュレーションを行った。
dma_result0.bmp を見ると正常に「A」の文字が見える。
Cコードの合成を行った。その結果を示す。
Latency は 3083 クロックで、64 ピクセル x 48 行の「A」という画像の総ピクセル値 3072 から 11 クロックしか離れていないので、ほぼ 1 クロックで 1 ピクセルを処理することができている。
C/RTL協調シミュレーションを行ったところ、エラーになってしまった。
「ERROR: [COSIM 212-4] *** C/RTL co-simulation finished: FAIL ***」を調べると、”
AR# 61063 Vivado HLS 2014.2 : C/RTL 協調シミュレーションに関する問題を調査するためのデバッグ ガイド ”が見つかった。そこに”
Vivado HLS: Debug Guide for investigating C/RTL co-simulation issues ”のリンクがあった。Vivado HLS: Debug Guide for investigating C/RTL co-simulation issuesを見ても原因はよくわからない?
IP 化を行った。
Vivado RTL Synthesis にチェックを入れた。
結果を示す。
Resource Usage のLUT が合成結果(1269 ) の半分程度の 695 になっている。ロジックが消されている恐れがある。
今までは、テスト用の64 ピクセル x 48 行の「A」という画像でやっていたので、800 ピクセル x 600 行の実際に処理する画像用に値を切り替えた。
もう一度、C コードの合成を行った。
IP 化を行った。やはり LUT は合成時の約半分になっている。
DMA_Read.h を示す。
#ifndef __DMA_READ_H__ #define __DMA_READ_H__ #define HORIZONTAL_PIXEL_WIDTH 800 #define VERTICAL_PIXEL_WIDTH 600 #define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH) #define MAX_FRAME_NUMBER 3 #define DMA_WRITE_MODE 0 #define FREE_RUN_MODE 1 #define MEMCPY_LENGTH (HORIZONTAL_PIXEL_WIDTH*4) #endif
DMA_Read_addr.cpp を示す。
#include <stdio.h> #include <string.h> #include <ap_int.h> #include <hls_stream.h> #include <ap_axi_sdata.h> #include "DMA_Read.h" int DMA_Read_addr(volatile int *in, hls::stream<ap_axis<32 ,1 ,1 ,1 > >& outs, unsigned int frame_buffer0, unsigned int frame_buffer1, unsigned int frame_buffer2, ap_uint<2 > & active_frame, ap_uint<1 > mode){#pragma HLS INTERFACE s_axilite port=mode #pragma HLS INTERFACE ap_none register port=active_frame #pragma HLS INTERFACE s_axilite port=frame_buffer0 #pragma HLS INTERFACE s_axilite port=frame_buffer1 #pragma HLS INTERFACE s_axilite port=frame_buffer2 #pragma HLS INTERFACE m_axi depth=3072 port=in offset=off #pragma HLS INTERFACE axis port=outs #pragma HLS INTERFACE s_axilite port=return ap_axis<32 ,1 ,1 ,1 > pix; int dma_index; static int n = 0 ; if (mode == DMA_WRITE_MODE){ n = (int )active_frame; }else { n++; if (n > 2 ) n = 0 ; } switch (n){ case 0 : dma_index = frame_buffer2/sizeof (int ); break ; case 1 : dma_index = frame_buffer0/sizeof (int ); break ; case 2 : dma_index = frame_buffer1/sizeof (int ); break ; default : dma_index = frame_buffer0/sizeof (int ); break ; } for (int y=0 ; y<VERTICAL_PIXEL_WIDTH; y++){ for (int x=0 ; x<HORIZONTAL_PIXEL_WIDTH; x++){#pragma HLS PIPELINE II=1 pix.data = in[dma_index+(y*HORIZONTAL_PIXEL_WIDTH)+x]; if (y==0 && x==0 ) pix.user = 1 ; else pix.user = 0 ; if (x == (HORIZONTAL_PIXEL_WIDTH-1 )) pix.last = 1 ; else pix.last = 0 ; outs << pix; } } return 0 ; }
DMA_Read_addr_tb.cpp を示す。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ap_int.h> #include <hls_stream.h> #include <iostream> #include <fstream> #include <ap_axi_sdata.h> #include "DMA_Read.h" #include "bmp_header.h" int DMA_Read_addr(volatile int *in, hls::stream<ap_axis<32 ,1 ,1 ,1 > >& outs, unsigned int frame_buffer0, unsigned int frame_buffer1, unsigned int frame_buffer2, ap_uint<2 > & active_frame, ap_uint<1 > mode);int main() { using namespace std; hls::stream<ap_axis<32 ,1 ,1 ,1 > > outs_dummy; hls::stream<ap_axis<32 ,1 ,1 ,1 > > outs; ap_axis<32 ,1 ,1 ,1 > pix; ap_axis<32 ,1 ,1 ,1 > vals, vals_dummy; BITMAPFILEHEADER bmpfhr; BITMAPINFOHEADER bmpihr; FILE *fbmpr, *fbmpw; int *rd_bmp, *hw_lapd; int blue, green, red; ap_uint<2 > active_frame = 0 ; int *frame_buffer; if ((fbmpr = fopen("test.bmp" , "rb" )) == NULL){ fprintf(stderr, "Can't open test.bmp by binary read mode\n" ); exit(1 ); } fread(&bmpfhr.bfType, sizeof (char ), 2 , fbmpr); fread(&bmpfhr.bfSize, sizeof (long ), 1 , fbmpr); fread(&bmpfhr.bfReserved1, sizeof (short ), 1 , fbmpr); fread(&bmpfhr.bfReserved2, sizeof (short ), 1 , fbmpr); fread(&bmpfhr.bfOffBits, sizeof (long ), 1 , fbmpr); fread(&bmpihr, sizeof (BITMAPINFOHEADER), 1 , fbmpr); if ((rd_bmp =(int *)malloc (sizeof (int ) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){ fprintf(stderr, "Can't allocate rd_bmp memory\n" ); exit(1 ); } int *buf; if ((buf =(int *)malloc (3 * sizeof (int ) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){ fprintf(stderr, "Can't allocate buf memory\n" ); exit(1 ); } for (int y=0 ; y<bmpihr.biHeight; y++){ for (int x=0 ; x<bmpihr.biWidth; x++){ blue = fgetc(fbmpr); green = fgetc(fbmpr); red = fgetc(fbmpr); rd_bmp[((bmpihr.biHeight-1 )-y)*bmpihr.biWidth+x] = (blue & 0xf f) | ((green & 0xf f)<<8 ) | ((red & 0xf f)<<16 ); } } fclose(fbmpr); if ((frame_buffer =(int *)malloc (MAX_FRAME_NUMBER * sizeof (int ) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){ fprintf(stderr, "Can't allocate frame_buffer0 ~ 2\n" ); exit(1 ); } memcpy(frame_buffer, rd_bmp, bmpihr.biHeight * bmpihr.biWidth * sizeof (int )); memcpy((int *)((unsigned int )frame_buffer + bmpihr.biHeight * bmpihr.biWidth * sizeof (int )), rd_bmp, bmpihr.biHeight * bmpihr.biWidth * sizeof (int )); memcpy((int *)((unsigned int )frame_buffer + 2 * bmpihr.biHeight * bmpihr.biWidth * sizeof (int )), rd_bmp, bmpihr.biHeight * bmpihr.biWidth * sizeof (int )); DMA_Read_addr((volatile int *)0 , outs_dummy, (unsigned int )frame_buffer, (unsigned int )frame_buffer+(bmpihr.biWidth * bmpihr.biHeight * sizeof (int )), (unsigned int )frame_buffer+(2 * (bmpihr.biWidth * bmpihr.biHeight) * sizeof (int )), active_frame, DMA_WRITE_MODE); DMA_Read_addr((volatile int *)0 , outs, (unsigned int )frame_buffer, (unsigned int )frame_buffer+(bmpihr.biWidth * bmpihr.biHeight * sizeof (int )), (unsigned int )frame_buffer+(2 * (bmpihr.biWidth * bmpihr.biHeight) * sizeof (int )), active_frame, FREE_RUN_MODE); int k = 0 ; for (int j=0 ; j < bmpihr.biHeight; j++){ for (int i=0 ; i < bmpihr.biWidth; i++){ outs >> vals; outs_dummy >> vals_dummy; ap_int<32 > val = vals.data; buf[(k*bmpihr.biWidth*bmpihr.biHeight)+(j*bmpihr.biWidth)+i] = (int )val; } } char output_file[] = "dma_result0.bmp" ; int i=0 ; switch (i){ case 0 : strcpy(output_file,"dma_result0.bmp" ); break ; case 1 : strcpy(output_file,"dma_result1.bmp" ); break ; case 2 : strcpy(output_file,"dma_result2.bmp" ); break ; } if ((fbmpw=fopen(output_file, "wb" )) == NULL){ fprintf(stderr, "Can't open %s by binary write mode\n" , output_file); exit(1 ); } fwrite(&bmpfhr.bfType, sizeof (char ), 2 , fbmpw); fwrite(&bmpfhr.bfSize, sizeof (long ), 1 , fbmpw); fwrite(&bmpfhr.bfReserved1, sizeof (short ), 1 , fbmpw); fwrite(&bmpfhr.bfReserved2, sizeof (short ), 1 , fbmpw); fwrite(&bmpfhr.bfOffBits, sizeof (long ), 1 , fbmpw); fwrite(&bmpihr, sizeof (BITMAPINFOHEADER), 1 , fbmpw); int offset = i * bmpihr.biWidth * bmpihr.biHeight; for (int y=0 ; y<bmpihr.biHeight; y++){ for (int x=0 ; x<bmpihr.biWidth; x++){ blue = buf[offset+((bmpihr.biHeight-1 )-y)*bmpihr.biWidth+x] & 0xf f; green = (buf[offset+((bmpihr.biHeight-1 )-y)*bmpihr.biWidth+x] >> 8 ) & 0xf f; red = (buf[offset+((bmpihr.biHeight-1 )-y)*bmpihr.biWidth+x]>>16 ) & 0xf f; fputc(blue, fbmpw); fputc(green, fbmpw); fputc(red, fbmpw); } } fclose(fbmpw); free(rd_bmp); free(frame_buffer); return 0 ; }
2017年03月16日 05:17 |
Vivado HLS
| トラックバック:0
| コメント:0
BNN-PYNQ が頻繁に変更されているので、PYNQボードのBNN-PYNQをアップグレードした。
ネットで検索したところ、アップグレードは pip install --upgrade で良いそうだ。
sudo pip3.6 install --upgrade git+https://github.com/Xilinx/BNN-PYNQ.git コマンドを実行した。
~/jupyter_notebooks/bnn を見てみると、更新されていたが日時がおかしい。
date コマンドで見てみると、UTC だった。これなら仕方ないがJST に修正しよう。
sudo ln -sf /usr/share/zoneinfo/Japan /etc/localtime これで、JST に変更できた。
2017年03月14日 04:15 |
PYNQ
| トラックバック:0
| コメント:0
”
XilinxのBNN-PYNQをやってみる3(Hardware design rebuilt 1) ”の続き。
前回は、
BNN-PYNQ の cnv-pynq をHardware design rebuilt したので、今回はもう1つの lfc-pynq をHardware design rebuilt してみよう。
最初に、BNN-PYNQ/bnn/src/network ディレクトに cd した。
cd /home/masaaki/BNN-PYNQ/bnn/src/network もうすでにXILINX_BNN_ROOT 環境変数はセットしてある。
export XILINX_BNN_ROOT=/home/masaaki/BNN-PYNQ/bnn/src/ BNN-PYNQ/bnn/src/network ディレクトリの make_hw.sh を実行して、lfc-pynq のVivado HLS プロジェクトとVivado プロジェクトを生成する。
./make-hw.sh lfc-pynq pynq a すると、前回と同様に/home/masaaki/BNN-PYNQ/bnn/src/network/output ディレクトリのbitstream, hls-syn, report, vivado の各ディレクトリに lfc-pynq ディレクトリができていた。
lfc-pynq のVivado HLS 2016.4 プロジェクトを開いた。
合成レポートを示す。やはり、Target が 5.00 ns でEstimated が 7.90 ns だった。
リソース使用量は cnv-pynq の方が、lfc-pynq よりも多かった。
次に、lfc-pynq のVivado 2016.4 プロジェクトを示す。
レポートを示す。
タイミングはメットしていた。
procsys ブロックデザインを示す。前回と同じだと思う。
Address Editor を示す。
2017年03月13日 05:06 |
PYNQ
| トラックバック:0
| コメント:0
”
XilinxのBNN-PYNQをやってみる2(jupyter notebook) ”の続き。
”
Ubuntu16.04にVivado 2016.4をインストール ”でVirtualBoxに新しいVirtualマシンを作って、Ubuntu 16.04 をインストールして、Vivado 2016.4 をインストールできたので、やっとBNN-PYNQのHardware design rebuilt がやれる環境が整った。それで、BNN-PYNQのHardware design rebuilt をやってみることにした。今回はcnv-pynq をやってみた。
BNN-PYNQ は、短い期間でアップデートされているので、GitHub からZIP ファイルをダウンロードするとアップデートするのが難しくなるので、git clone することにした。新しいUbuntu 16.04 上にBNN-PYNQ を git clone した。
git clone https://github.com/Xilinx/BNN-PYNQ.git これで、ホームディレクトリ上にBNN-PYNQ がクローンされた。
次に、
BNN-PYNQ のREADME.md のHardware design rebuilt を参照しながら、cnv-pynq のVivado HLS プロジェクトとVivado プロジェクトを生成する。
最初に、BNN-PYNQ/bnn/src/network ディレクトに cd した。
cd /home/masaaki/BNN-PYNQ/bnn/src/network XILINX_BNN_ROOT 環境変数にBNN-PYNQ/bnn/src/ をセットする。
export XILINX_BNN_ROOT=/home/masaaki/BNN-PYNQ/bnn/src/ BNN-PYNQ/bnn/src/network ディレクトリの make_hw.sh を実行して、cnv-pynq のVivado HLS プロジェクトとVivado プロジェクトを生成する。
./make-hw.sh cnv-pynq pynq a 長い時間がかかったが、cnv-pynq のVivado HLS プロジェクトとVivado プロジェクトを生成することができた。その結果のディレクトリとファイルを示す。
BNN-PYNQ/bnn/src/network ディレクトリの下に、output ディレクトリができて、その下に bitstream, hls-syn, report, vivado ディレクトリができていた。
hls-syn ディレクトリの下の cnv-pynq-pynq の下には、Vivado HLS のプロジェクトが生成されていた。
vivado ディレクトリの下の cnv-pynq-pynq の下には、Vivado のプロジェクトが生成されていた。
さっそく、Vivado HLS 2016.4 を立ち上げて、cnv-pynq-pynq の下のプロジェクトを開いた。
合成結果を示す。
Target が 5.00 ns に対して、Estimated は 7.90 ns で満たしていないが、実際のクロックは 100 MHz なので、大丈夫だろう?
BRAM_18K は96 % 使用している。DSP48E は 14 % 、FF は 26 %、LUT は 80 % 使用している。
次に、Vivado 2016.4 を立ち上げて、vivado ディレクトリの下の cnv-pynq-pynq の下のVivado プロジェクトを開いてみた。
procsys ブロックデザインを示す。
Address Editor を示す。
Project Summary を示す。タイミング違反が出ている。
LUT はVivado HLS では 80 % 使用していたはずが、54 % になっている。BRAM も少ないので、ロジックを消されたのかもしれない?
タイミング違反を調べるためにImplemented Design を開いた。
BlackBoxJam_0 間がタイミング違反になっているので、Vivado HLS の合成したIP がタイミング違反になっている。
このタイミング違反は直すのが難しそうです。Vivado HLS でTarget を 4 ns, 3ns にしてみたんですが、合成結果のEstimated は7.9 ns で変化がありませんでした。
Vivadoのimplementation のオプションのStrategy にPerformance_ExtraTimingOpt を選択してあるので、これ以上変更しても無理そうでした。
2017年03月12日 05:52 |
PYNQ
| トラックバック:0
| コメント:0
「モアナと伝説の海」(映画) を見てきました。映像はとっても綺麗で良かったです。歌も良かったです。内容は少し平凡かもしれませんけど。。。
2017年03月11日 21:13 |
日記
| トラックバック:0
| コメント:0
今日はUbuntu16.04にVivado 2016.4をインストールする覚書を書いておこうと思う。
ちなみに、私の環境は、VirtualBoxにUbuntu16.04をインストールしてある。
まずは、
Xilinx Japan のサイトに行って、サポート→ダウンロードとライセンスを選択して、
ダウンロード のサイトへ行く。
Vivado HLx 2016.4: WebPACK および Editions - Linux 用自己解凍型ウェブ インストーラー (BIN - 80.67 MB)をダウンロードする。
すると、Xilinx_Vivado_SDK_2016.4_0124_1_Lin64.bin がダウンロードできる。
Ubuntuでダウンロードしていれば、そのままだが、Windowsでダウンロードした場合は、Ubuntuに持っていく。
まずは、実行パーミッションを与える必要がある。
chmod +x Xilinx_Vivado_SDK_2016.4_0124_1_Lin64.bin 次に、Xilinx_Vivado_SDK_2016.4_0124_1_Lin64.bin を実行しよう。その際に、/opt/Xilinxに書くのでスーパーユーザーの権限が必要だ。
sudo ./Xilinx_Vivado_SDK_2016.4_0124_1_Lin64.bin スーパーユーザーのパスワードを入力すると、Vivado 2016.4 Installer が起動する。
Select Install Type では、Xilinx のUser ID とPassword を入れる。
Accept License Agreements では、3つのチェックボックスにチェックを入れる。
Select Ediition to Install では、私はVivado HL Webpack のラジオボタンを選択したが、これはお好みで。
Vivado HL Webpack の画面では、Software Development Kit (SDK) のチェックを入れたほうが良い。
後はデフォルトで良いと思うので、省略。
最初に5GB 以上ダウンロードしてからインストールを始めるので、時間がかかるのは覚悟した方が良い。
License Manager が起動するが、Vivado HL Webpack はライセンスは必要ないので、終了させておく。
インストールが終了しても、vivado コマンドを入れてもVivado は起動ないので、設定を行う。
LX Terminal から
gedit .bashrc コマンドを実行する。
.bashrc の最後に
source /opt/Xilinx/Vivado/2016.4/settings64.sh alias xsdk='env SWT_GTK3=0 xsdk' alias vivado='env SWT_GTK3=0 vivado' を追加する。
なお、xsdk のスクリプトに関しては、
「VivadoやXilinx SDKをLinux (Ubuntu) で動かすメモ (Ubuntu 16.04 LTS, Vivado 2016.4, 64bit環境) 」から引用させて頂いた。これが無いと xsdk が起動できない。vivado もGTK3 を無効にしておかないと vivado から SDK を起動できない。
source .bashrc で.bashrc の内容を反映する。これで、vivado コマンドが実行できるようになった。
ホームディレクトリの.Xilinx ディレクトリの一部がのユーザーとグループが root なので、ユーザーに変更する。ホームディレクトリに移動しておく(
cd を実行すれば良い) なお、masaaki は自分のアカウント名に修正してください。
sudo chown -R masaaki:masaaki .Xilinx/ なお、ケーブル・ドライバがインストールされていないそうなので、下のコマンドでインストールした。これは、
「VivadoやXilinx SDKをLinux (Ubuntu) で動かすメモ (Ubuntu 16.04 LTS, Vivado 2016.4, 64bit環境) 」から引用させて頂いた。私のとディレクトリが違っているので、コマンドを書き換えた。
sudo /opt/Xilinx/Vivado/2016.4/data/xicom/cable_drivers/lin64/install_script/install_driverst/install_drivers エラーになってしまった。これは、ビットストリームのダウンロードに影響するので、最悪Windowsに持って行ってダウンロードすればよいと思うので、とりあえずはこのままとした。
(2017/07/26:追記) ”
オープンソースMCUをつくってArduinoでプログラミングしてみよう! ”によると、cd してドライバをインストールすればドライバがインストールできるようだ。直接、パスを指定してインストールコマンドを起動するとエラーになってしまうようだ。つまり以下のようにすればよい。
cd /opt/Xilinx/Vivado/2016.4/data/xicom/cable_drivers/lin64/install_script/ sudo ./install_drivers (2017/07/28:追記) Vivado 2017.2 では、階層が1つ深く、
cd /opt/Xilinx/Vivado/2016.4/data/xicom/cable_drivers/lin64/install_script/install_drivers sudo ./install_drivers だった。2017.1 からなのかもしれない?
LX Termnal 上で
vivado とタイプすると Vivado 2016.4 が起動する。
.bashrc で vivado を起動するときにGTK3 を無効にしておいたので、vivado でFile メニューから Launch SDK でSDK を起動しても起動できた。
ちなみにSDK単体は
xsdk で、Vivado HLS は
vivado_hls コマンドで起動できる。
2017年03月11日 08:06 |
Vivado
| トラックバック:0
| コメント:0
”
XilinxのBNN-PYNQをやってみる1(インストール編) ”の続き。
前回は、BNN-PYNQをインストールした。今回は、jupyter notebook の bnn/Cifar10.ipynb をやってみた。
まずは、私のルーターがPYNQボードに振ったIP アドレス:9090 をブラウザでアクセスした。
パスワードを聞かれるので、「xilinx」と入力した。
jupyter が表示された。
bnn をクリックして、その下に行き、Cifar10.ipynb をクリックして実行した。
Cifar10.ipynb が表示された。
Cell をクリックして、Run All を選択した。
すべてのPython コードが実行された。結果を示す。
2017年03月09日 05:29 |
PYNQ
| トラックバック:0
| コメント:0
XilinxのBNN-PYNQ をやって見たいということで、やってみました。BNN-PYNQはBinarized Neural Network (BNN) on PYNQ だそうです。
まずは、PYNQボードを用意します。
使用している Linux のイメージは、pynq_z1_image_2017_02_10 です。
とりあえず、
sudo apt-get update sudo apt-get upgrade
をしました。
次に、
XilinxのBNN-PYNQ に書いてあったように
sudo pip3.6 install git+https://github.com/Xilinx/BNN-PYNQ.git
を実行しました。
~/jupyter_notebooks/bnn ディレクトリができていました。
その他のBNN-PYNQ のファイルは /opt/python3.6/lib/python3.6/site-package/bnn ディレクトリに入っていました。
bitstreams ディレクトリには、cnv-pynq-pynq.bit, cnv-pynq-pynq.tcl, lfc-pynq-pynq.bit, lfc-pynq-pynq.tcl が入っています。
libraries ディレクトリには、以下のファイルがあります。(書いていくのが面倒になってきました)
params ディレクトリの下です。cifar10, mnist, road-signs, streetview のディレクトリがあって、その下には、***-weights.bin や ***-thres.bin が並んでいます。
__pycache__ ディレクトリです。
src フォルダです。
ちなみに、PYNQボードには、nautilus, geany, geeqie をインストールしてあります。パソコンには、Xming をインストールしてPYNQボードのX Window を持ってこられるようにしています。上の画像は nautilus のX を持ってきてパソコンで表示したときの画像です。
2017年03月08日 05:31 |
PYNQ
| トラックバック:0
| コメント:0
昨日は、「
FPGAエクストリーム・コンピューティング 番外編:PYNQ祭り 」に参加して発表してきました。
「
PYNQでカメラ画像をリアルタイムFASTX コーナー検出 」という題で発表してきました。スライドはSlideShareにアップしました。
いろいろな発表が聞けて、しかも、懇親会ではGraham Schelleさんと写真も取ってもらったり、いろいろな方とお話しすることができてとても楽しかったです。皆さん、ありがとうございました。
皆さんの持ってきたPYNQボードです。これだけ並ぶと壮観ですね。
2017年03月05日 04:49 |
PYNQ
| トラックバック:0
| コメント:0
”
PYNQボードのFASTX コーナー検出にラプラシアンフィルタIPとアンシャープ・マスクキング・フィルタIPを追加5(Jupyter Notebookで開発中) ”の続き。
いろいろとJupyter Notebook でやってはいるが、まだカメラ画像が表示されない。ちなみに今使っているPYNQボードのMicro SDカードのイメージは 2017/02/10 以前のものだ。
症状としては、ディスプレイに映像信号が出ていない。ブルー画面のままになっている。
下に、Jupyter Notebook を Python に直したコードを貼っておく。
# coding: utf-8 # In[51]: import os import pynq.drivers.xlnk from pynq.mmio import MMIO import time # fastx、ラプラシアンフィルタ、アンシャープ・マスクキング・フィルタのビットファイルをオープン # bitfile open with open('/home/xilinx/pynq/bitstream/pynq_fastx_wrapper.bit', 'rb') as bf: buf = bf.read() with open('/sys/devices/soc0/amba/f8007000.devcfg/is_partial_bitstream', 'w') as fd: fd.write('0') # /dev/xdevcfgにビットストリームを書き込む with open('/dev/xdevcfg', 'wb') as f: f.write(buf) # CMA領域を確保する mmu = pynq.drivers.xlnk.xlnk() print(mmu) # 800x600x4バイトをCMA領域に割り当てて、仮想アドレスと物理アドレスを表示 buf = mmu.cma_alloc(800*600*4) buf_phy = pynq.drivers.xlnk.libxlnk.cma_get_phy_addr(buf) print("virtal", buf, "physical", hex(buf_phy)) # AXI VDMAのレジスタ領域をMMIOにとしてマップする、0x100 = 256バイトをアサイン vdma = MMIO(0x43000000, 0x10000) print(vdma) # VDMAの設定 vdma.write(0x30, 0x4) # S2MM_VDMACR (Reset = 1) i=0 while (vdma.read(0x30) & 0x4) == 0x4 : i += 1 vdma.write(0x30, 0x4) # S2MM_VDMACR (Reset = 1) while (vdma.read(0x30) & 0x4) == 0x4 : i += 1 rd_data = vdma.read(0x30) print('%x' % rd_data) vdma.write(0x48, 3) # S2MM_FRMSTORE (0x48) register vdma.write(0x30, 0x00010002) # S2MM_VDMACR (IRQFrameCount=1, Circular_Park=1) vdma.write(0xA4, 800*4) # S2MM_HSIZE vdma.write(0xA8, 800*4) # S2MM_FRMDLY_STRIDE vdma.write(0xAC, buf_phy) # S2MM_START_ADDRESS1 vdma.write(0xB0, buf_phy) # S2MM_START_ADDRESS2 vdma.write(0xB4, buf_phy) # S2MM_START_ADDRESS3 vdma.write(0x30, 0x00010003) # S2MM_VDMACR (IRQFrameCount=1, Circular_Park=1, RS=1(Run)) while (vdma.read(0x34) & 0x1) == 0x1 : i += 1 rd_data = vdma.read(0x30) print('%x' % rd_data) # FASTXコーナー検出IPの設定 fastx = MMIO(0x43C30000, 0x10000) fastx.write(0x10, 600) # rows fastx.write(0x18, 800) # cols fastx.write(0x20, 20) # threshold fastx_data = fastx.read(0x20) print(fastx_data) # ラプラシアンフィルタIPの設定 lap = MMIO(0x43C50000, 0x10000) lap_data = lap.read(0) print(lap_data) # アンシャープ・マスキング・フィルタIPの設定 usm = MMIO(0x43C60000, 0x10000) usm.write(0x18, 1) # usm_fil_enable_V usm.write(0x20, 10) # k = 2.5 usm_data = usm.read(0x20) print(usm_data) # axisスイッチ0, 1 の初期設定(カメラ画像を選択) axis_sw0 = MMIO(0x43C10000, 0x10000) axis_sw1 = MMIO(0x43C20000, 0x10000) axis_sw1.write(0x40, 0) # カメラをイネーブル axis_sw1.write(0x44, 0x80000000) # FASTX axis_sw1.write(0x48, 0x80000000) # ラプラシアンフィルタ axis_sw1.write(0x4C, 0x80000000) # アンシャープ・マスキング・フィルタ axis_sw1.write(0x0, 0x2) # Commit axis_sw0.write(0x40, 0) # カメラを選択 axis_sw0.write(0x0, 0x2) # Commit axis1_data = axis_sw1.read(0x44) print('%x' % axis1_data) axis0_data = axis_sw0.read(0x40) print('%x' % axis0_data) # AXI VDMA Start #vdma.write(0xA0, 600) # S2MM Vertical Size vdmad = vdma.read(0xA0) print(vdmad) # ビットマップ・ディスプレイ・コントローラ、カメラ・コントローラ、カメラ用I2Cの設定 bmdc = MMIO(0x43C00000, 0x10000) # bitmap display controller camc = MMIO(0x43C40000, 0x10000) # camera controller cam_i2c = MMIO(0x41600000, 0x10000) # I2C controller for camera # ビットマップ・ディスプレイ・コントローラのベースアドレス、カメラ・コントローラON bmdc.write(0x0, buf_phy) camc.write(0x0, buf_phy) camc.write(0x4, 0) # One_shot_mode is disabled bmdc_data = bmdc.read(0) print('%x' % bmdc_data) camc_data = camc.read(0) print('%x' % camc_data) # カメラ設定用I2Cの初期化と設定書き込み cam_i2c.write(0x100, 0x2) # reset tx fifo ,address is 0x100, i2c_control_reg cam_i2c.write(0x100, 0x1) # enable i2c def cam_i2c_write_sync(): time.sleep(1/1000) # 1ms wait def cam_i2c_write(cam_i2c, device_addr, write_addr, write_data): cam_i2c.write(0x108, 0x100 | (device_addr & 0xfe)) # Slave IIC Write Address, address is 0x108, i2c_tx_fifo cam_i2c.write(0x108, write_addr) cam_i2c.write(0x108, (write_data >> 8)|0xff) # first data cam_i2c.write(0x108, 0x200 | (write_data & 0xff)) # second data cam_i2c_write_sync() # カメラの設定 cam_i2c_write(cam_i2c, 0xba, 0xf0, 0x1) # Changed regster map to IFP page 1 cam_i2c_write(cam_i2c, 0xba, 0x97, 0x20) # RGB Mode, RGB565 mmu.cma_get_buffer(buf,64)[:]
一旦、BOOT.bin を作ってやってみようと思っている。
2017年03月04日 05:24 |
PYNQ
| トラックバック:0
| コメント:0
”
PYNQボードのFASTX コーナー検出にラプラシアンフィルタIPとアンシャープ・マスクキング・フィルタIPを追加4(SDK) ”の続き。
前回は、SDK のベアメタル・アプリケーションソフトでPYNQボード用のFASTX コーナー検出とラプラシアンフィルタ、アンシャープ・マスクキング・フィルタをテストできた。今回は、Jupyter Notebook を使用してPython で開発している。
CMA領域の使用方法は、@hasegaw さんにVDMA のテストコードを教えて頂いたので、それを参考に実装している。
慣れないPython でやり方を検索しながら作っているので、時間がかかっている。作りかけだがJupyter Notebook の画面を貼っておく。
明日のPYNQ祭りに間に合えば良いのだが。。。
2017年03月03日 05:15 |
PYNQ
| トラックバック:0
| コメント:0
昨日、娘の卒業式の後で、奥さんと
「サバイバルファミリー」(映画) を見てきました。
東日本大震災の時のことを思い出してしまいました。決して、他人事じゃないです。。。
という気持ちで見ていたので、見入っていたのですが、途中で汽車が来て助けてくれたのは、なぜなんだろう?という疑問が残りました。
2017年03月02日 13:05 |
日記
| トラックバック:0
| コメント:0
今、PYNQ祭りに向けて、FASTXコーナー検出などを動かすためにPython コードを書こうと思っていますが、寝坊の影響で頭が良く回りません。
今日は、2月のFPGAの部屋のブログのアクセス数を書いてみようと思います。
2月のFPGAの部屋のブログのアクセス数は
FC2 ブログ が 40,699 アクセス、
livedoor ブログ が 4,990 アクセスの合計 45,689 アクセスでした。
日本を含め32か国からアクセスされました。(.com とかがあるので正確ではありませんが)
パソコンの使用言語も見てみると、17か国語のパソコンからアクセスされています。
2017年03月01日 22:28 |
日記
| トラックバック:0
| コメント:0