I2C 통신 버스의 구조와 임베디드 장치 연결 방식
I2C의 SDA·SCL 구조, 주소 체계, 전송 모드, 버스 중재와 Linux·임베디드 환경에서의 활용 방법을 정리한다.
2026-08-14 · 최초 발행 2026-01-16
보드 안의 주변 장치를 연결하는 I2C 버스
I2C(Inter-Integrated Circuit, IIC)는 Philips Semiconductor(현 NXP)가 개발한 동기식 직렬 버스 프로토콜이다. 단일 보드에서 마이크로컨트롤러가 센서, EEPROM, RTC, LCD 컨트롤러 같은 주변 장치와 저속으로 통신하도록 설계됐다.
SDA와 SCL 두 개의 양방향 신호선만 사용하면서도 다중 마스터와 다수의 슬레이브 연결을 지원한다. 핀과 배선을 줄여야 하는 임베디드 설계에서 널리 쓰이는 이유다.
I2C는 집적 회로 사이의 단순한 통신, 최소한의 핀과 배선, 다중 장치 연결, 소프트웨어 주소 지정을 목표로 만들어졌다.
1982년 Philips Semiconductor에서 개발됐으며, 이후 1992년에는 400kbit/s Fast-mode, 1998년에는 3.4Mbit/s High-speed mode, 2000년에는 1Mbit/s Fast-mode Plus, 2012년에는 5Mbit/s Ultra Fast-mode가 추가됐다. 현재는 NXP Semiconductors가 관리한다.
| 특성 | 사양 |
|---|---|
| 신호선 | 2개 (SDA, SCL) |
| 주소 | 7비트 또는 10비트 |
| 속도 | 100kbps ~ 5Mbps |
| 거리 | 보드 내 (~수 m) |
| 토폴로지 | 버스 (멀티 드롭) |
SDA는 양방향 데이터 라인이고, SCL은 클럭 신호 라인이다. 마스터가 클럭을 생성하며, 슬레이브는 클럭 스트레칭으로 전송 시점을 조절할 수 있다. 7비트 주소로는 최대 127개 슬레이브 주소를, 10비트 주소로는 1023개를 다룰 수 있다.
오픈 드레인으로 공유하는 SDA와 SCL
I2C 장치는 SDA와 SCL을 HIGH로 직접 구동하지 않고 LOW로만 구동하는 오픈 드레인 또는 오픈 콜렉터 방식을 사용한다. HIGH 상태는 풀업 저항이 만든다. 이 구조는 Wired-AND 논리를 구성하고, 버스 충돌을 감지할 수 있게 한다.
전압 레벨은 표준적으로 3.3V 또는 5V를 사용한다. LOW는 0.3 x VCC 이하, HIGH는 0.7 x VCC 이상이며, 혼합 전압 환경에서는 레벨 시프터를 사용할 수 있다.
풀업 저항은 버스 커패시턴스에 따라 조절한다. 표준 모드에서는 1kΩ ~ 10kΩ, Fast 모드에서는 1kΩ ~ 3kΩ 범위가 제시된다.
START부터 STOP까지의 전송 규칙
전송은 START 조건으로 시작하고 STOP 조건으로 끝난다. SCL이 HIGH일 때 SDA가 HIGH에서 LOW로 바뀌면 START 조건이며, 같은 SCL 상태에서 SDA가 LOW에서 HIGH로 바뀌면 STOP 조건이다.
데이터는 MSB부터 8비트 단위로 전송한다. 각 바이트 뒤에는 ACK 또는 NACK이 따라온다.
7비트 주소는 총 128개이며 범위는 0x00 ~ 0x7F다. 예약 주소를 제외하면 112개를 사용할 수 있다. 첫 번째 바이트는 7비트 슬레이브 주소와 R/W 비트로 구성된다.
| A6 | A5 | A4 | A3 | A2 | A1 | A0 | R/W |
|----|----|----|----|----|----|----|----|
| 7비트 슬레이브 주소 | 0=W |
| 1=R |
10비트 주소는 1024개 주소를 지원한다. 첫 번째 바이트에는 11110XX(예약), 상위 2비트, R/W가 들어가며 두 번째 바이트에는 하위 8비트가 들어간다.
| 주소 | 용도 |
|---|---|
| 0x00 | 일반 호출 (General Call) |
| 0x01 | START 바이트 |
| 0x02-0x03 | 예약 (CBUS) |
| 0x04-0x07 | 예약 (고속 모드) |
| 0x78-0x7B | 예약 (10비트 주소) |
| 0x7C-0x7F | 예약 (미래용) |
쓰기·읽기와 반복 START
마스터 쓰기는 슬레이브 주소에 W(0)를 붙여 전송한 뒤 레지스터 주소와 데이터를 보낸다.
읽기에서는 마스터가 슬레이브 주소에 R(1)을 붙이고, 마지막 데이터 뒤에는 NACK을 보낸 다음 STOP으로 마무리한다.
레지스터 주소를 먼저 지정한 뒤 값을 읽는 복합 전송은 일반적으로 사용되는 형태다. 이때 STOP 대신 REPEATED START를 사용한다.
| 모드 | 속도 | 특징 |
|---|---|---|
| Standard | 100 kbit/s | 기본 모드 |
| Fast | 400 kbit/s | 널리 사용 |
| Fast Plus | 1 Mbit/s | 높은 구동력 |
| High Speed | 3.4 Mbit/s | 특수 프로토콜 |
| Ultra Fast | 5 Mbit/s | 단방향만 지원 |
슬레이브가 처리 시간을 더 필요로 하면 SCL을 LOW로 유지해 마스터를 대기시키는데, 이를 클럭 스트레칭(Clock Stretching)이라고 한다.
다중 마스터가 충돌을 처리하는 방식
여러 마스터가 동시에 버스를 사용하려 하면 중재가 필요하다. 두 마스터가 함께 START를 발생시킨 뒤 SDA에 데이터를 출력하고, 각 마스터는 동시에 SDA 라인을 모니터링한다. 자신이 보낸 값과 읽은 값이 다르면 해당 마스터는 중재에서 패배하고 즉시 전송을 중단한다.
이 중재는 데이터 손실 없이 동작하는 비파괴적 방식이다. 더 많은 0을 가진 낮은 주소가 우선권을 가지며, 하드웨어와 소프트웨어로 구현할 수 있다.
센서부터 I/O 확장기까지 연결하는 장치
I2C 버스에는 다양한 주변 장치를 연결할 수 있다.
- 온도 센서: LM75, TMP102
- 가속도계/자이로: MPU6050
- 습도 센서: SHT31, HTU21D
- 조도 센서: BH1750
- EEPROM: 24LC256, AT24C32
- FRAM: FM24CL64
- RTC: DS1307, DS3231, PCF8563
- OLED: SSD1306
- LCD: PCF8574 (I/O 확장)
- I/O 확장: PCF8574, PCF8575, MCP23017
Linux와 임베디드 환경에서 접근하기
Linux에서는 /sys/bus/i2c/devices/의 sysfs 인터페이스로 장치를 검색하고 기본 정보를 확인할 수 있다. /dev/i2c-N의 devfs 인터페이스는 사용자 공간에서 직접 접근할 때 사용한다. 커널 드라이버는 i2c-dev.ko이며, i2c*smbus* 함수가 관련 인터페이스다.
Arduino에서는 Wire 라이브러리로 마스터를 초기화하고 전송과 읽기를 수행한다.
#include <Wire.h>
void setup() {
Wire.begin(); // 마스터로 초기화
}
void loop() {
Wire.beginTransmission(0x48); // 슬레이브 주소
Wire.write(0x00); // 레지스터 주소
Wire.endTransmission();
Wire.requestFrom(0x48, 2); // 2바이트 요청
int temp = Wire.read() << 8;
temp |= Wire.read();
}
Raspberry Pi에서는 Python의 smbus로 바이트 읽기, 쓰기, 블록 읽기를 수행할 수 있다.
import smbus
bus = smbus.SMBus(1) # I2C 버스 1
# 읽기
data = bus.read_byte_data(0x48, 0x00)
# 쓰기
bus.write_byte_data(0x48, 0x01, 0xFF)
# 블록 읽기
block = bus.read_i2c_block_data(0x48, 0x00, 4)
응답하지 않는 버스를 점검할 때
장치가 응답하지 않으면 주소를 i2cdetect로 확인하고, 풀업 저항 값, 전원 공급, 배선 연결을 점검한다. 데이터 오류는 클럭 속도, 풀업 저항, 버스 커패시턴스, 노이즈 환경에서 원인을 찾을 수 있다.
버스 락업은 슬레이브가 SDA를 LOW로 유지할 때 발생한다. 수동 클럭 생성으로 복구하거나 전원을 리셋하는 방법을 사용한다.
Linux의 i2c-tools는 버스 스캔과 레지스터 확인에 쓸 수 있다.
# 버스 스캔
i2cdetect -y 1
# 레지스터 덤프
i2cdump -y 1 0x48
# 단일 읽기
i2cget -y 1 0x48 0x00
# 단일 쓰기
i2cset -y 1 0x48 0x01 0xFF
로직 분석기는 신호 파형을 분석하고 타이밍 문제를 진단하며 프로토콜을 디코딩하는 데 사용한다.
SPI와 UART 사이에서 I2C를 고를 때
| 특성 | I2C | SPI | UART |
|---|---|---|---|
| 신호선 | 2 | 4+ | 2 |
| 속도 | ~5Mbps | ~50Mbps | ~3Mbps |
| 거리 | 짧음 | 짧음 | 길음 |
| 다중 장치 | 주소 기반 | CS 핀 필요 | 1:1 |
| 복잡도 | 중간 | 간단 | 간단 |
| 전이중 | 반이중 | 전이중 | 전이중 |
다수의 저속 장치를 연결하거나 핀 수가 제한된 환경에서는 I2C가 맞는다. 센서, EEPROM, RTC가 대표적인 대상이다. 고속 통신과 핀 여유가 있다면 SD 카드, Flash, ADC에 SPI를 고려할 수 있다. 장거리 통신, 디버깅 콘솔, 1:1 통신에는 UART가 적합하다.