« 2010年7月4日 - 2010年7月10日 | トップページ | 2010年7月25日 - 2010年7月31日 »

2010年7月18日 - 2010年7月24日の1件の記事

2010年7月18日 (日)

XP2の外付けSRAM双方向アクセスに成功

UARTのソースコードを換えてみる(7/10/10)
 FPGAによるフォトフレームプロジェクトは山場を迎えた。外付けSRAM(ビデオRAM)にSPIインターフェースを通してデータを送り込み、そのデータを読んでRGBインターフェースへ画像データを出力する段階の開発である。これが動くとFPGAの機能は、ほぼ完成する(このあとはプロセッサーでのJPEGデコード機能などの開発)。

 気持ちに余裕がでてきたので、SPIを組み込む前に、この前、感動したwww.fpga4funのUART(このサイトではRS-232Cと言っている)を実際に動かしてみたくなった。コードはこちらが作ったもの(これも雑誌からの借り物だが)よりかなりコンパクトになっている。リソースはそれに比例して少なくなっているのだろうか。

Fpga4uart

 サイトの記事に出ているソースコードは抜粋で、実際のソースコードはzipファイルで落とせるようになっている。早速ダウンロードして解凍する。うーむ、サイトに出ているもの較べるとコード量が多い。エラー処理などの機能が追加されているようだ。

 クロック周波数、ボーレートなどを調整し、エラー処理などを簡略化して、これまでのUARTテストプログラムに入れて動かしてみた。ありゃあ、うんともすんとも言わない。ネットに公開されているコードが動かないということはまずあり得ない。自分が直したところがいけないに違いない。

 気を落ち着けて、最初からひとつづつ調べていく。その結果、単純な入力ミス(ボーレートが一桁多かった)、インターフェースミス(論理が逆だった)などが見つかる。これを直してfpga4funのUART送受信コードは無事動いた。

 気になるリソース使用量はどうだっただろうか。元のUARTのスライスが165だったのに対し、138まで下がった。一時は、96まで下がり、すごいと思っていたが、一行記載漏れがあり(これが原因で送信が最後まで動かなかった)、これを補うと動いたものの、スライスは大きく増えてしまった。まあ、それでも15%以上のリソース削減である。

 エラー処理などは少し残してあるので、これを削ればスライスはもっと少なくなるかもしれない。ただ、受信は、まだ不具合が残っており、ファイル転送などでデータを一気に送ると受信ミスがある。まあ、これは本筋と関係ないので、これ以上関わるのはやめることにする。

SPIとSRAMアクセスの間にバッファーが要るか(7/12/2010)
 SPIインターフェースの詳細設計に入る。この第5ステップの開発には実はSPI受信機能より、もっと重要な機能の開発がある。間断なく続くビデオインターフェースへのデータ転送の合間に、双方向でSPIからのデータをSRAMへ書き込む処理と、SPI読み込みとSRAM書き込みの間の非同期処理である。この間はバッファーを設ける必要があるだろう。これをどの段階で、どの程度の深さ(バッファー量)が必要なのか見極めなければならない。

 SPIはプロセッサー側がマスター、FPGAはスレーブなので、送信を待たせるわけにはいかない。マスターがCS(Chip Select)を上げて、クロックを動かせば、どんなことがあってもデータを読まなければならない。勿論、プロトコルを作って送信を待たせることも出来るが、この程度のしかけでは大げさすぎる。

 一方、SRAMのアクセスは、ピクセルクロック単位に時刻が決められた待ったなしの読み込みなので、これまたこれを邪魔してはいけない。FPGAは同時処理なので両者を同時に動かせるが、非同期なので、そこを通るデータは正確に受け渡す必要がある。これを調整するのがデータバッファーで、普通、FIFO(First In First OUT)とか, リングバッファーなどと呼ばれる。こういうシステムの設計でこのあたりが最も難しく、また最も面白い部分である。

 しかし、FPGAは完全な並列マシンなので、だいぶ気楽だ。これがプロセッサーのマルチタスク構造だと、やれプリエンプティブだの、ノンプリエンティティブだの、タスクスイッチオーバーヘッドと言ったOSの機能を気にしなければならないが、FPGAは基本的には全く独立して並行に動くので、データの動きにさえ気を遣っておればよい。

 それと、QVGAなのでピクセルクロックと、SRAMアクセスの間に余裕がある。たまたま、SRAMが書き込み中で読めなくても、2クロック後には、SRAMが空くので、そのときまで待って(5クロックくらい余裕がある)、読めばよい(ピクセルが少しずれるか?)。

 テストベンチは、SPIのデバッグのためUARTインターフェースを残し、プロセッサー側からSPIでデータを送った後、UARTコマンドで送り返して検証することにする。

A7183034

FIFOは要らないことがわかった(7/13/2010)
 少し意気込んで詳細設計に入ったが、SRAMのアクセス時間30ns(現在の33Mhzマスタークロック)、ピクセルクロックの間隔196ns、SPIの読み取り間隔などを詳しく計算しているうち、どうもFIFOなどの大掛かりな仕掛けは必要なさそうな感じがしてきた。

 SPIの8ビットデータが揃うのは、ARMの最速SPIが18Mhzで動くとして、1クロック55ns×8 =440nsだ。一方、SRAMのアクセス時間は、8ビットがクロック1サイクル30nsで読み書きできる。VGAインターフェースへの読み出しと、SPIからの書き込みがかぶっても、それぞれ2クロック以内にSRAMはあく。

 SPIの方はもっと余裕がある。SPIのシフトレジスターは、データが連続していれば、1フレーム(8ビット)のあとも次のデータは55ns後に来るが、読んだ8ビットデータをラッチするバッファーを一つ置いておけば、次の440ns後まで次のデータは来ない。1バイトのバッファーさえおいておけば、FIFOのようなしかけは不要だ。ピクセルクロックでの読み出しと、SPIのバッファー取り込みが、かぶったとしても、次のドットは196ns後なので、余裕でデータを読み込める。

 詳細設計に自信が出来てきたので、ソースコードを整理し始める。これまで分割してきたソースを統合する。UARTとビデオインターフェースのソースは別々だったので、これをまず総合する。そのあとSPIモジュールを足し、SPIからのデータをSRAMに書き込むプロセスを書き加える。

 www.fpga4fun.comで新しいHDLの書き方を覚えたが、alwaysを分けた簡明なコーディングは難しい。相互に関係する変数が多く、プログラム言語と違って外部変数を複数のモジュールで勝手にいじれないので(外部変数は参照のみ)、モジュールを分けるのは一苦労だ。

 7セグLEDから始まって、UART、SRAM、カラーバーと、沢山モジュールを開発してきたが、結局、1つのalwaysループに殆ど全てのプロセスを含める必要が出てきた。使い回しが難しい。このあたりがIPコアプロセッサーが幅を利かせている理由なのだろう。

Isplever

 メインループは350ステップを越えてしまった。いやな予感がする。案の定、論理合成でエラーが出る。Latticeの論理合成ステップは一風変わっていて、ソースコードをSAVEした時点で軽いエラーチェックが入り、Synplifyの論理合成でもう一回、Place&Routeという次のステップでも、もういちど結線上の論理エラーを出してくる。

 ところが、このPlace&Routeでのエラーメッセージは、どこでこのエラーが起きているのか教えてくれないので弱った。これは、このあとメッセージの中にステートメント番号が入っているところを見つけたが、最初は途方に暮れていた。

やっとSRAM双方向アクセスが通った(7/16/10)
 ソースが大きくなりすぎ苦労している。まずコンパイルにあたる論理合成が通らない。SRAMのアドレス操作が難しい。SPIによる書き込みと、ビデオインターフェースが間断なく読み込む処理は、頻繁にアドレスを換えて動く。複数のモジュールでひとつの変数をいじることが出来ない制約が重くのしかかる。何度か頓挫する。気分転換に別のことをやって再度挑戦するということの繰り返しである。

 やっとのことでソースコードが完成した。しかし、すぐにテストに入る気にならない。今度のモジュールはほぼ完成形で、SPIもビデオインターフェースもすべて組み込んである。ただ、SPIの送り側はまだ開発していないのでテスト手順が難しい。メモに書いてある手順をもういちど確認して、恐る恐る動かし始めた。

 まずオシロで出力を見るが、ビデオインターフェースが全く動いていない。UARTは動いている。しかし、SRAMから出てくるデータはめちゃめちゃである。ビデオインターフェースが動いていないのに何故だろう。

A7163030

 規模の大きなプログラムが動かないときの原因究明の常套手段は、分割してひとつづつ動かしてみることである。新しく入れたルーチンを次々にコメントアウトしていく。結局、最後のUARTまでになっても、SRAMの書き込みがうまくいかない。UARTはデバッグ用なのだけど、キーボードから入れたデータはゴミになって返ってくる。

 UARTにこだわっているわけではない。双方向でそれぞれが別のアドレスを指示しながらSRAMを読み書きできなければフォトフレームは動かない。UARTが動いていなければSRAM双方向アクセスの検証ができず、先に進めないからだ。

 アドレスを共通にするとUARTはちゃんとSRAMにデータを書き込み、正常に読み出せる。読み込みと書き込みのアドレスは、次のassign文で区別しているのだが、これがどうにもうまく動かない。 

  assign SRAMアドレス = (書き込みのとき)? 書き込みアドレス : 読み込みアドレス

Sram716

結局、ロジックアナライザーに出馬を願うことにした。ICプローブがFPGA基板にうまく接続できないので使用をためらっていたが、ロジアナでなければこれ以上の解析は無理だ。シミュレーターもあるが準備が大変だ。考えた末、基板のピンのパッドに10ミリくらいの0.5ミリ錫メッキ線を半田付けしてスタブを作り、そこへプローブをつける。アドレス線と、WriteEnableで5本のスタブを出した。

Sram_ok

苦労した甲斐があって、一発で原因が判明した。プログラムは思ったようには動かない、書いたように動くという好例だ。アドレスの切り替えに余裕を持たせて1クロック待ってから、Enableを出したつもりだったが、ロジアナで見てみると、Enableの前でアドレスが切り替わってしまっている。

 何だ、考えてみれば、assign文は組み合わせ回路なので遅延がない。さっきの書き込みの切り替えは、書き込みリクエストのフラグではなく、じかにWriteEnableにするだけで良いのだ。わかってしまえば、なんでもない話だった。

 ソースを作り替えて論理合成。おお、全く問題なくUARTが動く。懸案だったSRAMの双方向アクセスがやっと完成した。ロジアナさまさまである。ビデオインターフェースがまだ動かないが、これはwireとかreg変数の受け渡しか何かのミスだろう。FPGAでの開発は一山越したように思う。

 残るSPIの検証は、送り側の開発が必要である。久しぶりにSDカードの付いたAVRのMega128基板を取り出して、テストベンチの開発を準備する。うーむ、プログラミング言語は楽で良い。

| | コメント (4) | トラックバック (0)

« 2010年7月4日 - 2010年7月10日 | トップページ | 2010年7月25日 - 2010年7月31日 »