[IT 심층 분석]
임베디드 리눅스의 I2C 버스 경합으로 인한 센서 드롭아웃 파악 및 클럭 스트레칭(Clock Stretching) 보정
김민준 · IT 시스템 엔지니어|
소형 로봇 제어를 위한 커스텀 임베디드 리눅스 통합 보드를 설계하던 중 등골이 서늘해지는 하드웨어 버그와 마주쳤습니다. 모터의 발열을 체크하는 4개의 고유 I2C 온도 센서 데몬을 올렸는데, 10분만 지나도 시스템 로그에 "I2C timeout, I/O Error" 가 도배되며 센서 값들이 일제히 0xFF(모두 1, 비정상) 쓰레기값으로 반환되기 시작했습니다. 회로도와 센서 칩셋 스펙에는 아무런 이상이 없었음에도, 보드의 신경망이라 할 수 있는 I2C 버스는 계속 혼수상태에 빠졌습니다. 저는 결국 소프트웨어 엔지니어임에도 직접 사비로 구매한 고가의 논리 분석기(Logic Analyzer)를 I2C 핀에 물려 전기적 파형을 추적하는 하드웨어의 최전선까지 밀고 나갔습니다.
오실로스코프로 그려지는 전압 파동 속에서 원인의 실마리가 잡혔습니다. 클라이언트 센서가 데이터를 준비하느라 시간이 좀 더 필요할 때 클럭 라인(SCL)을 일부러 로우 상태로 끌어내려 호스트를 멈추게 하는 '클럭 스트레칭(Clock Stretching)' 기술을 이용하고 있었는데, 하필 저희 시스템의 AP 메인 칩셋(SoC) 컨트롤러 드라이버가 이 딜레이 시간을 견디지 못하고 너무나 성급하게 오류 플래그를 올려버린 것이 문제였습니다. 센서는 "잠시기다려주세요"라고 발을 걸었는데, 메인 칩셋은 "응답 없음, 연결을 끊겠다"라며 선을 잘라버린 소통의 대참사. 드라이버가 작성된 C 소스를 까보니 타임아웃 웨스카운트 값이 너무 타이트하게 하드코딩 되어 있었던 허술함 때문이었습니다.
저는 즉시 리눅스 커널 소스 트리로 진입하여 해당 제조사 전용 i2c-core 드라이버의 인터럽트 핸들링 루틴을 수정했습니다. 클럭 스트레칭 핀이 풀다운 당했을 때 대기하는 와치독 루틴의 스핀락 타깃을 10배로 늘리고, 패킷 오류 지연 시 곧바로 다운시키지 않고 버스 재시도 카운트(Retry Count)를 3회까지 회피하는 재시도 로직을 덧붙여 커널을 새로 빌드했습니다. 보드 펌웨어를 재플래싱하고 72시간 연속 발열 테스트를 런칭시켰을 때, 더 이상 오류 로그는 단 한 줄도 올라오지 않았고 센서 수치 변동 그래프의 곡선은 물결처럼 유려하게 그려졌습니다. 소프트웨어 개발과 하드웨어 스펙이 충돌하는 최하단 경계 오지에서만 느낄 수 있는 그 지독한 짜릿함은 저를 영원한 시스템 개발자로 남게 만들었습니다.