第10章 カメラ・表示 ― 「目」と「画面」、そして正直な限界
身体に、見て・聞いて・話し・動く力が付きました。残る感覚は視覚です。本章では、表示(画面に出す)とカメラ(取り込む)を扱います。ただし、ここはこれまでの章と性格が違います。映像は帯域も処理もメモリも、桁違いに重い。だから本章の主役は「すごい映像処理」ではなく、「何ができて、どこからが基板化(第14章)や上位連携(ネット越しAI)の話になるのか」を、正直に線引きすることです。誇張せず、できることとできないことを誠実に示します。
10.1 なぜ「入出力・限界」の章なのか
これまでの周辺(GPIO・通信・音声・モータ)は、扱うデータが細いか、連続でも1チャンネルでした。映像は違います。たとえば 640×480 の1フレームは約30万画素。色を付ければ1フレームで数百KB、これを毎秒何十枚も流せば、たちまち帯域とメモリの壁に当たります。小さなFPGAと入門ボードで、これをそのまま捌くのは無理がある――この現実を最初に共有しておきます。だからこそ本章は「限界の地図」を描くことに価値があります。
10.2 まず表示 ― Basys 3 には VGA が載っている
良い知らせから。音声(第8章)と違い、Basys 3 には VGA 出力が載っています(各色4ビット=12ビット色、と案内されています)。つまり画面に出す側は、外付けなしで今すぐ始められます。VGAは古い規格ですが、FPGA学習では定番で、同期信号さえ正しく作れば映像が出る素直さがあります。まずはここで「画面が光る」達成を取りに行きます。
10.3 VGAの仕組み ― 同期信号を正確に刻むだけ
VGAは、画素クロックに合わせて左から右・上から下へ点を走査し、水平同期(HSYNC)と垂直同期(VSYNC)で「行の折り返し」「画面の先頭」を知らせる方式です。640×480@60Hz なら画素クロックは約25MHz。可視領域の前後に帰線期間(フロント/同期/バックポーチ)があり、その分だけカウンタは可視サイズより大きく回ります。
640x480@60Hz のタイミング(規格値・目安。実機で要確認) ─────────────────────────────────────────────────────────────── 画素クロック ≈ 25MHz 水平:可視640 + フロント16 + 同期96 + バック48 = 800 画素/行 垂直:可視480 + フロント10 + 同期 2 + バック33 = 525 行/画面 HSYNC/VSYNC の極性は、いずれも負論理とされる ─────────────────────────────────────────────────────────────── ※ カウンタ(hcnt,vcnt)を回し、その値から「同期パルス」と「表示中か」を作る
芯になるのは2つのカウンタです。水平カウンタが1行(800)を数え終えるたびに垂直カウンタを1進め、垂直が1画面(525)を数え終えたら先頭へ戻る。同期パルスと「いま表示領域内か(描画してよいか)」は、このカウンタ値の範囲比較で作ります。
骨格・未検証
// vga_count.v ― VGAの画素カウンタ(骨格・未検証)
// このカウンタ値から、HSYNC/VSYNC と「表示中フラグ」を範囲比較で作る。
// 表示色は、表示中のとき framebuffer(外部RAM/低解像度BRAM)から引く(10.4)。
module vga_count (
input pix_clk, // 約25MHz(640x480@60Hz)
output reg [9:0] hcnt = 0, // 0..799(可視640 + 帰線160)
output reg [9:0] vcnt = 0 // 0..524(可視480 + 帰線 45)
);
always @(posedge pix_clk)
if (hcnt == 10'd799) begin
hcnt <= 0;
vcnt <= (vcnt == 10'd524) ? 10'd0 : vcnt + 1'b1;
end else
hcnt <= hcnt + 1'b1;
endmodule
※画素クロックは要・現物確認。 25MHz は 100MHz からクロック生成(MMCM/PLL)で作るのが定石、とされます。正確な分周・逓倍はFPGAのクロックリソース依存なので、専用工程で実機に合わせて確定します([改訂マーカー:画素クロック生成])。同期の極性・ポーチ値も、最終的に実機の表示で詰めます。
10.4 フレームバッファの壁 ― 全画面はBRAMに入らない
表示の本当の難所は、同期信号ではなく「何を表示するか=フレームバッファ」です。ここで正直な計算をします。
フレームバッファの重さ(目安) ─────────────────────────────────────────────────────────────── 640×480 × 1バイト/画素 ≈ 300KB … Basys 3 の内蔵BRAM(数百Kビット級)では入らない 160×120 × 1バイト/画素 ≈ 19KB … 低解像度なら内蔵BRAMでも現実的 文字/タイル方式 … 「文字コードの格子」を持ち、絵柄は小さなROMから引く ─────────────────────────────────────────────────────────────── → 全画面のフルカラーは「外部RAM(第4章)」前提。内蔵だけなら低解像度かタイル。
つまり選択肢は三つ。(1) 低解像度にして内蔵BRAMに収める、(2) 文字/タイル方式で「絵そのもの」でなく「並べる部品の番号」を持つ、(3) 外部RAM(第4章で見送った大容量メモリ)を実装してフルフレームを置く。本講座は、まず(1)か(2)で「映像の芯」を学び、フルフレームの(3)は外部RAMを本格実装する段(第11章のMicroPythonや第14章の基板化)へ送る、という段取りにします。
10.5 現実解としての小型ディスプレイ ― 既存の通信を再利用する
「大画面フルカラー」でなくてよいなら、もっと軽い表示が手に入ります。しかも新規IPはほぼ不要。第5章で作った通信を再利用できるからです(第6章のmicroSD/無線と同じ発想)。
SPI接続の小型TFT
SPI(第5章)で小さなカラー液晶に描く。spi_wb を再利用。全画面の帯域は要らず、必要な部分だけ書き換える運用に向く。
I2C接続の小型OLED
I2C(第5章)でモノクロOLEDに文字や簡単な図を出す。i2c を再利用。ステータス表示やデバッグ表示の定番。
※どの表示が最適かは用途次第(断定回避)。 解像度・色・速度・配線数のトレードオフがあり、唯一の正解はありません。VGA(内蔵・大画面だが帯域とメモリが要る)、SPI TFT(小型・部分更新が軽い)、I2C OLED(極小・文字向き)を、作るものに合わせて選ぶのが本講座の立場です。具体デバイスの型番・初期化手順は現物のデータシートで確認します。
10.6 カメラ ― ここが本当の難所
表示が「内蔵VGAで今すぐ」だったのに対し、カメラ(取り込み)は本章最大の難所です。理由は、入ってくるデータが速く・大量・止められないからです。
入口:並列(DVP)インターフェース
入門向けのカメラモジュールは、画素クロック+同期(HREF/VSYNC)+8bitデータの並列(DVP)で画素を吐く、とされる。FPGAはこれを取りこぼさず受ける。
壁:受けた画素の置き場
毎フレーム数百KBが流れ込む。内蔵BRAMには入りきらず、外部RAM(第4章)か、その場で間引き/縮小して小さくするしかない。
さらに高解像度のカメラは MIPI CSI のような高速シリアルを使い、これは専用の物理層・ハードIPが要る領域で、入門FPGA+小型ボードの素直な範囲を超えます(第6章のRFアナログ、第9章の大電力と同じ「FPGA単体では届かない」線引き)。本講座が現実的に扱うのは、並列(DVP)の低〜中解像度カメラまでです。
10.7 正直な線引き ― できること/できないこと
本章の核心を、表にして正直に示します(いずれも目安。手元の資源で変わります)。
カメラ・表示で「できること / できないこと」(目安・断定しない)
───────────────────────────────────────────────────────────────
◎ できる ・VGAでパターン/低解像度/文字・タイルを表示
・SPI/I2Cの小型ディスプレイに表示(既存再利用)
・並列(DVP)カメラから低解像度の静止画〜低フレームを取り込む
・取り込み画像へ軽い前処理(縮小・しきい値・単純フィルタ)
△ 条件つき ・フルフレーム表示/取り込み → 外部RAM(第4章/第14章)が前提
× 現実的でない ・高解像度フルモーション動画のリアルタイム処理
・MIPI高速カメラ(専用PHY/ハードIPの領域)
・ボード単体での本格的な画像認識(→ネット越しAIへ)
───────────────────────────────────────────────────────────────
10.8 カメラの設定と取り込み ― 既存IPの再利用+小さなFSM
並列カメラを使う場合、仕事は二つに分かれます。(A) 設定と(B) 取り込みです。
- (A) 設定(レジスタ書き込み): 多くのカメラは I2Cに似た制御線(SCCB と呼ばれることがある、とされる)で内部レジスタ(解像度・色フォーマット・フレームレート)を設定する。ここは第5章のI2Cを再利用できる見込み(信号作法は現物確認)。
- (B) 取り込み(画素の受信): 画素クロックに同期して HREF/VSYNC を見ながら8bitデータを受け、小さな取り込みFSMで「1ライン」「1フレーム」を切り出し、framebuffer(低解像度BRAM or 外部RAM)へ書く。ここは単純だがタイミングが要なので自作寄り、ただし骨格は専用工程で完全化。
※カメラの固有名・作法は断定しません。 入門で使われる並列カメラには定番のモジュールがいくつかある、とされますが、ピン配置・レジスタ設定・対応解像度・入手性は版で変わります。本文では型番を断定せず、要求(解像度・色・フレーム)を言語化してから現物のデータシートで選び、SCCB/DVPの作法を一次情報で確認します([改訂マーカー:使用カメラの現物])。
10.9 役割分担 ― 軽い前処理はFPGA、重い認識はネット越しAI
視覚こそ、旗印「ボード=身体、頭脳=ネット越し」が最も効く領域です。FPGAの並列性は、ライン単位の軽い前処理(縮小、グレースケール化、しきい値、単純なエッジ抽出)には強い。けれど「何が写っているか」を理解する重い推論は、本ボード単体では担いません。
発展:なぜ「縮小してから送る」が効くのか
ネット越しAIに画像を送るとき、フル解像度をそのまま送るのは帯域も時間も無駄になりがちです。多くの認識タスクは小さな画像でも十分な精度が出ます。FPGAの段で間引き・縮小・前処理を済ませておけば、送るデータが小さくなり、通信(第5〜6章)の負荷も下がります。「身体の側で賢く減らしてから、頭脳に渡す」――これが小型ボードで視覚を活かす定石です。
10.10 メモリマップに「表示/カメラ」を足す(設計案)
表示とカメラも、これまでどおりWishboneに足します。ただしフレームバッファ本体は大きいので、これは外部RAM前提の設計案になります(小規模なら低解像度BRAMで代替)。
メモリマップへの追記(設計案。番地は実装で確定) ─────────────────────────────────────────────────────────────── 0x0〜0xA 既存+音声(0x9)+モータ(0xA)(第8・9章の設計案) 0xB 〜 表示(VGA制御:framebufferの先頭/解像度/有効化) ← 新設(予約) 0xC 〜 カメラ(取り込み制御:開始/停止/ステータス/格納先) ← 新設(予約) (別領域) framebuffer 本体 … 外部RAM(第4章/第14章)。低解像度なら内蔵BRAM ─────────────────────────────────────────────────────────────── ※ VGAは framebuffer を読み、カメラFSMは framebuffer に書く。間をどう調停するかは設計判断。
10.11 【確認】この章の最小確認
欲張らず、表示→静止画→1フレームの順で、できる範囲を確実に積み上げます。
- 表示(FPGA)。 vga_count にクロックを与え、同期と表示フラグからVGAにテストパターン(色帯/格子)を出す。まず「画面が正しく光る」を達成。
- 小型表示(FPGA)。 SPI TFT または I2C OLED(既存再利用)に、文字や図形を表示。部分更新の軽さを体感。
- 静止画取り込み(FPGA)。 並列カメラをI2C系で低解像度に設定し、取り込みFSMで1フレームをBRAMへ格納 → VGA/小型表示に出して「撮れた」を確認。
- 前処理(FPGA)。 取り込み画像を縮小/グレースケール化し、必要なら通信(第5〜6章)でネット越しAIへ送る土台を作る。
10.12 この章のまとめ
- 視覚を、限界とともに扱った: 映像は帯域・メモリ・処理が桁違い。本章の主役は「正直な線引き」。
- 表示は内蔵VGAで今すぐ: 同期信号(カウンタ+範囲比較)を作れば画面が出る。骨格カウンタを示した(骨格・未検証)。
- フレームバッファが壁: 全画面フルカラーは内蔵BRAMに入らない。低解像度/タイル/外部RAM(第4章/第14章)で解く。
- 小型ディスプレイは既存再利用: SPI TFT・I2C OLED は第5章の通信をそのまま使える。
- カメラが本当の難所: 並列(DVP)の低〜中解像度までが現実的。MIPI高速や高解像度フルモーションは範囲外。
- 役割分担を守った: 取り込みと軽い前処理は身体(FPGA)、重い画像認識は頭脳(ネット越しAI)。誇張しない。
これで身体は、五感と運動の骨格がそろいました。ここまでは「ハードができる/できない」の話が中心でしたが、次章からは「使えるボードにするための土台」=ソフトに踏み込みます。ツールチェーン、Arduinoコア、ブートローダ、そしてMicroPythonへの道筋――第11章:ソフトの足場(Arduino/MicroPython)です。