Arduino言語でのHUB75 LEDアレイ制御の一応の完成形

基本の表示機能の作成から、

https://isehara-3lv.sakura.ne.jp/blog/2024/12/16/hub75パネルを動かしてみた/

① 画像イメージ情報を3パターン用意

② LED駆動用にUSBの口が二つあるACアダプタ(二つで3Aの容量)用意してラズピコのケーブルも接続できるようにして物としてのまとまりをよくする

USB – DCプラグケーブル購入して、ジャックは見繕って加工してつないだ

③ M5Stackをコントローラーにして3パターンの画像切り替えと表示オフ機能を持たせた

ラズピコとM5Stackのコードと、LEDアレイとラズピコ接続回路図は以下のリンクから、

https://github.com/chateight/hub75_led_array_drive

Arduino言語ではこれでほぼ終わりの予定

 

admin

HUB75パネルを動かしてみた

オーダーしていたパーツが届いたので動かしてみた

HUB75のフラットケーブルをつなぐためにユニバーサルボードでラズピコとコネクタの配線、GPIOとの対応付はAmazonで売り切れになっている接続ボードのコネクションリストと同じにした、何かの時に役立つかもしれないから

最初はテストパターン表示

フィボナッチ数列の13までの昇順と降順でちょうど16になるからそれを4回繰り返したデータを用意して表示させてみた、リフレッシュサイクルは60フレーム/s以上(akafuji表示状態で測定すると1000/14 =71.429 フレーム/s)だから人の目には綺麗に見える

次にイメージデータを表示させてみる、データは「赤富士」のフリー素材を持ってきて最終的にb/g/rの[3][32][64]配列に落とし込む、実行はPython使って最終的にはコンソールに出力された以下のcolor_code変数をプリントしたものをArduino IDEに切り貼り

#
# to make r/g/b array from shrinked bmp image
#
from PIL import Image
import numpy as np
import cv2

# resize the image file
image = Image.open("akafuji.png")
resized_image = image.resize((64, 32))
resized_image.save("resized.bmp")

# get b/g/r value
image = cv2.imread('resized.bmp')
color_code = [[[0 for i in range(64)] for j in range(32)] for k in range(3)]

for x in range(64):
	for y in range(32):
		pixel = image[y, x]
	
		color_code[0][y][x] = image[y, x, 0]//16
		color_code[1][y][x] = image[y, x, 1]//16
		color_code[2][y][x] = image[y, x, 2]//16

print(color_code)		

元の64*32のbmpファイルは、

こんな感じ、

これをLEDで表示させると、

ゴミが出てます、データそのものは0になっているから、なんかしらの要因でそうなってますね

ちなみに、Arduino IDEのコードの核の部分は以下の通り

<main処理>

void setup1(){
  // set the gpio pins direction
  pinMode(r1, OUTPUT);
  pinMode(r2, OUTPUT);    
  pinMode(g1, OUTPUT);
  pinMode(g2, OUTPUT);    
  pinMode(b1, OUTPUT);
  pinMode(b2, OUTPUT);    
  pinMode(clk, OUTPUT);    
  pinMode(lat, OUTPUT);
  pinMode(oe, OUTPUT);    
  pinMode(a, OUTPUT);
  pinMode(b, OUTPUT);    
  pinMode(c, OUTPUT);
  pinMode(d, OUTPUT);
  pinMode(e, OUTPUT);

  gpio_put(oe, HIGH);
  gpio_put(lat, LOW);
  gpio_put(clk, LOW);
}

void loop1(){
  // message check from core0
  //
  while (rp2040.fifo.available()>0){
    // bool rp2040.fifo.pop_nb(uint32_t *dest)
    message = rp2040.fifo.pop();
  }
  // led display refreah loop
  //
  for (row_c = 0; row_c < 16; row_c++){
    // select row address
    gpio_put(oe, HIGH);
    gpio_put(a, a_sel[row_c]);
    gpio_put(b, b_sel[row_c]);
    gpio_put(c, c_sel[row_c]);
    gpio_put(d, d_sel[row_c]);
    gpio_put(e, e_sel[row_c]);
    
    // display row data with shade control
    for (byte j = 0; j < 15; j++){
      row_set(j);
      gpio_put(oe, HIGH);
      clock_func(lat);
      gpio_put(oe, LOW);
    }
  }
  //mov_data(1, 2);
}

<common.h>

行選択信号のeは64*32では使わないので常時LOW

// gpio pin assignment for HUB75

#define r1 (2)
#define r2 (5)
#define g1 (3)
#define g2 (8)
#define b1 (4)
#define b2 (9)
#define clk (11)
#define lat (12)
#define oe (13)
#define a (10)
#define b (16)
#define c (18)
#define d (20)
#define e (22)

// row select matrix

byte row_c = 0; // row counter

byte a_sel[32] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
byte b_sel[32] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1};
byte c_sel[32] = {0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1};
byte d_sel[32] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1};
byte e_sel[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

<functions>

clock_func()でgpis_put()が一回だけだとパルスが細すぎてLEDパネルでうまくラッチできないから3回書き込みでパルス幅確保

// to make clock pulse

void clock_func(byte port){
  //digitalWrite(0, HIGH);
  gpio_put(port, 1);  // in case of wite once, data wouldn't be captured correctly
  gpio_put(port, 1);
  gpio_put(port, 1);
  //digitalWrite(0, LOW);
  gpio_put(port, 0);
}

// row data buffer write

void row_set(byte shade){
    for (byte i = 0; i < 64; i++){ 
// akafuji color order b/g/r 
// red 
      if (akafuji[2][row_c][i] > shade){
        gpio_put(r1, 1);        
      }
      else{
        gpio_put(r1, 0);
      }
      if (akafuji[2][row_c + 16][i] > shade){
        gpio_put(r2, 1);
      }
      else{
        gpio_put(r2, 0);
      }
      // green
      if (akafuji[1][row_c][i] > shade){
        gpio_put(g1, 1);
      }
      else{
        gpio_put(g1, 0);
      }
      if (akafuji[1][row_c + 16][i] > shade){
        gpio_put(g2, 1);
      }
      else{
        gpio_put(g2, 0);
      }
      //blue
      if (akafuji[0][row_c][i] > shade){
        gpio_put(b1, 1);
      }
      else{
        gpio_put(b1, 0);
      }
      if (akafuji[0][row_c + 16][i] > shade){
        gpio_put(b2, 1);
      }
      else{
        gpio_put(b2, 0);
      }
      // write to row buffer
      clock_func(clk);
    }
}

文字も自分でフォント作るよりも、既存のフォントで文字作ってそれをイメージ化してbmpデータとするのが現実的に思える

P.S.

いきなりですが、ゴミ対策はアドレス選択変更前に表示オフを追加すれば良い、つまりrow選択アドレス変える時には表示を一旦オフにしろという原則通り、

// select row address 
gpio_put(oe, HIGH);

 

iPhoneでlive撮影して、平均化してしまうと輝度低下して冴えない写真になるのは致し方なしだね

 

admin