Video出力の研究
SimさんのサイトでNTSC用の抵抗値について研究されていたのを思い出し、自分でもやってみようと思いました。
NTSC信号は1VPPの信号で同期信号(SYNC)と映像信号が合成(コンポジット)された信号です。本来は同期信号のパルスの立ち上がり、立下り時間の細かいタイミングがRS170という規格で規定されています。今回はマイコンでやるので、0か1という簡易な同期信号を作成します。以下に電圧レベルを示します。
●NTSCの電圧レベル
SYNC -40IRE(-0.286V) (IREとは0.714Vを100とするレベル単位)
映像黒 0IRE(0V)
映像白100% 100IRE(0.714V)
実際はACカップリングされるので、テレビ側でクランプというSYNCレベルを固定する作業をして、DCとしてA/D変換します。
マイコンではACカップリングしないで、DCレベルとしてNTSCを出力します。
●マイコンでのVideo信号の電圧レベル
SYNC(同期信号) 0V(GND)
映像黒またはSYNCのOFF 約0.3V
映像白100% 約1.0V
NTSCのカラー色を出すには、3.58MHzのサブキャリアという波形を同期信号に挿入する必要がありますが、サブキャリア無しの同期信号にして、色は簡単に白黒グレイの3色でいきたいと思います。
●テレビ信号について
テレビは1秒間に29.97枚の画像を更新して動いているように見せています。また1枚の画像は水平ラインが525ラインで構成されますが、インターレースといって、偶数ライン毎(525/2本)、奇数ライン毎(525/2本)と交互に画像を更新していきます。
偶数ラインまたは奇数のラインはそれぞれ262.5本となりますが、これをフィールドとよびます。2フィールドで1フレームという呼び方もします。
テレビで表示するためにはフィールドの横方向の先頭と上方向の先頭を決めてあげる必要があります。なぜなら連続する信号の中から、ここから先頭だと知らないと1ラインずつ取り出すことができないからです。この先頭を決めるのが同期信号と呼ばれ、信号中に含まれています。この同期信号は画像以外の部分で、画像とは、はっきりと区別ができるようなレベルの信号になっています。
同期信号の種類は、横方向の同期信号=水平同期信号 、 縦方向の同期信号=垂直同期信号があります。
1フレームの構成
第1フィールド (奇数または偶数) 奇数偶数はメディアによって異なるようです。放送とDVDは違うみたいです。
262.5本のライン
1ラインの中に水平同期と画像情報 (262.5−20)ライン
垂直同期だけのライン 20ライン(ブランキング期間)
垂直同期はさらに3ラインの等価パルスライン+3ラインVSYNCライン+3ラインの等価パルスライン
が20ラインの先頭に含まれています。
10ラインから20ライン目までは水平同期つきの画像がない領域です。
第2フィールド (偶数または奇数)
262.5本のライン
1ラインの中に水平同期と画像情報 (262.5−20)ライン
垂直同期だけのライン 20ライン(ブランキング期間)
垂直同期はさらに3ラインの等価パルスライン+3ラインVSYNCライン+3ラインの等価パルスライン
が20ラインの先頭に含まれています。
273ラインから282ライン目までは水平同期つきの画像がない領域です。
●マイコンでのテレビ信号のシミュレート
ではマイコンではどうするかいうと、テレビの1ラインの周期が約63.56µsなので、まずこの時間を作ります。今回は16ビットタイマーにてコンペアマッチ割り込みを使用して作成しました。割り込み1回で1ラインなので、割り込みの中でラインをカウントすることができます。
【 割り込み内での処理 】
1ライン目から9ライン目までは垂直同期パルスをVideoポートに出力します。つまり0Vと0.3Vをdelay関数を使って規定の間隔で出力します。10ライン目以降は水平同期パルスをVideoポートに出力します。
【 割り込み外の処理 】
メインループは通常Sleep状態で停止しています。Sleepは割り込みの終了によって解除され、メインループが動き出します。つまり1ライン単位でのタイミングの頭だしが常にできているわけです。(垂直および水平同期がとれている)
10ライン目から20ライン目は、各種演算や画像用メモリの書き換えやスイッチを読み取ったり等の処理をしています。
21ライン目から262ライン目までは画像メモリの内容をVideoポートに出力しています。かなりタイミングが厳しいので、他の処理は行うことができません。
1ラインの処理が終わったらまたSleepに入り、メインループを停止します。
●画像メモリ
カタカタの「イ」では16×16バイトを画像メモリとしました。1バイト=1ドットで表現し、あらかじめ「イ」のドットデータを画像メモリに書き込んでおきました。画像メモリをテレビに書き出すには、テレビの21ライン目から画像メモリのラインを順次出力するわけですが、テレビ6ライン分で画像メモリ1ライン分とすることにしました。これは、見た目がちょうどよい大きさにするためです。横方向の1ドットを出力すると大体6ライン分のサイズが縦横比1:1に近くなります。
ドット出力について説明すると、1ライン63.5µsですが、割り込み中の時間である水平同期パルス出力時間分の11µsを差し引くと、メインループでは残り40〜50µsくらいしかありません。割り込みのオーバーヘッドがあるともっと少なくなります。残りの時間40〜50µsに多くのドットを打てるかというと、C言語ではせいぜい30〜40ドットくらいでしょう。ここでは正確に同じタイミングでVideoポートへ出力しないと、各ラインの画像の終端がバラバラになってしまいます。
アセンブラだともっとドットが打てます。今回はC言語ですが16ドットくらいならまだ余裕があります。
ここに説明図
●実際の回路
抵抗3本で白黒3階調(0.78V、0.65V、0.5V)と約0.3Vおよび0Vを作ることにしました。
R0=1Kオーム
R1=2Kオーム
R2=1Kオーム

2007.7.21回路修正 VideoポートをPORTBからPORTCへ変更しています。ご注意ください。
Video信号は1VPPなので、必ず振幅が1V以下である必要があります。抵抗の定数を変更する場合は必ず、1V以下なのをオシロで確認してください。テスターでやる場合は一度ブレッドボードに抵抗だけの回路を組んで、5Vをかけてテストすればよいと思います。
●全体の回路
ATmega168の外部水晶20MHzを使用して回路を作りました。
(開けなかった場合は、2,3度クリックしてみてください)
●実際のTV映像(テレビのビデオ入力につなぎました)
1
2
3
1番目はカタカタの「イ」
2番目はSin波形、天地逆ですが(笑)
3番目はブロック崩し風ぶろっきー君デモ版
4番目はテキスト表示とドット波形表示 2007.9.3追加記事
クリックすると大きくなります
●実験ソフト1 カタカナの「イ」
同期信号のタイミングについては、ChanさんのRS-170A概要 (最後にリンクあります) を参考にさせていただきました。本当は2フィールド構成にしたかったのですが、2フィールドだとテレビがうまく認識してくれません。しょうがないので、1フィールドの繰り返しにしました。
内容としては、タイマーを動かし1H(63.5µs)で割り込みをかけます。
割り込み内では、何ライン目かカウントしていて、対応するカウントで同期信号のパルスを出します。
割り込みが終わると、メインループではスリープしているので、スリープを抜けループが動きだします。
ループ内では指定したラインからイの文字表示を開始します。まず表示開始の横方向は、画面の中央に文字がくるように適当なdelayを入れました。次に縦方向です。イのフォントは16×16ですが、6ラインごとにフォントの1ラインを出力していきます。。
フォントの横方向の1ドット毎は、タイミング制御していません。適当に遅れがでて幅がでています。
今回は細かいタイミング制御をすることなく、文字を出しています。将来、表示装置として使う場合は 位置を決め打ちで出せるように、タイミング制御する必要があります。といっても難しくなく、1文字の出力時間間隔を一定に保つだけなのです。
統合環境:AVRStudio4 Ver4.12 SP4 Build498
コンパイラ:WinAVR-20060421
カタカナの「イ」 ATMega168Video.zip Ver1.0a 2007.7.21
●実験ソフト2 Sin波形
基本はまったく実験ソフト1と同じで、同期信号の割り込みとスリープです。
最初にメモリを用意し、Sin波形を2PI分、40ステップ入れておきます。
X軸が時間なのですが、あるラインカウントでX軸のループ(メモリの40ステップを順に見ていく)をしていったときに、波形メモリの値とラインカウントが一致すれば点を打ち、そうでなければ黒を出力します。これを全ラインをおこなうと波形が表示されます。
グラフを正確に書くのは難しいみたいです。タイミング制御をきちんとやらないと指定した座標に点を打つことはできません。アセンブラでやりたいところです。今回はC言語なので、時間軸はループの実行速度なので密なものはできませんでした。荒い点々でしたが、雰囲気はつかめた感じです。
統合環境:AVRStudio4 Ver4.12 SP4 Build498
コンパイラ:WinAVR-20060421
Sin波形 ATMega168Video_Sin.zip Ver1.0a 2007.7.21
●実験ソフト3 環境ソフト ぶろっきー君(デモ版) 【 まだゲームはできません 】
ブロック崩し風の動きがあるものを作ってみました。デモ版なので、ゲームはできません。見て楽しんでください。
基本はまったく実験ソフト1と同じで、同期信号の割り込みとスリープです。なおかつ、「イ」はドットが16×16でしたが、ブロック表示用に20×16ドットに拡張しました。やっていることは文字表示と基本的に同じです。数フレーム毎にドットを変更していくだけです。
ブロックくずし風なのですが、まだラケットの判定ルーチンを組み込んでいません。デモ版としてラケットはボールに追従して動きます。よって必ず、ボールを打ち返します。打ち返すというより、床にバウンドする処理のままです(笑)
ソースを変更すれば、ボールの早さを調節できるので見たい方はやってみてください。
著作権は放棄していませんが、ソースにオリジナルがすんによることをコメントに記述してもらえれば改変して公開することが可能です。公開したときは、オリジナルソフトのサイトとしてここのサイトも紹介してください。リンクを張ってもらえると助かります。 (たぶんいないと思いますが商業使用は要相談)
統合環境:AVRStudio4 Ver4.12 SP4 Build498
コンパイラ:WinAVR-20060421
ブロック崩し風デモ ATMega168Video_BlockDemo.zip Ver1.0 2007.7.21
2007.9.3追加記事
●実験ソフト4 テキスト表示とドット波形表示(参考版) 【 まだ初期実験中のものです。汎用性はありません 】
とりあえず、RAMに72x72ドットのビデオメモリーと9x8のキャラクターメモリーを確保にして、グラフと文字表示をやってみました。やはりあと少しRAMが欲しいです。1Kのうち73%使用しているので、後日追加予定のプログラムで大きなことはできないです。シリアル通信して、表示を更新するぐらいでしょうね。
横5縦8ドットのフォントは自作で、英数字の大文字だけ作りました。フォントはプログラムメモリーにあるので、RAMは消費しません。WSNAKさんの#172TVゲーム基板にも移植する予定です。
試行錯誤した点は、水平方向の表示をアセンブラでやっているところです。これは、ループを極力排除し、べたでそのまま水平9バイトを72ドットに展開しています。最初はループで作ったので、タイミングがずれてガタガタの表示でした。アセンブラルーチンはインラインではなく、Cからアセンブラを呼ぶ形式にしました。AVRのアセンブラはあまり経験がないのでもうちょっとよいコードにできるかもしれません。改善の余地あるかもしれません。
著作権は放棄していませんが、ソースにオリジナルがすんによることをコメントに記述してもらえれば改変して公開することが可能です。公開したときは、オリジナルソフトのサイトとしてここのサイトも紹介してください。リンクを張ってもらえると助かります。 (たぶんいないと思いますが商業使用は要相談)
統合環境:AVRStudio4 Ver4.12 SP4 Build498
コンパイラ:WinAVR-20060421
WELCOME デモ ATMega168VideoSin2ver01.zip 2007.8.14
●マイコンのVideo出力でできそうなものの検討 2007.7.23追加
1) ラーメンタイマー(タイマーはあくまで、1Hの63.5µsを基準に考える。1H時間に半端がでないように水晶周波数の選定も重要)
2) 漢字表示装置(EEPROMに漢字フォントをのせ、漢字を表示する。ただし、画像メモリが少ないのでスクロール表示にする)
3) 環境ビデオ的な使い方 その1(よくあるいやしグッズで、画面の中に線で描いた人が歩いたり、とまったり、寝たりしている)
4) 環境ビデオ的な使い方 その2(よくあるいやしグッズで、画面の中に線で描いたシャクトリムシが動いている)
5) リサージュ図形の表示(いろいろな関数を使って曲線?を表示する、意外とおもしろい形ができたりする)
●参考リンク
ChanさんのRS-170A概要 Chanさんのサイト
AVR Video Generator widh an AVR Mega163 (ATMELサイト)
ワンチップマイコンで作るビデオ信号ジェネレーター 小山先生(弘前大学)のサイト
ワンチップマイコンでゲームを作ろう 小椋さんのサイト