NRV FPGA 트러블슈팅 노트
Troubleshooting · 01
← Jay Tech Notes로 돌아가기

FPGA I²C 디바이스 인식 오류: 미연결 포트가 가짜 ACK를 만든 문제

센서가 연결되지 않았는데도 FX10이 센서 레지스터 쓰기에 대한 ACK를 받은 것처럼 동작했습니다. 오실로스코프로 각 I²C 포트를 직접 측정하고 FPGA의 SDA 결합 로직을 따라가 보니, 블록 디자인에서 미사용으로 정의해 제외한 포트를 내부 Verilog가 유효한 SDA 변수처럼 다시 참조하고 있었습니다. 이 포트들의 기본 Low 값이 최종 SDA를 강제로 Low로 만들었습니다. 실제 사용하는 포트만 결합하도록 Verilog를 수정해 실제 센서가 없을 때는 ACK가 발생하지 않도록 해결했습니다.

증상 센서 미연결 상태에서도 ACK 구간의 SDA가 Low로 내려감
확인 방법 Device port별 SDA/SCL 파형 측정과 FPGA RTL 신호 추적
원인 블록 디자인에서 미사용으로 제외한 포트 1~3을 Verilog가 유효 SDA 변수로 다시 참조해 AND 연산에 포함
해결 CAMERA_NUM에 따라 실제 사용하는 포트만 선택적으로 결합

1. FX10·FPGA·카메라 연결 구성

FX10 FMC 보드와 FPGA 보드에는 카메라를 연결할 수 있는 Device port 0~3이 구현되어 있습니다. 오류를 확인할 당시 실제 센서는 0번 포트 하나에만 연결했고, 나머지 1~3번 포트는 사용하지 않았습니다. FPGA 쪽 I²C는 3.3 V, 센서 쪽 I²C는 1.8 V이므로 두 논리 전압 레벨 사이에는 레벨 컨버터를 적용했습니다.

FX10 FMC 보드, FPGA 보드, DVS 카메라와 Device port 0부터 3까지의 위치
FPGA 보드의 Device port 0~3 위치입니다. 당시에는 Device port 0에만 센서가 연결되어 있었고, 사진에서 잘 보이지 않는 Device port 1을 포함해 port 1~3은 모두 미연결 상태였습니다. 실제 연결 포트 수와 RTL에서 정의한 포트 수가 다른 상태가 이번 문제의 출발점이었습니다.

2. 센서가 없으면 ACK가 나오지 않아야 하는 이유

I²C는 SDA와 SCL 두 신호를 여러 장치가 공유하는 버스입니다. 두 라인은 풀업에 의해 기본적으로 High를 유지하고, 장치는 필요한 순간에만 라인을 Low로 당깁니다. 한 바이트를 전송한 뒤 9번째 클럭에서 수신 장치가 SDA를 Low로 당기면 ACK, High로 남으면 NACK입니다.

여러 컨트롤러와 대상 장치가 풀업된 SDA와 SCL을 공유하는 I2C 버스 구조
여러 컨트롤러와 대상 장치가 풀업된 SDA와 SCL 두 라인을 공유하는 I²C 기본 구조입니다.
시작 조건, 7비트 주소, 읽기 쓰기 비트, ACK, 8비트 데이터와 정지 조건을 나타낸 I2C 전송 파형
주소와 읽기·쓰기 비트를 보낸 뒤 9번째 클럭에서 ACK를 확인하고, 이어서 8비트 데이터를 주고받는 I²C 전송 흐름입니다.
정상 조건 전송한 주소에 응답할 센서가 없다면 ACK 구간에서 SDA를 Low로 당길 장치도 없어야 합니다. 따라서 SDA는 High로 남고 FX10은 NACK로 판단해야 합니다.

3. 오실로스코프로 포트를 하나씩 확인

센서를 분리한 상태에서 FX10이 센서 레지스터에 쓰기 트랜잭션을 보내도록 한 뒤, 각 Device port의 I²C 신호를 직접 측정했습니다. 단발성 구간을 놓치지 않도록 오실로스코프의 트리거를 사용해 SDA와 SCL을 함께 관찰했습니다.

STEP 1 오류 재현 센서 분리 후 I²C 명령 전송
→
STEP 2 포트 측정 SDA·SCL을 트리거로 포착
→
STEP 3 신호 추적 가짜 ACK의 구동 위치 확인
→
STEP 4 RTL 확인 포트별 SDA 결합 로직 검사

측정 결과 센서가 없는데도 ACK가 나와야 하는 타이밍에서 SDA가 High에서 Low로 내려갔습니다. 실제 슬레이브의 응답이 아니라 FPGA 내부 로직이 SDA를 Low로 만들고 그 값이 FX10으로 전달되는 것으로 판단했습니다.

오실로스코프로 함께 측정한 FPGA I2C SDA와 SCL 파형
Device port에서 두 I²C 라인을 함께 측정한 화면입니다. 센서 미연결 조건에서도 SDA가 Low로 내려가는 구간을 확인한 뒤 FPGA 내부 신호를 추적했습니다.

4. 원인: 미사용 포트까지 AND 연산에 포함

기존 RTL은 네 카메라 포트의 SDA를 모두 AND 연산해 FX10으로 전달할 최종 SDA를 만들었습니다. I²C의 open-drain 신호를 결합할 때 Low가 우선되는 구조 자체는 필요하지만, 실제로 활성화되지 않은 내부 포트까지 결합한 것이 문제였습니다. 블록 디자인 단계에서는 사용하지 않을 포트 1~3을 미사용으로 정의해 회로에서 제외했습니다. 그런데 비트스트림을 구성하는 내부 Verilog 코드에서는 제외된 포트의 SDA를 유효한 신호 변수처럼 다시 불러와 AND 연산에 포함했습니다. 즉, 블록 디자인의 미사용 포트 정의와 Verilog의 실제 신호 참조가 서로 맞지 않은 설계 오류였습니다.

assign __i2c_o.sda =
    cam_selected
        ? (cam_i2c_bus_temp_arr[0].sda &
           cam_i2c_bus_temp_arr[1].sda &
           cam_i2c_bus_temp_arr[2].sda &
           cam_i2c_bus_temp_arr[3].sda)
        : sda;
포트 실제 연결 내부 SDA 상태 기존 로직에 미친 영향
Device port 0 사용 실제 센서 신호 정상적으로 반영
Device port 1~3 미사용 별도 구동 없이 기본 Low AND 결과를 항상 Low로 만듦
Root cause

블록 디자인에서 제외한 미사용 포트를 내부 Verilog가 유효 신호로 다시 참조했습니다.

포트 1~3은 블록 디자인에서 미사용으로 정의해 제외했지만, Verilog는 이 포트들을 유효한 SDA 변수처럼 다시 불러왔습니다. 이 중 하나라도 Low이면 AND 결과가 Low가 되므로, 실제 센서가 없는 상황에서도 FX10이 이를 정상 ACK로 오인했습니다.

5. 해결: CAMERA_NUM만큼의 유효 포트만 선택

블록 디자인에서 사용하도록 정의한 포트 범위와 내부 Verilog의 신호 참조 범위를 CAMERA_NUM으로 일치시켰습니다. 카메라가 한 대면 0번 포트만 사용하고, 두 대 이상일 때만 해당 개수만큼의 포트를 AND 연산에 포함했습니다. SDA 출력 enable도 같은 기준으로 처리했습니다.

generate
    if (CAMERA_NUM == 1) begin
        assign __i2c_o.sda = cam_selected
            ? cam_i2c_bus_temp_arr[0].sda : sda;
        assign __i2c_o.sda_en = cam_selected
            ? !cam_i2c_bus_temp_arr[0].sda : !sda;
    end else if (CAMERA_NUM == 2) begin
        assign __i2c_o.sda = cam_selected
            ? (cam_i2c_bus_temp_arr[0].sda &
               cam_i2c_bus_temp_arr[1].sda) : sda;
        assign __i2c_o.sda_en = cam_selected
            ? !(cam_i2c_bus_temp_arr[0].sda &
                cam_i2c_bus_temp_arr[1].sda) : !sda;
    end else if (CAMERA_NUM == 3) begin
        assign __i2c_o.sda = cam_selected
            ? (cam_i2c_bus_temp_arr[0].sda &
               cam_i2c_bus_temp_arr[1].sda &
               cam_i2c_bus_temp_arr[2].sda) : sda;
        assign __i2c_o.sda_en = cam_selected
            ? !(cam_i2c_bus_temp_arr[0].sda &
                cam_i2c_bus_temp_arr[1].sda &
                cam_i2c_bus_temp_arr[2].sda) : !sda;
    end else if (CAMERA_NUM == 4) begin
        assign __i2c_o.sda = cam_selected
            ? (cam_i2c_bus_temp_arr[0].sda &
               cam_i2c_bus_temp_arr[1].sda &
               cam_i2c_bus_temp_arr[2].sda &
               cam_i2c_bus_temp_arr[3].sda) : sda;
        assign __i2c_o.sda_en = cam_selected
            ? !(cam_i2c_bus_temp_arr[0].sda &
                cam_i2c_bus_temp_arr[1].sda &
                cam_i2c_bus_temp_arr[2].sda &
                cam_i2c_bus_temp_arr[3].sda) : !sda;
    end
endgenerate
  1. 현재 하드웨어에서 실제 연결하는 카메라 수를 CAMERA_NUM으로 정의했습니다.
  2. 유효한 Device port의 SDA만 최종 SDA 결합에 포함했습니다.
  3. 같은 포트 범위를 사용해 SDA 출력 enable 신호도 함께 수정했습니다.
  4. 미사용 포트의 기본값이 FX10 쪽 I²C 응답에 영향을 주지 않는지 다시 측정했습니다.

6. 수정 결과

블록 디자인에서 유효하게 사용하도록 정의한 포트와 Verilog가 실제로 참조하는 포트 범위를 맞춘 뒤에는 미사용 포트의 영향이 제거됐습니다. 센서가 연결되지 않은 상태에서는 ACK 구간의 SDA가 Low로 내려가지 않아 정상적으로 NACK가 되었고, 실제 사용하는 포트의 신호만 FX10으로 전달되는 것을 확인했습니다.

  • 센서 미연결: 응답할 장치가 없으므로 NACK
  • 센서 연결: 해당 포트의 실제 SDA 응답만 반영
  • 미사용 포트: 최종 SDA와 SDA enable 계산에서 제외
  • 카메라 수 변경: CAMERA_NUM에 맞춰 유효 포트 범위 변경

7. 이 작업을 하면서 배운 점

이번 문제는 한 줄의 Verilog만 고치는 작업으로 끝나지 않았습니다. 센서의 제어 신호가 FPGA와 FX10을 거쳐 host 프로그램까지 어떻게 전달되는지 전체 카메라 시스템을 다시 따라가며, 어느 구간에서 실제 신호와 프로그램의 판단이 달라지는지 확인해야 했습니다.

Dynamic Vision Sensor에서 FPGA, FX10, USB를 거쳐 Host PC로 이어지는 카메라 데이터 처리 구조
센서의 영상 데이터는 MIPI 수신과 FPGA의 AXI DMA, FX10의 GPIF III·DMA·USB endpoint를 거쳐 Host PC로 전달됩니다. I²C는 이 데이터 경로를 동작시키기 위한 센서 제어 경로입니다.

센서에서 시작된 이미지 데이터가 FPGA의 MIPI D-PHY와 Rx subsystem, AXI DMA를 지나 FX10의 GPIF III, DMA buffer, USB endpoint를 거쳐 PC 프로그램으로 전달되는 구조도 함께 이해하게 됐습니다. I²C 제어 경로와 고속 이미지 데이터 경로를 구분하고, 두 경로가 시스템 안에서 어떻게 연결되는지도 확인할 수 있었습니다.

또한 오실로스코프 파형, Verilog RTL, FX10 firmware, host 프로그램을 서로 연결해서 보는 방법을 익혔습니다. 이후에는 한 프로그램의 오류 메시지만 보는 것이 아니라 하드웨어 신호부터 데이터 전달 경로 전체를 훑어가며 문제 지점을 좁히고, 필요한 Verilog와 여러 프로그램의 코드를 읽어 직접 원인을 찾고 수정할 수 있게 됐습니다.

by jy
기록 범위

NRV 카메라 시스템 개발 중 직접 측정하고 분석해 수정한 내용을 개인 기술 노트로 정리했습니다. 카메라 수와 포트 구성에 따라 RTL의 유효 입력 범위를 함께 확인해야 합니다.