カテゴリー「FPGA」の26件の記事

2010年11月 9日 (火)

CQ-STARM基板のCPU換装とDE0の到着

チップの換装で肝を冷やす(11/2/2010)
 今年2月から始めたフォトフレームプロジェクトは最終段階に入った。JPEG画像ファイルをデコードする機能の開発である(第8ステップ)。このほかに液晶モニターにFPGA基板とプロセッサー基板を取り付ける工作(第9ステップ)が残っているが、これはそう大した話ではない。こちらのほうが難易度が高い。

 まず、プラットホームを整えなければいけない。前記事にあるように、現在のCQ-STARM基板の石、STM32F103VBT6は、フラッシュは128KBあるが、SRAMが20KBで、JPEGファイルをデコードするためには、SRAMの容量(24KB以上必要)が足らない。

Ab093391 手持ちの石にこのあいだXilinxのFPGAチップと一緒に買った、フラッシュ512KB、SRAM 64KBのSTM32F103VET6があるが、今問題なく動いている基板のチップをはがすのはどうも抵抗があってすぐには踏み切れなかった。

 しかし、このままVET6を残していても、この先何か使うあてがあるわけではない。暫く悩んでいたが、思い切って換装することにした。

 定番のサンハヤトの低温ハンダを取り出す。この前のFPGAのときと同じようにチップの裏面にフラックスが固着していて、とりはずしは少し難渋した。ハンダは溶けているのにチップがずれてくれない。ずらすのではなくピンセットの先端を隅に差し込み、少しこじるように浮かすと、きれいにはがれた。

 ハンダ吸い取り線で念入りに低温ハンダを除去し、クリーナーで基板を綺麗にする。何回目かの0.5ミリピッチICのハンダ付けである。大分慣れてきてこの前のようにピンの微調整もなくぴったりハンダ付けが出来た。うーむだいぶ腕が上がったぞ(しかし、これが落とし穴だった)。

 何も入っていない新品のCPUチップの動作テストは、JTAGのOpenOCDのコマンドである。通電する。全く反応はない。用心のためすぐ電源を切る。

 うわあ、この間とりかえたばかりのレギュレータ(LDS3985)が火傷しそうに熱い。ショートだ。こういうときに限って、ショートチェックを怠っている。良かった、電源をすぐ切って。いや、駄目になったかもしれない。どきどきしてきた。まあ、これはいずれわかる。壊したとしてもレギュレーターだけだろう。

 基板を点検する。見たところ、ハンダブリッジもない。きれいなもんだ。しかし、テスターで測ると、しっかり0オーム。やれやれ。ピンコンパチなので疑うのはハンダ付けしかない。どこかでショートしている。なおもルーペで目検。

Ab093399 ありました、ありました。STM32の電源は、VddとVssが4隅に隣接して配置されている。その一箇所のパッドのピン位置より奥のところで波しぶきのように細くハンダが浮いて付いているところを発見した。(写真にとろうと思ったが微小すぎて撮れなかった)

 こういうこともあるんだ。恐らくフラックスで流動化したハンダが飛び散って空中で握手をしたようだ。半田ごてをあてれば苦もなくなくなった。テスターで測る。大丈夫。ショートはやっぱりここだった。

それこそ、祈る気持ちで通電する。OpenOCDを動かす。良かったあー、動いているぞ。

JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (Manufacturer: 0x23b, Part: 0xba00, Version: 0x3)
JTAG Tap/device matched
JTAG tap: stm32.bs tap/device found: 0x06414041 (Manufacturer: 0x020, Part: 0x6414, Version: 0x0)
JTAG tap: stm32.bs             got: 0x06414041 (mfg: 0x020, part: 0x6414, ver: 0x0)

JTAGはこの石を認識した。レギュレーターは壊れていなかった。
コマンドを入れる。

> flash probe 0
device id = 0x10016414
flash size = 512kbytes
flash 'stm32x' found at 0x08000000

 よーし、フラッシュ512KBも認めた。これでSTM32103VET6のハードは動いている。電圧を測る。3.29V。問題ない。

 ほっと胸を撫で下ろす。それにしても、レギュレーターひとつでこんな波乱万丈の気分が味わえるのを喜ぶべきなのか、情けないと思うべきなのか。たかが、¥100程度の石なのだが、生きとし生けるものを無駄にすることは、どんなものでも心が深く傷付いてしまう(単にケチなだけかも)。

「ねむい」さんの尽力でVE6が動かない問題は解決した(11/3/2010)
 次は、ソフトだ。当面、DFUを入れてとりあえずは前の石の状態にもどすことにする。以前お世話になった「ねむい」さんのサイトから頂いたDFUのプロジェクトのソース一式をEclipseにインストールする。これはVB6用なので、これをVE6用に変えなければならない。  

 詳しく調べると、MakefileでCPUなどを定義する環境変数を換えれば、ソース内の細かいコードはすべて、それにならって変わるようなので、変数のMedium Density(VB6など)の定義をHigh Density(VE6など)に切り替える。ビルドは特に問題なくOKとなった。

 この前、不調だったフラッシュローダーを動かしてみるが、相変わらず動かない。次の手段、OpenOCDを立ち上げJTAGモードに入る。TelnetからOCDのコマンド、

flash write_image erase ../main.bin 0x08000000 bin
 
でDFUのbinファイルを素直に書き込む。よーし書けた。順調だ。これでPCからDFUSeを動かせば、USBを通してこのボードをPCが認識するはずだ。

 あれえ、音沙汰がない。PCのデバイスマネージャーを見てみると、USBの不明なディバイスのアイコンは出るが、肝心のDFUSeの反応がない。さて、どこが悪いのだろう。

 32ビットマシンのスタートアップまわりの、この種のトラブルシューティングは、ちょっとまだ手が出ない。何から調べれば良いのかもわからない。しかし、この「ねむい」さんが提供してくれたDFUは前のVB6のチップのときは、何の問題なく動いていた。フラッシュが128Kから512Kに増えたからといって、フラッシュの開始アドレスが動いたわけでもない。普通なら何もしなくても動くはずだ。試しにVB6用のオリジナルのbinファイルを入れてみたが、これも動かなかった。やっぱり何かは換えないといけないようだ。

 とりあえずはご当人にそれとなく聞いてみよう。勝手にいじっておいて動かないと言うのも気が引けるが、このところご無沙汰しているし、「ねむい」さんのブログに挨拶代わりに遠慮がちにコメントを出してみた。JPEGでもあわよくばお世話になりたい下心もある。

 すると、次の日、詳しく調べたいのでソースを送って欲しいというレスポンスが帰ってきた。お言葉に甘えて、すぐソースコードを送ると、また2日もしないうちに、詳細な修正手順が送られてきた。いやいやありがたい話である。

 それによると、103VE6に換えるときに、103VB6_EVALという基板の設定変数を一緒に103VE6_EVALに換えているが、これがどうもまずいようだ。考えてみたら当然である。このCQ-STARM基板はもともとVB6用の基板であり、これにVE6が載るとは想定していない。VE6_EVALという評価ボードは物理的にこのボードとは別にあるのだ。その証拠に、VB6ボードにはない、NORメモリの初期化までやっている。これだ。これだ。

VE6が動いた。JPEGライブラリの準備OK(11/6/2010)
 謎が解けた。このMakefileにはチップによって換わる変数は3つあって、ひとつはCPUのモデルを決める、           SUBMODEL = STM32F103VET6(VBT6)
と、メモリサイズを決める     MPU_DENSITY = STM32F10X_HD(MD)
それに、評価ボードの定義  EVAL_BOARD = USE_STM3210E_EVAL(10B_EVAL) 
                                                                                              (カッコ内はVB用)
があるが、このうち一番下の変数をはずして(元のVBに戻す)ビルドし直す。

 JTAGで書き込む。USBの設定が少し複雑(ハブの電源を切らないとコードを抜いただけでは初期化しにいかない)で少し手間取ったが、無事、DFUSeが石を認識した。試しにLEDブリンクのテストプログラムをDFUSeで書き込む。順調に書けた。リセットし直すとLEDが点滅した。よーし、動いたようだぞ。

 次は、前のフォトフレームの本番プログラムだ。ついでにロングファイルネーム(LFN)の対応を止める。何とフラッシュサイズは、89KBから20KBに激減した。

 新しいDFUSeで書き込む。おおお、FatFSが動いた。ファイルをFPGAに送り込み、前の画像が出た。久しぶりの画像である。いとおしく眺める。これでJPEGファイルデコードの準備は整った。「ねむい」さんには感謝、感謝である。さらに、メールのやりとりの間にあと2つ贈り物をもらった。本当にありがとうございました。Ws000001

(1)STMフラッシュローダーのフリー版を教えてもらったhttp://www.mcuisp.com/ のmcuisp.exeである。始め漢字が全面に出て思わずたじろいだが、英語の翻訳ページがあり、ダウンロードできた。動かしてみた。こいつはすごい。これまで散々手こずってきた純正のフラッシュローダーの機嫌の悪さに較べれば、圧倒的に安定してチップに書くことが出来る。メッセージも豊富で動かしていて安心感がある。サイトの情報によるとARMだけでなくAVRやPICにも使えるようだ。これは良いものを教えてもらった。

(2)どうしても動かなかったHex2DFUが動いた
 Makefileに定義してあって、hexやbinファイルを作る手順に上記フリーソフトが動くように設定してあったのだが、これまでどうしても動かなかった。スペースの入ったディレクトリのパスは受け付けないということを教えられ、これを別のところへ持って行ったらあっさり動いた。他のディレクトリパスは"Program Files"などを受け付けていたので、まさかと思っていた。これでHexファイルからDFUファイルに変換する手間が省けて、DFUでの開発が楽になる。

DE0を発注してしまった(11/5/2010)
 すんさんの掲示板にも書いたけれど、遂にALTERAのFPGA評価ボードDE0をDigiKeyに発注してしまった。この評価ボードは、Altera CycloneⅢにDRAMやフラッシュ、VGA、I2C、UART、PS2など盛りだくさんのペリフェラルがついた教育用評価ボードで、価格が1万円少々と破格の安値で前から注目していた。私が掲示板で勧めたこともあったのかも知れない、周りで次から次に買う人が増え、しかも面白そうなアプリケーションをDE0で動かしておられるのを掲示板で見せられて指をくわえていた。

Ab093390

 今まで買わなかったのは別に1万円の出費を惜しんでいたわけではない(え、いややっぱり1万円を越すと何かとありますが)。どうせ買うのなら、価格がDigiKeyの送料無料ラインを楽々越えるので、日頃、手に入りにくいチップが集まってから一緒に買おうと思っていた。しかし、今のところ欲しいチップは、PGA2311という電子ボリュームICだけで、なかなか次のものがあらわれない。

 手を出さなかった理由はほかにもある。新し物好きなので気が散って今やっているものを投げ出す恐れが強い。それに、既に2つの会社のFPGA、Xilinx、LatticeのインターフェースケーブルがごろごろしているのにまたAlteraのものも増やさなければならない。さらに開発環境をこれ以上増やすのは今のPCはドライブがもう満杯で、ディスクを買い直す必要がある。

 あれやこれやで、暫くは買わないと心に堅く決めていたのだが、フォトフレームが動き出して、すっかり緊張の糸が切れ、欲しい気持ちに歯止めが効かなくなってしまった。それに今のフォトフレームで不満なところを、今度の評価ボードは埋めてくれるような気がしてきたからである。

 現在のフォトフレームはSPIでデータを送っているが、シリアルなのでスピードが遅い。特にVGAにしてしまったので、画面描画中は、全くデータを受け取ることができない。SRAMは10nsの高速だが、既にFPGAのクロックは15nsまで上がっており、パラレルバスにしないと帰線期間中の大量データ書き込みは出来ない(SPIでは送れても数十バイト)。

 FPGAでSDカードを読み、内部で処理すれば、うまくいけば動画レベルまで画像処理が出来そうな気がする。今の付録基板では、CPUコアは恐らく入らないだろう。DE0クラスでないと無理だ。DE0ならもしかするとウェブカメラまで出来るかもしれない。まあ、このへんを実現するのは、相当、使い込まなければ無理だと思うけれど、夢があることは大事なことだ。

DigiKeyからDE0が届いた(11/8/2010)
 何だかんだやっているあいだに、DigiKeyから品物が到着してしまった。ここはいつも恐ろしく早い。土日を抜けば、営業日勘定で1日半(木曜午後注文して、月曜朝到着)という早さだ。早速梱包を開けて中を取り出す。思っていた以上にコンパクトだ。電子ボリュームのIC(PGA2311)と一緒に記念撮影。

Ab093386

 すんさんの掲示板で、発注したことを報告したら、沢山の人からレスポンスを貰った。また一人新しく買う人が増えたのと、このDE0を知るきっかけとなったご当人のSimさんからもコメントを頂いた。こちらはFPGAなどまだ初心者も良いところで、色々教えてもらおうと思っているところなのに、情報提供を期待されるなんて少し面映い。

 当研究所のブログは、技術情報の提供は余り主眼に置いていない。むしろ、みなさんの新しい情報にお世話になっている。どちらかというと、このブログは挫折しないため(動かなくてもめげずに這い上がるため)のノウハウ談だと思っている。

 このDE0でもせいぜいたくさん失敗を重ねることにしよう。ただ、先の話はともかく、今すぐDE0を使う手近なアプリケーションは思い当たらない。少しづつこのボードのデモを動かしながら勉強をしていこうと思う。

 そのなかで気になっているのが、Simさんがすんさんの掲示板で紹介された、NiosのAvalon-MMというCPUバスだ。今度のフォトフレームもここの性能如何で何が出来るかが決まる。CPU設計のまさしく奥の院で、この仕様が公開され、いじれるというのは、ソフトウエア開発者にとっては夢のような話である。

 ああ、こんな話をしている場合ではない。CPUのSRAMサイズが大きくなったので、早くJPEGライブラリを入れてフォトフレームを完成させなければ。

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

2010年11月 1日 (月)

フォトフレーム: SRAMを増設して15ビットカラーに

 雑誌(デジタルデザインテクノロジー誌2009年1号)の付録基板Lattice XP2を使ったFPGAフォトフレームは、遂にSDカードからのBMP画像ファイルを7インチWVGAデジタル液晶に表示することに成功した。細かい不具合を直すと、これが思っていた以上にきれいな画になったので、欲を出して、SRAMを増設し12ビットカラーから、もう少し本格的なデジタルフォトフレームにしようとがんばってみた。

SRAMへの書き出しを逆にして直った謎は解けた(10/20/2010)

 さんざん悩ませてきた縞模様の画像が解消されたのは、理屈に合わないがSPIから送られてきたデータの順序を逆にすることだった。12ビットのRGBの色信号はバイトをまたがって構成されており、本来この順番を逆にしたら、でたらめなデータになってしまうはずである。

 落ち着いて考え直して見てその原因がわかった。SPI,UARTはMSBファーストでデータを送るのだが、送られたデータをそのまま右端(LSB)から入れていくと、出来たバイトは逆のLSBファーストになるのだ。SPIで入れたupperバイトは15から8番目のデータで、送られるとMSBから8-15と並ぶ。lowerバイトは、これと同じ、0-7。

 この16ビットデータ(8-15と0-7)を並べてどちらから連続して12ビットとっても元にはもどらない。このupperとlowerをひっくり返すと、0-7、8-15と並び、これで16ビットデータは連続する。メモリからUARTに出す時は、これと全く同じようにMSBから送り出すので、元のオーダーに戻る。1バイト毎の処理ならばメモリにどういう形で入っているかは問題にならない。これが解決を遅らせた要因でもある。

 結果としては、リトルエンディアンとビッグエンディアンを間違えたということになる。ただ、何か少し違うような気もする。まあ、いずれにしてもUARTなどのシリアル系ではビット順は注意しないといけないことを身をもって学んだ。

Aa203325

デジタル色信号の配線の間違いがあった(10/24/2010)
 テスト画像のような単色画像はもう問題ないが、グラデーションのある写真画像はまだバグが残っていて鮮明な画像にならない。原因究明に、良い方法を思いついた。3原色のグラデーションの画像でテストすれば一発でどの色がおかしいかが分かる理屈だ。

 次女に作画を発注し、それをSDカードに移す。映し出された画像を見て、一目瞭然でおかしいところが判明した。赤と緑は問題ないが、青の暗いところが暴れている。うーむ、こいつはすごい。デジタル信号の間違いが一目で分かる。基板を調べると、画像のとおり青のビット3とビット4が逆に配線されていた。こういうトラブルシューティングは実に爽快である。配線間違いはFPGAのピンアサインでも修正できるが、あとのことを考えて半田ごてで修正する。

 よーし、写真がきれいに出るようになった。ただ、この液晶、輝度が高すぎて正面から見ると画像が白っぽく飛んでしまう。インバーターに半固定の抵抗をつけてブライトネスの調整をしてみたが、見やすい明るさまで落とすことは出来ない。液晶パネルは見る角度でずいぶん印象が違う。

液晶には最適な見る角度があるようだ。パネルを下からあおぎみるようにすると、黒がきれいに落ちて、画質が格段に向上することを発見した。逆に上からみるとパネルは白っぽくなって画像は薄く見にくくなる。フォトフレームは上から見ることが多い。早速、ディスプレイを天地逆にセットし、スキャン方向を今までのちょうど逆にして画像を出してみる。

Aa213328

 おおー、これは美しい。今まで輝度が大きすぎて白っぽい画が、色の良く出たまともな画像になった。これなら、フォトフレームとして十分実用になる画だ。ここではたと気が付いた。こちらが正位置なのだ。だから垂直方向の調整ビットが逆になっていたのである。

640×480のVGAは、7インチの液晶パネルの大きさで見ると非常にきめ細やかで、みごたえのある解像度になる。やはりQVGA(320×240)とは画質が格段に違う。試しに前のアナログ液晶のQVGAと一緒に映してみた。こうして直接比較して見るとQVGAとの差は歴然としている。今までの苦労が報われる美しさだ。

これはもう玩具の域を超えた立派なフォトフレームだ。実装が楽しみになってきた。 テスト画像を作ってくれた次女が感心してくれ、「欲しい。作って」とも言ってくれる(親孝行な奴だ)。

Aa253343

 しかし、12ビットカラーの明暗の段差はどうしようもない。単色では16階調しかないので、青空などははっきり等高線がついてしまいせっかくの解像度が台無しだ。微妙に色が変わるところは貼り絵的な段差になる。ここまできれいな画像が出るのなら、もう少し多ビットカラーに拡張したくなってきた。

JPEGデコードは現行のCQ-STARMでは無理とわかる(10/27/2010)
 フォトフレーム計画のロードマップによれば、次のステップ(第8ステップ)はJPEGファイルの描画である。実用的なフォトフレームにするには是非実現したい機能である。 FPGAの方が一段落したので、JPEGライブラリの方を本格的に調べ始めた。JPEGについては、以前から実現する方法をウェブで調べている。

 ウェブの検索では、いくつかのサイトがヒットしていたが、詳しく調べると、これらは、すべてオープンソースのfreeJPEG(IJG)がオリジナルであることがわかった。何と、このブログにもときどきコメントを寄せてくれる、ねむいさんや、そら。さんも、このJPEGライブラリを実装されて動かされているようだ。これは心強い。いざとなったら教えてもらえる。

 しかし、オリジナルのサイトのreadme.txtで確認したところ、現在の基板CQ-STARMではSRAMの容量不足で実装できないことがわかった。がっくり落ち込む。この付録基板のCPUは、STM32F103VBT6でフラッシュが128KB、フラッシュは何とか入りそうだが、SRAMは20KBしかない。

 IJGのJPEGルーチンは、デコード時、最小でもバッファーメモリは24KBを必要とするようで、ここに詳しい報告がある。この付録基板(CQ-STARM)は、ねむいさんが以前STM32F107VC6(フラッシュ256K、SRAM48K)に換装されておられ、私もこのあいだDigiKeyに発注してあるのだが、在庫切れでまだ到着していない(3ヶ月以上待たされている)。

 そういえばこれとは別に、STM32F103VET6を買ってあったのを思い出した。これはSTM32Primer2の石の予備に買ってあったものである。これは同じ型番の石なので問題なくピンコンパチでCQSTARM基板に換装できるはずだ。これなら今すぐにでもできる。 

 とはいえ、現在機嫌良く動いている基板のCPU換装は何となく気が進まない。¥3000も出せば、512KBフラッシュ、SRAMが64KBの同じ石のARM基板が買える。迷いどころである。

 ということで、方針が固まるまで、FPGAのSRAMを増設して15ビットカラー(3万2千色)にする方を先に着手することにする。

SRAMの増設も簡単には済まなかった(10/29/2010)
 液晶は18bitカラーだし、FPGAのピンも余っている。しかしメモリが512KBしかないので12ビットカラー(460KB)にした。SRAMを増設して1024KBにすれば、18ビット(690KB)まで出せるが、今度はコネクターを20ピンにしてしまっているので今のハードでは15ビットカラーが限度だ。転送時間のこともあるので、とりあえずの次の目標は、15ビットカラーにする。いずれにしても必要な、SRAMの増設にまずとりかかった。

Aa283374

 メモリ増設は色々なところで紹介されているように簡略なSRAMチップの2階建て(Piggy Back)方式で実装することにする。同じアドレス、データ線を使い、アドレス最高ビットでOE(OutPut Enable)を用いてバンク切り替え(OEの意味が始めて分かった)する。OEとWEを独立させて制御すれば、簡単に動くはずだ。

 SRAMの変換基板を重ねるため、最初ピンヘッダーで重ねようと、ローハイトのピンヘッダーを準備して、一方のピンが変換基板の穴に入るよう細く削りだした。しかし、全部の削りだしが終わる頃、SRAMがFPGA基板のソケットの下に半田付けしてあったことに気が付く。しまった。ピンヘッダー経由では高さがあってFPGA基板の下側にはいらない。

 仕方がないので、強引だが0.5ミリ錫メッキ線を一本づつピンポストに立てて半田付けし密着させることにする。始めてこずったが、写真のように一旦テープで線を揃え、基板の穴を通して一度に半田付けするとうまく行くことがわかった。

Aa283370

 2階建てが終わった。12ビットカラーでひとまずSRAM増設のテストをする。しかし、思ったようには動かない。

 トラブルの切り分けのため、まず2つめをdisableにして動かす。これは問題なく動いた。それではと増設したSRAMのテストをする。しかしこれは単独でも駄目だった。2つめのSRAMのハードが疑われる。ただ、読み込みはやっているようだ。

 ハードをチェックする。まずはピンアサインから。おやおや、WEのピンの場所を1つ間違えていた。何度も確かめてピンに印をつけてあったはずなのに、この印ごと間違えている。情けない。2段になったピンアサインは本当に間違いやすい。

 これを直して、2つ目もやっとデータが書き込まれた。しかし、何ラインかごとに画像が櫛のようにずれる。うーむ、これもハード臭いな。画像がずれるのは、データではなくアドレスがおかしい。2段重ねの導通をテスターで何度も測る。問題ない。ショート?それなら一つ目からおかしくなるはずだ。それはありえないと、独り言を言っているとき、変換基板のICチップのピンの半田付けがやけに薄いところを見つけた。

 ルーペで確認する。ついているようなついていないような微妙な半田付けだ。テスターでは導通している。問題なさそうだが、どうもここしか考えられない。だめもとで半田付けをやり直した。

 よーし、やっぱり半田付け不良だった。2枚目のSRAMも正常に画像を蓄積し表示ができるようになった。テスターでの導通は、プローブで押さえたためと思われる。

 2枚のSRAMの切り替えのテストも手間取った。最初、2つ目のSRAMの動作を止め、スタートアドレスをいくら1枚目の後半にしても画像が切れない。アドレスの最高位ビットを何度も計算しなおし(ワードアドレスなので混乱する)、19ビット目のビットが立てば、2枚目のSRAMをアクセスしに行き、データがないので真っ白になるはずなのだが、そうならない。

 今度はソフトだ。さんざん調べた結果、原因はこれも意外なところが犯人だった。追加したステートメントではなく、ソースリストの最後の書き込みと読み込みアドレスを区分するassign文のビットが拡張されていないという単純なミスだった(19ビット目が全く無視されていた)。

 これを直して、無事、SRAMをまたがって画像が蓄積された。これで1024Kのビデオバッファーが実現した。今度のミスは配線間違いとハンダ付け不良というハードミスが2つ、ソフトのうっかりミスが一つ、SRAM増設にともなうVerilogHDLのコードの方はすべて思ったように動いてくれた。HDLコーディングに大分自信がついてきた。

Aa313384

15ビットカラーが出た(10/31/2010)
 メモリが増設できたので、残るは15ビットカラー化である。STM32プロセッサーとFPGAのロジックを修正する。FPGAの方は12ビットカラーに比べると格段に楽になった。ステートマシンは不要で、メモリを取り出し、16ビットを5:6:5に配分するだけである。STM32の方は少し難しくなる。奇数回での送出になるので、バッファーの切れ目にどこで遭遇しても取り間違いが出ないよう、SDカード読み出しを関数にして何度も呼び出す必要がある(最初これに気がつかなくて、前と同じ縞模様が再現し、冷や汗をかいた)。

Aa253353

 内部処理を外部関数に切り出すのは、C言語では変数のスコープが大きく変わるので非常に気を遣うのだが、この際、泣き言は言っていられない。何しろここの世界は何十年のキャリアがある。弱みを見せるわけには行かないのだ。コンパイルする。何とかエラーは出さずに済んだようだ。これで動けば良いが。

 ハードの作業が残っていた。15ビット用の3本のデジタル色信号線を追加して、それぞれRGBに追加する。論理合成、ピンアサインも順調に済み、いよいよ通電である。STM32のUART端末で恐る恐るファイルを指定する。

 出た。STM32の修正も問題なく、15ビットカラーが出た。単色のグラデーションはまだ段差が目立つ(32階調)が、青空は何とか目だたない程度までなくなった。全体に画像がしっとりした感じになる。いやあ、これならフォトフレームとしても大威張りだ。

Aa263359

 次に何をするか迷っている。やっぱり今動いているCQ-STARM基板のCPU換装か。それとも別の基板を買ってくるか。

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

2010年10月19日 (火)

フォトフレーム:最後まで難航したが遂に成功

 久しぶりに晴れ晴れとした気分でブログを書いている。そう、悪戦苦闘していたLattice XP2基板のFPGAデジタルフォトフレームが、やっとのことで想定どおりの640×480ドット12ビットカラーの画像をBMPファイルから描画するようになったのだ。

 フォトフレーム計画(プロジェクト)を立ち上げて、ほぼ7ヶ月。今年のがた老AVR研究所はほとんどの時間をこれにあてていた。毎日のように一喜一憂していたが、遂に第7ステップのBMPファイルの描画に成功した。当面のゴールである。嬉しいというより背負っていた重い荷をおろしたときのような解放感が強い。

 綺麗な画がでるまでは、本当に暗かった。何度もプロジェクトを投げ出しそうになった。その度に気持ちを奮い立たせて元へ戻った。たかが趣味で何でこんな苦しい思いをするのか時々馬鹿馬鹿しくなるが、うまく行ったときの快感が忘れられない。前にも書いたが、相当中毒が進んでいる。

 思い通りにならない時は、世の中すべてが自分に反対しているように見え、今までの生き方そのものが否定されているような暗澹たる気分になるのだが、一旦解決したとなるともう有頂天、まるで天下をとったような気分になる。これだから電子工作はやめられない。

ピクセルのずれが直らない(10/10/2010)
 前記事にあるとおり、XP2のフォトフレーム基板に何とか画像らしいものが出て、あとはもう一息、微調整で上手く行くという考えは甘かった。どうやっても、まともな画像になってくれないのである。

 左右の逆表示は、液晶モニターのスキャン方向ビットの調整(この液晶のデータシートの垂直方向指示ビットは間違っている。0->上から 1->下からが正しい)で直ったが、ピクセルドットの食い違いによる不具合はどうやってもうまくいかない。

Aa123286

 12ビットカラーは6バイトで4ピクセルを表現するので、1ピクセルでもずれると、とんでもない色になってしまう。連続しているところはちゃんと12ビットをとりだしているのだが、1ライン(640ドット)描いた次のラインで、SRAM読み込みがスタートせず、1ドットずれてデータが入り、48ラインごとに元の状態に戻り、結果として縞模様の斜めにずれた画像になる。

 状況は、画面の状態から良く分かるのだが、これをどう解決するかの方策が見つからない。1ライン中の連続表示ではうまく行っているので、ラインのスタートのときにSRAMアクセスのトリガーをかけてやれば、良いように思えるのだが、どんなあわせ方をしても斜めの縞模様は解消できない。

 描画範囲と、画像の幅は1ピクセルでも違うと、大きく左右にずれる。しかしこの傾きは微妙だ。ドットで言えば、40ピクセルくらいしか傾いていない。縦の行は480行あるので、12行について1ドットの勘定だ。

 ピクセルドットの計算違いや、SRAMのアドレスインクリメントの狂いで、こんな微妙な違いは起こらないことに大分経ってから気づいた。FPGAの中のビットハンドリングがどこかで変調をきたしている。

 非同期アクセスか、ハザードの問題だろうか。ステートマシンのグレイコードをいじってみたり、非同期だったSPIのCS信号を同期させてみたり、SRAMアドレスハンドリングを調べてみたりするが、状況は全く変わらない。

 いくつかBMPファイルを入れてテストしてみるが、みな同じ現象。画像データそのものを疑ってペイントソフトが作ったファイルをバイナリエディターで確認するが問題なし。現象ははっきりしているが、原因がわからないので解決できない。

やっぱりバグは外にあった(10/13/2010)
 ひとつめの不具合、画像が斜めに傾く現象は、意外なところが犯人だった。最初、FPGAのビットハンドリングをしつこく調べていたが、どうしても不具合を発見できない。少し冷静になって「デバッグは外へ、外へ」の鉄則どおり、データを送り出すところから調べてみることにした。

 SPIからのデータは、BMPファイルのヘッダーを取り除いた色信号そのもののデータが果てしなく続くデータストリームである。ここで1バイトでもずれたら画像は間違いなく斜めになる。しかしコードはSDカードの読み込みブロックサイズを意識せず、ブロックをまたがってもちゃんとデコードできるようになっている。ずれるわけはない、うっ、待てよ。このブロックの終了条件、おかしくないかい。

 うはあ、大小比較は等しいときはFalseだ。これだ。1バイト、ブロックサイズを行き過ぎている。2KBごとに1バイト、1ライン960バイトなので3ラインごとに1ドット(12ビット)ずれる理屈だ。これだこれだ。あせる手でSTM32のコードをコンパイルしなおし、テストする。

Aa143291

 良いぞ、画像の傾きは直った。しかし、3原色の背景は少し色が出てきたが、まだ縞模様のままで本来の色ではない。次の不具合、色を正しくするトラブルシューティングだ。

「デバッグは外へ」にならって、送られてくるSPIの画像データをロジアナでさらにくわしく調べる。うーむ、でだしのところから既におかしいぞ。今のロジアナはプロトコルアナライザー機能がないので、8ビット波形を手でデコードしてみるが、明らかにBMPファイルの通りになっていない。

 どうも、8ビットデータの処理を間違えているのではないか。データのシフトがおかしい、おや、この<<(ビットシフト)が式全体にかかっているように見える。ああー、C言語の文法を間違えている? 参考書を確認する。 そうだ、+(プラス)の方が<<より優先順位が高い。今のコーディングでは4ビットシフトしてデータをつけたすのでなく、全体に足してからシフトしてしまう。括弧が必要だ。

 よーし、縞模様になる原因はわかったぞ。これで問題は解決だ。意気込んでコンパイルし、テストする。画が出るのをわくわくして待つ。あれえ、縞模様は消えない。前より少し色が出たようにも見えるが、本来の赤は緑がかった青に、青は黄色になり黒い細い縦線が残ったままだ。期待していただけに、反動ですっかり落ち込む。

高性能のロジアナを注文してしまう(10/14/2010)
 負けず嫌いの当研究所の所長は、こういう状況ではたいてい意地になる。こうなったら徹底的に原因究明をしてやる。ちょうど良い機会だ。これまで欲しくても我慢していた、200Mhzのロジアナ(ZeroPlus LAP-C16128、¥38,800 )を勢いで注文してしまった。深夜にネットで注文し、振込みもネットですませる。

 2日で到着した。おお、これは便利だ。ソフトが充実している。しかしプロトコルアナライザーでつまづく。標準で付いているSPIが設定できない。ラインが足らないと文句を言われる。BUSにはちゃんと3本定義した。思いあぐねて夜中の1時半、販売元のストロベリーリナックスに到着の報告も兼ねて問い合わせのメールをした。

Aa143301

 何と30分後に回答が帰ってきた。その日はもう気力がなかったので、次の日テスト。何だと、CTRキーを押しながらadd channelしないと同じバスに入っていかないという。マニュアルにあるのかもしれないが、読みきれない。早い回答があるというのは、FAQなのだろう。

 CTRキーを使わなくてもバスに最初に設定したラインを右クリックしても同じことができることがわかった。知ってしまえばなんと言うこともない設定だが、概念を理解していないと難しい。

W1014

 しかし、やっぱり道具や測定器には金をかけるものである。次々に新事実が明らかになってきた。プローブがまともなので測定が手軽に出来るのが良い。それにこのクラスのロジアナには、まだ使っていないけれど0.5ミリピッチICにもつけられる極小のプローブ16本がサービスでついている。お買い得だ。

 SRAMアドレス、制御線、カラー信号などつけられるだけのプローブをつけてタイミングチャートを出し、何度も測定した結果、明らかになったのは、

 ・色信号が安定して出されていない。データによるものか、FPGAのコードによるものか、FPGAの出力ピンのハードの影響か今のところわからないが、単純な単色の色コードが周期的に描画されている(画像の通りだけれど)。

・個別の色はでたらめだが、全体としては想定どおり(カラーバー)の色信号が出ている。つまり4ビットカラーの送出シーケンスに誤りがなく、中のデータだけが問題である。

・SRAMアクセスは完全にうまく行っている。

W1015

何のことはない原因はやっぱり単純なミスだった(10/17/2010)
 ロジアナの測定で原因がだいぶ絞られてきた。FPGAの描画プロセス、SRAMの読み込みには、ほぼ問題がない。不具合はやはり、送られてくるデータと、それをデコードするプロセスのところにある。

順番としては、SRAMに本来の12ビットデータが入っているか確認するのが先だ。UARTを復活させて16進表示でSRAMの中味を別の手段で確認しようとしたが失敗する。画像データをスキャンさせながらUARTを動かしてSRAMの中味を誤りなく表示させることは難しい。垂直同期期間だけUARTを動かそうとするが、どうもエラーが出るようで表示するたびに内容が違う。

 万策が尽きた。少し開発の手を休めて家族と買い物に行ったりする。こういう気分転換がデバッグに効果があるようだ。いずれにしてもSRAMは間違いなく読んでいる。STM32は、画像データをデータブロックなしに果てしなく500KB近くをSRAMに送り込んでいる。それで狂いもなく一画面分が表示されるのだから、FPGAのハザードやノイズで色が変わるならもっとランダムに色が変わらないとおかしい。現在の画はきれいに縦線が揃っている。

 16ビットのSRAMへの送り込み、取り出しはUARTの時に2バイトコードで正しく処理されていることを確認しているのであまり深く調べてこなかったが、どう考えてもここで何かが間違っているとしか考えられない。しかし、何度見返してみても16ビットデータは最初の24ビットBMPファイルから4ビットを3つづつ取り出し、それをSRAMに貯めこんでいる。SRAMから取り出す順序も間違っていない。

 ところが、ロジアナで見たRGBデータの組み合わせ(赤一色が青と黒のまだらになる。画面もそうなっている)は、SRAMデータのMSBとLSBを逆にすると赤一色からその色の組み合わせになることが紙の上でわかった。うーむ、もしかするとこれかもしれない。

 半信半疑だけれど、もうやることがない。おかしいとは思うが、これを逆に(SPIで受ける時upperバイトとlowerバイトを逆にする)して見る事にした。おおー、何ということだ。逆にすると、カラーバーを入れたテストファイルの画面が見事に原画と同じように表示されたではないか。

Aa173314

 ばんざい。ばんざい。これまでUARTで動いていた順序を逆にしたわけだから、おかしくなるはずなのだが、現実には綺麗に画像が出ている。理屈はわからないがうまく行ったことだけは確実だ。嬉しくて記念撮影をする。ここ一週間ばかり頭を悩ませていた問題が遂に解決した。 

 とにかく嬉しい。ガッツポーズをしながら部屋の中を歩き回る。これまでの暗い気分がうそのように晴れて、体中に充実感がみなぎる。この成功した時の気分がたまらない。しかし、今度は本当に大変だった。もう少しでこの計画を断念するところまで追い込まれていた。諦めずに粘った甲斐があった。

 興奮が納まって改めて冷静に原因を考える。何故以前のUARTでは問題にならなかったのだろう。そうか、UARTは8ビット単位だったのでSRAMに入ったものをそのまま返すだけで問題にならなかったのだ。今度は、バイトをまたがってデータを作り直している。SPIはMSBファーストだが、SRAMに入るときは丁度逆になるようだ。

 その証拠に、テスト画面でなく、昔のデジカメの写真(640×480)を出してみると見事にネガ写真になった。そう、色信号まで逆なのだ。これはFPGAのピンアサインを逆に設定し直して、無事、写真もそれらしく出た。まだ、どこか不具合が残っていて少し色がおかしいが、これまでの化け化けの写真と違ってだいぶましな画像になった。

Aa173315

 とにかく、フォトフレームプロジェクトはこれで一段落した。教訓は、言い古された表現だけれど、「デバッグは外へ、外へ」「大丈夫と思ったところが危ない」「デバッグに疲れたら別のことをやって気分転換」だ。最後に今まで疑っていたFPGAやSRAM、STM32などハードのみなさん、この場を借りてお詫び申し上げます。疑って申し訳ありませんでした。

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

2010年10月10日 (日)

フォトフレーム: 画像らしいものが出てあともう一息

デジタル液晶も画面が真っ暗(9/30/2010)
 どうも何かに呪われている。フォトフレームのHDLソースのロジック追加は、擬似コードレベルからのコーディングは特に問題なく完成し、論理合成やコンフィギュレーションも順調に終わったので、通電したのだが、画面には何の反応もない。オシロで見る限り同期周波数も、色信号も規定どおりに出ている。しかし画面はアナログ液晶のときと同じように真っ暗なままである。

 いったい何が悪いのだ。手探りで作ったPLLは見事に33Mhzのクロックを逓倍して62Mhz(正確には61.875Mhz)のマスタークロックを作っている。デジタル液晶のピクセルクロック31Mhzも正確に出ている(実際は30.938Mhzだが)。同期信号も所定どおりの間隔で出ていることをオシロで確認した。

 今度の液晶はピクセルクロックと、色信号の出る間のDATAイネーブル信号を要求しているが、これも想定どおりちゃんと入っている。それなのに、どうして画面に何もでてこないのか。SRAMにデータを書き込まないで描画すると、メモリのランダムな値でちょうど砂をまいたような画面になるはずなのだが、全く暗いままだ。このままでは何の手がかりがない。何処から手をつけてよいのかわからない。やっぱりカラーバーから確かめていくしかないか。

カラーバーも真っ暗(10/2/2010)
 SRAMからの描画をあきらめて、わかりやすいカラーバーを出してみることにする。急いでコーディングし、試してみた。しかし、こいつも駄目である。ところが、電源を切ろうとして一瞬カラーバーが出た。ありゃあ、前と同じだ。過渡的なときには色が出るが、一旦電源を入れてしまうと出ない。前のアナログ液晶と同じである。良く画面を見てみるとカラーバーがうっすらと出ているのが見えている。しかし、そのうちもっと暗くなって、画面は視認できなくなる。

 何が原因なのだろう。デジタル液晶なので色信号の電圧はLVTTLだ。オシロにもきれいな3.3Vパルスが出ている。DATAイネーブルを疑ったが、ここは正論理で間違いなく正しいピンに所定の描画サイクルで出ている。このデジタル液晶はピクセルドット周波数を要求する。この立ち上がりと立下りのどちらでRGBデータを拾うのかはデータシートに明記されていない。まさかと思うが両方やってみる。もちろん状態に変化はない。

 電源を切ったときとか、入れた瞬間に鮮やかな色が出て、定常になると色が消えるというのが不可解だ。何かの条件が色を出すのを止めている感じだが、この条件が見えない。
前のアナログのときと同じような状態というのが気にかかる。

S_aa033247

遂に鮮やかなカラーバーが出た。原因は意外なところ(10/3/2010)
 ここ数日は暗い日々だった。苦労して作ったデジタル液晶が、このあいだのアナログ液晶と同じように、まともな明るさにならない。ピクセルクロックもデータイネーブルも規定どおり、水平・垂直同期も正確に出ている。色信号もオシロで見る限り正常。しかし、画面は暗いままである。前と同じように電源投入直後は少し明るいが次第に暗くなる。この次第に暗くなるというのが何ともおかしい。

 原因がわからない。液晶パネルのドット描画のロジックが良く見えていないので対策のしようがない。ピクセルクロックの立下りでデータを拾う仕様で、データが逆に出ていたら真っ暗になるのかとか妄想してみるがピクセルデータは期間中、同じ値(のはず)であり、そんなわけはない。同期の裏側で描画しているから? そんなことあるわけない。

 アナログの場合は、色信号の電位差で明るさが決まるが、デジタルは各ビットが1であれば問題なく何らかの色は出るはずである。電源を疑ってケースを開け、それぞれの接続を確かめ、パネルに近いところで波形や電圧を見る。電源は少しパルスが乗っているが、3.05Vと正常範囲内だ。しかし、レギュレーターが、触った時火傷しそうに熱いのに気が付いた。

 一段目のレギュレーターは液晶パネルのバックライト用の12Vから5Vにするため7V分を熱にしているからだが、ちょっと熱すぎる。熱抵抗を計算してみると最初のTA48M05(500mA)では125°C/Wでヒートシンクなしでは少し苦しい。大きめのレギュレーターTA4805S(1A、62.5°C/W)に換えてみることにする。

 換装して電源を入れる。お、ほんの少し画面が明るくなったように見える。しかし大勢に影響はない。解決策をもとめてウェブを探していたら他社の液晶パネルのデータシートが見つかった。そこにはロジック部の消費電流が出ている。そういえば、この液晶のデータシートには、ロジック部の消費電流が記号でTBDとあるだけで実数値が出ていない。ウェブの消費電流の方を見て驚いた。5Vで120mA、3.3Vでは160mAも流れると書いてある。

 ロジック部の消費電流がこんなに大きいとは思っていなかった(100mA以下とみていた)。3.3Vのレギュレーターは例のLPCMプレーヤーに入れてビートが出たため使っていないXC6202である(8ヶも余っている)。 150mAとれるので余裕と思っていたが足りない可能性がある。これはいけない。この液晶パネルの実際の消費電流を測ってみた。

 結果は125mAで、XC6202の定格内だ。こちらのレギュレーターは熱もそうない。電圧もちゃんと3.05Vでている。しかし、これまでの状況から、どうも電源が臭い。調べるところがなくなって、だめもとで別の3.3V電源アダプターでロジック部を供給することにしてみた。

 何と、何と、これで液晶モニターに鮮やかな色が戻ったのである。ええー、オシロで測った今までの電源電圧は一体なんだったのか。きれいな3原色が表示される。夢にまで見た鮮やかさである。

 また、XC6202が悪者になってしまった。こいつが力不足で120mAを消費するロジック部を正常に駆動できなかったのだ。定格内なのにおかしいが、これが原因であることは間違いない。急いで、500mAとれるTA48M33にしてみる。鮮やかな色が出た。結局、電源容量不足という単純な原因が画面が明るくならない原因だった(あとでデータシートを良く見たら電源の最小電圧は3.135Vだった。たった0.085Vの差で真っ暗になるとは)。わかってしまえば何でもないが、ここにたどり着くまでえらい時間がかかった。

S_aa043267

SRAMを読んだ画面が出た!(10/6/2010)
 液晶に色が戻ったので、ロジックを更にいじって、カラーバーを上段に、コメントアウトしてあったSRAMの内容を表示するルーチンを生き返らせて、下段に出すレイアウトにする。出ました、出ました。まだSPIが動いていないのでデータは更新できないが、SRAMのランダムなデータを拾って、ちょうど大理石模様のようなこまかい画像が表示された。

 今までは、縦縞ばかりだった(1ライン中のデータが同じままのとき)が、これはSRAMを順調にラインを越えてアクセスしていることを意味する。いやあ、嬉しい。これまでの暗い気持ちがいっぺんに吹き飛ぶ。これで画像表示まで大きく近づいた。しかしそれにしても長い道のりだった。この爽快感はいつ経験してもこたえられない。ランナーがマラソンにはまるのと同じである。苦しみが大きければ大きいほど、喜びが倍増する。

 いよいよ次は実際の画像の確認である。SPIから送られた画像データが表示出来れば、フォトフレームの第7ステップ(一期完成ステージ)は完了する。STM32プロセッサーのBMPデータの抽出コードはまだ出来ていないので、とりあえずSPIの動作を確認するため、UARTでSRAMを確認できるようにする。

 データ読み込み中は画面を止めることにしたので、SPIの動作を優先しSPIデータが入る(チップセレクト)とただちに読み出しを停止するように変更する。UARTは別のSRAMアドレスを用意し、画面の垂直ブランクの時だけSRAMをアクセス出来るよう、assign文で読み込みアドレスの切り替えを2段にする。

 VerilogHDLの変更が終わった。わくわくしながら電源ON。しかし、データを送れば画面はかわるものの一色でぬりつぶされ、UARTからはデタラメな文字しか出てこない。かえって退歩してしまった(最初はSRAMを読んでいる証拠の砂模様画像だった)。まあ、これからが勝負である。ひとつづつつぶしていこう。

やっとのことで画像らしいものが出た。あと一息(10/8/10)
 FPGAのソースコード開発をひとまず横に置き、画像ファイルを送るSTM32側の開発を再開した。BMPファイルを読み、ヘッダー情報からRGBデータだけを抽出して、FPGAにSPIで送るロジックの開発だ。

 24ビットのRGBデータを12ビットRGBに抜き出すロジックは、はじめSDカードからの読み込みの単位で処理を考え、読み込みブロックをまたがるRGBの分離に頭を捻っていたが(RGBは3バイトで1ピクセルを構成するので、端数が出る可能性がある)、これは発想の転換でいっぺんに解決した。いや気分が良い。

 つまりプログラムはRGBをとりだす処理の方をメインループにし、ブロックサイズを越える時点で、次のSDカードを読む処理を入れてデータブロックを更新すればよい。今まであれこれ悩んでいた継ぎ目でのロジックはこの方法では考える必要がない。一気に解決した。このあたりがソフトウエア開発の醍醐味だろう。幾何でいう補助線一本で証明が出来たときの快感と同じである。

 機嫌よくコーディングを終えて、BMPファイルを用意する。ペイントプログラムはどうもピクセル単位にキャンバスを作れないようなので、一旦ペイントで適当に画像を作り、デジカメについていたおまけソフトで640×480のピクセル24ビットBMPファイルに切り出す。

Photo

 さあ、これで画像ファイルも出来た。PCでSDカードに移し、STM32のSDカードスロットに入れて、FPGAに送り込む。さあどうだ、FPGAは、その後UARTを止めたりして前の状態に戻しSRAMが読める状態になっているはずだ。あれえ、全く変わらない。

 SPIは読んでいるようだが(LEDが点滅)、SRAMにちゃんと書いていないようだ。こうなってくると、もうオシロは役に立たない。ロジックアナライザーの出番である。FPGA基板のコネクターに例のスタブ(0.5mm銅線)をたて下位のSRAMアドレスやいくつかの制御線にプローブをあて慎重に解析を開始した。

 今度のソースはこれまでになく複雑になっている。画像を出すロジックは、同期信号を作成するモジュール、色信号を所定のドットに乗せるロジック、12ビット色信号を16ビットSRAMデータを読みながら作るロジックの3段が並行し、これにSRAMを読むモジュールと計4つのプロセスが同時に走る。

 ロジアナの威力はやはりすごい。次から次に不具合が見つかっていく。しかし現在のロジアナの限界が見えてきて解析が順調に進まなくなった。今使っているロジアナは、2年前に買ったオプティマイズの100Mhz、32CHの安いけれどなかなかの性能で、これまで重宝してきた。

 しかし、今のFPGAのマスタークロックは、62Mhzでピクセルクロックは31Mhzである。ピクセルクロックくらいまでは見えるが、60Mhz台のSRAMアクセスのタイミングを正確にとることは難しい。実際に、このタイミングをはずしているのかロジアナが捕まえられなかったのかがわからないのでは解析しようがない。うーむ、「すん」さんがこのあいだ買ったという200Mhz台のロジアナが欲しいな。少し高いけど(¥38,800)。

 それはともかく、とりあえずは先に進まなければならない。コードを少し修正しては、ロジアナでタイミングを調べ、さらにおかしそうなところを修正してタイミングチャートを調べる。RGBをぬきだすところと、画面に出すところのタイミングが少しづつ合ってきてSRAMのアクセスが順調になってきた。ドット単位にアドレスが増えていく。

Wvga

しかし、SPIで入れたデータがどうしても順調にSRAMに書き込まれない。出来る時と出来ない時がある。散々調べた結果、原因は、やっぱりFPGAのコードではなく外であることがわかった。やれやれ。

 STM32のCS(チップセレクト)が間違っていたのである。データを送る以前に正しくCSがセットされていなかった。これを直すと画面のSRAM初期画面と明らかに異なる画面が出た。ちょうど水平同期が乱れた時の横線である。これだ。SRAMに新しくデータが送られた証拠である。画像のサイズが狂っているので横流れになっているが、これを補正していけば画像になるはずである。

 今度のデジタル液晶は、800×480のWVGAなので汎用性を持たせるため、両側の80ドットを黒くして画面を640×480にしている。もしかしたらSRAMアクセスは黒いところも動き、画像を縦の長さを無視して展開しているのではないか。ソースコードをいじって640ドットだけSRAMを読むようにする。

 出た。元の画に較べれば、色は殆ど出ていないし、表示が斜めに傾き、画像がちょうど裏になっている(スキャン方向を間違えている)が、明らかにBMPファイルの画像の絵である。フォトフレームを志して半年、はじめて出た記念すべき画像だ。

S_aa093281

 いやいやそれにしても普段何気なく使っている映像機器の画面表示の裏にはとんでもなく複雑なロジックが動いていることを実感する。スクラッチから静止画をひとつ出すのにこんなに苦労するとは正直言って始める前には想像もしていなかった。

 ここまでくればもうあと一息である。ハードや画面描画には問題なくなったので、あとは中のRGBデータのハンドリングを正しくしてやれば、ちゃんとした映像になる見通しがついた。デジタルフォトフレームのプロジェクトもそろそろ大詰めが近い。

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

2010年9月28日 (火)

フォトフレーム: デジタル液晶インターフェース実装

 完成を目の前にしてプロジェクトの進行が足踏み状態である。遅れの原因は今度は仕事ではなく、久しぶりの海外旅行のためである。海外と言っても、お隣の台湾で、それも台北近辺のみ。家族で3日間中華料理をいやというほど堪能してきた。お陰で体重が2キロも増えて、食事制限中である。

Photo

 家族と一緒だったのと、日本と大差がないと聞いた台北の電脳街には結局足を伸ばさなかった。ただ町を歩いていて気が付いたのは、LED電光掲示板がやたらに大きくて、どこにでもあることである。お寺のお札を売るところにも大きな電光表示板があるのには驚いた。

Photo_2

 それはともかくフォトフレームプロジェクトである。この間はもう完成だと浮かれていたが、調べてみると、まだまだやることが沢山あることがわかって頭を抱えていた。16ビットアクセスが出来るようになったが、液晶とFPGAをつなぐコネクター周りはまだ全く実装ができていない。今度はデジタルなので、20本以上の配線が必要である。この工作だけでも結構大変だ。

 それに、現在のSRAMでは(512KB)、VGAでは16ビットカラー(614KB)でなく、12ビットカラー(RGB444、4096色、460KB)しか出せない。SRAMからアクセスした2バイトのデータを4ビットづつRGBに展開していくロジックも必要である。QVGAデータをVGAに展開することも出来るが、ピクセルを合成するこちらのロジックはもっと大変である。

16ビットデータからRGB12ビットを取り出す(9/11/10)
 元のBMPの24ビットRGBファイルデータを、SPI8ビット、SRAM16ビットを経由して、ピクセルクロック単位に、4ビットづつのRGBデータ12ビットを切り出すロジックを少しまともに調べ始めた。

 24ビットBMPデータからSPIで送り出すところは各RGB8ビットから上位4ビットを取り出し、8ビットバッファーが埋まれば次々にSPIに送り出すだけで良い。受け取った側は何も知らずにただSRAMに書き出す。ここも問題ない。やっかいなところは、SRAMから読み出した16ビットデータを12ビットづつRGBに展開するところである。

 ピクセルクロックが早くなっているので、ここの余裕は全くない。うーむ、やっぱりマスタークロックを少なくとも2倍にしないと、このあたりの処理は無理なようだ。あれこれ考えた末、動くがどうかは自信がないが、出来たのは次のロジックである。

・SRAMからの16ビットデータを、一旦、バッファーに読み出し、このバッファーを2つ用意する。

・ステートマシンを4 段作り、ステート毎にRGB4ビット、12ビットを取り出し、残った
データを消さないよう、バッファーを換えて次のSRAMアドレスからデータを読み出す。

・4段終わると、最初のアライメントに戻るので(12×4=16×3)、最初のステートに戻る。

・以上の処理を行うサブモジュールを、描画プロセスとは独立して並行に走らせ、描画プロセスは、このサブモジュールが作った4ビットRGBを次々に液晶データラインに移すだけとする。

・サブモジュールの起動/終了は、画面1単位、つまり垂直同期のあとの最初の水平同期がトリガーとなる。終了は、SRAM最終アドレス。

FIFOが必要になった(9/13/10)
 ピクセルクロックとマスタークロックの差がなくなったので、新たな問題が発生した。プロセッサーからSPIでデータを受けるところにFIFOバッファーが必要になったのである。描画の最中はすべてSRAMのRead処理に占められ、Writeは出来ない。

 前は、1ピクセルクロックの間にマスタークロックは6回以上繰り返されるので、描画中も隙間を縫ってSRAM書き込み(2クロック)が入れたが、今度は空きがないのでSRAM書き込みは、水平ブランキングや垂直ブランキングの間に行わねばならない。

 640ピクセル描画するのに32ns×640ピクセル、20.5μsの間にSPIがデータを送ってきてもデータが書き潰されないようにするには、SPIが9Mhzで動いているので、1バイト0.88μsとして、24バイト以上のバッファーが計算上必要である。

 しかも、読み込みの間に万が一書き込みのリクエストが通ると、2クロック待たされ、ここで描画がおかしくなる。1ライン読み込みの途中では書き込みを止めるなどの措置をしないといけない。

 FIFOのコーディングはそう難しくないが、テストの方法が悩ましい。適当な画像ファイルを送っておいて、まず描画ルーチンを完成させ、そのあと描画中にファイルを送って様子をみるしかない。単独のテストは出来ない。

 ソースコードにかなり手を入れる必要がでてきた。旅行の準備も必要だ。集中して時間がとれない。とりあえずispLEVERの新しいプロジェクトを起こし、ソースをそっくりコピーして新しい機能を入れていく。まず、LatticeのIPexpressが提供するPLLモジュールでマスタークロック33Mhzを15/8倍の61.875Mhzにする(逓倍は奇数ができるが、分周ができないようだ)。これを半分にすれば、所定のピクセルクロック31Mhzに殆ど同じ(30.9375Mhz)になる勘定だ。

 このソースを作ったところで旅行の期日が迫ってきた。2匹の猫を預かってもらうブリーダーとの打ち合わせ、旅行用品の買い物、成田に前泊するホテルの確認など、電子工作どころでなくなった。

デジタル液晶のインターフェースを実装する(9/22/10)
 台湾から帰る前日に台風11号が台湾を直撃した。ホテルではNHKのBSが一部視聴できたので日本のニュースに不自由はしなかったが、台風は日本をはずれたのでニュースになっていない。台風情報は現地の放送を見るしかない。しかし言葉は全く分からないが漢字の字幕が出るし、台風の二ユースは似たようなものなので、これは面白かった。

 まず、嵐の中の中継が20年前の日本と同じ、新人アナウンサーが風に吹き飛ばされそうになりながら悲壮な顔でマイクに向かって叫んでいる。横ではオチョコになった傘を必死に支える通行人の背中のヤッケには○○新聞(TV局名)というロゴがすけて見えて、やらせであることが見え見え。家族で腹を抱えて笑っていた。

 帰りの飛行機が心配だったが、幸い半日遅れただけで台北の桃園飛行場を立つことが出来た。しかし離陸して5分もしない頃、乱気流に飛び込んで激しく降下し乗客が大きな悲鳴をあげる。台風が去ったといっても油断ができない。しかし、その後は平穏に成田に戻ることができた。いやあ怖かった。

 台湾も暑かったが、帰ってきた日本も相変わらずの暑さだ。旅行の後片付けも落ち着いて久しぶりにオーディオルームの電子工作机に戻った。液晶インターフェースの実装を開始した。

A9283246

 例の画像表示回路特集のトラ技(2009年11月号)の回路図を参考にする。クロストークや不要電波の放射を抑えるため、デジタル信号をなまらせるダンピング抵抗を入れるので思ったより複雑になる。それに液晶のフレキパネルの変換基板から直接FPGAにケーブルを出さず、ピン数を減らしたコネクターで中継したので、ハンダ付け箇所が2倍になり思ったより時間がかかった。

 やっとのことで配線が全て終わり、液晶パネルからフラットケーブルが出てFPGA基板につながった。アートワークのメモと一緒に記念撮影する。さて、ハードはこれで全部できあがった。次はSTM32プロセッサーのBMPファイルからのRGBデータ切り出しと、これまで擬似コードのレベルで止まっているVerilogHDLのコーディングである。何とか、個別テストを積み上げて開発ができないか頭を捻る。

想定されるテストの手順は、

・水平・垂直同期の確認(FPGAからの出力をオシロで確認)

・12ビットRGBデータの確認(描画を止めて、UARTのバイナリー端末で確認)

・SRAM読み出しの確認(ロジアナでSRAMアクセスをピックアップ)

・テスト用画像のBMP化(これは実際に画を出して確認)

・画像送出のテスト(同上)

でめでたくBMPファイルの画像が出るはずなのだが(第7ステップの完成)。

A9283241

木を見て森を見ずの諺どおりの勘違い(9/26/10)
 いよいよ、VerilogHDLソースを書き始めようというところで、重大な思い違いを見つけてすっかり落ち込んだ。旅行に出かける前に、SPIにはFIFOがいると書いていたが、もっと基本的なところに間違いがあった。あるとき(これまた風呂に入っているとき)、少しくらいのバッファーでは画像を表示し(読み)ながらデータを書くことができないことに気付き愕然とする。

 当初は、水平・垂直ブランキングの間にデータを書き込むつもりだったが、水平ブランキングと1ライン描画の時間の比は、WVGAで1ライン1000ドットとしてVGAの640ドットで2:1、垂直ブランクは9H(ライン)だが、縦は480本もあるのでFIFOバッファーは全体画像の半分近くなければ、SPIのデータはとりこぼしてしまう。

 やれやれ、以前のXbeeのUARTのバッファーのときと同じだ。ピクセルクロックの少なくとも2倍のSRAMアクセスのスピードがなければ、そもそも描画中にデータを書き込むことは不可能なことに早く気が付くべきだった。今はSRAMアクセスは2クロックを前提にしているのでピクセルクロックと同じだ。木を見て森を見ずという諺の通りである。

 画面を乱さずに画像を換えることは、この仕様では無理である。フォトフレームとして見栄えは落ちるが、一旦画像を止めて表示し直すという方法にするしかない。まあ画像がでたら、クロックを更に上げて、描画中にもSRAM書き込みが出来るような改修に挑戦してみよう(SRAMをもうひとつ付ける手もある)。画像を出すことが先だ。

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

2010年9月11日 (土)

フォトフレーム: デジタル液晶を動かす準備

 前回のブログから2週間以上日が空いてしまった。珍しく連続して仕事があり電子工作に時間がとれなかったこともあるが、何かひとつ大きな懸案が解決すると暫く気が抜けてやる気がなくなるという、いつもの癖でもある。

 こういうときは、細かい手仕事か全然別の工作のことを考えて気を紛らし、意欲が復活するのを待つ。そういうことなら、リニアPCMプレーヤーを作ったお陰で、最近音を出す機会が急に増えたオーディオ装置に手を加えたいものがある。この装置は昔々、オーディオに凝っていたときに揃えたQUADのセット(405、44、CD67)と、タンノイのスピーカー、Berkeleyである(憧れのAutographまでは手が出なかった)。

A9103077

 音域は広くないが落ち着いたクラシック向けの音で30年近く愛聴している。スピーカーは、さすがに最近、音に艶がなくなった(近々修理に出す予定)が、アンプは一度電源コンデンサーを交換したくらいで元気に音をだしてくれている。

 しかし、リモコンに慣れた体には音量調整にいちいち装置まで腰を浮かすのがつらい。電子ボリュームというICがあるのは知っていて、いずれはリモコンを自作してやろうと思っていた。それがウェブをさまよっていて、TI(BurrBrown)のPGA2311というICを見つけた。こいつは他の電子ボリュームICに較べると、値段は3倍以上するが、歪み率が2桁近く低いことがわかった。どうも高級オーディオ用のICのようだ。3倍以上といってもDigikeyで一個¥1000近辺で買える。

 ちゃんとしたオーディオセットにはこれくらい奢(おご)ってやりたい。急にリモコンが作りたくなってきた。仕事の帰りに久しぶりに秋月に寄り、沢山ある赤外線受信モジュールのひとつ(シールド付き、PL-IRM0101-3 ¥110 )を買ってきた。ロジアナにつなぎ、リモコンを当てると、さまざまな波形が即座に見える。フォトフレームそっちのけで、ウェブを見ながら家中のリモコンを片っ端から試して面白がっていた。

I00622

 そのうち、いつもこのブログにコメントを寄せてくれるshuji009さんが、電子ボリュームを使った工作を計画していることを、すんさんの電子掲示板で知った。うーむ、どちらも示し合わせて始めたわけではない。何か同期しているようだ。そんなこんなでフォトフレームプロジェクトの方は進捗が遅い。でも、少しづつ作業は進めている。

デジタル液晶の準備(8/31/2010)
 半かけで放置してあったデジタル液晶のケースの工作を再開した。この液晶は、アナログ液晶と一緒にAitendoの決算バーゲンで買った7インチのWVGA(800×480)のワイド液晶パネルである。韓国製(DMMT-7000WVGA)の新品で、シャープのLQ070Y3DG01のコンパチをうたっており、店には元の液晶もあったが中古だったので新品のこちらの方を選んだ。

S_a9093056

S_a9093074

 18ビットRGBで26万色出るデジタル液晶である。クロックはこれまでの6Mhz台ではなく、一気に30Mhz台に上がる。素人がいじる限界の周波数だ。液晶を2台買う時に、アナログと同じ仕様というのも芸がないと思って、少し背伸びしたのだが、30Mhzというと今のFPGAのマスタークロックとほぼ同じだ。SRAMのアクセスが心配である。S_a9093061

 インバータは別付けで既に用意がしてある。インバーターを裸で使うのはちょっと怖いので、この前に壊した最初のカシオのアナログ液晶のプラスチックケースにインバータ基板を入れる工作にとりかかる。インバーターと、フレキケーブル変換基板を、液晶パネルの裏面に5ミリのスペーサーをエポキシ系接着剤で固定して、そこへネジ止めする。スペーサーは接触面積が少ないので瞬間接着剤(シアノクレート系)では、ちょっと力をかけるとすぐはずれるので使えない。S_a9093055

 ケースと液晶パネルの固定は、ケース表面の4隅にパネルが固定されるよう寸法を正確に測った小さなアクリル小片を接着し、パネルが中で動き出さないようにしてから、ケースの裏面に固定用のアクリル板をあててケースのネジ止めで全体が動かないようにする。このあたりは瞬間接着剤でも十分だ。うむ、うまく行った。

S_a9093064_2

 電源は迷った。インバーターはENABLE用のTTL入力を要求するので、12Vと5Vが必要になる。抵抗分圧でも良いが、液晶のロジック部分の電源は3.3Vが必要である。迷った挙句、5Vと3.3Vのレギュレーターを2段使って12Vアダプターから供給することにした。インバーター用とロジック用の電源は分けた方が良いとされているが、パネルに2つも電源コードがつながるのはみっともない。まあ、このあたりは問題があればいつでも換えられる。

S_a9093068

 エポキシの乾燥は時間をかけると強力になるので1日置いてから組み立てにとりかかる。電源アダプターは、最初のとき開けた穴を流用する。フレキケーブルが長すぎたがそう問題ではない。変換基板からはフラットケーブルでFPGAにつなぐ予定だ。 インバータ部の配線が終わったので、とりあえず12V電源を入れて確認する。よーし、ちゃんとラスターが出た。

BMP画像ファイルのフォーマットを勉強する(9/4/2010)
 そろそろ画像ファイルのフォーマットを検討する段階である。最終的にはJPEGファイルを入力にすることにしているが、早く画像が見たい。とりあえず最初はBMPファイルから画像を出すことにする。ARM上のJPEGデコードライブラリは、ネット上にいくつかフリーのものがあることは大分前に確認している。フラッシュも30KB程度ですみそうだが、簡単に動かすことはできない。

 BMPファイルについては概念的なことは知っているが詳細は全く知らない。あらためてウェブで調べる。WAVファイルと同様BMPファイルフォーマットもすぐ見つかった。有難い時代になったものである。ここのサイトの説明が簡明でわかりやすい。

 それによると、24ビットBMPが一番簡単そうである。驚いたことに16ビットBMPというフォーマットはないのだそうだ。8ビット以下は、カラーパレットという別のテーブルを用意し、これをインデックスにして色を表す。こちらの方も面倒だ。

 PC上の定番ソフト、ペイントを調べ、JPEGから24ビットBMPに変換できることを確認する。よし、このフォーマットをJPEGのターゲットファイルとしよう。24ビットBMPはピクセルごとにRGB順に8ビットづつ色信号が並び、表示行の一行が4の倍数(不足分はパッドする)で、これがライン分並ぶという至極、簡明なフォーマットである。ヘッダーを削って、これを2バイトづづ(5+5+5、1ビットパッド)、FPGAへ送れば、3万色の画像が出る理屈だ。

 悩ましいのは、BMPのストリームの方向である。標準は一番下右からデータが始まり、上へ上がっていくという通常のビデオスキャンとは逆の方向である。最初戸惑ったが、フレームメモリ(SRAM)の最高アドレスから逆に書いていくとか、モニターにスキャンを逆にするモードなどで対応できることがわかり胸をなでおろした。

 BMPファイルからのデコードに見通しがついた。いやいや、遂にフォトフレームプロジェクトも画像フォーマットを具体的に検討するところまで来たかと感慨にふける。

デジタル液晶のソフト改修の検討(9/8/10)

 デジタル液晶はワイド仕様のWVGAである。画面の中央部に640×480を表示するにしても、ピクセルクロックは31MHzもある。FPGAのマスタークロックは33Mhzで、このままでも動きそうな気もするが、5%を越える誤差は少し厳しい。これはPLLで微調整が出来そうだが、それよりSRAMのアクセスが問題だ。現在のソースではうまくいかない。

 現在は、2クロックでデータを読む仕掛けになっている。ピクセルクロックにクロックを合わせた場合、倍のクロックにしないと上手く動かない。PLLでマスタークロックを2倍にして現行のソースを使うか、マスタークロックをそのままにして、SRAMのアクセスをパイプライン(アクセスリクエストとデータフェッチを同一クロックで行う)にして描画は前のクロックのデータを使う方式にするか迷った。

チャートを引いて検討する。確信は持てないが、後者のパイプライン方式でもうまく行きそうな気がする。最初の1ピクセルの表示はできないが、SRAMのデータシートには、最も簡単なアクセス方式としてCEもOEもアクティブにしたままアドレスだけをかえるチャートが例として出ている。つまり、アドレスの変更だけで10ns後には自然にデータラインにデータが出てくる。ピクセルクロックとマスタークロックを同一にすれば問題ないように思われる。

データバスを16ビットにする(9/10/2010)
 今度の液晶パネルがWVGAとえらく昇格してしまったので、メモリが足らなくなった。この4メガビットSRAMは、1アドレスあたり16ビットをアクセスできるが、配線とソフトが面倒なので、これまでは上半分の8ビットしか使っていなかった。半分の256KBではVGAでは8ビットカラーも無理だ(308KB要る)。

ワイド画面にしないで中央に640×480を出すにしても、残りの8ビットを使わないとVGAの16ビットカラーは出せない。実は16ビットカラーだと614KBも必要で、512KBならRGB4ビットづつの12ビットカラー(4096色、460KB)が限度である。

変更がおおがかりになってきたので、少しづつ動作確認しながら作業していくことにする。まずは、この16ビットアクセスの変更だ。これはクロックが今のままでもテストが可能だ。 FPGA基板のSRAMの配線を追加する。こんどのXP2は144ピンなのでまだ余裕だが、アドレス18、SRAMデータ16、RGBデータ15、これにSPIやUART、SRAM制御線を入れていくと60本近い。相当混んできた。これだけ本数が増えるとピンアサインに気を遣う。

 FPGAのピンアサインは沢山読み替えが必要で一筋縄ではいかない。まず論理合成ツールの入力となるのはピンナンバーであるが、ピンナンバー以外にIO[nn]といったピン名があり、これが雑誌基板の外出しのコネクターのAnnとかBnnというコネクター単位のピン番号と対応する。順番に並んでいるかと思うと思わぬところで飛び番があったりして、戸惑う。しかも雑誌の表示は部品面で実際のハンダ付け面と違うので余計混乱する(書き直せばよいのだがさぼっている)。

A9113094

 何とか配線が終わったので、VerilogHDLソースの変更にとりかかった。単にバスを広げるだけではなく、LowとHighバイトを互いに読んだり、書いたりする処理をつけ加える必要がある。SRAMアクセスは2回に一回になる。

 最後のデータの書き出しでつまづいた。データが奇数で終わるとSRAMに書き出されないまま終わってしまう。SPIの処理終了のところで何とか出来ないか、あれこれ考えていたが、簡単には出来そうにない。まあ画像データなので最後の1バイトが読めなくても大勢には影響しないのだが気分が悪い。

 これが食事をしているときに突然閃いた。何も2回に一回アクセスする必要はない。毎回アクセスしてSRAMに書き、2回に一回だけアドレスを増やせば良いのだ。処理時間に影響は全くない。気が付けば何でもないことだが、コロンブスの卵だ。しかし、こういう解決は気持ちが良い。

 機嫌良くコーディングを終えて、早速テストに入る。SRAM側のサブモジュールのバスを拡張するのを忘れていたり(VerilogHDLは型にうるさくないので見過ごし)、2ビット分の配線間違い(出てくるデータ化けを分析してピンポイントで発見。こいつも気分が良かった)があったりしたが、順調にSRAMの16ビット化は完了した。このあいだ9MHzに上げたSPIからの文字データが矢のように流れる。

このあたりでブログに報告することにする。次はいよいよピクセルクロックの高速化である。もしパイプラインが動かなければ、マスタークロックそのものを上げる必要がある。

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

2010年8月26日 (木)

エラーのないFPGAのUARTコードを自作する

 FPGAのフォトフレームプロジェクトは、いよいよ第一期完成フェーズにあたる第7ステップに進んだ。SDカードにあるビットマップ画像データを液晶モニターに表示する段階である。フォトフレームを作ると決めてブログで宣言したのが今年の2月末。ほぼ6ヶ月かけてここまできたことになる。

A8263052

 このあいだには、XilinxのFPGAチップと液晶モニターをプローブの誤接触で壊したり、HDL言語(VerilogHDL)の習得にてこずったり、今回も多くのドラマ(?)が生まれた。電子工作を始めて2年半、自分でも感心するほど多種多様な工作をしてきたが、ひとつのプロジェクトにこんなに長く(半年)かけたことはない。FPGAはやはりてごわい。

 これまで何度も書いているように、当研究所では電子工作には必ず何らかの実用的(こじつけでも良い)な目的を決めてから、工作を始めることにしている。定年後の楽しみに始めたアマチュアの電子工作である。何をやろうと、どこでやめようと誰もとがめる人はいないのだが、これだけ目的にこだわるのは理由がある。

 自分は飽きっぽい性格で、めげやすい。何の規制もせずにやりたいことだけやっていたら、いつまでたっても技術の向上は望めない。電子工作は幸い、初心者からプロまで、どんなレベルであろうと、それなりに夢中になり楽しめる世界だが、悔しいことに技術レベルが上がれば上がるほど楽しめる範囲が広くなっていくことは否定できない。

 何でも良いから具体的な目標(仕様)を設定しておくと、何とかそれを実現しようと、一生懸命に工夫、努力をする。飽きっぽい割には、一旦こだわると意地になる習性がある。しかし、これによって技術レベルは確実に上がる。遊びとは言いながら少しでも技術レベルを上げて今まで出来なかったことを可能にし、世界を広げたい。

 当研究所の所長は、この40年間、ほぼコンピューターのシステム開発を仕事にしていた(後半は企画と管理ばっかりだったが)。この世界ではコンピューターのハードウエアというものはいわば神が創ったものであり、これに注文をつけることはとんでもないことで、仕様どおり有難く使わせていただくものだった。

 PCやマイクロコンピューターでも似たようなものである。しかしFPGAはこういう今までの常識をくつがえすディバイスである。作ろうと思えば、自らが思いのままプロセッサーを自作できるのだ。何とかこのディバイスを自由自在に操れるようにしておきたい。

 フォトフレームプロジェクトは現物を作るだけでなくFPGAをマスターするということもプロジェクトの大きな目的にしている。そんなこともあってまた少し道草を食って、本来のフォトフレームとは関係ないFPGAのUARTにはまりこんでいた。

雑誌のサンプルUARTソースがうまく動いていない(8/16)
 SPIのバグ取りに散々苦労して、わかって見ればその原因はUARTの方だったという話は前回にした。このFPGAのUARTのVerilogHDLソースコードは、雑誌のデザインウエーブマガジン(その後季刊のデジタルデザインテクノロジーに改称)2008年10月号P86のサンプルソースをそっくり利用させてもらっている。

 雑誌のサンプルソースにバグはないはずなのだが、SRAMからのUART出力には明らかにエラーが出ている。エラーの頻度はそう高くないので、これまで気が付かなかった。これとは別のfpga4fun.comのUARTに較べれば、はるかに安定していると思っていた。

 しかし、詳しく調べると、1KBに数文字の字化け(エラー)があるようだ。特にリセット直後の数文字はたいていおかしい。フォトフレームプロジェクトではそろそろデジタル液晶の準備にかからなければいけない(ケース工作はほぼ完成)のだが、ここはそれ、しつこい性格である。気になると、他の事に手が付かなくなる。この際、徹底的にデバッグすることにした。

 折りしも、SPIのトラブルのとき勧められた、「HDLによる高性能デジタル回路設計」という本を入手し、FPGAを本格的に勉強しはじめたこともある。ロジアナを使って、雑誌サンプルソースの不具合の原因解明を始めた。

Dwv_uart

 まず、犯行現場の現場検証が重要だ。字化けの事実を検証する。テスト用にボーレートカウンターの動きをFPGA出力ピンに出すコードをソースに追加して、これをロジアナで拾い、少しづつデータを送ってはロジアナでタイミングチャートを分析する。

 その結果、どこで字化けが起きるかは、ほぼ確定できた。UARTのデータの送出順序はLSBファーストである。字化けは必ずMSBで起きている。データの最後の方を集中的に調べていくと、添付画像にあるように、8ビット目の最後がボーレートの半分で終わり、そのままストップビットになるところがいくつも見つかった。

 UART受信はボーレート期間中の多数決論理でHかLを決めているので、ボーレートが少しずれると半分の幅しかないMSBで0のデータが1になる可能性がある。これが前回の記事で1や2が半角のアやイになる理由である。スタートビットはこのあと正しく出ているので、エラーはここだけに止まる。

 字化けが起きる原因はつきとめられた。しかし何故、このUARTの最後のビットがボーレート通りの時間にならないかがわからない。ソースコードにはおかしなところはない。きちんとボーレートの時間通りウェイトが入っている(はずである)。

「HDLによる高性能デジタル回路設計」で勉強する。(8/18)
 すんさんの掲示板で勧められ、絶版だと聞いていたが、秋葉原の書泉で探してみたら最後の一冊らしいカバーが少し汚れたものが見つかり早速手に入れた。

Hdl

 噂には聞いていたが、高度な内容である。非同期回路だけでなく、同期回路も安心ならないことを学ぶ。それ以外にも考慮しなければならないことが沢山ある。自分がいかに能天気にRTL設計をしていたかを思い知らされる。

 雑誌UARTのソースコード(動作環境 Altera QuartusⅡ)は、この本を読み進むうち、かなりな問題があることがわかってきた。まず、送信要求のビットはキーボード押下で発生する非同期パルスだが、その配慮がなされていないこと、状態遷移のレジスターが多段(5ビット)で、単なるバイナリーコードであるうえに、これをインクリメントするステップと、状態遷移をするロジックが同一クロック時に動いており、これが正しく評価されない可能性があることなどである。

 本に拠れば、非同期はもちろんであるが、同期回路といえども、ハザード(出力が不定になるところ)は、常に起きる可能性があり、その対処が必要としている。それから言えば、この雑誌のサンプルソースはあやしいところが沢山ある。

 それにこのソースには不可解なところがある。UARTは非同期通信なので、同期シリアル(USART)と違ってデータはクロックのエッジではなく、HighかLowでデータを採取する。それなのにサンプリング周波数はボーレートの2倍にとってある。少なくとも送信の場合はオーバーサンプリングしても無意味である。

 恐らく、受信側のモジュールとボーレートを共通にするためだと思うが、ソースコードを読めば読むほど、何かあやしくなってきた。具体的にどこでハザードが起き、それによってボーレートが最後だけ短くなるのかは、まだ経験が浅くてつきとめられない。しかし現実に字化けが起きていることは事実である。

 こうなったら、自前でUARTのソースコードを書いてみたくなってきた。参考書で学んだテクニックを応用する絶好の機会だ。

ここまで勉強したら自分で作ってみよう(8/21)
 擬似コーディングを念入りにやって、自前のUART送信コードを書き始めた。UARTは、クロックパルスを持たない非同期通信なので、スタートビットからの時間間隔(ボーレート)だけでデータをHかLに設定して送信する。雑誌の2倍サンプリングをやめて、ボーレートだけのステートマシンにする。

 自慢は、ステートレジスターのグレイコード化(1ビットづつ変化する遷移ビット)と、同時に多数のビットを変えないロジック、ボーレートカウンターのような多数のビットを変更するときは、ステートをあけて結果を利用するなどのテクニックだ。半日ばかりで出来た。おお、前よりステートメント数も少なくなっている。これで動けばいうことなしだ。

 期待に胸をふくらませて論理合成する。祈る気持ちでUART端末を立ち上げる。ARMからデータを送り、FPGA側のUARTのスペースキー(出力指示)を押した。やった、やったぞ、最初の文字から全く誤りなくテキスト文書が表示される。キーを何度も押す。すごい。全くエラーがない。このあいだのXbeeの電力ロガーのデータはテキストデータで定型なので、少しでもエラーがあると目立つのだが、どこまでも綺麗に出力される(前は、3回に一回はどこかしらデータの乱れがあった)。

Uart_ok

 いやあ満足、満足である。勢いに乗って消費リソースを調べてみた。今度のソースコード全体のスライスは366、前は382だった。差はわずかだが、このスライス量はすべてのルーチン(UART受信、SRAMアクセス、ビデオ信号、SPI、10進変換など)を含んでいる。送信UARTだけならスライス量は80程度と考えられ、それでこの差は大幅な削減だ。嬉しい。

 調子に乗って、またソースコードを公開してしまうことにした。送信の部分だけだが、Latticeの環境では、間違いなく雑誌のコードより信頼性の高いVerilogHDLソースである。なおコメントに日本語が入っているが、これは公開のために追加したもので、Latticeのエディターでは日本語は化けてしまうので注意されたい。

//------------------------------------------------------------
// UART送信モジュール   8/25/2010 (C) LABO Gataro
//
//  CLKはマスタークロック、BAUDは受信モジュールと共通のパラメーター
// (受信モジュールは、DWM2008年10月月号P86を利用している)
//
//   メインで以下のステートメントが必要(38.4kbpsのとき)
//
//   parameter CLK  = 33000000;        // FPGA master clock 
//   parameter BAUD =  CLK/(38400*2);  // 38.4kbps 8bit 1start/stop
//   assign div = BAUD;
//
module UART_TX( so, pi, xmit, rdy, div, pCLK, pRST );
output     so ;      // transmitted out シリアル出力
input[7:0] pi;       // data to transmit 送信データ(8ビット)
input xmit;          //start transmit flag   (req)  送信要求
output rdy;          // rdy=0 : in send proc (busy) ビジーフラッグ
input[10:0] div;     // baud rate count from main module ボーレート
input pCLK;          // master clock
input pRST;          // master reset(XP2 is positive reset)

reg [7:0] ps8;
reg       so ;
reg [1:0] state;
reg [10:0] dc ;
reg       rdy ;

reg [4:0] bitctr;    // including start/stop bit
wire [10:0] div2;
assign div2 = {div[9:0],1'b0};  // multiply by 2 for TX

parameter IDLE = 2'b00;  //state reg in gray code
parameter DSET = 2'b01;
parameter WAIT = 2'b11;

always @(posedge pCLK or posedge pRST ) begin
  if(pRST) begin          // initial process if reset
   ps8 <= 8'h00;          // clear output reg
   state <= IDLE;         // initial state
   dc  <= div2;           // load baud rate couner
   rdy <= 1'b1;           // inform TX ready
   so  <= 1'b1;           // UART is negative logic(active=0)
   bitctr <= 4'h0;        // confirm initial status
  end
  else begin
   case(state)
    IDLE: if(xmit == 1'b1) begin    // if tx request
            ps8 <= pi;              // set 8bit tx data
            state <= DSET;          // move to next state
            bitctr <= 4'h0;         // initialize counter
            rdy <= 1'b0;            // set busy bit
          end

    DSET: begin
           if(bitctr == 4'h0)      so <= 1'b0; // start bit
           else if(bitctr == 4'h9) so <= 1'b1; // stop bit
                else begin
                  so <= ps8[0];            // put data on serial line
                  ps8[6:0] <= ps8[7:1];    // shift data reg
                end
           bitctr <= bitctr + 4'h1;       // shift 1 bit
           state <= WAIT;                 // go to wait state
          end

    WAIT: begin
           dc <= dc - 11'h1;            // decrement baud rate counter
           if(dc == 11'h0) begin        // refill baud rate value
             dc <= div2;
             if(bitctr > 4'h9) begin  // goto IDLE after stop bit sent
               state <= IDLE;
               rdy <= 1'b1;           // set ready bit
             end else
               state <= DSET;  //repeat 10 times(start + 8bits + stop)
           end
          end
    endcase               
  end  // end of else after Init
end   // end of always clause
endmodule  // UART_TX

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

2010年8月15日 (日)

FPGAのSPIインターフェース遂に完成

 ここ1週間ばかり、お盆休みをとっていたのだが、外にもでかけず(まあ猛暑だったこともあるが)FPGAのSPI(スレーブ)インターフェースのデバッグに夢中になっていた。先ほど、やっとのことでバグの原因が判明し、清々しい気分でこのブログを書いている。

 今度も、日頃からお世話になっているkugaさんのヒントで解決したのだが、最後の最後になっても細かいエラーが取れず、今回も苦労した。しかし、苦労が多ければ多いほどその喜びは大きい。人間というのは因果なものである。

なかなか正しいデータが受け取れない(8/8/2010)
 FPGAのLattice XP2基板のSPIインターフェースは、フォトフレームプロジェクトの第5ステップにあたり、送り側のARMプロセッサー(STM32F103)のSDカードデータを送るSPI(マスター)インターフェース(第6ステップ)は、既に完成している。

A8153045

 前にも書いたように、FPGAのSPIスレーブインターフェースは、fpga4fun.comから拝借したソースコードを使わせてもらっている。テスト環境ではARMからデータを送った後、FPGAのUARTのリターンキーを押せば、SRAMに蓄積されていたデータがUART端末に表示される。

 前記事にもあるように、30バイト程度の短いメッセージならほぼ正しく帰ってくるが、少しデータが増えると、カウンターがおかしくなるらしく、表示が止まらなくなる。いわゆる暴走である。UARTで結果が見えるように、テストデータはキャラクターで、SDカードの中のテキストファイルを選んで送信するのだが、派手に字化けする。

 データはともかく、カウンターに目茶目茶な数字がはいっているようだ。切れ切れに見えるメッセージもあちこちでデータが化け、特に日本語の2バイト文字は悲惨な結果になる。まあ、プログラムの最初はこんなものだ。少しづつ不具合を直していこう。

 データの中味をチェックする前に、先にデータカウンターの部分を直さないとテストがやりにくい。いちいちリセットしているのではたまらない。しかし、FPGAはいわゆるprintfデバッグ(変数を途中で出力させて調べること)が出来ない。カウンターの数字を知る方法は何かないかと考えていたら、以前7セグLEDテストのときにバイナリから十進4桁データに変換するモジュールを開発したのを思い出した。

 デバッグ対象のコードにさらに不確定要素を加えるのは、デバッグの常道にはずれるが、この際、背に腹は代えられない。何とか組んでカウンターの数字をUARTに出してみた。ASCIIの数字キャラクターは、バイナリに0x30を加えるだけなので楽である('1'=0x31,'2'=0x32...)。

 テストのためにまずカウンターを固定して、モジュールから数字を取り出す。あれえ、全く違う数字が出る。SPIが読んだ時の数字(でたらめだが)のようだ。やれやれ、こいつのデバッグもしなければいけないのか。ソースを見直す。うはあ、こいつはマスタークロックで何十回かループしないと結果がでないソースコードだった。10進数字を取り出す前に計算終了のフラグをテストするループを加えて、やっと決め打ちした数字がUARTにでた。

 このモジュールが出す読み込んだデータの数は予想通り支離滅裂な数字だった。unsigned変数は0から1を引くと、最大数になり、止まらなくなる。カウンターが0になったときに備えて、0からこれ以上引かないような姑息なロジックも入れるが、これも関係なし。リセットした直後は、まあまあのデータが出るが、続けるとまるで駄目である。

 SPIってこんなに不安定なのか。しかしおかしなことに8ビットフレームを1ビットでも間違えれば、あとはすべて狂うはずだが、奇妙なことに正しいデータが復活する時がある。STM32側のデータはロジアナで追って、バイト数が合っていることを確認した。中味は30バイトほど調べて少なくとも間違っていなかった。まあ、この不具合はすべてFPGA側が原因だろう。

 前にも書いたが、このfpga4funのコードは一風変わっている。各変数のあとにひとつづつクロック単位に動くalways文がついている。例えばSCKの立ち上がりは、3ビットのシフトレジスターを動かし、そのデータが01Xになった時、つまりSCKが立ち上がったときに1になるよう変数を定義し、その変数を使って8ビットデータを拾う。実に巧妙な方法だ。

 このコードは、SPIの入力をマスタークロックでサンプリングして、ビットの立ち上がりを調べている。SPIのSCKクロックで動かす方がより正確なデータがとれるような気がするのだが、人さまの書いたソースなので、原因究明の方法の糸口が見つけられない。

 FPGAのクロック33Mhzと、最初設定したSPIの速度9Mhzの差が近いので、サンプリングが上手く行っていないのかも知れないと、クロックを半分の4.5Mhz(計算ではSCKの1パルスに3回以上サンプリングできる)に落としたが、結果は変わらなかった。

 これ以上何をやって良いのか見当がつかなくなった。サンプリングだとデバッグしにくいので、むしろSCKのクロックに合わせた回路の方が安全のように思えてきた。考えた末、遂にfpga4funのソースをあきらめ、自前で作ることにする。

自前のSPIスレーブルーチンもエラー続出(8/10/2010)

 腰を据えて、自前のSPI スレーブコードを書き始めた。思ったより早くコードが完成した。おお、fpga4funのコードより消費スライスも少ない。良いぞ。テストする。最初、200バイトあまりのデータが正しく表示されたので小躍りして喜んだが、少しデータが増えると相変わらず字化けが起きる。ところどころでデータが欠落する。

 不思議に字化けの連続にはならない。8ビットフレームが守られているからか。相変わらず、文字カウントはリセット直後は良いが、あとはデタラメになる。???である。目を皿のようにしてリセットあたりのロジックを確かめるが原因がわからない。

 迷走している。ロジアナでSRAMのアドレスまで出して詳細に調べる。殆どの8ビットフレームはちゃんとSRAMにアクセスし、カウンターも上がっていくが、ところどころ、書き込まれずにスキップしたり、カウンターが変わっていない(または2以上カウントアップ)ところが出ている。

 40センチほどあるSPIの配線が長すぎるかと思ってジャンパー線を減らし短くしてみる。少し改善されたようには見えるが、相変わらず安定しない。カウンターはいまだにでたらめである。SPIは殆どが基板上のディバイス間でしか使われないので、こういうジャンパー線で20センチも延ばしてはいけないのかも知れない。プルアップも効果なし。

Spi811adr

 謎は深まるばかりである。ロジアナを見れば、SPIはほぼ所定のデータを読み、WE(WriteEnable)が8ビット単位に忠実にパルスが上がってSRAMに書き込みをしていることは間違いない。不審なところは、同じalwaysループ内で動いているSRAMアドレスの増え方である。

 アドレスは読み書きで同一のバスを使っているが、このassign文をやめて別個のregにして2重に持たせるようにした。しかしこれでも駄目。一体何だろう。アドレスがところどころで突然0に戻る。しかも、途中で書き込みが終わってしまうときもある。CSにノイズが入っているのか。そんなばかな。これまでにない難関にぶちあたってしまったようだ。少し頭を冷やそう。

やっぱり聞いてみるものだ(8/12/2010)

 この5日間、悩み続けたFPGAの謎は、「すん」さんの掲示板に上げた質問に、いつもお世話になっているkugaさんが助言してくれて、いっぺんに解決した。HDLはプログラムではない回路だと考えろなどと少し偉そうなことを書いていたが、所詮はソフト屋である。

 同じループ内にあれば、全てのステートメントは間違いなく実行されるものと信じていた。ところがループを駆動するタイミングと判断する信号の間が非同期の場合は、その動作は保証されないという、FPGAでは極く初歩(だろうと思う)の常識を知らなかった。

 SPIスレーブは相手マスターからの同期クロックで動くメイン側から見れば典型的な非同期回路である。これを気楽にアドレスカウンターのインクリメントのトリガーに使っていたために、アドレスやカウンターのインクリメントが不定になっていたのである。

 アドレスカウンターは256Kワードなので18ビットである。さらにデータカウンターも18ビット、計36ビットをSPIのデータレディをトリガーにすれば、マスタークロックのタイミングと必ずいずれどこかでぶつかって、そのときの値は不定になってしまう。

 夜中、恐る恐る「こんなことってあるのか」などと大層なタイトルで掲示板に上げたら、ものの1時間もしないうちにkugaさんから回答があった。最初、非同期ということがわからず、反論でもないけれどロジアナのチャートを見せて「どこかでカウンターをこわしているやつがいる」的な主張をしたら、kugaさんから「18段のDFF(D-FlipFlop)を同時に動かすとき」という言葉で目が覚めた。

 これまでのブログをお読みになれば分かるように、当研究所のFPGAの勉強は基礎からやっていない。7セグLEDやUART、カラーバーなどが思ったより順調に動いたものだから、つい甘く見ていた。基礎からの勉強の必要性を痛感した。疑っていたFPGAさんごめんなさい。

 コードの方は、
always @(posedge pCLK) spi_rdy <= ( byte_received );

spi_rdy      ...... メインモジュールでのレディ信号
byte_received ..... spi入力(スレーブ)モジュールでのレディ信号
pCLK      ..... メインモジュールのマスタークロック
の一行をspi入力モジュールにつけるだけで、ほぼ正しくデータがSRAMに入るようになった。ばんざい。いやあ、やっとトンネルを越えた。

813spi_ok

 しかし不思議なことがある。最初のfpga4funからもらったSPIはマスタークロックで動いていた。非同期回路ではない。それがどうしてうまく行かなかったのだろう。試しに、fpga4funのコードを入れた見た。ややや、ちゃんと動くぞ。これはどういうことだ。

 しかし、どちらのルーチンもまだ細かい誤データが出る。8ビットの頭のビット(MSB)を間違え、1が半角のア、2がイになる。つまり、0011->1011 となる。ビットマップの画像データは文字データほどシビアではないとはいえ、こんなところでゴミは入れたくない。戦いはまだ終われない。

最後のエラーはUART送信のバグだった(8/14/2010)
 ロジアナを入れっぱなしにし、ソースを少しづつ変えながらUART端末を2つ立ち上げて、ファイルを送っては、チャートを調べ、出力データをチェックする作業を続ける。もう一息なのだけれど、まだ完全にERRORなしのデータは送れない。

 fpga4funの方のソースのSCKの立ち上がりを2ビットでなく、3ビットまで読んで立ち上がりとみなすというロジックに換えて(01Xでなく011で立ち上がり)、かなりエラーは少なくなった。サンプリングするところがSCKの立ち上がりから1クロック分あとになる方がエラーが少なくなるようだ。

 ARMの方にも少し心配が残っている。CS(ChipSelect)を別個のGPIOで出しているのだが、データを送り終える前に、デアサートされてしまう。最後の1バイトはエラーになるし、受信側(FPGA)のレジスターは途中で中断され悪影響が心配である。CSをデアサートする前に、SPIのビジービットがリセットされるのを監視するロジックを加える。

 これでエラー状況が好転するかと淡い期待を持っていたが、残念ながら全く影響はなかった。データカウントがファイルのデータ長と一致したのが唯一の収穫。

Spi_screen

 万策がつきた。この程度のエラー率(1KB送って数バイト)を許容して先に進むかどうかである。QVGAの8ビットカラーなら77KB、16ビットなら154KB、画面が汚れるだろう。そうだ全体のエラーがどれくらいになるか、調べてみよう。

 FPGAのUARTの部分に機能を追加して、スペースキーを押せば、SRAMのデータを一定量づつ際限なく表示するロジックを加えた。ここの部分は、複数データを任意にUART出力できるように改善して大分モニターらしくなっている。簡単に機能が追加できた。

 テストしてみる。すると驚くべき事実が判明した。同じSRAMアドレス上のデータが、表示するたびに変わるのである。あーあーあ、何故これをもっと早くやらなかったのか。これまでSPIのエラーだと思っていたのは、すべてUART送信側のエラーだったのである。SPIはしっかりデータを送っていたのだ。これまで疑っていたSPIのみなさん大変失礼しました。

 これで、プロセッサーからFPGAに画像データを送るルートは確立された。次のステップはいよいよ液晶モニターに画像を表示するステップである。買ってきたデジタル液晶はワイド液晶なので、ピクセルクロックに30Mhz以上を要求されている。これは少しきついので、これまでのアナログ液晶に簡単なラダー抵抗のDACを加えて、とりあえず8ビットカラーにしてみようかとも考えている。フォトフレームプロジェクトは山場を迎える。

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

2010年8月 6日 (金)

ARM STM32基板のSPIでFPGAにデータが送れた

SPI動き出す(8/1/2010)
 CQ-STARM基板(STM32F103VB6)のSPIインターフェースである。だいぶ慣れてきたとはいえ、ARMのディバイスをちゃんと動かすのは8ビットマシンと違って設定が大変である。手元にはFatFSというお手本があるのだが、このSDカードのSPIはDMAを使った複雑な構成で、こちらはまだDMAを使うだけのスキルがない。このソースを簡単に流用出来ない。まず新しくSPIを定義するだけで大変だ(CQ-STARMはSPIを3つ持っている)。

 構造的には、AVRのものと変わらないが、設定するレジスターが半端な数ではない。あちこち叱られながら、日曜一日で、今までのコード例を参考に、やっと2つめのSPI2が動き始めた(SPI1がSDカードアクセス)。出力チェックは最初、オシロでやり、動作を確認してからロジアナに切り替えた。デバッグのためUARTと一緒に動かしているので飛び飛びのデータだが、それらしい波形が出てきた。

 まだ、CS(チップセレクト)が動いていないが、ロジアナで見たところでは、ほぼ想定どおりだ。簡単なファイルを読ませて、シリアルデータを追う。よし、前のAVRと違って、全く問題なくクロックとデータが一致している。あとは正確なCSが出れば、結合テストに進むことが出来る。

Stm32pass_c_2

 シリアルデータを可視化できるロジックアナライザーが欲しくなってきた。今使っているオプティマイズのロジアナは、100Mhz分解能で、32チャンネル、128Kビットのサンプリングが出来、安くてもハードとしては十分な性能だが、ソフトがいまいちでパラレルは16進に変換できてもシリアルは出来ない。秋月や、ストロベリーリナックスで出しているロジアナが良さそうだが、現在のロジアナのハード性能を上回る機種は4万近くになるので迷っている。

SPIのチップセレクトを作るのに成功した(8/2/2010)
 気持ちの良い達成感。やっとのことで画像ファイルを送るルーチンが完成した。

 最初、SPIのデータは出たが、ファイル転送のトリガーになるチップセレクトが言うことを聞かなかった。チップセレクトは、SPIのNSS(Negative Slave Select)ピンを使っている。このピンを出力にしておけば、マスターで送信するとき必ず0になり、いちいち設定する手間が省けるということだ。

 しかし、ロジアナで見ると、送信前から0になったままで変化しない。それならというので、SPI_SSOutputCmdというコマンドで、強制的に動かそうとしたが、これも変化がない。Webで調べると、この状況は、STマイクロのフォーラムでERRATAではないかと話題になっている問題であることが分かった。

 ここのサイトによれば、STM32F103のSPIにはデータを送るときや、マスタースレーブの切り替えで、自動的にチップセレクトをアサート(負論理なので0)する機能がついているはずなのだが、これが動かないらしい。

 こちらも動かそうといろいろやったが変化がない。途方に暮れたとき急に思いついた。これまでのFatFSのSDカードのSPIでは、この問題をどうやって解決したのだろう。あわてて、ソースを見てみた。何とこのピンを全く使わず別の普通のGPIOピンを使って制御していた。なーんだ。始めからこうすればよかったのだ。

Stm32_spi

 再配線が面倒なので、元のNSSピンを汎用のGPIOに設定し(だいぶSTMライブラリに慣れてきた)、送信の前後に、0(アサート)、1(デアサート)するステートメントを挟む。
よーし、ロジアナで送信の前後にちゃんとCSがでることを確認した。やれやれやっと動いた。

 フラッシュのサイズが80KB近い。LFNをはずすと、もう少し減るかもしれないが、JPEGライブラリが入るかどうか心配になってきた。

STマイクロのペリフェラルライブラリの使い方を簡単に紹介(8/3/2010)
 だいぶSTM32の汎用ピンの設定に慣れて、その構造がわかってきたので、これからSTM(マイクロ)の標準入出力ライブラリを使ってARMのペリフェラルを開発する人のために、使い方を簡単にまとめておこうと思う(自分のためでもある)。これを理解するまで大変だったのだ(ライブラリのバージョンは3.1.2)。

 STマイクロのライブラリの使い方は、日本語では、ここに結構詳しく載っているが、専門家向けすぎて良くわからないところがある。これから紹介する方法は、理論的でもなく一部の例だけなので全体を理解するのには役立たないかもしれないが、実践的なことが強みである。ひとつ通してしまえば他への応用が効くと思う。

 ARMのペリフェラル(ディバイス群のこと)や、GPIO(汎用入出力ピン)の設定は、AVRのように簡単ではない。特にGPIOは、単純なことをやりたいだけなのにとても面倒である。AVRなどではI/Oポートの設定は、入出力か、プルアップか、初期値が0か、くらいの設定しかなく、設定レジスターも2つしかないので初期化は気が抜けるほど簡単だが、ARMはそうはいかない。ARMは、ピンごとに詳細な仕様をことこまかに設定する必要がある。

 こうしたペリフェラルの設定は、ARMにもAVRと同じように各設定レジスターの全パラメータを定義したヘッダーファイル(stm32f10x.h)が用意されているので、これを使ってレジスター単位にひとつづつ設定していっても良い(もちろん直に即値を入れてもかまわない)が、ソースコードの視認性と移植性、メンテナンス性は格段に落ちるだろう。

 というのは、各機能ごとに膨大な数のレジスターがあり、特に別機種への移植を考えると、こうした情報隠蔽化や抽象化をしておかないととんでもない時間がかかってしまう。

 メーカーにとっては、同じソースコードを最小の変更で使い回しできるので断然有利だが、アマチュアにとってみれば、調べることがかえって増えるので、それほどのメリットはないかもしれない。

 いやそれにしてもLEDを点滅させるだけでも大変な手順を踏む必要がある。これに輪をかけてタイマーの設定は複雑だ。、今流用させてもらっているソースFatFSにも良い例(リエントラントで動くインターバルタイマー)があるので、これはあとでじっくり勉強する予定だ。

 さて、ARMのペリフェラルとGPIOの設定方法である。GPIOとSPIの例を下にあげる。他のペリフェラルも細かい設定は異なっても、手順は共通のようだ。

 ここでは開発環境については詳しく触れない。STマイクロから提供されるライブラリをコンパイルの時どこに置くかは、Makefileで定義するが、このあたりは先人の環境をそっくり真似て、そこへ新しいソースを置くか、これまでのmain.cに付け加える。最初のうちはこの方法が一番楽だ(今度も「ねむい」さんの環境をそっくり真似た)。

それでは、新しいディバイスを設定していこう。

1. まず、ARMではペリフェラルが使うピンだけではなく、それぞれのピンの属するバスを調べて、このバス単位に各ピンのクロックをENABLEにするところから始めなければならない。これは完全に機種依存で、それぞれのチップのデータシートで調べる。CQ-STARMのSTM32F103VB6は、SPI1は、APBバスの2番で、SPI2は、APBバスの1番だったりするので気をつけないといけない。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2| ..., ENABLE);

2. 次に、各ペリフェラルに固有のパラメーター設定のための構造体を定義する。例はGPIOで、構造体の定義は各ディバイス単位のヘッダーファイルstm32f10x_gpio.hにあるのでその型(GPIO_InitTypeDef)で、自分の構造体を作る。

  GPIO_InitTypeDef  GPIO_InitStructure; // インスタンスを作る

3. この構造体のメンバーに、それぞれのパラメーターを定義していく。パラメーター名はヘッダーファイルに#defineで出ている。下の例では、ピン13と15がGPIOピンに指定され、50MHzで駆動し、モードはAF(Alternative Function、SPIやUARTなどの特定機能)PP(プッシュプル、普通の出力ピン、他にオープンドレインやプルアップの入力などがある)にする。このように、STM32では、各ピン単位に相当きめ細かい設定が出来る。

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

4. こうして設定されたパラメーターを次のコマンドで初期化する。これはGPIOB
  つまりポートBの初期化である。(ポートAならGPIOA)
GPIO_Init(GPIOB, &GPIO_InitStructure);

(このコマンドは、何度も実行可能。同一ピンに対しては最新が有効)

5.GPIOはこれでやっと下記の関数を使って、0、1にすることが出来る。

GPIO_SetBits(GPIOB, GPIO_Pin_12);   //pin12を1にする
GPIO_ResetBits(GPIOB, GPIO_Pin_12);   //pin12を0にする

6.SPIなどのペリフェラルは、さらに2と同じように初期化構造体をつくり、パラメーターを設定していく。まず、SPIなら構造体の型、SPI_InitTypeDefを使って、

SPI_InitTypeDef  SPI_InitStructure2;    // インスタンスを作る

SPI_InitStructure2がその構造体のインスタンスの名前。GPIOと同じようにここへパラメーターをメンバーとして定義していく。

/* SPI2 configuration   8/1/2010 Chekcked */
SPI_InitStructure2.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure2.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure2.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure2.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure2.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure2.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure2.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure2.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure2.SPI_CRCPolynomial = 7;   // Default=7 (not use)

7. もちろん、このパラメーターも、次の関数で初期化。

 SPI_Init(SPI2, &SPI_InitStructure2);

このSPI2というのは、実際のディバイスのI/Oレジスターの構造体名で、これらは既に定義済み(stm32f10x.h)で新たにユーザーで定義しようとするとエラーになる(PORTAみたいなもの)

8. これで終わりではない。さらに動作を始めるために、次の関数で有効にする。

 SPI_Cmd(SPI2, ENABLE);

9.これでやっと、定義と初期化が終わった。このあとディバイス所定の関数を使うとディバイスが動き始める。おつかれさま。

SPI_I2S_SendData(SPI2, c16);          //SPI2へ、c16にある16ビットデータを送る。SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE);   //送信終了チェック
  ・・・
  ・・・

 気をつけなければならないのは、この各ペリフェラルの設定だけでは動かないことだ。必ず、3.のように、そのペリフェラルが使うピンに対してもGPIOの設定をしなければならない。GPIOモードのAF_PP(汎用ピンとして使うなら、Out_PP)などである。こうしたピンは固定されているのでペリフェラルの定義だけで動きそうだが、これがないと実際の入出力をしてくれない。これを知らずにはまった人は沢山いるだろう(かくいう私もそうである)。

FPGAにデータは送れたが(8/6/2010)
 ARMでSDカードのファイルのデータをSPIで送るところまで成功した。次はいよいよFPGAがこのデータを正しく受け取り、SRAMに展開してくれるかをテストする段階である。

 FPGAのLatice XP2基板を取り出す。机の上には、ARM、Lattice XP2基板に加え、UARTモジュール2つ(秋月USB-UARTモジュールと、自作COM1-TTLアダプター)、Latticeのパラレルライターと基板5つが勢ぞろいし壮観である。

 XP2基板は、UARTでSRAMに読み書きするコードが書き込まれている。これを、SPIで読んだデータだけを単純に出力するコードに書き換える。ARMのCOM1端末から、ファイル名を指示し、送った後、XP2のもうひとつのUART端末でキーを押せば、入っただけのデータがこのUART画面に出力されるという勘定である。

A8063042

 デバッグのためオシロやロジアナで調べやすいようブレッドボードでSPIやUARTケーブルを中継する。すべての結線は済んだ。緊張の瞬間である。ARMでファイルを指定しキーを押す。何事もなく送信が終わった。

 次は、データが正しくSRAMに書かれたかどうかを確かめる。FPGA(XP2)のUARTのリターンキーを押した。っと、何も変化がない。高揚した気分が一気に坂道を転げ落ちる。何度やっても同じ。

 まあ、これはいつものことだ。何度かやるうち、送っているときにFPGAのLEDが点くのを発見した。FPGAのSPIコードにはLEDが点くステートメントが入っていたのを思い出した。おお、FPGAのSPIはデータは読んでいるようだ。少し希望の光が差した。

 気を取り直して、FPGAのソースをチェックする。チップセレクトが下がればSPIのクロックを監視することにして、上がれば受信を中止し、次の受信のためカウンターを0に戻している。おーっと、また初歩的ミスだ。これでは、折角受信をしても終了のチップセレクトが上がったとたんにカウンターが0になりデータがないことになってしまう。

 急いで、ここをなおし再度テスト。やった、やった。それらしいデータがあらわれた。LFとCRキャラクターの関係で行がずれたりしているけれど、確かにSDカードのデータだ。テストしたファイルは小さなファイルだったので、今度は少し大きめのファイルを送る。

 いけない、UARTが暴走を始めた。SRAMの中味ではないようだ。不思議なことに、一旦暴走してFPGAをリセットした後は、最初成功した小さなファイルも表示できなくなった。電源を切ってSRAMの中味が完全に消えると元に戻るが、どこが悪いか見当がつかない。

 FPGAのデバッグは難しい。送られたデータ数をカウントしている変数ctrの内容がわかれば、暴走の原因はつかめるのだが、プロセッサーと違って、FPGAの中の変数を簡単にソースコードを加えて表示することが出来ない。

 まあ、とにかくプロセッサーからFPGAにデータを送るところまでは動いたようだ。このあとは、じっくり調べていくことにして、とりあえずはここまでの状況を報告しておくことにする。

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

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)