레지스터 주소 한 바이트를 쓴 뒤 센서 값을 읽을 때, 두 호출 사이에 STOP이 들어가면 일부 장치는 읽기 위치를 유지하지 못합니다. 임베디드 Linux의 /dev/i2c-N에서 반복 시작(repeated START)이 필요한 장치라면 한 번의 I2C_RDWR 요청에 쓰기·읽기 메시지를 묶으세요. Linux 커널의 I²C 사용자 공간 인터페이스와 I²C 프로토콜 설명을 기준으로 정리합니다.
1. 버스에서 실제로 달라지는 점
예를 들어 7비트 주소 0x48, 레지스터 0x00에서 한 바이트를 읽는 장치의 전형적인 순서는 다음과 같습니다. S는 START, Sr는 STOP 없이 다시 만드는 START, P는 STOP입니다. 주소 뒤의 W/R은 방향 비트이며, 표의 0x48은 시프트하지 않은 7비트 주소입니다.
| 구간 | 버스 순서 | 의미 |
|---|---|---|
| 쓰기 메시지 | S 0x48 W ACK 0x00 ACK |
읽을 레지스터를 지정 |
| 읽기 메시지 | Sr 0x48 R ACK [DATA] NACK P |
같은 거래 안에서 값 한 바이트 수신 |
커널 문서의 combined transaction은 메시지 사이의 STOP 대신 START를 보냅니다. 반면 /dev/i2c-N에 write()를 한 번, read()를 한 번 따로 호출하는 방식은 이러한 묶음 거래를 표현하지 못합니다. 모든 센서가 반복 시작을 요구하는 것은 아니므로, 실제 레지스터 포인터 동작과 바이트 순서는 해당 센서 데이터시트로 결정해야 합니다.
2. PC에서 순서를 검사하는 C 예제
다음 코드는 위 버스 순서를 나타내는 작고 독립적인 모델입니다. i2c_sequence.c로 저장해 gcc -std=c11 -Wall -Wextra -Werror i2c_sequence.c -o i2c_sequence로 빌드하고 실행하세요. 메시지 사이가 STOP이 아니라 RESTART인지 검사합니다. 핀 신호나 실제 ACK를 검증하는 코드는 아닙니다.
예상 출력:
3. Linux I2C_RDWR로 옮기는 순서
/sys/class/i2c-dev/또는i2cdetect -l로 어댑터 번호를 확인하고 해당/dev/i2c-N을 엽니다. 번호가 재부팅 후 바뀔 수 있으므로 고정으로 가정하지 않습니다.ioctl(fd, I2C_FUNCS, &funcs)로I2C_FUNC_I2C지원을 확인합니다. 이 기능이 없으면 이 방식의I2C_RDWR묶음 전송을 사용할 수 없습니다.struct i2c_msg msgs[2]를 구성합니다. 첫 메시지는addr=0x48,flags=0,len=1,buf가 레지스터 바이트0x00을 가리키도록 합니다. 두 번째 메시지는 같은 7비트 주소,flags=I2C_M_RD,len=1,buf가 결과 저장 바이트를 가리키도록 합니다. 각 메시지에 주소와 방향을 따로 설정해야 합니다.struct i2c_rdwr_ioctl_data의msgs와nmsgs=2를 채우고ioctl(fd, I2C_RDWR, &request)를 한 번 호출합니다. 실패하면errno를 기록하고, 장치 전원·주소·풀업·어댑터 지원·권한을 점검합니다. 커널 드라이버가 이미 소유한 장치에는 임의 접근하지 않습니다.
I2C_SLAVE로 주소를 정한 뒤 별도의 write()와 read()를 호출하는 예제를 그대로 바꿔 붙이면 반복 시작이 보장되지 않습니다. 로직 애널라이저에서는 쓰기 ACK 다음에 STOP 없이 START가 이어지는지 확인하고, 마지막 데이터 바이트 뒤 NACK·STOP을 확인하세요. PC 예제는 순서만 검증했으며 실제 어댑터, 센서, 전기 신호는 시험하지 않았습니다.
댓글
첫 댓글을 남겨 보세요.