« 2016年5月 | トップページ | 2016年7月 »

2016.06.30

HyperFFT回路を実機で動かしてみて心境の変化

シミュレーションで正しいとわかったので、ハードウェアFFTを実際のFPGAにインプリメントしてみました。

FPGAにロジアナコアを入れて、JTAGで見た実機の信号と、シミュレーション時のパターンが完全に一致しました!

Icchi


これはうまくいっているかも・・と喜んだのも束の間。

同じデータを変換しても、たまにビットが変わることが確認されました。

どうやら、スピードグレード-1のFPGAをスピードグレード-3として論理合成していたので、実際にはスピードが間に合っていなかったと思い、検証を続けていたのですが、どうやら原因はそれだけではないことがわかってきました。

FFTエンジンを回すと、Linuxがいきなりカーネルパニックしたり。まだメインメモリにはアクセスしていないから、Linuxは関係ないはずなのに・・

どうやら、原因がわかってきました。

この回路は、Radix-8のバタフライ演算を1クロックで計算するため、216個のDSP48Eが400MHzで動いています。すると消費電力がハンパない。

BRAM216個だったら全然驚かないのですが、DSP48Eが216個はかなりきます。

SLICEやBRAMとは比べ物にならないほど電流を食うのかもしれません。

発熱でさらに電力が増えると、電源電圧が低下する。

どうやらこのFFT回路は、今までにCosmo-Zで作ったどんなデザインより消費電力が多いようです。狭い基板に詰め込みすぎて、電源が足りなくなって全力が出せない。まるでU.S.S.ディファイアントのような基板です。

クロック400MHzで動かして51.2μ秒で計算するというのはあきらめました。

ハイエンドなFPGAには乗算器いっぱい(数千個とか)あるから、これを有効活用するためにDSP48Eを全力でぶんまわす数値計算アプリを作ろう!という考えは正しくないと思えてきました。

自分の中で何かが変わりました。GPUとFPGAのどっちが速いかなんてことを考えるのはあまり意味がありません。結局は電力です。

クロック上げてDSPいっぱい動かして最高速度を極めるよりも、クロック下げて広い面積で処理したほうが、同じ性能でもトータルの消費電力をされられるかもしれません。

これからはエコ設計でいこう。

ワットあたりの処理能力というのを追究してみたいと思う次第です。

結局、クロック250MHzで動かして、ちょっと遅めの82μ秒で計算することにしたら、電源も発熱もかなり落ち着いて安定しました。

| | コメント (0)

2016.06.29

Hyper FFT回路が論理的に正しいことを確認

Radix-8、周波数間引き、改良型アルゴリズムの「Hyper FFT回路」がようやくZYNQの7Z030に入りそうという見通しが立ってきました。

このFFT回路は、216個の乗算器がクロック400MHzで一斉に動作し、Radix-8のバタフライ演算を1クロックで処理します。32768ポイントのFFTが51μ秒しかかからないという恐ろしい速度のFFT回路です。

しかし、クロック400MHzだといろいろな箇所で論理合成が通りません。タイミングエラーが出てしまいます。

わかてきたことは、Block RAMって意外と遅いってことです。普通にXILINXのCoreGeneratorでBRAMを作ると、400MHzで通りません。XILINXのデータシートではBRAMは400MHzで動くはずなのに、困ってしまいますよね。

どうすればよいかというと、CoreGenのオプションで、下のところをチェックを入れればいいようです。

Bram_option_2

BRAMのプリミティブの中にある出力レジスタを有効にしたり、ユーザ回路部分にSLICEを使ってレジスタを入れてくれるようです。今まで、レイテンシが増えるだけじゃん・・って思っていたのですが、なんと、これを入れるとタイミングエラーが解消しました。

レイテンシと引き換えに周波数を上げられるのですね。

あと、256→32にビット幅を変換するBRAMを作ったりすると、ユーザロジックが使われるので遅くなる場合があるようです。その場合もこのオプションで改善できました。

これをZYNQに実装して、パイプラインを入れまくってクリティカルパスを緩くしたところ、なんとかタイミングエラーが出ないようになりました。クロック-クロック間が2.5nsって思った以上に厳しいですね。

Fft_timing_met

さて、論理的な検証のほうですが、シミュレーション上は51μ秒で計算できるのが確かめられました。

Fft_51us_sim_2 

しかし、計算結果が正しくありません。

細かいところを波形を見ていてもわかりにくいので、textioを使って、結果のテキストに書き出すようにしてみました。

やりかたは、まずtextioを読み込みます。

use ieee.std_logic_textio.all;
use std.textio.all;

それから、適当なところでfile型のオブジェクトと、line型の変数を宣言します。

file wf_x : text open write_mode is "read_x.txt"; --出力ファイル
variable wl : line;

ファイルに書き込むには、まずline変数(以下の例ではwl)に文字列をセットして、writelineでファイルに書き出す、という形になります。

write(wl,"x read data",left);
writeline(wf_x,wl); --行をファイルに書き出し
write(wl,"stage raddr x0       x1       x2       x3       x4       x5       x6       x7",left);
writeline(wf_x,wl); --行をファイルに書き出し

このとき、writeという関数を使うと、line変数に""で囲った文字列や、VHDL上の信号、変数などを書き出すことができます。writeは万能です。

16進数で書き出したいときにはhwriteという関数を使います。

if(x_valid = '1') then
  write(wl,f_tmp(14 downto 12),left,6);
  hwrite(wl,f_tmp(11 downto 0),left,6);
  hwrite(wl,x0_o,left,9);
  hwrite(wl,x1_o,left,9);
  hwrite(wl,x2_o,left,9);
  hwrite(wl,x3_o,left,9);
  hwrite(wl,x4_o,left,9);
  hwrite(wl,x5_o,left,9);
  hwrite(wl,x6_o,left,9);
  hwrite(wl,x7_o,left,9);
  writeline(wf_x,wl); --行をファイルに書き出し
end if;

上のような書き方をした場合、アドレスと、x0_o~x7_oまでの信号の値が書き出されます。

x read data
stage raddr x0       x1       x2       x3       x4       x5       x6       x7
000   000   00000000 00001000 00002000 00003000 00004000 00005000 00006000 00007000 
000   001   00000001 00001001 00002001 00003001 00004001 00005001 00006001 00007001 

こうして生成されたファイルと波形を見ると、一致しているのがわかります。

Textio

テキスト出力は便利ですので、長いデータのデバッグが必要になったらぜひ試してみてください。

C言語のソフトで作った計算途中経過と、シミュレータが吐き出した結果を見比べてみて、いろいろ直しました。

まだシミュレーションだけど、HyperFFT回路動きました!計算結果も正しいようです。

普通にFFT回路をFPGAに作ると、アドレスの計算とか、ステージ(ループ)間での無駄な待ち時間が生じてしまうのですが、私のアルゴリズムはそういう無駄が一切なく、20480クロックで結果が出ます。

| | コメント (0)

2016.06.28

Cosmo-ZのVivado化(3)

Cosmo-ZのデザインのVivado化を進めています。

Vivadoがわからない私に代わって、学生のアルバイトさんが進めています。

ついに、Vivadoで作ったデザインでCosmo-Zが動いたようです。いままで動かなかった原因は、リセットのピンのつながりがISEとVivadoで違っていたからのです。

Cosmoz_reset

CPUはIPインテグレータになったので、その周りのモジュールのIP化を始めました。

まずはADCデコードモジュールです。最大750MHzでやってくるLVDS信号を、位相を調整しながら受信するモジュールです。

Adc_ip

おおっ!なんかパラメータでチャネル数を変えられるようになっているぞ!

Adc_generic

だんだんわかってきました。

ISEのときにはパッケージで以下のような型を定義して、ADCのチャネル数×ビット数の二次元のバスを作っていたけれども、VivadoのIPにするにあたってはこれはできないようです。

type t_adcdata_array is array((MAX_ADCCH - 1) downto 0) of std_logic_vector(ADC_BITS-1 downto 0);

なので、ADCチャネル数を変えるとバス幅が変わる、太いのバスを作って何とかするようです。

| | コメント (0)

2016.06.22

Cosmo-ZデザインのVivado化(2)

Cosmo-ZデザインをVivadoに移行して、動いたようです。

先週試したときに動かなかった原因は、リセットやクロックの接続、ペリフェラルのアドレス、などがだったようでした。

○○のモジュールに行くクロックは△△で、というのを直したところ、動くようになったとこのとです。

Cszvivado

リセット信号は、ISEの時にはaxis_resetという信号だったのが、Vivadoではperipheral_aresetn[0:0]になったり、ISEのときにはCPUのコアから出る信号がprocessing_system7_0_…という冗長な名前だったのが、Vivadoではスッキリしています。

正確には測っていませんが、論理合成時間も半分くらいに減ったような気がします。

リソースの使用率

8chのCosmo-ZをVivadoで論理合成したときは、

Cszvivado3

Cszvivado4

でした。

ISEでは、

Number of Slice Registers   16,085/157,200   10%
Number of Slice LUTs   16,083/78,600  20%
Number of occupied Slices  6,985/19,650  35%
Number of RAMB36E1/FIFO36E1s  58/265  21%
Number of RAMB18E1/FIFO18E1s 16/530  3%
Number of DSP48E1s  72/400 18%

だったので、リソース利用量が格段に減っています。特にDSP48が32個も減っているのが気になります。

これで良いのかどうか不安になります。(何か大事なものが削除されていないだろうか、という意味)

困ったことがもう1つあって、PHYにリセット信号を作っていたタイマーが動かなくなったことでした。

こういう回路でPHYチップに短いリセット信号を送っているのですが、Vivadoに移行したらうまく動かなかったとのことでした。

    process(clk100m) begin
        if(clk100m'event and clk100m = '1') then
            if(phy_timer(phy_timer'left) = '0') then
                phy_timer <= phy_timer + 1;
            end if;
            if(phy_timer = 0) then
                phy_resetn <= '0';
            elsif(phy_timer(phy_timer'left) = '1') then
                phy_resetn <= '1';
            end if;     
        end if;
    end process;
    phy_resetn_op <= phy_resetn;

このタイマーで使っている信号phy_timerを宣言しているところの

signal phy_timer  : std_logic_vector(19 downto 0);
signal phy_resetn : std_logic;

にしたら動くようになったとのことです。

signal phy_timer  : std_logic_vector(19 downto 0) := (others => '0');
signal phy_resetn : std_logic;

どうやら信号の初期値が0になっていないようだとのことなのですが、VHDLの信号の宣言に初期値を書いてはいけないと昔、教わったのですが、今は書かなければならないのでしょうか。

| | コメント (0)

2016.06.21

FPGAで作るHyperFFTのアルゴリズム

FPGAでハードウェアFFTを行う回路を作りたいわけなのですが、事情により、0.8ms以内に32768ポイントのFFTを行わなければなりません。

32768ポイントのFFTは、245760回のバタフライ演算が必要ですが、クロック400MHzで1クロック=1演算として動かしたとしても614μ秒かかってしまいます。実際にはメモリの読み出しと書き込みが入るので、1クロックでメモリに読んだり書いたりした場合、2.4msかかってしまうことが予想されます。

普通にFFTをしていては絶対に間に合わないわけなのです。

FFTの計算上のボトルネックは何かを考えてみましょう。

よくある通常のFFT(時間軸間引き、Radix-2のクリーチューキー型)のアルゴリズムを考えてみます。

Fft1_2

この例では16ポイントのFFTなので、ステージは4まであります。

  • 最初のステージ
    • 隣のデータとバタフライ演算
    • 1回の繰り返しを8回繰り返す
  • ステージ2
    • 2つ隣のデータとバタフライ演算
    • 2回の繰り返しを4回繰り返す
  • ステージ3
    • 4つ隣のデータとバタフライ演算
    • 4回の繰り返しを2回繰り返す
  • ステージ4
    • 8つ隣のデータとバタフライ演算
    • 8回の繰り返しを1回繰り返す

このようになります。

このアルゴリズムの欠点は2個あって、計測に応用するのであれば入力データは時系列でならんでいるから、ビットリバースを行うと時間がかかってしまいます。

また、大きなサイズのFFTでは、後ろのステージにいくほど計算すべきデータのアドレスが離れてしまうので、一度に読み出せなくなります。DDRメモリの読み出しなどでメモリの読み出し時間が長くなってしまいます。

読み出すべきアドレスがバラバラに変わるので、メモリのバス幅を広くしようとしても、複数のデータを同時に読み出すことができません。

メモリの利用効率が悪いので遅くなります。

最初の問題は、私が考えた改良型FFTのアルゴリズムを使うと、解決できます。

データの流れはこのようになるので、

Fft2

すべてのステージで

  • 隣のデータとバタフライ演算をする
  • N/2離れたアドレスに書き込み

という、アドレスの規則性が出てきます。

常に隣合うデータを読み込んで計算すればよいので、バタフライ演算回路とメモリの関係は下の図のようになります。

Fft3

J=A*W+B、K=A*W-B

というバタフライ演算を行う場合、演算結果のJとKを2つのブロックRAMに分けてかき、ブロックRAMから次のAとBを読み出す際には2倍のバス幅で読み出すことができます。

このため、メモリの利用効率が良くなり、バタフライ演算器を止めることなく回すことができます。

一方、計測データなど、入力データが時系列で並んでいる場合には、周波数間引きというアルゴリズムを使うと良いでしょう。

周波数間引きのアルゴリズムでは、入力は順番に並んでいて、結果がビットリバースになります。

Fft4

周波数間引きの場合は、バタフライ演算の式は

J=A+B

K=(A-B)*W

となります。

上で紹介したアルゴリズムはFFTのための演算回数を減らすことはありませんでした。そのため、32768ポイントのFFTでは、依然として245760回のバタフライ演算が必要です。

この演算回数を劇的に減らすのがRadix-4やRadix-8という計算手法です。

普通のアルゴリズムで8ポイントのFFTをすると、2つのデータを12回のバタフライ演算で処理してやる必要がありました。

バタフライ演算は入力が決まってしまえば出力は一意に決まるので、この計算を8入力8出力の関数として考えることができます。

つまり、

Fft5

ということです。

中間の結果をメモリにストア/ロードしなくてよいので、速くなります。

Radix2の場合のバタフライ演算量は 245760回で、メモリの読み書きが491520回必要だったので、400MHzでメモリを読み書きした場合は1.2msかかりましたが、

Radix8にすると、、バタフライ演算量は32768/8×5= 20480となって、メモリの読み書きが20480回になります。400MHzで動かし、1クロックで8個分のデータを一気に読みだせば、51usで計算できることになります。

なんと、24倍に高速化できる計算になります。

ただし、この高速化の恩恵を受けるには、8個分のデータを1クロックでメモリから取ってきたり、1クロックで書き込まなければならないので、通常のFFTのアルゴリズムではできません。私の考えた改良型FFTでなければ、メモリが詰まってしまうことになるでしょう。

やりたいことは、

  • Radix-8で高速化し
  • 改良型FFTで、メモリのボトルネックを解消し、
  • 周波数間引きで、計測データを時間ロスせずに連続して変換する

ということです。

32768ポイントのFFTをわずか51μ秒で実行する超高速FFT。

はたして、できるでしょうか?

| | コメント (0)

2016.06.20

XILINXのAXI Stream複素数乗算回路

FPGAで高速フーリエ変換回路を作りたいと思い、XILINXのCoreGeneratorの中にある複素数乗算回路を試しています。

Cmult0

CoreGenのMultipliersの中にある、5.0のAXI4 Streamのものです。

実数部と虚数部はデフォルトのまま、ともに16bitにします。

Cmult1

出力の幅はフォルトでは33になって、実数虚数合わせてなぜか80bitになるようです。

Cmult2

ここでよくわからないのが、Latencyの設定です。AutomaticにするとLatency 6になりますが、Manualにすると0~6まで変えることができます。

数の表現

FFTなどで使うような-1~+1までの数を表現したい場合、16bitの固定小数点では下記のように符号1ビットで、有効数字15bitで表します。

Cmult9


この表現だと、+1は0x7fff、-1は0x8001、+0.5は0x3fff、0は0x0000となります。

このような数を2個、16bit & 16bitの組にして、複素数乗算器に入れると、80bitの信号が出てきますが、[70:55]と[30:15]を切り出すと、元のとおり16bit & 16bitの複素数の乗算結果が得られます。

Cmult10

パイプライン化の検証

Latency 0にしてシミュレーションしてみたところ、入力を与えるのと同時に結果が出てきました。

Cmult3

Latency 1にすると、入力が与えられた次のクロックで出てきます。

Cmult4

Latency 2すると、入力が与えられた次の次のクロックで出てきます。

Cmult5

気になるのは、このコアの中身はパイプライン化されているかどうかです。Latencyが大きいと、もしかすると、1つの乗算器を何回も使いまわすようなことをしているかもしれません。

乗算器の使いまわしをしていてパイプライン化されていないとすると、連続してデータを与えることができないので、困ってしまいます。シミュレーションで試したところ、Automaticに設定してレイテンシ6の回路を作り、1クロックごとに異なるデータを与えても問題ないようでした(下の図)。

Cmult7

つまり、中身はパイプライン化されています。

リソースの使用量

リソースはどのくらい使っているのかというと、ZYNQの030に実装してみたところ、

Cmult6

でした。なぜDSP48Eの使用数が3個なのかはわかりません。複素数の乗算なら4回の掛け算だと思うのですが、謎です。レイテンシを変えていっても変化はありませんでした。

気になるリソースの使用率は、

Latency 1の場合

Number of Slice Registers 1
Number of occupied Slices 1
Number of DSP48E1s        3

Latency 2の場合

Number of Slice Registers 2
Number of occupied Slices 2
Number of DSP48E1s        3

Latency 3の場合

Number of Slice Registers 2
Number of occupied Slices 2
Number of DSP48E1s        3

Latency Auto(6の場合)

Number of Slice Registers 66?
Number of occupied Slices 66?
Number of DSP48E1s        3

と、ほぼDSP48のみだけで動いているようなのですが、レイテンシを増やしていくとSLICEも使うようになります。

速度の見積もり

どのくらいの速度で動くかというと、Latency2,3の場合CLK 400MHzにするとタイミングエラーが出ました。Latency 1の場合はタイミングエラーが出ないのですが、

Latency 1にして、ユーザロジックで入力と出力にレジスタを入れたところ、

Cmult8

のようになったので、おそらく解析できていないのだと思います。

コアの中がどういう回路なのかはわかりませんが、上のタイミングエラーのレポートを見る限り、fanoutが大きい気がするので、Latencyをautoにしないと最高速度での動作はできないのかもしれません。

ちなみに、Latency=Auto(6)にしたところ、667MHzでもタイミングエラーはでませんでした。

まとめ

  • XILINXのAXI Stream複素数乗算器は、ちゃんと動く
  • レイテンシはAuto (=6)のままにしないと、400MHzの動作でもタイミングエラーが出る
  • 虚部・実部を16bit & 16bitで表現した場合、結果の[70:55]と[30:15]を切り出せばよい

| | コメント (0)

2016.06.18

MCAでK40の効果を見てみる

Cosmo-Zにプラスチックシンチレータとフォトマルをつなぎ、この写真のような感じで、測りました。

片方のシンチレータの真横に塩化カリウム(40Kの放射線源として)を置き、もう一つのシンチレータは少し離しておきました。

Mca_3

このような配置で、K40ありと、K40なし、でそれぞれ10時間測ってみました。

Mca0618nok

Cosmo-ZのMCAで取ったデータをCSVでエクスポートできるようにしたので、EXCELでグラフにできます。

まず、塩化カリウムありの場合を見てみます。CH4が塩化カリウムの試薬に近い方です。

Withk40_2

次は塩化カリウムなしの場合です。2つのグラフがほとんど重なっています。

Nok40

高さ250あたりのところに違いがあるので、差を取ってみます。

Diffk40

塩化カリウムの試薬に近いほうのCH4では、試薬の有無によって大きな差が出ました。横軸の200あたりにK40の影響と思われるピークが見えていますが、ピークがはっきりしないですね。

プラスチックシンチレータなので、この程度かもしれません。

ちなみに、2インチのNaIを某社に発注中です。

| | コメント (0)

2016.06.17

Kintex-7のPCI Expressボードを早く仕上げなければ・・

長いこと開発が停滞しているKintex-7のPCI Expressボードですが、そろそろ完成させなければならなくなってきました。

Np1083

PCI Express Gen2 x1に光のモジュールが2機搭載されているというこのボード。

今週、アルバイトさんが部品の配置を直してくれました。

Kintex-7はバイパスコンデンサが内蔵されているから、小さなコンデンサをFPGAの裏に貼りつける必要はないので、比較的楽にできるはず。

本気でやればあと5時間くらいで配線が引けると思うので、来週から本気出します!

| | コメント (0)

2016.06.16

MITOUJTAGのBLOGANAをVerilogで使う

MITOUJTAGにはBLOGANA(ブロガナ)という機能があります。

BLOGANAは、ChipScopeやSignalTapと同様、FPGAの中のBRAMに波形を溜め込んで、「JTAGで吸い出して見る」という、内蔵型のJTAGロジックアナライザです。

BLOGANAを使うには、コアを埋め込みたいモジュールに

component blogana2 is
  generic(
    BIT_WIDTH     : integer := 72; --サンプリングする信号のBIT幅を指定(1bit以上、252bit以下で選択)
    SAMPLE_LENGTH : integer := 1024--サンプリングの長さ(word)を指定(1word以上、8192word位下で選択)
    );
  Port (    CLK         : in std_logic;
            TRIG        : in std_logic;
            USER_OP     : out std_logic_vector(19 downto 0);
            SAMPLE_EN   : in std_logic;
            DIN         : in std_logic_vector(255 downto 0); --BIT幅はgenericのBIT_WIDTHで指定
            SAMP_FREQ   : in integer range 0 to 2147483647; -- サンプリング周波数
            BUSY        : out std_logic                     -- 必ずどこかに出力すること
            );
end component;

というコンポーネントを宣言して、インスタンシエートします。

最近はISEでもVivadoでも、VerilogからVHDLのモジュールを呼び出すことはできるので、Verilogでも使えるはず・・と思っているのですが、私はVHDL派なのでVerilog対応はおざなりになっていたのですが、お客様からVerilogでも使用できないかという問合せがあったので、試してみました。

というか、インターンで来ている学生さんに試してもらいました。

結論からいうと、このままではダメでした。

という理由によるものでした。

GenericにあるBIT_WIDTHやSAMPLE_LENGTHはInteger型でも大丈夫なのですが、PortのところにあるSAMP_FREQがダメな原因でした。

どうすればよいかというと、SAMP_FREQをstd_logic_vectorに書き換える必要がありました。

うまく動くようになったLEDチカチカのソースを載せます。

module LED_Chika(xtalclk_ip, led_op, tmp);
input   xtalclk_ip;
output [7:0] led_op;
output tmp; wire [71:0] blogana_din;
wire   blogana_trig;
wire   blogana_busy;
wire [19:0] blogana_user;

//
wire   xtalclk;
reg  [7:0] led;
reg  [31:0] timer;
reg    count_en;
reg  [2:0] count; assign xtalclk = xtalclk_ip;
assign led_op = led;

blogana2 #(
   .BIT_WIDTH(72),
  //サンプリングする信号のBIT幅を指定(1bit以上、252bit以下で選択)
   .SAMPLE_LENGTH(1024)
//サンプリングの長さ(word)を指定(1word以上、8192word位下で選択)
   )
blogana
   (  .CLK(xtalclk),
   .TRIG(blogana_trig),
   .DIN(blogana_din),
   .USER_OP(blogana_user),
   .SAMPLE_EN(1'b1),
   .SAMP_FREQ(32'd480000),
   .BUSY(blogana_busy)
   );
always @(posedge xtalclk) begin
  if (timer == 5000000) begin //10Hz
   timer <= 32'h00000000;
   count_en <= 1'b1;
  end else begin
   timer <= timer + 1;
   count_en <= 1'b0;
  end
end
//counter ( output LED )
always @(count) begin
  case (count)
  3'b000: begin
   led <= 8'b00000001;
  end
  3'b001: begin
   led <= 8'b00000010;
  end
  3'b010: begin
   led <= 8'b00000100;
  end
  3'b011: begin
   led <= 8'b00001000;
  end
  3'b100: begin
   led <= 8'b00010000;
  end
  3'b101: begin
   led <= 8'b00100000;
  end
  3'b110: begin
   led <= 8'b01000000;
  end
  3'b111: begin
   led <= 8'b10000000;
  end
  default: begin
   led <= 8'b11111111;
  end
  endcase
end
always @(posedge xtalclk) begin
  if (count_en == 1'b1) begin
   count <= count + 1;
  end
end

assign blogana_trig = count_en ? 1'b1 : 1'b0;
assign blogana_din[2:0] = count;
assign blogana_din[10:3] = led;
assign blogana_din[42:11] = timer;
assign blogana_din[43] = count_en;

assign  tmp = blogana_busy;

endmodule

これでVerilogからblogana2というモジュールをインスタンシエートする形になりますが、ISEのプロジェクトマネージャでは

Verilog_blogana

という期待通りの階層構造が表示され、blogana2.vhdが下位モジュールとして認識されるようです。

論理合成したら、出来上がったBitファイルを書き込みます。

そして、ロジアナ画面を開き、BLOGANAボタンを押すと、ダイアログが開き、

Verilog_blogana2

BLOGANAを組み込んだソースファイルを指示されます。このダイアログに書かれているサンプリング周波数、ビット幅、データ長は、GenreicとPortで設定したSAMP_FREQ、BIT_WIDTH、SAMPLE_WIDTHです。

Verilogファイルを読むこむと、

assign blogana_din[*:*] = ○○○

で書いた行を自動的に解析して、信号に名前を付けてくれます。

Verilog_blogana3

バスはまとめてバスにしてくれて、名前まで付けてくれるので、意外と便利ですよ。

BLOGANAのソースファイルと、インスタンシエートするサンプルのVerilogファイルはこちらにアップロードしました。

https://www.tokudenkairo.co.jp/login2/getfile.php?target=blogana2_verilog

| | コメント (0)

2016.06.15

Cosmo-ZがハードウェアMCAになった

ZYNQ搭載のADCボード「Cosmo-Z」を32chのハードウェアMCA、つまり放射線計測器にする開発を進めています。

Mca_1

まず、MCAでスペクトラムを表示させて、任意の部分を拡大できるようにしました。Windows MDIアプリなので、波形と同時に表示させたり、スペクトラムの全体と、一部を拡大して、特定のチャネル(エネルギー)のカウント数を詳しく見たりするということもできるようになってきました。

シンチレータを2個用意して、TFAを調整してだいたいのゲインを合わせます。

そして、片方(CH4,黄色の線)のほうのシンチレータの横に塩化カリウムを置きます。中のカリウム40が1.3MeV程度のγ線を出してくれるので、少し差が出てきます。

Mca_3


わずか100秒程度でも、MCAに表示されたスペクトラムに差が出てきました。

Mca_2

| | コメント (0)

2016.06.14

Cosmo-ZデザインのVivado化

アルバイトの学生さんが、Cosmo-ZのデザインをVivado化することに挑戦してくれています。

ISEのデザインをVivadoに移行するわけなのですが、PSが出してくるAXI HPはAXI3の仕様になっていて、バーストサイズが16しかないと言っていました。

ISEのときにはEDKが自動的にAXI HP0ポートにInterconnectを入れてくれたけれども、Vivadoでは自分でInterconnectを明示的に入れなければならないということで、結構ハマっていたようです。

そして、無事に移行できたようなのですが、うまく起動しないとのこと。

実際に試してみると、起動時のinit.shの中で止まってしまいます。どうやらcosmoz.elfを起動した瞬間に止まってしまうようで、おそらくAXIバスにつながったGPIOを読みにいって、応答がなくて固まっているのかな・・という気がしました。

また、Vivadoのレポートを見ると、

Cosmozvivado

LUTの使用率が16%で、BRAMが21%となっています。

ISEで作ったときには、LUTは95%、BRAMは99%だったので、何かがごっそり抜けている感じがします。

来週中にはVivado化されたCosmo-Zが動くかな・・と期待しています。

| | コメント (0)

2016.06.13

ZynqBerryの新しいLinuxデザインが出ています

Raspberry Pi型のFPGAボード「ZynqBerry」に6月10日、ZynqBerryの新しいリファレンスデザインがリリースされました。

Zb_2

今回更新されたものは、ZynqでLinuxを動かすためのファイル一式。Debian 8.4のイメージと、FlashROMに書き込むデータ(boot.bin)と、SDカードに入れておくべきファイル類です。

http://www.trenz-electronic.de/download/d0/Trenz_Electronic/d1/TE0726/d2/Reference%20Designs/d3/Debian_8.4.html

Zb_debian

それから、そのboot.binを作るためのハードウェアデザインのソースも公開されるようになりました。

Zb_src

http://www.trenz-electronic.de/download/d0/Trenz_Electronic/d1/TE0726/d2/Reference%20Designs/d3/2015.4/d4/rpi_hw_ips.html

上記のページにある

TE0726-rpi_hw_ips-vivado_2015.4-build_34_20160602111427.zip
Size 14.45 MB / Modified 10.06.2016 - 06:21:33

をダウンロードすると、FPGAの内部構成が見られます。

Zb_vivado

どうやらカメラ入力と、HDMI出力、オーディオ出力などが入っているようです。

Linuxを起動してみると、以前のような文字化けはなくなっていました。また、HDMIをつなぐとTrenz社のロゴの画面が出ていました。

Zb_hdmi

この画面は実はSDRAMの内容を表示しているだけなので、メモリの0x1c000000番地に乱数を書いてやるとランダム模様に変わりました。

つまり、非常に単純なビットマップ出力グラフィックコントローラになっているようなので、そのうち誰かがドラバを作ってくれれば、Linuxの画面をHDMI出力に出すことができるようになるのではないかと思います。

→ZynqBerryの入手方法についてはこちら http://www.trenz.jp/products/te0726/

| | コメント (0)

2016.06.10

Cosmo-Zで32chのパルス波形計測が可能になった

ようやく、Cosmo-Zで32chのパルス波形の計測が可能になりました。(従来は8chまでだった・・)

「パルス波形計測モード」とは、放射線のように、たまにしか来ない信号を測るときに、信号がない期間も記録しておくと無駄なので、トリガが入った前後の波形だけを記録するというモードです。

テスト波形生成回路で、チャネルごとに高さの変わる波形を作り、信号のある時間だけ波形を取ってみると・・

Testwave_32ch

おおっ。全チャネル記録されていました。

このテスト波形は、毎秒180回くらいのレートで作り出しています。1つの波形の記録に800バイトくらい必要なので、1秒ごとに約4.6MBのデータが溜まっていきます。

宇宙線の検出なら十分に間に合うでしょう。

| | コメント (0)

2016.06.09

AXI HPポートのタイミングを緩和する

長い間悩んできたタイミングエラーがあります。

ZYNQのPS-PL間のインタフェースで起きているタイミングエラーなのですが、

Timerr_1

実は、Cosmo-Zでは多数のADCの信号を束ねるために、64bitのFIFOの後、8:1マルチプレクサを通じてAXI HPポートに送っています。

図にするとこんな感じです。

Timerr_3

見るだけでも気が遠くなりそうなロジックです。

エラーレポートを見ると、PSが出してくるaxi_hp0_WREADYから、FIFOのRD、そしてデータへと続くパスが250MHzのクロックで間に合わないということのようです。

Timerr_2

そこで、前から気になっていたオプションを試してみました。

EDK(古くてスマン)を開いて、AXI HP0の設定を開きます。

Timerr_4

その中にある、Use register slice on W channelの設定を、BYPASSからFULLY_REGISTEREDに変えます。

Timerr_5

これをすると、おそらく、AXI HP0のWチャネルにレジスタが挿入されて、タイミングが緩和されるかと思ったのですが・・

ビンゴでした!

Timerr_6

タイミングエラーが解決されて、無事綺麗になりました。

EDKの深いところにあるオプションとか、怖くてなかなか変えられませんが、今回はうまくいったようで良かったです。

| | コメント (0)

2016.06.08

Cosmo-Zの汎用パルス処理回路が完成

Cosmo-Zで、放射線計測用のTFA、CFD、Trapezoid Shaper、PeakHold、LinearGate、LLD/ULD、ゲート発生回路が動作するようになりました。

まずは、普通にオシロスコープモード。

Cszapp_1

アナログ入力の部分を指で触ったときの波形です。

手元にシンチレータ+フォトマルがない、という場合でもテストできるよう、FPGAにテスト波形生成回路が入っています。

テスト波形を出してみると、

Cszapp_2

ここで、左のツールボタンにある

Cszapp_3

を押すと、放射線信号処理回路の設定画面が開きます。

Cszapp_4

TFAと書かれた四角をクリックすると、TFA(Timing Filter Amplifier)の設定ボックスが開きます。τdは微分時定数、τpzはポールゼロ回路の時定数、τintは積分時定数、Gainは積分器のゲインです。

Cszapp_5

●BLR(Base Line Restorer)回路

BLRと書かれたボックスの下のチェックボックスをONにすると、ベースライン回復回路(Base Line Restorer)がONになります。BLRは負極性のパルスに対して動作するようになっていますが、「正パルス」と書かれたチェックボックスをONにすることで、正の極性のパルスにも対応できます。

●CFD(Constant Fraction Discrimininator)回路

CFDと書かれた四角をクリックすると、CFD(Constant Fraction Discriminator)の設定ボックスが開きます。CFDは一定の時間遅延させた信号を引くことで、正確なトリガタイミングを生成する回路です。
 τは遅延時間、Ratioは引き算する信号の比率です。特に変更する必要はないでしょう。

Cszapp_6

●Trapezoid Shaper回路

Trapezoidal Shaperと書かれた四角をクリックすると、台形波形整形回路の設定ができます。

Cszapp_7

kは整形後の台形波形の立ち上がり時間、lは台形の頂上の時間、Gainは整形回路のゲイン、τは入力波形の減衰の時定数です。デフォルトの値は、テスト波形に対して最適な値となるように設定さています。

Cszapp_8

●トリガ・ゲートジェネレータ

トリガ・ゲート・ジェネレータは、トリガが入ってから一定時間のゲート信号を生成します。

Cszapp_9

生成されたトリガ信号は、後段のピークホールド回路やリニアゲート回路のゲート信号として使用できます。トリガソースには、同じチャネルのCFD出力、LLD/ULD出力、外部入力が選択できます。

Cszapp_10_2

トリガは、遅延や幅を自由に設定できます。

Cszapp_11

このように、波形処理回路の各部をWindowsからコントロールできるようにしました。

| | コメント (0)

2016.06.07

Windowsのドライバを自動インストールする方法

お客様から「Pocket JTAG Cableのドライバがインストールできません」という問合せをいただくことがあります。

Pocket JTAG Cableのドライバをインストールする手順は、USBでつないで、Windowsが「不明なデバイスとして認識」したら、デバイスマネージャを開いてドライバの更新を押すというものなのですが、さすがに不親切だし、どうにかしたいと思っていました。

やりたいことは、

  • Windowsに不明なデバイス(自社製品)を自動的に探してほしい
  • デバイスが挿入される前にドライバをWindowsに教えたい

ということです。

今まではデバイスを挿入しないと、ドライバのインストールができなかったので、卵が先か鶏が先かで困っていたのです。

そこで、当社のアルバイトの学生さんにINFとかPNFとか、CATとか一通り説明して、「自動インストール」の方法を調べてもらいました。

DriverStoreというディレクトリにドライバが入っていて、そこに入っているドライバは新規デバイスであっても自動的に探してくれるようなので、そこにコピーしてレジストリを書き換えたら何とかなるのでは・・と気が付いたのですが、さらに調べて、dpinst.exeというツールを見つけてくれました。

要するにこういうことです。

① infとsys、catと同じ場所にDPinst.exeを置いて、実行することでDriverStoreにステージされる

② ステージされた後にUSBのデバイスを抜き差しすると、デバイスマネージャーにすぐに認識される

③ DPInstとおなじところにxmlを置くことでインストーラーの画面構成を少し編集できる

XMLはこのような感じで書きます。

<?xml version="1.0"?>
-<dpInst>
<forceIfDriverIsNotBetter/>
<suppressAddRemovePrograms/>
<enableNotListedLanguages/>
<!-- US -->

-<language code="0x0409">
<dpinstTitle>PocketJtag-cable Driver Installer</dpinstTitle>
<welcomeIntro>This wizard will help you install PocketJtag-cable Driver.</welcomeIntro>
<eula path="Eula/Eula_US.txt" type="txt"/>
</language>
<!-- JP -->

-<language code="0x0411">
<dpinstTitle>PocketJtag-cable Driver インストーラ</dpinstTitle>
<welcomeIntro>このウィザードでは、PocketJtag を動作させるために必要なソフトウェア ドライバをインストールします。</welcomeIntro>
<eula path="Eula/Eula_JP.txt" type="txt"/>
</language>
</dpInst>

/Eula/以下のtxtなどにソフトウェアが利用規約を書くと同意画面で文言を表示させることができるようです。

必要なければ、別に、XMLは書かなくても良いようです。

DPInstは32bit版と64bit版があるようなので、OSに合わせて使い分けなければなりません。

実際にやってみましょう。

Dpinst_1

このEXEをつっつきます。

Dpinst_2

おっ、ダイアログが開いた。

Dpinst_3

なるほど。使用許諾を出せるというわけですね。XMLを書かないと、この画面がスキップされます。

次へを押すと、

Dpinst_4

おおっ!

Dpinst_5

実際のUSBのデバイスをつながなくても、ドライバがインストールできたではないですか!!

こうやればよかったのか~



| | コメント (0)

2016.06.06

AD7960で作ったAD変換回路のノイズ特性

AD7960を使って18bitのA/D変換回路を作っています。

Np1084pcb

このボードは18bitのADC(AD7960)が8ch付いていて、フロントエンドはAD8253になっていて、ゲインがx1,x10,x100,x1000で可変であるというものです。

したがって、μVオーダーの微弱な信号から4V程度の信号までなんでも変換できてしまうというものです。

AD7960というのは、1ch入り5Mサンプリングの18bit ADCです。出力はシリアルで出てくるので、最高速度で動かした場合、ディジタル部は250MHz程度のクロックとなるのでLVDSの差動出力になっています。

Ad7960_0

こういうADCを使ったシステムを作るときに、キャプチャソフトまで作ると大変なのですが、先日のテクニックによって、ADCの出力値をFPGA内でデコードして、内蔵ロジアナでキャプチャしてExcelに落とせるようになりました。

入力をGNDに落としてADCの値を見てみます。

Ad7960_1

VREF=4.096Vなので、1LSB≒31μVとなります。

ヒストグラムにしてみると、

Ad7960_2

うーん。サンプル数が少ないので何ともいえませんが、目分量で±3LSB(≒100μV)程度揺らいでいるとみるべきでしょうか。

AD7960のデータシートによれば、この程度のゆらぎはあるようです。

Ad7960_3

データシートによれば、Transition Noiseは1.1LSBとなっています。どの部分が1.1LSBなのかはわかりませんが。

このADCのシステムでノイズを発生させているものは、

  • ADCそれ自身 (35μV)
  • 抵抗(1kΩ)の熱雑音。BW=10MHzとして。13μV。
  • フロントエンドOPアンプ。AD8253・・・10nV/√Hz。BW=10MHzとして、31μV。
  • ADCドライブ用OPアンプ。THS4130・・・1.3nV/√Hz。BW=10MHzとして、4μV。

これらの二乗の和の平方根を取ってみると、√(35^2+13^2+31^2+4^2)≒48。

ノイズは約48μVとなります。

ヒストグラムを見る限り、理論値の2倍程度出ていることになります。

このノイズはどこから来るのか、長いデバッグが始まりそうです。

| | コメント (0)

2016.06.03

ZynqBerryのチュートリアルが完成

インターンで来ている学生さんが、ZynqBerryのチュートリアルを完成させてくれました。

ZynqBerryのチュートリアルは↓こちらのページにあります。

http://www.trenz.jp/tutorial/zynqberry-tutorial/

Zb_tut

いちおう、このページを見れば一通りの開発ができると思います。

ポイントは、Vivadoのバージョンと、SDKのバージョンを合わせておくことです。(推奨は2015.4)。バージョンを合わせておくと、ハード・ソフト開発がうまく連携できますし、sdk_create_prebuilt_project_guimode.cmdを実行するだけでソフトウェアのプロジェクトが作成できます。

バージョンを合わせておくと、

  • sdk_create_prebuilt_project_guimode.cmdでSDKプロジェクトを自動生成
  • Boot.binの作成や、フラッシュROMの書き込みがCMDファイルでできる

といったメリットがあります。

バージョンが合っていなくてCMDファイルが使えなくても、このチュートリアルを読んでいただければ、開発はできると思います。

ここで作ったLEDチカチカは、AXI-GPIOから「周期」の信号を出して、その値を周期として自作のタイマを動かすことで、PLとPSが連携した可変周期LEDチカチカとなっています。Zb_tut2

TeraTermからキーボードで値を打ち込むと、その値でLEDがチカチカするという、ZYNQならではの複雑なLEDチカチカです。

Zb_tut3_2

ZYNQのPSとPLを使ったサンプル回路として見ていただければ幸いです。

| | コメント (0)

2016.06.02

FPGAでFFT回路を動かしてみた結果

実機でFFTを動かしてみると、同じデータを変換しても、たまにビットが変わる。タイミングが間に合っていないのかと思ったら、スピードグレード-1のFPGAをスピードグレード-3として論理合成していた。計算を間違えているのか、ロジアナがこけているのか。うむむ。

実機のFPGAでFFTを動かすと安定しない原因がわかったぞ。240個のDSP48Eが400MHzで動くと消費電力がハンパない。発熱でさらに電力が増える。今までに作ったどんなデザインより消費電力が多い。狭い基板に詰め込みすぎて全力が出せない。まるでUSSディファイアントのようだ。

最近のFPGAって乗算器いっぱいあるから、全力でぶんまわす数値計算アプリを作ろう!という考えは正しくないと思った。

今日、自分の中で何かが変わった。GPUとFPGAのどっちが速いかなんてことを考えるのはもうやめよう。きっと、巨大なFPGAで2000個くらいの乗算器を同時に回すとボードが耐えられない。

これからはエコ設計でいこう。クロック上げて最高速度で動かすよりも、クロック下げて広い面積で処理したほうが、同じ性能でもトータルの消費電力をされられるかもしれない。エコだよ、エコ。涼しい回路を作ろう。

| | コメント (0)

DACを作ったら発振した件

AD9717(125MHz,14bit,2ch)とOPアンプをいくつか使ってDACを作っています。

しかし、見事に発振してしまっています。

Scope_0

回路的にはこんな感じです。

Ad9717_2

AD9717は差動出力で電流出力タイプのDACなので、完全差動アンプのTHS4521を使ってシングルエンドの信号に直し、それをADA4899で増幅してSMAコネクタから出そうというものです。

しかし、見事に発振。

上のオシロの波形を見るとわかると思いますが、電圧が高くなってくると発振し、急激に電圧が変化するところでリンギングを生じています。

前者の発振・・つまり、電圧に依存する発振については差動増幅器からADA4899へとつながる部分の抵抗値を変えることで収まりました。

後者の発振、電圧の変化でリンギング、については、同軸ケーブルをつないだことによる容量性負荷の発振と思われます。

ケーブルへの出力段にADA4899に選んだことが間違いだったのか。

(使用した実績のあるTHS4041CDにしておけばよかった・・・)

超低ノイズで帯域が広いから選んだのですが、まさか、ここで発振するとは。

コンデンサを切って貼っての戦いが始まります。



| | コメント (0)

« 2016年5月 | トップページ | 2016年7月 »