TEC0117ボードを入荷しました
GOWINのGW1NR-9という8MByteのSDRAMを内蔵したFPGAボードがTrenzElectronic社から発売されています。
これを入荷しました!
箱の中身はこんな感じ。
下記のURLで販売しています。
https://www.trenz.jp/product/TEC0117-01
品切れの際には、次の入荷までしばらくお待ちいただくことになると思うので、お早めに!
GOWINのGW1NR-9という8MByteのSDRAMを内蔵したFPGAボードがTrenzElectronic社から発売されています。
これを入荷しました!
箱の中身はこんな感じ。
下記のURLで販売しています。
https://www.trenz.jp/product/TEC0117-01
品切れの際には、次の入荷までしばらくお待ちいただくことになると思うので、お早めに!
8ch 125MHz 14bit DACボードの動作テストをしています。
ねじ穴で内層が切れていたり、SPIのCLKのネットがつながっていなかったりということで多少のジャンパが飛ぶ結果となりました・・・
まぁ、急いで作った基板だし、一発ではうまく動きませんね。
軽微な修正でよかったです。
つるっつるの正弦波を出すことに成功。
DACボードから1MHzの正弦波を出してADCで受けたときの歪率は-80dB。10MHzでも-60dBくらいでした。
同軸ケーブルや容量負荷でも当然ながら発振しない。望んだとおりの性能が出たと言えます。
あとは顧客の要求仕様に合うようにOPアンプの帰還抵抗を調整して出力電圧の調整を行えば完成なのですが、±5V出すとか、結構厳しいかもしれません。
出力段には、「かわかわさん」に教えていただいたTHS3491を使ったほうがいいかなと思えてきました。
実装中の基板が次から次へと上がってきます。
あるお客様は25日締めなので、納品が1月25日を過ぎると翌月扱いになって入金が3月末になってしまうかもしれません。
(そもそも、25日締め翌月末払いだと26日から31日の間に相手方に届くと翌々月末支払いになって60日以上の支払サイトになる場合があるので、下請法のコンプライアンス的にどうなのかという問題はあります。
声を大にして言いますが、25日締め翌月末払いは下請法の支払遅延となる可能性をはらんだ条件なので、この世の中から消えてなくなったほうがよいです)
ただ、そんなことを言っても相手がわかってくれないと(もしくは、わかっていてそういう条件に設定しる場合も)揉めるだけなので、25日までに納品するのが吉です。しかも今月は25日が土曜日なので24日の金曜日には届いていないと面倒なことになりそうです。
そういうわけで、急いで製造していたのですが、何とか、今日基板が届きました。
今までP●.comで作っていた基板を国産メーカーに切り替えたので、ちょっと不安はあったのですが6台とも完璧に動作してくれました。P社で6層だと最速で急いでも受注日はカウントしないとか金フラッシュ+1日とかで1週間くらいはかかりますが、某国産メーカーは土曜日も営業してくれているので、本当に速く届きます。しかも安い。
それを信頼できる実装業者で特急実装し、本日届きました。
さあ、これを全力で検査するぞ!
6台のCosmo-Zの全48チャネルに1つずつ正弦波を入れていき、すべてのチャネルで波形が取れるかどうかを軽くテストしたところ、全く問題なしでした。
@100kHzでの歪率も-80db以下で、正弦波を正弦波として扱えています。
6台の検査が無事に終わりました。
すべてのチャネルは完璧に動作しました。
明日さらに正確に測定して、無事に出荷できそうです。
1月の14日ごろに実装に出していたCosmo-Kの基板が届きました。
Cosmo-Kシリーズには、SFP(10Gbps)×3個のCosmo-K-と、SFP×3個とユニバーサルエリアの付いたCosmo-K0と、QSFP(40Gbps)が1個のCosmo-K+がありますが、上の写真のように1枚の基板に面付して製造しています。そのため、K+とK-とK0の製造台数が変わると使われなかった基板が無駄になってしまいます。
K0はほとんど受注がないので無視していいのですが、K+はK-より少し少ないのがもったいなく感じるところです。
出来上がってきた基板にファームウェアを書き込んで、USB3.0のテストを行ったところ、IN/OUTともに300MByte/sec出ていて、かつ256Mバイトまでのメモリの検査を行って異常なしでした。
ひとまず安心です。
機能の設計の続きを行います。
AM 0:30
基板のパターンを8個コピペしただけだったのを、回路図を複製して部品番号を振りなおしネット名を付け替えます。この作業が一番大変でした。
AM 5:00
8ch分の回路が正しく出来上がります。
AM 5:58
このDACチップは250MHz 14bitのパラレルインタフェースなのでメザニンコネクタまで一対一で配線を引けます。
クロックは大事にしようとガードリングを付けたり別の層にしたら、SPIの配線が引きにくくなることに気が付いて、1時間の手戻りが発生です。
AM 8:01
家族の食事を作ったり、子供を学校に送り出したりして、仕事の再開です。
この基板は0.1mm/0.1mmのルールにしなくても0.125mmでいけるかと思ったり、6層にしなくても4層でいけると思い、デザインルールを緩くすることにしました。そのため、自分に無駄に厳しい労働を強いることになりました。
AM 10:12
アナログアンプに供給する±2.5Vの電源をチャネルごとに用意したり、電源の層のスプリットプレーンを置いて、左半分は完成です。
AM 11:04
アナログ回路が必要とする±5Vの電源を生成するDC-DCモジュールを、基板の右側に2chごとに配置しました。スイッチング電源なので気休めのLCフィルタでノイズを落とします。DCDCの後には±2.5Vを出すLDOを配置しています。
きっと重い基板になるのでしょう。
まだ完成じゃありません。
AM 11:52
1.0Vを出す基準電圧回路を乗せます。
なかなか完成しません。
PM 1:01
あとはポリゴン貼ったり、部品番号を順番になるように付けなおしたり、シルクの位置を調整したりします。
内層に通した電源がViaの壁で分断されていたりといった致命的なミスを見つけ、手直ししたりします。
これでようやく完成です。
PM 1:23
出図完了です。
今日は完徹してしまいました。
設計を開始してから延べ16時間くらいでできました。
生基板が到着するのは23日の木曜日です。
特電の製品でCosmo-Kというのがあります。
Kintex-7を中心にDDR3メモリ、USB3.0、GPIO、SATA、10Gbpsの光ファイバを何個か備えたボードです。
なぜか今月に入って注文がぽぽぽぽーんと入ってきたので、生基板の在庫が切れてしまいました。
そこで、新しく生基板から作ることにしたのですが、せっかくなので基板の改版を行うことにしました。
直したいところは「VCCAUX_IOを2.0Vにする」ということと「SFPケージの穴を大きくする」ということの2つです。
Kintex-7にはVCCAUX_IOという謎の電源ピンがあります。VCCAUXは通常は1.8Vですが、VCCAUX_IOはI/Oの出力バッファに割り当てられている電源のようで、DDR3メモリを最高速度でアクセスするには2.0Vにする必要があります。
現在の基板がこんな状態で、ほとんどあまりのピンがない状態です。
それでも何とかVCCAUX_IOの端子を切り分けて、コンデンサを内側に1個追加し、配線を引き出すことができました。
次に、光ファイバのモジュールであるSFPを収めている箱「ケージ」のピンの穴が狭かったので、これを太くしました。
使用している部品は、Anphenolの10127103-101LFとTE Connectivityの2007198-1です。
これらの部品には、たくさんの卵型の突起が生えていて、この突起を基板にはんだ付けすることで固定します。
データシートには穴の直径は1.05mmと書かれているのですが、絶対に1.05mmの穴には入りません。
今まではラジオペンチでこの卵型の突起をつぶして細くして基板に差し込んでいたのですが、「このデータシート、ゼッタイ変だよな~」と思いつつ、穴を限界まで太くすることにしました。
これで完成です。
今回の修正は主にこの2か所なのですが、いままでの基板とパターンやステンシル、レジストなどに予期せぬ相違が発生していないかを念入りにチェックしなければなりません。
ガーバのDIFFっていうのがあれば便利なのですが、そういうのはなさそうなのでGCPrevieを使って念入りに見比べて、ようやく出図です。軽微な修正のはずだったのに5時間くらいかかってしまいました。
来週の木曜日には生基板が出来上がってくる予定です。
GHz帯で使えるショットキバリアダイオードで、HSMS-2xxxというのがありました。
ダイオードの接続にいろいろなバリエーションがあるので、検波回路や保護回路にいろいろと使えます。
私がCosmo-Zのアナログの保護回路に使っていたのはHSMS-282Pというもので、下の図のような接続だったのですが、このHSMSシリーズが2年ほど前からディスコンになってしまっていたのです。
流通在庫を探すなどして何とかしのいできましたが、
このたび、Skywork Solutions Inc.という会社がSMS3923-081LFというのを出してくれました。Digikeyでも買えます!
性能もほぼHSMS-282Pに匹敵するもので、代替可能と判断しました。
深夜に会社に来て、実装用部品の受け入れ作業を行っています。
特電ではほぼすべての部品はDigikeyで買っていますが、購入した部品に4桁の数字のラベルを貼ります。
このラベルは自作のWebアプリで管理するためのもので、いつ、何を、何個買って、何に使って、どこに保存しているかをかかを管理するものです。
昨年からの方針転換で「部品の在庫は極力もたない」という方針で、原則1回の実装で購入した部品は使い切る方針なのですが、どうしても残ってしまって次回にも使うという部品はあるものです。
今日届いたのはCosmo-Kの部品だったようです。
さて、Cosmo-Kの部品が揃ったら、次にCosmo-ZとCosmo-Z ADC拡張ボードの部品をDigikeyに発注です。
一晩で50万円分くらい買います。実装失敗したらどうなっちゃうんだろう・・
Cosmo-Zは200種類くらいの部品があるので、発注していたら朝になってしまいました。
子供たちの朝ごはんを作って、寝ます。
ある基板が在庫が切れてしまったので、再生産することになりました。
以前はP〇.comで作っていたのですが、P社の内層クリアランスは0.5mm必要で、Viaが0.3mm径の場合のみ0.4mmでよいとのことでした。
製造基準書には丁寧に内層クリアランス径は1.1mmと書かれているので、下の図のようなイメージで間違っていないのでしょう。
内層クリアランスというのはViaの端から何mm開けなければならないかということです。
そもそも、なぜこれが必要なのかというと、Viaを作るためのメッキ液が染み込むとかいう化学的な理由なのかもしれません。そのあたりは詳しくありません。
まぁいずれにせよ、1.0mmピッチという比較的端子幅の広いBGAに対しても1.1mmの内層クリアランス径となると、下の図のようにベタパターンの分離が起きてしまいます。
GNDは内挿のベタのプレーンを作って、ベタパターンで配線するのが普通ですが、内層クリアランスが大きいと分断されてしまうのです。
いままでは、島ができてしまった部分には、自分ではんだ面や他の内層ら接続したりしていたのですが、前回作っていた基板ではそれを忘れていてP社の人が気づいて向こうで修正してくれていました。
今回の製造からは、日本の国産基板メーカーに変えることにしたのですが、製造会社に修正されたことをすっかりわすれていて、ガーバを出してから1分後に気が付き、あわてて基板キャンセルを行いました。
今回の基板メーカーに「内層クリアランスはどのくらいですか」と聞いてみたところ、0.15mmという回答でした。
つまり、図にするとこうなります。
ホント大丈夫か?
ちょっと不安になってしまう。
特急コースなら6層基板が2日で仕上がってP社の5日コース(実働10日くらいのイメージ)より安いという。
マジ神!
内層クリアランスが少なくてもよいと言われても経験的に広く取ってきた身としてはやはり怖いので、基本的に1.1mm径のルールで作って、最小限のGND島の部分だけ狭くして通り道を作ることにします。
ZYNQ搭載高速ADCボード「Cosmo-Z」にユーザ回路を追加する方法の続きです。
FilterブロックにはADCで計測された生データが流れているので、ここに適当なフィルタを追加します。
適当なフィルタということでCICフィルタを選びました。
CICフィルタとは
CICフィルタというのは足し算とデシメーションだけでできている単純なローパスフィルタで、特性は急峻ではありませんが、構造は簡単です。
詳しいことは当ブログの過去記事
http://nahitafu.cocolog-nifty.com/nahitafu/2015/08/cosmo-z18bit-ec.html
の記事をご覧ください。
SLICEモジュールの改造
VivadoでIPコアとして使えるCICフィルタは、AXI Streamを前提としていて、生のデータは入れられないようです。
そこで、前回作ったSLICEモジュールを改造して、8chのデータが詰まった96bitのAXI Streamを、16bitのAXI Stream 8chに分解するようにしました。
元のADCデータは12bit×8chなのですが、これを12bitのAXI Stream 8本に分けたところ、VivadoがWarningを出してきました。
どうやら、AXI Streamはビット幅が8の倍数でないと正しく動作しないかもしれないそうなのです。
CICフィルタに入れるデータは2の補数表現であろうから、リニア→2の補数表現に変換しなければなりません。
せっかくなので、CH1をCH1,2,3,4にコピーして、CH2をCH5,6,7,8にコピーする機能もSliceモジュールに持たせましょう。
architecture Behavioral of cosmoz_data_slice is
ATTRIBUTE X_INTERFACE_INFO : STRING;
ATTRIBUTE X_INTERFACE_INFO of tdata_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata0_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT0 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid0_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT0 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata1_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT1 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid1_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT1 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata2_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT2 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid2_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT2 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata3_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT3 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid3_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT3 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata4_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT4 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid4_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT4 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata5_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT5 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid5_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT5 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata6_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT6 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid6_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT6 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata7_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT7 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid7_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT7 TVALID";
begin
tvalid0_o <= tvalid_i;
tvalid1_o <= tvalid_i;
tvalid2_o <= tvalid_i;
tvalid3_o <= tvalid_i;
tvalid4_o <= tvalid_i;
tvalid5_o <= tvalid_i;
tvalid6_o <= tvalid_i;
tvalid7_o <= tvalid_i;
tdata0_o <= (tdata_i(ADC_BITS * (0 + 1) - 1 downto ADC_BITS * 0) - x"800") & "0000";
tdata1_o <= (tdata_i(ADC_BITS * (0 + 1) - 1 downto ADC_BITS * 0) - x"800") & "0000";
tdata2_o <= (tdata_i(ADC_BITS * (0 + 1) - 1 downto ADC_BITS * 0) - x"800") & "0000";
tdata3_o <= (tdata_i(ADC_BITS * (0 + 1) - 1 downto ADC_BITS * 0) - x"800") & "0000";
tdata4_o <= (tdata_i(ADC_BITS * (1 + 1) - 1 downto ADC_BITS * 1) - x"800") & "0000";
tdata5_o <= (tdata_i(ADC_BITS * (1 + 1) - 1 downto ADC_BITS * 1) - x"800") & "0000";
tdata6_o <= (tdata_i(ADC_BITS * (1 + 1) - 1 downto ADC_BITS * 1) - x"800") & "0000";
tdata7_o <= (tdata_i(ADC_BITS * (1 + 1) - 1 downto ADC_BITS * 1) - x"800") & "0000";
こんなふうになりました。
Combineモジュールの改良
Combineモジュールでは逆にこれらのデータを束ねます。
ATTRIBUTE X_INTERFACE_INFO : STRING;
ATTRIBUTE X_INTERFACE_INFO of tdata_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid_o : SIGNAL is "xilinx.com:interface:axis:1.0 DOUT TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata0_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN0 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid0_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN0 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata1_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN1 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid1_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN1 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata2_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN2 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid2_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN2 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata3_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN3 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid3_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN3 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata4_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN4 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid4_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN4 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata5_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN5 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid5_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN5 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata6_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN6 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid6_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN6 TVALID";
ATTRIBUTE X_INTERFACE_INFO of tdata7_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN7 TDATA";
ATTRIBUTE X_INTERFACE_INFO of tvalid7_i : SIGNAL is "xilinx.com:interface:axis:1.0 DIN7 TVALID";
begin
tvalid_o <= tvalid0_i;
tdata_o(ADC_BITS * (0 + 1) - 1 downto ADC_BITS * 0) <= tdata0_i(15 downto 4) - x"800";
tdata_o(ADC_BITS * (1 + 1) - 1 downto ADC_BITS * 1) <= tdata1_i(15 downto 4) - x"800";
tdata_o(ADC_BITS * (2 + 1) - 1 downto ADC_BITS * 2) <= tdata2_i(15 downto 4) - x"800";
tdata_o(ADC_BITS * (3 + 1) - 1 downto ADC_BITS * 3) <= tdata3_i(15 downto 4) - x"800";
tdata_o(ADC_BITS * (4 + 1) - 1 downto ADC_BITS * 4) <= tdata4_i(15 downto 4) - x"800";
tdata_o(ADC_BITS * (5 + 1) - 1 downto ADC_BITS * 5) <= tdata5_i(15 downto 4) - x"800";
tdata_o(ADC_BITS * (6 + 1) - 1 downto ADC_BITS * 6) <= tdata6_i(15 downto 4) - x"800";
tdata_o(ADC_BITS * (7 + 1) - 1 downto ADC_BITS * 7) <= tdata7_i(15 downto 4) - x"800";
Block Designを配線する
SliceモジュールとCombineモジュールをRTLモジュールとして作り、間にCICフィルタを挟みます。
ADCに入ってくる信号はCH1(正弦波)とCH2(矩形波:トリガ信号)で、それを以下のような方針で8chに振り分けます。
VivadoのIPのCICフィルタの設定は以下のとおりです。
ゆるめ フィルタ
ふつう フィルタ
きつめ フィルタ
入出力ビット幅
フィルタの設定がきつくなると力バスのビット幅も増えてきます。
同じ条件で評価したいので、いずれのフィルタも、入出力データは16bit幅でTruncationの設定にしています。
ちょっと失敗したこと
SliceとCombineをRTLモジュールにしたことが失敗でした。
なぜなら、RTLモジュールでAXI Streamを作ると、Varidateをしたときにバスの速度が自動的に推定されないようで、全部手作業で設定しなければいけないようでした。ポートをクリックして、Block Interface PropertyをつっついてCONFIGの中のFREQ_HZを全部設定しなおさなければなりません。
IPとして作れば、おそらく自動で設定されます。
RTLモジュールはIPコアと違い、ツールがラッパを作ってアトリビュートを設定することができないのでしょう。
論理合成して実行
これを論理合成して、計測を行ってみました。
結果は次の図の波形のとおり。
フィルタがきつくなるにつれ、遅延が増えていくのがわかります。
時間軸的に拡大してみると、フィルタを通したほうはすべてカクカクしています。
これはCICフィルタがデシメーションをしているためで、4回に1回しかデータを出力しないからです。
灰色の線(CH8)は矩形波の反射による鋭いヒゲを除去できているのでLPFとしての効果はありそうです。
CICフィルタの周波数特性とノイズ除去性能
LPFなので、どのくらいノイズが除去できるか気になるところです。
今回使っている正弦波の発振器は、安物なので、波形が歪んでいます。
そのため、FFTをすると結構な高調波が乗ってしまうのですが・・・
CICフィルタを通すと、
(ゆるめ)
(ふつう)
(きつめ)
全体的にノイズは減っているのでしょうが、CICフィルタ自体が緩すぎて、あまり効果は感じられません。
サンプリング周波数の1/8付近(10MHz付近)のノイズは落ちていますが、20MHz付近ではかえってノイズが増えているように見えます。
矩形波もフィルタした結果のFFT
トリガの矩形波もCICフィルタに掛けているので、そのFFTでスペクトラムを見てみます。
矩形波のスペクトラムはくし型になります。
まずは「ゆるめ」のフィルタ。fs/4の20MHzで急峻に切れています。
次は「ふつう」のフィルタ。10MHz付近の減衰が少しだけ大きくなっています。
最後は「きつめ」のフィルタ。
10MHzと30MHz付近で大きくカットできました。
元が幅が広がったスペクトラムのほうがフィルタの特性は把握しやすいですね。
きっと、10MHz、20MHz、30MHz、40MHzのすべての部分で急峻に切れているのでしょう。
まとめ
いかがでしたでしょうか。
Cosmo-ZのFilterブロックでAXI Streamをほどいて再結合させ、その間にリアルタイムな信号処理を追加することができました。
ZYNQ搭載の高速ADCボード「Cosmo-Z」(コスモゼット)は、FPGAをユーザがカスタマイズすることができる高速データ収集装置です。
Cosmo-Zをカスタマイズしてユーザ回路でデータを処理するやり方の例を紹介します。
ダウンロードとプロジェクトの生成
まずは「Cosmo-ZのFPGAソース公開とビルド方法」の記事を読み、ダウンロードとプロジェクトの生成を行ってください。
Vivadoのプロジェクトを起動すると、以下のようなBlockDesignが現れます。
Signal Processブロック
上の図で左下にあるSignalProcessをクリックして開きます。
SignalProcessは階層構造になっていて、様々なモジュールが中に入っています。
SignalProcessブロックでは、ADCBlock→Filter→UPP(汎用パルス処理)→TRIGGER→trigdelay(トリガディレイ)→captureという順に信号が流れていきます。
ユーザがカスタマイズできるのは、FilterとTRIGGERの2種類です。
Filterをカスタマイズすることで、
することができます。
信号の規格
各ブロックを接続している信号はAXI Streamという標準的なバス規格ですが、バスのビット幅はADC_MAXCH × ADC_BITSでパラメタライズできるようになっています。
ADC_MAXCHはADCのチャネル数、ADC_BITSはADCのビット数で、デフォルトではADC_MAXCH=8、ADC_BITS=12となっています。
この値を変更するには、BlockDesignのトップにあるコメントを書き換え、
Tcl窓にNahiConfigByCommentと入力します。
Tclスクリプトが走り、プロジェクト内のすべてのモジュールのADC_BITSとMAX_ADCCHが一斉に書き換えられます。
それに伴い、AXI Streamのビット幅も自動的に調整されます。
Filterブロックをカスタマイズしよう
BlockDesignにあるFilterブロックを開けてみると、実は、中身は空っぽです。
このFilterは、BlockDesignの階層になっていて、ユーザが自分で回路を作りこむようになっています。
モジュールの追加
まず、FilterブロックをIPインテグレータで開いたら、
VivadoのSourcesにある+ボタンをクリックし、
Add or Create Designを行います。
プロジェクトのsrcの中にあるdata_combine.vhdとdata_slice.vhdを追加します。
追加したら、BlockDesignの何もないところで右クリックし、Add moduleを行ってRTLソースを追加します。
以下のような2つのモジュールが追加されます。
SliceとCombine
SLICEはCosmo-Zの計測データが流れているAXI Streamを1つ1つのチャネルのデータに分解してくれるものです。
※XILINXのコアにも似たようなのはあるのですが、SLICEが12bit単位とか14bit単位とかできなさそうです。
Sliceの中身
Sliceモジュールの中身は
tvalid_o <= tvalid_i;
tdata0_o <= tdata_i(ADC_BITS * (0 + 1) - 1 downto ADC_BITS * 0);
tdata1_o <= tdata_i(ADC_BITS * (1 + 1) - 1 downto ADC_BITS * 1);
tdata2_o <= tdata_i(ADC_BITS * (2 + 1) - 1 downto ADC_BITS * 2);
tdata3_o <= tdata_i(ADC_BITS * (3 + 1) - 1 downto ADC_BITS * 3);
tdata4_o <= tdata_i(ADC_BITS * (4 + 1) - 1 downto ADC_BITS * 4);
tdata5_o <= tdata_i(ADC_BITS * (5 + 1) - 1 downto ADC_BITS * 5);
tdata6_o <= tdata_i(ADC_BITS * (6 + 1) - 1 downto ADC_BITS * 6);
tdata7_o <= tdata_i(ADC_BITS * (7 + 1) - 1 downto ADC_BITS * 7);
Combineモジュールの中身は
tvalid_o <= tvalid_i;
tdata_o(ADC_BITS * (0 + 1) - 1 downto ADC_BITS * 0) <= tdata0_i;
tdata_o(ADC_BITS * (1 + 1) - 1 downto ADC_BITS * 1) <= tdata1_i;
tdata_o(ADC_BITS * (2 + 1) - 1 downto ADC_BITS * 2) <= tdata2_i;
tdata_o(ADC_BITS * (3 + 1) - 1 downto ADC_BITS * 3) <= tdata3_i;
tdata_o(ADC_BITS * (4 + 1) - 1 downto ADC_BITS * 4) <= tdata4_i;
tdata_o(ADC_BITS * (5 + 1) - 1 downto ADC_BITS * 5) <= tdata5_i;
tdata_o(ADC_BITS * (6 + 1) - 1 downto ADC_BITS * 6) <= tdata6_i;
tdata_o(ADC_BITS * (7 + 1) - 1 downto ADC_BITS * 7) <= tdata7_i;
です。
本当に単純にばらしたりくっつけたりしているだけです。
デフォルトの直結で動作させた場合
まずは分解したデータをそのままつないで結合するデザインを作ります。
いきなりですがこれを論理合成してFPGAに書き込んで動かしてみます。
論理合成の途中経過は省略します。
Cosmo-ZのCH1にはファンクションジェネレータから100kHzの正弦波を、CH2にはTTLレベルのトリガ信号を入れます。
CH3~CH8はオープンにしています。
Webオシロで見てみると、茶色の線(CH1)には正弦波が、赤色の線(CH2)には矩形波が映っています。
CH3~CH8には何も入力していないのでノイズが見えています。
CH3~CH8に、FPGA内部の配線をつなぐ
CH3~CH8はコネクタには何もつながっていないので、ノイズしか入ってきませんでした。
ノイズを見てもしようがないので、FPGAの中でCH1とCH2の信号をコピーしてつないでみましょう。
結果は下の図のとおり。CH3,4,5にはCH1のコピーが、CH6,7,8にはCH2のコピーが入りました。
まとめ
Filterブロックの中から信号を取り出すことで、計測したままのデータをそのまま扱うことができるようになりました。
特殊電子回路㈱が運営するTrenz製品販売サイトでは、購入前のボード選定に関するご質問や、購入後の使い方の質問をよくいただきます。
いつも調べてメールで返答しているのですが、そういったお問い合わせや無償サポートの内容をまとめて公開したら、今後、ご購入いただく方や今悩んでいる方たちのためになるかと思い、2年分くらいをまとめました。
こちらのページです。
https://www.trenz.jp/qanda/index.html
納期や価格の問い合わせは省き、他の人にも有益となるようなお問い合わせだけをまとめました。
質問の内容や回答にお客様の秘密が含まれるような場合はその部分を削除し、一部加筆訂正しています。
今のところ、
という記事があります。
記事の全文は検索可能ですので、Trenz製品に興味を持ってみたらぜひとも読んで検索してみてください。
今日は趣向を変えて風水のプログラミングをしてみます。
オカルトな世界にもいろいろあるのですが、(玄空飛星)風水、九星気学、四柱推命は計算のアルゴリズムがしっかりと確立していて、入力が同じならば出力は同じになるという特徴を持っています。
例えば、(玄空飛星)風水ならば、竣工年と建物の向きが決まれば、結果は一意に定まります。
四柱推命ならば誕生の年月日と時間で結果は一意に決まります。
そのアルゴリズムは、ちゃんとした本を読めば書いてあります。(ドクター〇パとか李〇●竹とかを読んでも書いていません)
作ったプログラムの一部を示しましょう。
PHPで書いてあります。
$運星 = array(); //
$運星["東南"] = 剰余($era + 8); //
$運星["南" ] = 剰余($era + 4); //
$運星["南西"] = 剰余($era + 6); //
$運星["東" ] = 剰余($era + 7); //
$運星["中央"] = 剰余($era + 0); //
$運星["西"] = 剰余($era + 2); //
$運星["北東"] = 剰余($era + 3); //
$運星["北"] = 剰余($era + 5); //
$運星["北西"] = 剰余($era + 1); //
switch($向) {
case "N1": case "N2": case "N3":
$中央水星 = $運星["北"];
$中央山星 = $運星["南"];
break;
case "NE1": case "NE2": case "NE3":
$中央水星 = $運星["北東"];
$中央山星 = $運星["南西"];
break;
case "E1": case "E2": case "E3":
$中央水星 = $運星["西"];
$中央山星 = $運星["東"];
とか、
if($中央山星 == 5) {
if( (preg_match("/[23]/",$向) && !($era % 2)) // 偶数で区分2か3
|| (preg_match("/[1]/",$向) && ($era % 2))) { // 奇数で区分1
$山星順行 = true;
}
else {
$山星順行 = false;
}
}
if($中央水星 == 5) {
if( (preg_match("/[23]/",$向) && !($era % 2)) // 偶数で区分2か3
|| (preg_match("/[1]/",$向) && ($era % 2))) { // 奇数で区分1
$水星順行 = true;
}
なんだかとても怪しげなプログラムですね。
PHPは変数名に普通に漢字が使えるし、連想配列が使えるのでわかりやすく書けました。
もし、英数字しか使えないとどうやって英語に訳せばよいかわからなくて困るでしょう。
さて、これは何を計算するプログラムなのかというと、風水のチャートを作るプログラムなのです。
この数字がわかると、建物の部屋の吉方向や凶方向、場所の運勢や適した用途がわかります。
計算で求められるのはこの数字までで、その数字をどうやって解釈するかは風水師の経験にゆだねるところが多いのです。
このツールの良いところは、年飛星も表示できることと、北を上にして表示できること。
下の図は、卯山酉向(西向き)で第7運(1984~2003年)に建てられた物件のチャート。
だいたいどの風水本も風水サイトも南が上で表示されているので、北が上にするというオプションも付けました。
北が上のほうがわかりやすいですよね。
Trenz製品販売日本語サイトの見えないところをリニューアルしました。
見えない部分だけど大事な仕事。
まず、今までTrenzサイトでは検索窓にカーソルを合わせることが困難でした。
どうやら2018年にスライダーを起動するJavascriptが追加された際に、スライダーの枠のdivが、実際の画像のサイズよりも大きいheightで定義されていて、その枠の見えない部分にバリアされて検索窓にカーソルが合わせられなかったようです。
そのため、スクロールする一瞬だけ検索ができるということになっていました。
この不具合を1年4か月くらい放置していました。いけないですね。
せっかく検索ができるようになったので、本文を全文検索できるようにしました。
Trenz製品販売日本語サイトをはじめ、特電の作るWebページはtkcmsというCMS(コンテンツマネージメントシステム)で作られていますが、そのデータは以下のような感じでデータベースに入っています。(実際には1つのレコードには30個くらいの項目があるのですが簡単にしています。)
そして、過去のページ内容をいつでも復元できように、すべてのページのすべての時点のデータを全保存しています。
だから、元になるテーブルを全検索しては、すでに無効になっている記事や更新される前のデータもひっかかってしまいます。
このようなテーブルに対して全検索を行うには、まず、アクティブな記事のリストを作り(ここでSELECTを1回)、各記事のURLやタイトルをキーとして内容を取り出すためのSELECT文を記事の数だけforeachで回すことになります。
合計、ページ数+1回のSELECT文を回さなければならなくなり、重くなります。
そこで考えたのが、検索用のキャッシュテーブルを作ること。
全記事のデータの中から現在アクティブかつ最新のものを取り出し、HTMLのタグを外し、全角英数字を半角英数字に変換したテーブルを作ります。
そして、この検索用キャッシュテーブルに対して検索を行います。
全角半角で揺れても大丈夫になるし、1回のSELECT文で済むし、各ページの検索スコアを設定することもできるようになりました。
例えばZynqberryで検索したときの結果は以下のとおり。
商品情報だけではなく、記事全文からテキスト検索できるようになりました。
あけましておめでとうございます!
今年もよろしくお願いします。
今年の抱負は、「Facebookをがんばる」「レスポンシブデザインをがんばる」にしたいと思います。
かなえられない高い目標よりも、まずは現実的な目標を。。
さて、
HyperFDACとか、Cosmo-K DVIとか、JTAGチャレンジ基板とか、一昨年までにやっていて完成させていなかった製品を、やっぱり完成させたいですね。
それから、Web版MITOUJTAGの開発も再開したいと思っています。
Web版MITOUJTAGは、Webブラウザ経由でJTAGが使えるというクラウドアプリで、サーバ上でJTAGの複雑な処理をするというものなのですが、今までに2回作りました。
1回目は「MITOUJTAG Air」の名前で出したのですが、ソースコードがぐちゃぐちゃになって失敗。2回目はMITOUJTAGオンラインの名前で出して、ユーザ間のコミュニケーションができるようにしたもので、キャラクタが出てきてオンラインゲーム風でした。やはりソースコードがぐちゃぐちゃになったのと、ブラウザからUSB-JTAGにアクセスするためにActiveXを使っていたことで崩壊。
3度目を今年はやりたい。FPGAのデバッグではなく、CPUのデバッグにも広げたい。その方策は考えてある。
手を付けていて完成していなかったものをすべて片づけて、それから組み込みとかIoTとかFPGAではない、次の世界にいきたい。
それが今年の目標です。
最近のコメント