いわゆる HUB75 という規格のLEDパネルを M5Stack で光らせます。光らせて何かをするというより、LED Matrix Panel の光る仕組みについて実験してみたという主旨です。
参考
HUB75 LED Matrix Panel
屋外の高いところとかに、輝度がやや高めの LED ディスプレイがあったら、だいたいこの規格の LED パネルが使われています(多分)。最近は国内でも簡単に購入できるようになりました。そこそこの輝度があって、制御に必要な機器もそれなりの値段で入手できることから、業務用としてはかなり広く使われているという印象です。
HUB75 の仕様については、下記の記事で詳しく書かれているので、ここでは要点だけ書きます。
なお、64x64 のパネルの場合は HUB75E という、HUB75 を拡張した規格が使われていることが多いようです。HUB75E では GND ピンをひとつ潰して、代わりに列を指定するための E ピンが追加されています。ABCDE の 5bit で指定することで、32列 (x2=64列) 指定できます。
使ったもの
- M5Stsck
- 32x64 LED Matrix Panel (HUB75)
- 30A/5V 安定化電源
LED Matrix Panel は、同じ見た目をしていても、信号回りの仕様(ピン配置、HIGH/LOWの解釈)が異なることがあるようです。
結線
- LED Matrix のピン名: M5Stack の GPIO
- A: 18
- B: 19
- C: 21
- D: 22
- R1: 16
- G1: 26
- B1: 17
- CLK: 2
- OE: 23
- LAT: 5
実際に結線しようとしてから気がつきましたが、M5Stack のデフォルトで出ているピンだけだと、微妙にピン数が足りなくて R2,G2,B2 に結線できませんでした。無理矢理出して足りるようにすることもできますが、実験なのでとりあえず今回は R2,G2,B2 は無しでやりました。このため、パネルの上半分しか光りません。
M5Stack の 18 と 19 のピンは LCD に使われているため、LED パネルを光らせている間に LCD を動かすとバグります。1, 3 のピンはシリアル通信に使われており、35, 36 は input only なので今回の用途には使えません。
なお LED Matrix Panel は 5V 動作ですが、M5Stack の 3.3V の出力を直接入れても問題なく動作するようです。
だいぶん粗いですが、こんな結線でも光りました。ただし、ちょっとでも触るとノイズがのってちらつきます。
全点灯プログラム
実験なので、いろいろしやすいように Arduino で書いてみました。PIN_R1, PIN_G1, PIN_B1 を HIGH にしたり LOW にしたりすると、色を変えられます。
#define PIN_A 18
#define PIN_B 19
#define PIN_C 21
#define PIN_D 22
#define PIN_R1 16
#define PIN_G1 26
#define PIN_B1 17
#define PIN_CLK 2
#define PIN_OE 23
#define PIN_LAT 5
void setup()
{
pinMode( PIN_A, OUTPUT );
pinMode( PIN_B, OUTPUT );
pinMode( PIN_C, OUTPUT );
pinMode( PIN_D, OUTPUT );
pinMode( PIN_R1, OUTPUT );
pinMode( PIN_G1, OUTPUT );
pinMode( PIN_B1, OUTPUT );
pinMode( PIN_CLK, OUTPUT );
pinMode( PIN_OE, OUTPUT );
pinMode( PIN_LAT, OUTPUT );
digitalWrite( PIN_A, LOW );
digitalWrite( PIN_B, LOW );
digitalWrite( PIN_C, LOW );
digitalWrite( PIN_D, LOW );
digitalWrite( PIN_R1, LOW );
digitalWrite( PIN_G1, LOW );
digitalWrite( PIN_B1, LOW );
digitalWrite( PIN_LAT, LOW );
// OE のみ HIGH で OFF になる
digitalWrite( PIN_OE, HIGH );
digitalWrite( PIN_CLK, LOW );
}
void loop()
{
int i = 0;
char d = 0;
for ( d = 0; d < 16; d++ ){
// ラッチはこのタイミングで HIGH にする必要があるぽい
digitalWrite( PIN_LAT, HIGH );
// (R=1,G=1,B=1)
digitalWrite( PIN_R1, HIGH );
digitalWrite( PIN_G1, HIGH );
digitalWrite( PIN_B1, HIGH );
// R2,G2,B2 も結線できている場合
// digitalWrite( PIN_R2, HIGH );
// digitalWrite( PIN_G2, HIGH );
// digitalWrite( PIN_B2, HIGH );
// RGB データ (R=1,G=1,B=1) を 64ibt 分転送する
for ( i = 0; i < 64; i++ ){
digitalWrite( PIN_CLK, HIGH );
digitalWrite( PIN_CLK, LOW );
}
// LED を消灯する (データ転送時のちらつきを防ぐ)
digitalWrite( PIN_OE, HIGH );
// LED パネルの光らせる列を 4bit で指定する
digitalWrite( PIN_A, ( d & 1 ) );
digitalWrite( PIN_B, ( d & 2 ) >> 1);
digitalWrite( PIN_C, ( d & 4 ) >> 2);
digitalWrite( PIN_D, ( d & 8 ) >> 3);
// 4bit で指定した列に RGB データを転送する
digitalWrite( PIN_LAT, LOW );
// LED を点灯する
digitalWrite( PIN_OE, LOW );
}
}
中間色点灯プログラム
LED が点灯する時間の長さを調整することで、中間色を表現してみるテストです。
// setup() と #define は上のプログラムと同じなので省略
// 色調(階調)の設定
inline void SET_RGB( char r, char g, char b, int j ){
digitalWrite( PIN_R1, r > j ? HIGH : LOW );
digitalWrite( PIN_G1, g > j ? HIGH : LOW );
digitalWrite( PIN_B1, b > j ? HIGH : LOW );
}
char d = 0;
void loop()
{
int i = 0;
int j = 0;
for ( j = 0; j < 16; j++ ){ // RGB 16 階調 (16x16x16=4096色)
for ( d = 0; d < 16; d++ ){
digitalWrite( PIN_LAT, HIGH );
for ( i = 0; i < 64; i++ ){
SET_RGB( d, i/4, 15-d, j );
digitalWrite( PIN_CLK, HIGH );
digitalWrite( PIN_CLK, LOW );
}
digitalWrite( PIN_OE, HIGH );
digitalWrite( PIN_A, ( d & 1 ) );
digitalWrite( PIN_B, ( d & 2 ) >> 1);
digitalWrite( PIN_C, ( d & 4 ) >> 2);
digitalWrite( PIN_D, ( d & 8 ) >> 3);
digitalWrite( PIN_LAT, LOW );
digitalWrite( PIN_OE, LOW );
}
}
}
240MHz 動作なら 256 階調でもできそうなのですが、上記のプログラムで 256 階調にするとちらつきました。16 階調くらいにして、ようやくちらつかなくなりました。真面目に 256 階調やるなら、やはり DMA などを使う必要がありそうです。
結論
いろいろ中途半端になってしまったので、ESP32 でもうちょっと真面目に書いて情報追記しときます(いつ?)。