ライン

PICによるカラーコンポジットビデオ信号出力実験(高解像度/16色/正方画素化)

ライン

2013年10月14日

 先般、32KバイトのSRAMを搭載したPIC32MX150F128Bで横240×縦224ドット、8色表示のビデオ出力システムを作成しましたが、SRAM容量的には16色対応も可能なので、ビデオメモリの形式を変更して16色対応のシステムを作成しました。
 また、これまで作ったシステムはどれも1ドットの縦横比が縦長だったり横長だったりと、画像表示にはいまいち不向きでした。これは、NTSCのカラービデオ信号のタイミングの元となるカラーサブキャリアの周波数を、PICのシステムクロックに使う以上、どうしようもない制限だと考えていましたが、工夫すれば正方形に近いドット表示ができそうな気がしてきたので、あわせて実験してみました。

実験結果画像

ハードウェア

 前回のPIC32MX150F128Bを使ったシステムと全く同じ回路です。以前パックマンテトリスを作ったときのハードウェアから、マイコンチップを変更したものです。ビデオ出力の安定化のため、75Ωの抵抗を追加しました。PORTBのスイッチ類と音声出力は今回の実験では特に使っていません。

回路図

設計

 これまでビデオメモリの形式として、B、R、Gの3枚のプレーンを用意し、16ドット単位で画像データを表してきました。これは、昔のパソコンのグラフィックメモリ形式に近く、過去の資産を流用するにはよかったのですが、色数を増やすには不向きです。また、プログラムでリアルタイムにビデオ信号を生成するには非常に不利な形式で、そろそろ限界を感じていました。そこで今回は、過去にこだわらず、1ドットに対して、図のように4ビットを割り当て、単純にカラーパレット番号を書き込むことでドット表示される形式としました。
 なお、1ワード中の上位ビットが画面の左側になるようにしました。人によっては、逆のほうがメモリ構造がリトルエンディアンのPICにとっては素直な書き方だと言われるかもしれません。実際のところ、私も当初それで作ったのですが、明らかに人間にとっては使いにくいことに気付いたので、反対にしました。

ビデオメモリ構成

 次にドットの縦横比について考えます。これまでに実験した結果から、カラーサブキャリアの1周期の5分の3くらいを1ドットの横幅とすると、正方形に近くなることがわかりました。5分の3周期で1ドットというのは、かなり半端です。図のように、システムクロックをカラーサブキャリア(約3.58MHz)の15倍に設定し、9クロックで1ドット分の信号を生成、出力すれば実現できますが、5ドット分出力してやっとちょうど3周期になって、位相が元の位置に戻ります。
 また、これまで1ドットに対して必ず最低3回以上の信号出力を行ってきましたが、9クロックで3回出力は大変なので、2回だけの信号出力とします。しかし、9は2で割れませんから、ここでも半端な状況となりますが、難しくは考えず、4クロックと5クロックに分けることとしました。この場合、図のようにカラーサブキャリアの位相の15分の0,4,9,13,3,7,12,1,6,10という一見不思議な順に波形データを出力することになりますが、これはこの順にカラー信号波形のデータを各色分持つことで実現できます。
 ドットの横幅が減った分、これまでより横方向の解像度を上げることができます。以前のものは240ドットまでしかテレビ画面に収まらなかったのですが、256ドットというきりのよいドット数を表示することにしました。縦方向はテレビの都合上224ドットです。メモリ容量はちょうど28Kバイトとなり、SRAMの空き容量は4Kバイトになります。ちなみに256×224ドットというのは、元祖ファミコンの解像度と同じです。

波形

プログラム

 ソースプログラムとHEXファイルはここからダウンロードできます。
 (2013.12.12)ソースプログラムとHEXファイルの修正をしました。set_palette関数の計算式にミスがあり、赤の色合いが弱くなっていました。

ソースプログラムのダウンロード

 ソースプログラムは、composite32-high4.cとcomposite32-high4.hが本システムの本体で、composite32-high4-demo1.cがmain関数を含む、使用例です。
 ビデオメモリ形式を変更して、これまでより信号生成部分が楽になりました。前回の横240ドットのものはPORTB全体に出力していたので、汎用出力としてはつぶしてしまいましたが、バイト単位での出力が可能になったので、RB8〜RB15は汎用出力にも使えるようになりました。RB5〜RB7は汎用出力には使えません。
 カラーの指定には、set_palette()関数を使います。パレット番号は0〜15、あとは3原色の重みを0〜255で与えます。初期値は、パレット0〜7は従来通り、8〜15は0〜7の明るさを半分にしたものをセットしています。(パレット8はパレット0と同じ真っ黒。)

   set_palette(パレット番号, Blueの強さ, Redの強さ, Greenの強さ)

 デモ内容は以前のものと大きくは変えていませんが、ビデオメモリの形式を変更したため、点表示やキャラクター表示の部分を変えました。特に、横m×縦nドットのキャラクター表示関数putbmpmn(x,y,m,n,bmp[ ])はこだわって作ったので、いろいろ使えると思います。

実験結果

 デモ画像の結果を見ると、表示された円や正方形の縦横比がかなり改善されたことがわかります。実際に長さを測ってみると、1:1.05程度でまだわずかに横長のようですが、あまり気になりません。
 その代わり、細い線の色がこれまで以上に気になるようになりました。白がピンクや水色に見えることはこれまでもありましたが、白以外でも横方向1ドットしかない線は色が化けてしまっています。1ドットあたり2回しか信号出力していないことも原因の1つだと思われます。使う側でなるべく縦に細い線を表示させないようにすることが、使うコツとなりそうです。

サンプル画像

最後に

 同時発色の色数は16色で、色のズレもはげしいながら、PICワンチップで初代ファミコンと同じ解像度でテレビに出力できるところまできました。専用の音源やスプライト機能はありませんが、CPU性能では大きく上回っているので、ファミコン並みのゲームであれば実現できるのではないかと思えてきました。
 PIC32MX150F128BはDIP28ピンと扱いやすく、しかもメモリ容量も大きいので、入手して遊んで見られてはいかがでしょうか。

Copyright (C) KenKen All Rights Reserved.