最終更新日時:2022-05-06 12:02:45
この程度のものでグラボと言うな、と言われないために初めに言っておくとグラボはディスプレイに表示できれば間違いないのでこれは詐欺ではありませんよ。
GPUって言うと詐欺になってしまいますね。コイツは演算というか画像"処理"(Processing)していないから。
いや、一応2倍に拡大する処理をしているからGPUと言えるのでは?(笑)
さて、ここでは汎用ロジックのみでVGAという規格の画像出力を行うモジュールについて書きます。
VGAとは「Video Graphics Array(ビデオ グラフィックス アレイ、略称:VGA)は、IBMがEGAの後継として、1987年に発表した表示回路規格である。」 (
Wikipediaより
)
簡単に言うと数あるディスプレイに表示するための「決まりごと」の一種です。
CPUを作る上で表示装置がLEDランプや、7セグメントだけだと寂しいのでいち早く表示回路がほしかったので取り敢えず作っちゃいました。
流石にコレは74HC00だけで作ると石の性能が追いつかないので無理です。回路は引けても現実ではうまく行かないものです。
VGAを選んだのはテキトーに作っても意外とよく動いてくれますし、何よりも先人がいる。コレは重要。
しかしまあ、先人の足跡はとても参考になりましたが、手持ちのパーツをやりくりする都合上論理設計の段階で自分でやる羽目になりましたが。
とても入手製の良い、安いパーツのみで構成しているため手軽にチャレンジしてみてくださいね!
仕様
まず解像度を決めましょうか。
画面サイズで最低限欲しいのは横160縦120くらいですね。
根拠としてはマイコンから扱える手軽なディスプレイが128x64とかなので、文字を表示するならこのくらいは必要になるだろうと思ったからです。
深い意味はない。
欲を言うと640x400以上はほしいものです。脇 英世氏の「16ビット・パソコンを使いこなす」(昭和61年刊)によると漢字を使うとなるとこのくらいは必要とのこと。
もっとも、漢字のフォントを作る気は無いので気にする必要はありませんが。
それに、640x400以上では必要なRAM、アクセス速度、アドレス幅を考えると少々厳しいものがあります。
これらより現実的な値は160x120〜320x240くらいと見当をつけました。
が、160x120は先に作っているページを見つけたのでもう320x240しか残っていません。
320x240で決定です。
ちなみに、IchigoJamは256x192らしいです。
そう考えると横が320あっても文字を読めるサイズにしたら余りたくさんは表示できなさそうだ。
次に階調を考えましょう。
RAMは8bitなので各色2bit、すなわち4階調です。
あまり考え込んでもうまい配置を思いつきませんでした。
2bitはアルファ値拡張用に取っておきましょう(笑)
多少不格好ですが楽なのでコレで行きます。
CPUとの接続はちぇりー独自のバス規格があるのでそれに準拠します。
最終的にCPUへ組み込むので、そこらはしっかりと守る必要があります。
具体的にはアドレス幅が足らないので、メモリマップドではなく16bitワードを基調とした3ワードのコマンド形式としました。
①横アドレス+色信号
②縦アドレス
③VRAM入れ替え
の三種です。
軽く決めたところでVGAの規格について少し調べて中核となる同期信号を生成する回路の設計に入ります。
同期信号生成部
同期信号の生成はVGAにとって肝になる部分です。
モジュール全体として、コレを基準に表示のみならずRAMアクセス制御や待ち合わせなどの処理を行って行きます。
まず、規格を調べる前に表示の方法です。
現在のディスプレイでは320x240は対応していなくても640x480は対応しているものが多いです(ちぇりーしらべ)。
そのため、640x480に2x2ピクセルをひとまとまりにして表示することにします。
縦、横ともに1/2で分周すれば簡単にできるのでコレで行きます。
さて、早速タイミングの設計を始めます。
tinyvga.com
さんより表をお借りします。
この手のものでほぼ確実に使われている表ですね。
タイミングについては
elm-chan
氏のページと、
がたろう
氏のページがわかりやすいです。
勝手にリンク飛ばしてすみません。
今更私が説明する必要は無いでしょうが取り敢えずタイミングの説明をしようかと思います。
いくつか私がハマってしまったところや、それをするとどうなるかなどの説明が調べても見つからないところなどがあったため、そこらの知見をメモしておこうかと思います。
設計をする際、まずやったことはタイミングの簡略化です。
具体的には水平同期のフロントポーチ、シンクロパルス、バックポーチにおいて1/16で分周するとそれぞれ1,6,3と割と素直な値が得られます。
垂直は、まぁ、仕方がない…
これらを含めて設計をします。
あと、これは640x480@60Hzの表です。
下に各状態における信号の扱いを記した表を示します。クリックすると別ページで表示されます。
先人方の苦労により私の説明などもはや不要だと思いますが、一応説明しておきます。
VGAでは主に表示領域と非表示領域なるものがあり、その名の通りそれぞれ表示のための領域と、表示以外のすなわち同期のための領域があります。
表示領域ではR,G,Bの色信号を0〜0.7Vの範囲でアナログ出力します。
全ての信号のもとになるPixel freq.は入手製の良さから25MHzの水晶振動子を用いました。
同期信号生成部
まず色信号と表示領域について設計していきます。
なお、色信号とは便宜上、私が勝手に言っているだけなので気にしないでください。
表示領域ではその名の通り、「表示」をします。
表示をするためには、どの位置でどのような色を出せばいいかということをディスプレイを始めとする表示装置に与える必要があります。
より具体的には1pixelずつ三原色であるR,G,Bを左から右へ、上から下へと言う具合に日本語の文字の書き順のような動きで移動していきます。
1pixelを認識するために、この信号は1ピクセルあたりの持続時間が規定されており、それは上の表のPixel freq.の欄の25.175MHzの逆数をとったものです。
1/25.175x106≒39.721x10-9s
つまり約40nSがそれに当たります。
Visible areaは1pixelの表示の640個分であるため、
1pixelあたり約39.721ns x 640pixel = 25.422μs
となり辻褄が合います。
ここで実際に表示するのは図の左下にあるように2x2pixelで1pixelとするため、上で述べた25MHzを1/2に分周して生成しました。
また、表示中には同期信号であるH-Sync、及びV-Syncは偽を送信し続けます。
ただ、同期信号は負論理であるため信号レベルとしては5Vです。
この時間で1pixelずつどんどん表示装置に送っていくと端にぶつかり表示領域外、つまり非表示領域へと出ていきます。
この表示領域外へ出たことの検出をやらねば次に行くことができません。
横の表示範囲を0からアドレスでふると、639番目が右端になり、この時、表示領域外を検出させます。
1から始めた場合640とスッキリした字面ではありますが、カウンタはクリアすると0になるために結果的に都合が悪いです。
しかしながらがたろう氏のページを見る限り、ある程度の差はティスプレイ側が吸収してくれるようなので、640、1/2に分周した私の回路では320で端に来たと検出するようにしました。
数値の根拠としては、
32010は2進では1010000002
であり、入力が2つのANDを用いて検出できるためです。
これがもし63910であれば10011111112というとんでもないことになってしまいます。
あまり褒められたことではありませんが、FPGAやPLDを使わないで作るため仕方のないことです。
また、非同期リセットのカウンタを用いた場合、この回路でもほぼぴったりに(あくまで同期リセットと比較した場合)リセットができますが手持ちのパーツに非同期リセットかつ同期カウントのものは無いので関係のない話です。
実際に使用した回路を示します。
スポンサードリンク
水平方向における非表示領域の設計
次に水平方向における非表示領域について考えていこうと思います。
水平方向の非表示領域は 同期信号生成部 の図では右端の部分にあたります。
ここは水平方向の走査で一回ずつ必ず実行されます。
ここで行われる主な動作は水平方向の同期です。
図では白の線で表される波形がその同期に使われる信号です。
同期には3つの段階があり、1つ目はフロントポーチと呼ばれています。※①
フロントポーチは表示領域が終了した時点からシンクロパルスまでの期間を示したものです。
規格では16pixel分、約0.63555μsとされています。
2つ目はシンクロパルスです。※②
この期間は出力をHに(負論理のため0V)します。
長さは96pixel分、約3.8133μsです。
最後にバックポーチです。※③
長さは48pixel分、約1.9066μsです。
頭が良ければこの数値のまま考えられるのでしょうが、私には無理なので一旦全て2のべき乗で割ってみます。
そうすると、信号の長さはそれぞれ1:6:3になります。
これを表にして整理してみます。
なお、カウントは25MHzを1/16に分周して、かつ非表示領域に入ってからのものです。
今、必要なのは水平同期が真になるタイミングです。
水平同期が真になるタイミングというのが上の表の②の範囲です。
そこをよく見るとなんと2桁目、3桁目のいずれかが真の時(赤で囲った部分)が②に範囲と
とても良く似ています。
(ええ、似ています)
先程述べたとおり、がたろう氏の努力により多少値が違っていても表示できる可能性が示されています。
そのため、このような多少ずれたタイミングでもなんとかイケる可能性があるような気がします。
というか、結論を言ってしまうと問題ありませんでした。
以上より、同期信号を論理式で表すと
H-Sync = ~(2桁目 + 3桁目)
で表されます。(バーが2段重ねで表示できないので否定は~で統一します)
しかしながら、このままではカウントが10になったときも真になってしまいます。
それを防ぐためには以下のようにする必要があります。
H-Sync = ~{(2桁目 + 3桁目) ~4桁目}
カルノー図を書いて簡約にすると
= ~2桁目 ~3桁目 + 4桁目
となり、ここにきて突然ではありますが、NORとNANDの使用状況からド・モルガンの法則を用いて最終的に
= ~(2桁目 + 3桁目) + 4桁目
という形にしました。
これでシンクロパルスが生成できます。
非表示領域の終了は紫かピンクか微妙な色のところであればおそらく大丈夫だった気がしますが、本来3pixel分間隔を取らなければならないのに1pixel分では怖いので取り敢えずカウントが10のときのパターンにしました。
赤く囲った部分がシンクロパルスを生成している部分です。
カウンタを表示領域と共用しているため、非表示領域のときのみ変化するように後段にNANDを入れています。
ピンクで囲った部分は非表示領域の終了を検出している部分です。
また、ここでは色信号はすべて0Vに下げる必要があります。
これが先に述べた、調べても出てこなかったという色信号のことです。
基本、図のように非表示領域では0V落とすようになっていますが、そこのゲートをケチると連続して表示する際にだんだん滲んでくる、という現象が見られました。
写真では赤色のラインです。
本来であれば同じ間隔で赤、黒、赤、黒…と繰り返すはずですが、途中から滲んで同じ間隔になる前に黒くなってしまっています。
コンデンサでハイパスフィルタでもかかっているのでしょうか?
良くはわかりませんでした。
垂直方向における非表示領域の設計
垂直も水平と同じように考えます。
まず、垂直方向の非表示領域を検出することから始めます。
同じように表より480にします。
数値の根拠は、
48010は2進では1111000002
であり、入力が4つのANDを用いて検出できます。
幸いにも74HC21は4入力のANDであるため、これを用いて簡易に検出できます。
これがもし47910であれば(ry
あまり褒められたことではありませんが、(ry
また、非同期リセットのカウンタを用いた場合、(ry
はい、こういうことです。
次に、シンクロパルス(垂直)を生成しましょうか。
例のごとく表で整理してみると、
となります。
こうしてみてみると、割と簡単に検出できるように見えます。
まず、赤く囲われているところは先で使用した垂直方向の非表示領域を検出するところを再利用できます。
次にピンクのところは考慮する必要がありません。
まず、愚直に論理式を書いて見ます。
V-Sync = ~(9・8・7・6・~5・4・~3・2)
テスト:
\[
V Sync = \overline{9 \cdot 8 \cdot 7 \cdot 6 \cdot \overline{5} \cdot 4 \cdot \overline{3} \cdot 2}
\]
こんな感じになります。
もっとまとめる?と
= ~(非表示領域検出・~5・4・~3・2)
このままだと、5入力のANDが必要なので、実際のICのICに当てはめると4入力AND、2入力ANDがそれぞれひとつ必要になってしまいます。
更にいじっていきます。
ここで、5及び3はド・モルガンの法則でNORにまとめることができます。
するとどうでしょう、ANDしなければならないところが4つに減り、更にNOTする必要もなくなります。(負論理にするため最後には必要です。)
式ではつまりこうなります。
= ~{非表示領域検出・4・2・~(5+3)}
回路では、次の画像のピンクの部分にあたります。
ごちゃごちゃしていてすみません。
画像を作るのがめんどくさくなって来ました。
青いところは非表示領域検出で、紫のところはこれから出てくる全てのシーケンスの終端を検知する部分です。
また、シンクロパルス(垂直)を生成する部分はここには映っていませんが枠外でNOTしています。
最後に、全ての工程を終えたことを検知させます。
前に出てきた紫のところです。
ここは単純にWhole frameである524でANDしているだけなので、特に説明はしません。
回路図
試験基板の回路図です。本番のものではありません。
具体的には、リセット周りが本番用のものと違います。
メモリアクセスの部分はまだ書いていません。
完成はしています。
製作 試作一号機(失敗)
試作一号機
これは先に出てきた、縦がオカシイ奴です。
オカシイ上に途中から動かなくなった、完全な失敗作です。
しかしながらそれなりの知見を得られ、これのデータをもとに二号機を製作しました。
スポンサードリンク
製作 製作 試作二号機
試作二号機は下のデカイ方です。
これは仕様のところで述べたようにコマンドによる制御で任意の画像を表示できます。
資料集
記事を全て復旧するのが負荷が高いので順次入れます。
関連するページ
-
NAND(74HC00)だけで16bitCPUを作る[NLP-16] このページはNAND素子のICである74HC00のみを用いて16bitCPUを作るという馬鹿みたいなことを纏めたページ。 また、早速だが使っているICは7400ではない。以前は”7400でCPUを作りたい”にしていたが詐欺なので変えた。 使用しているのはC...(以下略)
記事作成日時:2022-02-27 15:47:09
最終更新日時:2023-09-12 03:59:52
-
NAND(74HC00)だけで16bitCPUを作る[NLP-16] このページはNAND素子のICである74HC00のみを用いて16bitCPUを作るという馬鹿みたいなことを纏めたページ。 また、早速だが使っているICは7400ではない。以前は”7400でCPUを作りたい”にしていたが詐欺なので変えた。 使用しているのはC...(以下略)
記事作成日時:2022-02-27 15:47:09
最終更新日時:2023-09-12 03:59:52
-
VGA表示装置Ver2 以前製作したグラボ(笑)をいい感じに改良してキャラクタジェネレータ付きのVGA表示装置を製作しました(というか製作中か)...(以下略)
記事作成日時:2023-09-01 16:00:02
最終更新日時:2023-09-04 12:57:36
-
電子工作 修理 TOP ここでは私が製作した物や修理したものについて書こうと思う。記事の内容については責任を一切負うつもりはない。 主な製作の方向性は私が製作したいと思えたものを作っている。そこには何ら崇高な目的も技術的に重要な要素もない。欠片もない。一個人での開発の集積場であり、何かを啓発するつもりもない。...(以下略)
記事作成日時:2022-02-27 15:41:38
最終更新日時:2022-02-27 17:30:32