SSD1306 OLED 제어

최진철·2026년 1월 17일

Embedded 📲

목록 보기
1/4
post-thumbnail

I²C 드라이버

Datasheet해당 링크 에서 확인할 수 있습니다.

Linux Kernel Module

Raspberry Pi에서 SSD1306 기반 128×32 OLED 디스플레이를 제어

Linux 커널 I²C 드라이버를 구현하며 실제 동작이 어떻게 이루어지고 있는지를 파악해 봅시다!!.

1. 코드 개요

  • 목적: I²C를 통해 SSD1306 OLED를 초기화하고 텍스트를 출력
  • 주요 기능:
    • OLED 초기화 (Display ON, Contrast, Multiplex 등)
    • 5×8 폰트 기반 텍스트 출력
    • 화면 채우기, 커서 이동, 수평 스크롤
    • 모듈 로드/제거 시 정리 (화면 지우기, Display OFF)

2. 주요 상수 정의

#define I2C_BUS_AVAILABLE       1           // Raspberry Pi I²C-1 버스
#define SLAVE_DEVICE_NAME       "SSD1306"   // 드라이버 이름
#define SSD1306_SLAVE_ADDR      0x3C        // SSD1306 기본 I²C 주소
#define SSD1306_MAX_SEG         128         // 가로 해상도 (세그먼트)
#define SSD1306_MAX_LINE        3           // 페이지 수 (32줄 → 4페이지, 0~3)
#define SSD1306_DEF_FONT_SIZE   5           // 5×8 폰트

3. I2C Communication

I2C_write() / I2C_Read()

static int I2C_Write(unsigned char *buf, unsigned int len) {
    return i2c_master_send(dev_i2c_client_oled, buf, len);
}
  • master → slave 데이터 전송

SSD1306_Write() - Control Byte 처리 ⭐

Control Byte (8비트) 구조
┌────────────────────────┐
│ 7  6  5  4  3  2  1  0 │
└────────────────────────┘
   │  │
   │  └─ D/C# (Data/Command#) 비트 (6번째 비트) 1:-> data 0 - > cmd 
   └──── Co (Continuation bit) (7번째 비트, 거의 0으로 씀)

static void SSD1306_Write(bool is_cmd, unsigned char data) {
    unsigned char buf[2] = {0};
    buf[0] = is_cmd ? 0x00 : (1 << 6);  
    // 0x00 = Command, 0x40 = Data
    buf[1] = data;
    i2c_master_send(dev_i2c_client_oled, buf, 2);
}

Control Byte 의미 (SSD1306 데이터시트 p.20~21)

  • 0x00 → 다음 바이트는 명령어 (0xAE, 0xA8 등)
  • 0x40 → 다음 바이트는 GDDRAM에 쓸 픽셀 데이터

4. 초기화 함수 - SSD1306_DisplayInit()

1. SSD1306_DisplayInit() - 디스플레이 초기화

데이터시트 관련 페이지: p.20~21 (Initialization Flow), p.28~31 (Command Table)


Datasheet에 나와 있는 절차를 따라 software initalization을 진행합니다.

SSD1306_Write(true, 0xAE);      // Entire Display OFF
                                // p.28: 0xAE = Set Display ON/OFF (0=OFF)

SSD1306_Write(true, 0xD5);      // Set Display Clock Divide Ratio / Oscillator Frequency
SSD1306_Write(true, 0x80);      // Default value (추천값)
                                // p.32: 0xD5 = Clock 설정, 0x80 = 기본 분주비

SSD1306_Write(true, 0xA8);      // Set Multiplex Ratio
SSD1306_Write(true, 0x1F);      // 32 COM lines (128×32 OLED용)
                                // p.31: 0xA8 = Multiplex Ratio, N = 31 (0x1F) → 32줄

SSD1306_Write(true, 0xD3);      // Set Display Offset
SSD1306_Write(true, 0x00);      // No offset
                                // p.31: 0xD3 = Vertical shift
																	-->상세 정보는 38페이지 
SSD1306_Write(true, 0x40);      // Set Display Start Line = 0
                                // p.30: 0x40~0x7F = Start Line 설정

SSD1306_Write(true, 0x8D);      // Charge Pump Setting
SSD1306_Write(true, 0x14);      // Enable charge pump (0x14 = Enable)
                                // p.63: 0x8D = Charge Pump, 0x14 = Enable (3.3V)

SSD1306_Write(true, 0x20);      // Set Memory Addressing Mode
SSD1306_Write(true, 0x00);      // Horizontal addressing mode
                                // p.34: 0x20 = Addressing Mode, 0x00 = Horizontal

SSD1306_Write(true, 0xA1);      // Set Segment Remap (Column 127 → SEG0)
                                // p.31: 0xA0/A1 = Segment Remap

SSD1306_Write(true, 0xC8);      // COM Output Scan Direction (Reverse)
                                // p.31: 0xC0/C8 = COM Scan Direction

SSD1306_Write(true, 0xDA);      // Set COM Pins Hardware Configuration
SSD1306_Write(true, 0x02);      // Alternative COM pin config (128×32용)
                                // p.40: 0xDA = COM Pins, 0x02 = Alternative + disable remap

SSD1306_Write(true, 0x81);      // Set Contrast Control
SSD1306_Write(true, 0x80);      // Contrast = 128 (중간값)
                                // p.28: 0x81 = Contrast, 0~255

SSD1306_Write(true, 0xD9);      // Set Pre-charge Period
SSD1306_Write(true, 0xF1);      // Phase1=15, Phase2=1
                                // p.32: 0xD9 = Pre-charge

SSD1306_Write(true, 0xDB);      // Set VCOMH Deselect Level
SSD1306_Write(true, 0x20);      // ~0.77×VCC
                                // p.32: 0xDB = VCOMH, 0x20 = 0.77 VCC

SSD1306_Write(true, 0xA4);      // Entire Display ON (RAM 내용 출력)
                                // p.28: 0xA4/A5 = Resume to RAM / Ignore RAM

SSD1306_Write(true, 0xA6);      // Normal Display (1=ON)
                                // p.28: 0xA6/A7 = Normal / Inverse

SSD1306_Write(true, 0x2E);      // Deactivate scroll
                                // p.29: 0x2E = Deactivate scroll

SSD1306_Write(true, 0xAF);      // Display ON
                                // p.28: 0xAF = Display ON

SSD1306_Fill(0x00);             // 전체 화면 지우기 (검정)

2. SSD1306_SetCursor() - 커서(페이지+컬럼) 이동

데이터시트 관련 페이지: p.29 (0x21, 0x22 명령어)

  • 상세 정보 p-36

SSD1306_Write(true, 0x21);      // Set Column Address
SSD1306_Write(true, cursorPos); // 시작 컬럼
SSD1306_Write(true, 127);       // 끝 컬럼 (128-1)
SSD1306_Write(true, 0x22);      // Set Page Address
SSD1306_Write(true, lineNo);    // 시작 페이지 (0~3)
SSD1306_Write(true, 3);         // 끝 페이지 (32줄 → 4페이지)
  • 0x21 : Column Address 범위 설정
  • 0x22 : Page Address 범위 설정
    → 이후 쓰기하는 데이터가 이 범위에만 적용됨

3. SSD1306_PrintChar() & SSD1306_String() - 글자 출력

데이터시트 관련 페이지: p.32~35 (GDDRAM 구조)

c -= 0x20;                      // 폰트 배열은 0x20(스페이스)부터 시작
for (temp = 0; temp < 5; temp++) {
    data_byte = SSD1306_font[c][temp];
    SSD1306_Write(false, data_byte);  // Control Byte 0x40 + 5바이트 폰트 데이터
}
SSD1306_Write(false, 0x00);     // 글자 끝 여백 1픽셀
  • SSD1306은 GDDRAM(Graphic Display Data RAM)에 픽셀 데이터를 순서대로 씁니다.
  • Horizontal addressing mode에서는 왼쪽→오른쪽, 위→아래로 자동 진행
  • 5×8 폰트 → 5바이트(가로 5픽셀) + 1바이트 여백

4. SSD1306_Fill() - 전체 화면 채우기

데이터시트 관련 페이지: p.25 (GDDRAM Write)

for (i = 0; i < 128 * 4; i++)   // 128×32 = 4096비트 = 512바이트
    SSD1306_Write(false, data); // 0x00 = 지우기(검정), 0xFF = 채우기(흰색)

5. SSD1306_StartScrollHorizontal() - 수평 스크롤

데이터시트 관련 페이지: p.30 (0x26/0x27, 0x2F 명령어)

SSD1306_Write(true, is_left_scroll ? 0x27 : 0x26); // 0x26=Right, 0x27=Left
.
SSD1306_Write(true, start_line_no);
SSD1306_Write(true, 0x00);      // 5 frames interval (속도)
SSD1306_Write(true, end_line_no);
.
SSD1306_Write(true, 0x2F);      // Activate scroll

6. remove() 시 정리

SSD1306_Write(true, 0x2E);      // Deactivate scroll (p.29)
SSD1306_Fill(0x00);             // 화면 지우기
SSD1306_String(" ThanK YoU!!! ");
msleep(2000);
SSD1306_Fill(0x00);
SSD1306_Write(true, 0xAE);      // Display OFF

⇒ Thank You!! 출력되고 화면 종료


Datasheet Check

함수데이터시트 명령어역할
SSD1306_DisplayInit()0xAE, 0xD5, 0xA8...초기화 시퀀스 전체
SSD1306_SetCursor()0x21, 0x22출력 영역 설정
SSD1306_PrintChar()GDDRAM Write픽셀 데이터 쓰기
SSD1306_Fill()GDDRAM Write전체 화면 채우기
SSD1306_StartScrollHorizontal()0x26/0x27, 0x2F스크롤 기능
SSD1306_Write()Control Byte + Data명령어/데이터 구분
profile
세상의 어려운 문제를 해결하자

0개의 댓글