MIPI-CSI 카메라 드라이버 개발 - 1
NVIDIA/Jetson

MIPI-CSI 카메라 드라이버 개발 - 1

본 글은 Jetson Tegra 플랫폼의 카메라 인터페이스와 데이터 흐름, MIPI CSI 드라이버의 일반적인 구성 및 설정에 대해 자세히 설명합니다. 테스트 환경은 아래와 같습니다.

 

테스트 환경

  • Jetson Xaveir NX
  • Sony IMX185 Camera

 

Jetson Camera Subsystem

Jetson Device 간에는 H/W적인 차이는 있지만 전반적인 Camera Subsystem은 아래 이미지와 같이 거의 동일합니다.

 

 

구성 요소에 대해 간단히 설명하자면

 

Jetson 카메라 직렬 인터페이스(CSI)는 카메라 직렬 인터페이스 2(CSI-2)에 대한 MIPI Alliance 사양을 기반으로 합니다. 우선 카메라 센서는 CSI를 통해 Jetson에 연결됩니다. CSI 블록은 센서 MIPI 신호의 수신기로 작동하고 비디오 입력 장치(VI)에 대한 픽셀 데이터 소스로 작동합니다. CSI 블록은 Bayer Raw 데이터 뿐만 아니라 YUV 또는 RGB 데이터 유형도 전달 할 수 있습니다.

 

이러한 강력한 구성 요소를 갖춘 Tegra 카메라 하위 시스템은 다양한 형식의 여러 소스에서 데이터를 원활하게 처리하는 옵션을 제공합니다.

 

Linux 4 Tegra Camera Driver

Camera Subsystem 다음으로 Tegra 카메라 인터페이스의 소프트웨어 아키텍처를 살펴보자면, 먼저 Nvidia는 Linux4Tegra(L4T) 소프트웨어로 Linux OS를 지원합니다. 카메라 드라이버는 CSI 버스를 통해 카메라 센서의 데이터를 센서의 기본 형식으로 구성하고 읽으며 선택적으로 이를 다른 형식으로 변환합니다.

Nvidia는 카메라 및 애플리케이션 사용 사례에 따라 선택할 수 있는 두 가지 유형의 카메라 액세스 경로를 제공합니다.

Direct V4L2 Interface

Direct V4L2 Interface를 지원하는 애플리케이션에서는 이 인터페이스를 사용하여 Camera Core Library를 사용하지 않고도 NVIDIA V4L2 드라이버와 통신할 수 있습니다. 주로 카메라에서 RAW 데이터를 캡처하기 위한 것으로, 처리가 수행되지 않고 데이터가 사용자 애플리케이션에서 직접 소비되는 최소 경로입니다.

 

애플리케이션은 다음과 같이 커널 모드 V4L2 드라이버를 사용합니다.




Camera Core Library Interface

Camera Core Library Interface는 모든 제어 기능을 제공하고 애플리케이션과 커널 모드 V4L2 드라이버 간의 모든 처리를 수행합니다. 카메라 코어 라이브러리 인터페이스의 일반적인 사용 사례는 다음과 같습니다.

  • NVIDIA ® Jetson™ ISP 기능을 갖춘 애플리케이션
  • RGB 형식을 YUV 형식으로 변환하고 Bayer 센서에 대한 다양한 후처리 작업을 수행해야 하는 애플리케이션

다음 다이어그램은 애플리케이션 및 커널 모드 V4L2 드라이버가 포함된 Jetson Linux 아키텍처 프레임워크를 보여줍니다.


이 모델에서 카메라 데이터는 Camera Core, libArgus와 같은 몇몇 Nvidia 라이브러리를 통해 소비됩니다. 이 경우 코어에서 사용 가능한 GPU를 효율적으로 활용하여 입력 데이터에 대한 다양한 데이터 처리를 수행할 수 있습니다.

Jetson IMX185 카메라

보다 자세히 살펴보기 위해 기본적으로  2MP(1920 x 1080, Bayer 센서) Sony CSI 카메라 모듈 IMX185을 사용하여 예시를 들자면 기본 구성은 아래와 같습니다.

IMX185 카메라는 TCA9546 I2C 확장 칩을 통해 I2C 버스 0번에 센서 I2C 주소는 0x1a 에 연결되어 있습니다.

IMX185 드라이버는 I2C 버스 드라이버를 사용하여 트리거되고 Tegra V4L2 카메라 프레임워크에 등록됩니다. 그러면 애플리케이션에서 사용할 수 있는 /dev/videoX 장치가 생성됩니다.

IMX185 드라이버를 불러오려면 다음을 처리해야 하며 다음 섹션에서 자세히 설명합니다.

  • Device tree node
  • V4L2 compatible sensor driver

이번에는 IMX185 카메라의 장치 트리를 설정하는 방법을 살펴보겠습니다.

Device Tree Changes for Tegra Camera

글에서 사용되는 예제파일인 tegra194-camera-imx185-a00.dtsi 파일은 /hardware/nvidia/platform/t19x/common/kernel-dts/t19x-common-modules폴더에 있습니다.

Tegra Camera Platform

tegra-camera-platform은 Tegra SoC에 연결된 카메라/센서의 기본 정보를 정의하는 하나 이상의 모듈로 구성됩니다. 상단의 공통 부분에는 연결된 모든 항목에 대한 통합 정보가 포함되어 있지만 각 모듈 하위 섹션에서는 이를 개별적으로 정의합니다. 여기서 num_csi_lanes 항목은 모든 카메라가 활성화 되었을 경우 CSI 레인의 총 수를 의미합니다. 여기서는 단일 4 lane imx185 카메라를 사용하기에 num_csi_lanes를 4로 할당합니다.

tegra-camera-platform {
compatible = 'nvidia, tegra-camera-platform';
num_csi_lanes = <4>;        //Number of lanes
max_lane_speed = <1500000>; //Maximum lane speed
min_bits_per_pixel = <10>;  //bits per pixel
vi_peak_byte_per_pixel = <2>;   //byte per pixel
vi_bw_margin_pct = <25>;    //Don't care
isp_peak_byte_per_pixel = <5>;//Don't care
isp_bw_margin_pct = <25>;   //Don't care

		modules {
			module0 {
				badge = "imx185_bottom_liimx185";
				position = "bottom";
				orientation = "0";
				drivernode0 {
                			...
  
};

 

모듈 정보는 tegra-camera-platform 장치 트리 노드 내의 각 센서 ID를 설명하기 위한 것입니다. 시스템에 동일한 모듈이 여러 개 있는 경우 각 모듈에 대해 고유한 배지 이름을 만듭니다. 예를 들어 시스템에 두 개의 동일한 카메라 모듈이 있는 경우 첫 번째 카메라 모듈을 imx185_bottom으로 호출하고 두 번째 카메라 모듈을 imx185_top으로 호출할 수 있습니다.

 

		modules {
			module0 {
				badge = "imx185_bottom_liimx185";
				position = "bottom";
				orientation = "0";
				drivernode0 {
					/* Declare PCL support driver (classically known as guid)  */
					pcl_id = "v4l2_sensor";
					/* Driver v4l2 device name */
					devname = "imx185 30-001a";
					/* Declare the device-tree hierarchy to driver instance */
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9546@70/i2c@0/imx185_a@1a";
				};
			};
		};
	};

Device tree node

장치 트리 노드에서 장치의 올바른 작동을 위해서는 카메라 속성(output resolution, FPS, Mipi Clock 등)을 추가해야 합니다. 카메라 센서는 여러가지 모드를 지원할 수도 있습니다. 아래 예시에는 몇몇 센서 모드를 생략하고 mode0만 보이지만 실제로 5가지 센서 모드를 지원합니다. 이러한 모드 설정을 카메라 센서 Device tree node에 포함할 수 있습니다.

i2c@3180000 {   //I2C-2 base address
tca9546@70 { //I2C expander IC
i2c@0 {
    imx185_a@1a {
        compatible = "nvidia,imx185";

        reg = <0x1a>;
        devnode = "video0";

        /* Physical dimensions of sensor */
        physical_w = "15.0";
        physical_h = "12.5";

        sensor_model ="imx185";
        /* Define any required hw resources needed by driver */
        /* ie. clocks, io pins, power sources */

        /* Defines number of frames to be dropped by driver internally after applying */
        /* sensor crop settings. Some sensors send corrupt frames after applying */
        /* crop co-ordinates */
        post_crop_frame_drop = "0";

        /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */
        use_decibel_gain = "true";

        /* if true, delay gain setting by one frame to be in sync with exposure */
        delayed_gain = "true";

        /* enable CID_SENSOR_MODE_ID for sensor modes selection */
        use_sensor_mode_id = "true";

        /* WAR to prevent banding by reducing analog gain. Bug 2229902 */
        limit_analog_gain = "true";
        
        mode0 { /*mode IMX185_MODE_1920X1080_CROP_30FPS*/
            mclk_khz = '24000';		//MIPI driving clock
            num_lanes = '4';		//Number of lanes
            tegra_sinterface = 'serial_a'; //Serial interface
            phy_mode = 'DPHY';		//physical connection mode
            discontinuous_clk = 'yes';
            dpcm_enable = 'false';		//Don't care
            cil_settletime = '0';		//Don't care

            active_w = '1920';		//active width
            active_h = '1080';		//active height
            mode_type = 'bayer';		//sensor type
            pixel_phase = 'rggb';		//output format
            csi_pixel_bit_depth = '12';	//bit per pixel
            readout_orientation = '0';	//Don't care
            line_length = '2200';		//Total width
            inherent_gain = '1';		//Don't care
            mclk_multiplier = '2';	//pix_clk_hz/mclk_khz
            pix_clk_hz = '74250000';	//Pixel clock HTotal*VTotal*FPS 
            gain_factor = "10";
            min_gain_val = "0"; /* 0dB */
            max_gain_val = "480"; /* 48dB */
            step_gain_val = "3"; /* 0.3 */
            default_gain = "0";
            min_hdr_ratio = "1";
            max_hdr_ratio = "1";
            framerate_factor = "1000000";
            min_framerate = "1500000"; /* 1.5 */
            max_framerate = "30000000"; /* 30 */
            step_framerate = "1";
            default_framerate= "30000000";
            exposure_factor = "1000000";
            min_exp_time = "30"; /* us */
            max_exp_time = "660000"; /* us */
            step_exp_time = "1";
            default_exp_time = "33334";/* us */
            embedded_metadata_height = "1";
    };	
    };
};
}; 
};

 

각 속성 설명에 대한 자세한 내용은 아래 링크 가이드를 확인

https://docs.nvidia.com/jetson/archives/r35.1/DeveloperGuide/text/SD/CameraDevelopment/SensorSoftwareDriverProgramming.html

 

Sensor Software Driver Programming — Jetson Linux<br/>Developer Guide 34.1 documentation

After driver development is complete, you must also add the new device information to the system kernel device tree so it can be registered (instantiated) when the kernel boots. The below methods are for registering your device. Device-tree overlay With UE

docs.nvidia.com

속성 중 센서 픽셀 클럭 설정에는 두 가지 종류가 있으며 사용하는 카메라 모듈에 따라 다릅니다. bayer 센서에 대해서는 pix_clk_hz를 구성합니다. 이와 반대로 Serializer / Deserializer 칩을 사용하는 카메라 모듈이 있는 경우 serdes_pix_clk_hz를 구성합니다.

이 예에서 픽셀 클럭은 다음과 같이 계산됩니다.

pix_clk_hz = HTotal x VTotal xFPS

IMX185의 경우 

  • active output size는 1920×1080@30fps
  • sensor ouput size는  2200×1125@30fps

pix_clk_hz = 2200 x 1125 x 30 = 74250000

pix_clk_hz는 74250000입니다.

 

DTS Binding

앞에서 본 것처럼 카메라 데이터 흐름은 다음과 같습니다.

Sensor Output CSI Input CSI output VI Input
liimx185_imx185_out0 liimx185_csi_in0 liimx185_csi_out0 liimx185_vi_in0

 

내부 포트 간의 바인딩은 아래 설정을 사용하여 수행됩니다. 

 

CSI-VI 포트 바인딩의 경우 num-channels 할목은 연결된 카메라 센서 수를 정의합니다. 둘 이상의 카메라 센서가 연결되었을 경우 해당 항목을 업데이트 해주어야 하며 포트 정의 또한 확장해주어야 합니다. 이 예에서는 단일 IMX185 카메라를 사용하기 때문에 num-channles = <1>로 설정합니다. port-index는 어떤 CSI 포트가 사용되었는지 나타내고, bus-width은 각 센서에 연결된 CSI 레인 수를 식별하는 것으로 카메라 센서의 CSI 레인 수를 적어 주면 됩니다. remote-endpoint는 두 포트를 바인딩하기 위한 레이블을 정의합니다.

	host1x {
		vi@15c10000 {
			num-channels = <1>;
			ports {
				#address-cells = <1>;
				#size-cells = <0>;
				port@0 {
					reg = <0>;
					liimx185_vi_in0: endpoint {
						port-index = <0>;
						bus-width = <4>;
						remote-endpoint = <&liimx185_csi_out0>;
					};
				};
			};
		};

		nvcsi@15a00000 {
			num-channels = <1>;
			#address-cells = <1>;
			#size-cells = <0>;
			channel@0 {
				reg = <0>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						liimx185_csi_in0: endpoint@0 {
							port-index = <0>;
							bus-width = <4>;
							remote-endpoint = <&liimx185_imx185_out0>;
						};
					};
					port@1 {
						reg = <1>;
						liimx185_csi_out0: endpoint@1 {
							remote-endpoint = <&liimx185_vi_in0>;
						};
					};
				};
			};
		};
	};

 

드라이버는 Host1x DMA 엔진 모듈을 통해 VI 출력에서 ​​데이터를 가져옵니다.

부팅하는 동안 DTS에 설정한 값을 토대로 카메라 드라이버(imx185.c)에 의해 추가 드라이버 및 장치 등록이 수행됩니다.

 

드라이버에 대한 설명은 다음 글에서 설명 하겠습니다.

 

출처 :

https://docs.nvidia.com/jetson/archives/r35.1/DeveloperGuide/text/SD/CameraDevelopment/CameraSoftwareDevelopmentSolution.html

 

Camera Software Development Solution — Jetson Linux<br/>Developer Guide 34.1 documentation

This topic describes the NVIDIA® Jetson™ camera software solution, and explains the NVIDIA-supported and recommended camera software architecture for fast and optimal time to market. It outlines and explains development options for customizing the camer

docs.nvidia.com

https://www.sunnywale.com/uploadfile/2022/0608/IMX185LQJ-C_Awin.pdf

 

'NVIDIA > Jetson' 카테고리의 다른 글

JETPACK 6 Flash  (0) 2024.06.23
Jetson Sytem Upgrade  (0) 2024.05.11
Isaac Ros Image Segmentation  (0) 2024.01.11
Virtual Machine Jetson Flash  (0) 2023.08.15
Linux to Jetson USB 테더링  (0) 2023.07.16