ライン

PICによるカラーコンポジットビデオ信号出力実験(PIC32MX編)

ライン

2012年8月8日

 秋月電子にて28ピンDIPタイプのPIC32MXシリーズが驚きの低価格で販売開始されました。以前カラーコンポジット出力実験に使用したPICは、dsPIC33FJ256GP506という64ピンQFPタイプだったので、やや取り扱いにくいものでしたが、この低価格のPIC32MXシリーズでも同様のことができたら、PICでのカラー出力の敷居が随分低くなるだろうと考え、早速入手して試してみました。カラーコンポジット信号の説明や、ビデオメモリ形式などの詳細は、こちらの16ビット版を参照ください。

 ※プログラムサイズの削減、効率化、カラーパレット対応など改良を行いました。(2013.1.1追記)

設計

 今回選択したPICはPIC32MX120F032Bです。RAM容量が8KBと、160×100ドット8色出力に必要なビデオメモリ6000バイトよりやや大きい程度なので、あまり大規模なアプリケーションは作れないかもしれませんが、ちょっとしたゲーム程度であれば何とかなりそうです。なんといっても200円という価格の手軽さが魅力的です。驚いたことにPIC24FJ64GA002とピン配置がほぼ同じで、周辺機能もかなり互換性があるようです。これで、しかも32ビットマイコンなんだから、きっと簡単に移植できるだろうと考えたのですが、実際にはそんなに甘くはありませんでした。
 PIC32MXシリーズはMIPS社のMIPS32 M4Kコアを採用しています。RISCチップのため、命令体系がシンプルで、16ビットPICに比べると1命令でできることが限られてきます。そのため、動作速度はdsPIC33Fシリーズと同じ最大40MIPSなのですが、同じようには出来ませんでした。
 カラーコンポジット信号の生成はタイミングが非常に重要なため、主要部分は全てアセンブラーで記述していますが、16ビットPICはアドレッシングモードが豊富で、工夫すれば少ない命令クロック数で多くのことができました。実際1ドットの生成に12命令クロックで済んだのですが、今回のPIC32MX版ではどう頑張っても12命令では実現できず、15命令クロックで作成することにしました。1ドットあたりの時間は決まっているため、その分動作周波数が高くなってしまいます。カラーサブキャリア周波数約3.58MHzの15倍、53.7MHzで動作させる必要があります。定格は40MHzですから、34%程度のオーバークロックとなってしまいました。さすがにここまでくると、一般的な許容範囲は超えている気がしますが、私の手元のチップは問題なく動作しています。

回路

 今回の実験回路は16ビット版同様に非常にシンプルです。28ピンDIPなのでブレッドボードでも十分作れるでしょう。クロック源は必ず3.579545MHzの水晶発信子を使用してください。セラミック発信子では精度が足りず、色が出ません。
 映像信号はPORTBのRB0〜RB4で形成したDAコンバーターに出力していますが、RB5〜RB7にもダミーデータが出力されますので、出力ポートとしては使用することは出来ません。RB8〜RB15およびPORTAを使ってください。周辺機能のピン割り当てについては、その限りではありませんが。

実験基板

回路図

当初、RB0〜RB4と抵抗の間に、出力バッファ代わりにインバーターの74HC04を接続していましたが、不要なので削除しました。あわせてピン番号も記載しました。左記写真には当初の名残で74HC04が載っています。(2012.8.12追記)

プログラムの使い方

 composite32.cとcomposite32.hをプロジェクトに追加してください。またデモプログラムとして、main関数が含まれるdemo1.cまたはdemo2.cのどちらかを追加し、ビルドすれば簡単なデモプログラムが走らせられますので、応用プログラム作成の参考にしてください。
 このデモプログラムの先頭でコンフィグレーション設定を記述しています。クロックにかかわる部分は変更しないでください。また、main関数の最初にポートの設定の後、init_composite()関数を呼び出すことで、タイマーが開始され、コンポジット信号の出力が始まります。
 映像信号生成と出力部分はほぼ全てインラインアセンブラーで記述していますが、利用するのにアセンブラーの知識は特に必要ありません。C言語でビデオメモリの配列に書き込むプログラムを作れば、勝手に割り込み処理でビデオ信号が出力されます。ビデオメモリの形式は、以前作成した16ビット版と完全互換ですので、こちらを参照してください。せっかくの32ビットCPUなのですが、互換性重視のため、unsigned shortの配列でメモリ確保し、16ビット単位でアクセスしています。

ソースプログラムのダウンロード(Rev.2)

PICの出力のインバーターを削除したため、プログラムを更新しました。 インバーターを接続する場合は、composite32.cの最初のほうにある「#define INVERTER」を有効にしてください。(2012.8.12追記)
プログラムの大幅更新を行い、Rev.2としました。カラーパレット機能の追加以外、使い方に変更はありません。(2013.1.1追記)

プログラム製作について

 今回、各信号のタイミング生成に非常に苦労しました。16ビットPICではタイマー割り込みを使えば、(いくつかの例外を除き)必ず同じタイミングで割り込み処理ルーチンに制御が移りました。しかし、PIC32MXではどういうわけかかなりのばらつきが発生します。解決策として、割り込み処理の最初にタイマーの値を読み取り、その値によってウェイトを発生させてタイミングを合わせることにしました。ムダが増えますが、これで何とか等しいタイミングで信号生成することができたようです。しかし、シミュレータではタイマー割り込みが思うように動かず、全て手探りの状態でプログラムを書くという状況になってしまいました。
 →その後の調査で、ばらつきは当初感じたほど多くはないことが判明し、Rev.2ではムダをかなり削減しました。
  またRAMアクセス時にデフォルトで入る1クロックのウェイトを削除しました。(2013.1.1)

 →さらに調べたところ、ばらつきの原因はCPUをアイドル状態にするために使用したPowerSaveIdle()関数にあることが判明しました。
  WAIT命令を実行する前処理で数10クロックの間、割り込みを禁止しており、その間に発生した割り込みが保留となってしまっていたためです。
  PowerSaveIdle()関数は使わずに単純にWAIT命令を使えば、ほぼばらつきはなくなりました。(2013.1.3)

 また、32ビット化されることで、1命令が4バイト、しかも1ドットあたりの命令クロック数も増やしたので、16ビット版の時のように160ドット分の信号生成プログラムをべたに並べると、32KBのプログラムメモリ領域を結構圧迫することになり、アプリケーション用の領域が少なくなってしまいました。16ビット版では1クロックの余裕もなかったのでできなかったループでしたが、1ドットあたり15命令クロックに増やしたことで、多少の余裕ができたため、32ドット単位でループさせることができました。 →16ドット単位のループにすることでさらに短縮しました。(2013.1.1)
 なお、16ビット版ではカラーバースト信号の開始タイミングをOC3割り込みで生成しましたが、割り込み呼び出しや復帰処理に時間がかかり、水平同期の立ち上がりとカラーバースト信号開始のわずかな時間では間に合わなかったため、OC3割り込みは使わず、OC1割り込みで水平同期の立ち上がりの後、NOP命令のウェイトでタイミングを図り、カラーバースト信号出力するようにしました。
 また、16ビット版では水平同期信号と垂直同期信号の処理部分はOC1割り込みで共通でしたが、今回はタイマー値を読み取ってタイミングを図るため、垂直同期信号はOC3割り込みで処理しています。
 タイミングの詳細は以下の図のようになります。

水平1ラインのタイミング

実験結果

 16ビットPICとは随分勝手が違い、またタイミング生成が手探りだったこともあって、途中までは本当にできるのか疑問だったのですが、無事テレビへのカラー出力に成功しました。いくつかの実験プログラムを作成し、コンパイルの最適化レベルもいろいろと試してみたところ、どれも正しくカラー表示が得られました。
 YouTubeに我が家の液晶テレビへの出力動画をアップしましたので、ご覧ください。

 カラーシューティングゲーム「ロペー」の回路図とHEXファイルを公開しました。(2012.8.19)

Copyright (C) KenKen All Rights Reserved.