ESP32-S3 + E-Paper 완전 사용 가이드
E-Paper는 SPI 인터페이스로 ESP32-S3에 연결합니다.
라이브러리는 GxEPD2가 사실상 표준이며, Adafruit GFX 기반이라 텍스트/도형 API가 익숙하게 느껴집니다.
Deep Sleep과 조합하면 배터리 수개월 수명이 가능한 것이 E-Paper의 가장 큰 장점입니다.
목차
- 필요한 부품
- 핀 연결 (SPI 배선)
- 라이브러리 설치
- 기본 텍스트 출력 코드
- 부분 갱신 (Partial Update)
- Deep Sleep 연동
- 전력 소비 비교
- 드라이버 IC별 GxEPD2 클래스
- 자주 발생하는 문제와 해결법
1. 필요한 부품
| 부품 | 대표 제품 | 비고 |
|---|---|---|
| E-Paper 모듈 | Waveshare 2.9" 흑백 / 1.54" 흑백 | SPI 4선 방식. 모듈 뒷면에서 드라이버 IC 모델명 확인 필수. |
| MCU | ESP32-S3 Dev Module | SPI 핀을 자유롭게 지정 가능. 기존 ESP32보다 유연함. |
| 연결 케이블 | 8핀 DuPont 케이블 | Waveshare 모듈에는 케이블이 포함된 경우 많음. |
| 커패시터 (권장) | 100µF 전해 + 100nF 세라믹 | 전원 라인 안정화. 화면 갱신 시 순간 전류 급증 대응. |
2. 핀 연결 (SPI 배선)
ESP32-S3는 기존 ESP32와 달리 SPI 핀을 자유롭게 지정할 수 있어 핀 충돌 없이 유연하게 연결이 가능합니다.
아래 핀 번호는 예시이며 자신의 보드 레이아웃에 맞게 변경하세요.
| E-Paper 핀 | 신호 이름 | ESP32-S3 GPIO (예시) | 설명 |
|---|---|---|---|
| VCC | 전원 | 3.3V | 반드시 3.3V. 5V 연결 시 패널 손상. |
| GND | 접지 | GND | 공통 GND |
| SCL (SCLK) | SPI 클럭 | GPIO36 | SPI 클럭 신호 |
| SDA (MOSI) | SPI 데이터 출력 | GPIO35 | MCU → E-Paper 단방향 전송 |
| CS | Chip Select | GPIO34 | LOW일 때 E-Paper 활성화 |
| DC | Data / Command | GPIO33 | LOW = 명령, HIGH = 데이터 |
| RST | Reset | GPIO32 | LOW 펄스로 패널 초기화 |
| BUSY | Busy 상태 신호 | GPIO31 | 반드시 연결. HIGH = 갱신 중. 이 신호를 무시하면 화면 깨짐. |
중요 - BUSY 핀: E-Paper는 화면 갱신 중 BUSY 핀을 HIGH로 유지합니다.
GxEPD2 라이브러리는 BUSY가 LOW가 될 때까지 자동으로 대기합니다.
BUSY 핀을 연결하지 않으면 다음 명령이 갱신 도중에 전송되어 화면이 깨지거나 패널이 손상될 수 있습니다.
전원 안정화 권장: E-Paper는 화면 갱신 시 순간적으로 전류가 크게 증가합니다.
VCC-GND 사이에 100µF 전해 커패시터와 100nF 세라믹 커패시터를 병렬로 달아주면
전압 강하로 인한 ESP32 브라운아웃 리셋을 예방할 수 있습니다.
3. 라이브러리 설치
Arduino IDE 기준 설치 방법:
Sketch → Include Library → Manage Libraries 에서 아래 3개를 검색하여 설치합니다.
| 순서 | 라이브러리 이름 | 제작자 | 역할 |
|---|---|---|---|
| 1 | GxEPD2 | ZinggJM | E-Paper 드라이버. 수십 종 패널 드라이버 IC 지원. 핵심 라이브러리. |
| 2 | Adafruit GFX Library | Adafruit | 텍스트, 도형, 비트맵 출력의 기반 그래픽 라이브러리. GxEPD2 의존성. |
| 3 | U8g2_for_Adafruit_GFX | olikraus | 한글 등 유니코드 폰트, 다양한 크기의 확장 폰트 지원. (선택사항이나 권장) |
보드 설정: Arduino IDE → Tools → Board → ESP32S3 Dev Module 선택.
보드 패키지가 없다면 Boards Manager에서 "esp32 by Espressif" 버전 3.x 이상을 설치하세요.
4. 기본 텍스트 출력 코드
GxEPD2는 페이지 방식으로 동작합니다.firstPage() → 그리기 명령 → nextPage() 루프로 화면을 전송합니다.nextPage()가 false를 반환할 때까지 do-while로 반복합니다.
#include <SPI.h>
#include <GxEPD2_BW.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeMonoBold9pt7b.h>
// ── 핀 정의 ───────────────────────────────────────────
#define EPD_CS 34 // Chip Select
#define EPD_DC 33 // Data / Command
#define EPD_RST 32 // Reset
#define EPD_BUSY 31 // Busy (반드시 연결)
#define EPD_SCK 36 // SPI Clock
#define EPD_MOSI 35 // SPI MOSI (SDA)
// ── 디스플레이 객체 생성 ──────────────────────────────
// GxEPD2_BW<드라이버클래스, 높이> 이름(CS, DC, RST, BUSY)
// Waveshare 2.9" 흑백 (GDEW029T5 / SSD1680 계열)
GxEPD2_BW<GxEPD2_290_T5D, GxEPD2_290_T5D::HEIGHT>
display(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
void setup() {
Serial.begin(115200);
// ESP32-S3: SPI 핀을 명시적으로 지정
// begin(SCK, MISO, MOSI, SS) — E-Paper는 MISO 없음 (-1)
SPI.begin(EPD_SCK, -1, EPD_MOSI, EPD_CS);
display.init(115200); // 115200 = 시리얼 디버그 활성화
display.setRotation(1); // 0: 세로, 1: 가로, 2: 세로 반전, 3: 가로 반전
// ── 전체 화면 갱신 (Full Update) ──────────────────
display.setFullWindow();
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE); // 배경 흰색으로 초기화
display.setFont(&FreeMonoBold9pt7b); // 9pt 고정폭 볼드 폰트
display.setTextColor(GxEPD_BLACK);
display.setCursor(10, 30); // (x, y) — y는 베이스라인 기준
display.println("Hello E-Paper!");
display.setCursor(10, 55);
display.print("Boot: ");
display.println(millis() / 1000);
// 도형 그리기
display.drawRect(5, 5, 280, 118, GxEPD_BLACK); // 외곽선 사각형
display.drawLine(5, 65, 285, 65, GxEPD_BLACK); // 구분선
} while (display.nextPage()); // false 반환 시 전송 완료
// ── 화면 유지 후 E-Paper 절전 모드 ────────────────
// powerOff(): 재초기화 없이 다음 갱신 가능 (권장)
// hibernate(): 최저 전력이나 다음 갱신 전 display.init() 필요
display.powerOff();
}
void loop() {
// 기본 예제는 setup()에서 한 번만 갱신
}
좌표계 주의: setCursor(x, y)에서 y는 폰트의 베이스라인(baseline) 위치입니다.
FreeMonoBold9pt7b 기준 폰트 높이가 약 14px이므로 y=0이면 글자가 화면 위로 잘립니다.
첫 번째 줄은 y=18 이상으로 설정하세요.
5. 부분 갱신 (Partial Update) — 숫자/시간 업데이트
전체 갱신(Full Update)은 2~4초가 걸리고 화면 깜박임이 발생합니다.
숫자나 시간처럼 일부 영역만 바뀌는 경우 부분 갱신(Partial Update)을 사용하면
약 0.3초 내에 빠르게 업데이트할 수 있고 깜박임도 없습니다.
반드시 알아야 할 것: 모든 E-Paper 패널이 부분 갱신을 지원하지는 않습니다.
흑백 2색 패널은 대부분 지원하지만, 3색(흑백적) 패널은 부분 갱신을 지원하지 않습니다.
또한 부분 갱신을 너무 자주 반복하면 잔상(ghosting)이 생깁니다.
30분~1시간마다 한 번씩 전체 갱신으로 잔상을 제거해야 합니다.
// ── 부분 갱신 예시: 온도 숫자만 빠르게 업데이트 ────────
void updateTemperature(float temp) {
// 갱신할 영역 (x, y, width, height)
// 픽셀 단위로 변경이 필요한 영역보다 약간 크게 잡을 것
int16_t x = 10, y = 70;
uint16_t w = 200, h = 35;
display.setPartialWindow(x, y, w, h); // 부분 갱신 영역 지정
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE); // 해당 영역만 흰색으로 초기화
display.setFont(&FreeMonoBold9pt7b);
display.setTextColor(GxEPD_BLACK);
display.setCursor(x, y + 24);
display.print("Temp: ");
display.print(temp, 1); // 소수점 1자리
display.print(" C");
} while (display.nextPage());
}
// ── 잔상 방지: 전체 갱신 주기 관리 예시 ─────────────────
int partialCount = 0;
void loop() {
float temperature = readSensor(); // 센서 값 읽기
if (partialCount >= 30) { // 30회 부분 갱신 후
display.setFullWindow(); // 전체 갱신으로 잔상 제거
partialCount = 0;
// ... 전체 화면 다시 그리기
} else {
updateTemperature(temperature); // 부분 갱신
partialCount++;
}
delay(60000); // 1분 대기
}
6. Deep Sleep 연동 — 배터리 절감의 핵심
E-Paper의 진짜 장점은 Deep Sleep과 조합할 때 나옵니다.
화면을 업데이트하고 Deep Sleep에 진입하면 ESP32-S3 소비전류가 약 70µA로 떨어집니다.
E-Paper는 전원이 꺼져도 화면을 유지하므로 슬립 중 추가 전력이 전혀 필요하지 않습니다.
Deep Sleep의 동작 원리:
Deep Sleep에 진입하면 CPU, 대부분의 RAM, 디지털 주변장치가 모두 꺼집니다.
RTC 컨트롤러와 RTC 메모리만 유지됩니다.
Deep Sleep에서 깨어나면 전체 재부팅과 동일하게 setup()부터 다시 실행됩니다.
이전 상태를 유지하려면 RTC 메모리(RTC_DATA_ATTR)에 변수를 저장해야 합니다.
#include <SPI.h>
#include <GxEPD2_BW.h>
#include <Adafruit_GFX.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#define EPD_CS 34
#define EPD_DC 33
#define EPD_RST 32
#define EPD_BUSY 31
#define EPD_SCK 36
#define EPD_MOSI 35
// Deep Sleep 후에도 유지되는 변수 (RTC 메모리 저장)
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR float lastTemp = 0.0;
#define SLEEP_MINUTES 5 // 5분마다 깨어나 화면 갱신
GxEPD2_BW<GxEPD2_290_T5D, GxEPD2_290_T5D::HEIGHT>
display(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
void drawScreen() {
display.setFullWindow();
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
display.setFont(&FreeMonoBold9pt7b);
display.setTextColor(GxEPD_BLACK);
display.setCursor(10, 25);
display.print("Boot #");
display.println(bootCount);
display.setCursor(10, 50);
display.print("Temp: ");
display.print(lastTemp, 1);
display.println(" C");
display.setCursor(10, 75);
display.print("Sleep: ");
display.print(SLEEP_MINUTES);
display.println(" min");
// 외곽 테두리
display.drawRect(2, 2, 292, 124, GxEPD_BLACK);
} while (display.nextPage());
}
void setup() {
bootCount++;
// SPI 초기화
SPI.begin(EPD_SCK, -1, EPD_MOSI, EPD_CS);
// 0 = 시리얼 디버그 끔 (슬립 최적화 시 0 권장)
display.init(115200);
display.setRotation(1);
// 센서 읽기 (예시)
lastTemp = 24.5; // 실제 코드에서는 센서 라이브러리로 대체
// 화면 갱신
drawScreen();
// ── E-Paper 절전 진입 ────────────────────────────
display.powerOff();
// ── GPIO 핀 플로팅 방지 (누설 전류 차단) ──────────
// Deep Sleep 중 SPI 핀이 플로팅 상태가 되면 E-Paper 내부 회로에
// 전류가 흘러 Deep Sleep 전류가 수 mA로 늘어날 수 있음
gpio_hold_en((gpio_num_t)EPD_CS);
gpio_hold_en((gpio_num_t)EPD_DC);
gpio_hold_en((gpio_num_t)EPD_RST);
gpio_deep_sleep_hold_en();
// ── Deep Sleep 타이머 웨이크업 설정 ──────────────
esp_sleep_enable_timer_wakeup(
(uint64_t)SLEEP_MINUTES * 60ULL * 1000000ULL // 단위: 마이크로초
);
// Deep Sleep 진입 — 이 줄 이후 코드는 실행되지 않음
esp_deep_sleep_start();
}
void loop() {
// Deep Sleep 사용 시 loop()는 호출되지 않음
}
웨이크업 원인 확인 방법: 버튼으로 깨어났는지, 타이머로 깨어났는지 구분할 수 있습니다.
// setup() 맨 위에 추가
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
if (cause == ESP_SLEEP_WAKEUP_TIMER) {
// 타이머 웨이크업: 정기 갱신
} else if (cause == ESP_SLEEP_WAKEUP_EXT0) {
// 외부 핀(버튼) 웨이크업: 즉시 갱신
} else {
// 최초 부팅
}
7. 전력 소비 비교 (ESP32-S3 + 2.9" E-Paper 기준)
| 동작 상태 | 소비 전류 | 지속 시간 | 비고 |
|---|---|---|---|
| 화면 갱신 중 (Active) | 20~60mA | 2~4초 | 갱신 주기에만 발생. 전체 전력 소비의 대부분. |
| WiFi 연결 + 데이터 수신 | +100~250mA | 1~5초 | 날씨, 뉴스 등 인터넷 데이터 수신 시 추가. |
| Deep Sleep (ESP32-S3) | ~70µA | 슬립 전 구간 | Espressif 공식 측정 기준. 모듈 단독 시 약 26.85µW. |
| E-Paper 화면 유지 | 0W | 무한 | 전원이 완전히 꺼져도 화면 내용이 유지됨. |
| E-Paper hibernate() 모드 | ~0.01µA | 슬립 전 구간 | E-Paper 내부 DC-DC 완전 차단. 재기동 시 init() 필요. |
| E-Paper powerOff() 모드 | ~수 µA | 슬립 전 구간 | 재초기화 없이 다음 갱신 가능. 일반적으로 권장. |
배터리 수명 추정 (2000mAh 기준)
| 갱신 주기 | WiFi 사용 | 예상 배터리 수명 | 적합한 응용 |
|---|---|---|---|
| 5분마다 | 사용 안 함 | 약 4~6개월 | 온습도 센서 표시, 시계 |
| 5분마다 | 매번 연결 | 약 1~2개월 | 날씨 표시기, 대중교통 도착 정보 |
| 1시간마다 | 매번 연결 | 약 6~12개월 | 전자 가격표, 회의실 표시판 |
| 1일 1회 | 매번 연결 | 약 2~3년 | 오늘의 날씨/명언 표시 |
8. 드라이버 IC별 GxEPD2 클래스 이름
자신의 E-Paper 패널 뒷면에 표시된 모델명을 확인한 후 아래 표에서 해당 GxEPD2 클래스를 선택하세요.
잘못된 클래스를 선택하면 화면이 절반만 표시되거나 전혀 동작하지 않습니다.
| 패널 크기 | 패널 모델 / 드라이버 IC | 색상 | GxEPD2 클래스 이름 | 부분 갱신 |
|---|---|---|---|---|
| 1.54" | GDEP015OC1 / IL3829 | 흑백 | GxEPD2_154 |
지원 |
| 1.54" | GDEH0154D67 / SSD1681 | 흑백 | GxEPD2_154_D67 |
지원 |
| 2.13" | GDEH0213B72 / SSD1680 | 흑백 | GxEPD2_213_BN |
지원 |
| 2.13" | GDEW0213I5F / IL0373 | 흑백적 | GxEPD2_213c |
미지원 |
| 2.9" | GDEW029T5D / SSD1680 | 흑백 | GxEPD2_290_T5D |
지원 |
| 2.9" | GDEH029A1 / SSD1608 | 흑백 | GxEPD2_290 |
지원 |
| 2.9" | GDEW029Z13 / UC8151 | 흑백적 | GxEPD2_290c_Z13 |
미지원 |
| 4.2" | GDEY042T81 / SSD1683 | 흑백 | GxEPD2_420_GDEY042T81 |
지원 |
| 4.2" | GDEW042Z15 / IL0398 | 흑백적 | GxEPD2_420c |
미지원 |
| 7.5" | GDEW075T7 / GD7965 | 흑백 | GxEPD2_750_T7 |
지원 |
| 7.5" | GDEW075Z09 / UC8179 | 흑백적 | GxEPD2_750c_Z08 |
미지원 |
전체 지원 목록 확인: GxEPD2 GitHub 저장소의 src/ 폴더에서
모든 지원 드라이버 목록을 확인할 수 있습니다.
→ https://github.com/ZinggJM/GxEPD2
3색 패널 주의: 흑백적(Red) 또는 흑백황(Yellow) 3색 패널은GxEPD2_BW 대신 GxEPD2_3C 클래스를 사용해야 합니다.
또한 3색 패널은 갱신 시간이 10~15초로 매우 깁니다.
// 3색 패널 (흑백적) 사용 예시
#include <GxEPD2_3C.h>
GxEPD2_3C<GxEPD2_290c_Z13, GxEPD2_290c_Z13::HEIGHT>
display(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
// 적색 출력
display.setTextColor(GxEPD_RED);
display.println("Red Text");
// 흑색 출력
display.setTextColor(GxEPD_BLACK);
display.println("Black Text");
9. 자주 발생하는 문제와 해결법
| 증상 | 원인 | 해결법 |
|---|---|---|
| 화면이 전혀 바뀌지 않음 | BUSY 핀 미연결 | BUSY 핀을 반드시 GPIO에 연결. display.init() 전에 Serial.begin()으로 디버그 로그 확인. |
| 화면이 절반만 표시됨 | 잘못된 GxEPD2 드라이버 클래스 | 패널 뒷면 모델명 스티커 확인 후 올바른 클래스로 변경. |
| 화면에 잔상(ghost)이 남음 | 부분 갱신 과다 사용 | 30회~1시간 주기로 setFullWindow() 전체 갱신 실행. |
| Deep Sleep 후 화면이 깨짐 | GPIO 핀 플로팅으로 E-Paper에 오신호 유입 | gpio_hold_en()으로 슬립 중 핀 상태 유지. gpio_deep_sleep_hold_en() 추가. |
| Deep Sleep 전류가 수 mA로 높음 | SPI 핀 플로팅 또는 E-Paper 미절전 | display.powerOff() 호출 후 슬립 진입. gpio_hold_en() 적용. |
| 3.3V에서 동작 불안정, 브라운아웃 리셋 | 갱신 시 순간 전류 급증으로 전압 강하 | VCC-GND 간 100µF 전해 + 100nF 세라믹 커패시터 추가. |
| SPI.begin() 후 화면 응답 없음 | 다른 SPI 장치와 핀 충돌 | CS 핀을 각 장치마다 별도로 사용. SCK/MOSI는 공유 가능. |
| 갱신 속도가 매우 느림 (10초 이상) | 3색(흑백적/황) 패널 사용 | 3색 패널은 원래 10~15초 소요. 정상 동작. 흑백 패널로 교체 검토. |
| 텍스트가 화면 상단에서 잘림 | setCursor y 좌표가 너무 작음 | y 좌표를 폰트 높이 이상으로 설정. FreeMonoBold9pt7b 기준 y=18 이상. |
| nextPage() 루프가 무한 반복됨 | BUSY 핀 미연결 또는 표시 객체 초기화 실패 | display.init() 반환값 확인. BUSY 핀 연결 확인. Serial 로그로 디버깅. |
디버깅 시작 체크리스트
- BUSY 핀이 GPIO에 연결되어 있는가?
- VCC가 3.3V인가? (5V 연결 시 패널 손상)
- GxEPD2 드라이버 클래스가 패널 모델과 일치하는가?
- SPI.begin()에 올바른 핀 번호가 지정되어 있는가?
- display.init() 전에 SPI.begin()이 호출되었는가?
- display() 혹은 display.nextPage()가 호출되었는가? (이 줄 없으면 화면 전송 안 됨)
참고 자료
- GxEPD2 GitHub: https://github.com/ZinggJM/GxEPD2
- Waveshare E-Paper Wiki: https://www.waveshare.com/wiki/E-Paper_ESP32_Driver_Board
- ESP32-S3 Sleep Modes 공식 문서: https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/system/sleep_modes.html
- Adafruit GFX Library Guide: https://learn.adafruit.com/adafruit-gfx-graphics-library
Hardware Development Series — ESP32-S3 + E-Paper 실무 가이드

'ESP32' 카테고리의 다른 글
| ESP32 개발 보드에 USB-C 또는 Micro-USB 포트가 두 개 있는 이유 (0) | 2026.05.03 |
|---|---|
| ESP32 아두이노 환경과 ESP-IDF 환경 비교 (0) | 2026.04.30 |
| ESP-Claw 개념 (0) | 2026.04.27 |
| ESP32 SD 카드의 폴더를 PC에서 직접 보이게 (0) | 2026.04.22 |
| Iridium 9603N 전원 인가 시 BOD 리셋 이슈 (0) | 2026.04.12 |
| Iridium 9603N ESP32-S3 위성 통신 송신 절차 (0) | 2026.04.11 |
| ESP32 C3 Super Mini Pomodoro timer (0) | 2026.04.10 |
| ESP32의 시리얼 포트(UART) 사용 방법 (0) | 2026.04.09 |
취업, 창업의 막막함, 외주 관리, 제품 부재!
당신의 고민은 무엇입니까? 현실과 동떨어진 교육, 실패만 반복하는 외주 계약,
아이디어는 있지만 구현할 기술이 없는 막막함.
우리는 알고 있습니다. 문제의 원인은 '명확한 학습, 실전 경험과 신뢰할 수 있는 기술력의 부재'에서 시작됩니다.
이제 고민을 멈추고, 캐어랩을 만나세요!
코딩(펌웨어), 전자부품과 디지털 회로설계, PCB 설계 제작, 고객(시장/수출) 발굴과 마케팅 전략으로 당신을 지원합니다.
제품 설계의 고수는 성공이 만든 게 아니라 실패가 만듭니다. 아이디어를 양산 가능한 제품으로!
귀사의 제품을 만드세요. 교육과 개발 실적으로 신뢰할 수 있는 파트너를 확보하세요.
캐어랩