ライン

PICによるカラーテキストビデオ出力実験

ライン

2012年9月17日

 PICマイコンによるカラーグラフィックのビデオ出力に成功しましたが、解像度が160×100ドット、色数は8色と、いまどきのPCやゲーム機等からは考えられない程の低スペックになってしまっています。これはこれで使い道はたくさんあると思いますが、少ないビデオメモリの中でもう少し表示解像度を上げる方法を考えている中で、フォントパターンを用意して、テキストコードとカラー番号でカラービデオ出力するという発想にいたりました。

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

デモンストレーション画像
※画面だけです。プレイはできません。今のところ・・・

プレイできるようになりました(2013.2.4)

ハードウェア

 以前と同じ、28ピンDIPタイプのPIC32MXシリーズを使いました。回路も以前のものと同じです。ただし、プログラムの都合上、クロック設定を以前よりさらに高速化しました。入力クロック3.58MHzを16倍した約57.3MHzで動作させます。オーバークロックもこの辺までにしたほうがようさそうです。

設計

 以前は160×100ドットのグラフィックを実現しましたが、この時カラーサブキャリアの1周期を水平方向の1ドットに割り当てていました。今回は解像度を上げるため、1ドットをカラーサブキャリアの1周期以下にしなければなりません。試しに単純に1ドットを半周期にして、水平方向解像度が倍の320ドットの実験をしてみたのですが、色の境界での色ずれが激しく、例えば黒のバックに白い1ドットを表示するつもりが、ピンクになってしまうなど、とても実用的ではないことがわかりました。
 そこで1ドットをカラーサブキャリアの3分の2周期や4分の3周期とすることを考えてみました。3分の2周期ということは240度で1ドットとなりますが、精度よくカラー表現するのに1ドットあたり3回は信号出力が必要と思われ、最低80度ごとに信号出力することになりますが、こんな中途半端なタイミングは生成できません。60度ごとも考えましたが、性能上とても実現できそうにありません。
 4分の3周期の場合、270度で1ドットになります。90度ごとに信号出力すると1ドット当たりちょうど3回出力できます。4ドットでちょうど3周期になり、キリがよいのでこれを採用しました。
 あとはシステムクロックですが、1信号出力あたり4命令クロックにおさめることにしました。1周期にすると16命令クロック、つまり水晶発信子の入力クロックを16倍することになります。

回路図

 

波形

フォントデータ構造

 ごく一般的な1文字あたり横8ドット×縦8ドットとしました。横8ドットはちょうどカラーサブキャリアの6周期にあたり、プログラムも組みやすいので好都合です。データ構造は感覚的に分かり易い左端が最上位の横方向8ビットで1バイトとし、上から順に8バイトで1文字としています。これを256文字分単純にFontDataというunsigned charの1次元配列に格納しておきます。プログラム上から書き換える必要性はあまりないと思いますので、const指定して、フラッシュメモリ上に配置しました。キャラクターの数は256個として、文字コードを8ビットで表します。フォントデータのサイズは8×256=2Kバイトです。

フォントデータ形式

ビデオメモリ構造

 ビデオメモリは右記の構造となっています。横30文字×縦27文字はドット数になおすと水平240ドット、垂直216ドットです。水平1ドットがカラーサブキャリアの4分の3周期なので、180周期となりテレビ画面の横幅いっぱいを使いました。ブラウン管だと調整しないとはみ出すかもしれません。垂直方向は1ドット1ラインです。
 文字コードエリアのすぐ後ろに色を表すアトリビュートエリアがあります。文字と1対1で対応しており、1文字あたり1バイトを割り当てたので、256色を表現できます。そこで256種類のカラーパレットを用意し、パレット番号で色を指定することにしました。

VRAM構造

カラーパレットとバックグランドカラー

 カラーパレットの設定は、動作中のプログラムから簡単に書き換えられるように関数を用意しました。パラメータは全て0〜255の値となり、戻り値はありません。

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

 また、バックグランドカラーも設定でき、これはカラーパレットとは別に用意されます。パラメータはカラーパレット設定同様に0〜255の値をとり、戻り値はありません。

   set_bgcolor(Blueの強さ, Redの強さ, Greenの強さ)

プログラムの使い方

 割り込み等の全体的なプログラムの構造は、以前作成したグラフィック版と同様で、Timer2とOC1、OC2、OC3割り込みを使用しています。ただし、システムクロックを上げたので、タイミングは異なります。そして映像描画のところを、グラフィックメモリ読み出しの代わりに、テキストメモリ読み出しとなり、フォントデータとカラーパレットに沿って信号出力するように変更しただけです。
 使い方は非常に簡単なので、デモプログラムを見ていただければ分かると思います。最初にinit_composite()関数を呼び出すことで、ビデオメモリ、カラーパレット、バックグランドカラーの初期化と、各種割り込みの設定を行い、ビデオ信号出力が開始されます。カラーパレットの初期値はパレット番号0〜7の順にそれぞれ、黒、青、赤、紫、緑、水、黄、白となります。8〜255は全て白です。またバックグランドカラーも初期値は黒です。
 今回、3種類のデモプログラムを用意しました。まとめてダウンロードして、それぞれに必要なファイルをプロジェクトに追加してビルドしてください。
 なお私の使用環境は、MPLAB X IDE v2.20、MPLAB XC32 Compiler v1.31です。(XC32 v1.33以降では利用できません。)最適化オプションは指定してもしなくても動作しています。

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

プログラムの大幅更新を行い、Rev.2としました。ループを多用したのでサイズが削減されました。(2013.1.3)
他システム(PS/2キーボード関係)でも動作するよう修正しました。(2015.11.21)

デモ1

 昔のPCから取り出したフォントデータを画面いっぱいに色付きで表示するだけのものです。

<プロジェクトに追加するファイル>
 textdemo1.c
 fontdata.c
 colortext32.c
 colortext32.h

サンプル画像1

デモ2

 HSVカラースペースをカラーパレットを使って表現したものです。中間色もきれいに表示されます。32ビットマイコンだと、浮動小数点演算も気軽に使えます。

<プロジェクトに追加するファイル>
 textdemo2.c
 fontdata.c
 colortext32.c
 colortext32.h

サンプル画像2

デモ3

 ご存知の有名ゲームの画面だけ真似て作ってみました。残念ながらゲームが動くわけではありません。今のところ。誰かが続きを作ってくれることを期待!

<プロジェクトに追加するファイル>
 textdemo3.c
 fontdata3.c
 colortext32.c
 colortext32.h

※誰も作ってくれないので、自分で作りました。こちら(2013.2.4)

サンプル画像3

最後に

 これまでの水平方向160ドットに比べると、解像度が約33%アップしています。実際にテレビにつないで映してみると、縦方向の細い線が見えにくかったり、色がずれていたりすることがこれまでより多くなりましたが、アナログテレビはこんなものだと思えば、許容できると思います。また、256色同時発色できるカラーパレットは、なかなか使えそうです。
 今回のデモプログラムを作っていて、昔パソコンが出始めた頃に、BASICでプログラムを組んでいた頃の感覚に似ていると感じました。それくらい簡単に使えるので、ぜひ何か応用作品を作ってみてください。
 最後に、我が家の液晶テレビへの出力動画を紹介します。


2014年10月4日

ライブラリ化について

 より手軽に使えるように、ライブラリ化をしました。カラーテキストビデオ出力機能を使いたいプロジェクトに、ライブラリファイルを追加し、ヘッダーファイルをインクルードするだけで、簡単に使えるようになります。ライブラリには、使用するための初期化関数のほか、画面の表示したい場所にカーソルを設定し、文字列や数値を出力する機能などがあります。右のようなフォントも内蔵しています。

 <プロジェクトに追加するファイル>
 ・lib_colortext32.a  ライブラリファイル
 ・colortext32.h    ヘッダーファイル(機能追加版)

フォント

 ファイルはこちらでダウンロードできます。参考までにソースファイルも入れておきます。
 (2015.11.21 Rev.2) ライブラリファイルを更新しました。画面の一番右下に表示してもスクロールせず、次の文字を表示するときにスクロールする仕様に変更しました。

利用可能な関数
void start_composite(void); //カラーコンポジット出力開始
void stop_composite(void); //カラーコンポジット出力停止
void init_composite(void); //カラーコンポジット出力初期化
void clearscreen(void); //画面クリアしカーソルを先頭に移動
void cls(void); //画面クリアしカーソルを先頭に移動 (Rev.2で追加)
void set_palette(unsigned char n,unsigned char b,unsigned char r,unsigned char g); //パレット設定
void set_bgcolor(unsigned char b,unsigned char r,unsigned char g); //バックグランドカラー設定
void vramscroll(void); //1行スクロール
void setcursor(unsigned char x,unsigned char y,unsigned char c); //カーソル位置とカラーを設定
void setcursorcolor(unsigned char c); //カーソル位置そのままでカラー番号をcに設定
void printchar(unsigned char n); //カーソル位置にテキストコードnを1文字表示し、カーソルを1文字進める
void printstr(unsigned char *s); //カーソル位置に文字列sを表示
void printnum(unsigned int n); //カーソル位置に符号なし整数nを10進数表示
void printnum2(unsigned int n,unsigned char e); //カーソル位置に符号なし整数nをe桁の10進数表示(前の空き桁部分はスペースで埋める)

 このライブラリを使用して作ったゲームがあるので、参考にしてください。 →ブロック崩し

Copyright (C) KenKen All Rights Reserved.