【Raspberry Pi】Raspberry Pi Pico+Adafruit DVI Breakout BoardでHDMI出力

Raspberry

今回は、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() が失敗していると思い込んでいたものの、実際には高すぎるクロックによりマイコン自体がフリーズし、プログラムが一行も走っていない状態でした。

そこから段階的にクロックを下げて検証した結果、以下のことが判明しました。

  1. 250MHzまで: プログラムは正常に走るが、DVI信号(640×480相当)のタイミング規格に合わないため、液晶には何も表示されない。
  2. 252MHz(黄金比): 320×240ピクセル・ダブリングに必要な正確なクロック。ここで初めて液晶が同期した。
  3. 教訓: 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() {}

参考

コメント