2011年12月30日金曜日

FUNCTION GENERATORの作成 3

鋸波、三角波、矩形波も出力できるようになった。 これらはDDSのphase accumulatorの値や、sin tableへの入力アドレス、符号信号を利用して生成している。


FPGAのBRAMは本質的にDual Port Memoryであり、sin(x) tableのROMもDual Port ROMとして生成している。このDual Portの利点を活かして波形生成機能も2CH持つことにした。 それぞれのCHで生成波形の種別や周波数、初期位相、振幅(減衰量)を個別に設定できる。また、両CHの出力について乗算(DSB変調波形の生成)・加算が出来るようにした。

以下はCH1側にDDS1とDDS2の乗算結果を、CH2にDDS2の出力そのままを出している。



以下はDDS2で三角波、DDS1で正弦波を発生させ、両者を加算した波形をCH1に出している。


ここまでの機能のDDS部とUART I/FでSpartan3E 250E用にRTLを構築して合成したところ合成できた。


まだDAC I/F部は入っていないがここまでの機能であればSpartan3E 250Eに実装出来そうだ。

2011年12月25日日曜日

FUNCTION GENERATORの作成 2

一応、DDS部のRTL作成が終わり、シミュレーションで動作確認をしている。
以下はdds_coreをテストベンチに4つインスタンスして、1.0Hz(基本波), 1.001Hz, 1.01Hz, 1.1Hzを生成させてみている。 phase_accumulatorの小数部は12bitなので、基本波の1/1000程度の周波数までは生成できる。ただし、前回のブログに書いた通り小数の場合は誤差はあり、1mHzは実際は0.9765625mHzになる。 (上記の周波数はDACのサンプリングレートを1usecとした場合で表している。 最終的には変わるかもしれない。元々1Hzから10MHz程度の周波数を生成可能にしたいと考えていたので、1usecでは10MHzが生成できないため。 現状、1usecとしているのは開発に使用するSpartan3A StarterKitのDACのサンプリングレートが1usec位になるためだ。)

動作モードとしては単一周波数をずっと出し続けるモードの他にSweepモードも持たせようと考えている。Sweepの種別は周波数が倍々で増加するoctave モード、10倍づつ増加するdecade モード、そして設定されて増分づつ増加するstep linear モードの3種だ。

step linear mode


octave mode

2011年12月17日土曜日

FUNCTION GENERATORの作成 1

ファンクションジェネレータはケースに入れて末永く使える物にしたいと思っており、その為にはFPGAも評価ボードではなく専用の物が欲しくなる。が、あんまりお金もかけられないのでFPGA部についてはSDR-SDRAMC作成で使用したSpartan3EのボードかLattice XP2のボードを利用しようと考えている。 でも、それにインプリするのはまだ先の話だ。 Spartan3A StarterKitはDACも搭載されているので、これを使って開発を行う。 それで今は正弦波発生部(DDS)の検討を行っている。正弦波はsin(n)のテーブルをROMに持っておき、ROMのアドレスを0から順次与えてROMのリードデータをDACに出力する。

正弦波テーブルはROMなのでnは角度値そのものではなくテーブルの要素番号になる。つまり、1周期をN分割してテーブルに持つ訳であり、1アドレスは2π/Nの角度に相当する。ROMにアドレスnを入れて出力を得るということはsin(n・2π/N)の値を得ていることになり、nを0からN-1まで1づつ増加させて得られる正弦波を基本波とすると、nをm倍の速度で増加させれば(n += m)、m倍の周波数の波形が得られることになる。でもこれだと基本波の整数倍の周波数しか得られない。1.2倍とか2.5倍等小数倍の周波数を発生させたい場合は何らかの補間処理が必要になる。この補間方法として直線補間または4点のラグランジェ補間を考えていた。

ラグランジェ補間は上記のような演算を行う。割り算があるが分母の各項は何れも既知なので定数化できる。また、乗算等の演算量も多い。 以下はN=360でnを0.1刻みにした時の直線補間とラグランジェ補間の比較だ。 何bitのDACを使うかは未定だがとりあえず16bitDACを使うという想定で、正弦波の最大振幅は32767にしている。波形は両者差が無いように見える。

以下は理想値に対する誤差だ。

これを見ると直線補間の方は最大1.3 digit程度の誤差が発生するのに対してラグランジェ補間の方はほぼ0となっている。ところが、上記の計算では振幅の量子化(小数点以下の切り捨て)をしていなかった。量子化した場合は以下のようになった。

これをみると、ラグランジェ補間の方も最大1digitの誤差があり、直線補間と大差なさそうなので直線補間で行くことにした。 次に1周期の分割数Nは幾つがいいか?  小さいと直線補間での誤差が大きくなり、大きいとテーブルサイズが大きくなってしまう。 Nを上図の10倍の3600とし、DACのサンプリング周期を1usとした場合、目標仕様の下限周波数1Hzを作るためにはnは1us x 3600 = 0.0036刻みにしなければならない。 駆動周波数にもよるとは思うが(たぶん)float adderはlatencyが1以上かかるので、phase accumulator部は固定小数演算にしたい。その場合、固定小数の小数部が何ビットあれば0.0036を十分に近似できるだろうか? 整数部は分割数N、つまり3600が表現できる必要があるので12bit必要で、phase accumulatorが32bitの場合小数部は32-12=20bit、この20bitで0.0036を近似すると0.003599・・ (99.977[%])と%オーダーの誤差になる。 FPGAに入力される源振(水晶発振器)の周波数精度はppmオーダーなので、%オーダーではちょっと残念だ。 せめて整数Hz(1Hzの整数倍)は精度よく出したい。 そこで分割数Nは1000000(20bit)、小数部を12bitにしようと思う。 この場合、テーブルサイズがめちゃめちゃデカくなってしまう。正弦波は相似形な波形なので1/4象限のデータのみをテーブルにして他はそれを写像して作り出すことはできる。そうするとテーブルサイズは1/4の250000になる。振幅の最大値を32767にするのでデータのbit幅は15bit、したがってそのままでは250000 x 15 = 3750000、 3.5Mbitの容量のROMが必要になってしまうが、以下の方法で圧縮できるはずだ。 250000を例えば4要素毎の区間に分割し区間内では先頭のみ15bitデータ、他は前方の要素との差分とする。

sin関数は0の部分が最も変化率が大きいが、今検討している分割数の場合その部分の変化率(差分)は1以下なので差分は1bitで表すことができる。ということは4要素の場合15bit x 4 = 60bitが18bitと1/3に圧縮できる。要素数を増やせばさらに圧縮率は高くできる。また、この方式は直線補間をする上でも都合がいい。 直線補間は以下のような演算になるが、Δy10は差分値がそのまま使える。 Δx10は要素nとn+1の差なので1、(x-x0)はphase accumulatorの小数部になる。したがって、差分値が1か0かでy0に小数部を加算する・しないを行えば良い筈だが、テーブルのデータが既に15bitに量子化されていてかつ出力するDACも16bitだとすれば、小数部をそのまま加算する意味は無いので、実際は小数部を四捨五入して加算するようにする。

テーブル1要素のデータ構成、即ち、何要素でグルーピングするのがいいかについて検討する。
上記では4要素の図を示したが、実際は直線補間のためにもう1要素(例えばP0~P3とP4)必要になる。要素数に対する圧縮率とROM容量を計算すると以下のようになった。

要素数30位から飽和している感じで、要素数32の場合ROM容量はおよそ370Kbitだ。冒頭に書いたようにターゲットFPGAはSpartan3E(XC3S250E)またはLatticeのXP2(XP2-5)であり、これらのBlockRAMの容量は250Eが216K、XP2-5が166K、・・・・・うぅぅ、はいらねーーー、くそー もうひと工夫必要だ。
テーブルに書くデータをCプログラムを書いて生成してみた。右側8桁が差分情報だ。

ここで差分データからuniqなデータ数を数えてみたら734個だった。

そこで差分データのuniqなパターンに固有番号を付与してテーブルにはその番号を書くようにすれば、32bitのデータが(734個なので)10bitになる。したがってROM容量は(15bit+10bit) x 7813 word = 195.325KbitになるのでXC3S250Eにはギリギリ入りそうな感じだ。伸張処理では番号をビットデータに戻すためのテーブルが必要になるがこれは分散RAMで作るしか無いだろう。分散RAMは38Kbitあり、必要な容量は734x32bit = 23.488Kbitなので入るんじゃなかろうか?  厳しいかなー??? ・・・待てよ! MicroBoardを使う手があるぞ。あれならSpartan6 LX9でEBRは576Kbit, 分散RAMは90Kbitなので余裕のよっちゃんだ。おー、250EでダメだったらMicroBoardにしよっと。

2011年12月12日月曜日

next theme

毎回、毎回、同じようなのばっかりやってても進歩がないので、次のテーマはアナログっぽいのをやることにした。 具体的にはファンクションジェネレータを作ろうと思う。 以前から実験用に1台欲しかった。秋月などで完成品を売ってるが結構な値段するので、なかなか手が出ないし、頑張れば自作できそうな気もする。あくまでも自分で使うだけなのでそれなりに機能すれば良い。 今現在のざっくりとした構想としては、正弦波、矩形波、三角波等の他、任意波形の出力。 正弦波はDDSで生成する。任意波形はDRAMに波形データを書いておいてそれを再生する方式にする。周波数範囲としては1Hz ~ 10MHz位は欲しいなぁ~。 正弦波と他波形の加算・乗算などもできるとうれしいかも。 アナログは殆ど素人なので、最終的にどんなものが出来るかわからんがやってみよう。

2011年12月11日日曜日

2011年12月1日木曜日

(LP)DDR-SDRAMCの作成 3

内蔵CPUによるMemory R/Wは32bit単位でSingle Accessなので負荷としては軽い。 そこでいつものようにDRAMに画像データを置いてVGA I/Fに表示させた。これだとReadだけではあるがBurst Readが繰り返し発生する。 VGA I/FはSpartan3A Starter KitやDE0のように抵抗ラダー式にした。


画像サイズはXGA (1024x768)にした。 表示素材はNASAのImage Galleryから入手した。


表示のチラつきやノイズ等もなく綺麗に表示されている。

元々このSDRAMCではDRAMをSelfRefresh Modeにすることも出来るようにしていたが、もう少し進めてSelfRefresh時にDRAMへの供給Clockを止めたり、またSDRAMC停止時にはDeepPowerDown Modeにするようにした。 以下はSimulationで確認している様子。


SelfRefreshに入るところ


SelfRefreshから抜けるところ


停止(Deep Power Down)に入るところ


一応安定に動作できているので、いつも通りRTL一式を以下で公開した。
http://www.hi-ho.ne.jp/bravo-fpga/

自作CPUで遊ぶ 25

まだ制御ソフトが完成していないので今まではスピンドルを移動するために一々簡単なプログラムを書いて移動させていたのだが、非常に面倒なのでCNCペンダント的なものを作ることにした。 右側の縦に2つ並んでいるスイッチ...