2018年03月29日

高速通信の検討

FPGA で、高速通信をしてみたいと書いた。それについてのメモ:

世の中のインターフェイスは、みな数Gbps になってしまった。SATA が 6Gbps, USB が 5Gbps , イーサネットは 1Gbps だが、同じ RJ45 のタイプで、2.5/5 Gbps もある。そんなものは、(安物の FPGA) では 扱えない。たとえ扱えたとしても、電子工作では電気特性的に無理だろう。

映像系の一方向通信では、HDMI 2.0 が 18Gbps ! カメラインターフェイスの CSI-2 とかも G2a - 2.5 Gbps/G2b - 2.9 Gbps 。

どれもこれも、電子工作では手も足も出ない感じ。しかも普及しているから安価に使えるのである。電子工作の出番はない。

では、電子工作で扱えるレベルは、どれぐらいなのだろうか?お手軽に使えて高速なものと言えば、SPI (3.3Vシングルエンド) 。これは 30Mbps だとかなり厳しい。電気的な条件を整えてようやくという感じだろうか。

3.3Vシングルエンドを多ビット化したものだと SD/SDIO (HS)。50 MHz x 4 bit で 25 MB/sec -- これが一応可能 , UHS-I の 1.8V シングルエンドだと 104 MB/sec 208 MHz がある。さらに eMMC (4.0) だと 8bit 化で 208 MB/sec 。
と言っても、電子工作で信号線をケーブルで引き出したら、とても通信が出来ないのではないかと思われる。

次に 差動信号による通信はどうだろう?
LVDS.png
LVDS という規格がある。液晶モジュールをはじめとして基板間の通信に良く使われている。差動にすればケーブルで引き出せるのだ。LVDS は、2.5v 差動信号で 1.8v のものは、sub-LVDS 。FPGA は 普通にサポートしている。どこまでの速度で通信できるかは、FPGA 次第だが、iCE40 (のポート自体)は、250 MHz 。

    I/O 電圧 2.5V が正式な LVDS で iCE40 では、Rs = 150Ω, Rp = 140Ω だそうだ。Rs は 150 だが iCE40 の内部抵抗 30Ωを引いた値。
    これ 3.3v で無理やり作るとすると、Rs = 180Ω, Rp = 130Ω ? 半端な値があるので、ここあたりで購入すると良いかも知れない。

iCE40 は、簡単な回路なら 133 MHz とかで動くみたいなので、100MHz 以上で通信できる可能性はある。


さて、仮になにかデバイスを作るとして、ホスト側では、何を利用できるのだろうか?

想定は Raspi などの SBC 。まず USB だが、2.0 の 480Mbps はちょっと無理として、12Mbps なら、マイコン あるいは FPGA で扱える。だが、12Mbps は高速通信から外す。

SPI が、どれでも使えそうなものになるが、その上は何だろう?

だいたいの SoC は SDIO を持っているのだが、Wifi モジュールとの通信に使われる。Wifi がモジュール化されてオプションとなる SBC として、PINE A64 あるいは、出たばかりの PINE H64 がある。

    PINE-WIFI.jpg

    調べた情報:PINE H64 は、A64 と少し違う。14 pin の方の SDIO は同じだが、反対側には UART PCM とかが出ている。

eMMC がモジュールになっている SBC もいくつかある。PINE 系はみなそうだし、ODROID もモジュールがあるようである。ただ、モジュールの形状から、扱うのは厄介な感じ。

SBC 以外だと ESP32 がある。SDIO/SD master が普通に利用できる。SDIO slave も利用できるはずなのであるが、SPI FLASH が付いていると無理。もし、SPI FLASH を外せると、SDIO 経由でファームウェアをダウンロードし、起動後は、SDIO デバイスとして使うことができる。

    ESP-32S-ALB-top.jpg
    analoglamb.comというショップにショップ・オリジナルの ESP-32S-ALB というのがある。ESP-WROOM32 互換だが、シールドがないので、実験用に SPI-FLASH を取り除くことができる。ついでに書くと ESP-WROOM32 も安価で発売されていて REV0/REV1 を選択して購入できる。

    今のところ単なるネタだが、PINE H64 用の WIFI+BT モジュールに出来ると面白いかと思っている。普通の モジュールだとファームウェアを弄ったり出来ないが、これだといろいろ遊べるのである。

SDIO がひとつの候補だが、他には?

一応 100M イーサがある。PHY は、そこそこ安い。PHY とのインターフェイスは、MII または RMII 。ESP32 は、このインターフェイスを持っている。普通は、トランス付きの RJ45 コネクタで HUB につなぐのだが、基板間程度の距離であれば、PHY どうしを直結することも可能。この場合当然 1:1 接続になる。

    PHY には、安価な LAN8720A (QFN24 RMII) が使える。-- 10個で $3 とかその程度。LAN8710A はもう少し安い。RMII に加えて MII もサポートしており、ピン数が多い(QFN32)。

    これをどうするのだ?と思われるかも知れないが、PHY は パケットを受け渡しするだけの機能。TCP はおろか Ethernet フレームも理解しない。パケットの中身は自由に定義して使うことも出来るのだ。

他には、USB 2.0 対応の FTDI とか、EZUSB-FX2 とかを使って電子工作で扱えるもの入力 変換するとか。USB を経由すると、スループットは高くともレスポンスは悪くなる。大量のデータを受信または送り付けるような使い方が良い。

一方通行の映像系だと、MIPI CSI カメラインターフェイスを持っている SBC がある。MIPI CSI は LVDS を何組か使う。 2 組で CLK と DATA のものもある。ただの CSI は、8bit パラレル。液晶出力を持った SBC もある。昔ながらの液晶モジュールは 24 bit パラレル+同期信号 とかだが、SBC の方がどうなっているかは未調査。


FPGA 同士ならば LVDS がお手軽そうに思える。... のだが、そもそも 異なるクロックドメイン間で データを受け渡すのはどうしたら良い? これは、LVDS に限った話ではなくて、SPI スレーブとか外部からクロックと同期したデータが来る場合の問題。シリアルのように、数倍のクロックで動作させて データが安定したのを見計らって・・・というのは不可。それでは、高速通信にならない。

どうも EBR を使って 非同期 FIFO を作るらしい。他の lattice FPGA だと FIFO_DC というのが用意されているが、iCE40 は使えるどうか分からない。が、dual port メモリがあれば、自分で組める。

とにかく EBR を使うと 512B の 非同期FIFO が手に入る。

LVDS での使い方は、クロック1組、データ一組の合計4本の信号線でパケットを送り付ける -としよう。双方向で対称で作ると、8 本もの信号線が必要。どちらかが、クロックを送出するということにしても 6 本。-- SDIO と変わらない。4 倍速で転送できなければ、速度では SDIO に劣ることに。また、片側だけのクロックを使う場合、スキューがどうのとかいう面倒そうな問題がある。SATA のように 送受信 各1 組で済ませられると良いのだが。これまた、さらに難しそうな。

USB は、同期パターンから始まって、それにクロックのスキューを調整するとかなんとか。スキューがどうのという話が必須なのであれば、遅延させたデータを使って、パルス幅で 0/1を判断するのが簡単そうな気がする。

    FPGA にはディレイの機能があるものだと思い込んでいたが、iCE40 にディレイ機能はなかった。MachXO2 だと 32段階のディレイが設定できたのだが。... と言っても 50ps x31 で 1.5ns ほど。全然足りなかった。ちなみに Spartan-6 は 75ps x 255 まで。20ns ほど遅延できるようだ。

ちょっと前の CMOS インバータ TC7W04 とか使ってディレイさせるのは どうだろうか? 電源電圧によってだいぶ性能が変わるのだが、3.3V だと 20ns ぐらいと見た。(4.5V 8ns/2V 30ns)。 一回受けた入力を外部に出してまた入力する。で、posedge で動作させて、TC7W04 の出力が H だったら、L 期間が短く L だったら L 期間が長い。これで 0/1 を判断する。
本当に単に遅いバッファ・インバータを使えば良いのだろうか?... ちょっと違うような気がしてきた。信号の立ち上がり(下がり)が遅いだけで、役に立たない?
SN74LVC1G14 これの入力に RC フィルタを入れて、遅延させるのはどうか?LVC は高速で 最小 1ns とかで動作する。シュミットトリガ入力は RC と組み合わせて発振器を作ったりするのに都合が良い。
多分こちらの方が良さそう。

    schmitt_vco.png
    そういえば、シュミットトリガ入力での RC 発振器は VCO にも応用できるのであった。

    他には、パルス幅変調。タイマ IC 555 の応用にあるあれである。



SN74LVC1G14 について検討

SN74LVC1G14 は、1回路のシュミットトリガ・インバータである。aliexpress なんかで格安に買える。

schmit-osc.png
(ここから拝借)

RC 発振器を作ると、入力がきれいな三角波になる。コンデンサの電圧がリニアに上がっていくが スレッショルド電圧に達した途端に反転。今度はリニアに下がる。下のスレッショルド電圧に達したら、また反転。
上下のスレッショルド電圧間を行ったり来たりするのである。

T = RC となっているが、チップによって 多分係数が変わる。また、周波数が高いと 他の要素が効いてくるので、計算通りにはいかないと思う。仮に 係数=1 として概算してみる。

R=1k , C=1nF (1000p) で 1MHz だから R=200 , C=50pF で 100MHz (1/2 T=5ns)。これぐらいになると、チップ 自体の遅延が 1.5 〜 4.6ns なので、正確な計算は無理である。

    ちょっと検討:
    FPGA で受けた入力を 外部に出力し、RC フィルタを通して インバーターの IN に接続。インバーターの OUT をまた FPGA に戻す回路を考える。戻した信号を遅延入力とする。

    FPGA でループバックさせれば、発振するはずだ。この時の周期を T とする。

    ずっと1だったところに 0パルスが来たとする。posedge で 遅延入力を取り込むと 短パルスは 1 として読めて、長パルスは 0 として読める。どちらになるかの境目は 1/2 T ... ではない。

    上下のスレッショルド電圧を VH,VL とする。VH → VL の時間が 1/2 T である。この場合の時間は、VCC → VL 。VH - VL = 0.7V ぐらい。3.3V → VL(1.3V) = 2V だとすると 3 倍ぐらいで 3/2T ぐらい。これより短いと そもそも 0 にすらならない。
    さて、ずっと1だった状態に戻すには? 0 で放電した分を充電するわけで、パルスと同じ時間 1 にしておけば良い。

      遅延させるだけなら、RC LPF だけで良いのでは? 余計なものが入らなければ、時間をより正確に出せる。
      シュミットトリガ入力はあった方が良さそう。例えば MachXO2 だと シュミットトリガ入力がある。(ヒステリシス 0.45V @3.3V) 。-- iCE40 にもあった。(ヒステリシス 0.2V @3.3V)。

    さて、短パルスは、FPGA の応答周波数でだいたい決まってくる。長パルスはどれだけなのか?実装にも依存するし、目安はあっても、分からないのである。

    ならば、キャリブレーション手段を提供すれば良い。0/1 が間違っても、パルスを受け取りそこなうことはない。方法はまだ決めないが、あまり難しいことではない。幸いなことに、長パルスは、どれだけ長くしても問題ない。キャリブレーション前でも確実に通信する手段は確保できているのだ。

かつて、ピーヒャラヒャラという出力で、テープにデータを記録した時代があったが、それを 100MHz のレベルでやろうと言うのである。もし出来ると面白い。



INPUT DATA
___________ ____ __________ ______________
|____| | |____|____|____| | | |
@ @

DELAYED DATA
_______________________ ___________________ ___
|_______________|

もう少し、イメージを具体化。入力データと遅延データ。論理が逆だとかというのは気にしない。だいたい入力データも逆にするかも知れないのである。

入力データをクロックとして扱い posedge -- @ の位置で 受信回路を動作させる。動作させるタイミングはそこだけである。そのときに遅延データが1なら短パルス、0 なら長パルス。パルスを出したら同じ時間以上 1 にする。目的は、パルスの 0 で放電した分の充電。同じ時間だと状態が完全に元に戻らない可能性があって悩ましい。+1 とすれば良いのだが無駄が多い。多分短パルスが連続した場合のみ遅延が短くなっていくという問題になるはず。

次の問題は、初期状態にする方法。SPI などでは、CS 信号があるので、それでデータの先頭が判断できる。1 本でなんとかしようとしているので、その方法は採用しない。かと言って、posedge でしか動かないわけだからどうしたものか? やはり正常では出てこないパターンを作るしかないか。NRZI --- 1 が 7 つ以上は連続しないというやつ。もし 1 が 7 つ連続して来たら、初期状態にする。短パルスが連続して来ないのだから、充電のための期間の問題も解決。

次、実際のクロックをいくつにするか。NZRI も含めて、0 か 1 かを生成する部分は、100MHz 目標としよう。実際のパターンを生成する部分は、2相クロックを使うことにしよう。出てくる短パルスは、5ns 。長パルスは、最短 2 倍で 10ns 。多分正確に この中間値で遅延させるのは無理。だいたい、FPGA からピンに出力し、それを FPGA に戻すだけである程度遅延がある。インバータを通すだけで、10ns 超えてしまうのではないか?

    lattice のデバイスでは、/* synthesis syn_keep=1 */ というのを使って LUT を 1段2段入れていくということが出来るようだ。それで望む時間の遅延が得られるかどうかは分からないがメモ。



電圧レベル変換について(まとめ)

いきなりまとめだが、いくつか前に追記で書いたことをまとめておく。

SPI だが、30Mbps 程度が精いっぱいと書いた。実際その通りらしいのだが、できるだけ高速に 通信したい具体的な用途がある。JTAG である。しかも JTAG アダプタは 相手によっていろいろな 電圧に対応しなければならない。それについての考察。

ホスト側は、Raspi のような SBC を想定するが、FTDI の FT2232H, FT233H など実際に高速に I/O できる USB アダプタがある。いずれにしても 3.3V 固定の I/O 電圧を 電圧レベル変換したうえで高速にという要求がある。

level_shifter.png
結論だが、74LVC シリーズの 07, 125 を使うこういう回路が良さそうだ。1G07 などと書いてあるが 別に 6 回路入りの 74LVC07, 4 回路入りの 74LVC125 でもかまわない。ただし、OUTPUT 1段目 の 07 の電源は HOST 側の 3.3V で、他はターゲット側。

74LVC シリーズは、1.65V 〜 5.5V の電源電圧で使える。ターゲットから電源を貰って動作させれば、入り口出口は、実に普通である。電圧レベル変換は、オープンドレイン・バッファの 07 が担う。INPUT については、オープンドレインなので 3.3V でプルアップすれば、ターゲットの電圧とは関係なしに、 H レベルが 3.3V になる。OUTPUT の 125 は、入力に 5.5V までかけられるのだが、H レベル は、VCC x 0.7 ぐらい。3.3V I/O では H レベルを超えられないケースがあり、やはり、オープンドレインでの電圧変換が必要になる。

問題はプルアップ抵抗の値。小さいと消費電力が増えてしまう。大きいと信号の立ち上がりが遅くなってしまう。大きいと遅くなるのは、CMOS の入力がコンデンサとして働くためである。5pF だと考えると 1KΩのプルアップで LPF を構成し、5nS ほど立ち上がりが遅れる計算になる。

なお、TRST などの出力は、07 の オープンドレイン をそのまま出力してかまわない。

ちなみに、lattice XO2 または iCE40 をコンフィグする場合いかのピンが関係する

TXD (O) ADBUS0 - TCK XO2 iCE40 (I)
RXD (I) ADBUS1 - TDI XO2 iCE40 (I)
RTS (O) ADBUS2 - TDO XO2 iCE40 (O)
CTS (I) ADBUS3 - TMS XO2 (I)
DTR (O) ADBUS4 - ispEN iCE40 (I)
DSR (I) ADBUS5
DCD (I) ADBUS6 - CDONE
RI (I) ADBUS7 - CRESRT_B iCE40 (I)

ターゲット側電源 125 x 3, 07 x 1
ホスト側 3.3V 電源 07 x 5

こういうバランスなので、ターゲット側 07 は、1G07 が良いかも知れない。

追記:
07 + プルアップ + 125 というのは、部品点数が多い。2電源のレベルシフタ IC を使うとこういう苦労は必要ないようだ。LVC2T45 (2回路), LVC8T245 (8回路) がある、他に AVC4T245 (4回路) もあるが、3.6V まで (4.6V トレラント) 。

posted by すz at 21:02| Comment(0) | TrackBack(0) | MachXO2
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/182807461
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック