1. 에뮬레이터가 대신하는 층을 먼저 정한다
장치 에뮬레이터는 앱 아래의 특정 장치나 외부 버스 응답을 흉내 낸다. native_sim은 Zephyr 앱·커널을 Linux 실행 파일로 빌드하는 보드 대상이다. QEMU는 선택한 가상 보드의 CPU·플랫폼을 실행한다. 이 셋은 같은 뜻이 아니다. 장치 에뮬레이터는 충분한 자원이 있으면 다른 보드에서도 빌드할 수 있고, native_sim에서는 호스트 디버깅과 조합하기 쉽다.
| 수단 | 대신하는 층 | 이 경로만으로 남는 질문 |
|---|---|---|
| 장치·버스 에뮬레이터 | I²C·SPI 등의 버스 컨트롤러 또는 그 아래 주변장치의 응답 | 실물 컨트롤러의 레지스터·전기 신호·타이밍 |
native_sim | 호스트에서 Zephyr 앱·커널을 돌리는 실행 대상 | 특정 MCU의 ISA·메모리맵·보호 기능 |
| QEMU 보드 | 지원되는 가상 CPU·보드와 일부 주변장치 | QEMU가 모델링하지 않은 실리콘 세부 동작 |
| 실물 보드 | 소프트웨어 대역 없이 물리 연결을 직접 사용 | 측정하지 않은 환경·고장·제품 변형 |
2. 앱은 같은 EEPROM API를 호출한다
v3.7.0의 AT24 예시에서는 테스트가 EEPROM API를 호출하고, 실제 eeprom_at2x.c 드라이버가 I²C 메시지를 만든다. 에뮬레이션된 I²C 컨트롤러는 주소로 주변장치 에뮬레이터를 찾고 transfer 콜백으로 전달한다. 따라서 앱의 호출이 곧장 RAM 배열로 뛰어가는 모의 객체보다 더 긴 경로, 즉 주변장치 드라이버의 페이지 경계·주소 폭·재시도 처리를 거친다.
요청은 왼쪽에서 오른쪽으로 이동하고, 결과·오류는 역방향으로 돌아옵니다. 좁은 화면에서는 좌우로 이동하세요.
eeprom_read() 또는 eeprom_write()로 공개 장치 API 호출실제 보드에서도 호출 형태 유지i2c_write_read() 또는 i2c_write() 수행시험 대상인 실제 주변장치 드라이버transfer 호출대상 주소가 없으면 v3.7.0 코드에서 -EIO근거: v3.7.0 AT24 드라이버의 I²C read/write 경로, v3.7.0 I²C 컨트롤러의 주소 검색·전달.
3. 같은 주변장치 노드에 두 역할이 붙는다
주변장치 드라이버와 해당 에뮬레이터는 같은 devicetree compatible을 대상으로 삼는다. 그러나 서로 같은 C 객체는 아니다. 드라이버 쪽은 DEVICE_DT_DEFINE() 계열로 struct device를, 에뮬레이터 쪽은 EMUL_DT_DEFINE() 계열로 struct emul을 정의한다. 에뮬레이터 매크로가 가리키는 노드에는 대응하는 device 정의가 있어야 한다. 에뮬레이션된 부모 버스는 활성 child 노드를 모아 초기화하고, 그 child의 에뮬레이터를 등록한다.
두 패널은 같은 child node에서 출발합니다. 가운데를 가로지르는 선은 C 포인터가 아니라 devicetree 정체성의 공유를 뜻합니다.
compatible = "atmel,at24"device 객체 + EEPROM API버스로 보낼 I²C 메시지 생성DT_DRV_COMPATEMUL_DT_INST_DEFINE()으로 emul 객체bus API + 선택적 test backend APIzephyr,i2c-emul-controller → child 주소 reg로 요청 전달| 계약 | v3.7.0에서 보는 위치 | 어긋나면 |
|---|---|---|
| 부모 버스 | zephyr,i2c-emul-controller 노드와 I²C emul 드라이버 | 예상한 child 요청이 실제 I²C 에뮬레이터에 닿지 않음 |
| child node | compatible, reg, status | 드라이버·에뮬레이터 인스턴스가 빠지거나 주소가 달라짐 |
| device 객체 | DEVICE_DT_DEFINE() 계열 | EMUL_DT_DEFINE()의 필수 대상과 연결 실패 |
| emul 객체 | EMUL_DT_DEFINE() 계열의 bus API·선택적 backend API | 버스 요청 전달 또는 테스트용 조작 경로가 없음 |
bus_api는 부모 버스가 주변장치 대역과 통신할 때 쓴다. _backend_api는 테스트가 장치의 상태를 버스 밖에서 조작할 수 있게 하는 선택적 API다. 예를 들어 충전기 연결 이벤트를 주입한 뒤 정상 BC1.2 드라이버 콜백을 검증할 수 있다. 모든 에뮬레이터가 그런 backend를 제공하는 것은 아니다.
근거: 동일 compatible·bus/backend API 계약, v3.7.0 emul 매크로, child 목록·초기화 소스.
4. 고정 버전의 AT24 예시를 좁게 재현한다
v3.7.0 공식 예시는 tests/drivers/eeprom/api에 at2x_emul.overlay와 at2x_emul.conf를 더해 native_sim 대상으로 빌드한다. overlay는 I²C 버스 child에 atmel,at24, 주소 0x57, 크기 256바이트, 페이지 8바이트, 주소 폭 8비트를 선언한다. 이 값은 에뮬레이터가 임의로 추측하는 장치 특성이 아니라 해당 테스트에서 설정한 계약이다.
west build -b native_sim tests/drivers/eeprom/api -- \
-DDTC_OVERLAY_FILE=at2x_emul.overlay \
-DOVERLAY_CONFIG=at2x_emul.conf위 명령은 3.7.0 문서의 AT24 예시에 기초한다. 실행 파일의 PASS 결과를 여기서 주장하지 않는다. 최신 문서의 옵션명과 섞지 않도록 OVERLAY_CONFIG 표기를 고정했다.
| overlay 값 | 드라이버에서 관찰할 동작 | 판정할 경계 |
|---|---|---|
reg = <0x57> | I²C 전송 주소가 emul controller의 child 주소 검색과 맞는가 | 다른 주소로 보내면 대상 에뮬레이터를 못 찾음 |
pagesize = <8> | 한 번의 write가 페이지 경계를 넘지 않도록 분할되는가 | 연속 쓰기의 실제 메시지 개수를 추적 |
size = <256> | 끝 범위를 넘는 읽기·쓰기를 드라이버가 거절하는가 | 버스 에뮬레이터에 도착하기 전에 막힐 수 있음 |
address-width = <8> | 오프셋 주소 바이트를 드라이버가 어떻게 만드는가 | 다른 주소 폭의 물리 칩까지 검증한 것은 아님 |
5. 오류를 주입할 때 관찰 지점을 먼저 정한다
에뮬레이터의 힘은 성공 응답만 돌려주는 데 있지 않다. 지원하는 backend나 버스 mock hook으로 잘못된 상태·오류를 넣고, 앱이 보는 API 결과까지 확인할 수 있다. 다만 어느 API가 실제로 노출되는지는 에뮬레이터 구현마다 다르다. v3.7.0 I²C emul controller는 주소를 찾지 못하면 -EIO를 돌려주며, mock transfer가 -ENOSYS를 반환하면 기본 에뮬레이터 transfer로 넘어간다. 이 내부 경로와 AT24 자체의 범위 오류를 한 종류의 실패로 뭉뚱그리지 않는다.
화살표는 하나의 가상 테스트 설계 순서입니다. 특정 AT24 backend API가 있다는 뜻은 아닙니다. 좁은 화면에서는 좌우로 이동하세요.
| 증상 | 먼저 확인할 조건 | 다음 관찰 |
|---|---|---|
| 에뮬레이터 객체 참조 링크 실패 | child status, Kconfig가 에뮬레이터 구현을 포함하는지 | 빌드 설정과 EMUL_DT_GET() 대상 노드 비교 |
I²C 요청이 -EIO | 전송 주소와 child reg, 버스 속도와 메시지 순서 | 컨트롤러의 주소 미발견과 AT24 에뮬레이터 콜백의 오류를 구분 |
| 읽기·쓰기 범위 오류 | AT24의 size와 요청 offset + length | 버스 호출 전에 드라이버가 거절했는지 확인 |
| 호스트에서만 PASS | 대역이 구현하지 않은 장치 동작 또는 버스 timing이 있는지 | 실물 컨트롤러 API 테스트와 보드 결합 시험 |
근거: bus/backend API와 BC1.2 주입 예시, I²C 주소 미발견·mock fallback 코드, AT24 에뮬레이터의 속도·메시지 오류, AT24 범위 검사.
6. 통과의 범위를 적어야 이점이 남는다
가상 I²C 위에서 AT24 드라이버 테스트가 통과하면 그 설정에서 앱 API, AT24 드라이버, 에뮬레이션된 메시지 흐름이 맞았다는 근거가 된다. 실제 SoC I²C 컨트롤러 드라이버, 신호 무결성, 전원 차단, EEPROM의 write-cycle timing까지 검증됐다는 뜻은 아니다. 실물 컨트롤러는 물리 장치를 연결한 별도 API 테스트가 필요하다. 모델이 정확하지 않으면 호스트에서 초록색 결과를 반복해도 같은 오류를 놓칠 수 있으므로, 에뮬레이터가 구현한 레지스터·응답·오류 범위도 테스트 문서에 남겨야 한다.
v3.7.0 문서가 나열하는 버스 대역은 I²C, SPI, eSPI, MSPI다. 별도로 ADC·GPIO·플래시·EEPROM 같은 클래스 대역도 있다. 이 글의 I²C 경로를 그 모든 클래스에 똑같이 대입하지 않는다. 예를 들어 GPIO 에뮬레이터는 상위 GPIO API를 테스트하기 위한 다른 구성이다.
| 주장 | 필요한 증거 | 이 글의 상태 |
|---|---|---|
| AT24 드라이버 경로를 시험할 수 있다 | 고정 문서의 예시와 v3.7.0 소스의 I²C 전달 구조 | 소스 기반 구조 설명 |
| 특정 테스트가 PASS했다 | 빌드 로그, 실행 플랫폼, 테스트 출력 | 로컬 실행 증거 없음 |
| 실물 보드에서도 동작한다 | 보드·칩·설정·환경을 기록한 측정 | 별도 검증 필요 |
7. 고정 버전 근거와 이어 읽기
기준은 Zephyr 3.7.0 장치 에뮬레이터 문서와 같은 버전 외부 버스 문서다. 구현은 v3.7.0 태그의 I²C emul controller, AT24 드라이버, 테스트 overlay로 확인했다. 문서의 도식은 새로 그렸으며 코드 전문이나 원본 그림을 옮기지 않았다.