I²C — 선 두 개로 여럿을 다룬다
SPI 는 슬레이브마다 CS 핀이 필요했다. I²C 는 선 두 개로 최대 100여 개를 다룬다. 비결은 주소를 데이터로 보내는 것과 **오픈드레인 + 풀업**이다.
선 둘, 모두 오픈드레인
VDD
|
[Rp] [Rp] 풀업 저항 (둘 다 필요)
| |
SDA ─────┴─────┼───────┬───────────┬──────────
SCL ───────────┴───────┼───────┬───┼──────┬───
| | | |
마스터 슬레이브A 슬레이브B
모든 장치가 당기기만 하고(open-drain) 밀지 않는다. 그래서 여럿이 같은 선에 붙어도 단락이 나지 않는다.
아무도 안 당기면 → 풀업이 HIGH 로 올린다
하나라도 당기면 → LOW
이 성질을 와이어드 AND 라 하고, I²C 의 중재·클럭 스트레칭·ACK 가 전부 이것 위에 서 있다.
풀업이 없으면 아무것도 안 된다. 오픈드레인은 HIGH 를 만들 수 없으므로 선이 계속 떠 있고, 통신은 시작조차 못 한다. "I²C 가 전혀 응답이 없다" 의 1순위 원인이다.
풀업 저항을 어떻게 고르나
너무 크면 → 상승이 느려 고속에서 파형이 삼각형이 된다
너무 작면 → 전류가 늘고 LOW 전압이 충분히 안 내려간다
상승 시간 ≈ 0.85 × Rp × Cb
Cb = 버스 전체 정전용량 (선 + 장치 핀, 규격 최대 400pF)
| 속도 모드 | 최대 속도 | 최대 상승 시간 | 흔한 Rp |
|---|---|---|---|
| Standard | 100 kHz | 1000 ns | 4.7k~10k |
| Fast | 400 kHz | 300 ns | 2.2k~4.7k |
| Fast Plus | 1 MHz | 120 ns | 1k 내외 |
Fast 모드(300ns) 에 Cb=200pF 이면
Rp ≤ 300ns / (0.85 × 200pF) ≈ 1.76kΩ
규격상 버스 정전용량 상한이 400pF 다. 선을 길게 뽑거나 장치를 많이 붙이면 이 한계에 닿아, 저항을 아무리 낮춰도 파형이 안 선다. 그때는 I²C 버스 버퍼나 리피터를 쓴다.
증상 진단
파형이 삼각형 · 상승이 느리다 → Rp 가 너무 크거나 Cb 가 너무 크다
LOW 가 0.5V 까지밖에 안 내려간다 → Rp 가 너무 작다 (전류 과다)
아래쪽 한계도 계산으로 나온다 — 저항은 "범위"다
위는 최대값(상승 시간)만 본 것이다. 최소값은 반대편, 즉 LOW 를 만들 수 있는가에서
나온다. 오픈드레인이라 LOW 는 슬레이브의 트랜지스터가 전류를 빨아들여(sink) 만드는데,
규격이 그 능력을 IOL 로 정해 둔다.
Rp(min) = (VDD − VOL(max)) / IOL
I²C 규격: IOL = 3 mA, VOL(max) = 0.4 V
VDD = 3.3V → Rp(min) = (3.3 − 0.4) / 3mA ≈ 967 Ω
VDD = 5.0V → Rp(min) = (5.0 − 0.4) / 3mA ≈ 1.53 kΩ
이보다 낮추면 트랜지스터가 다 못 빨아들여 LOW 가 0.4V 아래로 안 내려간다. 그러면 상대가 그 신호를 0 으로 못 읽어 통신이 깨진다 — 위 "증상 진단"의 두 번째 줄이 이것이다.
두 한계를 합치면 창(window)이 나온다 (VDD 3.3V, Cb 100pF 기준).
| 모드 | Rp(min) — LOW 보장 | Rp(max) — 상승 시간 | 실무 선택 |
|---|---|---|---|
| Standard 100kHz | 967 Ω | 11.8 kΩ | 4.7 kΩ (여유 큼) |
| Fast 400kHz | 967 Ω | 3.5 kΩ | 2.2 kΩ |
| Fast Plus 1MHz | 967 Ω | 1.4 kΩ | 1 kΩ (창이 거의 없다) |
왜 4.7kΩ 이 관행이 됐나 — 100kHz·낮은 용량에서 창의 한가운데라 웬만해선 안 틀린다. 그런데 400kHz 로 올리거나 선을 길게 뽑아 Cb 가 커지면 창의 위쪽이 내려와 4.7kΩ 이 창 밖으로 밀려난다. "속도만 올렸는데 통신이 깨졌다"의 정체가 이것이다 — 저항은 그대로인데 허용 범위가 좁아진 것이다.
함정 — Cb 는 선 길이뿐 아니라 붙은 장치 수에도 비례한다(핀당 약 10pF). 센서를 하나 더 달았더니 깨지는 일이 그래서 생긴다.
꼬리질문 대비 — "풀업이 왜 필요한가?"(오픈드레인은 LOW 만 만들 수 있어 HIGH 를 저항이 만든다 — 그래서 와이어드 AND 가 되고 다중 마스터 중재가 가능하다). "Rp 를 최소값으로 하면 항상 좋은가?"(상승은 빨라지지만 LOW 소비 전류가 늘고 배터리 기기에서 문제 — 3.3V/1kΩ 이면 LOW 마다 3.3mA).
프레임 — 시작·주소·ACK·정지

START SCL 이 HIGH 인 동안 SDA 가 HIGH→LOW (유일하게 이때만 SDA 가 변한다)
데이터 SCL 이 LOW 인 동안에만 SDA 를 바꾼다
ACK 받는 쪽이 9번째 클럭에 SDA 를 LOW 로 당긴다
STOP SCL 이 HIGH 인 동안 SDA 가 LOW→HIGH
"SCL 이 HIGH 일 때 SDA 가 변하면 특수 신호" 라는 규칙 하나가 START·STOP 을 데이터와 구분한다. 별도의 제어선 없이 프레임 경계를 만드는 영리한 설계다.
쓰기: [S] [주소+W] [A] [레지스터] [A] [데이터] [A] [P]
읽기: [S] [주소+W] [A] [레지스터] [A] [Sr] [주소+R] [A] [데이터] [N] [P]
^ 반복 시작 — STOP 없이 방향을 바꾼다
반복 시작(repeated start) 이 중요하다. STOP 을 내면 버스가 풀려 다른 마스터가 끼어들 수 있다. 레지스터 주소를 쓴 뒤 값을 읽는 사이에 끼어들면 엉뚱한 레지스터를 읽는다. 그래서 STOP 없이 Sr 로 이어 간다.
주소 — 7비트인데 8비트로 쓴다
7비트 주소 0x68 을 보낼 때 실제 바이트는
1101000 0 = 0xD0 쓰기 (R/W = 0)
1101000 1 = 0xD1 읽기 (R/W = 1)
└─0x68─┘ └ 방향
데이터시트가 어느 형식으로 적었는지 확인해야 한다. 어떤 문서는 0x68(7비트)로, 어떤 문서는 0xD0(8비트, 쓰기)로 적는다. 이걸 혼동해 주소를 두 배로 넣거나 절반으로 넣는 것이 초보의 대표적 실수다.
// STM32 HAL 은 8비트 형식(왼쪽 시프트된 값)을 받는다
HAL_I2C_Master_Transmit(&hi2c1, 0x68 << 1, buf, n, 100);
// ^^^^^^^^^ 7비트를 시프트
// 붙어 있는 장치를 전부 찾아보는 스캐너 — 가장 먼저 돌려 볼 코드
for (uint8_t a = 1; a < 128; a++) {
if (HAL_I2C_IsDeviceReady(&hi2c1, a << 1, 1, 10) == HAL_OK)
printf("found 0x%02X\r\n", a);
}
주소가 안 맞는지 확인하는 가장 빠른 방법이다. 아무것도 안 나오면 배선·풀업 문제, 예상과 다른 주소가 나오면 데이터시트 해석 문제다.
클럭 스트레칭 — 슬레이브가 시간을 번다
마스터가 SCL 을 놓아 HIGH 가 되려는 순간
슬레이브가 SCL 을 계속 LOW 로 당기고 있으면 → 마스터는 기다린다
오픈드레인이라 슬레이브도 SCL 을 당길 수 있다. 준비가 안 됐을 때 클럭을 붙잡아 마스터를 기다리게 하는 것이 클럭 스트레칭이다.
문제는 이것을 지원하지 않는 마스터가 있다는 것이다. 특히 소프트웨어로 I²C 를 구현한 경우 SCL 을 놓고 바로 다음으로 넘어가 버린다. 그러면 슬레이브가 준비되기 전에 데이터를 읽어 값이 깨진다.
// 소프트웨어 I²C 라면 반드시 확인해야 한다
static void scl_release(void) {
SCL_HIGH();
uint32_t t = 10000;
while (!SCL_READ() && --t) { } // ✓ 슬레이브가 놓을 때까지 기다린다
}
버스가 잠기면 — 실무에서 가장 골치 아픈 것
증상: SDA 가 계속 LOW 에 붙어 있고 아무 통신도 안 된다
원인: 슬레이브가 바이트를 절반만 보낸 상태에서 마스터가 리셋됐다
슬레이브는 클럭을 더 받아야 다음 상태로 가는데 아무도 안 준다
전원을 껐다 켜야 풀리는 상황이라 제품에서 치명적이다. 해법이 정해져 있다.
// 버스 복구 — SCL 을 9번 이상 흔들어 슬레이브를 빼낸다
void i2c_bus_recover(void) {
i2c_pins_to_gpio(); // I2C 주변장치를 떼고 GPIO 로
for (int i = 0; i < 9; i++) { // 최대 9클럭이면 어떤 상태에서든 빠져나온다
SCL_LOW(); delay_us(5);
SCL_HIGH(); delay_us(5);
if (SDA_READ()) break; // SDA 가 풀렸으면 됐다
}
// STOP 조건을 만들어 확실히 마무리
SDA_LOW(); delay_us(5);
SCL_HIGH(); delay_us(5);
SDA_HIGH();
i2c_pins_to_af(); // 다시 I2C 로
I2C1->CR1 |= I2C_CR1_SWRST; // 주변장치도 리셋
I2C1->CR1 &= ~I2C_CR1_SWRST;
i2c_init();
}
9클럭인 이유는 한 바이트가 8비트 + ACK 이므로, 어떤 지점에 멈춰 있든 9클럭 안에 프레임이 끝나기 때문이다.
이 복구 루틴을 초기화 시 한 번 무조건 돌리는 것이 실무 관행이다. 이전 실행에서 잠긴 채 리셋됐을 수 있기 때문이다.
다중 마스터와 중재
두 마스터가 동시에 시작하면
각자 주소를 보내다가, 자기가 HIGH 를 보냈는데 선이 LOW 면
→ "다른 놈이 당겼다" 를 알아채고 즉시 물러난다
와이어드 AND 덕분에 충돌이 자동으로 해결된다. 0 을 보내는 쪽이 이기므로, 주소가 작은 쪽이 우선이다. 진 쪽은 데이터가 깨지지 않고 그냥 물러나 다시 시도한다.
CAN 의 중재와 같은 원리인데, I²C 는 이것을 선 두 개로 한다.
실무에서 데는 곳
// ✗ 주소를 시프트 안 함
HAL_I2C_Master_Transmit(&hi2c1, 0x68, ...); // 실제로는 0x34 로 간다
// ✗ 풀업이 없거나 내부 풀업만 믿음
GPIOB->PUPDR |= (0b01 << (6*2)); // 내부 풀업은 수십 kΩ — 너무 약하다
내부 풀업으로 I²C 를 돌리려는 시도가 자주 보인다. 100kHz 에 짧은 선이면 우연히 될 수도 있지만, 400kHz 나 선이 길면 파형이 안 선다. 외부에 4.7k 를 다는 것이 기본이다.
✗ 여러 장치가 같은 주소를 쓴다
→ ADDR 핀으로 주소를 바꿀 수 있는지 데이터시트 확인
→ 안 되면 I2C 멀티플렉서(TCA9548A 등)나 별도 버스
// NACK 를 무시하지 않는다
if (HAL_I2C_Master_Transmit(...) != HAL_OK) {
// 슬레이브가 응답하지 않았다 — 재시도하거나 오류 처리
}
I²C 는 ACK 가 있어 응답 확인이 가능하다 — SPI 와 다른 큰 장점이다. 그걸 무시하고 반환값을 안 보면 그 이점을 버리는 것이다.
한눈에 정리
- 모두 오픈드레인 + 풀업 — 와이어드 AND 가 중재·스트레칭·ACK 의 근거다
- 풀업이 없으면 통신이 시작조차 안 된다 — 1순위 원인
- 상승 시간 ≈ 0.85 × Rp × Cb, 버스 정전용량 규격 상한은 400pF
- 파형이 삼각형이면 Rp·Cb 가 크고, LOW 가 안 내려가면 Rp 가 작다
- "SCL 이 HIGH 일 때 SDA 가 변하면 특수 신호" 라는 규칙이 START·STOP 을 만든다
- 반복 시작(Sr) 은 STOP 없이 방향을 바꿔 다른 마스터가 끼어드는 것을 막는다
- **7비트 주소를 8비트로 시프트**해야 한다. 데이터시트가 어느 형식인지 확인
- 주소 스캐너를 먼저 돌린다 — 아무것도 없으면 배선, 다르면 주소 해석
- **클럭 스트레칭**은 슬레이브가 SCL 을 붙잡는 것. 소프트웨어 마스터는 반드시 기다려야 한다
- 버스 잠김은 SCL 9클럭 + STOP 으로 복구한다. 초기화 시 무조건 한 번 돌린다
- ACK 가 있으니 반환값을 확인한다 — SPI 에 없는 이점을 버리지 않는다
출처 — NXP, UM10204 I²C-bus specification and user manual Rev.7 (§3 규격·§7.1 전기 특성·400pF·상승 시간) · STMicroelectronics, RM0090 STM32F4 Reference Manual §27 I²C · STMicroelectronics, AN4235 STM32 I²C 최적화