【Raspberry Pi】Raspberry Pi PicoのHDMI出力で「文字のギザギザ」を克服する!VGA白黒表示とフォント最適化の記録

Linux

前回、PicoとAdafruit DVI Breakout Boardでテキスト表示に成功しましたが、標準設定では文字の「ギザギザ(ジャギー)」が目立ち、視認性に課題が残りました。

そこで今回は、Pico 2を使わず、あえて初代Picoのままでどこまで美しく、読みやすいテキスト表示ができるか挑戦しました。AI(Gemini)と相談しながら導き出した、リソース節約と美しさの両立案をまとめます。


今回の改善アプローチ

1. 解像度とメモリの最適化(VGA 640×480)

あえてカラーを捨てて**白黒(1bitモード)**に特化することで、RP2040の限られたRAMを節約。これにより、高解像度なVGA(640×480)設定でも、画面全体をクリアに維持したまま高速な描画を可能にしました。

2. フォントサイズと「太字(Bold)」の魔法

最小の fontsize=1 を使用すると、1ピクセルの線が細すぎて液晶モニター上ではかすれて見えたり、逆にジャギーが際立ったりします。

標準フォントの限界

PicoのDVI出力サンプルでよく使われる標準フォントは、軽量ですが「1ドットの集合体」感が強く、VGA解像度ではどうしても文字が細く、ギザギザ(ジャギー)が目立ってしまいます。

2. 解決策:FreeSansBold12pt7b の採用

今回は、Adafruit GFXライブラリ等で利用できる**プロポーショナルフォント(可変幅フォント)**の太字版を導入しました。

  • なぜこのフォントか?:
    • Bold(太字)なので、1bit(白黒)表示でも文字が背景に負けず、くっきりと浮かび上がります。
    • 文字の角や曲線が最適化されており、標準フォントよりも圧倒的に「読みやすく、高級感がある」表示になります。

3. 実装の工夫(メモリ管理)

プロポーショナルフォントは美しい反面、標準フォントよりもデータ量が大きくなります。

  • 白黒(1bit)化の効果: 画面のバッファを1bitに絞ることで浮いたRAMを、これらリッチなフォントデータの格納や描画処理に充てることができました。

「こだわりポイント」のヒント

  • 「fontsize=1」の意味: 大きなフォントを縮小するのではなく、12ptなどの適切なサイズのフォントをそのままsize=1で描画するのが、最もエッジが綺麗に出る設定です。「拡大してぼやけるのを防ぐ」という意図を伝えると説得力が増します。
  • ソースコードの紹介: #include <Fonts/FreeSansBold12pt7b.h> を追加し、tft.setFont(&FreeSansBold12pt7b); のようにセットする一連の流れを載せると、初心者にとって非常に有益なガイドになります。
#include <PicoDVI.h>
#include <Fonts/FreeSans9pt7b.h> // 滑らかなフォントを読み込み 
#include <Fonts/FreeSansBold12pt7b.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 = false   // ← これを true/false 切り替えて試す
};
int progress = 0; // 0〜100
// 引数から false を削除し、電圧(VREG_VOLTAGE_1_20)を指定
//DVIGFX16 display(DVI_RES_320x240p60, my_dvi_cfg, VREG_VOLTAGE_1_20);
// 修正前
// DVIGFX1 display(DVI_RES_640x480p60, my_dvi_cfg, VREG_VOLTAGE_1_20);

// 修正後:第2引数に「ダブルバッファリング」の設定が必要です
DVIGFX1 display(DVI_RES_640x480p60, false, my_dvi_cfg, VREG_VOLTAGE_1_30);
void setup() {
  if (!display.begin()) {
    pinMode(LED_BUILTIN, OUTPUT);
    while (1) {
      digitalWrite(LED_BUILTIN, HIGH); delay(100);
      digitalWrite(LED_BUILTIN, LOW);  delay(100);
    }
  }

  display.fillScreen(0);
  display.setTextColor(1);

  // 1. まずフォントをセットする(重要:getTextBoundsの前にセット)
  display.setFont(&FreeSansBold12pt7b);
  display.setTextSize(1); // FreeFontsは元から大きいのでサイズ2くらいが綺麗です

  String text = "Loading........";

  // 2. テキストの範囲を計算
  int16_t x1, y1;
  uint16_t w, h;
  display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);

  // 3. 中央の座標を計算
  // FreeFontsの場合、y座標には「高さ(h)」を足す、もしくはy1のオフセットを考慮する必要があります
  int centerX = (640 - w) / 2;
  int centerY = (480 + h) / 2; // +h にすることでベースラインを中央に下げます

  // 4. テキストの描画
  display.setCursor(centerX, centerY);
  display.print(text);

  // 画面の四隅に枠を描画(これが映れば信号は正常です)
  display.drawRect(0, 0, 640, 480, 1);
}

まとめ

「Picoでもここまでできる!」 デバイスの性能を限界まで引き出すのではなく、**「適切なリソース配分(カラーを捨ててフォントに振る)」**という戦略によって、実用性の高いディスプレイ出力を実現できました。

コメント