2.1 Overview
이 장에서는 i.MX 8M PLUS Image Signal Processing(ISP) 센서 드라이버, API 함수와 호출 프로세스 아키텍처에 대해 설명한다. 또한 새로운 API를 추가하는 방법과 다양한 센서를 장착하기 위한 구현 프로세스에 대해서도 설명한다.
약어와 규칙
3A: Auto Exposure, Auto Focus, Auto White Balance
AE: Auto Exposure(자동 노출)
AF: Auto Focus(자동 초점)
API: Application Programming Interface
AWB: Automatic White Balance
BLC: Black Level Correction
fps: Frames Per Second
I2C: Inter-Integrated Circuit
IOCTL: Input Output Control
ISI: Independent Sensor Interface
ISP: Image Signal Processing
ISS: Image Sensor Specific
VVCAM: Vivante`s kernel driver integration layer
WB: White Balance
접두사 "0x"나 접미사 "H"는 16진수를 나타낸다(예: "0x32CF"나 "32CFH").
접두사 "0b"는 이진수를 나타낸다(예: "0b0011.0010.1100.1111").
코드 조각은 Consolas 폰트로 제공된다.
2.2 ISP Software Architecture
ISP 프레임워크에서 애플리케이션 레이어와 3A(Auto Exposure, Auto Focus, Auto White Balance) 레이어는 센서 API를 호출한다. 이것은 ISI 레이어 코드로 ISS에서 함수 포인터를 사용하여 수행된다. 센서에서 출력되는 데이터 스트림은 처리를 위해 ISP로 직접 전송된다. 다음 그림에서 회색 화살표는 함수 호출을 나타내고, 흰색 화살표는 센서의 출력 이미지 데이터 방향을 나타낸다.
2.2.1 ISS (Image Sensor Specific) Driver
- 센서별 구현
- 센서별 속성과 동작:
- 센서 데이터 시트
- 보정 데이터
2.2.2 ISP Sensor Module Block Diagrams
i.MX 8M Plus ISP 센서 모듈은 다음 그림과 같이 구성되어 있다.
Linux 커널의 센서 모듈: I2C는 아래 Figure 2와 같이 센서 레지스터를 읽고 쓰기 위해 커널에서 호출된다.
- ISI Layer: 해당 센서 함수를 호출하는 인터페이스, 다른 센서를 마운트하기 위한 함수 포인터와 이러한 함수 포인터로 구성된 구조체를 포함한다.
- ISS: ISP 드라이버 코드가 다른 모듈의 코드를 수정하지 않고 독립적으로 다른 센서를 사용할 수 있도록 함수 포인터를 사용한다.
- Sensor API: 센서 전원 켜기, 초기화, 센서 레지스터 읽기/쓰기, 센서 해상도 구성, 노출 파라미터, 현재 센서의 구성 파라미터와 다른 함수를 가져오는 것을 포함한다.
- VVCAM: ISP, MIPI, 카메라 센서와 I2C 커널 드라이버를 포함하는 i.MX 8M Plus ISP 커널 드라이버 통합 레이어.
- Sensor Driver: 센서 하드웨어에서 센서 API 작업을 수행한다.
- I2C: Read-Write Sensor Register. 레지스터를 쓸 때 그 값은 32비트 값이여야 한다. 레지스터 읽기에는 제한이 없다.
- Kernel Working Mode: VVCAM에는 커널에 두 가지 유형의 작업 모드가 있다:
- V4L2 Mode: V4L2 커널 드라이버의 일부로 작동하는 커널 드라이버, 디바이스 이름을 등록하고 V4L2 서브 디바이스 스타일로 작업한다. 이 모드는 V4L2 센서 디바이스 형식과 호환된다.
2.3 ISP Independent Sensor Interface (ISI) API reference
ISP API에 대한 추가 정보는 ISP Independent Sensor Interface API를 참조한다. 편의를 위해 이곳에 구조체와 함수를 제공한다.
2.3.1 ISI Structures
2.3.1.1 IsiCamDrvConfig_s
이 구조체는 카메라 센서 드라이버별 데이터를 정의한다.
Structure Members | Type | Description |
CameraDriverID | uint32_t | 카메라 센서 드라이버 ID |
*pIsiHalQuerySensor | IsiHalQuerySensor_t | HAL 핸들이 있는 쿼리 센서 모드. |
*pfIsiGetSensorIss | IsiGetSensorIss_t | 현재 구조체에서 IsiSensor 멤버를 초기화가기 위한 함수 포인터이다. |
IsiSensor | IsiSensor_t | 이 구조체는 ISI 레이어에서 센서를 컨트롤하기 위한 센서 이름과 함수 포인터를 포함한다. |
2.3.1.2 IsiSensor_t
이 구조체는 센서 인스턴스를 생성하는 데 사용되는 구성 구조체를 정의한다. 데이터 구조체 정의에 대한 자세한 내용은 ISP Independent Sensor Interface API를 참조한다.
Structure Members | Type | Description |
*pszName | const char | 카메라 센서의 이름 |
pIsiSensorSetPowerIss | IsiSensorSetPowerIss_t | 센서 전원 함수 설정 |
pIsiCreateSensorIss_t | IsiCreateSensorIss_t | 센서 핸들 생성 |
pIsiReleaseSensorIss | IsiReleaseSensorIss_t | 센서 핸들 해제 |
pIsiRegisterReadIss | IsiRegisterReadIss_t | 센서 레지스터 읽기 |
pIsiRegisterWriteIss | IsiRegisterWriteIss_t | 센서 레지스터 쓰기 |
pIsiGetSensorModeIss | IsiGetSensorModeIss_t | 센서 모드 정보 가져오기 |
pIsiSetSensorModeIss | IsiSetSensorModeIss_t | 센서 모드 인덱스 설정 |
pIsiQuerySensorIss | IsiQuerySensorIss_t | 센서 모드 지원 쿼리 |
pIsiGetCapsIss | IsiGetCapsIss_t | 센서 지원 기능 가져오기 |
pIsiSetupSensorIss | IsiSetupSensorIss_t | 센서 포맷 설정과 센서 초기화 |
pIsiGetSensorRevisionIss | IsiGetSensorRevisionIss_t | 센서 리비전 ID 가져오기 |
pIsiCheckSensorConnectionIss | IsiCheckSensorConnectionIss_t | 센서 연결 상태 검사 |
pIsiSensorSetStreamingIss | IsiSensorSetStreamingIss_t | 스트리밍 설정 |
pIsiGetAeInfoIss_t | IsiGetAeInfoIss_t | AE 정보 가져오기 |
pIsiSetHdrRatioIss | IsiSetHdrRatioIss_t | HDR 비율 설정 |
pIsiGetIntegrationTimeIss | IsiGetIntegrationTimeIss_t | 적분 시간 가져오기 |
pIsiSetIntegrationTimeIss | IsiSetIntegrationTimeIss_t | 적분 시간 설정 |
pIsiGetGainIss | IsiGetGainIss_t | 현재 센서 게인 가져오기 |
pIsiSetGainIss | IsiSetGainIss_t | 센서 게인 설정 |
pIsiGetSensorFpsIss | IsiGetSensorFpsIss_t | 현재 프레임 속도 가져오기 |
pIsiSetSensorFpsIss_t | IsiSetSensorFpsIss | 센서 프레임 속도 설정 |
pIsiSetSensorAfpsLimitsIss | IsiSetSensorAfpsLimitsIss_t | 자동 FPS 제한 가져오기 |
pIsiGetSensorIspStatusIss | IsiGetSensorIspStatusIss_t | ISP 상태(BLC와 WB 사용이 센서 WB인지 ISP WB인지) 가져오기 |
pIsiGetAeStartExposureIss | IsiGetAeStartExposureIss_t | AE 시작 노출 가져오기 |
pIsiSetAeStartExposureIss | IsiSetAeStartExposureIss_t | AE 시작 노출 설정 |
pIsiSensorSetBlcIss | IsiSensorSetBlcIss_t | 센서 BLC가 사용 가능한 경우, 센서 BLC 설정 |
pIsiSensorSetWBIss | IsiSensorSetWBIss_t | 센서 WB가 사용 가능한 경우, 센서 WB 설정 |
pIsiSensorGetExpandCurveIss | IsiSensorGetExpandCurveIss_t | 센서 데이터가 압축된 경우, 확장 커브를 가져오기 |
pIsiActivateTestPatternIss_t | IsiActivateTestPatternIss | 센서 테스트 패턴 설정 |
pIsiFocusSetupIss | IsiFocusSetupIss | AF 핸들 생성 |
pIsiFocusReleaseIss | IsiFocusReleaseIss_t | AF 핸들 해제 |
pIsiFocusSetIss_t | IsiFocusSetIss_t | 포커스 위치 설정 |
pIsiFocusGetIss_t | IsiFocusGetIss | 포커스 위치 가져오기 |
pIsiGetFocusCalibrateIss | IsiGetFocusCalibrateIss | 포커스 보정 정보 가져오기 |
2.3.1.3 IsiSensorInstanceConfig_s
이 구조체는 센서 인스턴스를 생성하는 데 사용되는 구성 구조체를 정의한다.
Structure Members | Type | Description |
SensorId | uint8_t | 센서 ID |
SensorInitAddr | uint32_t | 센서 초기화 주소 |
SensorInitSize | uint16_t | 센서 초기화 크기 |
HalHandle | HalHandle_t | HAL 세션에서 사용할 핸들 |
HalDevID | uint32_t | 이 센서의 HAL 디바이스 ID |
I2cAfBusNum | uint8_t | 포커스 모듈의 I2C 버스 |
SlaveAfAddr | uint16_t | 포커스 모듈의 I2C 슬레이브 주소 |
SensorModeIndex | uint32_t | 센서 모드 인덱스 |
szSensorNodeName[32] | char | 센서 노드 이름 |
I2cBusNum | uint8_t | 센서의 I2C 버스 |
SlaveAddr | uint16_t | 센서의 I2C 슬레이브 주소 |
*pSensor | IsiSensor_t | 센서 드라이버 인터페이스에 대한 포인터 |
hSensor | IsiSensorHandle_t | IsiCreateSensorIss에서 반환된 센서 핸들 |
2.3.2 ISI Functions
다음 ISI API는 IsiSensor_s 데이터 구조체에 정의된 함수 포인터를 사용하여 Sensor API Reference 섹션(2.3.3)에 정의된 해당 센서 함수를 호출한다.
Table 2. ISI functions
ISI API | Function Description |
IsiSensorSetPowerIss(…) | 센서의 전원 켜기/끄기 |
IsiReadRegister(…) | 센서 레지스터 값 읽기 |
IsiWriteRegister (…) | 센서 레지스터 값 쓰기 |
IsiCreateSensorIss (…) | 센서 인스턴스 생성과 센서에 리소스 할당 |
IsiReleaseSensorIss (…) | 센서 인스턴스 해제 |
IsiGetSensorModeIss (…) | 센서 모드 정보 가져오기 |
IsiSetSensorModeIss (…) | 센서 모드 인덱스 설정 |
IsiQuerySensorIss (…) | 센서 모드 지원 쿼리 |
IsiGetCapsIss (…) | 센서 기능 가져오기 |
IsiSetupSensorIss(…) | 센서 형식 설정과 센서 초기화 |
IsiCheckSensorConnectionIss (…) | 센서 연결 상태 검사 |
IsiGetSensorRevisionIss (…) | 센서 ID 가져오기 |
IsiSensorSetStreamingIss (…) | 센서 스트리밍 상태 설정 |
IsiGetAeInfoIss (…) | AE 정보 가져오기 |
IsiSetHdrRatioIss (…) | HDR 비율 설정 |
IsiGetIntegrationTimeIss (…) | 마이크로초 단위의 노출 시간 가져오기 (고정 소수점, q10) |
IsiSetIntegrationTimeIss (…) | 마이크로초 단위의 노출 시간 설정 (고정 소수점, q10) |
IsiGetGainIss (…) | 센서 게인 가져오기 (고정 소수점, q10) |
IsiSetGainIss (…) | 센서 게인 설정 (고정 소수점, q10) |
IsiGetSensorFpsIss (…) | 센서 프레임 속도 가져오기 (고정 소수점, q10) |
IsiSetSensorFpsIss (…) | 센서 프레임 속도 설정 (고정 소수점, q10) |
IsiSetSensorAfpsLimitsIss (…) | 자동 FPS 제한 설정 (고정 소수점, q10) |
IsiGetSensorIspStatusIss (…) | 센서 모듈 상태(BLC, WB) 가져오기 |
IsiGetAeStartExposureIss (…) | AE 시작 노출 가져오기 (exposure time us* gain) (고정 소스점, q10) |
IsiSetAeStartExposureIss (…) | AE 시작 노출 설정 (exposure time us* gain) (고정 소수점, q10) |
IsiSensorSetBlc (…) | 센서 BLC 설정 |
IsiSensorSetWB (…) | 센서 WB 설정 |
IsiSensorGetExpandCurve (…) | 센서 확장 커브를 가져오기 |
IsiActivateTestPattern (…) | 센서 패턴 모드를 설정 |
IsiFocusSetupIss (…) | AF 모듈 설정 |
IsiFocusReleaseIss (…) | AF 모듈 해제 |
IsiFocusSetIss (…) | 포커스 위치 설정 |
IsiFocusGetIss (…) | 포커스 위치 가져오기 |
IsiFocusCalibrateIss (…) | 포커스 보정 정보 가져오기 |
IsiDumpAllRegisters (…) | 예약됨 |
2.3.3 Sensor API Reference
이 섹션에서는 units/isi/drv/<sensor>/source/<sensor>.c에 정의된 API에 대해 설명한다. 여기서 <sensor>는 센서의 이름이다(예: OV2775). 다음 테이블의 API를 참조하여 사용 중인 센서에 대한 고유한 API를 정의할 수 있다. 상위 애플리케이션 레이어는 IsiCamDrvConfig_t 구조체를 사용하여 다음 함수를 호출할 수 있다.
Table 3. Sensor API reference
Sensor API | Description |
SENSOR STRUCTURES | |
IsiCamDrvConfig_t | 상위 레이어에서 함수 포인터에 접근할 수 있는 구조체 제공 |
SENSOR FUNCTIONS | |
<sensor>_IsiSensorSetPowerIss(…) | 센서의 전원 켜기/끄기 |
<sensor>_IsiReadRegister(…) | 센서 레지스터 값 읽기 |
<sensor>_IsiWriteRegister (…) | 센서 레지스터 값 쓰기 |
<sensor>_IsiCreateSensorIss (…) | 센서 인스턴스 생성과 센서에 리소스 할당 |
<sensor>_IsiReleaseSensorIss (…) | 센서 인스턴스 해제 |
<sensor>_IsiGetSensorModeIss (…) | 센서 모드 정보 가져오기 |
<sensor>_IsiSetSensorModeIss (…) | 센서 모드 인덱스 설정 |
<sensor>_IsiQuerySensorIss (…) | 센서 모드 지원 쿼리 |
<sensor>_IsiGetCapsIss (…) | 센서 기능 가져오기 |
<sensor>_IsiSetupSensorIss(…) | 센서 형식 설정과 센서 초기화 |
<sensor>_IsiCheckSensorConnectionIss (…) | 센서 연결 상태 검사 |
<sensor>_IsiGetSensorRevisionIss (…) | 센서 ID 가져오기 |
<sensor>_IsiSensorSetStreamingIss (…) | 센서 스트리밍 상태 설정 |
<sensor>_IsiGetAeInfoIss (…) | AE 정보 가져오기 |
<sensor>_IsiSetHdrRatioIss (…) | HDR 비율 설정 |
<sensor>_IsiGetIntegrationTimeIss (…) | 마이크로초 단위의 노출 시간 가져오기 (고정 소수점, q10) |
<sensor>_IsiSetIntegrationTimeIss (…) | 마이크로초 단위의 노출 시간 설정 (고정 소수점, q10) |
<sensor>_IsiGetGainIss (…) | 센서 게인 가져오기 (고정 소수점, q10) |
<sensor>_IsiSetGainIss (…) | 센서 게인 설정 (고정 소수점, q10) |
<sensor>_IsiGetSensorFpsIss (…) | 센서 프레임 속도 가져오기 (고정 소수점, q10) |
<sensor>_IsiSetSensorFpsIss (…) | 센서 프레임 속도 설정 (고정 소수점, q10) |
<sensor>_IsiSetSensorAfpsLimitsIss (…) | 자동 FPS 제한 설정 (고정 소수점, q10) |
<sensor>_IsiGetSensorIspStatusIss (…) | 센서 모듈 (BLC, WB) 상태 가져오기 |
<sensor>_IsiGetAeStartExposureIss (…) | AE 시작 노출 가져오기 (exposure time us* gain) (고정 소수점, q10) |
<sensor>_IsiSetAeStartExposureIss (…) | AE 시작 노출 설정 (exposure time us* gain) (고정 소수점, q10) |
<sensor>_IsiSensorSetBlc (…) | 센서 BLC 설정 |
<sensor>_IsiSensorSetWB (…) | 센서 WB 설정 |
<sensor>_IsiSensorGetExpandCurve (…) | 센서 확장 커브 가져오기 |
<sensor>_IsiActivateTestPattern (…) | 센서 테스트 패턴 모드 설정 |
<sensor>_IsiFocusSetupIss (…) | AF 모듈 설정 |
<sensor>_IsiFocusReleaseIss (…) | AF 모듈 해제 |
<sensor>_IsiFocusSetIss (…) | 포커스 위치 설정 |
<sensor>_IsiFocusGetIss (…) | 포커스 위치 가져오기 |
<sensor>_IsiFocusCalibrateIss (…) | 포커스 보정 정보 가져오기 |
2.3.4 ISS Sensor Driver User Space Flow
Function Pointers
ISS(Image Sensor Specific) 드라이버에서, 센서 API와 동일한 유형의 함수 포인터를 정의한다. 또한 이러한 함수 포인터를 IsiSensor_s 데이터 구조체에 통합한다. 그런 다음, 드라이버는 IsiSensor_s 구조체, 카메라 드라이버 ID와 IsiGetSensorIss_t 함수 포인터를 IsiCamDrvConfig_s 데이터 구조체에 통합한다. IsiGetSensorIss_t 함수 포인터에 해당하는 함수에서, 드라이버는 ISS 레이어에 정의된 함수 포인터에 센서 API를 설정한다. 애플리케이션 레이어는 이 데이터 구조체에 액세스하여 센서 API를 작동할 수 있다. 추가적인 정보는 #unique_37 섹션(해당 섹션이 보이지 않음)을 참조한다.
Sensor Defines
각 센서에서 고유한 센서에 대한 #define이 있다. 이러한 #define은 애플리케이션의 요구 사항에 따라 설정해야 한다. 센서에 대한 사용자 정의 #define 세트의 예는 Set the Sensor Macro 섹션에 있다.
Sensor Exposure Function
센서의 노출 함수도 센서마다 다르다. 노출 함수를 수정하려면, 특정 구현 방법에 대해 센서의 데이터 시트를 참조한다. 맞춤형 노출 함수의 예는 Write Customized Exposure Parameters 섹션에 있다. ISI에 정의된 IsiGetSensorIss_t 함수 포인터 인터페이스는 센서 API에 해당한다. 각 ISI API는 함수 포인터를 통해 해당 센서 API를 호출한다.
애플리케이션 레이어는 SensorOps::driverChange() 함수를 통해 IsiCamDrvConfig_t 데이터 구조체로 함수 포인터의 주소를 얻는다.
SensorOps::driverChange(std::string driverFileName, std::string calibFileName) {
…..
DCT_ASSERT(!pCamDrvConfig->pfIsiGetSensorIss(&pCamDrvConfig->IsiSensor));
pSensor = &pCamDrvConfig->IsiSensor;
동시에 애플리케이션 레이어는 이 주소를 ISS로 전달하여 ISS가 다른 센서에 액세스할 수 있도록 한다.
2.4 IOCTL Introduction
사용자 공간의 인터페이스는 직접 커널 공간의 함수를 작동할 수 없다. 작업의 명령과 파라미터는 IOCTL 명령을 사용하여 호출한다.
2.4.1 IOCTL Commands
커널 공간에서 IOCTL 명령에 대한 해당 작업은 다음 테이블에 나와 있다.
Table 4. IOCTL Commands (Native Mode)
IOCTL | IOCTL Operation |
VVSENSORIOC_RESET | 센서 리셋 |
VVSENSORIOC_S_POWER | 센서 전원 설정 |
VVSENSORIOC_G_POWER | 센서 전원 가져오기 |
VVSENSORIOC_S_CLK | 센서 clock 설정 |
VVSENSORIOC_G_CLK | 센서 clock 가져오기 |
VVSENSORIOC_QUERY | 센서 모드 지원 쿼리 |
VVSENSORIOC_S_SENSOR_MODE | 센서 모드 설정 |
VVSENSORIOC_G_SENSOR_MODE | 센서 모드 가져오기 |
VVSENSORIOC_READ_REG | 레지스터 읽기 |
VVSENSORIOC_WRITE_REG | 레지스터 쓰기 |
VVSENSORIOC_READ_ARRAY | 레지스터 배열 읽기 |
VVSENSORIOC_WRITE_ARRAY | 레지스터 배열 쓰기 |
VVSENSORIOC_G_NAME | 센서 이름 가져오기 |
VVSENSORIOC_G_RESERVE_ID | 예비 센서 ID 가져오기 |
VVSENSORIOC_G_CHIP_ID | 칩 ID 가져오기 |
VVSENSORIOC_S_INIT | 센서 초기화 설정 |
VVSENSORIOC_S_STREAM | 센서 스트림 설정 |
VVSENSORIOC_S_LONG_EXP | 긴 노출 설정 |
VVSENSORIOC_S_EXP | 노출 설정 |
VVSENSORIOC_S_VSEXP | 매우 짧은 노출 설정 |
VVSENSORIOC_S_LONG_GAIN | 긴 게인 설정 |
VVSENSORIOC_S_GAIN | 게인 설정 |
VVSENSORIOC_S_VSGAIN | 매우 짧은 게인 설정 |
VVSENSORIOC_S_FPS | 프레임 속도 설정 |
VVSENSORIOC_G_FPS | 프레임 속도 가져오기 |
VVSENSORIOC_S_HDR_RADIO | HDR 비율 설정 |
VVSENSORIOC_S_WB | 화이트 발란스 설정 |
VVSENSORIOC_S_BLC | 블랙 레벨 보정 설정 |
VVSENSORIOC_G_EXPAND_CURVE | 확장 커브 가져오기 |
VVSENSORIOC_S_TEST_PATTERN | 테스트 패턴 설정 |
2.4.2 IOCTL Call Flow
IOCTL은 아래와 같이 Native Mode와 V4L2 Mode를 모두 지원한다.
2.4.2.1 Native Mode
아래 그림은 Native Mode의 IOCTL 호출 흐름을 보여준다. 자세한 내용은 VVCAM Flow in Native Mode를 참조한다.
2.4.2.2 V4L2 Mode
아래 그림은 V4L2 Mode에서 IOCTL 호출 흐름을 보여준다. 자세한 내용은 VVCAM Flow in V4L2 Mode 섹션을 참조한다.
2.5 VVCam API Reference
이 섹션에서는 vvcam/common/vvsensor.h에 선언된 API에 대해 설명한다.
2.5.1 Sensor Driver Enumerations
2.5.1.1 SENSOR_BAYER_PATTERN_E
enum Members | Description |
BAYER_RGGB | Bayer RGGB 패턴 모드 |
BAYER_GRBG | Bayer GRBG 패턴 모드 |
BAYER_GBRG | Bayer GBRB 패턴 모드 |
BAYER_BGGR | Bayer BGGR 패턴 모드 |
BAYER_MAX | Bayer 패턴 모드의 수 |
2.5.1.2 sensor_hdr_mode_e
enum Members | Description |
SENSOR_MODE_LINEAR | 선형 모드 |
SENSOR_MODE_HDR_STITCH | ISP HDR 모드 |
SENSOR_MODE_HDR_NATIVE | 다양한 노출 이미지를 ISP에서 처리하기 전에, 센서에서 결합한다. |
2.5.1.3 sensor_stitching_mode_e
enum Members | Description |
SENSOR_STITCHING_DUAL_DCG | 이중 DCG 모드 3x12-bit |
SENSOR_STITCHING_3DOL | 3 DOL 프레임 3x12-bit |
SENSOR_STITCHING_LINEBYLINE | 대기없이 라인에 3x13-bit 라인 |
SENSOR_STITCHING_16BIT_COMPRESS | 16-bit 압축된 데이터 + 12-bit RAW |
SENSOR_STITCHING_DUAL_DCG_NOWAIT | 대기없이 2x12-bit 이중 DCG |
SENSOR_STITCHING_2DOL | DOL2 프레임이나 1 CG+VS sx12-bit RAW |
SENSOR_STITCHING_L_AND_S | L+S 2x12-bit RAW |
SENSOR_STITCHING_MAX | 센서 스티칭 모드의 수 |
2.5.2 Sensor Driver Structures
2.5.2.1 sensor_blc_t
Structure Members | Type | Description |
red | uint32_t | Red Black Level Correction (BLC) 레벨 |
gr | uint32_t | Gr BLC 레벨 |
gb | uint32_t | Gb BLC 레벨 |
blue | uint32_t | Blue BLC 레벨 |
2.5.2.2 sensor_data_compress_t
Structure Members | Type | Description |
enable | uint32_t | 0: 압축하지 않은 센서 데이터 1: 압축한 센서 데이터 |
x_bit | uint32_t | 압축된 센서 데이터이면, x_bit는 압축되기 전 데이터 비트 너비를 나타낸다. |
y_bit | uint32_t | 압축된 센서 데이터이면, y_bit는 압축 후 데이터 비트 너비를 나타낸다. |
2.5.2.3 sensor_expand_curve_t
Structure Members | Type | Description |
x_bit | uint32_t | 데이터 압축 해제 커브의 입력 비트 너비 |
y_bit | uint32_t | 데이터 압축 해제 커브의 출력 비트 너비 |
expand_px[64] | uint8_t | 데이터 압축 해제 커브의 입력 간격 index.exp: 1<<expand_px[i] = expand_x_data[i+1] - expand_x_data[i] |
expand_x_data[65] | uint32_t | 데이터 압축 해제 커브의 65점 입력 |
expand_y_data[65] | uint32_t | 데이터 압축 해제 커브의 65점 출력 |
2.5.2.4 sensor_hdr_artio_t
Structure Members | Type | Description |
ratio_l_s | uint32_t | 긴 노출과 짧은 노출의 센서 HDR 노출 비율 (고정 소수점, q10) |
ratio_s_vs | uint32_t | 짧은 노출과 매우 짧은 노출의 센서 HDR 노출 비율 (고정 소수점, q10) |
accuracy | uint32_t | 센서 HDR 정확도 (고정 소수점, q10) |
2.5.2.5 sensor_mipi_info
Structure Members | Type | Description |
mipi_lane | uint32_t | MIPI 레인 |
2.5.2.6 sensor_test_pattern_t
Structure Members | Type | Description |
enable | uint8_t | 센서 테스트 패턴 활성화/비활성화 |
pattern | uint32_t | 센서 테스트 패턴 |
2.5.2.7 sensor_white_balance_t
Structure Members | Type | Description |
r_gain | uint32_t | White Balance (WB) R 게인 |
gr_gain | uint32_t | WB Gr 게인 |
gb_gain | uint32_t | WB Gb 게인 |
b_gain | uint32_t | WB B 게인 |
2.5.2.8 vvcam_ae_info_t
Structure Members | Type | Description |
def_frm_len_lines | uint32_t | 센서의 기본 프레임 세로 라인 (항상 센서의 기본 모드는 VTS) |
curr_frm_len_lines | uint32_t | 현재 프레임 세로 라인 |
one_line_exp_time_ns | uint32_t | 한 라인의 노출 시간(ns 단위) (always = sensor PCLK * HTS) |
max_longintegration_line | uint32_t | 최대 긴 적분 라인 |
min_longintegration_line | uint32_t | 최소 긴 적분 라인 |
max_integration_line | uint32_t | 최대 노출 라인 |
min_integration_line | uint32_t | 최소 노출 라인 |
max_vsintegration_line | uint32_t | 최대 매우 짧은 적분 시간 (마이크로초 단위) |
min_vsintegration_line | uint32_t | 최소 매우 짧은 적분 시간 (마이크로초 단위) |
max_long_again | uint32_t | 최대 긴 아날로그 게인 (고정 소수점, q10) |
min_long_again | uint32_t | 최소 긴 아날로그 게인 (고정 소수점, q10) |
max_long_dgain | uint32_t | 최대 긴 디지털 게인 (고정 소수점, q10) |
min_long_dgain | uint32_t | 최소 긴 디지털 게인 (고정 소수점, q10) |
max_again | uint32_t | 최대 아날로그 게인 (고정 소수점, q10) |
min_again | uint32_t | 최소 아날로그 게인 (고정 소수점, q10) |
max_dgain | uint32_t | 최대 디지털 게인 (고정 소수점, q10) |
min_dgain | uint32_t | 최소 디지털 게인 (고정 소수점, q10) |
max_short_again | uint32_t | 최대 짧은 아날로그 게인 (고정 소수점, q10) |
min_short_again | uint32_t | 최소 짧은 아날로그 게인 (고정 소수점, q10) |
max_short_dgain | uint32_t | 최대 짧은 디지털 게인 (고정 소수점, q10) |
min_short_dgain | uint32_t | 최소 짧은 디지털 게인 (고정 소수점, q10) |
start_exposure | uint32_t | 노출 시작 (exposure lines*gain (고정 소수점, q10)) |
gain_step | uint32_t | 게인 단계 (고정 소수점, q10) |
cur_fps | uint32_t | 현재 프레임 속도 (고정 소수점, q10) |
max_fps | uint32_t | 최대 FPS (고정 소수점, q10) |
min_fps | uint32_t | 최소 FPS (고정 소수점, q10) |
min_afps | uint32_t | 최소 아날로그 FPS (고정 소수점, q10) |
int_update_delay_frm | uint8_t | 적분 업데이트 지연 프레임 |
gain_update_delay_frm | uint8_t | 게인 업데이트 지연 프레임 |
hdr_radio | sensor_hdr_artio_t | HDR 비율 |
2.5.2.9 vvcam_clk_s
Structure Members | Type | Description |
status | uint32_t | CLK 활성화 상태 |
sensor_mclk | unsigned long | 센서 MIPI clock |
csi_max_pixel_clk | unsigned long | 센서 최대 픽셀 clock |
2.5.2.10 vvcam_mode_info_array_t
이 구조체는 vvcam_mode_info의 추상화이다.
Structure Members | Type | Description |
count | uint32_t | 지원되는 모드의 수 |
modes[VVCAM_SUPPORT_MAX_MODE_COUNT] | struct vvcam_mode_info | 센서 기능의 구조체 |
2.5.2.11 vvcam_mode_info_t
Structure Members | Type | Description |
index | uint32_t | 모드 인덱스 |
width | uint32_t | 이미지 너비 |
height | uint32_t | 이미지 높이 |
hdr_mode | uint32_t | HDR 모드 |
stitching_mode | uint32_t | HDR 스티칭 모드 |
bit_width | uint32_t | 센서 비트 너비 |
data_compress | sensor_data_compress_t | 압축된 센서 데이터 |
bayer_pattern | uint32_t | Bayer 모드 |
ae_info | vvcam_ae_info_t | AE 정보 |
mipi_info | sensor_mipi_info | 센서 MIPI 정보 |
preg_data | void * | 센서 레지스터의 구성 포인트 |
reg_data_count | uint32_t | 센서 레지스터의 구성 크기 |
2.5.2.12 vvcam_sccb_array_s
Structure Members | Type | Description |
count | uint32_t | SCCB 레지스터의 수 |
*sccb_data | vvcam_sccb_data_s | SCCB 레지스터 데이터 |
2.5.2.13 vvcam_sccb_cfg_s
Structure Members | Type | Description |
slave_addr | uint8_t | 레지스터 슬레이브 주소 |
addr_byte | uint8_t | 레지스터 주소 바이트 |
data_byte | uint8_t | 레지스터 데이터 바이트 |
2.5.2.14 vvcam_sccb_data_s
Structure Members | Type | Description |
addr | uint32_t | 레지스터 주소 |
data | uint32_t | 레지스터 데이터 |
2.5.2.15 vvcam_sensor_function_s
이 구조체는 센서 드라이버에서 함수에 해당하는 함수 포인터를 정의한다. 이 구조체는 Native 모드에서만 사용된다.
Structure Members | Type | Description |
sensor_name[16] | uint8_t | 센서 이름 |
reserve_id | uint32_t | 센서 드라이버에 저장된 올바른 센서 ID |
sensor_clk | uint32_t | 센서의 입력 clock 주파수 (Hz) |
mipi_info | sensor_mipi_info_s | MIPI CSI 인터페이스 특징: 레인 수와 데이터 너비 |
sensor_get_chip_id | int32_t (*sensor_get_chip_id) (void *ctx, uint32_t *chip_id) | 센서 레지스터에서 ID를 가져오는 함수 포인터 |
sensor_init | int32_t (*sensor_init) (void *ctx, vvcam_mode_info_t *pmode) | vvcam_mode_info 데이터 구조체를 초기화하는 함수 포인터 |
sensor_set_stream | int32_t (*sensor_set_stream) (void *ctx, uint32_t status) | 센서 데이터 스트림을 open/close하는 함수 포인터 |
sensor_set_exp | int32_t (*sensor_set_exp) (void *ctx, uint32_t exp_line) | 라인 단위로 노출 시간을 설정하는 함수 포인터 |
sensor_set_vs_exp | int32_t (*sensor_set_vs_exp) (void *ctx, uint32_t exp_line) | HDR 모드에서 매우 짧은 노출 프레임의 노출 시간을 설정하는 함수 포인터 |
sensor_set_gain | int32_t (*sensor_set_gain) (void *ctx, uint32_t gain) | dB가 아닌 배수로 게인을 설정하는 함수 포인터 |
sensor_set_vs_gain | int32_t (*sensor_set_vs_gain) (void *ctx, uint32_t gain) | dB가 아닌 배수로 매우 짧은 노출 프레임의 게인을 설정하는 함수 포인터 |
sensor_set_fps | int32_t (*sensor_set_fps) (void *ctx, uint32_t fps) | FPS(frame per second) 단위로 센서의 프레임 속도를 설정하는 함수 포인터 |
sensor_set_resolution | int32_t (*sensor_set_resolution)(void *ctx, uint32_t width, uint32_t height) | 센서의 해상도를 설정하는 함수 포인터 |
sensor_set_hdr_mode | int32_t (*sensor_set_hdr_mode) (void *ctx, uint32_t hdr_mode) | 센서의 HDR 모드를 선택하는 함수 포인터 |
sensor_query | int32_t (*sensor_query) (void *ctx, vvcam_mode_info_array_t *pmode_info_arry) | 센서 정보를 쿼리하는 함수 포인터 |
2.5.3 Sensor Driver API
V4l2 Sensor Driver API는 <sensor>_mipi_v3.c 파일에 선언되어 있다. 여기서 <sensor>는 센서의 이름이다(예: OV2775).
Table 5. Sensor Native Driver API
API Name | Description |
extern struct vvcam_sensor_function_s <sensor>_function | 함수 포인터에 센서 드라이버 연결 |
sensor_query(…) | 센서 정보 쿼리 |
sensor_write_reg(…) | 레지스터 쓰기 |
sensor_read_reg(…) | 레지스터 읽기 |
sensor_write_reg_arry(…) | 배열로 레지스터 쓰기 |
sensor_get_chip_id(…) | 센서에서 칩 ID 가져오기 |
sensor_init(…) | vvcam_mode_info 데이터 구조체 초기화 |
sensor_set_stream (…) | 센서의 흐름을 켜거나 끄기 |
sensor_set_exp(…) | 3A 노출 파라미터 분해로 노출 시간을 센서 레지스터에 쓰기 |
sensor_set_vs_exp(…) | 매우 짧은 노출 프레임에 대한 3A 노출 파라이터 분해로 노출 시간을 센서 레지스터에 쓰기 |
sensor_calc_gain(…) | 센서 게인을 계산 |
sensor_set_gain(…) | dB가 아닌 배수로 게인 설정 |
sensor_set_vs_gain (…) | dB가 아닌 배수로 매우 짧은 노출 프레임의 게인 설정 |
sensor_set_fps(…) | 센서의 프레임 속도 설정 |
sensor_set_resolution(…) | 센서의 해상도 설정 |
sensor_set_hdr_mode(…) | 센서의 HDR 모드 선택 |
Table 6. Sensor V4l2 Driver API
API Name | Description |
<sensor>_g_clk(…) | 센서 clock 가져오기 |
<sensor>_power_on(…) | 센서 전원 켜기 |
<sensor>_power_off(…) | 센서 전원 끄기 |
<sensor>_s_power(…) | 센서 전원 설정 |
<sensor>_write_reg(…) | 지정된 레지스터에 데이터 쓰기 |
<sensor>_read_reg(…) | 지정된 레지스터에서 데이터 읽기 |
<sensor>_write_reg_arry(…) | 배열로 레지스터 쓰기 |
<sensor>_query_capability(…) | 센서 기능 쿼리 |
<sensor>_query_supports(…) | 센서 지원 모드 쿼리 |
<sensor>_get_sensor_id(…) | 센서 ID 가져오기 |
<sensor>_get_reserve_id(…) | 예비 센서 ID 가져오기 |
<sensor>_get_sensor_mode(…) | 센서 모드 가져오기 |
<sensor>_set_sensor_mode(…) | 센서 모드 설정 |
<sensor>_set_lexp(…) | 긴 노출 프레임에 대한 3A 노출 파라미터 분해로 노출 시간을 센서 레지스터에 쓰기 |
<sensor>_set_exp(…) | 3A 노출 파라미터 분해로 노출 시간을 센서 레지스터에 쓰기 |
<sensor>_set_vsexp(…) | 매우 짧은 노출 프레임에 대해 3A 노출 파라미터 분해로 노출 시간을 센서 레지스터에 쓰기 |
<sensor>_set_lgain(…) | dB가 아닌 배수로 긴 노출 프레임의 게인 설정 |
<sensor>_set_gain(…) | dB가 아닌 배수로 게인 설정 |
<sensor>_set_vsgain(…) | dB가 아닌 배수로 매우 짧은 노출 프레임의 게인 설정 |
<sensor>_set_fps(…) | 센서 FPS 설정 |
<sensor>_get_fps(…) | 센서 FPS 가져오기 |
<sensor>_set_test_pattern(…) | 테스트 패턴 설정 |
<sensor>_set_ratio(…) | 센서 HDR 비율 설정 |
<sensor>_set_blc(…) | 센서 서브 BLC 설정 |
<sensor>_set_wb(…) | 화이트 밸런스 설정 |
<sensor>_get_expand_curve(…) | 센서 확장 커브 가져오기 |
<sensor>_get_format_code(…) | 형식 코드 가져오기 |
<sensor>_s_stream(…) | 센서 시작 또는 중지 |
<sensor>_enum_mbus_code(…) | 열거형 MBUS 코드 |
<sensor>_set_fmt(…) | 센서 형식 설정 |
<sensor>_get_fmt(…) | 센서 형식 가져오기 |
<sensor>_priv_ioctl(…) | 개별 I/O 컨트롤 |
<sensor>_link_setup(…) | 링크 설정 |
<sensor>_regulator_enable(…) | 레귤레이터 활성화 |
<sensor>_regulator_disable(…) | 레귤레이터 비활성화 |
<sensor>_set_clk_rate(…) | clock 속도 설정 |
<sensor>_reset(…) | 센서 리셋 |
<sensor>_retrieve_capture_properties(…) | 캡쳐 속성 검색 |
<sensor>_probe(…) | 센서 찾기 |
<sensor>_remove(…) | 센서 제거 |
<sensor>_suspend(…) | 센서 일시 중지 |
<sensor>_resume(…) | 센서 재가동 |
2.6 Camera Sensor Driver in V4L2 Mode
2.6.1 VVCAM Flow in V4L2 Mode
V4L2 모드에 새로운 센서 드라이버를 포팅하기 전에 이 섹션을 주의 깊게 읽어야 한다. 센서 포팅 과정에서 문제가 발생하면, 당신의 소스 코드 릴리스에서 플랫폼의 기존 센서 드라이버를 참조한다.
함수 인터페이스를 추가하려면, 다음 섹션을 참조한다:
- ISI API Reference (2.3)
- ISS Sensor Driver User Space Flow (2.3.4)
- Sensor API Reference (2.3.3)
- VVCAM Flow in V4L2 Mode (이 섹션)
허브 및 센서 커널 드라이버 모두, 해당 인터페이스와 호출을 추가해야 한다. 센서를 이식하는 동안, 3A 모듈에서 레지스터에 기록된 값으로 전달되는 노출 파라미터를 변환할 때 센서 데이터 시트의 다른 센서에는 다른 변환 방법이 있다는 점에 유의해야 한다. 센서 데이터는 정확하게 정의되어야 한다.
카메라 센서를 포팅하려면, 다음 섹션에 설명된 대로 다음 단계를 수행해야 한다:
- 커널에 센서 DTB 파일을 생성한다.
- VVCAM에서 센서 V4L2 드라이버를 만든다(VVCAM은 Vivante의 커널 드라이버 통합 레이어이다).
- ISI 레이어에서 센서 ISI API를 생성한다.
2.6.1.1 Sensor Driver Software Architecture in V4L2 Mode
V4L2 모드에서 센서 드라이버의 소프트웨어 아키텍처는 아래 그림과 같다. V4L2-subdev 드라이버는 vvcam/v4l2/sensor/<sensor>/<sensor>_xxxx.c 파일에 정의되어 있다. 여기서 <sensor>는 센서 이름이다(예: OV2775).
v4l-subdevx라는 센서의 디바이스 노드는 직접 액세스를 위해 /dev에 생성할 수 있다. <sensor>_priv_ioctl() 함수는 ioctl()을 통해 사용자 공간에서 전달된 명령과 파라미터를 커널 공간에서 수신하는 데 사용된다. 명령어에 따라 <sensor>_xxxx.c의 해당 함수 호출에도 사용된다.
참고
개발자는 아래 그림과 같이 Vivante V4L2-Subdev Driver를 자체 센서로 교체해야 한다.
2.6.2 Camera Sensor Porting Setup in V4L2 Mode
2.6.2.1 Create Sensor DTS File in Kernel
센서를 추가할 때, 커널 디바이스 드라이버를 지원하기 위해 새로운 DTS 파일을 추가해야 한다. sensor0이 i2C2에 연결되어 있으면, i2C2 노드에 센서 디바이스를 추가한다.
예를 들면:
&i2c2 {
/delete-node/ov5640_mipi@3c;
ov2775_0: ov2775_mipi@36 {
compatible = "ovti,ov2775";
reg = <0x36>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_csi0_pwn>, <&pinctrl_csi0_rst>, <&pinctrl_csi_mclk>;
clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>;
clock-names = "csi_mclk";
assigned-clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>;
assigned-clock-parents = <&clk IMX8MP_CLK_24M>;
assigned-clock-rates = <24000000>;
csi_id = <0>;
pwn-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>;
rst-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
mclk = <24000000>;
mclk_source = <0>;
status = "okay";
port {
ov2775_mipi_0_ep: endpoint {
data-lanes = <1 2 3 4>;
clock-lanes = <0>;
max-pixel-frequency = /bits/ 64 <500000000>;
remote-endpoint = <&mipi_csi0_ep>;
};
};
};
};
2.6.2.2 Create Sensor V4L2 Driver in VVCAM
- 지원하는 모드 정보에 대해 struct vvcam_mode_info_s를 생성한다.
static struct vvcam_mode_info_s pov2775_mode_info[] = { { .index = 0, .width = 1920, .height = 1080, .hdr_mode = SENSOR_MODE_LINEAR, .bit_width = 12, .data_compress = { .enable = 0, }, .bayer_pattern = BAYER_BGGR, .ae_info = { .def_frm_len_lines = 0x466, .curr_frm_len_lines = 0x466, .one_line_exp_time_ns = 29625, .max_integration_line = 0x466 - 4, .min_integration_line = 1, .max_again = 8 * 1024, .min_again = 2 * 1024, .max_dgain = 4 * 1024, .min_dgain = 1.5 * 1024, .gain_step = 4, .start_exposure = 3 * 400 * 1024, .cur_fps = 30 * 1024, .max_fps = 30 * 1024, .min_fps = 5 * 1024, .min_afps = 5 * 1024, .int_update_delay_frm = 1, .gain_update_delay_frm = 1, }, .mipi_info = { .mipi_lane = 4, }, .preg_data = ov2775_init_setting_1080p, .reg_data_count = ARRAY_SIZE(ov2775_init_setting_1080p), }, { .index = 1, .width = 1920, .height = 1080, .hdr_mode = SENSOR_MODE_HDR_STITCH, .stitching_mode = SENSOR_STITCHING_DUAL_DCG, .bit_width = 12, .data_compress = { .enable = 0, }, .bayer_pattern = BAYER_BGGR, .ae_info = { .def_frm_len_lines = 0x466, .curr_frm_len_lines = 0x466, .one_line_exp_time_ns = 59167, .max_integration_line = 0x400, .min_integration_line = 1, .max_vsintegration_line = 44, .min_vsintegration_line = 1, .max_long_again = 8 * 1024 * DCG_CONVERSION_GAIN, .min_long_again = 1 * 1024 * DCG_CONVERSION_GAIN, .max_long_dgain = 4 * 1024, .min_long_dgain = 2 * 1024, .max_again = 8 * 1024, .min_again = 2 * 1024, .max_dgain = 4 * 1024, .min_dgain = 1.5 * 1024, .max_short_again = 8 * 1024, .min_short_again = 2 * 1024, .max_short_dgain = 4 * 1024, .min_short_dgain = 1.5 * 1024, .start_exposure = 3 * 400 * 1024, .gain_step = 4, .cur_fps = 30 * 1024, .max_fps = 30 * 1024, .min_fps = 5 * 1024, .min_afps = 5 * 1024, .hdr_ratio = { .ratio_l_s = 8 * 1024, .ratio_s_vs = 8 * 1024, .accuracy = 1024, }, .int_update_delay_frm = 1, .gain_update_delay_frm = 1, }, .mipi_info = { .mipi_lane = 4, }, .preg_data = ov2775_init_setting_1080p_hdr, .reg_data_count = ARRAY_SIZE(ov2775_init_setting_1080p_hdr), }, { .index = 2, .width = 1920, .height = 1080, .hdr_mode = SENSOR_MODE_HDR_NATIVE, .stitching_mode = SENSOR_STITCHING_DUAL_DCG_NOWAIT, .bit_width = 12, .data_compress = { .enable = 1, .x_bit = 16, .y_bit = 12, }, .bayer_pattern = BAYER_BGGR, .ae_info = { .def_frm_len_lines = 0x466, .curr_frm_len_lines = 0x466, .one_line_exp_time_ns = 59167, .max_integration_line = 0x466 - 4, .min_integration_line = 1, .max_long_again = 8 * 1024 * DCG_CONVERSION_GAIN, .min_long_again = 1 * 1024 * DCG_CONVERSION_GAIN, .max_long_dgain = 4 * 1024, .min_long_dgain = 2 * 1024, .max_again = 8 * 1024 , .min_again = 2 * 1024, .max_dgain = 4 * 1024, .min_dgain = 1.5 * 1024, .start_exposure = 3 * 400 * 1024, .gain_step = 4, .cur_fps = 30 * 1024, .max_fps = 30 * 1024, .min_fps = 5 * 1024, .min_afps = 5 * 1024, .hdr_ratio = { .ratio_l_s = 8 * 1024, .ratio_s_vs = 8 * 1024, .accuracy = 1024, }, .int_update_delay_frm = 1, .gain_update_delay_frm = 1, }, .mipi_info = { .mipi_lane = 4, }, .preg_data = ov2775_1080p_native_hdr_regs, .reg_data_count = ARRAY_SIZE(ov2775_1080p_native_hdr_regs), }, };
- 새로운 센서 V4L2 드라이버를 등록한다.
static int ov2775_probe(struct i2c_client *client, const struct i2c_device_id *id) { int retval; struct device *dev = &client->dev; struct v4l2_subdev *sd; struct ov2775 *sensor; u32 chip_id = 0; u8 reg_val = 0; pr_info("enter %s\n", __func__); sensor = devm_kmalloc(dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) return -ENOMEM; memset(sensor, 0, sizeof(*sensor)); sensor->i2c_client = client; sensor->pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); if (!gpio_is_valid(sensor->pwn_gpio)) dev_warn(dev, "No sensor pwdn pin available"); else { retval = devm_gpio_request_one(dev, sensor->pwn_gpio, GPIOF_OUT_INIT_HIGH, "ov2775_mipi_pwdn"); if (retval < 0) { dev_warn(dev, "Failed to set power pin\n"); dev_warn(dev, "retval=%d\n", retval); return retval; } } sensor->rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); if (!gpio_is_valid(sensor->rst_gpio)) dev_warn(dev, "No sensor reset pin available"); else { retval = devm_gpio_request_one(dev, sensor->rst_gpio, GPIOF_OUT_INIT_HIGH, "ov2775_mipi_reset"); if (retval < 0) { dev_warn(dev, "Failed to set reset pin\n"); return retval; } } sensor->sensor_clk = devm_clk_get(dev, "csi_mclk"); if (IS_ERR(sensor->sensor_clk)) { sensor->sensor_clk = NULL; dev_err(dev, "clock-frequency missing or invalid\n"); return PTR_ERR(sensor->sensor_clk); } retval = of_property_read_u32(dev->of_node, "mclk", &(sensor->mclk)); if (retval) { dev_err(dev, "mclk missing or invalid\n"); return retval; } retval = of_property_read_u32(dev->of_node, "mclk_source", (u32 *)&(sensor->mclk_source)); if (retval) { dev_err(dev, "mclk_source missing or invalid\n"); return retval; } retval = of_property_read_u32(dev->of_node, "csi_id", &(sensor->csi_id)); if (retval) { dev_err(dev, "csi id missing or invalid\n"); return retval; } retval = ov2775_retrieve_capture_properties(sensor,&sensor->ocp); if (retval) { dev_warn(dev, "retrive capture properties error\n"); } sensor->io_regulator = devm_regulator_get(dev, "DOVDD"); if (IS_ERR(sensor->io_regulator)) { dev_err(dev, "cannot get io regulator\n"); return PTR_ERR(sensor->io_regulator); } sensor->core_regulator = devm_regulator_get(dev, "DVDD"); if (IS_ERR(sensor->core_regulator)) { dev_err(dev, "cannot get core regulator\n"); return PTR_ERR(sensor->core_regulator); } sensor->analog_regulator = devm_regulator_get(dev, "AVDD"); if (IS_ERR(sensor->analog_regulator)) { dev_err(dev, "cannot get analog regulator\n"); return PTR_ERR(sensor->analog_regulator); } retval = ov2775_regulator_enable(sensor); if (retval) { dev_err(dev, "regulator enable failed\n"); return retval; } ov2775_set_clk_rate(sensor); retval = clk_prepare_enable(sensor->sensor_clk); if (retval < 0) { dev_err(dev, "%s: enable sensor clk fail\n", __func__); goto probe_err_regulator_disable; } retval = ov2775_power_on(sensor); if (retval < 0) { dev_err(dev, "%s: sensor power on fail\n", __func__); goto probe_err_regulator_disable; } ov2775_reset(sensor); ov2775_read_reg(sensor, 0x300a, ®_val); chip_id |= reg_val << 8; ov2775_read_reg(sensor, 0x300b, ®_val); chip_id |= reg_val; if (chip_id != 0x2770) { pr_warn("camera ov2775 is not found\n"); retval = -ENODEV; goto probe_err_power_off; } sd = &sensor->subdev; v4l2_i2c_subdev_init(sd, client, &ov2775_subdev_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->dev = &client->dev; sd->entity.ops = &ov2775_sd_media_ops; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; sensor->pads[OV2775_SENS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; retval = media_entity_pads_init(&sd->entity, OV2775_SENS_PADS_NUM, sensor->pads); if (retval < 0) goto probe_err_power_off; retval = v4l2_async_register_subdev_sensor_common(sd); if (retval < 0) { dev_err(&client->dev,"%s--Async register failed, ret=%d\n", __func__,retval); goto probe_err_free_entiny; } memcpy(&sensor->cur_mode, &pov2775_mode_info[0], sizeof(struct vvcam_mode_info_s)); mutex_init(&sensor->lock); pr_info("%s camera mipi ov2775, is found\n", __func__); return 0; probe_err_free_entiny: media_entity_cleanup(&sd->entity); probe_err_power_off: ov2775_power_off(sensor); probe_err_regulator_disable: ov2775_regulator_disable(sensor); return retval; }
- v4l2_subdev_ops 데이터 구조체를 구현한다.
static struct v4l2_subdev_video_ops ov2775_subdev_video_ops = { .s_stream = ov2775_s_stream, }; static const struct v4l2_subdev_pad_ops ov2775_subdev_pad_ops = { .enum_mbus_code = ov2775_enum_mbus_code, .set_fmt = ov2775_set_fmt, .get_fmt = ov2775_get_fmt, }; static struct v4l2_subdev_core_ops ov2775_subdev_core_ops = { .s_power = ov2775_s_power, .ioctl = ov2775_priv_ioctl, }; static struct v4l2_subdev_ops ov2775_subdev_ops = { .core = &ov2775_subdev_core_ops, .video = &ov2775_subdev_video_ops, .pad = &ov2775_subdev_pad_ops, };
- 센서 전용 IOCTL을 구현한다.
static long ov2775_priv_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov2775 *sensor = client_to_ov2775(client); long ret = 0; struct vvcam_sccb_data_s sensor_reg; mutex_lock(&sensor->lock); switch (cmd){ case VVSENSORIOC_S_POWER: ret = 0; break; case VVSENSORIOC_S_CLK: ret = 0; break; case VVSENSORIOC_G_CLK: ret = ov2775_get_clk(sensor,arg); break; case VVSENSORIOC_RESET: ret = 0; break; case VIDIOC_QUERYCAP: ret = ov2775_query_capability(sensor, arg); break; case VVSENSORIOC_QUERY: ret = ov2775_query_supports(sensor, arg); break; case VVSENSORIOC_G_CHIP_ID: ret = ov2775_get_sensor_id(sensor, arg); break; case VVSENSORIOC_G_RESERVE_ID: ret = ov2775_get_reserve_id(sensor, arg); break; case VVSENSORIOC_G_SENSOR_MODE: ret = ov2775_get_sensor_mode(sensor, arg); break; case VVSENSORIOC_S_SENSOR_MODE: ret = ov2775_set_sensor_mode(sensor, arg); break; case VVSENSORIOC_S_STREAM: ret = ov2775_s_stream(&sensor->subdev, *(int *)arg); break; case VVSENSORIOC_WRITE_REG: ret = copy_from_user(&sensor_reg, arg, sizeof(struct vvcam_sccb_data_s)); ret |= ov2775_write_reg(sensor, sensor_reg.addr, sensor_reg.data); break; case VVSENSORIOC_READ_REG: ret = copy_from_user(&sensor_reg, arg, sizeof(struct vvcam_sccb_data_s)); ret |= ov2775_read_reg(sensor, sensor_reg.addr, (u8 *)&sensor_reg.data); ret |= copy_to_user(arg, &sensor_reg, sizeof(struct vvcam_sccb_data_s)); break; case VVSENSORIOC_S_LONG_EXP: ret = ov2775_set_lexp(sensor, *(u32 *)arg); break; case VVSENSORIOC_S_EXP: ret = ov2775_set_exp(sensor, *(u32 *)arg); break; case VVSENSORIOC_S_VSEXP: ret = ov2775_set_vsexp(sensor, *(u32 *)arg); break; case VVSENSORIOC_S_LONG_GAIN: ret = ov2775_set_lgain(sensor, *(u32 *)arg); break; case VVSENSORIOC_S_GAIN: ret = ov2775_set_gain(sensor, *(u32 *)arg); break; case VVSENSORIOC_S_VSGAIN: ret = ov2775_set_vsgain(sensor, *(u32 *)arg); break; case VVSENSORIOC_S_FPS: ret = ov2775_set_fps(sensor, *(u32 *)arg); break; case VVSENSORIOC_G_FPS: ret = ov2775_get_fps(sensor, (u32 *)arg); break; case VVSENSORIOC_S_HDR_RADIO: ret = ov2775_set_ratio(sensor, arg); break; case VVSENSORIOC_S_BLC: ret = ov2775_set_blc(sensor, arg); break; case VVSENSORIOC_S_WB: ret = ov2775_set_wb(sensor, arg); break; case VVSENSORIOC_G_EXPAND_CURVE: ret = ov2775_get_expand_curve(sensor, arg); break; case VVSENSORIOC_S_TEST_PATTERN: ret= ov2775_set_test_pattern(sensor, arg); break; default: break; } mutex_unlock(&sensor->lock); return ret; }
2.6.2.3 Create Sensor ISI API in ISI Layer
- 센서 핸들에 대한 typedef your <sensor>_Context_t.
typedef struct OV2755_Context_s { IsiSensorContext_t IsiCtx; struct vvcam_mode_info_s CurMode; IsiSensorAeInfo_t AeInfo; IsiSensorIntTime_t IntTime; uint32_t LongIntLine; uint32_t IntLine; uint32_t ShortIntLine; IsiSensorGain_t SensorGain; uint32_t minAfps; uint64_t AEStartExposure; } OV2775_Context_t;
- 센서 라이브러리 콜백 함수에 대해 IsiCamDrvConfig를 구현한다.
IsiCamDrvConfig_s 데이터 구조체를 정의한다. 이 데이터 구조체에 정의된 데이터 멤버에는 센서 ID(CameraDriverID)와 IsiSensor 데이터 구조체에 대한 함수 포인터가 포함된다. IsiCamDrvConfig_t 구조체의 주소를 사용하여, 드라이버는 함수 포인터에 연결된 센서 API에 액세스할 수 있다.
IsiCamDrvConfig_t IsiCamDrvConfig = { .CameraDriverID = 0x2770, .pIsiHalQuerySensor = <sensor>_IsiHalQuerySensorIss, .pfIsiGetSensorIss = <sensor>_IsiGetSensorIss }
참고
- IsiCamDrvConfig는 units/isi/drv/<sensor>/source/<sensor>.c 파일에 정의되어 있다.
- <sensor>_IsiHalQuerySensorIss()는 IOCTL 명령 VVSENSORIOC_QUERY를 사용하여 <sensor>가 지원하는 모든 모드를 가져온다.
<sensor>_IsiGetSensorIss는 다음과 같이 정의되어 있다.
RESULT <sensor>_IsiGetSensorIss(IsiSensor_t *pIsiSensor) … pIsiSensor->pIsiCreateSensorIss = <sensor>_IsiCreateSensorIss; pIsiSensor->pIsiReleaseSensorIss = <sensor>_IsiReleaseSensorIss; pIsiSensor->pIsiRegisterReadIss = <sensor>_IsiRegisterReadIss; pIsiSensor->pIsiRegisterWriteIss = <sensor>_IsiRegisterWriteIss; pIsiSensor->pIsiGetSensorModeIss = <sensor>_IsiGetSensorModeIss; … };
참고: Sensor API Reference 섹션에 설명되어 있다.
2.6.3 Native HDR Mode Porting
Native HDR 모드의 경우, 2-노출 HDR 및 3-노출 센서 HDR이 다음 주의 사항과 함게 지원되고 있다:
- 새로운 Native HDR 모드가 추가되면, hdr_mode는 SENSOR_MODE_HDR_NATIVE로 설정되어야 하고, stitching_mode는 사용 중인 센서에 해당하는 스티칭 모드로 설정되어야 한다.
static struct vvcam_mode_info_s pov2775_mode_info[] = { … { .index = 2, .width = 1920, .height = 1080, .hdr_mode = SENSOR_MODE_HDR_NATIVE, .stitching_mode = SENSOR_STITCHING_DUAL_DCG_NOWAIT, .bit_width = 12, .data_compress = { .enable = 1, .x_bit = 16, .y_bit = 12, }, .bayer_pattern = BAYER_BGGR, .ae_info = { .def_frm_len_lines = 0x466, .curr_frm_len_lines = 0x466, .one_line_exp_time_ns = 59167, .max_integration_line = 0x466 - 4, .min_integration_line = 1, .max_long_again = 8 * 1024 * DCG_CONVERSION_GAIN, .min_long_again = 1 * 1024 * DCG_CONVERSION_GAIN, .max_long_dgain = 4 * 1024, .min_long_dgain = 2 * 1024, .max_again = 8 * 1024, .min_again = 2 * 1024, .max_dgain = 4 * 1024, .min_dgain = 1.5 * 1024, .start_exposure = 3 * 400 * 1024, .gain_step = 4, .cur_fps = 30 * 1024, .max_fps = 30 * 1024, .min_fps = 5 * 1024, .min_afps = 5 * 1024, .hdr_ratio = { .ratio_l_s = 8 * 1024, .ratio_s_vs = 8 * 1024, .accuracy = 1024, }, .int_update_delay_frm = 1, .gain_update_delay_frm = 1, }, .mipi_info = { .mipi_lane = 4, }, .preg_data = ov2775_1080p_native_hdr_regs, .reg_data_count = ARRAY_SIZE(ov2775_1080p_native_hdr_regs), }, };
- 2-노출에 대한 Native HDR 기본 스티칭 비율을 설정하고, 3-노출에 대한 스티칭 비율로 ratio_s_vs(long/short)를 사용하고, ratio_l_s(long/normal)와 ratio_s_vs(normal/short)를 모두 설정한다.
static struct vvcam_mode_info_s pov2775_mode_info[] = { … { .index = 2, .width = 1920, .height = 1080, .hdr_mode = SENSOR_MODE_HDR_NATIVE, .stitching_mode = SENSOR_STITCHING_DUAL_DCG_NOWAIT, .bit_width = 12, .data_compress = { .enable = 1, .x_bit = 16, .y_bit = 12, }, .bayer_pattern = BAYER_BGGR, .ae_info = { .def_frm_len_lines = 0x466, .curr_frm_len_lines = 0x466, .one_line_exp_time_ns = 59167, .max_integration_line = 0x466 - 4, .min_integration_line = 1, .max_long_again = 8 * 1024 * DCG_CONVERSION_GAIN, .min_long_again = 1 * 1024 * DCG_CONVERSION_GAIN, .max_long_dgain = 4 * 1024, .min_long_dgain = 2 * 1024, .max_again = 8 * 1024, .min_again = 2 * 1024, .max_dgain = 4 * 1024, .min_dgain = 1.5 * 1024, .start_exposure = 3 * 400 * 1024, .gain_step = 4, .cur_fps = 30 * 1024, .max_fps = 30 * 1024, .min_fps = 5 * 1024, .min_afps = 5 * 1024, .hdr_ratio = { .ratio_l_s = 8 * 1024, .ratio_s_vs = 8 * 1024, .accuracy = 1024, }, .int_update_delay_frm = 1, .gain_update_delay_frm = 1, }, .mipi_info = { .mipi_lane = 4, }, .preg_data = ov2775_1080p_native_hdr_regs, .reg_data_count = ARRAY_SIZE(ov2775_1080p_native_hdr_regs), }, };
- 일반적으로 Native HDR은 센서단에서 데이터 압축을 수행하며, ISP 모듈의 압축 해제 함수를 활성화해야 한다. "data_compress.enable = 1"로 설정하면 센서 데이터가 압축되고 데이터가 x_bit에서 y_bit로 압축된다. 압축 해제 커브 API는 Sensor Compand Curve 섹션에 설명된대로 구현해야 한다.
static struct vvcam_mode_info_s pov2775_mode_info[] = { … { .index = 2, .width = 1920, .height = 1080, .hdr_mode = SENSOR_MODE_HDR_NATIVE, .stitching_mode = SENSOR_STITCHING_DUAL_DCG_NOWAIT, .bit_width = 12, .data_compress = { .enable = 1, .x_bit = 16, .y_bit = 12, }, .bayer_pattern = BAYER_BGGR, .ae_info = { .def_frm_len_lines = 0x466, .curr_frm_len_lines = 0x466, .one_line_exp_time_ns = 59167, .max_integration_line = 0x466 - 4, .min_integration_line = 1, .max_long_again = 8 * 1024 * DCG_CONVERSION_GAIN, .min_long_again = 1 * 1024 * DCG_CONVERSION_GAIN, .max_long_dgain = 4 * 1024, .min_long_dgain = 2 * 1024, .max_again = 8 * 1024, .min_again = 2 * 1024, .max_dgain = 4 * 1024, .min_dgain = 1.5 * 1024, .start_exposure = 3 * 400 * 1024, .gain_step = 4, .cur_fps = 30 * 1024, .max_fps = 30 * 1024, .min_fps = 5 * 1024, .min_afps = 5 * 1024, .hdr_ratio = { .ratio_l_s = 8 * 1024, .ratio_s_vs = 8 * 1024, .accuracy = 1024, }, .int_update_delay_frm = 1, .gain_update_delay_frm = 1, }, .mipi_info = { .mipi_lane = 4, }, .preg_data = ov2775_1080p_native_hdr_regs, .reg_data_count = ARRAY_SIZE(ov2775_1080p_native_hdr_regs), }, };
- Native HDR BLS 및 WB는 일반적으로 센서 측에서 수행할 필요가 있다. 그래서 센서 WB 및 BLS 인터페이스를 구현하고 Sensor White Balance and Black Level Correction (BLC) 섹션에 설명된 대로 센서 BLS 및 WB를 사용하도록 ISP를 구성해야 한다.
2.6.4 Sensor Compand Curve
vvcam_mode_info_t 데이터 구조체에서, sensor_data_compress_t 데이터 구조체는 센서 데이터가 압축되었는지 여부를 설명한다. 센서 데이터가 압축된 경우, sensor_data_compress_t 데이터 구조체는 데이터 압축 유형을 설명한다.
참고
- 확장 모듈에 대한 최대 비트 너비는 20비트이다.
- 확장 모듈을 제거하려면, data_compress.enable = 0을 설정한다.
- 컴팬드(compand) 및 복원 커브는 센서에 따라 다르다. 예를 들어, OV2775의 커브는 OS08A20의 커브와 다르다.
예제:
OV2775 Native HDR의 경우, 센서 데이터가 16비트에서 12비트로 압축된다. 그래서,
"x_bit =16"와 "y_bit=12" 이다.
이는 컴팬드 모듈에서 사용되는 복원 커브의 유형을 결정한다.
{
.index = 2,
.width = 1920,
.height = 1080,
.fps = 30,
.hdr_mode = SENSOR_MODE_HDR_NATIVE,
.bit_width = 12,
.data_compress.enable = 1,
.data_compress.x_bit = 16,
.data_compress.y_bit = 12,
.bayer_pattern = BAYER_BGGR,
.ae_info = {
.DefaultFrameLengthLines = 0x466,
.one_line_exp_time_ns = 59167,
.max_interrgation_time = 0x466 - 2,
.min_interrgation_time = 1,
.gain_accuracy = 1024,
.max_gain = 21 * 1024,
.min_gain = 3 * 1024,
},
.preg_data = ov2775_1080p_native_hdr_regs,
.reg_data_count = ARRAY_SIZE(ov2775_1080p_native_hdr_regs),
}
ISP는 지정된 압축 방법에 따라 압축 해제를 한다. 센서가 16비트에서 12비트로 압축되면, 컴팬드 모듈은 <sensor>_get_expand_curve() 함수를 호출하여 sensor_expand_curve_s 데이터 구조체에 정의된 대로 12비트에서 16비트 확장 커브를 가져온다.
아래에서 확장 커브의 한계를 참조한다.
(1 << pexpand_curve->expand_px[i]) =
pexpand_curve->expand_x_data[i+1] - pexpand_curve->expand_x_data[i]
예를 들어, OV2775는 커브를 확장한다.
OV2775는 4-피스 PWL(piece-wise linear) 커브를 통해 16비트에서 12비트로 데이터 압축을 수행한다. 다음 공식은 커브를 정의하며 다음 그림에 나와 있다.
백엔드 프로세서는 다음 공식을 사용하여 12비트 데이터를 16비트 데이터로 압푹 해제할 수 있다.
int ov2775_get_expand_curve(struct ov2775 *sensor,
sensor_expand_curve_t* pexpand_curve)
{
int i;
if ((pexpand_curve->x_bit) == 12 && (pexpand_curve->y_bit == 16)){
uint8_t expand_px[64] = {6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6};
memcpy(pexpand_curve->expand_px,expand_px,sizeof(expand_px));
pexpand_curve->expand_x_data[0] = 0;
pexpand_curve->expand_y_data[0] = 0;
for(i = 1; i < 65; i++){
pexpand_curve->expand_x_data[i] =
(1 << pexpand_curve->expand_px[i-1]) +
pexpand_curve->expand_x_data[i-1];
if (pexpand_curve->expand_x_data[i] < 512){
pexpand_curve->expand_y_data[i] =pexpand_curve->expand_x_data[i] << 1;
}
else if (pexpand_curve->expand_x_data[i] < 768){
pexpand_curve->expand_y_data[i] =(pexpand_curve->expand_x_data[i] - 256) << 2;
}
else if (pexpand_curve->expand_x_data[i] < 2560){
pexpand_curve->expand_y_data[i] =(pexpand_curve->expand_x_data[i] - 512) << 3;
}
else{
pexpand_curve->expand_y_data[i] =(pexpand_curve->expand_x_data[i] - 2048) << 5;
}
}
return 0;
}
return (-1);
}
ar0820 20-bit to12-bit as 16-bit output:
Knee-포인트의 자동 값은 oc_lut_XX 레지스터에서 다시 읽을 수 있지만 변경할 수는 없다(oc_lut_XX 레지스터에 대한 쓰기가 무시됨). 모든 knee-포인트 레지스터는 MSB로 정렬된다. 예를 들어, 프로그래밍된 값 0x2000은 출력이 12비트 데이터일 때 0x200으로 작동하고 출력이 16비트 데이터일 때 0x2000으로 작동한다.
확장 커브는 다음과 같이 정의된다:
expand_px[64] = {13, 13, 14, 9, 10, 11, 12, 13,
10, 11, 12, 13, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,};
expand_x_data[65] ={0,0x2000,0x4000,0x8000,0x8200,0x8600,0x8e00,0x9e00,0xbe00,
0xc200,0xca00,0xda00,0xfa00,0xfa01,0xfa02,0xfa03,0xfa04,
0xfa05,0xfa06,0xfa07,0xfa08,0xfa09,0xfa0a,0xfa0b,0xfa0c,
0xfa0d,0xfa0e,0xfa0f,0xfa10,0xfa11,0xfa12,0xfa13,0xfa14,
0xfa15,0xfa16,0xfa17,0xfa18,0xfa19,0xfa1a,0xfa1b,0xfa1c,
0xfa1d,0xfa1e,0xfa1f,0xfa20,0xfa21,0xfa22,0xfa23,0xfa24,
0xfa25,0xfa26,0xfa27,0xfa28,0xfa29,0xfa2a,0xfa2b,0xfa2c,
0xfa2d,0xfa2e,0xfa2f,0xfa30,0xfa31,0xfa32,0xfa33,0xfa34};
expand_y_data[65] = {0x00,
0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000,
0x20000, 0x40000, 0x80000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000,
0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000,
0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000,
0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000,
0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000,
0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000,
0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000, 0x100000};
참고
센서 데이터는 16비트 출력이므로, data_compress는 x_bit = 20 및 y_bit = 16으로 설정해야 한다.
.data_compress = {
.enable = 1,
.x_bit = 20,
.y_bit = 16,
},
2.6.5 Sensor White Balance and Black Level Correction (BLC)
ISP AWB는 일반 모드에서 사용된다. Native HDR 모드에서는 센서에서 이미지 합성 전에 블랙 레벨과 화이트 밸런스 보정을 수행해야 한다.
센서의 WB 모드를 활성화하려면 AWB 모드를 ISI_SENSOR_AWB_MODE_SENSOR로 설정하는 인터페이스를 제공해야 한다. 이 ISI_SENSOR_AWB_MODE_SENSOR 모드에서 ISP는 화이트 밸런스와 블랙 레벨 리덕션(reduction)을 수행하지 않는다. VVSENSORIOC_S_WB 및 VVSENSORIOC_S_BLC를 사용하여 블랙 레벨과 화이트 밸런스 보정을 위한 센서를 설정한다.
예제:
static RESULT OV2775_IsiGetSensorAWBModeIss(IsiSensorHandle_t handle,
IsiSensorAwbMode_t *pawbmode)
{
OV2775_Context_t *pOV2775Ctx = (OV2775_Context_t *) handle;
if (pOV2775Ctx == NULL || pOV2775Ctx->IsiCtx.HalHandle == NULL) {
return RET_NULL_POINTER;
}
if (pOV2775Ctx->SensorMode.hdr_mode == SENSOR_MODE_HDR_NATIVE) {
*pawbmode = ISI_SENSOR_AWB_MODE_SENSOR;
}
else {
*pawbmode = ISI_SENSOR_AWB_MODE_NORMAL;
}
return RET_SUCCESS;
}
2.7 Camera Timing Issue Solution
두 개의 센서 구성에 대해 다음 상황 중 하나가 발생할 수 있다:
- 두 번째 센서 FPS는 첫 번째 센서와 다르다.
- 두 번째 센서 이미지는 지터를 표시한다.
- 이미지의 두 번째 센서 초기 밝기는 수시로 변경된다.
해결책:
다음 예(예: OV2775)에서 이 문제를 해결하기 위해 타이밍을 조정할 수 있다:
- 아래 그림과 같이 센서 레지스터를 읽는다.
- MIPI clock과 Pclk를 계산한다.
- 이미지가 정상으로 돌아가고 두 센서의 FPS가 동일해질 때까지 센서 PLL 배율의 크기를 약간 줄인다.
- 이미지가 정상으로 돌아온 후, 센서의 HTS/VTS를 통해 FPS를 조정한다.