FC2カウンター FPGAの部屋 2023年08月
fc2ブログ

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

FPGAの部屋

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

AXI4-Stream Data Width Converter のバイト・レーン変換を確認する4

AXI4-Stream Data Width Converter のバイト・レーン変換を確認する3”の続き。

Pythonの画像処理ライブラリPillow(PIL)の Image.open でオープンした画像ファイルのフォーマットを確認するということで、前回は、blue.bmp、 green.bmp、 red.bmp を用意して、ZUBoard 1CG の PYNQ Linux にアップロードし、Jupter Notebook を書き換えて実行したところ、AXI4-Stream Data Width Converter で変換された 3 バイトの AXI4-Stream は上のバイトから RGB でなく BGR であることがわかった。前回の作業は、AXI4-Stream Data Width Converter は 2 個搭載されているが、その内の 3 バイト幅の AXI4-Stream から 4 バイト幅に変換する AXI4-Stream Data Width Converter の動作を見た。今回は、4 バイト幅の AXI4-Stream から 3 バイト幅に変換する AXI4-Stream Data Width Converter の動作を見た。

前回は、Vivado 2023.1 の i3filtes プロジェクトの i3filters ブロック・デザインの axis_dwidth_converter_1 の動作を観察した。
今回は、axis_dwidth_converter_0 の動作を観察する。
axis_dwidth_converter_0 は 4 バイト幅の AXI4-Stream から 3 バイト幅に変換する AXI4-Stream Data Width Converter だ。
zub1cg_pynq_195_230826.png

最初に blue.bmp を読み込んだときの axis_dwidth_converter_0 の AXI4-Stream インターフェースを観察した。
slot0 が axis_dwidth_converter_0 の入力の 4 バイト幅の AXI4-Stream インターフェースで、slot 1 が 3 バイト幅の AXI4-Stream インターフェースだ。
zub1cg_pynq_223_230830.png

3 バイト幅の AXI4-Stream インターフェースでは、0xfd までしか出ていないが、これは後ろのフィルタのスタート信号がまだ入っていなくてデータが流れていないためだと推測している。

次に green.bmp を読み込んだときの axis_dwidth_converter_0 の AXI4-Stream インターフェースを観察した。
zub1cg_pynq_224_230831.png

最後に red.bmp を読み込んだときの axis_dwidth_converter_0 の AXI4-Stream インターフェースを観察した。
zub1cg_pynq_226_230831.png

今までの AXI4-Stream Data Width Converter のバイト・レーン変換結果を表にまとめた。
zub1cg_pynq_227_230831.png

見事に BGR だった。
AXI4-Stream Subset Converter IP を使用して、AXI4-Stream のバイト・レーンを入れ替えることにする。
  1. 2023年08月31日 04:50 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

AXI4-Stream Data Width Converter のバイト・レーン変換を確認する3

AXI4-Stream Data Width Converter のバイト・レーン変換を確認する2”の続き。

Pythonの画像処理ライブラリPillow(PIL)の Image.open でオープンした画像ファイルのフォーマットを確認するということで、前回は、PNG の画像ファイルを ZUBoard 1CG の PYNQ Linux にアップロードし、Jupter Notebook を書き換えて実行したところ、PNG の画像ファイルは 4 チャネルでエラーが出てしまった。今回は、blue.bmp、 green.bmp、 red.bmp を用意して、ZUBoard 1CG の PYNQ Linux にアップロードし、Jupter Notebook を書き換えて実行したところ、AXI4-Stream Data Width Converter で変換された 3 バイトの AXI4-Stream は上のバイトから RGB でなく BGR であることがわかった。

特殊な BMP ファイルを Pinta で作った。
青、緑、赤それぞれ、最初のピクセルから 4 個だけ、値を 0xff, 0xfe, 0xfd, 0xfc にした。他のピクセルは 0xff とした。
blue.bmp、 green.bmp、 red.bmp を作成した。
下の図は、red.bmp の 4 番めのピクセルを 0xfc (252) にしたところだ。
zub1cg_pynq_215_230830.png

プライマリー色を赤 252 にして、鉛筆ツールで 4 番めのピクセルを書き換えた。
zub1cg_pynq_216_230830.png

出来上がった blue.bmp、 green.bmp、 red.bmp の画像ファイルを ZUBoard 1CG の PYNQ Linux にアップロードした。
zub1cg_pynq_217_230830.png

blue.bmp、 green.bmp、 red.bmp の画像ファイルを ~/jupyter_notebooks/examples/i3filters ディレクトリにコピーした。
cd
sudo mv *.bmp ~/jupyter_notebooks/examples/i3filters/


~/jupyter_notebooks/examples/i3filters ディレクトリに blue.bmp、 green.bmp、 red.bmp の画像ファイルがコピーされた。
zub1cg_pynq_218_230830.png

blue.bmp を Image.open() でオープンするように i3filters.ipynb を書き換えた。

#image_path = "./test2.jpg"
image_path = "./blue.bmp"
#image_path = "./green.bmp"
#image_path = "./red.bmp"
original_image = Image.open(image_path)


ガウシアン・フィルタ、メディアン・フィルタ、ソーベル・フィルタはすべてフィルタなしでスルーするように設定した。

gaussian.register_map.row_size = height
gaussian.register_map.col_size = width
gaussian.register_map.function_r = 2 # ORG_IMGwAxiDma
#gaussian.register_map.function_r = 3 # GAUSSIANwAxiDma

median.register_map.row_size = height
median.register_map.col_size = width
median.register_map.function_r = 2 # ORG_IMGwAxiDma
#median.register_map.function_r = 3 # MEDIANwAxiDma

sobel.register_map.row_size = height
sobel.register_map.col_size = width
sobel.register_map.function_r = 2 # ORG_IMGwAxiDma
#sobel.register_map.function_r = 3 # SOBELwAxiDma


i3filters.ipynb を実行して、bit ファイルをダウンロードする行を実行したら、Vivado で ILA ダッシュボードを表示する。
zub1cg_pynq_219_230830.png

Vivado 2023.1 で Project Navigator の PROGRAM AND DEBUG -> Open Hardware Manager -> Open Target をクリックして Auto Connect を選択すると、ILA ダッシュボードが表示された。
Trigger position in window を 512 から 100 に書き換えて、Run trigger for this ILA core の右向き三角ボタンをクリックして、トリガ待ちにした。

Jupyter Notebook で run_kernel() を実行すると、ILA ダッシュボードでトリガが掛かった。
zub1cg_pynq_220_230830.png

axis_dwidth_converter_1 (AXI4-Stream を 3 バイトから 4 バイトに変換する IP)の波形を示す。
slot2 が axis_dwidth_converter_1の出力(4 バイト)、slot3 が axis_dwidth_converter_1 の入力(3 バイト)となっている。
blue.bmp のときの波形を示す。
zub1cg_pynq_221_230830.png

green.bmp のときの波形を示す。
zub1cg_pynq_222_230830.png

red.bmp のときの波形を示す。
zub1cg_pynq_223_230830.png

見てお分かりの通りに、RGB だと思っていたのが、BGR だった。orz
  1. 2023年08月30日 05:05 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

AXI4-Stream Data Width Converter のバイト・レーン変換を確認する2

AXI4-Stream Data Width Converter のバイト・レーン変換を確認する1”の続き。

Pythonの画像処理ライブラリPillow(PIL)の Image.open でオープンした画像ファイルのフォーマットを確認するということで、前回は、blue.png、 green.png、 red.png の画像ファイルを作成した。今回は、PNG の画像ファイルを ZUBoard 1CG の PYNQ Linux にアップロードし、Jupter Notebook を書き換えて実行したところ、PNG の画像ファイルは 4 チャネルでエラーが出てしまった。

blue.png、 green.png、 red.png の画像ファイルを ZUBoard 1CG の PYNQ Linux にアップロードした。
zub1cg_pynq_208_230827.png

blue.png、 green.png、 red.png の画像ファイルを ~/jupyter_notebooks/examples/i3filters ディレクトリにコピーした。
cd
sudo mv blue.png ~/jupyter_notebooks/examples/i3filters
sudo mv green.png ~/jupyter_notebooks/examples/i3filters
sudo mv red.png ~/jupyter_notebooks/examples/i3filters


~/jupyter_notebooks/examples/i3filters ディレクトリに blue.png、 green.png、 red.png の画像ファイルがコピーされた。
zub1cg_pynq_209_230827.png

blue.png を Image.open() でオープンするように i3filters.ipynb を書き換えた。

#image_path = "./test2.jpg"
image_path = "./blue.png"
#image_path = "./green.png"
#image_path = "./red.png"
original_image = Image.open(image_path)


ガウシアン・フィルタ、メディアン・フィルタ、ソーベル・フィルタはすべてフィルタなしでスルーするように設定した。

gaussian.register_map.row_size = height
gaussian.register_map.col_size = width
gaussian.register_map.function_r = 2 # ORG_IMGwAxiDma
#gaussian.register_map.function_r = 3 # GAUSSIANwAxiDma


median.register_map.row_size = height
median.register_map.col_size = width
median.register_map.function_r = 2 # ORG_IMGwAxiDma
#median.register_map.function_r = 3 # MEDIANwAxiDma


sobel.register_map.row_size = height
sobel.register_map.col_size = width
sobel.register_map.function_r = 2 # ORG_IMGwAxiDma
#sobel.register_map.function_r = 3 # SOBELwAxiDma


これで、i3filters.ipynb を実行していったところ、DMA 用の共有物理メモリに読み込む行でエラーが発生した。
どうやら作成した png には、アルファ・チャネルがあって、RGB と alpha があるようだ。
そこでエラーが出ている。
zub1cg_pynq_210_230827.png
  1. 2023年08月29日 04:17 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

AXI4-Stream Data Width Converter のバイト・レーン変換を確認する1

ZUBoard 1CG の PYNQ v3.0.1 で自作のガウシアン・フィルタ、メディアン・フィルタとソーベル・フィルタを動作させる3”でガウシアン・フィルタの動作を確認できたが、ファイルをロードした 4 バイトのデータは AXI4-Stream Data Width Converter で 4 バイトを 3 バイトに変換してガウシアン・フィルタに入力されている。
このバイト変換は”PYNQ の画像ファイル・フォーマットを調査するために choose_RGB IP を Vitis HLS 2021.2 で作成する8”で解析して、4 バイトのデータが OpenCV の MAT 形式であることは確認してある。(MAT 形式のフォーマットについては、”Vitis Vision Library の AXI4 Master インターフェース版 medianblur をZYBO Z7-20 で使ってみる1(準備編)”を参照)
しかし、”PYNQ の画像ファイル・フォーマットを調査するために choose_RGB IP を Vitis HLS 2021.2 で作成する8”では、4 バイトを 3 バイトに変換した後についての検証が足りなかったので、もう一度、”ZUBoard 1CG の PYNQ v3.0.1 で自作のガウシアン・フィルタ、メディアン・フィルタとソーベル・フィルタを動作させる3”のハードウェアで検証してみよう。

まずは、色が単一の画像ファイルを作成する。
JPEG ファイルが無難だが、画像圧縮されていて、完全にはもとに戻らないので、PNG ファイルを作成してみる。

Ubuntu 22.04 の Pinta アプリケーションで、800 x 600 ピクセルの画像を新規作成する。
パレットからプライマリー色を右クリックすると”プライマリ色の選択”ダイアログが表示される。
赤を 0、緑を 0、青を 255 に変更する。これで青一色の画像になる。
zub1cg_pynq_204_230827.png

プライマリー色をペイント缶で画像全体に適用すると青一色の画像になった。
zub1cg_pynq_205_230827.png

これを blue.png に保存した。

同様に、”プライマリ色の選択”ダイアログで、赤を 255、緑を 0、青を 0 にして、ペイント缶で画像に適用した。
この画像を red.png として、保存した。
zub1cg_pynq_206_230827.png

同様に、”プライマリ色の選択”ダイアログで、赤を 0、緑を 255、青を 0 にして、ペイント缶で画像に適用した。
この画像を green.png として、保存した。
zub1cg_pynq_207_230827.png

今日は寝坊してしまったので、ここまでとする。
  1. 2023年08月28日 05:23 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG の PYNQ v3.0.1 で自作のガウシアン・フィルタ、メディアン・フィルタとソーベル・フィルタを動作させる3

ZUBoard 1CG の PYNQ v3.0.1 で自作のガウシアン・フィルタ、メディアン・フィルタとソーベル・フィルタを動作させる2”の続き。

前回は、i3filters ブロック・デザインの axis_dwidth_converter_0 と axis_dwidth_converter_1 に System ILA を追加して、論理合成、インプリメンテーション、ビットストリームの生成を行って成功した。hwh ファイルと bit ファイルが生成された。今回は、生成されたビット・ファイルと hwh ファイルを ZUBoard 1CG 上の Jupyter Notebook にアップロードし、i3filters.ipynb ファイルを作成して、メディアン・フィルタとソーベル・フィルタの動作を確認したところ動作した。

ZUBoard 1CG の PYNQ Linux の jupyter_notebooks/examples ディレクトリに i3filters ディレクトリを作成した。
cd jupyter_notebooks/examples/
sudo mkdir i3filters


以下のファイルを FileZilla を使って、ZUBoard 1CG の PYNQ Linux のホーム・ディレクトリにアップロードした。
HDL/2023.1/zub1cg/i3filters/i3filters.runs/impl_1/i3filters_wrapper.bit
HDL/2023.1/zub1cg/i3filters/i3filters.gen/sources_1/bd/i3filters/hw_handoff/i3filters.hwh
Vitis_HLS/ZUBoard_1CG/2023.1/gaussian_axis_RGB24/test2.jpg
なお、test2.jpg は通常画像にノイズを拡散させた画像となっている。
zub1cg_pynq_199_230827.png

ファイルをホーム・ディレクトリから jupyter_notebooks/examples/i3filters ディレクトリにコピーした。
cd
sudo mv i3filters.hwh jupyter_notebooks/examples/i3filters
mv i3filters_wrapper.bit jupyter_notebooks/examples/i3filters/i3filters.bit
sudo mv test2.jpg jupyter_notebooks/examples/i3filters


Jupyter Notebook 上で examples/i3filters ディレクトリにノートブックを作成した。
名前を Jupyter Notebook 上で i3filters に変更した。

i3filters.ipynb のコードを”ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる3”から持ってきて、ガウシアン・フィルタ用のコードを追加した。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from pynq import allocate, Overlay

i3filters = Overlay("./i3filters.bit")

dma = i3filters.axi_dma_0
median = i3filters.median_axis_RGB24_0
sobel = i3filters.sobel_axis_RGB24_0
gaussian = i3filters.gaussian_axis_RGB24_0

image_path = "./test2.jpg"
original_image = Image.open(image_path)

canvas = plt.gcf()
size = canvas.get_size_inches()
canvas.set_size_inches(size*2)

width, height = original_image.size
print("Image size: {}x{} pixels.".format(width, height))
plt.figure(figsize=(12, 10));
_ = plt.imshow(original_image)

in_buffer = allocate(shape=(height, width, 3), 
                           dtype=np.uint8, cacheable=1)
out_buffer = allocate(shape=(height, width, 3), 
                            dtype=np.uint8, cacheable=1)
                            
in_buffer[:] = np.array(original_image)

def run_kernel():
    dma.sendchannel.transfer(in_buffer)
    dma.recvchannel.transfer(out_buffer) 
    gaussian.write(0x00,0x01) # start
    median.write(0x00,0x01) # start
    sobel.write(0x00,0x01) # start
    dma.sendchannel.wait()
    dma.recvchannel.wait()
    
print(height)
print(width)

gaussian.register_map.row_size = height
gaussian.register_map.col_size = width
#gaussian.register_map.function_r = 2 # ORG_IMGwAxiDma
gaussian.register_map.function_r = 3 # GAUSSIANwAxiDma

median.register_map.row_size = height
median.register_map.col_size = width
median.register_map.function_r = 2 # ORG_IMGwAxiDma
#median.register_map.function_r = 3 # MEDIANwAxiDma

sobel.register_map.row_size = height
sobel.register_map.col_size = width
#sobel.register_map.function_r = 2 # ORG_IMGwAxiDma
sobel.register_map.function_r = 3 # SOBELwAxiDma

run_kernel()
sobel_image = Image.fromarray(out_buffer)

print("Image size: {}x{} pixels.".format(width, height))
plt.figure(figsize=(12, 10));
_ = plt.imshow(sobel_image)

del in_buffer
del out_buffer


i3filters.ipynb を実行した結果を示す。
ガウシアン・フィルタでノイズを除去しながらソーベル・フィルタでエッジを抽出する。
やはり、メディアン・フィルタ程はノイズが除去できていない
zub1cg_pynq_200_230827.png
zub1cg_pynq_201_230827.png
zub1cg_pynq_202_230827.png
zub1cg_pynq_203_230827.png
  1. 2023年08月27日 04:51 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG の PYNQ v3.0.1 で自作のガウシアン・フィルタ、メディアン・フィルタとソーベル・フィルタを動作させる2

ZUBoard 1CG の PYNQ v3.0.1 で自作のガウシアン・フィルタ、メディアン・フィルタとソーベル・フィルタを動作させる1”の続き。

前回は、”RGB 24 ビットの AXI4-Stream データ入出力対応のガウシアン・フィルタを Vitis HLS 2023.1 で作成する2”でガウシアン・フィルタ IP が生成できた。その gaussian_axis_RGB24 IP を”ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる1”のソーベル・フィルタとメディアン・フィルタの回路に追加した。今回は、i3filters ブロック・デザインの axis_dwidth_converter_0 と axis_dwidth_converter_1 に System ILA を追加して、論理合成、インプリメンテーション、ビットストリームの生成を行って成功した。hwh ファイルと bit ファイルが生成された。

Vivado 2023.1 の Source ウインドウで i3filters_i を右クリックし右クリックメニューから Create HDL Wrapper... を選択して、ブロック・デザインの HDL Wrapper を作成した。
zub1cg_pynq_191_230822.png

axis_dwidth_converter_0 と axis_dwidth_converter_1 の S_AXIS と M_AXIS の配線を選択し、右クリックして、右クリックメニューから Debug を選択する。
zub1cg_pynq_193_230826.png

Run Connection Automation をクリックし、Run Connection Automation ダイアログを表示させる。
デフォルトのままOK ボタンをクリックする。
zub1cg_pynq_194_230826.png

axis_dwidth_converter_0 と axis_dwidth_converter_1 の S_AXIS と M_AXIS の配線に system_ila_0 が追加された。
zub1cg_pynq_195_230826.png

PROJECT MNAGER から PROGRAM AND DEBUG -> Generate Bitstream をクリックし、論理合成、インプリメンテーション、ビットストリームの生成を行った。成功だ。
Project Summary を示す。
zub1cg_pynq_196_230826.png

HDL/2023.1/zub1cg/i3filters/i3filters.gen/sources_1/bd/i3filters/hw_handoff ディレクトリに i3filters.hwh ファイルが生成された。
zub1cg_pynq_197_230826.png

HDL/2023.1/zub1cg/i3filters/i3filters.runs/impl_1 ディレクトリに i3filters_wrapper.bit ファイルが生成された。
zub1cg_pynq_198_230826.png
  1. 2023年08月26日 16:25 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG の PYNQ v3.0.1 で自作のガウシアン・フィルタ、メディアン・フィルタとソーベル・フィルタを動作させる1

RGB 24 ビットの AXI4-Stream データ入出力対応のガウシアン・フィルタを Vitis HLS 2023.1 で作成する2”でガウシアン・フィルタ IP が生成できた。その gaussian_axis_RGB24 IP を”ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる1”のソーベル・フィルタとメディアン・フィルタの回路に追加した。

ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる1”の median_sobel ブロック・デザインを tcl ファイルに出力する。

Vivado 2023.1 の median_sobel プロジェクトで、File メニューから Export -> Export Block Design... を選択する。

Export Block Design ダイアログが表示された。
OK ボタンをクリックする。

プロジェクトのディレクトリに median_sobel.tcl ファイルが出力された。
この tcl ファイルを実行すると median_sobel ブロック・デザインが生成される。

ZUBoard 1CG 用の Vivado 2023.1 の i3filters プロジェクトを作成した。
zub1cg_pynq_184_230822.png

i3filters プロジェクトのディレクトリに先程作成した median_sobel.tcl をコピーして、名前を i3filters.tcl に変更した。
i3filters.tcl を開いて”set design_name medain_sobel”から”set design_name i3filters”に変更した。
zub1cg_pynq_185_230822.png

median_sobel プロジェクトのディレクトリから sobel_axis_RGB24 IP と median_axis_RGB24 IP のディレクトリを i3filters ディレクトリにコピーした。
gaussian_axis_RGB24 ディレクトリを新規作成した。
gaussian_axis_RGB24 ディレクトリに””RGB 24 ビットの AXI4-Stream データ入出力対応のガウシアン・フィルタを Vitis HLS 2023.1 で作成する2”で作成した gaussian_axis_RGB24/solution1/impl/export.zip の内容をコピーした。
zub1cg_pynq_186_230822.png

Vivado の Flow Navigator から IP Catalog をクリックした。
IP Catalog ウインドウが開く。
右クリックし、右クリックメニューから Add Repository を選択し、sobel_axis_RGB24 と median_axis_RGB24、gaussian_axis_RGB24 を選択して、IP を追加した。
zub1cg_pynq_187_230822.png

Vivado 2023.1 の Tcl Console で次のコマンドを実行した。
cd /media/masaaki/Ubuntu_Disk/HDL/2023.1/zub1cg/i3filters/
source i3filters.tcl


すると、メディアン・フィルタとソーベル・フィルタの回路が生成された。
zub1cg_pynq_188_230822.png

+アイコンをクリックして、gaussian_axis_RGB24 IP を追加した。
配線を行って、回路が完成した。
i3filers ブロック・デザインを示す。
zub1cg_pynq_189_230822.png

Address Editor 画面を示す。
zub1cg_pynq_190_230822.png
  1. 2023年08月25日 04:22 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

家のパソコンを Ubuntu 20.04 から Ubuntu 22.04 にアップグレードしたら Google chrome のアイコンが無くなった

職場のパソコンと自宅のパソコンを Ubuntu 20.04 にアップグレードした”でウインドウのキャプチャに問題が生じたので、職場と家のパソコンを Ubuntu 22.04 にアップグレードしたのですが、家のパソコンは Chrome を起動しながらアップグレードしたので、chrome のアイコンがランチャーにどうしても入らなくなってしまった。

家のパソコンを sudo do-release-upgrade コマンドでアップグレードした。
Ubuntu2204_1_230823.png
Ubuntu2204_2_230823.png

そのときに Google Chrome ブラウザを見ながらUbuntu 22.04 にアップグレードしたのがまずかったのか? Ubuntu 22.04 を起動したら Google Chrome ブラウザのアイコンが無くなっていた。
Google Chrome をアンインストールして再度インストールしてもアイコンが表示されない。
諦めてコマンドで Google Chrome を起動することにした。
/opt/google/chrome/chrome

Google Chrome のアイコンはランチャーに入っていないが、コマンドで起動すれば良さそうなので、これで良いことにする。どうせ、Google Chrome は常に起動しているし。。。

あー、とっても焦ってしまった。。。それに糊代の問題は解決できていない。
  1. 2023年08月24日 04:07 |
  2. パソコン関連
  3. | トラックバック:0
  4. | コメント:0

職場のパソコンと自宅のパソコンを Ubuntu 20.04 にアップグレードした

職場のパソコンと自宅のパソコンは AMD/Xilinx 社のチュートリアルをやるために Ubuntu 18.04 にしていたのだが、サポート期間が今年の 5 月で切れているということで、Ubuntu 20.04 にアップグレードした。

どうもアップデートが Chrome のアップデートしか無いな。。。と思っていたら、Ubuntu 18.04 のサポート期間が今年の 5 月で切れていたようだ。。。orz
ということで、遅ればせながら、職場のパソコンと自宅のパソコンを Ubuntu 20.04 にアップグレードした。こちらは、2025 年までサポートされるようなので、またサポート期間が終了したらアップグレードしよう。

ところで、Ubuntu 20.04 でブログを書くため Vivado などの画面をキャプチャするのだが、CRTL-ALT-Print Screen キーやスクリーンショット・アプリでウインドウを画面キャプチャした時に余計な糊代?が入ってしまう。
Ubuntu2004_1_230823.png

この糊代?が邪魔でいちいち範囲指定して切り取っている。
Ubuntu 18.04 に比べるとブログを書くのがひと手間増えてしまったが、対応策は無いものなんだろうか?
Ubuntu 22.04 にアップグレードすると直るのだろうか?
何か対応策をご存知でしたら、コメント欄で教えください。よろしくお願いいたします。
  1. 2023年08月23日 04:29 |
  2. パソコン関連
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2023年8月22日)

FPGAの部屋のまとめ サイト”を更新しました。
8月22日までの記事をまとめました。
  1. 2023年08月22日 05:20 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

RGB 24 ビットの AXI4-Stream データ入出力対応のガウシアン・フィルタを Vitis HLS 2023.1 で作成する2

RGB 24 ビットの AXI4-Stream データ入出力対応のガウシアン・フィルタを Vitis HLS 2023.1 で作成する1”の続き。

RGB 24 ビットの AXI4-Stream データ入出力対応のソーベル・フィルタを Vitis HLS 2023.1 で作成するということで、前回は、ソースコードとテストベンチコードを貼って、Vitis HLS 2023.1 で gaussian_axis_RGB24 プロジェクトを作成した。今回は、gaussian_axis_RGB24 プロジェクトで、C シミュレーション、C コードの合成、C/RTL 協調シミュレーション、Export RTL、Implementation を行った。

C シミュレーションを行った。結果を示す。
zub1cg_pynq_174_230820.png

gaussian_axis_RGB24/solution1/csim/build ディレクトリを示す。
gaussian.jpg と org.jpg が生成されている。
zub1cg_pynq_175_230820.png

org.jpg は gaussian_axis_RGB24 の col_size 変数に ORG_IMGwAxiDma を指定した時の出力となる。つまり元画像と同じ画像ファイルであるはずだ。
org.jpg を示す。ノイズが拡散されているのが分かると思う。
zub1cg_pynq_176_230820.jpg

ノイズが拡散された元画像に 3 x 3 のガウシアン・フィルタをかけた画像が gaussian.jpg となる。
gaussian.jpg を示す。拡散されたノイズがメディアン・フィルタほどではないがある程度取れて、綺麗な画像になっていることが分かる。
zub1cg_pynq_177_230820.jpg

C コードの合成を行った。結果を示す。
zub1cg_pynq_178_230820.png
zub1cg_pynq_179_230820.png

gaussian_axis_RGB24_Pipeline_LOOP_Y_LOOP_X の LOOP_Y_LOOP_X の Interval が 1 クロックとなっていて、メディアン・フィルタの出力が 1 クロック毎に 1 出力がでるようだ。問題無さそうだ。

C/RTL 協調シミュレーションを行った。結果を示す。
zub1cg_pynq_180_230820.png

Avg II が 480057 クロックだった。画像サイズは 800 x 600 = 480000 ピクセルなので、ほぼ 1 ピクセル / クロックとなっているようだ。

C/RTL 協調シミュレーションの波形を示す。
全体波形を示す。
zub1cg_pynq_181_230820.png

outs_TVALID もほぼ 1 でスループットが高いことが分かる。

最初の波形を拡大する。
zub1cg_pynq_182_230820.png

ins_TREADY を見ると、最初はディアサートされている期間があることが分かるが、それが過ぎたら、1 のままになっている。

Export RTL を行った。

Implementation を行って、Vivado で実装した時の性能を確認した。
結果を示す。
zub1cg_pynq_183_230820.png

CP achieved post-implementaion は 4.957 ns で動作周波数の 10 ns よりも小さく、2 倍のクロックで動作しそうだ。
ガウシアン・フィルタの演算は 2 の n 乗の計算で、演算器が楽に組めるのだと思う。
  1. 2023年08月20日 04:37 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

RGB 24 ビットの AXI4-Stream データ入出力対応のガウシアン・フィルタを Vitis HLS 2023.1 で作成する1

RGB 24 ビットの AXI4-Stream データ入出力対応のソーベル・フィルタを Vitis HLS 2023.1 で作成した。

2023/09/21: 修正: 出力のカラーが RBG になっていたので、RGB に修正した。

最初にヘッダ・ファイルとソースコードを示す。
ヘッダ・ファイルの gaussian_axis_RGB24.h を示す。

// gaussian_axis_RGB24.h
// 2023/08/18 by marsee
//

#ifndef __GAUSSIAN_FILTER_AXIS_RGB24_H__
#define __GAUSSIAN_FILTER_AXIS_RGB24_H__

#define HORIZONTAL 0
#define VERTICAL 1

#define ORG_IMGwAxiVdma 0
#define GAUSSIANwAxiVdma   1
#define ORG_IMGwAxiDma  2
#define GAUSSIANwAxiDma    3

#endif


ソースコードの gaussian_axis_RGB24.cpp を示す。

// median_axis_RGB24.cpp
// 2023/08/18 by marsee
//

#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "gaussian_axis_RGB24.h"

constexpr int size = 3;

void gaussian_fil(ap_int<32> (&pix_mat)[size][size], ap_uint<24> &result);
ap_int<32> gaussian_fil_calc(ap_int<32> *pixd);
ap_int<32> separate_rgb(ap_int<32> rgb, ap_int<32> &r, ap_int<32> &g, ap_int<32> &b);

int gaussian_axis_RGB24(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int32_t function,
         int32_t row_size, int32_t col_size){
#pragma HLS INTERFACE mode=s_axilite port=col_size
#pragma HLS INTERFACE mode=s_axilite port=row_size
#pragma HLS INTERFACE mode=s_axilite port=function
#pragma HLS INTERFACE mode=axis register_mode=both port=outs register
#pragma HLS INTERFACE mode=axis register_mode=both port=ins register
#pragma HLS INTERFACE mode=s_axilite port=return

    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> gaussian;
    ap_uint<24> val;

    ap_int<32> line_buf[2][1920];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1

    ap_int<32> pix_mat[size][size];
#pragma HLS array_partition variable=pix_mat complete

    LOOP_WAIT_USER : do {   // user が 1になった時にフレームがスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins >> pix;
        if(function==ORG_IMGwAxiDma || function==GAUSSIANwAxiDma)
            break;
    } while(pix.user == 0);

    LOOP_Y: for(int y=0; y<row_size; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=1080 min=48
        LOOP_X: for(int x=0; x<col_size; x++){
#pragma HLS LOOP_TRIPCOUNT avg=800 max=1920 min=64
#pragma HLS PIPELINE II=1
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix; // AXI4-Stream からの入力

            LOOP_PIX_MAT_K: for(int k=0; k<3; k++){
                LOOP_PIX_MAT_M: for(int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];
            ap_int<32> y_val = pix.data;
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            gaussian_fil(pix_mat, val);
            gaussian.data = val;
            if(x<2 || y<2)
                gaussian.data = 0;

            if(function==ORG_IMGwAxiVdma || function == GAUSSIANwAxiVdma){
                if(x==0 && y==0) // 最初のピクセル
                    gaussian.user = 1;
                else
                    gaussian.user = 0;
                if(x == (col_size-1)) // 行の最後
                    gaussian.last = 1;
                else
                    gaussian.last = 0;
            }else{
                gaussian.user = 0;
                gaussian.last = pix.last;
            }
            gaussian.keep = 0x7;
            gaussian.strb = 0x7;
            if(function==GAUSSIANwAxiVdma || function==GAUSSIANwAxiDma)
                outs << gaussian;
            else
                outs << pix;
        }
    }
    return(0);
}

// gaussian filter
//
// x0y0 x1y0 x2y0  1/16  2/16  1/16
// x0y1 x1y1 x2y1  2/16  4/16  2/16
// x0y2 x1y2 x2y2  1/16  2/16  1/16
//
void gaussian_fil(ap_int<32> (&pix_mat)[size][size], ap_uint<24> &result){
    ap_int<32> pix_1d_r[9], pix_1d_b[9], pix_1d_g[9];
    ap_int<32> y_r, y_b, y_g, y;

    for(int i=0; i<9; i++){
        separate_rgb(pix_mat[i/3][i%3], pix_1d_r[i], pix_1d_g[i], pix_1d_b[i]);
    }

    y_r = gaussian_fil_calc(pix_1d_r);
    y_b = gaussian_fil_calc(pix_1d_b);
    y_g = gaussian_fil_calc(pix_1d_g);

    result = (y_r << 16) + (y_g << 8) + y_b;
}

// gaussian_fil_calc
ap_int<32> gaussian_fil_calc(ap_int<32> *pixd){
    ap_int<32> y;

    y = pixd[0] + 2 * pixd[1] + pixd[2] + 2 * pixd[3] + 4 * pixd[4] + 2 * pixd[5] + pixd[6] + 2 * pixd[7] + pixd[8];
    y = y / 16;

    if(y<0)
        y = -y;
        //y = 0;
    else if(y>255) // 8 bits
        y = 255;
    return(y);
}

// separate_rgb
// RGBを分離する
// RBGのフォーマットは、{R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
//
ap_int<32> separate_rgb(ap_int<32> rbg, ap_int<32> &r, ap_int<32> &g, ap_int<32> &b){
    b = rbg & 0xff;
    g = (rbg>>8) & 0xff;
    r = (rbg>>16) & 0xff;
    return(0);
}


テストベンチの gaussian_axis_RGB24_tb.cpp を示す。

// gaussian_axis_RGB24_tb.cpp
// 2023/08/18 by marsee
// GAUSSIANwXilinxVideoStandard を define すると axi_vdma 用となり、コメントアウトすると axi_dma 用になる
//

#include <stdio.h>
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs/imgcodecs.hpp"

#include "gaussian_axis_RGB24.h"

//#define GAUSSIANwXilinxVideoStandard

constexpr int size = 3;

int gaussian_axis_RGB24(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int32_t function,
         int32_t row_size, int32_t col_size);
int gaussian_axis_RGB24_soft(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int32_t function,
         int32_t row_size, int32_t col_size);
void gaussian_fil_soft(ap_int<32> (&pix_mat)[size][size], ap_uint<24> &result);
ap_int<32> gaussian_fil_calc_soft(ap_int<32> *pixd);
ap_int<32> separate_rgb_soft(ap_int<32> rgb, ap_int<32> &r, ap_int<32> &g, ap_int<32> &b);

const char INPUT_JPG_FILE[] = "test2.jpg";
const char OUTPUT_JPG_FILE[] = "gaussian.jpg";
const char ORG_OUT_JPG_FILE[] = "org.jpg";

int main(){
    hls::stream<ap_axiu<24,1,1,1> > ins, ins2;
    hls::stream<ap_axiu<24,1,1,1> > ins_soft;
    hls::stream<ap_axiu<24,1,1,1> > outs, outs2;
    hls::stream<ap_axiu<24,1,1,1> > outs_soft;
    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> vals, vals_soft;

    // JPG ファイルをMat に読み込む
    cv::Mat img = cv::imread(INPUT_JPG_FILE);

    // ピクセルを入れる領域の確保
    std::vector<int32_t> rd_bmp(sizeof(int32_t)*img.cols*img.rows);
    std::vector<int32_t> hw_gaussian(sizeof(int32_t)*(img.cols)*(img.rows));
    std::vector<int32_t> sw_gaussian(sizeof(int32_t)*(img.cols)*(img.rows));

    // rd_bmp にJPGのピクセルを代入
    cv::Mat_<cv::Vec3b> dst_vec3b = cv::Mat_<cv::Vec3b>(img);
    for (int y=0; y<img.rows; y++){
        for (int x=0; x<img.cols; x++){
            cv::Vec3b pixel;
            pixel = dst_vec3b(y,x);
            rd_bmp[y*img.cols+x] = (pixel[0] & 0xff) | ((pixel[1] & 0xff)<<8) | ((pixel[2] & 0xff)<<16); // RGB 8 bits
            // blue - pixel[0]; green - pixel[1]; red - pixel[2];
        }
    }

#ifdef GAUSSIANwXilinxVideoStandard
    // ins に入力データを用意する
    for(int i=0; i<5; i++){ // dummy data
        pix.user = 0;
        pix.data = i;
        pix.last = 0;
        pix.user = 0;
        pix.keep = 0x7;
        pix.strb = 0x7;
        ins << pix;
    }
#endif

    for(int j=0; j < img.rows; j++){
        for(int i=0; i < img.cols; i++){
            pix.data = (int32_t)rd_bmp[(j*img.cols)+i];
#ifdef GAUSSIANwXilinxVideoStandard
            if (j==0 && i==0)   // 最初のデータの時に TUSER を 1 にする
                pix.user = 1;
            else
                pix.user = 0;

            if (i == img.cols-1) // 行の最後でTLASTをアサートする
                pix.last = 1;
            else
                pix.last = 0;
#else
            if(j==img.rows-1 && i==img.cols-1)
                pix.last = 1;
            else
                pix.last = 0;
            pix.user = 0;
#endif
            pix.keep = 0x7;
            pix.strb = 0x7;

            ins << pix;
            ins2 << pix;
            ins_soft << pix;
        }
    }

#ifdef GAUSSIANwXilinxVideoStandard
    gaussian_axis_RGB24(ins, outs, GAUSSIANwAxiVdma, img.rows, img.cols); // ハードウェアのメディアンフィルタ
    gaussian_axis_RGB24_soft(ins_soft, outs_soft, GAUSSIANwAxiVdma, img.rows, img.cols);  // ソフトウェアのメディアンフィルタ
#else
    gaussian_axis_RGB24(ins, outs, GAUSSIANwAxiDma, img.rows, img.cols); // ハードウェアのメディアンフィルタ
    gaussian_axis_RGB24_soft(ins_soft, outs_soft, GAUSSIANwAxiDma, img.rows, img.cols);  // ソフトウェアのメディアンフィルタ
#endif

    // ハードウェアとソフトウェアのメディアンフィルタの値のチェック
    for (int y=0; y<img.rows; y++){ // 結果の画像サイズはx-2, y-2
        for (int x=0; x<img.cols; x++){
            outs >> vals;
            outs_soft >> vals_soft;
            ap_uint<32> val = vals.data;
            hw_gaussian[y*img.cols+x] = (int32_t)val;
            if (val != vals_soft.data){
                printf("ERROR HW and SW results mismatch x = %ld, y = %ld, HW = %x, SW = %x\n",
                        x, y, val, vals_soft.data);
                return(1);
            }
        }
    }
    printf("Success HW and SW results match\n");

    const int gaussian_row = img.rows;
    const int gaussian_cols = img.cols;
    cv::Mat wbmpf(gaussian_row, gaussian_cols, CV_8UC3);
    // wbmpf にgaussian フィルタ処理後の画像を入力
    cv::Mat_<cv::Vec3b> sob_vec3b = cv::Mat_<cv::Vec3b>(wbmpf);
    for (int y=0; y<wbmpf.rows; y++){
        for (int x=0; x<wbmpf.cols; x++){
            cv::Vec3b pixel;
            pixel = sob_vec3b(y,x);
            int32_t rbg = hw_gaussian[y*wbmpf.cols+x];
            pixel[0] = ((rbg >> 8) & 0xff); // blue
            pixel[1] = (rbg & 0xff); // green
            pixel[2] = ((rbg >> 16) & 0xff); // red
            sob_vec3b(y,x) = pixel;
        }
    }

    // ハードウェアのメディアンフィルタの結果を jpg ファイルへ出力する
    cv::imwrite(OUTPUT_JPG_FILE, wbmpf);

#ifdef GAUSSIANwXilinxVideoStandard
    gaussian_axis_RGB24(ins2, outs2, ORG_IMGwAxiVdma, img.rows, img.cols); // ハードウェアのメディアンフィルタ
#else
    gaussian_axis_RGB24(ins2, outs2, ORG_IMGwAxiDma, img.rows, img.cols); // ハードウェアのメディアンフィルタ
#endif

    cv::Mat wbmpf2(gaussian_row, gaussian_cols, CV_8UC3);
    // wbmpf2 に元画像を入力
    sob_vec3b = cv::Mat_<cv::Vec3b>(wbmpf2);
    for (int y=0; y<wbmpf.rows; y++){
        for (int x=0; x<wbmpf.cols; x++){
            cv::Vec3b pixel;
            pixel = sob_vec3b(y,x);
            outs2 >> vals;
            int32_t val = vals.data;
            pixel[0] = (val & 0xff); // blue
            pixel[1] = ((val >> 8) & 0xff); // green
            pixel[2] = ((val >> 16) & 0xff); // red
            sob_vec3b(y,x) = pixel;
        }
    }

    // 元画像を jpg ファイルへ出力する
    cv::imwrite(ORG_OUT_JPG_FILE, wbmpf2);

    return(0);
}

int gaussian_axis_RGB24_soft(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int32_t function,
         int32_t row_size, int32_t col_size){

    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> gaussian;
    ap_uint<24> val;

    ap_int<32> line_buf[2][1920];

    ap_int<32> pix_mat[size][size];

    LOOP_WAIT_USER : do {   // user が 1になった時にフレームがスタートする
        ins >> pix;
        if(function==ORG_IMGwAxiDma || function==GAUSSIANwAxiDma)
            break;
    } while(pix.user == 0);

    for(int y=0; y<row_size; y++){
        for(int x=0; x<col_size; x++){
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix; // AXI4-Stream からの入力

            LOOP_PIX_MAT_K: for(int k=0; k<3; k++){
                LOOP_PIX_MAT_M: for(int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];
            ap_int<32> y_val = pix.data;
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            gaussian_fil_soft(pix_mat, val);
            gaussian.data = val;
            if(x<2 || y<2)
                gaussian.data = 0;

            if(function==ORG_IMGwAxiVdma || function == GAUSSIANwAxiVdma){
                if(x==0 && y==0) // 最初のピクセル
                    gaussian.user = 1;
                else
                    gaussian.user = 0;
                if(x == (col_size-1)) // 行の最後
                    gaussian.last = 1;
                else
                    gaussian.last = 0;
            }else{
                gaussian.user = 0;
                gaussian.last = pix.last;
            }
            gaussian.keep = 0x7;
            gaussian.strb = 0x7;
            if(function==GAUSSIANwAxiVdma || function==GAUSSIANwAxiDma)
                outs << gaussian;
            else
                outs << pix;
        }
    }
    return(0);
}

// gaussian filter
//
// x0y0 x1y0 x2y0  1/16  2/16  1/16
// x0y1 x1y1 x2y1  2/16  4/16  2/16
// x0y2 x1y2 x2y2  1/16  2/16  1/16
//
void gaussian_fil_soft(ap_int<32> (&pix_mat)[size][size], ap_uint<24> &result){
    ap_int<32> pix_1d_r[9], pix_1d_g[9], pix_1d_b[9];
    ap_int<32> y_r, y_b, y_g, y;

    for(int i=0; i<9; i++){
        separate_rgb_soft(pix_mat[i/3][i%3], pix_1d_r[i], pix_1d_g[i], pix_1d_b[i]);
    }

    y_r = gaussian_fil_calc_soft(pix_1d_r);
    y_b = gaussian_fil_calc_soft(pix_1d_b);
    y_g = gaussian_fil_calc_soft(pix_1d_g);

    result = (y_r << 16) + (y_g << 8) + y_b;
}

// gaussian_fil_calc
ap_int<32> gaussian_fil_calc_soft(ap_int<32> *pixd){
    ap_int<32> y;

    y = pixd[0] + 2 * pixd[1] + pixd[2] + 2 * pixd[3] + 4 * pixd[4] + 2 * pixd[5] + pixd[6] + 2 * pixd[7] + pixd[8];
    y = y / 16;

    if(y<0)
        y = -y;
        //y = 0;
    else if(y>255) // 8 bits
        y = 255;
    return(y);
}

// separate_rgb
// RGBを分離する
// RBGのフォーマットは、{R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
//
ap_int<32> separate_rgb_soft(ap_int<32> rbg, ap_int<32> &r, ap_int<32> &g, ap_int<32> &b){
    b = rbg & 0xff;
    g = (rbg>>8) & 0xff;
    r = (rbg>>16) & 0xff;
    return(0);
}


Vitis HLS 2023.1 で gaussian_axis_RGB24 プロジェクトを作成した。このプロジェクトは ZUBoard 1CG 用だ。
zub1cg_pynq_173_230818.png

今回のテストベンチ・コードでは OpenCV ライブラリを使用している。
Vitis HLS 2023.1 には内蔵された OpenCV は無いので、別にインストールした OpenCV を指定する。
Vitis HLS の Project メニューから Project Settings... を選択して、Project Settings ダイアログを開いた。
Simulation タブを開いて、sobel_axis_RGB24_tb.cpp の CFLAGS に

-I/usr/local/include

を設定した。
Linker Flags に

-L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc

を設定した。

更に、 Synthesis をクリックして、 Top Function に gaussian_axis_RGB24 を指定した。
  1. 2023年08月19日 04:00 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

AVNET からダウンロードした BSP を使って、Petalinux プロジェクトを作成して、xmutil をやってみたがやはりエラーだった(Ver. 2022.1)

AVNET からダウンロードした BSP を使って、Petalinux プロジェクトを作成して、xmutil をやってみたがやはりエラーだった”で Ver. 2022.2 の BSP をダウンロードして、Petalinux 2022.2 でやってみたが、エラーだった。今回は、Ver. 2022.1 の BSP をダウンロードして、Petalinux 2022.1 でやってみたが、エラーだった。

Ver. 2022.2 の BSP を AVNET のサイトからダウンロードし、”AVNET からダウンロードした BSP を使って、Petalinux プロジェクトを作成して、xmutil をやってみたがやはりエラーだった”の手順で構築していった。

できあがった rootfs.wic を balenaEtcher で MicroSD カードに書き込んだ。
書き込んだ MicroSD カードの /home/petalinux 上に binary_container_1.xclbin, pl.dtbo, pl.dtbi, shell.json, zub1cg_sbc_vadd をコピーした。
ZUBoard1CG_207_230817.png

ZUBoard 1CG で Petalinux 2022.2 を起動した。
ホーム・ディレクトリに examples/zub1cg_sbc_vadd ディレクトリを作成した。
cd
mkdir examples
cd examples
mkdir zub1cg_sbc_vadd
cd zub1cg_sbc_vadd


FileZilla を起動して、ZUBoard 1CG の Petalinux 2022.2 へ SFTP で vadd_file_transfer ディレクトリのファイルを転送した。

/lib/firmware/xilinx/zub1cg_sbc_vadd ディレクトリを作成した。
sudo mkdir /lib/firmware/xilinx/zub1cg_sbc_vadd

binary_container_1.xclbin の名前を binary_container_1.bin に変更する。こうしないと、XRT は FPGA ビットストリームを抽出して Kria のプログラマブル ロジックをコンフィグレーションすることができないそうだ。
mv binary_container_1.xclbin binary_container_1.bin

pl.dtbo binary_container_1.bin shell.json ファイルを /lib/firmware/xilinx/zub1cg_sbc_vadd ディレクトリにコピーした。
sudo cp pl.dtbo binary_container_1.bin shell.json /lib/firmware/xilinx/zub1cg_sbc_vadd

アクセラレーション・アプリケーションを確認して、zub1cg_sbc_vadd をロードしたところエラーになった。
sudo xmutil loadapp zub1cg_sbc_vadd
ZUBoard1CG_208_230817.png

Ver. 2022.1 でもダメだった。この方法ではダメそうだ。
  1. 2023年08月18日 10:59 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる3

ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる2”の続き。

RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成する2”で作成したメディアン・フィルタを使ってみようということで、前回は、作成したブロック・デザインの HDL Wrapper ファイルを作成し、論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。hwh ファイルと bit ファイルが生成された。今回は、生成されたビット・ファイルと hwh ファイルを ZUBoard 1CG 上の Jupyter Notebook にアップロードし、median_sobel.ipynb ファイルを作成して、メディアン・フィルタとソーベル・フィルタの動作を確認したところ動作した。

ZUBoard 1CG の PYNQ Linux の jupyter_notebooks/examples ディレクトリに median_sobel ディレクトリを作成した。
cd jupyter_notebooks/examples/
sudo mkdir median_sobel


以下のファイルを FileZilla を使って、ZUBoard 1CG の PYNQ Linux のホーム・ディレクトリにアップロードした。
HDL/2023.1/zub1cg/medain_sobel/medain_sobel.runs/impl_1/median_sobel_wrapper.bit
HDL/2023.1/zub1cg/medain_sobel/medain_sobel.gen/sources_1/bd/median_sobel/hw_handoff/median_sobel.hwh
Vitis_HLS/ZUBoard_1CG/2023.1/median_axis_RGB24/test2.jpg
なお、test2.jpg は通常画像にノイズを拡散させた画像となっている。
zub1cg_pynq_165_230816.png

ファイルをホーム・ディレクトリから jupyter_notebooks/examples/median_sobel ディレクトリにコピーした。
cd
sudo mv median_sobel.hwh jupyter_notebooks/examples/median_sobel
mv median_sobel_wrapper.bit jupyter_notebooks/examples/median_sobel/median_sobel.bit
sudo mv test2.jpg jupyter_notebooks/examples/median_sobel


Jupyter Notebook で examples/median_sobel ディレクトリを見た。
zub1cg_pynq_166_230816.png

Jupyter Notebook 上で examples/median_sobel ディレクトリにノートブックを作成した。
名前を Jupyter Notebook 上で median_sobel に変更しようとしたが、どうしてもできない。
ターミナルで jupyter_notebooks/examples/median_sobel ディレクトリに行って、mv コマンドで名前を変更した。
cd jupyter_notebooks/examples/median_sobel
sudo mv Untitled.ipynb median_sobel.ipynb

zub1cg_pynq_167_230816.png

median_sobel.ipynb のコードを”KV260 の PYNQ で自作のメディアン・フィルタとソーベル・フィルタを動作させる2”からコピーして、一部修正した。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from pynq import allocate, Overlay

median_sobel = Overlay("./median_sobel.bit")

dma = median_sobel.axi_dma_0
median = median_sobel.median_axis_RGB24_0
sobel = median_sobel.sobel_axis_RGB24_0

image_path = "./test2.jpg"
original_image = Image.open(image_path)

canvas = plt.gcf()
size = canvas.get_size_inches()
canvas.set_size_inches(size*2)

width, height = original_image.size
print("Image size: {}x{} pixels.".format(width, height))
plt.figure(figsize=(12, 10));
_ = plt.imshow(original_image)

in_buffer = allocate(shape=(height, width, 3), 
                           dtype=np.uint8, cacheable=1)
out_buffer = allocate(shape=(height, width, 3), 
                            dtype=np.uint8, cacheable=1)

in_buffer[:] = np.array(original_image)

def run_kernel():
    dma.sendchannel.transfer(in_buffer)
    dma.recvchannel.transfer(out_buffer) 
    median.write(0x00,0x01) # start
    sobel.write(0x00,0x01) # start
    dma.sendchannel.wait()
    dma.recvchannel.wait()

print(height)
print(width)

median.register_map.row_size = height
median.register_map.col_size = width
#median.register_map.function_r = 2 # ORG_IMGwAxiDma
median.register_map.function_r = 3 # MEDIANwAxiDma

sobel.register_map.row_size = height
sobel.register_map.col_size = width
#sobel.register_map.function_r = 2 # ORG_IMGwAxiDma
sobel.register_map.function_r = 3 # SOBELwAxiDma

run_kernel()
sobel_image = Image.fromarray(out_buffer)

print("Image size: {}x{} pixels.".format(width, height))
plt.figure(figsize=(12, 10));
_ = plt.imshow(sobel_image)

del in_buffer
del out_buffer


最初に

median.register_map.function_r = 3 # MEDIANwAxiDma

sobel.register_map.function_r = 3 # SOBELwAxiDma

でやってみた結果を示す。
つまり、メディアン・フィルタでノイズを除去しながら、ソーベル・フィルタでエッジを抽出する。
zub1cg_pynq_168_230816.png
zub1cg_pynq_169_230816.jpg
zub1cg_pynq_170_230816.png
zub1cg_pynq_171_230816.jpg

次に、

median.register_map.function_r = 2 # ORG_IMGwAxiDma

sobel.register_map.function_r = 3 # SOBELwAxiDma

でやってみた結果を示す。
つまり、メディアン・フィルタを掛けずにソーベル・フィルタでエッジを抽出する。
zub1cg_pynq_172_230816.jpg

ノイズもエッジを抽出されている。
  1. 2023年08月16日 06:47 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる2

ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる1”の続き。

RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成する2”で作成したメディアン・フィルタを使ってみようということで、前回は、medain_axis_RGB24 IP を”ZUBoard 1CG の PYNQ v3.0.1 で自作のソーベル・フィルタを動作させる1”で作成したブロック・デザインに追加した。今回は、作成したブロック・デザインの HDL Wrapper ファイルを作成し、論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。hwh ファイルと bit ファイルが生成された。

median_sobel ブロック・デザインの HDL Wrapper ファイルを生成する。
Vivado 2023.1 で Source タブをクリックして Source ウインドウを表示し、Desgin Sources の median_sobel_i を右クリックし右クリックメニューから Create HDL Wrapper... を選択し、HDL Wrapper ファイルの median_sobel_wrapper.v を生成した。
zub1cg_pynq_161_230815.png

Flow Navigator で PROGRAM AND DEBUG -> Generate Bitstream をクリックし、論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。
Project Summary を示す。
zub1cg_pynq_162_230815.png

HDL/2023.1/zub1cg/medain_sobel/medain_sobel.runs/impl_1 ディレクトリに median_sobel_wrapper.bit ファイルが生成された。
zub1cg_pynq_164_230815.png

HDL/2023.1/zub1cg/medain_sobel/medain_sobel.gen/sources_1/bd/median_sobel/hw_handoff ディレクトリに median_sobel.hwh ファイルが生成された。
zub1cg_pynq_163_230815.png
  1. 2023年08月15日 04:41 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG の PYNQ v3.0.1 で自作のメディアン・フィルタとソーベル・フィルタを動作させる1

RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成する2”でメディアン・フィルタが作成できた。その medain_axis_RGB24 IP を”ZUBoard 1CG の PYNQ v3.0.1 で自作のソーベル・フィルタを動作させる1”で作成したブロック・デザインに追加した。

ZUBoard 1CG の PYNQ v3.0.1 で自作のソーベル・フィルタを動作させる1”の sobel ブロック・デザインを出力する。

File メニューから Export -> Export Block Design... を選択する。
zub1cg_pynq_151_230813.png

Export Block Design ダイアログが表示された。
OK ボタンをクリックする。
zub1cg_pynq_152_230813.png

プロジェクトのディレクトリに sobel.tcl ファイルが出力された。
この tcl ファイルを実行すると sobel ブロック・デザインが生成される。
zub1cg_pynq_153_230813.png

ZUBoard 1CG 用の Vivado 2023.1 の median_sobel プロジェクトを作成した。

median_sobel プロジェクトのディレクトリに先程作成した sobel.tcl をコピーして、名前を medain_sobel.tcl に変更した。
zub1cg_pynq_154_230813.png

medain_sobel.tcl を開いて”set design_name sobel”から”set design_name median_sobel”に変更した。
zub1cg_pynq_155_230813.png

sobel_pynq プロジェクトのディレクトリから sobel_axis_RGB24 IP のディレクトリを median_sobel ディレクトリにコピーした。
median_axis_RGB24 ディレクトリを新規作成した。
median_axis_RGB24 ディレクトリに”RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成する2”で作成した median_axis_RGB24/solution1/impl/export.zip の内容をコピーした。
zub1cg_pynq_156_230813.png

Vivado の Flow Navigator から IP Catalog をクリックした。
IP Catalog ウインドウが開く。
右クリックし、右クリックメニューから Add Repository を選択し、sobel_axis_RGB24 と median_axis_RGB24 を選択して、IP を追加した。
zub1cg_pynq_157_230813.png

Vivado 2023.1 の Tcl Console で次のコマンドを実行した。
cd /media/masaaki/Ubuntu_Disk/HDL/2023.1/zub1cg/medain_sobel/
source median_sobel.tcl


すると、ソーベル・フィルタの回路が生成された。
zub1cg_pynq_158_230813.png

+アイコンをクリックして、median_axis_RGB24 IP を追加した。
配線を行って、回路が完成した。
median_sobel ブロック・デザインを示す。
zub1cg_pynq_159_230813.png

Address Editor を示す。
zub1cg_pynq_160_230813.png
  1. 2023年08月14日 04:55 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成する2

RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成する1”の続き。

メディアン・フィルタを ZUBoard 1CG の PYNQ v3.0.1 で使用するために Vitis HLS 2023.1 で RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成するということで、前回は、Vitis HLS 2023.1 で median_axis_RGB24 プロジェクトを作成し、C シミュレーションを行った。今回は、C コードの合成、C/RTL 協調シミュレーション、Export RTL、Implementation を行った。

C コードの合成を行った。結果を示す。
zub1cg_pynq_145_230812.png
zub1cg_pynq_146_230812.png

median_axis_RGB24_Pipeline_LOOP_Y_LOOP_X の LOOP_Y_LOOP_X の Interval が 1 クロックとなっていて、メディアン・フィルタの出力が 1 クロック毎に 1 出力がでるようだ。問題無さそうだ。

C/RTL 協調シミュレーションを行った。結果を示す。
zub1cg_pynq_147_230812.png

Avg II が 480057 クロックだった。画像サイズは 800 x 600 = 480000 ピクセルなので、ほぼ 1 ピクセル / クロックとなっているようだ。

C/RTL 協調シミュレーションの波形を示す。
全体波形を示す。
zub1cg_pynq_148_230812.png

outs_TVALID もほぼ 1 でスループットが高いことが分かる。

最初の波形を拡大する。
zub1cg_pynq_149_230812.png

ins_TREADY を見ると、最初はディアサートされている期間があることが分かるが、それが過ぎたら、1 のままになっている。

Export RTL を行った。

Implementation を行って、Vivado で実装した時の性能を確認した。
結果を示す。
zub1cg_pynq_150_230812.png

CP achieved post-implementaion は 6.928 ns で動作周波数の 10 ns よりも小さく、問題無さそうだ。
  1. 2023年08月13日 03:52 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成する1

メディアン・フィルタを ZUBoard 1CG の PYNQ v3.0.1 で使用するために Vitis HLS 2023.1 で RGB 24 ビットの AXI4-Stream データ入出力対応のメディアン・フィルタを Vitis HLS 2023.1 で作成した。

Vitis HLS 2023.1 で median_axis_RGB24 プロジェクトを作成した。
part は xczu1cg-sbva484-1-e を指定した。
zub1cg_pynq_138_230812.png

ソースコードとテストベンチ・コードは、”RGB 24 ビット・データ入出力対応のメディアン・フィルタを Vitis HLS 2021.2 で作成する1”のファイルを使用した。

今回のテストベンチ・コードでは OpenCV ライブラリを使用している。
Vitis HLS 2021.1 には内蔵された OpenCV は無いので、別にインストールした OpenCV を指定する。
Vitis HLS の Project メニューから Project Settings... を選択して、Project Settings ダイアログを開いた。
Simulation タブを開いて、median_axis_RGB24_tb.cpp の CFLAGS に

-I/usr/local/include

を設定した。
Linker Flags に

-L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc

を設定した。
zub1cg_pynq_139_230812.png

更に、 Synthesis をクリックして、 Top Function に median_axis_RGB24 を指定した。
zub1cg_pynq_140_230812.png

C シミュレーションを行った。結果を示す。
zub1cg_pynq_141_230812.png

median_axis_RGB24/solution1/csim/build ディレクトリを示す。
median.jpg と org.jpg が生成されている。
zub1cg_pynq_142_230812.png

org.jpg は median_axis_RGB24 の col_size 変数に ORG_IMGwAxiDma を指定した時の出力となる。つまり元画像と同じ画像ファイルであるはずだ。
org.jpg を示す。ノイズが拡散されているのが分かると思う。
zub1cg_pynq_143_230812.jpg

ノイズが拡散された元画像に 3 x 3 のメディアン・フィルタをかけた画像が median.jpg となる。
median.jpg を示す。拡散されたノイズが取れて、綺麗な画像になっていることが分かる。
zub1cg_pynq_144_230812.jpg
  1. 2023年08月12日 11:17 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG の PYNQ v3.0.1 で自作のソーベル・フィルタを動作させる2

ZUBoard 1CG の PYNQ v3.0.1 で自作のソーベル・フィルタを動作させる1”の続き。

前回は、Vivado 2023.1 の sobel_pynq プロジェクトを作成し、sobel_axis_RGB24 を使用して、sobel ブロック・デザインを作成した。論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。hwh ファイルと bit ファイルが生成された。今回は、hwh ファイルと bit ファイル、画像ファイルを ZUBoard 1CG に転送し、Jupyter Notebook を作成し、ソーベル・フィルタの動作を確認した。

HDL/2023.1/zub1cg/sobel_pynq/sobel_pynq.gen/sources_1/bd/sobel/hw_handoff/sobel.hwh ファイルと HDL/2023.1/zub1cg/sobel_pynq/sobel_pynq.runs/impl_1/sobel_wrapper.bit ファイルを FileZilla で ZUBoard 1CG の pynq linux に SFTP でホーム・ディレクトリにアップロードした。
zub1cg_pynq_133_230811.png

~/jupyter_notebooks/examples/sobel ディレクトリを Jupyter Notebook 上で作成した。

ZUBoard 1CG の pynq linux 上でホーム・ディレクトリ上の sobel.hwh と sobel_wrapper.bit を ~/jupyter_notebooks/examples/sobel ディレクトリにコピーする。
sobel_wrapper.bit は sobel.bit に名前を変更した。
sudo mv sobel.hwh jupyter_notebooks/examples/sobel/
sudo mv sobel_wrapper.bit jupyter_notebooks/examples/sobel/sobel.bit


Jupyter Notebook 上の examples/sobel ディレクトリを示す。
zub1cg_pynq_134_230811.png

test2.jpg を転送するのを忘れていたので、FileZilla で ZUBoard 1CG の pynq linux 上のホーム・ディレクトリにアップロードする。
test2.jpg を ~/jupyter_notebooks/examples/sobel ディレクトリにコピーする。
sudo mv test2.jpg jupyter_notebooks/examples/sobel/

Jupyter Notebook 上で examples/sobel ディレクトリに sobel.ipynb を作成した。
sobel.ipynb に”KV260 の PYNQ で自作のソーベル・フィルタを動作させる5”のコードをコピーして実行した。
test2.jpg のソーベル・フィルタ実行結果が表示されている。成功だ。
zub1cg_pynq_135_230811.png
zub1cg_pynq_136_230811.png
zub1cg_pynq_137_230811.png
  1. 2023年08月11日 04:08 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG の PYNQ v3.0.1 で自作のソーベル・フィルタを動作させる1

RGB 24 ビットの AXI4-Stream データ入出力対応のソーベル・フィルタを Vitis HLS 2023.1 で作成する”の続き。

RGB 24 ビットの AXI4-Stream データ入出力対応のソーベル・フィルタを Vitis HLS 2023.1 で作成する”で Vitis HLS 2023.1 を使用して、ソーベル・フィルタ IP の sobel_axis_RGB24 を作成した。今回は、Vivado 2023.1 の sobel_pynq プロジェクトを作成し、sobel_axis_RGB24 を使用して、sobel ブロック・デザインを作成した。論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。hwh ファイルと bit ファイルが生成された。

ZUBoard 1CG 用の Vivado 2023.1 の sobel_pynq プロジェクトを作成した。
zub1cg_pynq_122_230809.png

sobel_pynq ディレクトリの下に sobel_axis_RGB24 ディレクトリを作成し、”RGB 24 ビットの AXI4-Stream データ入出力対応のソーベル・フィルタを Vitis HLS 2023.1 で作成する”で生成された sobel_axis_RGB24/solution1/impl/export.zip を展開して sobel_axis_RGB24 ディレクトリにコピーした。
zub1cg_pynq_123_230809.png

IP Catalog に sobel_axis_RGB24 IP を追加した。
zub1cg_pynq_124_230809.png

sobel ブロック・デザインを作成し、完成させた。
axi dma を使用して、DMA したデータを AXI4-Stream で流して、sobel_axis_RGB24 に入力して、ソーベル・フィルタを掛ける。DMA するデータが OpenCV の MAT 形式なので、RGB のピクセルが 32 ビット幅(4 バイト)のデータバスに散らばっている。それを 3 バイト幅の RGB に戻すのが axis_dwidth_converter_0 の役割だ。その後、ソーベル・フィルタを掛けた 3 バイト幅のデータは axis_dwidth_converter_1 で 4 バイト幅(32 ビット幅)に変換される。つまり、OpenCV の MAT 形式に変換されて、PYNQ の Jupyter Notebook でその画像を表示することができるようになる。
zub1cg_pynq_125_230809.png

zynq_ultra_ps_e_0 は、Re-customize IP ダイアログの PS-PL Configuration で PS-PL Interface の AXI HPM0 FPD と AXI HPC0 FPD のみにチェックを入れた。(ちなみに、Re-customize IP ダイアログを表示させるには、IP をダブル・クリックする)
zub1cg_pynq_126_230809.png

axi_dma_0 は Re-customize IP ダイアログで Enable Scatter Gather Engine のチェックを外した。
更に、800 x 600 ピクセルの画像を一度に DMA するために Width of Buffer Length Resiger を 26 bits に変更した。
zub1cg_pynq_127_230809.png

axis_dwidth_converter_0 の Master interface TDATA width (bytes) を 3 に設定した。
OpenCV の MAT 形式から RGB 3 バイト幅に変換する。
zub1cg_pynq_128_230809.png

axis_dwidth_converter_1 の Master interface TDATA width (bytes) を 4 に設定した。
RGB 3 バイト幅から Open CV の MAT 形式に変換する。
zub1cg_pynq_129_230809.png

Address Editor 画面を示す。
zub1cg_pynq_130_230809.png

sobel ブロック・デザインの HDL Wrapper を作成した。
zub1cg_pynq_131_230809.png

Vivado の Flow Navigator から Generate Bitstream をクリックし、論理合成、インプリメンテーション、ビットストリームの生成を行って、成功した。
Project Summary を示す。
zub1cg_pynq_132_230809.png

HDL/2023.1/zub1cg/sobel_pynq/sobel_pynq.gen/sources_1/bd/sobel/hw_handoff ディレクトリに sobel.hwh ファイルが生成された。

HDL/2023.1/zub1cg/sobel_pynq/sobel_pynq.runs/impl_1 ディレクトリに sobel_wrapper.bit ファイルが生成された。
  1. 2023年08月10日 04:20 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

RGB 24 ビットの AXI4-Stream データ入出力対応のソーベル・フィルタを Vitis HLS 2023.1 で作成する

ソーベル・フィルタを ZUBoard 1CG の PYNQ v3.0.1 で使用するために Vitis HLS 2023.1 で RGB 24 ビットの AXI4-Stream データ入出力対応のソーベル・フィルタを Vitis HLS 2023.1 で作成した。

ソースコードとテストベンチ・コードは、”RGB 24 ビット・データ入出力対応のソーベル・フィルタを Vitis HLS 2021.2 で作成する3”の物を使用した。

Vitis HLS 2023.1 で sobel_axis_RGB24 プロジェクトを作成した。
part は xczu1cg-sbva484-1-e を指定した。
zub1cg_pynq_112_230809.png

今回のテストベンチ・コードでは OpenCV ライブラリを使用している。
Vitis HLS 2023.1 には内蔵された OpenCV は無いので、別にインストールした OpenCV を指定する。
Vitis HLS の Project メニューから Project Settings... を選択して、Project Settings ダイアログを開いた。
Simulation タブを開いて、sobel_axis_RGB24_tb.cpp の CFLAGS に

-I/usr/local/include


を設定した。
Linker Flags に

-L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc


を設定した。
zub1cg_pynq_113_230809.png

更に、 Synthesis をクリックして、 Top Function に sobel_axis_RGB24 を指定した。
zub1cg_pynq_114_230809.png

現在の Vitis_HLS/ZUBoard_1CG/2023.1/median_axis_RGB24 ディレクトリを示す。
zub1cg_pynq_111_230809.png

C シミュレーションを行った。
下の、Console では成功と表示されているが、_csim.log では、エラーになっている。これは、最初に OpenCV の設定を忘れていてエラーなったのが残っている状況だ。このログは消えないのだろうか?
zub1cg_pynq_115_230809.png

solution1/csim/build ディレクトリを示す。
sobel.jpg が生成されていた。
zub1cg_pynq_116_230809.png

C コードの合成を行った。結果を示す。
zub1cg_pynq_117_230809.png
zub1cg_pynq_118_230809.png

C/RTL 協調シミュレーションを行った。
結果を示す。
zub1cg_pynq_119_230809.png

C/RTL 協調シミュレーション波形を示す。
zub1cg_pynq_121_230809.png

ins_TREADY と outs_TVALID がほとんど 1 なので、スループットが高いことが分かる。

Export RTL を行った。

Implementation を行った。
CP achieved post-implementation が 5.934 ns で、良さそうだ。
zub1cg_pynq_120_230809.png
  1. 2023年08月09日 04:51 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

”Getting Started with PYNQ and the ZUBoard”をやってみる5

”Getting Started with PYNQ and the ZUBoard”をやってみる4”の続き。

Adam Taylor さんの”Getting Started with PYNQ and the ZUBoard”をやってみようということで、前回は、ブロック・デザインの HDL Wrapper ファイルを作成し、論理合成、インプリメンテーション、ビットストリームの生成を行って成功した。bit ファイルと hwh ファイルが生成された。今回は、前回生成した bit ファイルと hwh ファイルを ZUBoard 1CG の PYNQ v3.0.1 に転送し、”Getting Started with PYNQ and the ZUBoard”の Python3 のソフトウェアを動作せたところ、成功した。

ZUBoard 1CG の PYNQ v3.0.1 を起動して、Chrome ブラウザで IP アドレス の TCP ポート 9090 を見た。
Jupyter Notebook のログイン画面が出ているので、パスワードの xilinx を入れてログインした。
ディレクトリが表示されるので、右の New ボタンから Folder を選択して、新しいフォルダを作成する。
zub1cg_pynq_104_230807.png

Untitle Folder が作成された。
Untitle Folder の前のチェックボックスにチェックを入れて、Rename ボタンをクリックする。
zub1cg_pynq_105_230807.png

新しいディレクトリ名に tpg_overlay と入力して、Rename ボタンをクリックした。
zub1cg_pynq_106_230807.png

するとフォルダの名前が tpg_overlay に変更された。

ZUBoard 1CG の PYNQ v3.0.1 のホーム・ディレクトリの下の jupyter_notebooks/tpg_overlay ディレクトリが生成されたので、
FileZilla で tpg_bd.hwh ファイルと tpg_bd_wrapper.bit ファイルをホーム・ディレクトリに SFTP でアップロードした。
これは、jupyter_notebooks/tpg_overlay ディレクトリのオーナーが root なので、直接 SFTP でアップロードできないためだ。
zub1cg_pynq_107_230807.png

ここから ZUBoard 1CG の PYNQ v3.0.1 での作業となる。
tpg_bd.hwh ファイルと tpg_bd_wrapper.bit ファイルをホーム・ディレクトリから、jupyter_notebooks/tpg_overlay ディレクトリにリネームして移動した。
cd ~
sudo mv tpg_bd.hwh jupyter_notebooks/tpg_overlay/tpg.hwh
sudo mv tpg_bd_wrapper.bit jupyter_notebooks/tpg_overlay/tpg.bit


Jupter Notebook を見ると、tpg.hwh と tpg.bit ファイルが見える。
zub1cg_pynq_108_230807.png

Getting Started with PYNQ and the ZUBoard”の Python3 のソフトウェアを引用する。

import time 
import numpy as np
from pynq import pl
from pynq import Overlay
from pynq.lib.video import *
import cv2
import matplotlib.pyplot as plt

ol = Overlay('/home/xilinx/jupyter_notebooks/tpg_overlay/tpg.bit')

pixel_in = ol.pixel_pack_2_0
pixel_in.bits_per_pixel = 24

colourspace_in = ol.color_convert_2_0
rgb2bgr = [0.0, 1.0, 0.0,
           1.0, 0.0, 0.0,
           0.0, 0.0, 1.0,
           0.0, 0.0, 0.0]

colourspace_in.colorspace = rgb2bgr

cam_vdma = ol.axi_vdma_0
lines = 512
framemode = VideoMode(640, lines, 24)
cam_vdma.readchannel.mode = framemode
cam_vdma.readchannel.start()

tpg = ol.v_tpg_0
tpg.write(0x10,512)
tpg.write(0x18,640)
tpg.write(0x40,0)
tpg.write(0x30,0)
tpg.write(0x20,0xB)
tpg.write(0x00,0x81)

frame_camera = cam_vdma.readchannel.readframe()
frame_color=cv2.cvtColor(frame_camera,cv2.COLOR_BGR2RGB)
pixels = np.array(frame_color)
plt.imshow(pixels)
plt.show()


引用したコードで 右の New ボタンから Python3(ipykernel) を選択して、新しいノートブックを生成した。
新しいノートブックの前のチェックボックスにチェックを入れて、Rename ボタンをクリックして、名前を tpg.ipynb に変更した。

Getting Started with PYNQ and the ZUBoard”の Python3 のソフトウェアを tpg.ipynb に入力した。
ノートブックを実行していくとテスト・パターンが表示された。成功だ。
zub1cg_pynq_109_230807.png
zub1cg_pynq_110_230807.png
  1. 2023年08月08日 04:05 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

”Getting Started with PYNQ and the ZUBoard”をやってみる4

”Getting Started with PYNQ and the ZUBoard”をやってみる3”の続き。

Adam Taylor さんの”Getting Started with PYNQ and the ZUBoard”をやってみようということで、前回は、Color Convert (2ppc) IP と Pixel Pack (2 ppc) IP、 AXI Interrupt Controller IP を追加して、自動配線を行った。Validate Desgin を行ったところ、成功した。よって、ブロック・デザインが完成した。今回は、ブロック・デザインの HDL Wrapper ファイルを作成し、論理合成、インプリメンテーション、ビットストリームの生成を行って成功した。bit ファイルと hwh ファイルが生成された。

Source ウインドウに切り替えて tpg_bd を右クリックし、右クリックメニューから Create HDL Wrapper... を選択て、HDL Wrapper ファイルの tpg_bd_wrapper.v を生成した。
zub1cg_pynq_100_230806.png

Flow Navigator から Generate Bitstream をクリックし、論理合成、インプリメンテーション、ビットストリームの生成を行って成功した。
Project Summary を示す。
zub1cg_pynq_101_230806.png

HDL/2023.1/zub1cg/test_pattern_gen/test_pattern_gen.gen/sources_1/bd/tpg_bd/hw_handoff ディレクトリに tpg_bd.hwh ファイルが生成された。
zub1cg_pynq_102_230806.png

HDL/2023.1/zub1cg/test_pattern_gen/test_pattern_gen.runs/impl_1 ディレクトリに tpg_bd_wrapper.bit ファイルが生成された。
zub1cg_pynq_103_230806.png
  1. 2023年08月07日 04:15 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

”Getting Started with PYNQ and the ZUBoard”をやってみる3

”Getting Started with PYNQ and the ZUBoard”をやってみる2”の続き。

Adam Taylor さんの”Getting Started with PYNQ and the ZUBoard”をやってみようということで、前回は、生成した IP を使用してテスト・パターン・ジェネレーターのブロック・デザインを作成した。次に、Video Test Pattern Generator と AXI Video Direct Memory Access を Add IP して、自動配線を行った。今回は、Color Convert (2ppc) IP と Pixel Pack (2 ppc) IP、 AXI Interrupt Controller IP を追加して、自動配線を行った。Validate Desgin を行ったところ、成功した。よって、ブロック・デザインが完成した。

Color Convert (2ppc) IP を Add IP して、v_tpg_0 の m_axis_video 出力ポートから color_convert_2_0 の stream_in_48 入力ポートに配線を接続した。
zub1cg_pynq_84_230805.png

Run Connection Automation をクリックして自動配線を行った。
Run Connection Automation ダイアログが開いた。
All Automation にチェックが入っていない場合はチェックを入れる。
OK ボタンをクリックして自動配線を行った。
zub1cg_pynq_85_230805.png

現在のブロック・デザインを示す。
zub1cg_pynq_86_230805.png

Pixel Pack (2 ppc) IP を Add IP した。
zub1cg_pynq_87_230805.png

Run Connection Automation をクリックして自動配線を行った。
Run Connection Automation ダイアログが開いた。
All Automation にチェックが入っていない場合はチェックを入れる。
OK ボタンをクリックして自動配線を行った。
zub1cg_pynq_88_230805.png

現在のブロック・デザインを示す。
zub1cg_pynq_89_230805.png

color_convert_2_0 の stream_out_48 出力ポートから pixel_pack_2_0 の stream_in_48 入力ポートに配線を接続した。
pixel_pack_2_0 の stream_out_64 出力ポートから axi_vdma_0 の S_AXIS_S2MM 入力ポートへ配線を接続した。
zub1cg_pynq_90_230805.png

Add IP を行って、AXI Interrupt Controller IP を追加した。
zub1cg_pynq_91_230805.png

Run Connection Automation をクリックして自動配線を行った。
Run Connection Automation ダイアログが開いた。
All Automation にチェックが入っていない場合はチェックを入れる。
OK ボタンをクリックして自動配線を行った。
zub1cg_pynq_92_230805.png

現在のブロック・デザインを示す。
zub1cg_pynq_93_230805.png

axi_intr_0 をダブル・クリックして、設定を変更した。
Interrupt Output Connection を Single に変更した。
OK ボタンをクリックした。
zub1cg_pynq_94_230805.png

現在のブロック・デザインを示す。
zub1cg_pynq_95_230805.png

Add IP を行って、Concat IP を追加した。
axi_vdma_0 の s2mm_introut 出力ポートから xlconcat_0 の In0 入力ポートへ配線を接続した。
v_tpg_0 の interrupt 出力ポートから xlconcat_0 の In1 入力ポートへ配線を接続した。
xlconcat_0 の dout から axi_intc_0 の intr 入力ポートへ配線を接続した。
zub1cg_pynq_96_230805.png

これで配線が終了した。
Validate Design ボタンをクリックし、デザインをチェックした。
Validate Desgin ダイアログが表示されて、成功したので、配線のミスは無いようだ。
zub1cg_pynq_97_230805.png

完成したブロック・デザインを示す。
zub1cg_pynq_98_230805.png

Address Editor 画面を示す。
zub1cg_pynq_99_230805.png
  1. 2023年08月06日 04:28 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

”Getting Started with PYNQ and the ZUBoard”をやってみる2

Adam Taylor さんの”Getting Started with PYNQ and the ZUBoard”をやってみようということで、前回は、PYNQ の github リポジトリを git clone して、PYNQ リポジトリの下の boards/ip/hls ディレクトリに行って、build_ip.sh を実行して、Vitis HLS の IP を生成した。Vivado 2023.1 で test_pattarn_gen プロジェクトを作成し、生成した IP を IP Catlog に登録した。今回は、前回、生成した IP を使用してテスト・パターン・ジェネレーターのブロック・デザインを作成した。次に、Video Test Pattern Generator と AXI Video Direct Memory Access を Add IP して、自動配線を行った。

Adam Taylor さんの”Getting Started with PYNQ and the ZUBoard”のやり方を引用しているが、自分のやり方も加味している。

Vivado 2023.1 で Flow Navigator から IP INTEGRATOR -> Create Block Design をクリックして、ブロック・デザインを作成する。
Create Block Design ダイアログが開くので、Design Name に tpg_bd と入力して、OK ボタンをクリックした。
zub1cg_pynq_70_230805.png

Diagram ウインドウが表示されるので、真ん中の + ボタンをクリックして、Zynq UltraScale+ MPSoC を追加する。
zub1cg_pynq_71_230805.png

IP を選択するダイアログが表示された。
Search: に z と入力して、Zynq UltraScale+ MPSoC をダブル・クリックして追加した。
zub1cg_pynq_72_230805.png

Zynq UltraScale+ MPSoC が追加された。
zub1cg_pynq_73_230805.png

Run Block Automation をクリックして、設定を行う。
Run Block Automation ダイアログが表示された。
OK ボタンをクリックする。
zub1cg_pynq_74_230805.png

ZUBoard 1CG の設定が Zynq UltraScale+ MPSoC に設定された。
zub1cg_pynq_75_230805.png

Zynq UltraScale+ MPSoC をダブル・クリックして設定を行う。
Page Navigator から PS-PL Configuration を選択する。
General -> Interrupts -> PL to PS -> IRQ0[0-7] の Select を 1 にして、割り込みの設定を行った。
PS-PL Interface -> Master Interface -> AXI HPM1 FPD のチェックボックスのチェックを外した。
PS-PL Interface -> Slave Interface -> AXI HP -> AXI HPC0 FPD のチェックボックスのチェックを入れた。
zub1cg_pynq_76_230805.png

現在の Zynq UltraScale+ MPSoC を示す。
zub1cg_pynq_77_230805.png

+ ボタンをクリックして Video Test Pattern Generator を追加した。
zub1cg_pynq_78_230805.png

Video Test Pattern Generator をダブル・クリックして設定を行った。
Samples per Clock2 に変更した。
zub1cg_pynq_79_230805.png

+ ボタンをクリックして AXI Video Direct Memory Access を Add IP した。
AXI Video Direct Memory Access をダブル・クリックして、設定を行い、Enable Read Channel のチェックボックスのチェックを外した。
zub1cg_pynq_80_230805.png

Run Connection Automation をクリックして、自動配線を行う。
Run Connection Automation ダイアログが開く。
All Automation をクリックして、自動配線を行う。
zub1cg_pynq_82_230805.png

現在のブロック・デザインを示す。
zub1cg_pynq_83_230805.png
  1. 2023年08月05日 15:01 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

”Getting Started with PYNQ and the ZUBoard”をやってみる1

Adam Taylor さんの”Getting Started with PYNQ and the ZUBoard”をやってみよう。

Vivado, Vitis HLS 2023.1 を使用する。
Vitis の環境設定を行った。
source /media/masaaki/Ubuntu_Disk/tools/Xilinx/Vitis/2023.1/settings64.sh

最初に PYNQ の github リポジトリを git clone した。
git clone https://github.com/Xilinx/PYNQ.git
zub1cg_pynq_59_230803.png

PYNQ リポジトリの下の boards/ip/hls ディレクトリに行って、build_ip.sh を実行した。
cd PYNQ/boards/ip/hls
./build_ip.sh

zub1cg_pynq_60_230803.png

zub1cg_pynq_61_230803.png

Vitis HLS 2023.1 が起動して、高位合成を行った。
color_convert を見ると、solution1 ディレクトリが生成され、IP が生成されていた。
zub1cg_pynq_62_230803.png

Vivado 2023.1 を起動して、test_pattarn_gen プロジェクトを作成する。
zub1cg_pynq_63_230803.png

Avnet 社の ZUBoard 1CG 用のプロジェクトに設定した。
zub1cg_pynq_64_230803.png

test_pattarn_gen プロジェクトが作成された。
zub1cg_pynq_65_230803.png

PROJECT MANAGER の IP Catalog をクリックした。
IP Catlog ウインドウが開く。
ウインドウ内を右クリックし、右クリックメニューから Add Repository... を選択した。
zub1cg_pynq_66_230803.png

Repositories ダイアログが開く。
PYNQ/boards/ip をクリックして、Select ボタンをクリックした。
zub1cg_pynq_67_230803.png

Add Repository ダイアログが開いた。
OK ボタンをクリックした。
zub1cg_pynq_68_230803.png

IP が IP Catlog に登録されたが、VITIS HLS IP は 3 個だけ登録されていた。
zub1cg_pynq_69_230803.png

VITIS HLS IP の 3 個のパートは xc7z020-clg400-1 だった。他の IP は xczu7ev-ffvc1156-2-i とかで、ZYNQ じゃなかった。
他の IP はパートが違っているから IP Catalog に登録されないようだ?
Zynq MPSoC じゃなく Zynq でも ZUBoard 1CG の IP Catlog に入るということだと思う。結構賢い?
  1. 2023年08月04日 05:01 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG で DPU-PYNQ をやってみる3

”ZUBoard 1CG で DPU-PYNQ をやってみる2”の続き。

ZUBoard 1CG の PYNQ v3.0.1 上に DPU-PYNQ をインストールして、ノートブックを実行している。前回は、dpu_resnet50.ipynb と dpu_resnet50_pybind11.ipynb をやってみた。今回は、dpu_tf_inceptionv1.ipynb と dpu_yolov3.ipynb をやってみた。

dpu_tf_inceptionv1.ipynb をやってみたところ成功した。
dpu_tf_inceptionv1.ipynb の実行結果を引用する。
zub1cg_pynq_43_230802.png
zub1cg_pynq_44_230802.png
zub1cg_pynq_45_230802.png
zub1cg_pynq_46_230802.png
zub1cg_pynq_47_230802.png
zub1cg_pynq_48_230802.png

dpu_yolov3.ipynb をやってみたところ成功した。
dpu_yolov3.ipynb の実行結果を引用する。
zub1cg_pynq_49_230802.png
zub1cg_pynq_50_230802.png
zub1cg_pynq_51_230802.png
zub1cg_pynq_52_230802.png
zub1cg_pynq_53_230802.png
zub1cg_pynq_54_230802.png
zub1cg_pynq_55_230802.png
zub1cg_pynq_56_230802.png
zub1cg_pynq_57_230802.png
zub1cg_pynq_58_230802.png
  1. 2023年08月03日 04:00 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0

ZUBoard 1CG で DPU-PYNQ をやってみる2

ZUBoard 1CG で DPU-PYNQ をやってみる1”の続き。

前回は、ZUBoard 1CG で PYNQ v3.0.1 を動作させたが、そこにDPU-PYNQ をインストールした。そして、ノートブックの内の dpu_mnist_classifier.ipynb をやってみたところ、成功した。今回は、dpu_resnet50.ipynb と dpu_resnet50_pybind11.ipynb をやってみた。

dpu_resnet50.ipynb をやってみたところ、成功した。
dpu_resnet50.ipynb の実行結果を引用する。
zub1cg_pynq_24_230801.png
zub1cg_pynq_25_230801.png
zub1cg_pynq_26_230801.png
zub1cg_pynq_27_230801.png
zub1cg_pynq_28_230801.png
zub1cg_pynq_29_230801.png

dpu_resnet50_pybind11.ipynb をやってみたところ、成功した。
dpu_resnet50_pybind11.ipynb の実行結果を引用する。
zub1cg_pynq_30_230801.png
zub1cg_pynq_31_230801.png
zub1cg_pynq_32_230801.png
zub1cg_pynq_33_230801.png
zub1cg_pynq_34_230801.png
zub1cg_pynq_35_230801.png
zub1cg_pynq_36_230801.png
zub1cg_pynq_37_230801.png
zub1cg_pynq_38_230801.png
zub1cg_pynq_39_230801.png
zub1cg_pynq_40_230801.png
zub1cg_pynq_41_230801.png
zub1cg_pynq_42_230801.png
  1. 2023年08月01日 04:46 |
  2. ZUBoard
  3. | トラックバック:0
  4. | コメント:0