두 개의 선(SDA, SCL) 으로 여러 장치를 연결하는 동기식 시리얼 버스 (Inter-Integrated Circuit).
신호선
-
SDA — Serial Data — (양방향)
-
SCL — Serial Clock — (마스터가 생성)
-
둘 다 오픈드레인 → 풀업 저항 필수
통신 절차
- ① START 조건 : SCL이 High인 동안 SDA가 High → Low
- ② 주소 7비트 + R/W 1비트 전송
- ③ 슬레이브 ACK (해당 주소의 장치가 SDA를 Low로 당김)
- ④ 데이터 8비트 + ACK 를 반복
- ⑤ STOP 조건 : SCL이 High인 동안 SDA가 Low → High
START/STOP은 "SCL이 High일 때 SDA가 변하는" 특수한 조건이다. 일반 데이터 전송 중에는 SCL이 Low일 때만 SDA가 바뀌므로 구분된다.
오픈드레인이 핵심이다
각 장치는 SDA를 "Low로 당기기"만 할 수 있다. High로 밀지 못한다 High는 풀업 저항이 만든다
- 여러 장치가 동시에 출력해도 전기적 충돌이 없다
- 하나라도 Low면 Low (와이어드 AND)
이 성질 덕분에 ACK와 아비트레이션이 가능하다. 슬레이브가 SDA를 당기면 마스터가 그것을 읽어 ACK로 인식한다.
대가는 속도다. Low로 당기는 것은 빠르지만 High로 올라가는 것은 RC 시정수에 좌우되어 느리다.
주소
7비트 주소 → 최대 112개 (16개는 예약) 10비트 주소 → 확장 (덜 쓰임)
- 주소 충돌이 흔하다 — 같은 센서 두 개를 달면 주소가 같다
- 주소 선택 핀(A0/A1)이 있으면 다르게 설정
- 없으면 I2C 멀티플렉서(TCA9548A) 또는 별도 버스
데이터시트의 주소가 7비트인지 8비트(R/W 포함)인지 확인해야 한다. 0x68과 0xD0처럼 2배 차이로 표기되어 혼동을 준다.
속도 모드
- Standard — : 100 kbps
- Fast — : 400 kbps ← 가장 흔하다
- Fast+ — : 1 Mbps
- High-speed: 3.4 Mbps — (별도 프로토콜 필요)
SPI와의 선택
| 상황 | 선택 |
|---|---|
| 센서 여러 개, 저속, 핀 부족 | I2C |
| 대용량·고속 (디스플레이, 플래시) | SPI |
| 슬레이브가 많은데 핀이 없다 | I2C (주소로 구분) |
| 확실한 응답 확인이 필요 | I2C (ACK 있음) |
I2C는 "핀 절약", SPI는 "속도" 로 기억하면 된다.
자주 겪는 문제 ① — 버스 락업
슬레이브가 데이터를 전송하던 중 마스터가 리셋되면
→ 슬레이브는 계속 SDA를 Low로 잡고 있다
→ 마스터는 START를 만들 수 없다 (SDA가 이미 Low)
→ 버스가 영구적으로 멈춘다
복구 방법
// SCL을 수동으로 9번 토글해 슬레이브가 남은 비트를 전부 내보내게 한다
for (int i = 0; i < 9; i++) {
SCL_LOW(); delay_us(5);
SCL_HIGH(); delay_us(5);
if (READ_SDA()) break; // SDA가 풀리면 중단
}
// 그 뒤 STOP 조건을 만들어 정리
부팅 시 이 복구 루틴을 넣는 것이 실무 관행이다. 현장에서 원인 불명의 I2C 멈춤을 크게 줄여 준다.
자주 겪는 문제 ② — NACK
- 주소 전송 후 ACK가 없다
- 그 주소의 장치가 없다 (주소 오류, 전원 미인가, 배선 불량)
- HAL_I2C_IsDeviceReady() 로 스캔해 실제 주소를 찾는다
I2C 스캐너를 먼저 돌려 보는 것이 디버깅의 첫 단계다.
자주 겪는 문제 ③ — 풀업 저항
저항이 너무 크면 → 상승이 느려 고속에서 파형이 삼각형이 된다 저항이 너무 작으면 → 싱크 전류(3mA) 초과. Low 레벨이 안 내려간다
버스 총 커패시턴스 400pF 이하 유지가 규격
클럭 스트레칭
슬레이브가 SCL을 Low로 잡아 마스터를 기다리게 하는 기능이다. 느린 슬레이브(EEPROM 쓰기 중 등)가 시간을 벌 때 쓴다.
확장 개념
- SMBus — : I2C 기반. 타임아웃·PEC(패킷 오류 검사) 추가. 배터리·전원 관리용
- PMBus — : SMBus 확장. 전원 장치 전용
- I3C — : 차세대. 더 빠르고 인터럽트를 버스로 전달. 동적 주소 할당