读取失败覆盖了最后一个正常样本
한국어 원문으로 표시합니다.
한 줄 요약
드라이버는 정상 온도를 반환하는 함수가 아니라 실패할 때 무엇을 바꾸지 않을지도 정하는 경계입니다.
왜 이게 필요했나
전송 함수가 실패했는데 버퍼 첫 바이트는 바뀌었습니다. 이전 값과 새 값이 섞이면 그럴듯하지만 존재한 적 없는 온도가 됩니다. 에러 코드만 검사하는 것과 실패 결과를 사용자에게 공개하지 않는 것은 다른 일입니다. 작업용 버퍼에서 변환과 검증을 끝내고 성공 경로의 마지막에서 표본을 갱신합니다.
이번 실습은 실제 C 컴파일러로 여러분의 드라이버를 실행하지만 I2C 선에 전압을 걸지는 않습니다. 하드웨어 추상화 계층인 HAL을 함수 포인터 묶음으로 제공합니다. ctx는 모델의 상태를 가리키고 transfer·now_ms·recover가 그 상태를 사용합니다. 학생은 모델의 내부를 고치지 않고 이 공개 인터페이스로만 통신합니다.
어떻게 동작하나
주소는 0x48~0x4b의 7비트 값으로 전달합니다. R/W 비트를 붙이려고 왼쪽으로 한 번 더 미는 것은 이 HAL 계약에서는 잘못입니다. 실제 드라이버 라이브러리를 옮길 때도 인자가 7비트 주소인지 전송용 주소 바이트인지 문서를 먼저 확인해야 합니다.
한 번의 transfer 호출에 포인터 0x00 한 바이트 쓰기와 두 바이트 읽기를 같이 넘깁니다. 실제 버스의 반복 START·마지막 읽기 NACK·STOP은 HAL의 책임으로 둡니다. 이 수업의 검사기는 결합 호출의 주소·길이·포인터·기한을 검증하지 전기적 파형을 측정하지 않습니다. 센서 데이터시트와 HAL API 계약은 서로 다른 문서입니다.
오류 정책도 명시합니다. SENSOR_NACK는 전송 실패 상태이고 마지막 읽기 바이트에 제어기가 보내는 정상 NACK 신호와 같은 뜻으로 쓰지 않습니다. SENSOR_SHORT는 필요한 바이트를 모두 얻지 못했다는 뜻입니다. 이 두 상태와 형식 오류는 재시도하지 않습니다. SENSOR_BUS만 한 번 recover한 뒤 한 번 다시 읽습니다. 재시도도 실패하면 그대로 종료합니다. 모든 오류를 무한 재시도하는 구현은 잘못된 주소를 고치지도 못하면서 호출자를 붙잡습니다.
모델의 recover는 걸린 상태를 초기화합니다. SCL을 아홉 번 토글하거나 전원을 껐다 켜는 동작을 대신했다고 주장할 수 없습니다. 실물 복구는 버스 구성과 부품 규격에 맞춰 별도로 설계해야 합니다. 여기서는 복구가 실제 상태를 바꿔야 다음 전송이 성공하도록 모델을 만들어, 함수 이름만 호출하고 결과를 무시하는 실수를 구별합니다.
온도와 시각을 묶어서 실패를 추적한다
진입 시 공개 표본이 micro_c=25000000, observed_ms=100이라고 합시다. 새 전송은 첫 바이트 0x1a만 쓰고 SENSOR_SHORT를 반환합니다. 공개 표본의 메모리를 수신 버퍼로 쓰면 오류를 확인하기도 전에 이전 값이 손상될 수 있습니다. 함수 안의 두 바이트 작업 버퍼로 받고, 변환한 정수도 지역 변수에 둡니다. 실패 경로는 오류만 돌려주고 공개 표본을 건드리지 않습니다. 성공 경로에서만 새 온도와 완료 확인 시각을 옮깁니다.
| 호출 상황 | 반환 상태 | 호출 뒤 공개 온도 | 호출 뒤 공개 시각 |
|---|---|---|---|
| 이전 정상 값으로 시작 | 해당 없음 | 25000000 | 100 |
| 한 바이트만 받은 읽기 | SENSOR_SHORT | 25000000 | 100 |
| 다음 읽기는 26°C로 정상 완료 | SENSOR_OK | 26000000 | 새 완료 확인 시각 |
온도만 보존하고 시각을 현재로 바꾸는 구현도 틀립니다. 화면에는 예전 측정이 최신 표본처럼 보이기 때문입니다. 반대로 한 번 실패한 뒤 영원히 이전 값을 반환하는 구현도 틀립니다. 보존은 실패한 호출에만 적용하며 다음 정상 호출에서는 두 필드를 갱신합니다. 이 표의 순서를 실제 호출 순서로 시험해야 ‘보존’과 ‘영구 캐시’를 구별할 수 있습니다.
여기서 함께 갱신한다는 말은 한 함수 호출의 성공/실패 계약입니다. 두 필드의 대입이 다른 스레드에서 원자적으로 보인다는 뜻은 아닙니다. 이 모델은 동시 독자를 실행하지 않습니다. 실제 RTOS나 멀티스레드 프로그램에서는 표본을 읽는 쪽까지 잠금·메시지 전달 등의 일관성 규칙을 정해야 합니다. 지역 버퍼만 만들었다고 데이터 경쟁까지 해결했다고 쓰지 마세요.
복구 기록은 전송 BUS → 복구 OK → 재전송 OK처럼 상태를 순서대로 남깁니다. 마지막 결과만 SENSOR_OK라고 적으면 복구 없이 우연히 통과한 구현을 구별하지 못합니다. 전송 BUS → 복구 NACK이면 복구 오류를 돌려주고 끝나야 하며, 그 뒤 전송 호출은 없어야 합니다. 전송 BUS → 복구 OK → 재전송 BUS에서도 복구를 두 번째로 시작하지 않습니다. 각 화살표가 왜 허용되거나 금지되는지 말할 수 있어야 제한된 재시도 정책을 구현한 것입니다.
현장에서 만나는 모습
2026-09-10 확인한 Orion Sleep의 공식 임베디드 엔지니어 공고에는 C/C++, 하드웨어 인터페이스, 제한된 자원에서의 디버깅과 시험 체계가 함께 나옵니다. 이번 코스는 그 중 드라이버 계약과 재현 시험을 연습합니다. 하나의 해외 시니어 공고를 국내 전체 채용 수요로 일반화하지 않으며, 이 코스만으로 RTOS·보드 bring-up 경험을 대체하지 않습니다. 공고의 현재 지원 접수 여부도 별도로 확인해야 합니다.
실무 포트폴리오에는 정상 사례와 고장 주입 사례를 함께 남기세요. 부분 읽기 전에 저장한 온도와 시각이 오류 뒤에도 같은지, 복구 횟수가 정말 한 번인지가 관찰 가능한 근거입니다. 그 증거 없이 ‘안정적인 드라이버’라고만 적으면 무엇을 확인했는지 알 수 없습니다.
이어서 확인할 것
바로 이어지는 퀴즈에서 주소·오류·복구의 차이를 확인하고 시간 예산 이론을 읽습니다. 마지막 모듈의 누적 실습 중 4~6단계에서 정상 전송을 연결한 뒤 표본 보존과 제한된 복구를 더합니다. 처음에는 정상 경로만 다루므로 각 중간 버전은 아직 제품용 드라이버가 아닙니다. 이전 구현을 유지하면서 현재 단계의 계약을 추가하세요.