今回は、Raspberry Pi PicoとAdafruit DVI Breakout Boardを組み合わせたHDMI出力の表示テストを行いました。
セットアップにあたり、2つのAI(AI1・AI2)を「思考パートナー」として活用。 AI1からは「Pico Wでは動作が不安定になる可能性があるため標準のPicoが望ましい」とのアドバイスや、信号安定のための「10cmの短いHDMIケーブル」の使用を提案されました。
試行錯誤の結果、最終的にはAI2が提示したプログラム構成で無事に画面表示に成功! 本記事では、初期化の失敗をどう乗り越えたのか、その過程を記録します
構成
使用ハードウェア
IoTマイコン: Raspberry Pi Pico W
- ※無線機能付きモデルですが、今回はHDMI出力の制御に使用。
DVI出力ボード: Adafruit DVI Breakout Board
- HDMIコネクタを介してDVI-D信号を出力するインターフェースボード。
ディスプレイ: 産業用液晶モニター
- 10.1W型_静電容量式タッチモニタ
ソフトウェア環境
開発環境: Arduino IDE 2.3.4
使用ライブラリ: PicoDVI – Adafruit Fork
- RP2040のPIO(Programmable I/O)を活用してDVI信号を生成するライブラリ。
プロジェクト名: ras_dvi.ino
技術的なポイント(ブログ用メモ)
初期化失敗の回避: display.begin() が失敗(Lチカ状態)する場合、解像度設定やシステムクロック(252MHz)の安定性が鍵となります。今回は 320×240 (16bitカラー) 設定にすることで、メモリ消費を抑えつつ安定した起動を実現しました。
・ピンアサインの最適化: Adafruit DVI Breakoutのピン配置に合わせて、dvi_serialiser_cfg 構造体で GPIO 12, 14, 16, 18 を正確に指定。特に 差動ペア(D+/D-) の隣接ピン干渉に注意を払いました。
・デバッグの記録:クロック周波数の罠「最初はAIの助言通りにシステムクロックを 275MHz に設定しました。しかし、display.begin() が失敗していると思い込んでいたものの、実際には高すぎるクロックによりマイコン自体がフリーズし、プログラムが一行も走っていない状態でした。
そこから段階的にクロックを下げて検証した結果、以下のことが判明しました。
- 250MHzまで: プログラムは正常に走るが、DVI信号(640×480相当)のタイミング規格に合わないため、液晶には何も表示されない。
- 252MHz(黄金比): 320×240ピクセル・ダブリングに必要な正確なクロック。ここで初めて液晶が同期した。
- 教訓: PicoDVIにおいて、クロックは「高ければ良い」わけではなく、**ビデオタイミングに基づいた正確な数値(252MHzなど)**に設定することが、成功への最短ルートでした。
回路

最終コード
#include <PicoDVI.h>
const dvi_serialiser_cfg my_dvi_cfg = {
.pio = pio0,
.sm_tmds = {0, 1, 2},
.pins_tmds = {12, 16, 18}, // 青(D0), 緑(D1), 赤(D2)
.pins_clk = 14,
.invert_diffpairs = true// ← これを true/false 切り替えて試す
};
// 引数から false を削除し、電圧(VREG_VOLTAGE_1_20)を指定
DVIGFX16 display(DVI_RES_320x240p60, my_dvi_cfg, VREG_VOLTAGE_1_20);
void setup() {
// begin() の中でクロック設定(252MHz)も自動で行われます
if (!display.begin()) {
pinMode(LED_BUILTIN, OUTPUT);
while (1) {
digitalWrite(LED_BUILTIN, HIGH); delay(100);
digitalWrite(LED_BUILTIN, LOW); delay(100);
}
}
//display.fillScreen(0xFFFF); // 16bitの白
//display.fillRect(40, 40, 240, 160, 0xF800); // 中央に赤い四角
// 1. 画面を黒で塗りつぶす
display.fillScreen(0x0000);
// 2. 表示したい文字列とテキストサイズを設定
String text = "faithit";
int textSize = 3;
display.setTextSize(textSize);
// 3. テキストの範囲(幅と高さ)を取得
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
// 4. 中央の座標を計算
// 画面中央(160, 120)から、テキストの幅と高さの半分を引く
int centerX = (320 - w) / 2;
int centerY = (240 - h) / 2;
// 5. テキストの描画
display.setCursor(centerX, centerY);
display.setTextColor(0xFFFF); // 白
display.print(text);
// 6. 飾り(中央にガイドラインを描く場合)
//display.drawFastHLine(0, 120, 320, 0x1F); // 青い水平線
//display.drawFastVLine(160, 0, 240, 0x1F); // 青い垂直線
}
void loop() {}
参考





コメント