rk3568 适配摄像头 (mipi 双摄)
rk3568 适配双摄像其实就是逐个适配单摄像头,只是两颗摄像头的数据总线可能不同(cif+mipi),也可能相同(mipi(2lane) x 2)。几乎相同的上电时许,不同的时钟信号和总线协议决定加载过程会略有不同。
提示:rk3568 双摄像头组合方式:cif+ mipi 和 mipi x 2。
文章目录
- rk3568 适配摄像头 (mipi 双摄)
- 圈重点 看想学
- 1. 核查硬件,匹配摄像头
- 1.1 内核设备树(CIF + MIPI)
- 1.2 内核设备树(MIPI 双摄像)
- 2 摄像头适配HAL3
- 2.1 匹配 camera3_profiles.xml
- 2.2 匹配摄像头标定 xxx.jason
- 2.3 手动抓取摄像头信号
- Tips
- 总结
圈重点 看想学
a) 适配双摄像头
b) 双摄像头链接
1. 核查硬件,匹配摄像头
原理图核对硬件供电(vcc_2v8、vdd_1v8、vdd_1v2),时钟频率、reset、pwdn、power等控制信号,以及总线数据(i2c、mipi、cif)。逻辑分析仪只能抓取逻辑电平无法确认信号幅度和信号质量,必要时要用示波器抓取。
1.1 内核设备树(CIF + MIPI)
设配CIF+MIPI的双摄像头时,CIF占用cif编码,MIPI占用rkisp。此时mipi可使用1-4lane信号,须注意它要使用csi2_dphy0。
双摄像头适配时,先硬件后软件。硬件核对供电 vcc_1v8、vcc_1v2、vcc_2v8以i2c和总线信号;软件则是依次核查时钟信号、reset、pwdn、power等控制电平,驱动加载过程以及media/video拓扑树。摄像头(CIF协议)需要参照手册设定与之匹配总线数据宽度,以及cif总线众多GPIO复用。
/ {
vcc_camera: vcc-camera-regulator {
compatible = "regulator-fixed";
gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&camera_pwr>;
regulator-name = "vcc_camera";
enable-active-high;
regulator-always-on;
regulator-boot-on;
};
};
&i2c4 {
status = "okay";
os04a10: os04a10@36 {
compatible = "ovti,os04a10";
reg = <0x36>;
clocks = <&cru CLK_CIF_OUT>;
clock-names = "xvclk";
power-domains = <&power RK3568_PD_VI>;
pinctrl-names = "default";
pinctrl-0 = <&cif_clk>;
reset-gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "CMK-OT1607-FV1";
rockchip,camera-module-lens-name = "M12-40IRC-4MP-F16";
port {
ucam_out0: endpoint {
remote-endpoint = <&mipi_in_ucam0>;
data-lanes = <1 2 3 4>;
};
};
};
/*
* gc2145 needs to be disabled,
* when gmac1 is enabled;
* pinctrl conflicts;
*/
gc2145: gc2145@3c {
compatible = "galaxycore,gc2145";
reg = <0x3c>;
clocks = <&cru CLK_CIF_OUT>;
clock-names = "xvclk";
power-domains = <&power RK3568_PD_VI>;
pinctrl-names = "default";
/* conflict with gmac1m1_rgmii_pins & cif_clk*/
pinctrl-0 = <&cif_clk &cif_dvp_clk &cif_dvp_bus16>;
/*avdd-supply = <&vcc2v8_dvp>;*/
/*dovdd-supply = <&vcc1v8_dvp>;*/
/*dvdd-supply = <&vcc1v8_dvp>;*/
reset-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "CameraKing";
rockchip,camera-module-lens-name = "Largan";
port {
gc2145_out: endpoint {
remote-endpoint = <&dvp_in_bcam>;
};
};
};
};
&csi2_dphy_hw {
status = "okay";
};
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in_ucam0: endpoint@1 {
reg = <1>;
remote-endpoint = <&ucam_out0>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&isp0_in>;
};
};
};
};
&pinctrl {
cam {
camera_pwr: camera-pwr {
rockchip,pins =
/* camera power en */
<0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
&rkisp {
status = "okay";
};
&rkisp_mmu {
status = "okay";
};
&rkisp_vir0 {
status = "okay";
port {
#address-cells = <1>;
#size-cells = <0>;
isp0_in: endpoint@0 {
reg = <0>;
remote-endpoint = <&csidphy_out>;
};
};
};
&rkcif {
status = "okay";
};
&rkcif_dvp {
status = "okay";
port {
/* Parallel bus endpoint */
dvp_in_bcam: endpoint {
remote-endpoint = <&gc2145_out>;
bus-width = <8>;
vsync-active = <0>;
hsync-active = <1>;
};
};
};
&rkcif_mmu {
status = "okay";
};
&rkcif_dvp_sditf {
status = "okay";
};
1.2 内核设备树(MIPI 双摄像)
rk3568双摄像头所用mipi信号为拆分模式,将mipi的4组信号拆分为2+2;信号线0、1使用 csi2_dph1,信号2、3使用csi2_dph2,内核启动过程需要分别对应摄像头进行初始化,但是总线使用同一组。
/*
* csi2_dphy0: used for csi2 dphy full mode,
is mutually exclusive with
csi2_dphy1 and csi2_dphy2
* csi2_dphy1: used for csi2 dphy split mode,
physical lanes use lane0 and lane1,
can be used with csi2_dphy2 parallel
* csi2_dphy2: used for csi2 dphy split mode,
physical lanes use lane2 and lane3,
can be used with csi2_dphy1 parallel
*/
设配设备树时,由于原生ISP只有一个mipi编码,其中一组则需要使用cif的进行编码。
双摄像头适配时,先硬件后软件。硬件核对供电 vcc_1v8、vcc_1v2、vcc_2v8以i2c和mipi总线信号;软件则是依次核查时钟信号、reset、pwdn、power等控制电平,以及驱动加载过程和media/video拓扑树。此处不再赘述,直接看设备树。
&i2c2 {
status = "okay";
pinctrl-0 = <&i2c2m1_xfer>;
/* split mode: lane0/1 */
ov5695: ov5695@36 {
status = "okay";
compatible = "ovti,ov5695";
reg = <0x36>;
clocks = <&cru CLK_CIF_OUT>;
clock-names = "xvclk";
power-domains = <&power RK3568_PD_VI>;
pinctrl-names = "default";
pinctrl-0 = <&cif_clk>;
reset-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
pwdn-gpios = <&gpio4 RK_PB2 GPIO_ACTIVE_HIGH>;
power-gpios = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "TongJu";
rockchip,camera-module-lens-name = "CHT842-MD";
port {
ov5695_out: endpoint {
remote-endpoint = <&dphy1_in>;
data-lanes = <1 2>;
};
};
};
/* split mode: lane:2/3 */
gc5025: gc5025@37 {
status = "okay";
compatible = "galaxycore,gc5025";
reg = <0x37>;
clocks = <&pmucru CLK_WIFI>;
clock-names = "xvclk";
pinctrl-names = "default";
pinctrl-0 = <&refclk_pins>;
reset-gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
power-domains = <&power RK3568_PD_VI>;
power-gpios = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <1>;
rockchip,camera-module-facing = "front";
rockchip,camera-module-name = "TongJu";
rockchip,camera-module-lens-name = "CHT842-MD";
port {
gc5025_out: endpoint {
remote-endpoint = <&dphy2_in>;
data-lanes = <1 2>;
};
};
};
};
&csi2_dphy1 {
status = "okay";
/*
* dphy1 only used for split mode,
* can be used concurrently with dphy2
* full mode and split mode are mutually exclusive
*/
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
dphy1_in: endpoint@1 {
reg = <1>;
remote-endpoint = <&ov5695_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
dphy1_out: endpoint@1 {
reg = <1>;
remote-endpoint = <&isp0_in>;
};
};
};
};
&csi2_dphy2 {
status = "okay";
/*
* dphy2 only used for split mode,
* can be used concurrently with dphy1
* full mode and split mode are mutually exclusive
*/
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
dphy2_in: endpoint@1 {
reg = <1>;
remote-endpoint = <&gc5025_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
dphy2_out: endpoint@1 {
reg = <1>;
remote-endpoint = <&mipi_csi2_input>;
};
};
};
};
&mipi_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&dphy2_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi_in>;
data-lanes = <1 2>;
};
};
};
};
&rkcif_mipi_lvds {
status = "okay";
port {
cif_mipi_in: endpoint {
remote-endpoint = <&mipi_csi2_output>;
data-lanes = <1 2>;
};
};
};
&rkisp {
status = "okay";
};
&rkisp_mmu {
status = "okay";
};
&rkisp_vir0 {
status = "okay";
port {
#address-cells = <1>;
#size-cells = <0>;
isp0_in: endpoint@0 {
reg = <0>;
remote-endpoint = <&dphy1_out>;
};
isp0_in_dphy0: endpoint@1 {
reg = <1>;
remote-endpoint = <&dphy0_out>;
};
};
};
核查v4l2视频流节点,可以发现 video0~4可证明驱动正常加载。
ls /dev/video*
/dev/video0 /dev/video11 /dev/video14 /dev/video17 /dev/video2 /dev/video22 /dev/video5 /dev/video8
/dev/video1 /dev/video12 /dev/video15 /dev/video18 /dev/video20 /dev/video3 /dev/video6 /dev/video9
/dev/video10 /dev/video13 /dev/video16 /dev/video19 /dev/video21 /dev/video4 /dev/video7
核查拓扑树,确认camera链路是否正常。如无法看到完整链路则需要重新调配设备树解码链路。
media-ctl -p -d /dev/media0
Opening media device /dev/media0
Enumerating entities
Found 9 entities
Enumerating pads and links
Media controller API version 0.0.193
Media device information
------------------------
driver rkcif
model rkcif_mipi_lvds
serial
bus info
hw revision 0x0
driver version 0.0.193
2 摄像头适配HAL3
驱动和ISP均匹配后可在系统查看到两颗摄像头,且每颗具体参数都有详细属性说明。如有不匹配系统无法正常识别。
dumpsys media.camera | head -n 20
== Service global info: ==
Number of camera devices: 2
Number of normal camera devices: 2
Number of public camera devices visible to API1: 2
Device 0 maps to "0"
Device 1 maps to "1"
Active Camera Clients:
[]
Allowed user IDs: 0
== Camera service events log (most recent at top): ==
05-04 17:11:26 : USER_SWITCH previous allowed user IDs: <None>, current allowed user IDs: 0
05-04 17:11:14 : ADD device 1, reason: (Device added)
05-04 17:11:14 : ADD device 0, reason: (Device added)
== Camera device 0 dynamic info: ==
Device 0 is closed, no client instance
== Camera device 1 dynamic info: ==
Failed to write while dumping service media.camera: Broken pipe
2.1 匹配 camera3_profiles.xml
Camera驱动需要与HAL3 的camera3_profiles.xml清单相互匹配。
DTS | profiles.xml |
---|---|
rockchip,camera-module-index | cameraId, moduleId |
ockchip,camera-module-facing | lens.facing value |
ov5695: ov5695@36 {
...
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
</Profiles>
<Profiles cameraId="0" name="ov5695" moduleId="m00">
<lens.facing value="BACK"/>
正确匹配后可
2.2 匹配摄像头标定 xxx.jason
rk3568 芯片ISP2.1版本,使用ISP2。所用标定摄像头效果文件路径/vendor/etc/camera/rkisp2
,该文件名字与内核摄像头描述严格的匹配格式cameraName_moduleName_module_lens_name.json,如有差别就会无法匹配。
以 ov5695为例,内核设备树中定义相关属性,与之匹配标定效果文件为ov5695_TongJu_CHT842-MD.json
。
ov5695: ov5695@36 {
...
rockchip,camera-module-name = "TongJu";
rockchip,camera-module-lens-name = "CHT842-MD";
cameraName | moduleName | module_lens_name | json |
---|---|---|---|
ov5695: ov5695@36 | rockchip,camera-module-name = “TongJu”; | rockchip,camera-module-lens-name = “CHT842-MD”; | ov5695_TongJu_CHT842-MD.json |
2.3 手动抓取摄像头信号
驱动正常加载,但是Camera2无法正常预览。可选择手动抓取原始视频流确定camera是否正常,这也是标定摄像头必要流程。
v4l2-ctl -d /dev/video0 --set-fmt-video=width=800,height=600,pixelformat=NV12 --stream-mmap=3 --stream-skip=3 --stream-to=/sdcard/cif.out --stream-count=100 --stream-poll
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 30.04 fps
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 30.04 fps
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 30.04 fps
<<<<<<<<<<<
Tips
- rk3566 CIF_CLK 无信号输出
DTS增加参数配置
power-domains = <&power RK3568_PD_VI>;
- i2c 返回错误码 -6
此错误为 i2c总线无应答,产生原因较多。可先核查硬件供电和排线信号,再核查上电时许和时钟频率。 - 双摄像头建议配置为前摄和后摄
Camera2 默认通过控制前后摄切换对应摄像头,不支持多路同时显示。两颗设定为相同的摄像则无法正常预览、拍照和录像。 - 重启 camera 快速命令
adb root
adb shell "pkill provider && pkill camera"
adb shell am start -n com.android.camera2/com.android.camera.CameraLauncher
总结
活学活用,做个合格的搬运工。