世界を動かす技術を、日本語で。

24ビットアーケードCRTディスプレイアダプターをゼロから作る

概要

このプロジェクトは、RCadeのCRTディスプレイにPCの映像をUSB経由で表示するためのアダプタ開発記録です。 VGA信号の生成や非標準解像度対応、カラービット数の向上が主な課題。 Raspberry Pi RP2040やSTM32など複数のマイコンを活用した試行錯誤。 LinuxカーネルモジュールやGUDプロトコルの活用も検討。 最終的な目的は、柔軟かつ高品質なCRT出力を実現すること。

RCade用CRTアダプタ開発記

  • Frank がRCade用にアーケード筐体を調達、 オリジナルCRT を残した構成
  • Raspberry Pi で初期運用、より高性能なPCへの移行を目指す
  • JAMMAコネクタ を介したCRT接続、VGA-JAMMA変換器を利用
  • 非標準解像度 (例:336x262)対応の必要性
  • 18ビットカラー からの画質向上要望
  • USB接続 によるノートPC対応、PCI-eカード非使用

VGA信号とCRTディスプレイの仕組み

  • VGA はアナログ信号で R/G/B・HSYNC・VSYNC を伝送
  • CRT内部の 電子銃偏向磁石 による走査制御
  • HSYNC/VSYNC で走査タイミング同期、 フロント/バックポーチ で戻り時間確保
  • 必要信号: R/G/B・HSYNC・VSYNC の正確なタイミング生成

RP2040のPIOを用いたVGA信号生成

  • RP2040PIO(Programmable IO) でVGA信号生成に挑戦
  • PIOは 1命令1クロック でGPIO制御可能、 カスタムプロトコル 実装に最適
  • HSYNC/VSYNC/RGB 各信号を独立したPIOプログラムで制御
  • 解像度やパラメータはハードコーディング、柔軟性は低いがPoCには十分
  • 実機CRTでの動作確認 に成功、パターン描画で動作検証

Linuxカーネルモジュールによるフレームバッファ転送

  • Linuxカーネルモジュールフレームバッファ をUSB経由でRP2040に送信
  • DRMレイヤ と連携し、正しい解像度・リフレッシュレートで表示成功
  • 開発中に カーネルパニック頻発、デバッグに苦戦

GUDプロトコルの活用

  • GUD(Generic USB Display) はUSBディスプレイアダプタ用プロトコル
  • Linuxカーネルに公式対応、柔軟な機能広告・圧縮・差分転送に対応
  • ドキュメント不足 のため、カーネルモジュールをリバースエンジニアリング
  • RP2040向けにRustでGUDガジェット実装、Linux画像のCRT表示に成功
  • 12ビットカラー まで対応、配線は最小限のPoC構成

技術的課題と制限

  • USBフルスピード(FS) の帯域制限(11Mbps)で 10FPS未満
  • カラービット数解像度 の制約、 バッファアンダーフロー による同期ズレ
  • カラーバンドや画面のズレ など、実装上のバグも確認

追加の試行錯誤

  • GUDガジェットソフトウェア をPi ZeroやNixOSで動作検証
  • Buildrootのバージョン問題VGAオーバーレイの移植失敗
  • ユーザースペース実装 も検討するが、18ビットカラー制限に不満

STM32へのアプローチ

  • USBハイスピード(HS) 対応の STM32 マイコンを検討
  • 複数マイコン構成 (STM32→RP2040→VGA)は複雑化するため回避
  • よりシンプルかつ高速な構成 を模索中

このプロジェクトは、 ハードウェア・ソフトウェア両面での挑戦 と、 非標準CRT出力の実現 を目指す貴重な開発記録です。今後も より高品質かつ柔軟なCRTアダプタ の完成に向けた試行錯誤が続く見込み。

Hackerたちの意見

すごいプロジェクトだね!ソフトウェアをずっとやってるけど、もともとはEEの学位を持ってるんだ。ハードウェアいじるのが懐かしいな。

いいプロジェクトだね。詳細がたくさん含まれたレポートを書いてくれてありがとう。学生やメーカーのためにPCBレビューをよくやってるから、興味があればいくつかメモを書いたよ。これは不完全なレビューだけど、次の改版やプロジェクトに役立てばいいな。

デザイン:

  • コネクタやボタン周りのすべてのピンにESD保護を追加した方がいいよ。シンプルなTVSで大丈夫。ただ、TVSの静電容量はUSBやVGAみたいな高速ラインに負担をかけないように小さくする必要がある。低速ピンには安いTVSを使って、高速USB用の保護部品を検討して、VGAラインでも再利用するといいよ。使ってるUSB3300は最低限のESD保護があるみたいだけど、実際の使用には足りないかもね。
  • 抵抗DACと出力の間にバッファを考えてみて。オペアンプか専用のバッファチップがいいかも。これで抵抗DACがケーブルから隔離されて、負荷なしで動作できるようになる。バッファ出力に75オームの抵抗を直列に入れれば、75オームのVGAケーブルとのインピーダンスマッチングが最適になるよ。デモ用なら抵抗をVGAケーブルに直結しても大丈夫だけど、ちゃんとバッファリングしてインピーダンスを合わせると、エッジがさらにきれいになるよ。
  • あなたが使った加重和構成の代わりに、R-2R DACの設計を検討してみて。8ビットの深さには0.1%の抵抗が必要だけど、2つの抵抗値(Rと2R)だけを買って管理すればいいから、手作業での組み立てには便利だよ。
  • さらに良いのは、このプロジェクトは本物のDACチップを使うのにぴったりだってこと。抵抗DACは遊ぶには面白いし、製造コストが重視される超安価なデモボードには役立つけど(RP2040 VGAデモみたいに)、手作業で組み立てるプロジェクトには良いDACチップが最適だよ。PCBが小さくなって、組み立て時間も短縮できるし、抵抗用に24本のIOピンが必要ないから、物理的に小さいMCUパッケージを選べるようになる。

回路図:

  • 階層的な回路図を使うときは、ICや部品をルートシートに置かないのが良い習慣だよ。MCUや他の部品用に追加のシートを作って、ルートでブロックを接続するのをおすすめする。ルートページはブロック図のように扱ってね。
  • KiCADのバス機能を使うと、USB_D[0:7]やVGA_R[0:7]などのピンを減らせるかも。
  • 大きなSTMシンボルをいくつかのパーツに分けるのは、KiCADのシンボルエディタの使い方を学ぶ良い方法だし、標準のA4シートに収めることができるよ。
  • デバッグや組み立ての際に役立つメモを回路図に追加するのをためらわないでね。プロジェクトに戻ったときに自分のためにもなるから。
  • 回路図のラベルが読みやすいか、すべてが快適に見えるスペースがあるかを確認するために、クリーンアップをするのが好きだよ。長時間のデバッグセッションで疲れているときに回路図を読むのが楽になるから、いい習慣だよ。ページの空いているスペースを使って、部品をもっと間隔を空けて配置して、テキストが重ならないようにするといいよ。

PCB:

  • ほとんどの場所で0.15mm(5.9ミル)のトレースを使ってるね。小さいトレースは必要な場合を除いて避けた方がいいよ。PCBメーカーの最小トレース/スペースをデフォルトで避けて、必要な場所だけに使うのがベスト。これで歩留まりが改善されて、再作業も楽になるよ。多くのトレースは0.25mmや0.5mmでも問題ないはず。
  • 同様に、パッドの近くにトレースを走らせるのも本当に必要な場合を除いて避けよう。狭い場所にトレースを入れる必要があるときは大丈夫だけど、デフォルトではパッドとトレース、隣接するトレースの間にできるだけスペースを空けるようにしよう。スペースが狭いと、組み立て中に誤ってショートしやすくなるからね。
  • ビアについても同じことが言えるよ。スペースがあるときは、絶対に最小のビアを使わないようにしよう。
  • あなたのビアの多くが、グラウンドプレーンに大きなスロットを作るようにグループ化されてるね。低速で作業しているときはあまり問題ないけど、グラウンドプレーンに大きな切り欠きを作るのは良い習慣ではないよ。戻り電流はどこかに流れなきゃいけなくて、その大きなスロットは長い道を取らせることになり、放射を増やしたり高速信号を歪ませたりするから。

これは素晴らしいアドバイスだね!ありがとう!

小さなホビー用プロジェクトのPCBを(有料でもいいから)レビューしてくれる人を見つけるアドバイスはある?この分野に新しく入ったばかりで、フィードバックサイクルがPCBを製造して、発送して、ハンダ付けして、何が良くなったかを見つけるのに時間がかかるから、早く学ぶのが難しいんだ。(うまくいくこともあれば、どうやってやるべきだったのか分からないこともあるし)

投稿してくれてありがとう!こういうポジティブで建設的な批評が大好きだよ。自分もいくつかのヒントを得られた!

pyroelectro.comのブランキングの例画像はちょっとおかしいと思う。ブランキングは画像のすべての側面にあったし、2つの側面だけじゃなかったよ。ビームはラインの端に達する前にオフになって、リトレース中も部分的にオフだったし、ラインの始まりでもそうだった。リトレースして上に戻るときも同様。画像の上部での垂直ブランキングは重要で、CCやVITCがそこにエンコードされてたから(他の非標準的な使い方もあった)。要するに、アクティブな画像はブランキングでウィンドウボックスされてた。この例の画像はそれをうまく表現してないね。

例は間違ってないよ、ただタイミングの見方がちょっと違うだけ。ブランキングタイムをラインの終わりに全部集めてるから、フロントポーチとバックポーチに分けてないんだ。これはビデオジェネレーターではよくあるパターンで、ディスプレイとブランクのために単一のカウンターを使えるし、カウンターがアクティブカウントを超えたときにブランク条件を定義できるんだ。例えば、blanking := hcount >= 640 || vcount >= 480; output := blanking ? 0 : framebuffer[vcount][hcount];

新しいRP 2350は、著者がここで直面した制約を緩和する強化されたPIOを持ってるよ。それに、新しいHSTX(高速シリアル送信)ユニットは、迅速なラインコーディングに非常に適してる。RP 2350から高解像度・高深度のVGA信号を生成する別のプロジェクトがあるよ:https://www.breatharian.eu/hw/disphstx/index_en.html そして、元のPIOだけを使ったNTSCコンポジットもこちらにあるよ:https://github.com/obstruse/pico-composite8

問題はPIOじゃなくて、rp2040とrp2350がUSB1.1しかサポートしてないことだよ。これじゃ圧縮なしで320x240x16bpp@60Hzを処理するには帯域が足りないんだ。

記事には、実際にアーケードマシンでどのゲームを動かしているかが書かれてないね。18ビットDACが制約だって言ってたけど、ほとんどの2Dアーケードゲームは15ビットカラーしか出力しないよ。これだけすごいけど、MiSTeRを使う方がずっと簡単だと思う。

すべてのゲームはRecurse Centerの人たちが作ったカスタムゲームだよ!

アーケードマシンって本当に変わってたし(そしてすごかった)。例えば、コピー防止にすごく力が入れられてた。30〜40年前のゲームでも、まだ完全に解読されてないものがいくつかあるんだ。80年代から90年代のシステムもとても奇妙でエキゾチックだった。ストリートファイターIIの特定のバリエーションのように、面白いバグがあって、それを回避する必要があったりしたよ。

プロのヒント:STにはCubeMXっていう無料のツールがあって、USBのミスを避けられるよ。過去にいくつかH7のパーツを使ったことがあるけど、そんなことは一度もなかった。みんなが驚いてるのが意外だね。USBのハイスピードはフルスピードやロースピードとは全然違う電圧レベルだから、デジタルチップがよく使うものじゃないし、外部PHYが必要になるのはよくあることだよ。イーサネットと同じだね。俺のアドバイスは、ツールでIOを全部計画する前にボードを撃たないこと。これで何度も助けられたよ。それと、U5シリーズもチェックしてみて?ハイパーラム、内蔵のハイスピードPHY、パラレルディスプレイポートがあるから。あと、確かRaspberry Piも40ピンヘッダーでパラレルディスプレイ出せるはず。24ビットじゃないかもしれないけどね。

ちょっとしたメモだけど、仕事でほぼ同じプロジェクトをやったばかりだから:* PIOがカスタムデジタルプロトコルに使えるスイスアーミーナイフみたいで、RP2040から始めたよ。もっと速いUSB PHYを搭載したRP2040があったら最高だね!* STM32U5シリーズには内蔵のハイスピードUSB PHYを持つバリエーションがあって、2.5メガバイトのSRAMもあるし、自宅でハンダ付けするための簡単にハンダ付けできるフットプリント(LQFP64まで)もあるよ。* 最近はJLCPCBやPCBWayがかなり安く基板を組み立ててくれるよ。* 他の人が指摘してるように、ESD保護を基板に追加するのは良いアイデアだね。* 理想的には、急激な立ち上がり/立ち下がり時間を持つ全ての配線(ほとんどのデジタル信号)は、全体のトレースの下にしっかりしたリファレンスプレーンが必要で、クロストークやEMIを避けるために、信号がレイヤーを変える場合はリファレンスプレーン用のビアも必要だよ。* レンダリングを制御していて、色バンディングがまだ問題なら、インタリーブドグラデーションノイズを調べてみて。* GUDについては聞いたことがなかったな。ファームウェアとアプリケーションコードでシンプルなUSBバルクアウトエンドポイントを作ったけど、1日もかからなかったよ。時にはカスタムソリューションの方が早くて簡単だけど、どこで動かすか、誰に配布するかによるね。もちろん、俺のカスタムソリューションは他のものと互換性がないけど、今のところそれで問題ない。作業したプロジェクトについてブログを書こうと思ってるから、できたらHNにも投稿するつもりだよ。https://blog.demofox.org/2022/01/01/interleaved-gradient-noi...

RP2040はUSB FS(フルスピード)しかできなくて、11 Mbpsの速度が出せるんだ。最初にターゲットにしてた320x240x16bppでは、1フレームが153.6 kBになる。最大USB FS速度では、10 FPSにも満たない!恥ずかしいことに、最初は11 MBpsの帯域で計算してたから、8倍間違ってた。Windows NT Serverのシステム管理について本を書いたけど、ハードディスクやネットワーク帯域についての章でもこのエラーを続けてしまった。出版前にこれを見つけてくれた技術編集者に感謝だよ。

実際、ここでかなり進展があったよ。ただ、カーネルパニックが何度も起きたけどね。ちゃんとした開発環境を整えるのを面倒に思ってたから(うっかり)、ほとんどのバグはコンピュータを再起動しないといけなかった。これがすごくイライラして面倒だったけど、たくさん学んだよ。公式ドキュメントには呪われたものがあって、インタロバングなんかも見つけた!USBパススルー付きのVMでこの開発をするのは簡単じゃない?