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

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

FPGAの部屋

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

Donkey Car の所得したデータで学習し、自動走行させてみた

Donkey Car のキャリブレーション、教師データの取得を行った”の続き。

前回は、Donkey Car のキャリブレーションを行って、コースを走らせて教師データを取得した。今回は、教師データをGoogle Colaboratory で学習して、学習したモデルをDonkey Car に移して自動走行させてみよう。

Donkey Car の ~/mycar/data/ ディレクトリを見ると、tub_.... というディレクトリが並んでいた。
donkey_car_36_190730.png

今回使用するのは、tub_6_19-07-29 と tub_7_19-07-29 だ。両方合わせて 10269 データある。これを datas.zip に圧縮してホストパソコンの ~/Donkey_Car/ ディレクトリにSFTP する。
donkey_car_37_190730.png

Colabでの学習(GPU)

Donkey Car のGoogle Colab を起動した。

”ドライブにコピー”をクリックして、自分のGoogle Drive にコピーした。
donkey_car_38_190730.png

Google Drive にDonkey Car のJupyter Notebook がコピーされたので、それを起動した。
donkey_car_39_190730.png

Donkey Car のJupyter Notebook を実行していった。
donkey_car_40_190730.png
donkey_car_41_190730.png
donkey_car_43_190730.png
datas.zip をアップロードして、解凍し、学習データとしてニューラルネットワークを学習した。

donkey_car_44_190730.png

loading config file: /content/mycar/config.py
loading personal config over-rides

config loaded
"get_model_by_type" model Type is: categorical
training with model type <class 'donkeycar.parts.keras.KerasCategorical'>
Model: "model_1"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
img_in (InputLayer)             [(None, 120, 160, 3) 0                                            
__________________________________________________________________________________________________
conv2d_1 (Conv2D)               (None, 58, 78, 24)   1824        img_in[0][0]                     
__________________________________________________________________________________________________
dropout_6 (Dropout)             (None, 58, 78, 24)   0           conv2d_1[0][0]                   
__________________________________________________________________________________________________
conv2d_2 (Conv2D)               (None, 27, 37, 32)   19232       dropout_6[0][0]                  
__________________________________________________________________________________________________
dropout_7 (Dropout)             (None, 27, 37, 32)   0           conv2d_2[0][0]                   
__________________________________________________________________________________________________
conv2d_3 (Conv2D)               (None, 12, 17, 64)   51264       dropout_7[0][0]                  
__________________________________________________________________________________________________
conv2d_4 (Conv2D)               (None, 5, 8, 64)     36928       conv2d_3[0][0]                   
__________________________________________________________________________________________________
dropout_8 (Dropout)             (None, 5, 8, 64)     0           conv2d_4[0][0]                   
__________________________________________________________________________________________________
conv2d_5 (Conv2D)               (None, 3, 6, 64)     36928       dropout_8[0][0]                  
__________________________________________________________________________________________________
dropout_9 (Dropout)             (None, 3, 6, 64)     0           conv2d_5[0][0]                   
__________________________________________________________________________________________________
flattened (Flatten)             (None, 1152)         0           dropout_9[0][0]                  
__________________________________________________________________________________________________
fc_1 (Dense)                    (None, 100)          115300      flattened[0][0]                  
__________________________________________________________________________________________________
dropout_10 (Dropout)            (None, 100)          0           fc_1[0][0]                       
__________________________________________________________________________________________________
fc_2 (Dense)                    (None, 50)           5050        dropout_10[0][0]                 
__________________________________________________________________________________________________
dropout_11 (Dropout)            (None, 50)           0           fc_2[0][0]                       
__________________________________________________________________________________________________
angle_out (Dense)               (None, 15)           765         dropout_11[0][0]                 
__________________________________________________________________________________________________
throttle_out (Dense)            (None, 20)           1020        dropout_11[0][0]                 
==================================================================================================
Total params: 268,311
Trainable params: 268,311
Non-trainable params: 0
__________________________________________________________________________________________________
None
found 0 pickles writing json records and images in tub /content/mycar/data/tub_6_19-07-29
found 0 pickles writing json records and images in tub /content/mycar/data/tub_7_19-07-29
/content/mycar/data/tub_6_19-07-29
/content/mycar/data/tub_7_19-07-29
collating 10269 records ...
train: 8215, val: 2054
total records: 10269
steps_per_epoch 64
Epoch 1/100
63/64 [============================>.] - ETA: 0s - loss: 3.3674 - angle_out_loss: 2.2257 - throttle_out_loss: 2.2545 - angle_out_acc: 0.2696 - throttle_out_acc: 0.3826
Epoch 00001: val_loss improved from inf to 3.13174, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 12s 184ms/step - loss: 3.3630 - angle_out_loss: 2.2232 - throttle_out_loss: 2.2514 - angle_out_acc: 0.2706 - throttle_out_acc: 0.3831 - val_loss: 3.1317 - val_angle_out_loss: 1.9923 - val_throttle_out_loss: 2.1356 - val_angle_out_acc: 0.3462 - val_throttle_out_acc: 0.3809
Epoch 2/100
63/64 [============================>.] - ETA: 0s - loss: 3.1067 - angle_out_loss: 2.0148 - throttle_out_loss: 2.0993 - angle_out_acc: 0.3323 - throttle_out_acc: 0.3932
Epoch 00002: val_loss improved from 3.13174 to 2.98889, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 53ms/step - loss: 3.1063 - angle_out_loss: 2.0139 - throttle_out_loss: 2.0994 - angle_out_acc: 0.3337 - throttle_out_acc: 0.3938 - val_loss: 2.9889 - val_angle_out_loss: 1.9188 - val_throttle_out_loss: 2.0295 - val_angle_out_acc: 0.3452 - val_throttle_out_acc: 0.3862
Epoch 3/100
63/64 [============================>.] - ETA: 0s - loss: 3.0231 - angle_out_loss: 1.9465 - throttle_out_loss: 2.0499 - angle_out_acc: 0.3960 - throttle_out_acc: 0.4428
Epoch 00003: val_loss improved from 2.98889 to 2.92830, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 3.0233 - angle_out_loss: 1.9471 - throttle_out_loss: 2.0497 - angle_out_acc: 0.3971 - throttle_out_acc: 0.4431 - val_loss: 2.9283 - val_angle_out_loss: 1.8372 - val_throttle_out_loss: 2.0097 - val_angle_out_acc: 0.4624 - val_throttle_out_acc: 0.4546
Epoch 4/100
62/64 [============================>.] - ETA: 0s - loss: 2.8735 - angle_out_loss: 1.8158 - throttle_out_loss: 1.9656 - angle_out_acc: 0.4970 - throttle_out_acc: 0.4946
Epoch 00004: val_loss improved from 2.92830 to 2.69279, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.8727 - angle_out_loss: 1.8150 - throttle_out_loss: 1.9652 - angle_out_acc: 0.4966 - throttle_out_acc: 0.4950 - val_loss: 2.6928 - val_angle_out_loss: 1.6640 - val_throttle_out_loss: 1.8608 - val_angle_out_acc: 0.5469 - val_throttle_out_acc: 0.5000
Epoch 5/100
62/64 [============================>.] - ETA: 0s - loss: 2.7645 - angle_out_loss: 1.7299 - throttle_out_loss: 1.8995 - angle_out_acc: 0.5219 - throttle_out_acc: 0.5150
Epoch 00005: val_loss improved from 2.69279 to 2.65042, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 52ms/step - loss: 2.7651 - angle_out_loss: 1.7300 - throttle_out_loss: 1.9001 - angle_out_acc: 0.5222 - throttle_out_acc: 0.5144 - val_loss: 2.6504 - val_angle_out_loss: 1.6285 - val_throttle_out_loss: 1.8362 - val_angle_out_acc: 0.5547 - val_throttle_out_acc: 0.5249
Epoch 6/100
63/64 [============================>.] - ETA: 0s - loss: 2.6785 - angle_out_loss: 1.6660 - throttle_out_loss: 1.8455 - angle_out_acc: 0.5433 - throttle_out_acc: 0.5295
Epoch 00006: val_loss improved from 2.65042 to 2.55639, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.6771 - angle_out_loss: 1.6656 - throttle_out_loss: 1.8443 - angle_out_acc: 0.5436 - throttle_out_acc: 0.5295 - val_loss: 2.5564 - val_angle_out_loss: 1.5467 - val_throttle_out_loss: 1.7830 - val_angle_out_acc: 0.5791 - val_throttle_out_acc: 0.5322
Epoch 7/100
62/64 [============================>.] - ETA: 0s - loss: 2.6023 - angle_out_loss: 1.6173 - throttle_out_loss: 1.7936 - angle_out_acc: 0.5557 - throttle_out_acc: 0.5387
Epoch 00007: val_loss improved from 2.55639 to 2.53856, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.6040 - angle_out_loss: 1.6213 - throttle_out_loss: 1.7933 - angle_out_acc: 0.5535 - throttle_out_acc: 0.5383 - val_loss: 2.5386 - val_angle_out_loss: 1.5468 - val_throttle_out_loss: 1.7651 - val_angle_out_acc: 0.5542 - val_throttle_out_acc: 0.5347
Epoch 8/100
63/64 [============================>.] - ETA: 0s - loss: 2.5492 - angle_out_loss: 1.5788 - throttle_out_loss: 1.7598 - angle_out_acc: 0.5590 - throttle_out_acc: 0.5484
Epoch 00008: val_loss improved from 2.53856 to 2.48855, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.5489 - angle_out_loss: 1.5782 - throttle_out_loss: 1.7598 - angle_out_acc: 0.5591 - throttle_out_acc: 0.5487 - val_loss: 2.4886 - val_angle_out_loss: 1.5071 - val_throttle_out_loss: 1.7350 - val_angle_out_acc: 0.5752 - val_throttle_out_acc: 0.5439
Epoch 9/100
63/64 [============================>.] - ETA: 0s - loss: 2.4850 - angle_out_loss: 1.5364 - throttle_out_loss: 1.7168 - angle_out_acc: 0.5671 - throttle_out_acc: 0.5530
Epoch 00009: val_loss improved from 2.48855 to 2.45861, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.4876 - angle_out_loss: 1.5366 - throttle_out_loss: 1.7193 - angle_out_acc: 0.5669 - throttle_out_acc: 0.5521 - val_loss: 2.4586 - val_angle_out_loss: 1.4642 - val_throttle_out_loss: 1.7265 - val_angle_out_acc: 0.5908 - val_throttle_out_acc: 0.5547
Epoch 10/100
63/64 [============================>.] - ETA: 0s - loss: 2.4513 - angle_out_loss: 1.5038 - throttle_out_loss: 1.6994 - angle_out_acc: 0.5754 - throttle_out_acc: 0.5577
Epoch 00010: val_loss improved from 2.45861 to 2.42520, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 52ms/step - loss: 2.4534 - angle_out_loss: 1.5047 - throttle_out_loss: 1.7010 - angle_out_acc: 0.5748 - throttle_out_acc: 0.5569 - val_loss: 2.4252 - val_angle_out_loss: 1.4220 - val_throttle_out_loss: 1.7142 - val_angle_out_acc: 0.5820 - val_throttle_out_acc: 0.5449
Epoch 11/100
62/64 [============================>.] - ETA: 0s - loss: 2.4054 - angle_out_loss: 1.4839 - throttle_out_loss: 1.6635 - angle_out_acc: 0.5725 - throttle_out_acc: 0.5601
Epoch 00011: val_loss improved from 2.42520 to 2.36648, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 52ms/step - loss: 2.4062 - angle_out_loss: 1.4828 - throttle_out_loss: 1.6648 - angle_out_acc: 0.5730 - throttle_out_acc: 0.5603 - val_loss: 2.3665 - val_angle_out_loss: 1.3953 - val_throttle_out_loss: 1.6688 - val_angle_out_acc: 0.6045 - val_throttle_out_acc: 0.5698
Epoch 12/100
63/64 [============================>.] - ETA: 0s - loss: 2.3627 - angle_out_loss: 1.4525 - throttle_out_loss: 1.6365 - angle_out_acc: 0.5794 - throttle_out_acc: 0.5682
Epoch 00012: val_loss improved from 2.36648 to 2.31995, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.3616 - angle_out_loss: 1.4535 - throttle_out_loss: 1.6349 - angle_out_acc: 0.5793 - throttle_out_acc: 0.5680 - val_loss: 2.3199 - val_angle_out_loss: 1.3824 - val_throttle_out_loss: 1.6288 - val_angle_out_acc: 0.5928 - val_throttle_out_acc: 0.5635
Epoch 13/100
63/64 [============================>.] - ETA: 0s - loss: 2.3167 - angle_out_loss: 1.4297 - throttle_out_loss: 1.6018 - angle_out_acc: 0.5877 - throttle_out_acc: 0.5725
Epoch 00013: val_loss improved from 2.31995 to 2.31693, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.3165 - angle_out_loss: 1.4279 - throttle_out_loss: 1.6026 - angle_out_acc: 0.5880 - throttle_out_acc: 0.5724 - val_loss: 2.3169 - val_angle_out_loss: 1.3568 - val_throttle_out_loss: 1.6385 - val_angle_out_acc: 0.5928 - val_throttle_out_acc: 0.5605
Epoch 14/100
62/64 [============================>.] - ETA: 0s - loss: 2.2868 - angle_out_loss: 1.4144 - throttle_out_loss: 1.5796 - angle_out_acc: 0.5868 - throttle_out_acc: 0.5766
Epoch 00014: val_loss improved from 2.31693 to 2.24896, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.2894 - angle_out_loss: 1.4154 - throttle_out_loss: 1.5817 - angle_out_acc: 0.5872 - throttle_out_acc: 0.5752 - val_loss: 2.2490 - val_angle_out_loss: 1.3076 - val_throttle_out_loss: 1.5952 - val_angle_out_acc: 0.6035 - val_throttle_out_acc: 0.5737
Epoch 15/100
63/64 [============================>.] - ETA: 0s - loss: 2.2467 - angle_out_loss: 1.3801 - throttle_out_loss: 1.5566 - angle_out_acc: 0.5887 - throttle_out_acc: 0.5745
Epoch 00015: val_loss did not improve from 2.24896
64/64 [==============================] - 3s 50ms/step - loss: 2.2467 - angle_out_loss: 1.3810 - throttle_out_loss: 1.5562 - angle_out_acc: 0.5884 - throttle_out_acc: 0.5742 - val_loss: 2.2712 - val_angle_out_loss: 1.3112 - val_throttle_out_loss: 1.6156 - val_angle_out_acc: 0.6089 - val_throttle_out_acc: 0.5625
Epoch 16/100
63/64 [============================>.] - ETA: 0s - loss: 2.2113 - angle_out_loss: 1.3579 - throttle_out_loss: 1.5323 - angle_out_acc: 0.5946 - throttle_out_acc: 0.5812
Epoch 00016: val_loss improved from 2.24896 to 2.23349, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 50ms/step - loss: 2.2103 - angle_out_loss: 1.3572 - throttle_out_loss: 1.5316 - angle_out_acc: 0.5953 - throttle_out_acc: 0.5813 - val_loss: 2.2335 - val_angle_out_loss: 1.2920 - val_throttle_out_loss: 1.5875 - val_angle_out_acc: 0.6113 - val_throttle_out_acc: 0.5732
Epoch 17/100
62/64 [============================>.] - ETA: 0s - loss: 2.1604 - angle_out_loss: 1.3338 - throttle_out_loss: 1.4935 - angle_out_acc: 0.5997 - throttle_out_acc: 0.5882
Epoch 00017: val_loss improved from 2.23349 to 2.20767, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.1608 - angle_out_loss: 1.3312 - throttle_out_loss: 1.4952 - angle_out_acc: 0.6007 - throttle_out_acc: 0.5875 - val_loss: 2.2077 - val_angle_out_loss: 1.2500 - val_throttle_out_loss: 1.5827 - val_angle_out_acc: 0.6270 - val_throttle_out_acc: 0.5757
Epoch 18/100
62/64 [============================>.] - ETA: 0s - loss: 2.1226 - angle_out_loss: 1.3036 - throttle_out_loss: 1.4708 - angle_out_acc: 0.6040 - throttle_out_acc: 0.5903
Epoch 00018: val_loss improved from 2.20767 to 2.18893, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 50ms/step - loss: 2.1239 - angle_out_loss: 1.3017 - throttle_out_loss: 1.4730 - angle_out_acc: 0.6046 - throttle_out_acc: 0.5903 - val_loss: 2.1889 - val_angle_out_loss: 1.2589 - val_throttle_out_loss: 1.5595 - val_angle_out_acc: 0.6172 - val_throttle_out_acc: 0.5835
Epoch 19/100
62/64 [============================>.] - ETA: 0s - loss: 2.0955 - angle_out_loss: 1.2993 - throttle_out_loss: 1.4459 - angle_out_acc: 0.6119 - throttle_out_acc: 0.6006
Epoch 00019: val_loss improved from 2.18893 to 2.16634, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.1009 - angle_out_loss: 1.3013 - throttle_out_loss: 1.4503 - angle_out_acc: 0.6113 - throttle_out_acc: 0.5996 - val_loss: 2.1663 - val_angle_out_loss: 1.2460 - val_throttle_out_loss: 1.5433 - val_angle_out_acc: 0.6211 - val_throttle_out_acc: 0.5923
Epoch 20/100
63/64 [============================>.] - ETA: 0s - loss: 2.0628 - angle_out_loss: 1.2745 - throttle_out_loss: 1.4256 - angle_out_acc: 0.6136 - throttle_out_acc: 0.6017
Epoch 00020: val_loss did not improve from 2.16634
64/64 [==============================] - 3s 50ms/step - loss: 2.0644 - angle_out_loss: 1.2772 - throttle_out_loss: 1.4259 - angle_out_acc: 0.6121 - throttle_out_acc: 0.6019 - val_loss: 2.1808 - val_angle_out_loss: 1.2118 - val_throttle_out_loss: 1.5749 - val_angle_out_acc: 0.6313 - val_throttle_out_acc: 0.5771
Epoch 21/100
63/64 [============================>.] - ETA: 0s - loss: 2.0410 - angle_out_loss: 1.2611 - throttle_out_loss: 1.4104 - angle_out_acc: 0.6146 - throttle_out_acc: 0.6104
Epoch 00021: val_loss improved from 2.16634 to 2.15919, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 2.0427 - angle_out_loss: 1.2631 - throttle_out_loss: 1.4111 - angle_out_acc: 0.6147 - throttle_out_acc: 0.6101 - val_loss: 2.1592 - val_angle_out_loss: 1.2323 - val_throttle_out_loss: 1.5430 - val_angle_out_acc: 0.6284 - val_throttle_out_acc: 0.5903
Epoch 22/100
63/64 [============================>.] - ETA: 0s - loss: 2.0196 - angle_out_loss: 1.2475 - throttle_out_loss: 1.3958 - angle_out_acc: 0.6190 - throttle_out_acc: 0.6040
Epoch 00022: val_loss improved from 2.15919 to 2.09381, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 50ms/step - loss: 2.0210 - angle_out_loss: 1.2475 - throttle_out_loss: 1.3973 - angle_out_acc: 0.6200 - throttle_out_acc: 0.6041 - val_loss: 2.0938 - val_angle_out_loss: 1.1728 - val_throttle_out_loss: 1.5074 - val_angle_out_acc: 0.6406 - val_throttle_out_acc: 0.5923
Epoch 23/100
63/64 [============================>.] - ETA: 0s - loss: 1.9801 - angle_out_loss: 1.2206 - throttle_out_loss: 1.3698 - angle_out_acc: 0.6231 - throttle_out_acc: 0.6128
Epoch 00023: val_loss improved from 2.09381 to 2.08714, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 1.9815 - angle_out_loss: 1.2210 - throttle_out_loss: 1.3710 - angle_out_acc: 0.6224 - throttle_out_acc: 0.6121 - val_loss: 2.0871 - val_angle_out_loss: 1.1866 - val_throttle_out_loss: 1.4938 - val_angle_out_acc: 0.6401 - val_throttle_out_acc: 0.6104
Epoch 24/100
62/64 [============================>.] - ETA: 0s - loss: 1.9418 - angle_out_loss: 1.2092 - throttle_out_loss: 1.3372 - angle_out_acc: 0.6261 - throttle_out_acc: 0.6196
Epoch 00024: val_loss did not improve from 2.08714
64/64 [==============================] - 3s 50ms/step - loss: 1.9433 - angle_out_loss: 1.2085 - throttle_out_loss: 1.3391 - angle_out_acc: 0.6266 - throttle_out_acc: 0.6180 - val_loss: 2.0993 - val_angle_out_loss: 1.1816 - val_throttle_out_loss: 1.5085 - val_angle_out_acc: 0.6465 - val_throttle_out_acc: 0.5864
Epoch 25/100
62/64 [============================>.] - ETA: 0s - loss: 1.9338 - angle_out_loss: 1.2083 - throttle_out_loss: 1.3297 - angle_out_acc: 0.6255 - throttle_out_acc: 0.6216
Epoch 00025: val_loss improved from 2.08714 to 2.06859, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 50ms/step - loss: 1.9345 - angle_out_loss: 1.2086 - throttle_out_loss: 1.3302 - angle_out_acc: 0.6249 - throttle_out_acc: 0.6223 - val_loss: 2.0686 - val_angle_out_loss: 1.1483 - val_throttle_out_loss: 1.4944 - val_angle_out_acc: 0.6548 - val_throttle_out_acc: 0.5981
Epoch 26/100
62/64 [============================>.] - ETA: 0s - loss: 1.9065 - angle_out_loss: 1.1931 - throttle_out_loss: 1.3100 - angle_out_acc: 0.6347 - throttle_out_acc: 0.6264
Epoch 00026: val_loss improved from 2.06859 to 2.04724, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 50ms/step - loss: 1.9099 - angle_out_loss: 1.1940 - throttle_out_loss: 1.3129 - angle_out_acc: 0.6349 - throttle_out_acc: 0.6260 - val_loss: 2.0472 - val_angle_out_loss: 1.1247 - val_throttle_out_loss: 1.4849 - val_angle_out_acc: 0.6597 - val_throttle_out_acc: 0.6099
Epoch 27/100
63/64 [============================>.] - ETA: 0s - loss: 1.8839 - angle_out_loss: 1.1701 - throttle_out_loss: 1.2988 - angle_out_acc: 0.6394 - throttle_out_acc: 0.6255
Epoch 00027: val_loss did not improve from 2.04724
64/64 [==============================] - 3s 50ms/step - loss: 1.8852 - angle_out_loss: 1.1681 - throttle_out_loss: 1.3012 - angle_out_acc: 0.6398 - throttle_out_acc: 0.6250 - val_loss: 2.0572 - val_angle_out_loss: 1.1412 - val_throttle_out_loss: 1.4866 - val_angle_out_acc: 0.6479 - val_throttle_out_acc: 0.5933
Epoch 28/100
63/64 [============================>.] - ETA: 0s - loss: 1.8520 - angle_out_loss: 1.1541 - throttle_out_loss: 1.2749 - angle_out_acc: 0.6404 - throttle_out_acc: 0.6341
Epoch 00028: val_loss did not improve from 2.04724
64/64 [==============================] - 3s 50ms/step - loss: 1.8504 - angle_out_loss: 1.1530 - throttle_out_loss: 1.2740 - angle_out_acc: 0.6406 - throttle_out_acc: 0.6342 - val_loss: 2.0524 - val_angle_out_loss: 1.1295 - val_throttle_out_loss: 1.4877 - val_angle_out_acc: 0.6543 - val_throttle_out_acc: 0.5962
Epoch 29/100
62/64 [============================>.] - ETA: 0s - loss: 1.8219 - angle_out_loss: 1.1461 - throttle_out_loss: 1.2488 - angle_out_acc: 0.6444 - throttle_out_acc: 0.6342
Epoch 00029: val_loss did not improve from 2.04724
64/64 [==============================] - 3s 50ms/step - loss: 1.8202 - angle_out_loss: 1.1419 - throttle_out_loss: 1.2493 - angle_out_acc: 0.6456 - throttle_out_acc: 0.6344 - val_loss: 2.0724 - val_angle_out_loss: 1.1363 - val_throttle_out_loss: 1.5042 - val_angle_out_acc: 0.6602 - val_throttle_out_acc: 0.6060
Epoch 30/100
63/64 [============================>.] - ETA: 0s - loss: 1.8018 - angle_out_loss: 1.1369 - throttle_out_loss: 1.2334 - angle_out_acc: 0.6469 - throttle_out_acc: 0.6393
Epoch 00030: val_loss improved from 2.04724 to 2.03566, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 1.8012 - angle_out_loss: 1.1339 - throttle_out_loss: 1.2343 - angle_out_acc: 0.6475 - throttle_out_acc: 0.6389 - val_loss: 2.0357 - val_angle_out_loss: 1.1356 - val_throttle_out_loss: 1.4679 - val_angle_out_acc: 0.6475 - val_throttle_out_acc: 0.6104
Epoch 31/100
62/64 [============================>.] - ETA: 0s - loss: 1.7853 - angle_out_loss: 1.1236 - throttle_out_loss: 1.2235 - angle_out_acc: 0.6479 - throttle_out_acc: 0.6462
Epoch 00031: val_loss improved from 2.03566 to 2.02520, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 1.7898 - angle_out_loss: 1.1253 - throttle_out_loss: 1.2271 - angle_out_acc: 0.6472 - throttle_out_acc: 0.6450 - val_loss: 2.0252 - val_angle_out_loss: 1.1151 - val_throttle_out_loss: 1.4677 - val_angle_out_acc: 0.6616 - val_throttle_out_acc: 0.6143
Epoch 32/100
62/64 [============================>.] - ETA: 0s - loss: 1.7563 - angle_out_loss: 1.1123 - throttle_out_loss: 1.2002 - angle_out_acc: 0.6503 - throttle_out_acc: 0.6525
Epoch 00032: val_loss did not improve from 2.02520
64/64 [==============================] - 3s 50ms/step - loss: 1.7569 - angle_out_loss: 1.1140 - throttle_out_loss: 1.1998 - angle_out_acc: 0.6493 - throttle_out_acc: 0.6523 - val_loss: 2.0255 - val_angle_out_loss: 1.1203 - val_throttle_out_loss: 1.4654 - val_angle_out_acc: 0.6572 - val_throttle_out_acc: 0.6123
Epoch 33/100
63/64 [============================>.] - ETA: 0s - loss: 1.7554 - angle_out_loss: 1.1136 - throttle_out_loss: 1.1985 - angle_out_acc: 0.6458 - throttle_out_acc: 0.6498
Epoch 00033: val_loss did not improve from 2.02520
64/64 [==============================] - 3s 50ms/step - loss: 1.7560 - angle_out_loss: 1.1128 - throttle_out_loss: 1.1996 - angle_out_acc: 0.6458 - throttle_out_acc: 0.6493 - val_loss: 2.0505 - val_angle_out_loss: 1.1340 - val_throttle_out_loss: 1.4835 - val_angle_out_acc: 0.6592 - val_throttle_out_acc: 0.6099
Epoch 34/100
63/64 [============================>.] - ETA: 0s - loss: 1.7325 - angle_out_loss: 1.1067 - throttle_out_loss: 1.1791 - angle_out_acc: 0.6527 - throttle_out_acc: 0.6545
Epoch 00034: val_loss improved from 2.02520 to 1.99127, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 1.7275 - angle_out_loss: 1.1035 - throttle_out_loss: 1.1757 - angle_out_acc: 0.6533 - throttle_out_acc: 0.6553 - val_loss: 1.9913 - val_angle_out_loss: 1.0866 - val_throttle_out_loss: 1.4480 - val_angle_out_acc: 0.6636 - val_throttle_out_acc: 0.6226
Epoch 35/100
63/64 [============================>.] - ETA: 0s - loss: 1.7103 - angle_out_loss: 1.0837 - throttle_out_loss: 1.1684 - angle_out_acc: 0.6601 - throttle_out_acc: 0.6572
Epoch 00035: val_loss did not improve from 1.99127
64/64 [==============================] - 3s 50ms/step - loss: 1.7076 - angle_out_loss: 1.0810 - throttle_out_loss: 1.1672 - angle_out_acc: 0.6608 - throttle_out_acc: 0.6576 - val_loss: 1.9994 - val_angle_out_loss: 1.0877 - val_throttle_out_loss: 1.4555 - val_angle_out_acc: 0.6660 - val_throttle_out_acc: 0.6099
Epoch 36/100
63/64 [============================>.] - ETA: 0s - loss: 1.6924 - angle_out_loss: 1.0825 - throttle_out_loss: 1.1511 - angle_out_acc: 0.6592 - throttle_out_acc: 0.6610
Epoch 00036: val_loss did not improve from 1.99127
64/64 [==============================] - 3s 50ms/step - loss: 1.6950 - angle_out_loss: 1.0821 - throttle_out_loss: 1.1539 - angle_out_acc: 0.6593 - throttle_out_acc: 0.6594 - val_loss: 2.0371 - val_angle_out_loss: 1.1129 - val_throttle_out_loss: 1.4807 - val_angle_out_acc: 0.6567 - val_throttle_out_acc: 0.6104
Epoch 37/100
63/64 [============================>.] - ETA: 0s - loss: 1.6769 - angle_out_loss: 1.0704 - throttle_out_loss: 1.1417 - angle_out_acc: 0.6638 - throttle_out_acc: 0.6616
Epoch 00037: val_loss did not improve from 1.99127
64/64 [==============================] - 3s 50ms/step - loss: 1.6785 - angle_out_loss: 1.0716 - throttle_out_loss: 1.1427 - angle_out_acc: 0.6636 - throttle_out_acc: 0.6611 - val_loss: 2.0072 - val_angle_out_loss: 1.0874 - val_throttle_out_loss: 1.4635 - val_angle_out_acc: 0.6646 - val_throttle_out_acc: 0.6118
Epoch 38/100
63/64 [============================>.] - ETA: 0s - loss: 1.6569 - angle_out_loss: 1.0749 - throttle_out_loss: 1.1194 - angle_out_acc: 0.6618 - throttle_out_acc: 0.6710
Epoch 00038: val_loss did not improve from 1.99127
64/64 [==============================] - 3s 50ms/step - loss: 1.6566 - angle_out_loss: 1.0776 - throttle_out_loss: 1.1178 - angle_out_acc: 0.6605 - throttle_out_acc: 0.6713 - val_loss: 2.0223 - val_angle_out_loss: 1.0740 - val_throttle_out_loss: 1.4853 - val_angle_out_acc: 0.6782 - val_throttle_out_acc: 0.6196
Epoch 39/100
63/64 [============================>.] - ETA: 0s - loss: 1.6337 - angle_out_loss: 1.0643 - throttle_out_loss: 1.1015 - angle_out_acc: 0.6638 - throttle_out_acc: 0.6716
Epoch 00039: val_loss improved from 1.99127 to 1.94174, saving model to /content/mycar/models/mypilot.h5
64/64 [==============================] - 3s 51ms/step - loss: 1.6348 - angle_out_loss: 1.0660 - throttle_out_loss: 1.1018 - angle_out_acc: 0.6639 - throttle_out_acc: 0.6718 - val_loss: 1.9417 - val_angle_out_loss: 1.1158 - val_throttle_out_loss: 1.3838 - val_angle_out_acc: 0.6641 - val_throttle_out_acc: 0.6177
Epoch 40/100
63/64 [============================>.] - ETA: 0s - loss: 1.6047 - angle_out_loss: 1.0482 - throttle_out_loss: 1.0806 - angle_out_acc: 0.6632 - throttle_out_acc: 0.6727
Epoch 00040: val_loss did not improve from 1.94174
64/64 [==============================] - 3s 50ms/step - loss: 1.6059 - angle_out_loss: 1.0478 - throttle_out_loss: 1.0820 - angle_out_acc: 0.6638 - throttle_out_acc: 0.6726 - val_loss: 2.1267 - val_angle_out_loss: 1.1378 - val_throttle_out_loss: 1.5578 - val_angle_out_acc: 0.6611 - val_throttle_out_acc: 0.5977
Epoch 41/100
63/64 [============================>.] - ETA: 0s - loss: 1.6027 - angle_out_loss: 1.0421 - throttle_out_loss: 1.0816 - angle_out_acc: 0.6705 - throttle_out_acc: 0.6760
Epoch 00041: val_loss did not improve from 1.94174
64/64 [==============================] - 3s 50ms/step - loss: 1.6017 - angle_out_loss: 1.0461 - throttle_out_loss: 1.0786 - angle_out_acc: 0.6697 - throttle_out_acc: 0.6770 - val_loss: 2.0650 - val_angle_out_loss: 1.0897 - val_throttle_out_loss: 1.5202 - val_angle_out_acc: 0.6782 - val_throttle_out_acc: 0.6074
Epoch 42/100
62/64 [============================>.] - ETA: 0s - loss: 1.6009 - angle_out_loss: 1.0586 - throttle_out_loss: 1.0716 - angle_out_acc: 0.6682 - throttle_out_acc: 0.6746
Epoch 00042: val_loss did not improve from 1.94174
64/64 [==============================] - 3s 51ms/step - loss: 1.5973 - angle_out_loss: 1.0587 - throttle_out_loss: 1.0679 - angle_out_acc: 0.6682 - throttle_out_acc: 0.6753 - val_loss: 2.0174 - val_angle_out_loss: 1.0967 - val_throttle_out_loss: 1.4690 - val_angle_out_acc: 0.6685 - val_throttle_out_acc: 0.6221
Epoch 43/100
63/64 [============================>.] - ETA: 0s - loss: 1.5671 - angle_out_loss: 1.0455 - throttle_out_loss: 1.0444 - angle_out_acc: 0.6656 - throttle_out_acc: 0.6837
Epoch 00043: val_loss did not improve from 1.94174
64/64 [==============================] - 3s 50ms/step - loss: 1.5656 - angle_out_loss: 1.0453 - throttle_out_loss: 1.0430 - angle_out_acc: 0.6660 - throttle_out_acc: 0.6840 - val_loss: 2.0173 - val_angle_out_loss: 1.1034 - val_throttle_out_loss: 1.4656 - val_angle_out_acc: 0.6606 - val_throttle_out_acc: 0.6128
Epoch 44/100
63/64 [============================>.] - ETA: 0s - loss: 1.5590 - angle_out_loss: 1.0230 - throttle_out_loss: 1.0475 - angle_out_acc: 0.6747 - throttle_out_acc: 0.6850
Epoch 00044: val_loss did not improve from 1.94174
64/64 [==============================] - 3s 50ms/step - loss: 1.5619 - angle_out_loss: 1.0276 - throttle_out_loss: 1.0481 - angle_out_acc: 0.6736 - throttle_out_acc: 0.6849 - val_loss: 2.0355 - val_angle_out_loss: 1.0995 - val_throttle_out_loss: 1.4858 - val_angle_out_acc: 0.6763 - val_throttle_out_acc: 0.6069
Epoch 00044: early stopping
Training completed in 0:02:31.


donkey_car_45_190730.png

68 % 程度の精度だった。低い。。。やはり、家の中を白線無しで学習させたのが良くなかったのかも?

学習済みデータ mypilot.h5 をダウンロードした。
donkey_car_46_190731.png

自動走行
Donkey Car のRaspberry Pi に mypilot.h5 をアップロードした。
donkey_car_47_190731.png

myconfig.py を表示して、

DEFAULT_MODEL_TYPE="categorical"

に変更した。
donkey_car_48_190731.png

mycar ディレクトリで下のコマンドを実行して自動走行させた。
python manage.py drive --model ~/mycar/models/mypilot.h5
donkey_car_50_190731.png

(env) pi@donkeypi:~/mycar $ python manage.py drive --model ~/mycar/models/mypilot.h5
using donkey v3.0.2 ...
loading config file: /home/pi/mycar/config.py
loading personal config over-rides

config loaded
cfg.CAMERA_TYPE PICAM
PiCamera loaded.. .warming camera
Adding part PiCamera.
Starting Donkey Server...
Adding part LocalWebController.
Adding part ThrottleFilter.
Adding part PilotCondition.
Adding part RecordTracker.
"get_model_by_type" model Type is: categorical
loading model /home/pi/mycar/models/mypilot.h5
finished loading in 12.697422981262207 sec.
Adding part FileWatcher.
Adding part FileWatcher.
Adding part DelayedTrigger.
Adding part TriggeredCallback.
Adding part KerasCategorical.
Adding part DriveMode.
Adding part AiLaunch.
Adding part AiRunCondition.
Init ESC
Adding part PWMSteering.
Adding part PWMThrottle.
Tub does NOT exist. Creating new tub...
New tub created at: /home/pi/mycar/data/tub_8_19-07-30
Adding part TubWriter.
You can now go to <your pi ip address>:8887 to drive your car.
Starting vehicle...
8887
/usr/lib/python3/dist-packages/picamera/encoders.py:544: PiCameraResolutionRounded: frame size rounded up from 160x120 to 160x128
  width, height, fwidth, fheight)))
WARNING: Logging before flag parsing goes to stderr.
W0730 20:43:33.409733 1518576752 web.py:2246] 404 GET /favicon.ico (192.168.3.7) 11.80ms


ブラウザで 192.168.3.34:8887 を見るとカメラ画像が表示されていた。
donkey_car_49_190731.png

Mode & Pilot を Local Pilot (d) に変更したところ、自動走行がスタートした。
精度が低いので、自動走行では正しく走らなかったが、正しい方向に曲がる意志は確認できた。

^CShutting down vehicle and its parts...
stoping PiCamera
Part Profile Summary: (times in ms)
+--------------------+------------------+-------+--------------+
|        part        |       max        |  min  |     avg      |
+--------------------+------------------+-------+--------------+
|    PWMThrottle     |      20.27       |  1.46 |     2.60     |
|    FileWatcher     |       7.28       |  0.08 |     0.23     |
|    PWMSteering     | 1564516404941.14 |  1.55 | 128660891.52 |
| LocalWebController |       0.63       |  0.04 |     0.11     |
|     DriveMode      |       0.80       |  0.04 |     0.08     |
|   AiRunCondition   |       0.46       |  0.02 |     0.05     |
|   ThrottleFilter   |       0.49       |  0.03 |     0.06     |
|   PilotCondition   |       0.26       |  0.02 |     0.05     |
|   RecordTracker    |       0.30       |  0.02 |     0.05     |
|  KerasCategorical  |     2200.69      | 42.03 |    72.93     |
| TriggeredCallback  |       0.29       |  0.02 |     0.03     |
|      PiCamera      |       0.50       |  0.02 |     0.07     |
|      AiLaunch      |       0.76       |  0.03 |     0.06     |
|    FileWatcher     |       1.64       |  0.04 |     0.08     |
|   DelayedTrigger   |       0.18       |  0.02 |     0.04     |
+--------------------+------------------+-------+--------------+


tub_7_19-07-29 ディレクトリの最初の学習データ (160 x 120 ピクセル)を示す。
donkey_car_51_190731.png

そのJSON ファイル、record_1.json を示す。

{"user/mode": "user", "user/angle": 0.0, "user/throttle": 3.051850947599719e-05, "cam/image_array": "1_cam-image_array_.jpg", "milliseconds": 323}

  1. 2019年07月31日 05:35 |
  2. Donkey Car
  3. | トラックバック:0
  4. | コメント:0

”アルキメデスの大戦”を見てきました

アルキメデスの大戦”を奥さんと見てきた。面白かった。菅田さんが式を書くところで、一気に書いてたけど覚えたのだろうか?そのとも数字はいい加減か?
年寄り俳優陣もとっても良かったです。
  1. 2019年07月29日 04:46 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Donkey Car のキャリブレーション、教師データの取得を行った

Donkey Car のMicroSD カードを作成した”の続き。

前回は、Donkey Car のMicro SDカードを作成し、Donkey Car のRaspberry Pi 3B+ に無線LAN経由でログインすることができた。今回は、Donkey Car のキャリブレーションを行って、コースを走らせて教師データを取得した。

キャリブレーション
最初にモーターのキャリブレーションを行った。
donkey calibrate --channel 0 --bus 1
donkey_car_24_190728.png

370 を停止状態として、前進が 420 、後進が 330 くらいにした。

~/mycar/myconfig.py に記述した。
donkey_car_25_190728.png

ただし、実際に動かしてみた時に動かなかったので 450 と 300 に変更した。

次に、ステアリングのキャリブレーションを行った。
donkey calibrate --channel 1 --bus 1
donkey_car_26_190728.png

左 440、右 340 とした。
この値を~/mycar/myconfig.py に記述した。
donkey_car_27_190728.png

Cameraの有効化
~/mycar/myconfig.py のカメラ部分のコメントを外して、設定した。
donkey_car_28_190728.png

教師データの作成
Donkey Car のUSB ポートにジョイスティックのドングルを取り付けた。

教師データの取得
cd ~/mycar
python manage.py drive --js

donkey_car_29_190728.png
donkey_car_30_190728.png

donkey_car_31_190728.png

教師データを取得している間、コースを走らせてみた。
donkey_car_34_190729.jpg

コースが狭くて、うまく走らせることができなかった。
でも、データは取得できた。JPEGの画像ファイルと、その時のスロットルやステアリングの情報が書かれたJSON ファイルの組になっている。
donkey_car_33_190728.png

donkey_car_34_190728.png

なお、Donkey Car に nautilus をインストールした。
sudo apt install nautilus
でインストールすることができた。
  1. 2019年07月29日 04:35 |
  2. Donkey Car
  3. | トラックバック:0
  4. | コメント:0

Donkey Car のMicroSD カードを作成した

Donkey Car を組み立てた”の続き。

前回は、Donkey Car を組み立てた。今回は、Donkey Car のMicro SDカードを作成する。

FaBo DonkeyCar Docs の RaspPi3用のイメージ作成”を参考にする。

まずは、MicroSD カードにイメージを焼く Etcher をインストールした。インストールの参考にしたのは、”balena-io/etcher
Ubuntu 18.04 には、
echo "deb https://deb.etcher.io stable etcher" | sudo tee /etc/apt/sources.list.d/balena-etcher.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 379CE192D401AB61
sudo apt-get update
sudo apt-get install balena-etcher-electron

でインストールできた。
起動のコマンドは、
balena-etcher-electron
だった。
「Google Colaboraotoryと連携するために、DonkeyCar 3.0.2, TernsorFlow 2.0.0 beta1をインストールしたRaspberryPi用イメージ」を”balena-io/etcher”からダウンロードして、Etcher で書いた。
Etcher では、ZIPファイルのまま指定するようだ。
donkey_car_15_190727.png

書き込み後、カードリーダーを抜いて挿すと、boot 、 rootfs の 2 つのパーティションがUbuntu 18.04 にマウントされた。
donkey_car_16_190727.png

donkey_car_17_190727.png

boot の容量は 44.3 MB。その内の 23.4 MB を使用している。
donkey_car_18_190727.png

rootfs の容量は、 3.5 GB で、その内の 2.6 GB を使用している。32 GB のMicroSD カード使っているので、容量を拡張したいと思ったが、Raspberry Pi で起動したら容量が増えていた。
donkey_car_19_190727.png

Wifi の設定
FaBo DonkeyCar Docs の”Wifi の設定”に基づいて、Raspberry Pi 3 B+ のWifi の設定を行った。
donkey_car_20_190727.png

SSHでRaspberryPiのログイン
ここで、Raspberry Pi 3 B+ のIP アドレスを調べる方法だが、IP アドレスのスキャンのarp-scan コマンドを使用することにした。
”LAN内で利用されているIPアドレスを調べる『arp-scan』コマンド”を参照しながら、arp-scan をインストールした。
sudo apt install arp-scan

Donkey Car の Raspberry Pi 3B+ を起動しておいて、arp-scan を行うと、Raspberry Pi 3B+ が見えた。
donkey_car_21_190727.png

Raspberry Pi 3B+ の IP アドレスは、192.168.3.34 だった。

Raspberry Pi 3B+ の IP アドレスが分かったので、ホストパソコンから接続する。
ssh 192.168.3.34 -X -l pi
パスワードは raspberry だった。
donkey_car_22_190727.png

Projectの作成
donkey createcar --path ~/mycar
を実行した。
donkey_car_23_190727.png
  1. 2019年07月28日 05:10 |
  2. Donkey Car
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する11(アプリケーションで動作確認)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する10(CDCでUnsafeにならない記述)”の続き。

前回は、CDC でUnsafe を 0 にすることを目標にaxis2video_out.v の Verilog HDL コードを修正した。今回は、アプリケーション・ソフトを作成して、回路を動作させてみよう。

最初に、ビットストリームの生成を行ったので、ホストパソコンで、fpga_dp.bin を作成した。
cd ~/Docker/vivado182ub16/masaaki/ultra96_design/ultra96_design_dp/ultra96_design.runs/impl_1/
bootgen -image fpga.bif -arch zynqmp -w -o fpga_dp.bin

fpga_dp.bin を生成した。

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する8(ブロックデザインの変更)”にも書いたが、v4l2.dts を書き換えた。

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba_pl@0";
        #address-celss = <2>;
        #size-cells = <2>;
        __overlay__ {
            v4l2 {
                compatible = "fixstars,zynq-v4l2-1.0";
                #interrupt-cells = <0x3>;
                device-name="v4l2";
                interrupt-parent = <&gic>;
                interrupts = <0x0 0x59 0x4>;
            };
            
            axi_vdma_uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0010000 0x0 0x1000>;
            };
            
            display_dmar_axis_vga_uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0030000 0x0 0x10000>;
            };
                
            disp_gpio_uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0011000 0x0 0x1000>;
            };
            
            gpio_uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0012000 0x0 0x1000>;
            };
            
        };
    };
};


fpga-load.dts も fpga_dp.bin を使うように書き換えた。

/dts-v1/;
/ {
    fragment@0 {
        target-path = "/fpga-full";
        __overlay__ {
            firmware-name = "fpga_dp.bin";
        };
    };
};


余計な部分はあるが、”カメラ画像をDisplayPortに出力する9(アプリを作成、完成)”を参照して、 pcam5c_disp_dp.cpp を作成した。ソースコードを示す。

// pcam5c_disp_dp.cpp
// 2019/07/24 by marsee
//
// This software converts the left and right of the camera image to BMP file.
// -b : bmp file name
// -n : Start File Number
// -h : help

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

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

#define PIXEL_NUM_OF_BYTES    4
#define NUMBER_OF_WRITE_FRAMES  3

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

#define XGA_HORIZONTAL_PIXELS  1024
#define XGA_VERTICAL_LINES     768
#define XGA_ALL_DISP_ADDRESS   (XGA_HORIZONTAL_PIXELS * XGA_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define XGA_3_PICTURES         (XGA_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)

#define HD_HORIZONTAL_PIXELS  1920
#define HD_VERTICAL_LINES     1080
#define HD_ALL_DISP_ADDRESS   (HD_HORIZONTAL_PIXELS * HD_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
#define HD_3_PICTURES         (HD_ALL_DISP_ADDRESS * NUMBER_OF_WRITE_FRAMES)

int main(int argc, char *argv[]){
    int opt;
    int c, help_flag=0;
    char bmp_fn[256] = "bmp_file";
    char  attr[1024];
    unsigned long  phys_addr;
    int file_no = -1;
    int fd1, fd2, fd3, fd4;
    volatile unsigned int *axi_vdma_uio, *display_dmar_axis_vga_uio, *disp_gpio_uio, *gpio_uio;
    int active_frame;
    int resolution;
    int all_disp_addr;
    uint32_t row, col;
    int disp_active_frame=0;
    
    resolution = 1; // XGA
    while ((opt=getopt(argc, argv, "b:n:h:r:")) != -1){
    switch (opt){
        case 'b':
            strcpy(bmp_fn, optarg);
            break;
        case 'n':
            file_no = atoi(optarg);
            printf("file_no = %d\n", file_no+1);
            break;
        case 'r':
            resolution = atoi(optarg);
            break;
        case 'h':
            help_flag = 1;
            break;
        }
    }
    if(resolution == 0){
        printf("SVGA\n");
    } else if(resolution == 1){
        printf("XGA\n");
    } else {
        printf("HD\n");
    }
       
    // all_disp_addr
    switch(resolution){
        case 0 :
            all_disp_addr = SVGA_ALL_DISP_ADDRESS;
            row = SVGA_VERTICAL_LINES; col = SVGA_HORIZONTAL_PIXELS;
            break;
        case 1 :
            all_disp_addr = XGA_ALL_DISP_ADDRESS;
            row = XGA_VERTICAL_LINES; col = XGA_HORIZONTAL_PIXELS;
            break;
        default : // 2
            all_disp_addr = HD_ALL_DISP_ADDRESS;
            row = HD_VERTICAL_LINES; col = HD_HORIZONTAL_PIXELS;
            break;
    }
    

    // axi_vdma_uio IP
    fd1 = open("/dev/uio1", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (axi_vdma_uio) open error\n");
        exit(-1);
    }
    axi_vdma_uio = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!axi_vdma_uio){
        fprintf(stderr, "axi_vdma_uio mmap error\n");
        exit(-1);
    }

    // display_dmar_axis_vga_uio IP
    fd2 = open("/dev/uio2", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd2 < 1){
        fprintf(stderr, "/dev/uio2 (display_dmar_axis_vga_uio) open error\n");
        exit(-1);
    }
    display_dmar_axis_vga_uio = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    if (!display_dmar_axis_vga_uio){
        fprintf(stderr, "display_dmar_axis_vga_uio mmap error\n");
        exit(-1);
    }

    // disp_gpio_uio IP
    fd3 = open("/dev/uio3", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd3 < 1){
        fprintf(stderr, "/dev/uio3 (disp_gpio_uio) open error\n");
        exit(-1);
    }
    disp_gpio_uio = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
    if (!disp_gpio_uio){
        fprintf(stderr, "disp_gpio_uio mmap error\n");
        exit(-1);
    }

    // gpio_uio IP
    fd4 = open("/dev/uio4", O_RDWR|O_SYNC); // Read/Write, The chache is disable
    if (fd4 < 1){
        fprintf(stderr, "/dev/uio4 (gpio_uio) open error\n");
        exit(-1);
    }
    gpio_uio = (volatile unsigned *)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
    if (!gpio_uio){
        fprintf(stderr, "gpio_uio mmap error\n");
        exit(-1);
    }
    
    uint32_t framebuf0, framebuf1, framebuf2;
    framebuf0 = axi_vdma_uio[43]; // 0xac
    framebuf1 = axi_vdma_uio[44]; // 0xb0
    framebuf2 = axi_vdma_uio[45]; // 0xb4
    printf("framebuf0 = %x; framebuf1 = %x; framebuf2 = %x\n", framebuf0, framebuf1, framebuf2);
    
    display_dmar_axis_vga_uio[4] = framebuf0; // 0x10, fb0_V
    display_dmar_axis_vga_uio[6] = framebuf1; // 0x18, fb1_V
    display_dmar_axis_vga_uio[8] = framebuf2; // 0x20, fb2_V
    display_dmar_axis_vga_uio[10] = row; // 0x28, row_V
    display_dmar_axis_vga_uio[12] = col; // 0x30, col_V
    disp_gpio_uio[0] = 1; // disp_dmar_axis_vga start(init_done = 1)

    c = getc(stdin);
    while(c != 'q'){
        switch ((char)c) {
            case 'f':
                printf("active frame = %d\n", gpio_uio[0]);
                break;
        }
        c = getc(stdin);
    }
    
    return(0);
}


Ultra96 上のDebian で g++_opencv コマンドで pcam5c_disp_dp.cpp をコンパイルした。
g++_opencv pcam5c_disp_dp.cpp

~/examples/Pcam5C_DP/ ディレクトリで以下のコマンドを実行した。
sudo ./init_camera.sh
sudo ./pcam5c_disp_dp

MIPI_DP_74_190727.png

f リターン・キーを押すと、VDMA が使用しているフレームバッファ番号が表示される。それによると 1, 2, 3 の 3 個だった。 0 〜 2 だと思っていたので、失敗した。disp_dmar_axis_vga IP を修正する必要がある。

それ以前に、フレームバッファのアドレスから見たフレームバッファ領域は、0xe1000 のようだ。
0xe1000 は、921600 / 640 / 480 = 3 バイトなので、現在の私のdisp_dmar_axis_vga IP ではうまく行かないのがわかった。私の考えるフォーマットは4バイト、32ビット単位となっているのだ。

また、”カメラ画像をDisplayPortに出力する9(アプリを作成、完成)”の ./disp_pattern.sh をコピーして実行したが、DisplayPort の画面は真っ暗だった。
  1. 2019年07月27日 07:14 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する10(CDCでUnsafeにならない記述)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する9(DisplayPort のクロック制約を追加)”の続き。

前回は、DisplayPort 用のクロックのdp_video_ref_clk の制約を追加していなかったので、追加した。これで十分だとは思うが、今回は、CDC でUnsafe を 0 にすることを目標にaxis2video_out.v の Verilog HDL コードを修正してみよう。

シンクロナイザの前に組み合わせ回路を置くと、CDC でUnsafe 判定されてしまう。つまり、組み合わせ回路に入力されるすべての信号を後段のシンクロナイザで使用するクロックに同期しておけば良いのではないだろうか?
そこで、axis2video_out_v1 IP のaxis2video_out.v を以下のように修正した。
MIPI_DP_69_190724.png

MIPI_DP_70_190724.png

axis2video_out.v を示す。

// axis2video_out.v
// 2019/01/14 by marsee
// 2019/01/23 : Fixed IP start state machine bug
// 2019/07/25 : Added (* ASYNC_REG = "TRUE" *) 
//

`default_nettype none

module axis2video_out
    (
        // Clock and Reset
        input wire  disp_clk,
        input wire  axi_clk,
        input wire  axi_rst_n,
        input wire  init_done,
        
        // AXI4-Stream
        input wire  [31:0] axis_tdata,
        input wire  axis_tvalid,
        output wire axis_tready,
        input wire  [3:0] axis_tkeep,
        input wire  [3:0] axis_tstrb,
        input wire  axis_tuser,
        input wire  axis_tlast,
        input wire  axis_tid,
        input wire  axis_tdest,
        
        // IP
        output reg  ip_start,
        input wire  ip_done,
        
        // video in
        input wire  de_in,
        input wire  vsync_in,
        input wire  hsync_in,
        
        // video_out
        output wire  [35:0] disp_pixel,
        output wire  de_out,
        output wire vsync_out,
        output wire  hsync_out
    );

    parameter       IDLE_START =    1'b0,
                    IP_START_1 =    1'b1;
    
    reg reset_disp_2b = 1'b1, reset_disp_1b = 1'b1;
    wire    reset_disp;
    reg fifo_reset_axi_2b = 1'b0, fifo_reset_axi_1b = 1'b0;
    wire    fifo_reset_axi;
    reg fifo_reset_disp_2b = 1'b0, fifo_reset_disp_1b = 1'b0;
    wire    fifo_reset_disp;
    reg     de_1d, vsync_1d, hsync_1d;
    (* ASYNC_REG = "TRUE" *) reg vsync_axi_1b, vsync_axi_2b;
    wire    vsync_axi;
    (* ASYNC_REG = "TRUE" *) reg vsync_axi_1d, vsync_axi_2d;
    reg     cs_start;
    wire    pfifo_empty, pfifo_full;
    wire [33:0] pfifo_dout;
    reg    vsync_rising_edge_axi, vsync_falling_edge_axi;
    (* ASYNC_REG = "TRUE" *) reg init_done_axi_1d, axi_rst_n_axi_1d;
    (* ASYNC_REG = "TRUE" *) reg init_done_axi_2d, axi_rst_n_axi_2d;
    (* ASYNC_REG = "TRUE" *) reg init_done_disp_1d, axi_rst_n_disp_1d;
    (* ASYNC_REG = "TRUE" *) reg init_done_disp_2d, axi_rst_n_disp_2d;
    
    always @(posedge disp_clk) begin
        if(reset_disp) begin
            de_1d <= 1'b0;
            vsync_1d <= 1'b0;
            hsync_1d <= 1'b0;
        end else begin
            de_1d <= de_in;
            vsync_1d <= vsync_in;
            hsync_1d <= hsync_in;
        end
    end
    always @(posedge axi_clk) begin
        init_done_axi_1d <= init_done;
        init_done_axi_2d <= init_done_axi_1d;
        axi_rst_n_axi_1d <= axi_rst_n;
        axi_rst_n_axi_2d <= axi_rst_n_axi_1d;
    end
    always @(posedge disp_clk) begin
        init_done_disp_1d <= init_done;
        init_done_disp_2d <= init_done_disp_1d;
        axi_rst_n_disp_1d <= axi_rst_n;
        axi_rst_n_disp_2d <= axi_rst_n_disp_1d;
    end
    
    // reset signals    
    always @(posedge axi_clk) begin
        fifo_reset_axi_2b <= ~init_done_axi_2d | ~axi_rst_n_axi_2d | vsync_axi;
        fifo_reset_axi_1b <= fifo_reset_axi_2b;
    end
    assign fifo_reset_axi = fifo_reset_axi_1b;
        
    always @(posedge disp_clk) begin
        fifo_reset_disp_2b <= ~init_done_disp_2d | ~axi_rst_n_disp_2d | vsync_1d;
        fifo_reset_disp_1b <= fifo_reset_disp_2b;
    end
    assign fifo_reset_disp = fifo_reset_disp_1b;
        
    always @(posedge disp_clk) begin
        reset_disp_2b <= ~init_done_disp_2d | ~axi_rst_n_disp_2d;
        reset_disp_1b <= reset_disp_2b;
    end
    assign reset_disp = reset_disp_1b;
    
    // vsync_rising_edge, vsync_falling_edge
    always @(posedge axi_clk) begin
        if (!axi_rst_n) begin
            vsync_axi_2b <= 1'b1;
            vsync_axi_1b <= 1'b1;
        end else begin
            vsync_axi_2b <= vsync_1d;
            vsync_axi_1b <= vsync_axi_2b;
        end
    end
    assign vsync_axi = vsync_axi_1b;
    
    always @(posedge axi_clk) begin
        if (!axi_rst_n) begin
            vsync_axi_1d <= 1'b1;
            vsync_axi_2d <= 1'b1;
        end else begin
            vsync_axi_1d <= vsync_axi;
            vsync_axi_2d <= vsync_axi_1d;
        end
    end

    always @(posedge axi_clk) begin
        if (!axi_rst_n) begin
            vsync_rising_edge_axi = 1'b0;
            vsync_falling_edge_axi = 1'b0;
        end else begin
            vsync_rising_edge_axi <= ~vsync_axi_2d & vsync_axi_1d;
            vsync_falling_edge_axi <= vsync_axi_2d & ~vsync_axi_1d;
        end
    end
    
    // IP start State Machine
    always @(posedge axi_clk) begin
        if (!axi_rst_n) begin
            cs_start <= IDLE_START;
            ip_start <= 1'b0;
        end else begin
            case (cs_start)
                IDLE_START : begin
                    ip_start <= 1'b0;
                    if (vsync_falling_edge_axi) begin
                        cs_start <= IP_START_1;
                        ip_start <= 1'b1;
                    end
                end
                IP_START_1 : begin
                    if (ip_done) begin
                        cs_start <= IDLE_START;
                        ip_start <= 1'b0;
                    end
                end
            endcase
        end
    end
    
    // data width 34 bits, 512 depth
    pixel_fifo pixel_fifo_i (
        .wr_rst(fifo_reset_axi),
        .wr_clk(axi_clk),
        .rd_rst(fifo_reset_disp),
        .rd_clk(disp_clk),
        .din({axis_tuser, axis_tlast, axis_tdata}),
        .dout(pfifo_dout),
        .wr_en(~pfifo_full & axis_tvalid),
        .full(pfifo_full),
        .rd_en(de_1d),
        .empty(pfifo_empty)
    );
    assign axis_tready = ~pfifo_full;
    
    assign disp_pixel = {pfifo_dout[7:0], 4'd0, pfifo_dout[23:16], 4'd0, pfifo_dout[15:8], 4'd0}; //BRG
    assign de_out = de_1d;
    assign vsync_out = vsync_1d;
    assign hsync_out = hsync_1d;
endmodule

`default_nettype wire


このVerilog HDL コードについて解説する。
まずは、CDC のタイミングレポートの読み方は、Xilinx 社のUsers Guide の”デザイ ン解析およびクロージャテクニック UG906 (v2018.2) 2018 年 6 月 6 日”の 72 ページからの”クロック乗せ換えレポー ト”に載っているので、それを参照のこと。
そして、76 ページの”表 2‐3: CDC ルールおよび説明”で、ASYNC_REG プロパティ とあるがこれは何だろうか?と調べてみると、”Vivado プロパテ ィ リファレンス UG912 (v2018.1) 2018 年 5 月 4 日”の 141 ページの”ASYNC_REG”に書いてあった。
それによると、ASYNC_REG は、普通のFF とは様々な違いがあるそうだ。一番大きな違いと思われる部分を引用する。

ASYNC_REG では、 タイミング違反が発生しても最後の既知の値を出力するようにレジスタが変更されます。


ASYNC REG に指定するには、Verilog HDL の場合は、reg 宣言の前に” (* ASYNC_REG = "TRUE" *)”を付加する。axis2video_out.v でもシンクロナイザで使用するレジスタの reg 宣言の前に” (* ASYNC_REG = "TRUE" *)”を書いておいた。

さらに、axis2video_out.v では、組み合わせ回路に入力するすべての非同期信号(init_done, axi_rst_n)毎にシンクロナイザで同期してから、組み合わせ回路に入力するようにした。

これで、もう一度、論理合成、インプリメンテーション、ビットストリームの生成を行った。結果を示す。
MIPI_DP_73_190726.png

CDC レポートを示す。
まずは、 clk_pl_0 から dp_clik の場合のUnsafe は 0 個だった。
MIPI_DP_71_190725.png

dp_clk から clk_pl_0 の場合のUnsafe も 0 個だった。
MIPI_DP_72_190725.png

これで、Vivado のCDC レポートも公認の回路になったようだ。
  1. 2019年07月26日 04:45 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する9(DisplayPort のクロック制約を追加)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する8(ブロックデザインの変更)”の続き。

前回は、active_frame をGPIO で観察できるようにブロックデザインにGPIO を追加して、論理合成、インプリメンテーション、ビットストリームの生成を行って、fpga_dp.bin を生成した。今回は、DisplayPort 用のクロックのdp_video_ref_clk の制約を追加していなかったので、追加した。

DisplayPort 用のクロックのdp_video_ref_clk の制約を追加していないことに気がついた。これはまずい。。。

ultra96_design_dp ディレクトリのultra96_design のVivado Project でOpen Synthesized Design をクリックして、Synthesized Design を立ち上げた。

Edit Timing Constraints をクリックして、 Timing Constraints ウインドウを立ち上げた。
Clocks のCreate Clock で”Double click to create a Create Clock constraint”をダブルクリックし、Create Clock ダイアログを立ち上げた。

dp_video_ref_clk を指定して、148.5 MHz に相当する 6.734 ns の制約をかけた。
MIPI_DP_55_190724.png

制約が追加された Timing Constraints ウインドウを示す。
MIPI_DP_56_190724.png

これで、論理合成、インプリメンテーション、ビットストリームの生成を行った。Project Summary を示す。
MIPI_DP_57_190724.png

Timing の Worst Negative Slack (WNS) が -1.454 ns でマイナスになっている。
Open Implemented Design をクリックして、タイミング違反を見てみよう。
MIPI_DP_58_190724.png

clk_pl_0 to dp_clk と dp_clk to clk_pl_0 がタイミング違反になっている。これは、クロック間の信号のやり取りなので、対策を施してあれば無視することができる。
そこで、Clock Domain Glossing 解析をしてみよう。
Reports メニューからTiming -> Report CDC... を選択する。
Report CDC ダイアログで、From を clk_pl_0 に、To を dp_clk に設定する。
MIPI_DP_59_190724.png

CDC 解析結果だが、Unsafe が 1 件あった。
MIPI_DP_60_190724.png

シンクロナイザの前に組み合わせ回路があるということだ。組み合わせ回路の後にシンクロナイザで問題があるのだろうか?
実際のVerilog HDL コードは、シンクロナイザに前に実際に組み合わせ回路がある。選択されている部分だ。
MIPI_DP_61_190724.png

次に dp_clk から clk_pl_0 へのパスを解析する。
MIPI_DP_62_190724.png

やはり、CDC 解析結果に Unsafe が 1 件あった。
MIPI_DP_63_190724.png

同様に、シンクロナイザの前に組み合わせ回路があるということだ。
実際のVerilog HDL コードを示す。選択されている部分がそうだ。
MIPI_DP_64_190724.png

組み合わせ回路はあるが後ろのシンクロナイザで同期化してあるので、大丈夫だろう?ということで、clk_pl_0 と dp_clk 間のタイミング解析を無視することにした。

Edit Timing Constrains をクリックして、False Path を設定する。
Set False Path ダイアログで、 clk_pl_0 から dp_clk へのパスを無視する。
MIPI_DP_65_190724.png

Set False Path ダイアログで、 dp_clk から clk_pl_0 へのパスを無視する。
MIPI_DP_66_190724.png

False Path が設定された。
MIPI_DP_67_190724.png

ビットストリームの生成まで行った。Project Summary を示す。
MIPI_DP_68_190724.png

今度は、タイミング・エラーが出ていない。
  1. 2019年07月24日 05:28 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する8(ブロックデザインの変更)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する7(現状確認2)”の続き。

前回は、VDMA のフレームバッファのアドレスが分かれば良いのでは? ということで、VDMA のステータスをRead してみた。今回は、VDMA のフレームバッファが正常に読めたので、それを元にアプリケーション・ソフトが書けそうだ。だが、VDMA の現在表示しているフレームバッファの番号を示すs2mm_frame_ptr_out を観察したいので、AXI_GPIO を追加して、もう一度、手順をやり直した。

まずは、axi_gpio_0 をブロックデザインに追加した。
MIPI_DP_39_190723.png

display 階層モジュールも貼っておく。
MIPI_DP_40_190723.png

Address Editor 画面を示す。
MIPI_DP_41_190723.png

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

ビットファイル(design_1_wrapper.bit)が生成された。

cd ~/Docker/vivado182ub16/masaaki/ultra96_design/ultra96_design_dp/ultra96_design.runs/impl_1/
bootgen -image fpga.bif -arch zynqmp -w -o fpga_dp.bin

fpga_dp.bin を生成した。
MIPI_DP_43_190723.png

MIPI_DP_44_190723.png

次には、Ultra96 の Debian 上での作業となる。
fpga ユーザーのホーム・ディレクトリの下の examples/Pcam5C_DP/ディレクトリを新規作成して、Pcam5C ディレクトリから必要なファイルをコピーした。

v4l2.dts を編集して、自分で追加したIP とVDMA のUIO エントリを追加した。
MIPI_DP_47_190723.png

/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba_pl@0";
        #address-celss = <2>;
        #size-cells = <2>;
        __overlay__ {
            v4l2 {
                compatible = "fixstars,zynq-v4l2-1.0";
                #interrupt-cells = <0x3>;
                device-name="v4l2";
                interrupt-parent = <&gic>;
                interrupts = <0x0 0x59 0x4>;
            };
            
            axi_vdma_uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0010000 0x0 0x1000>;
            };
            
            display_dmar_axis_vga_uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0030000 0x0 0x10000>;
            };
                
            disp_gpio_uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0011000 0x0 0x1000>;
            };
            
            gpio_uio {
                compatible = "generic-uio";
                reg = <0x0 0xA0012000 0x0 0x1000>;
            };
            
        };
    };
};



MIPI_DP_46_190723.png

先程の fpga_dp.bin をUltra96 の /home/fpga/examples/Pcam5C_DP/ ディレクトリに SFTP した。
MIPI_DP_48_190723.png
  1. 2019年07月23日 04:52 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する7(現状確認2)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する6(現状確認)”の続き。

前回は、Pcam5C カメラの画像をDisplayPort に出力するために現状を再確認したのだが、自分で 1 からソフトウェアを作るか、それてもV4L2 を勉強して、それに沿って作るか迷っていた。今回は、とりあえずは、フレームバッファからDMA Read して、DisplayPort に出力するだけなので、VDMA のフレームバッファのアドレスが分かれば良いのでは? ということで、VDMA のステータスをRead してみた。

まずは、Fixstars Tech Blog さんの「Ultra96 Linux で MIPI カメラから画像を取得する (セットアップ編)」のブロックデザインのAddress Editor の画面を示す。
Ultra96_Pcam5C_51_190721.png

これで見るとVDMA のアドレスは、0xA0010000 からの 4K バイトとなっている。
このレジスタをRead してくれば良い。そして、”Ultra96のDisplayPortを使用するためのテスト3(実機テスト)”に memwrite.c が載っているので、それを参考にして memread.c を作成した。
memread.c を示す。
MIPI_DP_31_190722.png

// memread.c
// 2019/07/21 : by marsee
// I referred to http://independence-sys.net/main/?p=2209
//

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

#define BLOCK_SIZE    4096

volatile uint32_t *reg;

int main(int argc, char **argv){
    int fd;
    void *memp;
    uint32_t phy_addr;
    uint32_t phy_addr_base;
    uint32_t addr, addr2;
    uint32_t write_data;
    
    if (argc != 2){
        fprintf(stderr, "Usage : ./memread <address(hex)>\n");
        exit(-1);
    }
    
    fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (fd == -1){
        fprintf(stderr, "/dev/mem open error\n");
        exit(-1);
    }
    
    sscanf(argv[1], "%x", &addr);
    phy_addr = (uint32_t)addr;
    phy_addr_base = phy_addr & 0xfffff000; // 4k byte boundary
    memp = mmap(NULL, BLOCK_SIZE,
                    PROT_READ | PROT_WRITE, MAP_SHARED,
                    fd, phy_addr_base );
    if ((int64_t)memp == -1){
        fprintf(stderr,"/dev/mem map error\n");
        exit(-1);
    }
    close(fd);
    
    reg = (uint32_t *)memp;
    int index = (phy_addr & 0xfff)/sizeof(uint32_t);
    printf("%0.8x\n", reg[index]);
    
    munmap((void *)memp, BLOCK_SIZE);

    return(0);
}


gcc -o memread memread.c
で、Ultra96 上の Debian でコンパイルし、memread ができた。
MIPI_DP_32_190722.png

次に、”Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる3”を見ながら、コマンドを実行していって、VDMA のレジスタ設定を確認していこう。

Ultra96 上の Debian の ~/examples/Pcam5C/ ディレクトリで、
sudo su
./init_camera.sh

を実行した。
MIPI_DP_33_190722.png

MIPI_DP_34_190722.png

なお、VDMA のマニュアルとして”AXI Video Direct Memory Access v6.3 LogiCORE IP Product Guide Vivado Design Suite PG020 October 4, 2017”を参照している。
AXI Video Direct Memory Access v6.3 LogiCORE IP Product Guide Vivado Design Suite PG020 October 4, 2017”のTable 2‐5: Register Address Map を引用する。
MIPI_DP_35_190722.png
MIPI_DP_36_190722.png

Table 2‐5: Register Address Map によると、AXI4 Stream から DMA Write の設定レジスタ S2MM VDMA Control Register が 0xA0010030 番地で、S2MM Start Address が 0xA00100AC, 0xA00100B0, 0xA00100B4 番地のようだ。

とりあえずは、memread で見てみよう。
0xA0010030 0x00010003
0xA00100AC 0x70900000
0xA00100B0 0x709e1000
0xA00100B4 0x70ac2000
だった。
MIPI_DP_37_190722.png

AXI Video Direct Memory Access v6.3 LogiCORE IP Product Guide Vivado Design Suite PG020 October 4, 2017”のFigure 2‐9: S2MM VDMACR Register を引用する。
MIPI_DP_38_190722.png

S2MM VDMA Control Register (0xA0010030) が 0x00010003 なので、
IRQFrameCount が 1 で、
Circular_Park が 1 なので、”1 = Circular Mode – Engine continuously circles through frame buffers.”
RS が 1 なので、”1 = Run – Start VDMA operations. The halted bit in the VDMA Status Register deasserts to 0 when the VDMA engine begins operations.”
であることが分かる。つまり、VDMA 動いているということだ。

次に、フレームバッファは、
フレームバッファ 0 が 0x70900000 番地、フレームバッファ 1 が 0x709e1000 番地、フレームバッファ 2 が 0x70ac2000 なので、ここからDMA Read すれば良いことが分かる。
  1. 2019年07月22日 04:44 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Donkey Car を組み立てた

今日はDonkey Car を組み立てた。

組み立て”を見ながらDockey Car を組み立てていった。

まずは、プレートにスペーサを立てて、Raspberry Pi 3B+ を固定した。
donkey_car_4_190721.jpg

プレートにアクリルのスペーサを入れて、プラネジで降圧型変換器内蔵電圧計を取り付けた。
donkey_car_5_190721.jpg

降圧型変換器内蔵電圧計からRaspberry Pi 3B+ に電源を接続した。
donkey_car_6_190721.jpg

降圧型変換器内蔵電圧計の入力ポートを接続した。
donkey_car_7_190721.jpg

Donkey アームを取り付けた。
donkey_car_8_190721.jpg

PiCameraを取り付けた。
donkey_car_9_190721.jpg

Donkey アームを固定ピンでポートに固定した。
donkey_car_10_190721.jpg

モーターとハンドル制御用のI2C ポートを接続した。
donkey_car_11_190721.jpg

完成。だけど、バッテリーは接続されていません。
donkey_car_12_190721.jpg

donkey_car_13_190721.jpg

donkey_car_14_190721.jpg

次には、MicroSD カードを焼こう。
  1. 2019年07月21日 21:59 |
  2. Donkey Car
  3. | トラックバック:0
  4. | コメント:0

”天気の子”(映画)を見てきました

今日は1人で”天気の子”(映画)を見てきました。
私にとってはとっても良かったです。もう一度見たいですね。反社会的なところはありますが、違和感は無かったです。
  1. 2019年07月21日 21:26 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

”トイストーリー4”を見てきました

トイストーリー4”を奥さんと見てきました。トイストーリーは1, 2, 3 と映画館で見てきましたが、やはり 3 が一番良いですね。4 で終わりなんじゃないか?と思いました。これでトイストーリーシリーズも終わりなんでしょうね。
  1. 2019年07月20日 22:40 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する6(現状確認)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する5(再度fpga.bin を生成)”の続き。

前回は、fpga.bin を再度生成した。今回はPcam5C カメラの画像をDisplayPort に出力するために現状を再確認しよう。

Pcam5C カメラ画像をFixstars Tech Blog さんの「Ultra96 Linux で MIPI カメラから画像を取得する (セットアップ編)」を参照して、Pcam5C カメラから PNG 画像を取得できた。それが、”Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる3”だった。
ただし、Fixstars Tech Blog さんの「7. display port 経由での外部ディスプレイ出力」をやってみたところうまく行かなかった。”Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる4”参照。

Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる3”をもう一度やってみた。
cd ~/example/Pcam5C/
sudo su
./init_camera.sh
cd test
./rgbtest

MIPI_DP_27_190718.png
MIPI_DP_28_190718.png

20 枚のカメラ画像が取得できた。
MIPI_DP_29_190718.png

rgbtest.cc を引用する。
MIPI_DP_30_190718.png

これで buf のアドレスを取得できれば良いな?と思ったが、仮想アドレスだし、物理アドレスに直しても連続しているとは限らないかも知れない?V4L2 も良く分からないので、ソフトウェアは自分で1から構築することにしようと思う。

現状で動作しているのが分かっているので、心強い。

VDMA も自分で設定してV4L2 を使わないのも良いかも知れない?
まずは、Ultra96 のPMOD 拡張ボード上のカメラからDisplayPort に出力した時の記事を示す。
カメラ画像をDisplayPortに出力する7(ブロックデザインの変更)
Zynq UltraScale+ MPSoC のDisplayPort のLiveVideo のピクセルデータ
カメラ画像を DisplayPortに出力する8(Ultra96 での準備)
カメラ画像を DisplayPortに出力する9(アプリを作成、完成)

VDMA の設定値は、”AXI VDMAのドライバによるレジスタの設定値(S2MMの設定)”を確認すると良い。

なお、V4L2 を使うの良いかも知れない?
ikwzm さんが教えてくれたV4L2 の資料。
V4L2 API とOpenCV を使ってビデオキャプチャ
Linux Media Infrastructure userspace API
「Linux Media Infrastructure userspace API 」の中で、バッファ関連の説明
  1. 2019年07月19日 05:34 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する5(再度fpga.bin を生成)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する4(再度ブロックデザインの変更)”の続き。

前回は、ultra96_design_dp ディレクトリのVivado 2018.2 プロジェクトのブロックデザインをdisp_dmar_axis_vga IP に入れ替えて、論理合成、インプリメンテーション、ビットストリームの生成を行った。今回は、fpga.bin を再度生成しよう。

fppga.bin を生成する。この作業は、”Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる2”を参照してやっていこう。

~/Docker/vivado182ub16/masaaki/ultra96_design/ultra96_design_dp/ultra96_design.runs/impl_1/ ディレクトリに design_1_wrapper.bit があるのを確認した。
MIPI_DP_15_190710.png

同じディレクトリに fpga.bif を作成した。
MIPI_DP_16_190710.png

all:
{
    [destination_device = pl] design_1_wrapper.bit
}


MIPI_DP_17_190710.png

cd Docker/vivado182ub16/masaaki/ultra96_design/ultra96_design_dp/ultra96_design.runs/impl_1/
同じディレクトリで、
bootgen -image fpga.bif -arch zynqmp -w -o fpga.bin
を実行したところ、fpga.bin が生成された。
MIPI_DP_18_190710.png

MIPI_DP_19_190710.png

なお、ツィッターでAdam Taylor さんが”This week I am showing how to get the Zynq MPSoC DisplayPort controller up and running with live video from the Programmable Logic using Bare Metal SW”とツィートしていて、”MicroZed Chronicles: DisplayPort Controller — Part One”も公開されているので、少し待っていようと思う。
  1. 2019年07月18日 05:03 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する4(再度ブロックデザインの変更)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する3(fpga.binファイルの生成)”の続き。

”Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する”シリーズも fpga.bin の生成まで行っているが、このままではまずい。なぜならば、VGA画像をXGA 画像やHD 画像に変換する必要がある。ということで、”VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 5(やっと完成2)”でVGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP を作成した。このDMA を使用するとVGA画像をXGA画像やHD画像に変換することができるので、”Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する2(ブロックデザインの変更)”のブロックデザインをdisp_dmar_axis_vga IP に入れ替えよう。

まずは、ultra96_design_dp ディレクトリのVivado 2018.2 プロジェクトを示す。
MIPI_DP_24_190717.png

ブロックデザインを示す。
MIPI_DP_21_190716.png

ultra96_design_dp ディレクトリにdisp_dmar_axis_vga_IP ディレクトリを作成し、”VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 5(やっと完成2)”で作成したIP のファイルをコピーした。
MIPI_DP_26_190717.png

IP Catalog にdisp_dmar_axis_vga を登録した。これで、disp_dmar_axis_vga を使用する準備が整った。
MIPI_DP_20_190716.png

ブロックデザインの中の display 階層モジュール内の disp_dmar_axis を削除して、disp_dmar_axis_vga に入れ替えた。
MIPI_DP_22_190716.png

Address Editor を示す。
MIPI_DP_23_190716.png

これで、論理合成、インプリメンテーション、ビットストリームの生成を行ったところ成功した。
Project Summary を示す。
MIPI_DP_25_190717.png
  1. 2019年07月17日 05:00 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 5(やっと完成2)

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 4(やっと完成1)”の続き。

前回は、風呂掃除をしていた時にふとひらめいた。いままで画像を拡張しない時はうまく行っていたdisp_dmar_axis IP があるのだから、それにHLSストリーム・インターフェースで画像を拡大するIP を付けたらどうか?そして、それらを並列化したら良いのでは?というアイデアだった。ということで、ソースコードを貼った。今回は、C シミュレーション、C コードの合成、C/RTL 協調シミュレーション、Export RTL を行った。

まずは、現在のdisp_dmar_axis_vga プロジェクトを示す。
disp_dmar_axis_vga_10_190715.png

C シミュレーションを行った。
disp_dmar_axis_vga_11_190715.png

dmar_result.bmp も問題ない。
disp_dmar_axis_vga_12_190715.png

disp_dmar_axis_vga_9_190713.jpg

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

これも良さそうだ。

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

Latency は 480036 クロックだった。これは、出力しているSVGA 画像の 800 x 600 = 480000 クロックとほぼ等しい。これは、良い結果が期待できそうだ。

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

m_axi_gmem_ARLEN を見ると、0f となっていて、16 バーストであることが分かる。
outs_TREADY と outs_TVALID もほとんど 1 固定だ。これは良い。

拡大した。
disp_dmar_axis_vga_17_190716.png

最後にExport RTL を行った。
disp_dmar_axis_vga_15_190715.png

CP achieved post-implementation は 3.305 ns で問題無さそうだ。

やはり、データを加工するDMA をVivado HLS で書く時は、シンプルなDMA してデータをHLSストリーム出力する関数と、HLSストリーム入出力のデータ加工関数を用意して、トップの関数でそれらを接続し、DATAFLOW 指示子で並列動作するように記述するのが賢いようだ。
  1. 2019年07月16日 04:59 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 4(やっと完成1)

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 3(2 種類の実装を試した)”の続き。

前回は、disp_dmar_axis IP 用のソースコードを 2 種類作って試してみたが、うまく行かなかった。今回は、風呂掃除をしていた時にひらめいたdisp_dmar_axis IP の実装を試してみよう。

風呂掃除をしていた時にふとひらめいた。いままで画像を拡張しない時はうまく行っていたdisp_dmar_axis IP があるのだから、それにHLSストリーム・インターフェースで画像を拡大するIP を付けたらどうか?そして、それらを並列化したら良いのでは?というアイデアだった。やはり、風呂掃除はアイデアが湧くのでお勧めである。皆さん、風呂掃除をしましょう。。。w

さて、今回はファイルも分けて、VGA画像を 3 チャネル分DMA するのが、vga_dmar_axis.cpp で、HLSストリーム・インターフェースで画像を拡大するIP が axis_expand.cpp (ちょっと名前をミスった)、全体をまとめるのが、disp_dmar_axis_vga.cpp となる。

disp_dmar_axis_vga.cpp のソースコードを示す。今回はインターフェースを変更して、row, col つまり画像の縦横のピクセル数を入力するようにした。

// disp_dmar_axis_vga.cpp
// 2019/07/11 by marsee
//

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

#include "disp_dmar_axis_vga.h"

int vga_dmar_axis(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<2> active_frame);

int axis_expand(AXI_STREAM &ins, AXI_STREAM &outs, int row, int col);

int disp_dmar_axis_vga(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<16> row, ap_uint<16> col, ap_uint<2> &active_frame){
#pragma HLS DATAFLOW
#pragma HLS INTERFACE ap_ctrl_hs port=return
#pragma HLS INTERFACE ap_none port=active_frame
#pragma HLS INTERFACE s_axilite port=row
#pragma HLS INTERFACE s_axilite port=col
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE m_axi depth=307200 port=fb2 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb1 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb0 offset=slave

    AXI_STREAM dmad;
#pragma HLS STREAM variable=dmad depth=64 dim=1

    vga_dmar_axis(fb0, fb1, fb2, dmad, active_frame);
    axis_expand(dmad, outs, row, col);
    
    return(0);
}


次に、vga_dmar_axis.cpp を示す。

// vga_dmar_axis.cpp
// 2019/07/13 by marsee
//

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

#include "disp_dmar_axis_vga.h"

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height);

int vga_dmar_axis(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<2> active_frame){

    AP_AXIU32 pix;

    if (active_frame == (ap_uint<2>)0)
        disp_dmar_fb2(fb2, outs, VGA_WIDTH, VGA_HEIGHT);
    else if (active_frame == (ap_uint<2>)1)
        disp_dmar_fb0(fb0, outs, VGA_WIDTH, VGA_HEIGHT);
    else
        disp_dmar_fb1(fb1, outs, VGA_WIDTH, VGA_HEIGHT);
    return(0);
}

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;

    LOOP_Y0: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=480 max=480 avg=480
        LOOP_X0: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=640 max=640 avg=640
#pragma HLS PIPELINE II=1
            pix.data = fb0[(y*max_width)+x];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}

int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;

    LOOP_Y1: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=480 max=480 avg=480
        LOOP_X1: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=640 max=640 avg=640
#pragma HLS PIPELINE II=1
            pix.data = fb1[(y*max_width)+x];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}

int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;

    LOOP_Y2: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=480 max=480 avg=480
        LOOP_X2: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=640 max=640 avg=640
#pragma HLS PIPELINE II=1
            pix.data = fb2[(y*max_width)+x];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}


axis_expand.cpp を示す。

// axis_expand.cpp
// 2019/07/13 by marsee
//


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

#include "disp_dmar_axis_vga.h"

int axis_expand(AXI_STREAM &ins, AXI_STREAM &outs, int row, int col){
    AP_AXIU32 pix;
    int x_padding = (col - VGA_WIDTH)/2;
    int y_padding = (row - VGA_HEIGHT)/2;

    for(int y=0; y<row; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        for(int x=0; x<col; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            if (y < y_padding || y >= y_padding+VGA_HEIGHT){
                pix.data = 0;
                pix.dest = 0;
                pix.id = 0;
                pix.keep = 0;
                pix.strb = 0;
            }else if (x < x_padding || x >= x_padding+VGA_WIDTH){
                pix.data = 0;
                pix.dest = 0;
                pix.id = 0;
                pix.keep = 0;
                pix.strb = 0;
            }else{
                ins >> pix;
            }

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == col-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}


前と同じだが、disp_dmar_axis_vga.h を示す。


// disp_dmar_axis_vga.h
// 2019/07/11 by marsee
//

#ifndef __DISP_DMAR_AXIS_VGA_H__
#define __DISP_DMAR_AXIS_VGA_H__

#include "ap_axi_sdata.h"
#include "hls_video.h"

#define VGA_WIDTH 640
#define VGA_HEIGHT 480

#define SVGA_WIDTH 800
#define SVGA_HEIGHT 600

#define XGA_WIDTH 1024
#define XGA_HEIGHT 768

#define HD_WIDTH 1920
#define HD_HEIGHT 1080

#define RESO_SVGA 0
#define RESO_XGA 1
#define RESO_HD  2

typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM;
typedef ap_axiu<32,1,1,1> AP_AXIU32;
typedef hls::Scalar<3, unsigned char> RGB_PIXEL;
typedef hls::Mat<HD_HEIGHT, HD_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<HD_HEIGHT, HD_WIDTH, HLS_8UC1> GRAY_IMAGE;

#endif


最後にbmp_file0.bmp だが、ブログに貼れないのでPNG ファイルを示す。
disp_dmar_axis_vga_8_190712.png
  1. 2019年07月15日 05:15 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 3(2 種類の実装を試した)

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 2(性能が足りない)”の続き。

前回は、disp_dmar_axis IP を作って、C シミュレーション、C コードの合成、C/RTL 協調シミュレーションを行ったが、C/RTL 協調シミュレーション波形から性能が足りないということが分かった。今回は、ソースコードを 2 種類書いて試してみたが、うまく行かなかった。

まずは、”2つのHLSストリームを同時に入力して演算してHLSストリーム出力2”を参考にして、DMA 部分とAXI4 Stream 部分を分けた。DMA部分では、VGA画像をDMA してHLS Stream で出力する。AXI4 Stream 部分では、DMA 部分からのAXI4 Stream を受けて、周りに 0 のデータを挿入して、解像度を大きくする。DMA 部分とAXI4 Stream 部分を別関数にして、DATAFLOW 指示子で並列動作を狙った。
ソースコード disp_dmar_axis_vga.cpp を示す。

// disp_dmar_axis_vga.cpp
// 2019/07/11 by marsee
//

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

#include "disp_dmar_axis_vga.h"

int disp_dmar_stream(AXI_STREAM &ins, AXI_STREAM &outs, int max_width, int max_height);
int fb0_hls_stream(volatile ap_int<32> *fb, AXI_STREAM &outs);
int fb1_hls_stream(volatile ap_int<32> *fb, AXI_STREAM &outs);
int fb2_hls_stream(volatile ap_int<32> *fb, AXI_STREAM &outs);

int disp_dmar_axis_vga(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<16> row, ap_uint<16> col, ap_uint<2> active_frame){
#pragma HLS INTERFACE s_axilite port=col
#pragma HLS INTERFACE s_axilite port=row
#pragma HLS DATAFLOW
#pragma HLS INTERFACE ap_ctrl_hs port=return
#pragma HLS INTERFACE ap_none port=active_frame
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE m_axi depth=307200 port=fb2 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb1 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb0 offset=slave

    AP_AXIU32 pix;
    AXI_STREAM indata0;
    AXI_STREAM indata1;
    AXI_STREAM indata2;
#pragma HLS STREAM variable=indata0 depth=64 dim=1
#pragma HLS STREAM variable=indata1 depth=64 dim=1
#pragma HLS STREAM variable=indata2 depth=64 dim=1

    if (active_frame == (ap_uint<2>)0){
        fb2_hls_stream(fb2, indata0);
        disp_dmar_stream(indata0, outs, col, row);
    }else if (active_frame == (ap_uint<2>)1){
        fb0_hls_stream(fb0, indata1);
        disp_dmar_stream(indata1, outs, col, row);
    }else{
        fb1_hls_stream(fb1, indata2);
        disp_dmar_stream(indata2, outs, col, row);
    }

    return(0);
}

int disp_dmar_stream(AXI_STREAM &ins, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    AP_AXIU32 dmad;

    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    LOOP_Y0: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X0: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            if (y < y_padding || y >= y_padding+VGA_HEIGHT)
                pix.data = 0;
            else if (x < x_padding || x >= x_padding+VGA_WIDTH)
                pix.data = 0;
            else{
                ins >> dmad;
                pix.data = dmad.data;
            }

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}

int fb0_hls_stream(volatile ap_int<32> *fb0, AXI_STREAM &outs){
    AP_AXIU32 dmad;

    LOOP_Y1: for(int y=0; y<VGA_HEIGHT; y++){
        LOOP_X1: for(int x=0; x<VGA_WIDTH; x++){
#pragma HLS PIPELINE II=1
            dmad.data = fb0[(y*VGA_WIDTH)+x];
            outs << dmad;
        }
    }
    return(0);
}

int fb1_hls_stream(volatile ap_int<32> *fb1, AXI_STREAM &outs){
    AP_AXIU32 dmad;

    LOOP_Y1: for(int y=0; y<VGA_HEIGHT; y++){
        LOOP_X1: for(int x=0; x<VGA_WIDTH; x++){
#pragma HLS PIPELINE II=1
            dmad.data = fb1[(y*VGA_WIDTH)+x];
            outs << dmad;
        }
    }
    return(0);
}

int fb2_hls_stream(volatile ap_int<32> *fb2, AXI_STREAM &outs){
    AP_AXIU32 dmad;

    LOOP_Y1: for(int y=0; y<VGA_HEIGHT; y++){
        LOOP_X1: for(int x=0; x<VGA_WIDTH; x++){
#pragma HLS PIPELINE II=1
            dmad.data = fb2[(y*VGA_WIDTH)+x];
            outs << dmad;
        }
    }
    return(0);
}


この実装でC コードの合成はうまく行くのだが、C/RTL 協調シミュレーションで出力が出ないで、シミュレーションがいつまで経っても終わらなかった。
いずれの問題も、DMA エンジンを 3 個入れているところがまずいのだと思うが、DMA アドレスのオフセットを毎回変えずに、トリプル・バッファリングを実現するのには、必要となる。


次の実装は、if 文での実装に問題が合って単発転送になっているのじゃないか?という推測のもとに、for 文を細かく区切って実装したら、性能的にはどうだろうか?ということでやってみた。
ソースコード disp_dmar_axis_vga.cpp を示す。

// disp_dmar_axis_vga.cpp
// 2019/07/11 by marsee
//

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

#include "disp_dmar_axis_vga.h"

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height);
void pix_in_zero(AP_AXIU32 &pix, int x, int y, int max_width);

int disp_dmar_axis_vga(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<32> &resolution, ap_uint<2> &active_frame){
#pragma HLS INTERFACE ap_ctrl_hs port=return
#pragma HLS INTERFACE ap_none port=active_frame
#pragma HLS INTERFACE s_axilite port=resolution
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE m_axi depth=307200 port=fb2 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb1 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb0 offset=slave

    AP_AXIU32 pix;
    int max_width, max_height;

    switch((int)resolution){
        case 0: // SVGA
            max_width = SVGA_WIDTH;
            max_height = SVGA_HEIGHT;
            break;
        case 1: // XGA
            max_width = XGA_WIDTH;
            max_height = XGA_HEIGHT;
            break;
        default: // HD
            max_width = HD_WIDTH;
            max_height = HD_HEIGHT;
            break;
    }

    if (active_frame == (ap_uint<2>)0)
        disp_dmar_fb2(fb2, outs, max_width, max_height);
    else if (active_frame == (ap_uint<2>)1)
        disp_dmar_fb0(fb0, outs, max_width, max_height);
    else
        disp_dmar_fb1(fb1, outs, max_width, max_height);
    
    return(0);
}

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    Y00: for (int y=0; y<y_padding; y++){ // 最初の空白行
#pragma HLS LOOP_TRIPCOUNT min=60 max=300 avg=144
        X00: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }

    Y01: for (int y=y_padding; y<y_padding+VGA_HEIGHT; y++){
#pragma HLS LOOP_TRIPCOUNT min=480 max=480 avg=480
        X010: for (int x=0; x<x_padding; x++){ // 最初の空白列
#pragma HLS LOOP_TRIPCOUNT min=80 max=640 avg=192
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
        X011: for (int x=x_padding; x<x_padding+VGA_WIDTH; x++){
#pragma HLS LOOP_TRIPCOUNT min=640 max=640 avg=640
#pragma HLS PIPELINE II=1
            pix.data = fb0[((y-y_padding)*VGA_WIDTH)+x-x_padding];
            
            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
        X012: for (int x=x_padding+VGA_WIDTH; x<max_width; x++){ // 最後の空白列
#pragma HLS LOOP_TRIPCOUNT min=80 max=640 avg=192
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }

    Y02: for (int y=y_padding+VGA_HEIGHT; y<max_height; y++){ // 最後の空白行
#pragma HLS LOOP_TRIPCOUNT min=60 max=300 avg=144
        X02: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }
    
    return(0);
}

int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    Y10: for (int y=0; y<y_padding; y++){ // 最初の空白行
#pragma HLS LOOP_TRIPCOUNT min=60 max=300 avg=144
        X10: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }

    Y11: for (int y=y_padding; y<y_padding+VGA_HEIGHT; y++){
#pragma HLS LOOP_TRIPCOUNT min=480 max=480 avg=480
        X100: for (int x=0; x<x_padding; x++){ // 最初の空白列
#pragma HLS LOOP_TRIPCOUNT min=80 max=640 avg=192
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
        X101: for (int x=x_padding; x<x_padding+VGA_WIDTH; x++){
#pragma HLS LOOP_TRIPCOUNT min=640 max=640 avg=640
#pragma HLS PIPELINE II=1
            pix.data = fb1[((y-y_padding)*VGA_WIDTH)+x-x_padding];
            
            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
        X102: for (int x=x_padding+VGA_WIDTH; x<max_width; x++){ // 最後の空白列
#pragma HLS LOOP_TRIPCOUNT min=80 max=640 avg=192
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }

    Y12: for (int y=y_padding+VGA_HEIGHT; y<max_height; y++){ // 最後の空白行
#pragma HLS LOOP_TRIPCOUNT min=60 max=300 avg=144
        X12: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }
    
    return(0);
}

int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    Y20: for (int y=0; y<y_padding; y++){ // 最初の空白行
#pragma HLS LOOP_TRIPCOUNT min=60 max=300 avg=144
        X20: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }

    Y21: for (int y=y_padding; y<y_padding+VGA_HEIGHT; y++){
#pragma HLS LOOP_TRIPCOUNT min=480 max=480 avg=480
        X210: for (int x=0; x<x_padding; x++){ // 最初の空白列
#pragma HLS LOOP_TRIPCOUNT min=80 max=640 avg=192
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
        X211: for (int x=x_padding; x<x_padding+VGA_WIDTH; x++){
#pragma HLS LOOP_TRIPCOUNT min=640 max=640 avg=640
#pragma HLS PIPELINE II=1
            pix.data = fb2[((y-y_padding)*VGA_WIDTH)+x-x_padding];
            
            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
        X212: for (int x=x_padding+VGA_WIDTH; x<max_width; x++){ // 最後の空白列
#pragma HLS LOOP_TRIPCOUNT min=80 max=640 avg=192
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }

    Y22: for (int y=y_padding+VGA_HEIGHT; y<max_height; y++){ // 最後の空白行
#pragma HLS LOOP_TRIPCOUNT min=60 max=300 avg=144
        X22: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            pix_in_zero(pix, x, y, max_width);
            outs << pix;
        }
    }
    
    return(0);
}

void pix_in_zero(AP_AXIU32 &pix, int x, int y, int max_width){
    pix.data = 0;
    
    if (x==0 && y==0)
        pix.user = 1;
    else
        pix.user = 0;

    if (x == max_width-1)
        pix.last = 1;
    else
        pix.last = 0;
}


これも C/RTL 協調シミュレーションをやってみたところ、”VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 2(性能が足りない)”と同様に単発転送になってしまった。ここまで書くことは無いようだ。
次回は、うまく行った実装を紹介する。
  1. 2019年07月14日 05:06 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 2(性能が足りない)

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 1”の続き。

前回は、DisplayPort は接続するディスプレイによって、解像度の設定が違ってしまう。XGA のディスプレイだったらXGA 解像度の画像を出して、HD 解像度だったらHD 解像度の画像をLiveVideo に入力する必要がある。その加工はカメラ画像をDMA Write する側でやっていたのだが、今回のDMA Write はFixstars Tech Blog に書いてあるそのままを使用するので、DMA Read 側でいろいろな解像度の画像にすることにしよう。つまり、disp_dmar_axis IP を作り直そう。ということで、ソースコードやテストベンチのコードを貼った。
今回は、C シミュレーション、C コードの合成、をやってみよう。

Vivado 2018.2 でdisp_dmar_axis_vga プロジェクトを作成した。
disp_dmar_axis_vga_1_190712.png

最初に C シミュレーションを行った。
disp_dmar_axis_vga_2_190712.png

C シミュレーションの結果、dmar_result.bmp が生成された。予定通りの画像になっている。
disp_dmar_axis_vga_9_190713.jpg

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

Latency min が 480014 で、 SVGA の 800 x 600 = 480000 に比べて 12 クロックしか余計じゃないので、期待できそう?と思う。

disp_dmar_fb1 の合成結果を示す。
disp_dmar_axis_vga_4_190712.png

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

合成でのLatency min より、C/RTL 協調シミュレーションのLatency min の方がだいぶ増えてしまっている。

C/RTL 協調シミュレーション波形を見てみよう。全体波形から。
disp_dmar_axis_vga_6_190712.png

拡大してみよう。
disp_dmar_axis_vga_7_190712.png

outs に赤いところ(出力されていないところ)があるのが分かる。
m_axi_gmem_ARLENも 00 で単発転送であることが分かった。
これだとスループットが取れない。これではよろしくない。。。よって作り直そう。
  1. 2019年07月13日 22:00 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

VGA画像をXGA画像やHD画像に変換するdisp_dmar_axis_vga IP 1

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する3(fpga.binファイルの生成)”で、fpga.bin の生成まで行っておいて何なのだが、disp_dmar_axis IP がこのままではまずいことに気がついた。
DisplayPort は接続するディスプレイによって、解像度の設定が違ってしまう。XGA のディスプレイだったらXGA 解像度の画像を出して、HD 解像度だったらHD 解像度の画像をLiveVideo に入力する必要がある。その加工はカメラ画像をDMA Write する側でやっていたのだが、今回のDMA Write はFixstars Tech Blog に書いてあるそのままを使用するので、DMA Read 側でいろいろな解像度の画像にすることにしよう。つまり、disp_dmar_axis IP を作り直そう。

今度のDMA Read IP の名前は、disp_dmar_axis_vga とした。
最初にソースコードを貼っておく。
disp_dmar_axis_vga.h を貼っておく。

// disp_dmar_axis_vga.h
// 2019/07/11 by marsee
//

#ifndef __DISP_DMAR_AXIS_VGA_H__
#define __DISP_DMAR_AXIS_VGA_H__

#include "ap_axi_sdata.h"
#include "hls_video.h"

#define VGA_WIDTH 640
#define VGA_HEIGHT 480

#define SVGA_WIDTH 800
#define SVGA_HEIGHT 600

#define XGA_WIDTH 1024
#define XGA_HEIGHT 768

#define HD_WIDTH 1920
#define HD_HEIGHT 1080

#define RESO_SVGA 0
#define RESO_XGA 1
#define RESO_HD  2

typedef hls::stream<ap_axiu<32,1,1,1> > AXI_STREAM;
typedef ap_axiu<32,1,1,1> AP_AXIU32;
typedef hls::Scalar<3, unsigned char> RGB_PIXEL;
typedef hls::Mat<HD_HEIGHT, HD_WIDTH, HLS_8UC3> RGB_IMAGE;
typedef hls::Mat<HD_HEIGHT, HD_WIDTH, HLS_8UC1> GRAY_IMAGE;

#endif


disp_dmar_axis_vga.cpp を貼っておく。

// disp_dmar_axis_vga.cpp
// 2019/07/11 by marsee
//

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

#include "disp_dmar_axis_vga.h"

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height);
int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height);

int disp_dmar_axis_vga(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<32> &resolution, ap_uint<2> &active_frame){
#pragma HLS INTERFACE ap_ctrl_hs port=return
#pragma HLS INTERFACE ap_none port=active_frame
#pragma HLS INTERFACE s_axilite port=resolution
#pragma HLS INTERFACE axis register both port=outs
#pragma HLS INTERFACE m_axi depth=307200 port=fb2 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb1 offset=slave
#pragma HLS INTERFACE m_axi depth=307200 port=fb0 offset=slave

    AP_AXIU32 pix;
    int max_width, max_height;

    switch((int)resolution){
        case 0: // SVGA
            max_width = SVGA_WIDTH;
            max_height = SVGA_HEIGHT;
            break;
        case 1: // XGA
            max_width = XGA_WIDTH;
            max_height = XGA_HEIGHT;
            break;
        default: // HD
            max_width = HD_WIDTH;
            max_height = HD_HEIGHT;
            break;
    }

    if (active_frame == (ap_uint<2>)0)
        disp_dmar_fb2(fb2, outs, max_width, max_height);
    else if (active_frame == (ap_uint<2>)1)
        disp_dmar_fb0(fb0, outs, max_width, max_height);
    else
        disp_dmar_fb1(fb1, outs, max_width, max_height);
    return(0);
}

int disp_dmar_fb0(volatile ap_int<32> *fb0, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    LOOP_Y0: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X0: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            if (y < y_padding || y >= y_padding+VGA_HEIGHT)
                pix.data = 0;
            else if (x < x_padding || x >= x_padding+VGA_WIDTH)
                pix.data = 0;
            else
                pix.data = fb0[((y-y_padding)*VGA_WIDTH)+x-x_padding];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}

int disp_dmar_fb1(volatile ap_int<32> *fb1, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    LOOP_Y1: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X1: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            if (y < y_padding || y >= y_padding+VGA_HEIGHT)
                pix.data = 0;
            else if (x < x_padding || x >= x_padding+VGA_WIDTH)
                pix.data = 0;
            else
                pix.data = fb1[((y-y_padding)*VGA_WIDTH)+x-x_padding];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}

int disp_dmar_fb2(volatile ap_int<32> *fb2, AXI_STREAM &outs, int max_width, int max_height){
    AP_AXIU32 pix;
    int x_padding = (max_width - VGA_WIDTH)/2;
    int y_padding = (max_height - VGA_HEIGHT)/2;

    LOOP_Y2: for (int y=0; y<max_height; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=1080 avg=768
        LOOP_X2: for (int x=0; x<max_width; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=1920 avg=1024
#pragma HLS PIPELINE II=1
            if (y < y_padding || y >= y_padding+VGA_HEIGHT)
                pix.data = 0;
            else if (x < x_padding || x >= x_padding+VGA_WIDTH)
                pix.data = 0;
            else
                pix.data = fb2[((y-y_padding)*VGA_WIDTH)+x-x_padding];

            if (x==0 && y==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == max_width-1)
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
    return(0);
}


disp_dmar_axis_vga_tb.cpp を貼っておく。

// disp_dmar_axis_tb.cpp
// 2019/02/01 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include "hls_opencv.h"

#include "disp_dmar_axis_vga.h"

int disp_dmar_axis_vga(volatile ap_int<32> *fb0, volatile ap_int<32> *fb1, volatile ap_int<32> *fb2,
        AXI_STREAM &outs, ap_uint<32> &resolution, ap_uint<2> &active_frame);

#define NUM_FRAME_BUFFER 3
#define FB_NUMBER 0

int main(){
    using namespace cv;
    ap_uint<2> fb_number = FB_NUMBER;
    ap_uint<32> resolution = RESO_XGA;

    AXI_STREAM outs;
    AP_AXIU32 pix;
    ap_uint<32> *frame_buffer;
    
    // OpenCV で 画像を読み込む
    Mat src = imread("bmp_file0.bmp");

    // 画像をセーブするメモリをアロケート
    if ((frame_buffer =(ap_uint<32> *)malloc(NUM_FRAME_BUFFER * sizeof(ap_int<32>) * (src.cols * src.rows))) == NULL){
        fprintf(stderr, "Can't allocate frame_buffer0 ~ 2\n");
        exit(1);
    }
    
    // Mat フォーマットからフレームバッファに画像をロード
    Mat_<Vec3b> src_vec3b = Mat_<Vec3b>(src);
    for(int i=0; i<NUM_FRAME_BUFFER; i++){
        for(int y=0; y<src.rows; y++){
            for(int x=0; x<src.cols; x++){
                Vec3b pixel;
                pixel = src_vec3b(y,x);
                int rgb = ((int)(pixel(2))<<16) + ((int)(pixel(1))<<8) + pixel(0);
                frame_buffer[(src.cols*src.rows)*i + (src.cols*y) + x] = rgb;
            }
        }
    }
    
    disp_dmar_axis_vga((volatile ap_int<32> *)frame_buffer,
        (volatile ap_int<32> *)&frame_buffer[src.cols * src.rows],
        (volatile ap_int<32> *)&frame_buffer[2 * (src.cols * src.rows)],
        outs, resolution, fb_number);
        
    // AXI4 Stream から Mat フォーマットに変換しファイルに書き込み
    int row, col;
    switch(resolution){
        case RESO_SVGA:
            row = SVGA_HEIGHT; col = SVGA_WIDTH;
            break;
        case RESO_XGA:
            row = XGA_HEIGHT; col = XGA_WIDTH;
            break;
        default:
            row = HD_HEIGHT; col = HD_WIDTH;
            break;
    }

    Mat dst(row, col, CV_8UC3);
    Mat_<Vec3b> dst_vec3b = Mat_<Vec3b>(dst);
    for(int y=0; y<dst.rows; y++){
        for(int x=0; x<dst.cols; x++){
            outs >> pix;
            int rgb = pix.data;
            //int rgb = frame_buffer[(src.cols*y) + x];
            Vec3b pixel;
            pixel[0] = (rgb & 0xff); // blue
            pixel[1] = (rgb & 0xff00) >> 8; // green
            pixel[2] = (rgb & 0xff0000) >> 16; // red
            dst_vec3b(y,x) = pixel;
        }
    }

    imwrite("dmar_result.bmp", dst);
    
    free(frame_buffer);
    return(0);
}


bmp_file0.bmp を貼っておく。
disp_dmar_axis_vga_8_190712.png
  1. 2019年07月12日 04:53 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する3(fpga.binファイルの生成)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する2(ブロックデザインの変更)”の続き。

前回は、Ultra96 にMIPI 拡張ボードを挿入し、Pcam5C を取り付けて、DisplayPort にPcam5C のカメラ画像を出力するVivado プロジェクトのブロックデザインを作成した。今回は、そのブロックデザインを論理合成、インプリメンテーション、ビットストリームの生成を行って、ビットファイルを生成させる。そして、そのビットファイルをbin ファイルに変換しよう。

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

タイミング制約も満足している。
しかし、55 個の critical warnings が出ているがこれは何だろうか?
critical warnings を見てみると、制約ファイルに書いてあるポートがデザインに無いと言うことのようだ。
MIPI_DP_14_190710.png

とりあえず、この 55 個の critical warnings は無視しよう。

次は、 fppga.bin を生成する。この作業は、”Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる2”を参照してやっていこう。

~/Docker/vivado182ub16/masaaki/ultra96_design/ultra96_design_dp/ultra96_design.runs/impl_1/ ディレクトリに design_1_wrapper.bit があるのを確認した。
MIPI_DP_15_190710.png

同じディレクトリに fpga.bif を作成した。
MIPI_DP_16_190710.png

all:
{
    [destination_device = pl] design_1_wrapper.bit
}


MIPI_DP_17_190710.png

cd Docker/vivado182ub16/masaaki/ultra96_design/ultra96_design_dp/ultra96_design.runs/impl_1/
同じディレクトリで、
bootgen -image fpga.bif -arch zynqmp -w -o fpga.bin
を実行したところ、fpga.bin が生成された。
MIPI_DP_18_190710.png

MIPI_DP_19_190710.png
  1. 2019年07月10日 05:05 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する2(ブロックデザインの変更)

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する1(準備編)”の続き。

前回は、”Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる4”でPcam5C のカメラ画像をディスプレイに表示することができなかった。だが、”カメラ画像をDisplayPortに出力する9(アプリを作成、完成)”でMIPI ではないパラレル出力のOV5642 をDisplayPort に表示することができている。そこで、両方を組み合わせてPcam5C の画像をUltra96 のDisplayPort に出力したいということで、PSのLiveVideo を有効にした。今回は、それを元にブロックデザインを完成させよう。

カメラ画像をDisplayPortに出力する7(ブロックデザインの変更)”を参考にして、ブロックデザインを変更しよう。

~/HDL/Ultra96/cam_dp_183/ ディレクトリから、axi2video_out_IP と disp_dmar_axis_IP ディレクトリをコピーした。
MIPI_DP_5_190709.png

それをVivado のプロジェクトのIP Catalog にリポジトリを登録した。
MIPI_DP_6_190709.png

ブロックデザイン上で、axi2video_out と disp_dmar_axis と axi_gpio を Add IP した。
MIPI_DP_7_190709.png

gpio の設定を示す。1 ビットの出力に設定した。
MIPI_DP_8_190709.png

Slice をAdd IP した。これは、axi_vdma の s2mm_frame_ptr_out の 6 ビットを 2 ビットに変換するに使用する。
MIPI_DP_9_190709.png

完成したブロックデザイン全体を示す。
MIPI_DP_10_190709.png

階層化した display 階層モジュールを示す。
MIPI_DP_11_190709.png

Address Editor 画面を示す。
MIPI_DP_12_190709.png
  1. 2019年07月09日 05:14 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

Ultra96 MIPI拡張ボードに接続したPcam5C の画像をDisplayPort に表示する1(準備編)

Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる4”でPcam5C のカメラ画像をディスプレイに表示することができなかった。だが、”カメラ画像をDisplayPortに出力する9(アプリを作成、完成)”でMIPI ではないパラレル出力のOV5642 をDisplayPort に表示することができている。そこで、両方を組み合わせてPcam5C の画像をUltra96 のDisplayPort に出力したい。

まずは、”Fixstars Tech Blogの「Ultra96 Linux で MIPI カメラから画像を取得する」をやってみる4”をやったときの ~/Docker/vivado182ub16/masaaki/ultra96_desgin/ultra96_design ディレクトリが Vivado 2018.2 のプロジェクトなので、それをコピーして、ultra96_design_dp と名前を変更した。
MIPI_DP_4_190708.png

Vivado 2018.2 でプロジェクトを開き、ブロックデザインを開いた。
MIPI_DP_2_190707.png

Ultra96のDisplayPortを使用するためのテスト1(Vivado プロジェクトを作成した)”に沿って、Live Video を 1 にして、DisplaryPort のポートを表示させた。
MIPI_DP_1_190707.png

Live Video を 1 にした後のブロックデザインを示す。
MIPI_DP_3_190707.png
  1. 2019年07月08日 04:53 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

映画『スパイダーマン:ファー・フロム・ホーム』を見てきました

今日は、午前中、トレラン教室で宝篋山に登ってきた後、映画『スパイダーマン:ファー・フロム・ホーム』を見てきました。
いつもながら、スパイダーマンは悩めるティーンエイジャーで、そこが良いでしょうが、歯がゆい気もしますね。。。
映画はとても楽しめましたよ。
  1. 2019年07月07日 21:54 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

hls4mlをやってみた7(自分で学習したネットワークをhls4mlでハードウェア化2)

hls4mlをやってみた6(自分で学習したネットワークをhls4mlでハードウェア化1)”の続き。

前回は、白線追従ロボットカーの学習データ keras_curve_cnn2_line を hls4ml でVivado HLS 2019.1 のプロジェクトにしようということで、白線追従ロボットカーの学習データのネットワーク構造と重みのファイルを出力した。今回は、それをhls4ml でVivado HLS のプロジェクトにしてみよう。

keras_curve_cnn2_line.json と keras_curve_cnn2_line_weights.h5 をhls4ml/keras-to-hls/example-keras-model-files/ ディレクトリにコピーした。
hls4ml_28_190704.png

hls4ml/keras-to-hls/ ディレクトリに keras_curve_cnn2_line.yml を作成した。
hls4ml_29_190704.png

keras_curve_cnn2_line.yml の内容を示す。
hls4ml_30_190704.png

KerasJson: example-keras-model-files/keras_curve_cnn2_line.json
KerasH5:   example-keras-model-files/keras_curve_cnn2_line_weights.h5
OutputDir: keras_curve_cnn2_line
ProjectName: keras_curve_cnn2_line
XilinxPart: xcku5p-sfvb784-1-e
ClockPeriod: 5

IOType: io_parallel # options: io_serial/io_parallel
HLSConfig:
  Model:
    Precision: ap_fixed<16,6>
    ReuseFactor: 1



hls4ml でVivado HLS の tcl ファイルを作成する。
python keras-to-hls.py -c keras_curve_cnn2_line.yml
hls4ml_31_190704.png

hls4ml/keras-to-hls/keras_curve_cnn2_line/ ディレクトリができて、その下に build_prj.tcl が生成されている。
hls4ml_32_190704.png

Vivado HLS で build_prj.tcl を実行したところエラーが出てしまった。
cd keras_curve_cnn2_line
vivado_hls -f build_prj.tcl

hls4ml_33_190704.png

ERROR: [XFORM 203-504] Stop unrolling loop 'Product1' (/home/masaaki/DNN/hls4ml/nnet_utils/nnet_dense.h:97) in function 'nnet::dense, ap_fixed<16, 6, (ap_q_mode)5, (ap_o_mode)3, 0>, config6>' because it may cause large runtime and excessive memory usage due to increase in code size. Please avoid unrolling the loop or form sub-functions for code in the loop body.
ERROR: [HLS 200-70] Pre-synthesis failed.
command 'ap_source' returned error code
while executing
"source build_prj.tcl"
("uplevel" body line 1)
invoked from within
"uplevel \#0 [list source $arg] "


large runtime and excessive memory usage エラーだった。このエラー、何とかならないものだろうか?何時間、何日かかっても良いので、続けて欲しい。Xilinx さん、よろしくお願いします。

一応、Vivado HLS 2019.1を立ち上げて、もう一度、C コードの合成をやってみたが結果は同じだった。
hls4ml_34_190705.png

hls4ml は小さいネットワークの時のみ、使えるみたいだ。
  1. 2019年07月06日 04:34 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

hls4mlをやってみた6(自分で学習したネットワークをhls4mlでハードウェア化1)

hls4mlをやってみた5(KERAS_conv1d_small_nfilt5その2)”の続き。

前回は、KERAS_conv1d_small_nfilt5 のネットワーク構造を調べた。今回は、白線追従ロボットカーの学習データ keras_curve_cnn2_line を hls4ml でVivado HLS 2019.1 のプロジェクトにしてみよう。

hls4ml にかけるには、モデルの構造を記述したJSON ファイルと、モデルの重みの h5 ファイルが必要なので、keras_curve_cnn2_line のJupyter notebook を立ち上げて、出力してみよう。
最初に学習済みモデルを読み込む。

# 学習済みモデルの読み込み

from keras.models import load_model

model = load_model('keras_curve_cnn2_line.h5')


hls4ml_25_190704.png

モデルを json に書き出す。

# save as JSON
json_string = model.to_json()


モデルを json ファイルに書き出して、重みも h5 ファイルに書き出す。

json_name='keras_curve_cnn2_line.json'

with open(json_name, mode='w') as f:
    f.write(json_string)

model.save_weights('keras_curve_cnn2_line_weights.h5')


hls4ml_26_190704.png

keras_curve_cnn2_line.json と keras_curve_cnn2_line_weights.h5 を出力することができた。
hls4ml_27_190704.png

なお keras のコードは、Keras Documentation の”モデルについて”を参考にさせていただいた。
  1. 2019年07月05日 05:00 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

hls4mlをやってみた5(KERAS_conv1d_small_nfilt5その2)

hls4mlをやってみた4(KERAS_conv1d_small_nfilt5その1)”の続き。

前回は、KERAS_conv1d_small_nfilt5 ネットワークをビルドして、C コードの合成結果を観察した。今回は、KERAS_conv1d_small_nfilt5 のネットワーク構造を調べていこう。

KERAS_conv1d_small_nfilt5.cpp を引用する。

//
//    rfnoc-hls-neuralnet: Vivado HLS code for neural-net building blocks
//
//    Copyright (C) 2017 EJ Kreinar
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
#include <iostream>

#include "KERAS_conv1d_small_nfilt5.h"

//hls-fpga-machine-learning insert weights
#include "weights/w2.h"
#include "weights/b2.h"
#include "weights/w4.h"
#include "weights/b4.h"
#include "weights/w6.h"
#include "weights/b6.h"
#include "weights/w8.h"
#include "weights/b8.h"
#include "weights/w10.h"
#include "weights/b10.h"

void KERAS_conv1d_small_nfilt5(
    input_t input_1[N_INPUT_1_1*N_INPUT_2_1],
    result_t layer11_out[N_LAYER_10],
    unsigned short &const_size_in_1,
    unsigned short &const_size_out_1
) {

    //hls-fpga-machine-learning insert IO
    #pragma HLS ARRAY_RESHAPE variable=input_1 complete dim=0 
    #pragma HLS ARRAY_RESHAPE variable=layer11_out complete dim=0 
    #pragma HLS INTERFACE ap_vld port=input_1,layer11_out 
    #pragma HLS PIPELINE 

    const_size_in_1 = N_INPUT_1_1*N_INPUT_2_1;
    const_size_out_1 = N_LAYER_10;

    // ****************************************
    // NETWORK INSTANTIATION
    // ****************************************

    //hls-fpga-machine-learning insert layers

    layer2_t layer2_out[Y_OUTPUTS_2*N_FILT_2];
    #pragma HLS ARRAY_PARTITION variable=layer2_out complete dim=0
    nnet::conv_1d<input_t, layer2_t, config2>(input_1, layer2_out, w2, b2);

    layer3_t layer3_out[Y_OUTPUTS_2*N_FILT_2];
    #pragma HLS ARRAY_PARTITION variable=layer3_out complete dim=0
    nnet::relu<layer2_t, layer3_t, relu_config3>(layer2_out, layer3_out);

    layer4_t layer4_out[Y_OUTPUTS_4*N_FILT_4];
    #pragma HLS ARRAY_PARTITION variable=layer4_out complete dim=0
    nnet::conv_1d<layer3_t, layer4_t, config4>(layer3_out, layer4_out, w4, b4);

    layer5_t layer5_out[Y_OUTPUTS_4*N_FILT_4];
    #pragma HLS ARRAY_PARTITION variable=layer5_out complete dim=0
    nnet::relu<layer4_t, layer5_t, relu_config5>(layer4_out, layer5_out);

    layer6_t layer6_out[Y_OUTPUTS_6*N_FILT_6];
    #pragma HLS ARRAY_PARTITION variable=layer6_out complete dim=0
    nnet::conv_1d<layer5_t, layer6_t, config6>(layer5_out, layer6_out, w6, b6);

    layer7_t layer7_out[Y_OUTPUTS_6*N_FILT_6];
    #pragma HLS ARRAY_PARTITION variable=layer7_out complete dim=0
    nnet::relu<layer6_t, layer7_t, relu_config7>(layer6_out, layer7_out);

    layer8_t layer8_out[N_LAYER_8];
    #pragma HLS ARRAY_PARTITION variable=layer8_out complete dim=0
    nnet::dense<layer7_t, layer8_t, config8>(layer7_out, layer8_out, w8, b8);

    layer9_t layer9_out[N_LAYER_8];
    #pragma HLS ARRAY_PARTITION variable=layer9_out complete dim=0
    nnet::relu<layer8_t, layer9_t, relu_config9>(layer8_out, layer9_out);

    layer10_t layer10_out[N_LAYER_10];
    #pragma HLS ARRAY_PARTITION variable=layer10_out complete dim=0
    nnet::dense<layer9_t, layer10_t, config10>(layer9_out, layer10_out, w10, b10);

    nnet::softmax<layer10_t, result_t, softmax_config11>(layer10_out, layer11_out);


}


KERAS_conv1d_small_nfilt5.cpp と parameters.h から推定した層構成を示す。ただしすべての層の変数の型は ap_fixed<16,6> となっている。

入力層 40 入力
conv_1d 入力数 40 出力数 30
relu 入力数 30 出力数 30
conv_1d 入力数 30 出力数 20
relu 入力数 20 出力数 20
conv_1d 入力数 20 出力数 10
relu 入力数 10 出力数 10
dense 入力数 10 出力数 5
relu 入力数 5 出力数 5
dense 入力数 5 出力数 5
softmax 入力数 5 出力数 5


IP の入力と出力のフォーマットだが、 KERAS_conv1d_small_nfilt5.cpp で dim=0 で ARRAY_RESHAPE ディレクティブが書かれている。
よって、入力の input_1 が ap_fixed<16,6> が 40 個なので、640 ビット幅となり、
出力の layer9_out が ap_fixed<16,6> が 5 個なので、 80 ビット幅となっている。
KERAS_conv1d_small_nfilt5.vhd の entity 部分を引用する。

entity KERAS_conv1d_small_nfilt5 is
port (
    ap_clk : IN STD_LOGIC;
    ap_rst : IN STD_LOGIC;
    ap_start : IN STD_LOGIC;
    ap_done : OUT STD_LOGIC;
    ap_idle : OUT STD_LOGIC;
    ap_ready : OUT STD_LOGIC;
    input_1_V_ap_vld : IN STD_LOGIC;
    input_1_V : IN STD_LOGIC_VECTOR (639 downto 0);
    layer11_out_V : OUT STD_LOGIC_VECTOR (79 downto 0);
    layer11_out_V_ap_vld : OUT STD_LOGIC;
    const_size_in_1 : OUT STD_LOGIC_VECTOR (15 downto 0);
    const_size_in_1_ap_vld : OUT STD_LOGIC;
    const_size_out_1 : OUT STD_LOGIC_VECTOR (15 downto 0);
    const_size_out_1_ap_vld : OUT STD_LOGIC );
end;


2つの hls4ml のexample ネットワークを見てきたが、小さいネットワークだった。自分で構築したニューラルネットワークを次にはやってみたい。
  1. 2019年07月04日 04:56 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

hls4mlをやってみた4(KERAS_conv1d_small_nfilt5その1)

hls4mlをやってみた3(シミュレーション)”の続き。

前回は、ivado HLS プロジェクトの myproject_prj の C シミュレーションとC/RTL 協調シミュレーションの結果を見た。今回は、異なるネットワークを自分で yml ファイルを作成してやってみよう。

hls4ml/keras-to-hls/example-keras-model-files/ ディレクトリのKERAS_conv1d_small_nfilt5.json , KERAS_conv1d_small_nfilt5_weights.h5 の組のネットワークをVivado HLS で実装してみることにする。
hls4ml_17_190703.png

hls4ml/keras-to-hls/ ディレクトリに KERAS_conv1d_small_nfilt5.yml を作成した。
hls4ml_18_190703.png

KERAS_conv1d_small_nfilt5.yml の内容を示す。
hls4ml_19_190703.png

KerasJson: example-keras-model-files/KERAS_conv1d_small_nfilt5.json
KerasH5: example-keras-model-files/KERAS_conv1d_small_nfilt5_weights.h5
OutputDir: KERAS_conv1d_small_nfilt5
ProjectName: KERAS_conv1d_small_nfilt5
XilinxPart: xcku5p-sfvb784-1-e
ClockPeriod: 5

IOType: io_parallel # options: io_serial/io_parallel
HLSConfig:
Model:
Precision: ap_fixed<16,6>
ReuseFactor: 1


hls4ml でKERAS_conv1d_small_nfilt5 のネットワークを Vivaod HLS のプロジェクトへ変換した。
python keras-to-hls.py -c KERAS_conv1d_small_nfilt5.yml
hls4ml_20_190703.png

KERAS_conv1d_small_nfilt5 ディレクトリに行って、build_prj.tcl を実行する。
cd KERAS_conv1d_small_nfilt5
vivado_hls -f build_prj.tcl

hls4ml_21_190703.png

tcl スクリプトの実行が終了した。
hls4ml_22_190703.png

Vivado HLS 2019.1 を立ち上げて、C コードの合成の結果を確認した。
hls4ml_23_190703.png
hls4ml_24_190703.png

Latency は 15 クロックで、Interval は 1 クロックだった。
リソースも今度はFPGA に収まっている。
  1. 2019年07月03日 05:10 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

hls4mlをやってみた3(シミュレーション)

hls4mlをやってみた2(KERAS_3layer ネットワークの構成)”の続き。

前回は、Vivado HLS を使用して機械学習をハードウェア化するフレームワークのhls4ml を使用してVivado HLS のIP として生成した KERAS_3layer ネットワークがどのようななネットワークか知らないので調査した。今回は、そのVivado HLS プロジェクトの myproject_prj の C シミュレーションとC/RTL 協調シミュレーションの結果を見ていこう。

最初にテストベンチの myproject_test.cpp を引用する。

//
//    rfnoc-hls-neuralnet: Vivado HLS code for neural-net building blocks
//
//    Copyright (C) 2017 EJ Kreinar
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "firmware/parameters.h"
#include "firmware/myproject.h"
#include "nnet_helpers.h"


int main(int argc, char **argv)
{
  //hls-fpga-machine-learning insert data
  input_t input_1[N_INPUT_1_1] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  result_t layer9_out[N_LAYER_8] = {0,0,0,0,0};

  //hls-fpga-machine-learning insert top-level-function
  unsigned short size_in1,size_out1;
  myproject(input_1,layer9_out,size_in1,size_out1);

  //hls-fpga-machine-learning insert output
  for(int i = 0; i < N_LAYER_8; i++) {
    std::cout << layer9_out[i] << " ";
  }
  std::cout << std::endl;

  return 0;
}


入力配列(input_1)に値を代入して、1度だけ myproject() を読んでいる。
このテストベンチでのシミュレーション結果を示す。

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.
   Compiling ../../../../myproject_test.cpp in debug mode
   Compiling ../../../../firmware/myproject.cpp in debug mode
   Generating csim.exe
0.0292969 0.761719 0.0566406 0.142578 0.0361328 
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************


layer9_out[] に値が出力されいてる。

次に、C/RTL 協調シミュレーションの結果を示す。
hls4ml_14_190701.png

Latency は 15 クロックだが、Interval が NA になってしまっている。これは、myproject() のコールが 1 回のためだと思う。
それでは、テストベンチの myproject_test.cpp を myproject() を 2 回呼ぶように書き換えた。新しい myproject_test.cpp を示す。

//
//    rfnoc-hls-neuralnet: Vivado HLS code for neural-net building blocks
//
//    Copyright (C) 2017 EJ Kreinar
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "firmware/parameters.h"
#include "firmware/myproject.h"
#include "nnet_helpers.h"


int main(int argc, char **argv)
{
  //hls-fpga-machine-learning insert data
  input_t input_1[N_INPUT_1_1] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  input_t input_2[N_INPUT_1_1] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
  result_t layer9_out[N_LAYER_8] = {0,0,0,0,0};
  result_t layer9_out2[N_LAYER_8] = {0,0,0,0,0};

  //hls-fpga-machine-learning insert top-level-function
  unsigned short size_in1,size_out1;
  myproject(input_1,layer9_out,size_in1,size_out1);
  myproject(input_2,layer9_out2,size_in1,size_out1);

  //hls-fpga-machine-learning insert output
  for(int i = 0; i < N_LAYER_8; i++) {
    std::cout << layer9_out[i] << " ";
  }
  std::cout << std::endl;

  for(int i = 0; i < N_LAYER_8; i++) {
    std::cout << layer9_out2[i] << " ";
  }
  std::cout << std::endl;

  return 0;
}


このテストベンチで C シミュレーションを行った。結果を示す。

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.
   Compiling ../../../../myproject_test.cpp in debug mode
   Generating csim.exe
0.0292969 0.761719 0.0566406 0.142578 0.0361328 
0 0.399414 0.0439453 0.571289 0.015625 
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************


結果が 2 つになった。

C/RTL 協調シミュレーションの結果を示す。
hls4ml_15_190701.png

Interval が 1 になった。
C/RTL 協調シミュレーションの波形を確認しよう。
hls4ml_16_190701.png

波形を少し拡大してみよう。
hls4ml_17_190701.png

input_1_V_ap_vld が 1 になったクロックから layer9_out_V_ap_vld が 1 になるまでは、 75 ns で クロックが 5 ns なので、15 クロックかかっている。そして、次の結果が 1 クロック後に出いているので、Latency は 15 クロック、Interval が 1 クロックということがC/RTL 協調シミュレーションの波形からも確認することができた。
  1. 2019年07月02日 04:58 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

靴棚を作った

土曜日と日曜日に奥さんの要望で天井まで届く靴棚を作った。

2730 mm X 800 mm X 240 mm の靴棚なので、どうやって作るか迷ったが、高さ方向に 1530 mm と 1200 mm に分けて作ることにした。材料は 1 x 4 材 6F を 24 本買ってきた。約 6000 円だった。

まずは、下半分の 1530 mm を作った。
kutudana_1_190701.jpg

上半分を作っているところ。作業台の上に 1 x 4 材で作った靴棚の上半分のそのまた半分が載っている。もう半分を作って 240 mm の 1 x 4 材で連結する。こうして、 1 x 4 材で作ると安くなるのである。そして、重さも一人で持てる程度である。全部このサイズをムク材で作ったら一人で持てなくなる。この作り方でも、半分に分けて、やっと一人で持てる重さになる
kutudana_2_190701.jpg

作業場には、安いがスライドノコギリも用意してある。これが無いとまっすぐ垂直に材木を切れない。
kutudana_3_190701.jpg

最近あまりやっていないが、木工も趣味の1つなのだ。

玄関で上下を連結して出来上がり。しかし、一人で設置だったので、上半分が少し曲がってしまったかな?まあ、天井に押し付けて止めたので、天井に突っ張っているので、手でやっても動かないので、大丈夫だろう。
kutudana_4_190701.jpg

kutudana_5_190701.jpg

kutudana_6_190701.jpg

CNC買って家具作りのアルバイトも良いかも?
  1. 2019年07月01日 04:56 |
  2. 木工
  3. | トラックバック:0
  4. | コメント:0