カテゴリー「FPGA」の60件の記事

2018年5月20日 (日)

超リアルタイムHMD試作に向けた技術検証(中間報告?)

 以前から書き続けていた電脳メガネ計画ですが、一応、パーツ実験としてカメラからOLED表示までの一連のデータパスが貫通したので、一度動画にまとめました。


 

 あとは、上の動画だと遅延の解消にどういう価値があるのか分かり難いと思いますので、同じ観点で訴求されているマイクロソフトのHigh Performance Touchという動画にもリンクを張っておきます。とても分かりやすい動画なので、現実世界に対してバーチャル空間の処理が遅れないことの価値を感じていただければと思います。

また、同システムで高速度撮影も実施してみたので、分かりやすく性能を示す面で、こちらの動画も張っておきます

部屋が暗いというのもありますが、ちょっとザラザラしてくるのが高速度撮影の特徴です。S/N比が悪化しますが、情報が減っているわけではなく、これをフレーム間で足し合わせると、ノイズが減り、従来の露光時間の画像にも戻せてしまうという点で、情報量としては上位互換でして、これを使ってHDRなどの新しい撮影なども可能です。

 HMDとしては、まだまだ、システムとして機能するよう形にするには課題が山済みですが、使えるデバイスが揃えられるかという技術検証としての大きな山場は越えたように思います。
 次の課題は

  •  システムとしてどうやって実用的にメガネ(HMD)の形にしていくか
  •  アプリやコンテンツどうするか?

 というフェーズに移れそうに思います。
 

 後半のコンテンツ部分は、まあもうちょっと先になると思いますので、あれこれ考えつつシステムとしての検討が出来ればと思いますが、前半のシステム検討も時間とお金も必要になってくるのでじっくり進めていければと思います(そもそもHMDの形にするにはFPGAごと基板起こさないと辛いかもと思い始めていたりです)。

 今日は一旦ここまでを振り返ってみたいと思います。

 当方、RTOS自作したり、CPU作ったりと、計算機科学部分には比較的昔から取り組んでいましたが、特にFPGAとの出会いは大きかったように思います。
 当初はシリコンOSとか作れれば面白いかなという程度だったのですが、どうせFPGA使うならFPGAでしか出来ないことがやりたいな、しかもリアルタイム系、つまり現実世界や人間と深く相互作用するコンピューティングがやりたいなと思いが広がってきました。

 今回の試作は、リアル空間にリアルタイムに相互作用できる可能性を示せた点で意義があったと思います。これまで何度か書いておりますが、リアルタイムシステムというのはシステム全体で考える必要があります。その際に、特に重要なのがアムダールの法則だと思います。目的のスペックに対して、システムのボトルネックを効率よく取り除いていく必要があります。
 つまりは、入出力での遅延が計算機より遅いと意味が無くなってしまうわけです。例えば今回のようなAR的なものだと、カメラ/計算機/表示が、それぞれ16.6msで50msだったときに、計算機だけ16倍速くして 1ms にしても他が同じ速度だと、システム全体では 34.3ms に短縮されるだけで、1.5倍程度しか早くならないわけです。

 そういった中で、OLEDがFPGA直結で思惑通り 高速で動いてくれ、安価な Raspberry PI のカメラがこれもまたFPGAに直結で1000fpsで動作してくれたのは非常にラッキーでした。

 いや~、意外と何とかなるもんですね

 FPGA直結というのも肝でして、各種I/Oと演算器を直結できるI/Fが記述で来ちゃうのがFPGAの良いところでもあります。
 データフローとセットで計算機を構成できてしまい、いわゆる非ノイマン型の演算アーキテクチャのアイデアがいろいろ試せてしまうわけです。
 いわゆる一般のCPUやGPUはハードマクロで超高速ではあるものの、メモリからメモリにしか演算できないので、メモリにデータを入れたり、メモリからデータを出したりという部分が遅いとリアルタイム性が一気に失われてしまいます(そもそもメモリから画像を出力するHDMIなどの規格に1000fpsなどのプロファイルは無いわけで)。

 少し、おさらいしておくと、リアルタイムの世界では、スループットとレイテンシは分けて考える必要があります。
 昨今のGPUは非常に大きなスループットで計算することが出来ます。例えば1秒あたりに1テラ個以上の浮動小数点演算が出来てしまったりします。
 ただし、これは1個が 1ピコ秒で演算が出来るわけではなく帯域として1秒あたりに沢山演算できるというだけで、実際の演算は並列処理やパイプライン処理で、もっと時間をかけて演算しますし、演算器にデータがたどり着くまでに様々なバッファリングが行われてシステム的にも遅延が入るわけです。

 このデータを入れてから出てくるまでの時間がレイテンシと呼ばれるものですが、リアルタイムシステムではレイテンシもスループットと合わせてとても重要です。
 折角、1秒あたり1テラ個データを入力することが出来ても、そのデータをあちこちメモリに貯めたり、転送したりしてから回りまわって、少し遅れてデータが出てくるのだと価値が下がってしまうケースもあるわけです。

 なので、この分野だと、入力と演算器が直結でき、計算結果も出力デバイスに直結できてしまうFPGAは実に面白いわけです。

 計算分野を限定すれば、スパコンでも出来ない演算システムが作れるかもしれません。ワクワクしますね。

 引き続き頑張りたいと思います。

2018年5月 3日 (木)

非同期クロックのタイミング制約について(迷走中)

特にこれといって答えは出ていないのですが、非同期クロックの扱いに嵌っているので、少し経過を整理しておきます。

普段はあまり複数のクロックソースを混ぜることは無いのと、混ぜても局所的であまり嵌った事が無かったのですが、今回は迷走中です。

Zybo Z7 にて、PSから生成したクロックと、PLに直接入力されている125MHzからMMCMで生成したクロックとをそれぞれ、システムで使っていましたところ、タイミングエラーが取れないという状況になっています。

現在、非同期のクロックを使うにあたって、例えば低速なバスクロックから書き換えるレジスタを、高速のクロックで動く演算コアで参照していたり、自作の非同期FIFOを使っていたりするわけです。

UG903などには set_clock_groups で -asynchronous指定するようにかかれていますが、

https://japan.xilinx.com/support/answers/44651.html
を読むと「それぞれ set_false_path 制約が設定されている場合と実質的には同じです。」などと書かれていたりします。

自作の非同期FIFOなどは、グレイコードを利用しており、少なくとも同時に1bitしかメタステーブル状態に入らず、ダブルラッチ後に安定さえしてくれれば0と1のどちらに倒れても整合が取れることを前提に書いております。が、200MHz級の回路だと、下手すると普通に同期回路でも制約をミスすると動かない世界なので、 set_false_path だと1サイクルの幅を超えて2bit以上がメタステーブルに入る危険が出てきます(非同期FIFO以外も似た思想でデータ渡しているので同じ問題が出ます)。

で、set_max_delay での制約が正解なのかとおもいきや、どういう値を設定するべきなのか悩み中です。

Async2

単純にクロック周期では不足な気もします。

また、単純にクロック周期で指定しても下記のようなありさまです。

Err

Requirement は set_max_delay -datapath_only で指定した 5ns 指定が確かに入ったのですが、 Clock Skew -4.613ns などが入り込んできてエラーになっているわけです。

もちろんクロックスキューも計算に入れる必要があるわけですが、結局のところ「クロックスキューも含めて、すべての配線ばらつきの相対値が、別サイクルと混入しない範囲に収めたい」というのが要件でして、これを正しく指定する手はあるのだろうかというところで嵌っています。そもそもみんな揃ってずれるなら 5ns 以上の遅延があっても良いわけでして、単に max_delay だけで縛ると厳しすぎて制約が満たし難くなる気もします。

いやまあ、これが目的じゃないし、時間ももったいないので、いつものように、「動いているから気にしない!」で次に行くと思うんですが、イマイチ腑に落ちない状況です (^^;;

(後日談 2018/05/04)
上記のタイミングエラーは、コピペミスで似た名前の別のクロックに対して制約していたことが判明しました m(_ _)m
  クロックスースが別で非同期なのでですが、たまたま周期があっていて自動計算されたRequirementが設定した値と同じだったので設定が効いている物とばかり思い込んで嵌っていました。いい勉強にはなりました。

2018年4月29日 (日)

Zybo Z7 への Raspberry Pi Camera V2 接続(MIPI CSI-2受信)

 Zybo Z7-20 への Raspberry Pi Camera V2(Sony IMX219)の接続を挑戦中なので記録を残しておきます。

 最終目標は Zybo での 960fps (640x120) の高速度撮影ですが、今回はとりあえず普通に絵が取れるかどうかのアタリ実験までです。高速撮影時も画素数が減るだけで、物理層の速度は912Mbpsで変わらないので、物理層の実験にはなるはずです。まずはRaspberryPiで動いている手堅いパラメータで動作確認を行いました。

 どうやら Zybo Z7 の MIPI CSI-2 のコネクタと、手元にある Raspberry Pi3 のコネクタは、物理形状もピン配置も互換のようですので、基本的にはソフトとRTLを何とかすれば受信できるはずです。

 今回は基本的には現物主義のアプローチでRaspberry Pi3 に繋いだときのSCL/SDAのI2Cアクセスをロジアナで読んでコピーするというところと、 Xilinx の標準コアであるMIPI D-PHY コアを使えば、とりあえず何らかの信号が出てくるのでそこから適当に画像らしい部分を拾うというアプローチです。

  ただし、調べればいろいろ既に先駆者の情報がいろいろあります。
  Raspberry Pi V2 Camera の情報については RaspberryPi のフォーラムから、手繰ると回路解析やデータシートなどの情報があるようです。

 MIPI CSI-2関連も正式な仕様書は手に入りませんが、Googleで検索するとドラフト時の資料とか多少出てくるようなので、手がかりにはなりそうです。

 以前HDMIのRX作ったときと同様に、今回も規格に準拠したものを作ろうというのではなく、趣味で遊べる程度に映像が取り出せればOKというスタンスで解析していきます。

はじめに Raspberry Pi3 にカメラを繋いでまずは動かします。こちらのサイトを参考にしました。
絵が出たのが確認できたらすかさず、カメラモジュールの端子をロジアナに繋いで解析します。
ここは手抜きで、カプトンテープで軽く保護だけしてコネクタの隙間にピンをねじ込みました(乱暴)。

Dsc_0316

意外と何とかなるものです。
ZEROPLUSのI2Cプロトコルアナライザが大活躍です。

Imx219

で、raspstill コマンド実行時のI2Cのアクセス内容が以下の通り。

-----------------

r 0000 -> 02 19    ; MODEL_ID
r 0002 -> 20       ; ????
r 0003 -> 00       ; ????

w 0102 <- 01       ; ???? (Reserved)

w NULL

w 0100 <- 00       ; mode_select [4:0]  (0: SW standby, 1: Streaming)
w 6620 <- 01 01    ; ????
w 6622 <- 01 01

w 30EB <- 0C       ; Access command sequence Seq.(データシートと違う?)
w 30EB <- 05
w 300A <- FF FF
w 30EB <- 05
w 30EB <- 09

w 0114 <- 01       ; CSI_LANE_MODE (03: 4Lane 01: 2Lane)
w 0128 <- 00       ; DPHY_CTRL (MIPI Global timing setting 0: auto mode, 1: manual mode)
w 012a <- 18 00    ; INCK frequency [MHz] 6,144MHz

w 0157 <- 00       ; ANA_GAIN_GLOBAL_A
w 015A <- 09 BD    ; COARSE_INTEGRATION_TIME_A 
w 0160 <- 03 72    ; FRM_LENGTH_A
w 0162 <- 0D 78    ; LINE_LENGTH_A (line_length_pck Units: Pixels)
w 0164 <- 00 00    ; X_ADD_STA_A  x_addr_start  X-address of the top left corner of the visible pixel data Units: Pixels
w 0166 <- 0C CF    ; X_ADD_END_A 
w 0168 <- 00 00    ; Y_ADD_STA_A
w 016A <- 09 9F    ; Y_ADD_END_A
w 016C <- 06 68    ; x_output_size
w 016E <- 04 D0    ; y_output_size
w 0170 <- 01 01    ; X_ODD_INC_A  Increment for odd pixels 1, 3
w 0174 <- 01 01    ; BINNING_MODE_H_A  0: no-binning, 1: x2-binning, 2: x4-binning, 3: x2-analog (special) binning
w 018C <- 0A 0A    ; CSI_DATA_FORMAT_A   CSI-2 data format
w 0301 <- 05       ; VTPXCK_DIV  Video Timing Pixel Clock Divider Value
w 0303 <- 01 03    ; VTSYCK_DIV  PREPLLCK_VT_DIV(3: EXCK_FREQ 24 MHz to 27 MHz)
w 0305 <- 03 00    ; PREPLLCK_OP_DIV(3: EXCK_FREQ 24 MHz to 27 MHz)  / PLL_VT_MPY 区切りがおかしい次に続く
w 0307 <- 39       ; PLL_VT_MPY
w 0309 <- 0A       ; OPPXCK_DIV
w 030B <- 01 00    ; OPSYCK_DIV PLL_OP_MPY[10:8] / 区切りがおかしい次に続く
w 030D <- 72       ; PLL_OP_MPY[10:8]

w 455E <- 00       ; 
w 471E <- 4B       ; 
w 4767 <- 0F       ; 
w 4750 <- 14       ; 
w 4540 <- 00       ; 
w 47B4 <- 14       ; 
w 4713 <- 30       ; 
w 478B <- 10       ; 
w 478F <- 10       ; 
w 4793 <- 10       ; 
w 4797 <- 0E       ; 
w 479B <- 0E       ; 

w 0172 <- 03       ; IMG_ORIENTATION_A 
w 0160 <- 06 E3    ; FRM_LENGTH_A[15:8] 
w 0162 <- 0D 78    ; LINE_LENGTH_A
w 015A <- 04 22    ; COARSE_INTEGRATION_TIME_A
w 0157 <- 00       ; ANA_GAIN_GLOBAL_A

w 0157 <- 00       ; ANA_GAIN_GLOBAL_A
w 0160 <- 06 E3    ; FRM_LENGTH_A
w 0162 <- 0D 78    ; LINE_LENGTH_A (line_length_pck Units: Pixels)
w 015A <- 04 22    ; COARSE_INTEGRATION_TIME_A 

w 0100 <- 01       ; mode_select [4:0] 0: SW standby, 1: Streaming

w 0157 <- 00       ; ANA_GAIN_GLOBAL_A
w 0160 <- 06 E3    ; FRM_LENGTH_A
w 0162 <- 0D 78    ; LINE_LENGTH_A
w 015A <- 04 21    ; COARSE_INTEGRATION_TIME_A

w 0157 <- 00       ; ANA_GAIN_GLOBAL_A

w 0160 <- 0D 02    ; FRM_LENGTH_A
w 0162 <- 0D 78    ; INE_LENGTH_A (line_length_pck Units: Pixels)
w 015A <- 0D 02    ; COARSE_INTEGRATION_TIME_A

w 0157 <- E0       ; ANA_GAIN_GLOBAL_A

----------------

Web上の資料や他のオープンソースから情報があったものに関してコメントとつけていますが、不明なものも多いです。

次に、これを Zybo に繋ぎ変えます。

Dbxq41ivaaalchojpg_large

で、PSからI2Cコアを繋いで、他の信号はXILINの D-PHY コアを生成して素直に接続します。

Dphy

上記のような設定です。

Csi

あっさり信号は受信できていました。

ただしこの時一点嵌りまして、ILAで観測するにあたって、rxbyteclkhs クロックが間欠的にしかこないという点があります。まず dbghub にこのクロックがアサインされるとアウトで、ILAの方も、タイミングが悪いとキャプチャボタンを押してもエラーになります(何度か押せば取れるようです)。

また、図の通りレーンごとの信号は稀に前後するケースがあるようなので、rxsynchs でレーン間同期が必要なようです。

で、D-PHYコアから出てくるHSの信号を無信号期間も含めて何も考えずにDDR3-SRAMに記録する回路を書きまして、解析しました。

まずは何も考えずにダンプの一部をラインっぽいデータだけ抜き出して8bitでダンプしたらいきなり絵っぽいもが見えました。

Db21qbnvmaaisvpjpg_large

後で分かったのですが、RAW10bitでBeyerデータなのですが、どうも4画素が5バイトにパッキングされているようなのですが、4画素の上位8bitが並んだ後に、下位2bit 4画素分がパッキングされた1バイトが付いているようで、バイナリダンプでもそれなりに絵になるようですね。

ついでなので、この段階で一度まともにデータを切り出して、BAYERを考慮して簡単に色をつけてみます(ホワバラ的に簡単にレベル合わせだけしたので飽和しまくりですが)。まあ、色補正やガンマ処理とかいろいろやることは残っていますが、その辺は最後に回します。

6

現像をどうするかはこれから考えますが、特許の切れた(20年経ってますよね?)ACPI法あたりの簡易な方法でよい気はしています。ただ解像度が高い近年のイメージセンサだと古典的な方法はあまり効果が無いのと、ピクセルビニング使うとこれまた意味がなくなるのでいろいろ考察は必要になりそうです。

とりあえず、D-PHYの解析結果をまとめると、各レーンのパケットは

  • rxactivehs が1の区間だけ立っているところだけ見ればよさそう
  • パケットの先頭では rxsynchs が立つのでこれをレーン間で同期
  • データはバイトストリームで lane0 -> lane1 -> lane0 -> lane1 で巡回している

というのが見えてきました。

で、パケットには先頭にヘッダがあり

  • ID (1byte)
  • データ長(2byte)
  • ECC (1byte)
  • データ (データ長分)
  • CRC (2byte)

となっているようです。

 1ライン分のデータを示すパケットは ID = 0x2b で始まっているようです。またフレームスタートを示すのに ID=0x00、フレームエンドを示すのに ID = 0x01 というのが来ているようで、これにはデータ部分は無いようです。
またラインの最初に ID = 0x12 というのも1ラインと同じ長さのパケットが2つ来ているようです。

 これだけ分かれば、絵を取るには十分なのですが、追加で少し調べた限り、short packet と long packet というのがあるらしく、short packet は ID が 0x00 で frame start、0x01で frame end で他に optional で line start や line end もあるようですね。 0x12 は埋め込みデータ(詳細は未調査)で、0x2bはRAW10bit の画像データを示すようです。

 CRCはCRC-16-CCITTという名称のものになるようですが、まあ良く見かけるやつの模様です。ECCの部分は当初良く分からなかったのですがECCだそうです。CRCもECCもエラーが無ければ当面は無視してOKそうですね。

引き続き、受信回路の作成に取り掛かろうと思います。
今回、ここで取ったデータがそのままテストベンチで利用できそうです。

(追記)
実データを使ったテストベンチでRTLが動き始めました。
Out_img

シミュレーション結果としてAXI4-Stream Video で出力させて、ダンプしたものです。
ちなみにシミュレータには Veritak のシェアウェア版使っています。ビルドがとても早いので、コード弄りと動作確認のTATがとても短くて生産性高いのでお気に入りです。

(さらに追記)
もしかすると Zybo用に Digilent が出している Pcam 5C よりコスパが良いかもしれません。2018/4/29現在の秋月電子の価格でスペックと一緒に比較すると

Pcam 5C       : OmniVision OV05640 2592x1944(5M) 15fps 5,130円
RaspPi Cam V2 : Sony       IMX219  3280x2464(8M) 21fps 4,300円

のようです。
もちろん輸入費用とか、円ドルのレートとかいろいろあるわけですが、Raspberry Pi の量産の恩恵もありそうに思います。

2018年4月15日 (日)

ZyboのLinuxからI2Cを使ってみる

引き続き、@ikwzm様の環境でのLinux作業ので備忘録です。

イメージは下記のものを利用させていただいております。
FPGA+SoC+Linuxのブートシーケンス(ZYNQ+Vivado編)
https://qiita.com/ikwzm/items/7e90f0ca2165dbb9a577

作業に先立って、I2Cを有効にした ps7_init_gpl.c/ps7_init_gpl.hを作る必要があります。

ここでは再びベアメタルでI2Cを利用したときの下記のサイトを参考にさせていただきます。

ZYBOのPSでI2Cを動かしてみた
http://todotani.cocolog-nifty.com/blog/2016/09/zybopsi2c-615d.html

これを前回と同じ方法で、U-Boot の SPLに仕込みます。

次に、DeviceTreeです。@ikwzm様の環境の devicetree-4.14.21-zynq-zybo-z7.dts にすでにI2Cの項目があり

i2c@e0004000 のところで

status = "disabled";

となっているので

status = "okay";

とするだけです。
dtc で dtb に変換した後に、boot.bin と dtb をSDカードにコピーして起動したらめでたく

/dev/i2c-0

が見えるようになりました。

#include <sys/ioctl.h>
#include <linux/i2c-dev.h>

を追加して

int i2c = open("/dev/i2c-0",O_RDWR);
ioctl(i2c, I2C_SLAVE, 0x68);
uint8_t    buf[16];

buf[0] = 0x75;
write(i2c, buf, 1);
read(i2c, buf, 1);
printf("WHO_AM_I:0x%02x\n\r", buf[0]);

みたいな感じでとりあえず、MPU9250 の WHO_AM_I レジスタが読めました。

速度は DeviceTreeで

clock-frequency

の項目で指定は出来るようですが、動的に変えられないのかな?
とりあえずDeviTreeの変更で
clock-frequency = <0x61a80>;
とすることで目的の400Hz動作には設定できたようです。

ついでですが、I2Cを有効にした hdf (ハードウェア定義ファイル) を元に petalinuxでもdevice-treeを生成してみましたが、該当部分は

        i2c@e0004000 {
            compatible = "cdns,i2c-r1p10";
            status = "okay";
            clocks = <0x1 0x26>;
            interrupt-parent = <0x4>;
            interrupts = <0x0 0x19 0x4>;
            reg = <0xe0004000 0x1000>;
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            clock-frequency = <0x61a80>;
        };

となっていました。

ちなみに

sudo apt-get install i2c-tools
sudo apt-get install libi2c-dev

とかすると、いろいろツールが入り

bin/i2cdetect -y -r 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

とかも出来ました。

少しづつですが RaspberryPi 的に使えるようになって来ました。まだまだ覚えることが多そうです。

ZyboでLinuxからUIOアクセス(備忘録)

@ikwzm様の環境でのUIOからのアクセスに挑戦したので備忘録です。
FPGA+SoC+Linuxのブートシーケンス(ZYNQ+Vivado編)
https://qiita.com/ikwzm/items/7e90f0ca2165dbb9a577

本当にありがたく利用させていただいております(感謝)。

なお、今回は、FPGA region の機能は利用せずに、起動時のbitファイルを入れ替えます。
SDカードのFAT領域を弄るだけですね。Vivadoは2017.4を使っています。
やることは

  • u-boot の SPL部分に ps7_init_gpl.c / ps7_init_gpl.h を反映させる
  • DeviceTreeを入れ替える
  • bitファイルを入れ替える

u-boot が一番面倒ですね。@ikwzm様の環境のu-bootは「U-Boot v2016.03 (customized) 」との事ですが、どうせSPLしか利用しないので、将来のことも考えて新しめの U-Boot(v2018.03-rc4) を使ってみました。

git clone -b v2018.03-rc4 git://git.denx.de/u-boot.git

で、

cd u-boot

して

make zynq_zybo_config

make menuconfig
して、特に内容は弄らずSPLが有効になっているか一応確認。

ここで
board/xilinx/zynq/zynq-zybo に ps7_init_gpl.c と ps7_init_gpl.h をコピーして上書き。
(ちなみにVivadoからexport Hardware したときのhdfファイルが実体はzipファイルなのでunzipすればわざわざSDK起動しなくてもこれらのファイルは得られる模様です)

最後に

make CROSS_COMPILE=arm-linux-gnueabihf-

すれば spl の下に boo.bin が出来上がるのでSDカードにコピー

次に、DeviceTreeを変更します。

@ikwzm様の環境に既に

devicetree-4.14.21-zynq-zybo-z7.dts

が用意されているのでこれに書き足します。
私の場合、0x40000000 以降にWISHBONEを割り当てて、そこからRTLでアドレスデコードしているので、下記のように大胆に各種ペリフェラルデバイスのいるメモリ空間をまとめて1個のuioに割り当てています(後でbitファイルだけ入れ替えればよいように)。

 

    amba_pl: amba_pl {
        #address-cells = <1>;
            #size-cells = <1>;
            compatible = "simple-bus";
            ranges ;
            my_pl_peri: my_pl_peri@40000000 {
                compatible = "generic-uio";
                    reg = <0x40000000 0x40000000>;
                    xlnx,s00-axi-addr-width = <0x4>;
                    xlnx,s00-axi-data-width = <0x20>;
            };
        };

 

 

で、

sudo apt-get install device-tree-compiler

すれば、dtcが得られます(VirtualBoxのUbuntuでもよいですし、なんとZyboのDebianでもできそうです)。

dtc の使い方は

dtc -I dts -O dtb -o output_file.dtb input_file.dts

みたいな感じですので、 output_file.dtb と input_file.dts は各自のファイル名で読み替えてください。

出来上がった dtb ファイルをSDカードにコピー

最後に、bitファイルもSDカードにコピーして、uEnv.txt の中の dtbやbitファイルのファイル名を必要に応じて変更すれば完了です(もちろん元の名前のまま上書きするならこの作業は不要です)。

UIOへのアクセス方法は下記を参考にさせて頂きました。
https://qiita.com/take-iwiw/items/da91ce4dc2a8a8df3c0a

とりあえずアクセスでき始めました。
これでやっとXilinxSDK での standaloneでのプログラム(ベアメタルの開発)から次のステップに進めるかな?

ps7_init_gpl.c には、PSでのLinuxのブートに必要な設定と、PLでの自作ロジックの動作に必要な設定の両方が含まれているのが難しいところですね。

2018年4月13日 (金)

Zybo 開発環境構築記

 長らくZyboを眠らせたままでしたが、ちょっとだけ余裕が出てきたのでRealTime-GPUの設計を再開いたしました次第ですが、MIPI CSI-2 に挑戦したくて、Zybo Z7 を購入し、折角なのでちゃんと Zybo を Zybo らしく使おうと、最新の環境を構築しなおしました。
(なにしろ今までPSをWindowsのみの開発環境で XilinxSDK から standalone でしか使っていなかったので、Etherなど活用できずに、ただの内部シーケンサとしての利用でとまっていましたので。もったいなかったです)

 その際のWindows7上で作成した環境を備忘録程度に書いておきます。
 参考にさせていただいた記事の著者の皆様にこの場をお借りして御礼申し上げます。

 なお、作業できたときだけ、ちょっとづつ進めていたので、いろいろと思い出せないところがあるのですが、一連の情報へのポインタになればといったところです。

 どちらかというと、私のようなRTL開発はしたことあるけど、PS上にLinuxを構築する方法が分からないという人向けかもしれません。PSだけでも Raspberry Pi 的な世界が作れますので、それにFPGAが繋がると非常に楽しい世界が産まれそうです。似たような境遇の方の参考になれば幸いです。

[とりあえず Zynqで Linux を起動する最短コース]

1. Zybo を買う
 Zybo と Zybo Z7 と Zybo Z7-20 の3種類あります。

 違いの一覧表は
   https://reference.digilentinc.com/reference/programmable-logic/zybo-z7/migration-guide

 にあえります。 私は、Z7-20を買うのに、RSオンラインとDigikeyと秋月を比較しましたが、消費税と送料を加味すると秋月が一番安かったです。
 私は手元のものを使いましたが、SDカード/microUSBケーブル/ACアダプタも必要になるので、ご注意ください。
 ACアダプタは microUSBからの給電能力が十分なら不要かもしれません。

2. VirtualBoxに Ubuntu 16.04 LTS をインストール
 これはあちこちに情報があると思いますので、割愛します。

3. ビルド済みイメージ

 結局、下記をそのまま利用させていただきました。

 FPGA+SoC+Linux+Device Tree Overlay+FPGA Region(ブートイメージの提供)

  https://qiita.com/ikwzm/items/7e90f0ca2165dbb9a577

 非常に使いやすいです。

 SDカードのパーティーションは、

   apt install gparted

  などで gparted などを入れると良いかと思います。

  SDカード用のUSBアダプタを使って、VirtualBoxの[デバイス]->[USB]から選択すれば、Ubuntuからマウントできます。

4. 電源を入れて起動

 Zybo の UART にUSBを挿しておけばCOMとして認識されます。115.2kbps で接続すればログイン画面まで進むはずです。
 初期ユーザーが fpga  (パスワードもfpga) なのでログインします。
 /sbin/ifconfig
 で DHCPでアドレスが取れていれば、IPアドレスが確認できます。

 あとは apt が使えるので何でも好きなものが入れられます。
 sshでもログインするようにすればusb接続も不要になります(ACアダプタは必要)。

 adduser で追加のアカウントを作っても良いと思います。

5. X-Windowの設定

下記を参考にさせていただきました。

 FPGAの部屋  ZYBOのLinaro Ubuntu のXウインドウの表示をパソコンで行う(Xmingを使用)
http://marsee101.blog19.fc2.com/blog-entry-2947.html

 とても快適になります。

6. sambaの設定

sudo apt-get install samba

sudo pdbedit -a <user>
でユーザー追加

/etc/samba/smb.conf を編集

[homes] の
read only を no に変更

sudo systemctl restart smbd nmbd

これで、Windowsからアクセスできるようになります。

[開発ツールのインストール]
  ikwzm 様イメージだといきなり起動できてしまいますが、開発ツールも必要ですね。

1. SDSoC 2017.4 をインストール

 バウチャーつきを買うとSDSoCのライセンスもついてくるようです。
 以前にWindowsで先にVivadoを入れるとSDSoCが入らなかった記憶があります。SDSoCを入れるとSDSoCにはVivadoが含まれるようです。

2. VirtualBoxのUbuntuにPetaLinuxをインストール
 下記を参考にさせていただきました。

  ZYBO (Zynq) 初心者ガイド (8)
   https://qiita.com/take-iwiw/items/6e6915f7318689818368

3. ボードファイルのインストール

   下記を参考にさせていただきました。

   FPGAの部屋 Digilent社のボード・ファイルのインストール
   http://marsee101.blog19.fc2.com/blog-entry-3365.html

   gitでも取得できます。
   git clone https://github.com/Digilent/vivado-boards.git

 なお、Block Design での PSの設定は Zynqコアを置いただけでは反映されず、「Run Block Automation」を「Apply Board Preset」にチェックをつけて実行した段階で設定されるようです。

[PLの開発]
 PSが動いただけでも、PSに繋がる各種デバイスは利用できるので、ちょっとしたRaspberryPi 的な環境になります。
 が、私のような人間だと、「じゃあPLは、XilinxSDKのstandaloneの時と違ってどうやって使うの?」となります。ハードウェア空間はMMUでプロテクトされている上に、論理アドレスと物理アドレスが違うわけで、Linuxのデバイスドライバなんて超ハードルが高いわけです。
 で、UIOという以前軽く触っただけのものに本格的に手を出します。

 Device-Treeを書いて と UIOを使えばいいようです。
 とても分かりやすい記事が下記です。
 https://qiita.com/take-iwiw/items/da91ce4dc2a8a8df3c0a
 とても参考にさせていただきました。

 次はこれをどう反映させるかです。
 本来の配布イメージの趣旨としては FPGA region を使うべきなのですが、初心者な私にはこれまたハードルが高くてまだ試していません。
 でもひとまず確実な方法があります。SDカードを書き換えてリブートしちゃえば良いのです。
 ということでそのやり方ですが、FAT32のパーティーションにある、bitファイルと dtb ファイルを置き換えるなり、新しい名前で置いてuEnv.txtを書き換えるなりすればOKのようです。

 他は
 ZYBO (Zynq) 初心者ガイド (1) 開発環境の準備
 https://qiita.com/take-iwiw/items/966f252f6ca954aff08b

 をざっとこなせば概ね解決するかと思います。

[おまけ]
 sambaが標準で入っているの知らなかった&SDが8Gで心もとなかった時に、SFTPでのマウントを試みました。
 調べた範囲が下記のツールです。

 ・ dokan + win-sshfs => 試したけど自分の環境では動かなかった
 ・ SFTP Net Drive
       Free版(非商用限定)と Pro版がある模様、Free版はメールアドレス登録が必要
       Free版を試しましたが快適でした。ただマウント中にZyboを落とすとおかしくなりました。
 ・ExpanDrive 試してません&有料のようですが、調べた限り使い勝手はよさそうな感じ

 PetaLinux ベタで環境作る場合などで、sshだけはあるとか、ネットに繋ぐのでsambaではセキュリティー的に不安というときはsshでのマウントも便利そうです。

[おまけ2]
X-Windowが動いてうれしくて、xneko動かしてみました(懐)

xneko.tar.gz とってくる

% sudo apt install xutils-dev
% sudo apt search Xlib.h
% xmkmf
% make
% sudo make install

 いろいろ抜けていそうですが、引き続き、情報足していければと思います。



2018年3月10日 (土)

脳とFPGAと

 昨今大流行のDeep Learningですが、脳の模倣をコンピュータにやらせようという試みかと思います。
 で、現状手軽に手に入る計算機としては、メモリと演算器で構成されたノイマン型のプロセッサと、FPGAとでは構造的には後者のほうが脳のアーキテクチャに近いと思われます。
 実際に、Deep Learning をFPGAで加速しようという試みはあちこちにあるわけです。

 で、脳とDeep Learningの違いは山ほどあるわけですが、個人的に最大の違いは脳はアナログ回路だという事です。

 ここで、誤解を恐れずに言ってしまえば、Deep Learning のFPGAなどへの実装の試みは、脳のデジタル化とも言えると思っています。

 デジタルのメリットは、劣化無く伝送できる、劣化無くストレージできる、ストレージにランダムアクセスしやすいなど、いろいろあり、かつて、黒物家電がアナログからデジタルに進化したとき、当初はこのメリットを活かすべく、せっせとアナログをデジタルに置き換えていったわけです。

 が、ここで、単にアナログでやっていた演算をデジタルに置き換えてもあんまり面白くないわけです。

 かつてアナログがデジタル化する際に起こったデジタルらしい演算の代表格のひとつは、D級アンプでは無いかと考えております。
 従来、アナログを単純にデジタル化して多値で演算していたのに対し、D級アンプはサンプリング周波数を上げることで、1bitでありながら多値デジタルに対して等価以上の価値をもたらしました。

 脳をデジタル化する場合にも同じことが言えるのではないでしょうか?
 せっせと、重みを浮動小数点演算するのもありますので、XNORNetのようなバイナリ系のネットのほうが面白そうに思えます。

 個人的には、入出力も全部2値にできるような気がします。

 ・ 高いサンプリングレート
 ・ 精度の良い乱数生成器
 ・ 論理演算器
 ・ 分散されたストレージ

 だけあれば、デジタルらしさを活かした、まったく新しい脳っぽいことをするアーキテクチャが出来そうな気もします(深く考えてないですが)。

 で、実は上はFPGAは結構既に持っていて、無いのは乱数生成期なのですよね。
 CLB内に収まる程度の半導体面積の量子雑音を生成する素子を埋めたFPGAができると何か面白いことが出来そうな気がします。
 時間軸方向に確率的に現れる0/1で尤度を表しつつも、あくまで論理演算としつつ、サンプリングレートが高いので、結果として観測可能な帯域ではアナログ的に振舞うといったようなデバイスが作れないものかと、考えてみたりする今日この頃です。 

2018年2月19日 (月)

OLED(有機EL)高速駆動

PMOD用にZyboに繋がるOLEDがDigilentから販売されているので今回試してみました。
こちらのページのとおりやってみるとあっさり動作しました。
Digilentのライブラリの充実っぷりに驚きです。

次にこのOLEDパネルを、高速度撮影の出来る Sony の Xperia XZs で撮影してみました。

机上で計算した限りデフォルト値では、102fps程度の動作のはずです。なのでカメラの露光時間で64line × 102/960 = 6.8ラインが写っていれば目論見どおりです(やや幅広な気もしますが、こんなものな気もします)。

で、ここからデータシートと睨めっこです。どうやらもっとも発行時間の長い GS63 (輝度が6bitなので輝度値63の時の点灯時間)が基準になっているようです。

Digilentのサンプルソースから、初期設定箇所を探して、GS1~GS63 まで 32個あるテーブルを書き換えるコードを追加してみます。ついでに画像も書き込む前に2値化(つまり8色化)してます。
GS63をあまり小さくすると何も見えなくなってきたので、最終的に5まで下げました。

多少試行錯誤はしたのですが、階調さえ落とせば高速化したように見えます。

なお、このおじさんの写真はDigilentのサンプルプログラムに埋まっていた画像です(誰なんでしょう? 開発者とかなのかな? (^^;;  )。

データシートに従って机上計算したところ、内蔵オシレータが Typical値想定で 869Hz 出ているはずです。

960fps撮影なので1コマの間に概ね画面全体が写っていれば正解のはずです。

しかし、ローリングシャッター歪が見えないのはなぜだろう....(悩み)。高速度撮影時もローリングひずみ除去処理が入ってたら逆に計測性が難しくなるなぁ。

今回買ったボードはPMODからSPI接続ですが、SSD1331自体は1cycle 130nsでのパラレル書き込みも出来るようです。

なので、PMODから一旦LVDSなどで出してSERDESデコーダICを載せたボードを起こせばハイフレーム駆動できるんじゃないかと予想しています。

ただ、SSD1331以外のコントローラだと書き込みが300nsというのが多いのですよね(謎)。OLED自体はaitendoさんやAlibabaなんかで安いものが出回っているので、もう少し安くて解像度があって書き込みの早いやつが無いかと探し中です。

先がだいぶ楽しみになりました。

(2018/02/19追記)

パラレルモードでの書き込み速度を調べてみました。

SSD1331  96x 64  130ns
SSD1351 128x128  300ns
SSD1352 160x128  300ns
SSD1353 160x132  300ns
SSD1355 128x160  300ns
SSD1357 128x128  不明

SSD1331以外、結構遅いようです。内蔵メモリの構造とかかなぁ?
困っりました、SSD1331を4枚並べて面積を増やすぐらいしか思いつけない....

Oled_x4

2018年2月18日 (日)

電脳メガネ開発計画(?)

Zybo上で開発しているRealTime-GPUがそこそこ動き始めてきたので、格安な研究費で(つまり趣味で)トライする超リアルタイムな電脳メガネ開発計画(妄想)を公開します。
OLEDがハックできるかが最大の課題なのですが。

2_2

 

 

GPUの方は、先日書いたリアルタイムアーキテクチャのGPUで、動画映像をテクスチャとしたポリゴン描画が動き始めてきました。
ピクセルクロックは200MHzですが、一旦解像度を置いておけば性能は速度に振れるはずです。

 

OLEDはPMODでのSPI接続では速度が足りないので、SERDES基板は作ってパラレル書き込みにしないといけませんが、例によって Seeed Fusion PCB の $4.9 基板で作れそうに思っています。 まずは低解像度さげていいので時間軸において、人間の視覚がハッキングができる遅延時間&周波数帯までまで持ち上げたいのが今回の計画の趣旨です(お金さえ掛ければ解像度は上がるので)。

実際、今のVRメガネをつけてだとカメラの映像見ながらだとスポーツはおろか、自動車や自転車など日常生活ですら安全に行うのは困難だと思いますが、これはGPUにリアルタイム性がないのも一因と思っています。
ですので、マイクロソフトのHoloLensなど、AR目的のメガネはVR用と異なりあくまで現実世界はそのまま見せて置いて、CGは光学的に重畳しているわけです。

この動画とかみると、マイクロソフトも遅延の重要性はよくわかってるはずで)

メガネなのだから、人間の目以上の性能が必要です。時間分解能と遅延が十分でなければRealTimeとはいえません。OLEDは基本LEDなので応答速度はLCDとは桁違いの筈なのですよね。

カメラは手元のXperia XZs が 960fps ですが、なかなか仕様が開示されていてモジュール単体で手に入るものだと速いものがなく、探した範囲では Raspberry Pi 用の IU233 がまあまあ性能が出そうです(240fps)。(と、思っていたら、Pi Camera Module V2のIMX219がもっと安価で撮像スペックは高性能でした。小型ではないけど)。

Zybo も手元のも(初代)には無いですが、後継機からMIPIインターフェースがついているので繋がるはずです。
もっともまずはカメラはオプション的な位置づけで、ポリゴン描画をリアルタイムに十分速くすることに重点を置ければと思います。

GPUの方はスペック上は今200MHzのピクセルクロックで処理できているので、128x64のOLEDなら数値上は40usで1フレーム更新できちゃう帯域の計算になっちゃいますね(まあI/Fがついて来ませんが....)。

まあ実際1000fpsも厳しいとは思っていますが、もし仮に2万fpsとかでトータル遅延が100usとかのオーダーに出来たとすると、例えば野球で150kmのボールを打つときでも現実とバーチャルのずれがミリメートルオーダーになってくるので(時間軸的には)超リアルなスポーツゲームとかも出来るのではなかろうかと。

打倒ホロレンズ?(笑)。

いつかデンスケに会える日を信じて、夢は大きくがんばりましょう。

(2018/03/19: カメラをIMX219に変更しました)

2018年2月17日 (土)

バイリニアのXILINX FPGA向け実装

乗算器を使わないバイリニア補間のコードを書いています。その過程の線形補間の作成でちょっと面白い最適化に気がついたので記事にしておきます。

線形補間は2点の比なので、中心(足して2で割る)を求めて片方とリプレースすることを繰り返せば、加算器1段ごとに1bitづつ精度を上げていけます(いわゆる挟み撃ち法)。4bit程度しか精度が要らない今回の場合は、乗算器を使うよりお得かもしれません。

そこで最初下記のような計算ステージ1段で下記のようなことを行うコードを書いていたのですが、


always @(posedge clk) begin
  tmp    = (din0 + din1) / 2;
  dout0 <= sel ? tmp  : din0;
  dout1 <= sel ? din1 : tmp;
end

下記のように書けばコンパクトになるのではないかと思いやってみたところ、見事に(ISEの合成レポート上は)小さくなりました。  


always @(posedge clk) begin
  dout0 <= (din0 + (sel ? din1 : din0)) / 2;
  dout1 <= (din1 + (sel ? din0 : din1)) / 2;
end

リプレースをセレクタによって選択的に行うのではなく、置き換えない場合は自分自身を足して2で割ることで、値をキープするように書き換えています(実際には2で割る部分は最後に纏めてシフトするのが精度の点では良いようですが、今回は説明用ということで)。
前者は加算器2個、後者は1個なのになぜ? と思われる方もおられるかもしれません。

以下、XILINX社のUG474の図2-4を引用させて頂いて説明します。

Slicel

 XILINXのZynqの属するXILINX 7シリーズのSLICEはLUTの後ろに加算などをサポートするキャリーチェーンが必ずついているようです。
 なので

  • LUTを使う場合、キャリーチェーンの利用の有無は消費スライスに影響しない
  • キャリーチェーンを使う後にもロジックがあるとさらにLUTが必要になる

 ということになります。
 なので、加算が2個に増えることによるリソース増加はなく、演算の最後が加算で終わるように書き直すことによるLUT削減の方の効果が出るという一見不思議なことが起こるようです。
 もっとも、別の回路とくっつけて合成したら、結局はいい感じに収まる可能性もありますが。

 ただ、筆者の経験上、加減算を行う場合、FFへの代入の最後の演算が加減算で終わるように式変形してやると若干改善するケースは幾つかあるように思います。
 これはFPGA特有のテクニックで、LSI向けのRTLを書く場合は、回路が増えるデメリットだけだとは思いますので、果たして推奨するべきかは非常に微妙ですが、こういうこともあるのだなという面白い例かとは思います。

 なお、バイリニアなどの線形補間と良く似た計算でアルファブレンディングがあります。線形補間との違いは、線形補間は 256が1.0になるのに対して、アルファブレンディングは255が1.0であることです。

 この問題は、

http://www.cqpub.co.jp/dwm/contents/0104/dwm010400780.pdf

https://qiita.com/andantissimo/items/84be23b0f2937f8b3d90

とかに詳しい解説があるようで、それほど大きな追加コストはなく 256/255倍の計算は出来るように思います。

とはいえちょっと工夫すればはさみうち法でもアルファブレンディングが出来そうに思っています。

これはまた今度機会があれば考えてみたいと思います。

より以前の記事一覧