I2C 주소 똑같아도 상관없음! 멀티플랙서 TCA9548A 사용법

I2C 주소가 같은 ssd1306 5개를 esp32-c3 mini 에 연결해서 구동하려고 한다. 어떻게 연결해야 하나?

1. I2C 주소 문제 (0x3C, 0x3D)

일반적인 SSD1306 모듈은 뒷면의 저항(Jumper) 위치를 옮겨서 주소를 0x3C 또는 0x3D 중 하나로 설정할 수 있습니다.

  • 결론: 동일한 I2C 버스 하나에는 최대 2개까지만 직접 연결할 수 있습니다.
  • 우리는 5개를 연결해야 하므로, 단순히 병렬로 연결하는 것만으로는 불가능합니다.

2. 해결 방법: I2C Multiplexer (TCA9548A) 사용

가장 깔끔하고 권장되는 방법은 TCA9548A 같은 I2C 확장 모듈을 사용하는 것입니다.

  • 원리: 이 칩은 1개의 I2C 입력을 받아 8개의 독립된 I2C 채널(선택 가능)로 분리해 줍니다.
  • 연결 방식: ESP32-C3의 I2C 핀을 TCA9548A에 연결하고, 각 OLED를 TCA9548A의 SD0/SC0부터 SD4/SC4까지 하나씩 연결합니다.
  • 장점: 코드가 매우 단순해지며 전압 관리도 수월합니다.

3. 멀티플렉서 없이 연결하는 방법 (S/W I2C 또는 Multi-Bus)

부품을 추가하고 싶지 않다면 두 가지 대안이 있습니다.

A. 소프트웨어 I2C (Bit-banging)

ESP32-C3는 핀 매핑이 자유롭습니다. 5개의 디스플레이를 위해 각각 다른 GPIO 쌍을 사용하는 방식입니다.

  • 핀 소모: SDA 5개 + SCL 1개(공통) = 총 6개의 핀 필요.
  • 단점: CPU 부하가 늘어나고 화면 업데이트 속도가 느려질 수 있습니다.

B. 공통 SCL + 개별 SDA 방식

SSD1306 라이브러리(u8g2 등)에서 SDA 핀을 각각 다르게 설정하여 5개의 인스턴스를 생성합니다.

  • ESP32-C3 GPIO 예시:
    • SCL: GPIO 8 (공통)
    • SDA1: GPIO 0, SDA2: GPIO 1, SDA3: GPIO 2, SDA4: GPIO 3, SDA5: GPIO 4

4. 회로 연결 가이드 (TCA9548A 기준 권장)

ESP32-C3 MiniTCA9548ASSD1306 (5개)
3.3VVINVCC (모두 연결)
GNDGNDGND (모두 연결)
GPIO 8 (SCL)SCL
GPIO 10 (SDA)SDA
SD0~SD4각 OLED의 SDA에 하나씩 연결
SC0~SC4각 OLED의 SCL에 하나씩 연결

⚠️ 주의사항

  1. 전류 소모: OLED 5개를 동시에 켜면 전류 소모가 상당합니다. ESP32-C3 Mini의 3.3V 출력 핀만으로는 부족할 수 있으니, 외부 3.3V 전원을 사용하는 것이 안정적입니다.
  2. 메모리(RAM): ESP32-C3는 RAM이 넉넉한 편이지만, 128×32 해상도 버퍼 5개를 동시에 유지하면 메모리 압박이 올 수 있습니다. u8g2 라이브러리의 _F_(Full Buffer) 모드 대신 _1_ 또는 _2_ (Page Buffer) 모드 사용을 권장합니다.

Pythone PCA9548A.py

from machine import Pin, SoftI2C
import ssd1306
import time
import math

# 1. I2C 및 PCA9548A 설정
i2c = SoftI2C(scl=Pin(1), sda=Pin(0), freq=400000)
PCA_ADDR = 0x70

# 요청하신 새로운 채널 구성: 2, 3, 4, 6
CHANNELS = [2, 3, 4, 6]
WIDTH, HEIGHT = 128, 32

def select_channel(ch):
    i2c.writeto(PCA_ADDR, bytearray([1 << ch]))

# 2. 각 화면 객체 초기화
displays = []
for i, ch in enumerate(CHANNELS):
    select_channel(ch)
    oled = ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c)
    oled.contrast(50)
    displays.append(oled)
    print(f"Device {i+1} on Channel {ch} 초기화 완료")

# --- 애니메이션 변수 ---
offset = 0
ball_x, ball_y = 64, 16
dx, dy = 3, 2

print("데모 쇼를 시작합니다 (채널 2, 3, 4, 6)")

try:
    while True:
        # --- [화면 1: 슬라이딩 텍스트 (Ch 2)] ---
        select_channel(CHANNELS[0])
        d1 = displays[0]
        d1.fill(0)
        d1.text("SYSTEM ONLINE", int(math.cos(offset/5)*10) + 10, 10)
        d1.show()

        # --- [화면 2: 다이내믹 바 그래프 (Ch 3)] ---
        select_channel(CHANNELS[1])
        d2 = displays[1]
        d2.fill(0)
        for b in range(6):
            h = int((math.sin(offset/4 + b) + 1) * 12) + 2
            d2.fill_rect(5 + (b*20), 32-h, 12, h, 1)
        d2.show()

        # --- [화면 3: 바운싱 볼 (Ch 4)] ---
        select_channel(CHANNELS[2])
        d3 = displays[2]
        d3.fill(0)
        d3.fill_rect(ball_x, ball_y, 4, 4, 1)
        ball_x += dx
        ball_y += dy
        if ball_x <= 0 or ball_x >= 124: dx *= -1
        if ball_y <= 0 or ball_y >= 28: dy *= -1
        d3.show()

        # --- [화면 4: 스캐닝 라인 (Ch 6)] ---
        select_channel(CHANNELS[3])
        d4 = displays[3]
        d4.fill(0)
        scan_x = (offset * 4) % 128
        d4.vline(scan_x, 0, 32, 1)
        d4.text("SCANNING...", 35, 12)
        d4.show()

        offset += 1
        time.sleep_ms(5) # 전환 속도를 더 높였습니다.

except KeyboardInterrupt:
    print("데모 종료")

코멘트

“I2C 주소 똑같아도 상관없음! 멀티플랙서 TCA9548A 사용법” 에 하나의 답글

  1. micro2iot 아바타

    [구매정보] 블로그에서 사용한 부품 구매정보입니다.
    아래 링크를 통해 구매 시 소정의 수수료를 제공받으며, 채널 운영에 큰 도움이 됩니다.

micro2iot에 답글 남기기 응답 취소

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다