무엇을 만들었나
산업·공사 현장에 걸 동적 전광판이다. 실시간 시계와 기상청 날씨를 띄우고, 기온에 따라 더위·동상 주의를 자동으로 바꿔 표시하며, 안전 수칙 6단계를 순서대로 스크롤한다.
| 항목 | 내용 |
|---|---|
| 기간 | 2026.07.18 ~ 07.26 |
| 컨트롤러 | ESP32 (NodeMCU-32S) |
| 패널 | 64×32 HUB75 RGB LED 매트릭스 2장 — 물리 128×32 / 논리 256×32 |
| 드라이버 | 1/8 스캔 · ICN2038S |
| 전원 | 5V 20A 파워 서플라이 + 선 터미널 블록, 승압(레벨 시프터) 모듈 |
| 소프트웨어 | Arduino IDE · ESP32-HUB75-LED-MATRIX-PANEL-DMA-Display · Adafruit_GFX · FreeRTOS |
| 역할 | 1인 풀스택 — 회로/전원 설계, 펌웨어, API 연동, 픽셀 에디터 제작 |
전원부터
LED 매트릭스는 전기를 많이 먹는다. 64×32 패널 하나에 픽셀이 2,048개, 두 장이면 4,096개다. 전부 흰색으로 켜면 순간 전류가 상당히 올라간다. 5V 20A 파워 서플라이를 쓰고 선 터미널을 압착해 단자대에 물렸다.
여기까지는 예상한 작업이었다. 문제는 신호선 쪽에서 나왔다.
문제 1 — 3.3V로는 부족했다
ESP32의 GPIO 신호를 HUB75 리본 케이블에 점퍼선으로 직접 물렸더니 픽셀이 계속 깜빡이고 화면이 깨졌다.
회로 중간에 승압 칩(Step-up Converter / Level Shifter) 모듈을 넣어 로직 레벨을 5V로 올렸다. 깜빡임과 화면 깨짐이 한 번에 사라졌다.
문제 2 — 픽셀이 뒤죽박죽으로 나온다

전원과 신호를 정리하고 나니 화면은 켜졌는데, 글자를 그리면 라인 순서가 엉망으로 나왔다. 코드는 멀쩡한데 화면만 조각나 있었다.
원인은 패널 내부 구조에 있었다. 1/8 스캔 방식 64×32 패널은 픽셀 블록이 2-1-4-3 순서로 배치되어 있다. 라이브러리가 가정하는 일반적인 순서와 다르기 때문에, 논리 좌표를 그대로 넘기면 화면 위에서 블록이 뒤바뀐다.
좌표 변환으로 덮어버리기
배선을 다시 만드는 대신 소프트웨어에서 좌표를 바꿔 넘기기로 했다. Adafruit_GFX 를 상속한 VirtualMatrix 클래스를 만들어, 논리 좌표 (x, y) 를 실제 패널의 물리 좌표 (px, py) 로 변환한 뒤 그리도록 했다.
class VirtualMatrix : public Adafruit_GFX {
public:
VirtualMatrix() : Adafruit_GFX(LOGICAL_WIDTH, LOGICAL_HEIGHT) {}
void drawPixel(int16_t x, int16_t y, uint16_t color) override {
if (x < 0 || x >= LOGICAL_WIDTH || y < 0 || y >= LOGICAL_HEIGHT) return;
if (!dma_display) return;
const int panel_idx = x / 64;
const int local_x = x % 64;
int px, py;
// 1/8 스캔 (2-1-4-3) 픽셀 블록 및 출력 라인 순서 재배치 연산
if (y < 16) {
if (local_x < 32) {
px = panel_idx * 64 + local_x + 32; py = y;
} else {
px = panel_idx * 64 + (local_x - 32); py = y;
}
} else {
if (local_x < 32) {
px = panel_idx * 64 + local_x + 32; py = y - 16;
} else {
px = panel_idx * 64 + (local_x - 32); py = y - 16;
}
}
dma_display->drawPixel(px, py, color);
}
};
핵심은 drawPixel 하나만 오버라이드했다는 점이다. Adafruit_GFX 의 선 그리기, 사각형, 텍스트 출력은 전부 내부적으로 drawPixel 을 부른다. 그래서 이 함수 하나만 고쳐 놓으면 그 위의 모든 그리기 함수가 자동으로 보정된다.
| 변환하는 것 | 이유 |
|---|---|
x / 64, x % 64 | 몇 번째 패널인지, 그 패널 안에서 몇 번째 열인지 분리 |
local_x < 32 분기로 ±32 | 좌우 절반이 서로 뒤바뀌어 있어 맞바꾼다 |
y >= 16 일 때 y - 16 | 아래쪽 16행이 물리적으로는 위쪽과 같은 행에 들어간다 |
1편 정리
여기까지가 화면에 원하는 그림을 띄울 수 있게 되기까지의 이야기다. 전원을 넉넉히 잡고, 신호 레벨을 5V로 올리고, 픽셀 좌표를 패널에 맞게 재배치했다.
다음 편에서는 한글이 깨져서 결국 픽셀 에디터를 직접 만든 일을 쓴다. 아두이노 기본 폰트로는 한글이 성립하지 않았고, 결국 브라우저에서 도는 픽셀 에디터를 만들어 53개 도안을 직접 찍었다.
3편은 화면이 15초씩 멈추던 문제와 배경에 남는 푸르스름한 잔상 이야기다. 그리고 4편에서 그 잔상 진단이 틀렸다는 걸 알게 된다.