概要
Raspberry Pi PicoのPIO (Programmable I/O) を活用し、HUB75規格のLEDマトリクス(32×64ドット)にて 30fps・4096色 の動画(MP4ファイルから変換したデータ)を表示するプログラムを実装しました。
※以前公開した記事「ラズパイPicoでMP4動画データをLEDマトリクスに表示」のプログラムをアップデートしました。
実際の動作の様子は、以下のデモ動画(YouTube)からご覧いただけます。
YouTubeの動作デモ動画
成果物
ソースコード、バイナリファイル、および使い方は以下のGitHubリポジトリにまとめています。
shiomachisoft / PicoMtrx
ハードウェア構成
本システムで使用した主なハードウェアは以下の通りです。
| 項目 | 詳細 |
|---|---|
| マイコンボード | Raspberry Pi Pico (RP2040) |
| ドットマトリクスLED | WAVESHARE-20591(Pico-RGB-Matrix-P3-64x32)(64×32ドット / RGB各2階調 / HUB75規格 / Picoを直接装着可能)WIKI |
実現したスペック
- 表示フレームレート: 30 fps
- 表現色数: 4096色(RGB各4bit / 16階調 PWM制御)
システム構成とデータの流れ
PC側で事前にMP4ファイルからマトリクスデータを作成した後、Picoへ送信して表示させる構成です。
- ①変換: PCアプリでMP4ファイルを読み込み、マトリクス用のデータに変換。
- ②送信: PCからPicoへ、マトリクスデータをUSB通信で送信。
- ③表示: Picoがデータを受信し、ドットマトリクスLEDの表示を更新。
LEDマトリクスの描画・階調制御の仕組み
WAVESHARE-20591(Pico-RGB-Matrix-P3-64x32)は、全32行のパネルを上下16行ずつに分け、同時に2行ずつ選択して点灯させる 1/16ダイナミックスキャン方式 を採用しています。
なお、各LED素子自体は物理的に 「点灯 (1)」 か 「消灯 (0)」 の2状態しか出力できません。
スキャン時間とフレームレート:
- 1行あたりのスキャン時間: 10 μs
- 1フレーム内のスキャン回数: $16\text{行} \times 16\text{階調(※1)} = \mathbf{256\text{回}}$
- 1フレームの完成時間: $10\mu s \times 256\text{回} = 2,560\mu s$ (約 2.56 ミリ秒 / リフレッシュレート:約 390 Hz)
(※1): 例として、あるピクセルの赤色成分の階調値が 8(輝度 50%) の場合、以下のように動作します。
- 点灯回数: 1行あたり全16回のスキャン(1スキャン10μs)のうち、8スキャンで点灯し、残り8スキャンは消灯します。人間の目の残像効果により 「50%の明るさ(中間の濃さ)の赤色」 として認識されます。
PIO (Programmable I/O) による高速パラレル転送
HUB75規格のLEDマトリクスは、クロックピン(CLK)の立ち上がりエッジに同期して、上下各ラインのカラーデータ(R1, G1, B1 / R2, G2, B2)を内部のシフトレジスタへ順次流し込む構造になっています。
横1行(64列)の描画データを送るには、データ出力とCLKのHigh/Low切り替えを64回連続で行う必要があり、これらをCPUのGPIO操作(ソフトウェア制御)で行うと、クロック生成とピン制御のオーバーヘッドだけでCPUリソースを使い果たしてしまいます。
そこで、ラズパイPicoの PIO (Programmable I/O) を活用し、2行のアセンブリ命令で高速なハードウェア自動転送を実現しました。
PIOプログラム (rgb_matrix.pio)
.program rgb_matrix
.side_set 1
.wrap_target
out pins, 8 side 0
nop side 1
.wrap
PIOの動作解説
-
out pins, 8 side 0:
TX FIFO(送信バッファ)から1ピクセル分(8ビット)のデータを取り出し、R1/G1/B1/R2/G2/B2が割り当てられたGPIOへ出力します。同時にside-set機能により、クロックピン (CLK) を Low に駆動します。 -
nop side 1:
何も実行せず(nop)、side-set機能により クロックピン (CLK) を High に立ち上げます。この立ち上がりエッジにより、LEDマトリクス側のシフトレジスタにデータが確定・ラッチされます。 -
オートプル(Auto-pull)と64列分の転送シーケンス:
C-SDK初期化部分でsm_config_set_out_shift(&c, true, true, 32);を指定しています。
これにより、CPU側は32ビット(4ピクセル分)のデータをTX FIFOに書き込むだけで、PIOが自動的に8ビットずつ切り出してシフトアウト(オートプル)を行います。
横1行あたり64列(64ピクセル)の転送に対し、CPUは32ビットデータを 16回送信($4 \times 16 = 64\text{ピクセル}$)するだけ で完了します。
