rv1126通用性移植摄像头模组讲解,使用当前方式移植过gc2053、gc2093、imx415、sc8238、imx258等摄像头模组;
一、硬件接口
sc8238接口:
imx258接口:
整个摄像头模组连接到soc是靠iic和mipi接口,iic接口来注册驱动驱动、mipi接口来取图片数据;
如在当前首次注册驱动时报错,则去查找iic接口方面问题,在取图的时候出错则去查找mipi接口配置方面的问题。
二、软件调用
1、dts配置
(1)dts配置先查看数据手册sensor在工作时的时序要求,然后在查看硬件配置,看某些硬件是否是外部拉高。
(2)rv1126有两种dts mipi链路:
链路1(直接接到isp上):sensor --》 phy --》rkisp_vir
链路2(直接接到cif上):sensor --》 phy --》mipi-csi --》rkcif --》 rkisp_vir
在1126上如果要取raw数据的话建议是链接到cif上,当可正常取raw数据之后需要取nv12数据时链路到isp上。
例如下面使用的是链路1方式配置的dts
&i2c1 {
status = "okay";
imx258: imx258@1a {
status = "okay";
compatible = "sony,imx258";
reg = <0x1a>;
clocks = <&cru CLK_MIPICSI_OUT>; //MIPI接口只有这一个
clock-names = "xvclk";
power-domains = <&power RV1126_PD_VI>;
pinctrl-names = "rockchip,camera_default";
pinctrl-0 = <&mipicsi_clk1>; //声明时钟引脚 MIPI_CSI_CLK1
avdd-supply = <&vcc_avdd>;
dovdd-supply = <&vcc_dovdd>;
dvdd-supply = <&vcc_dvdd>;
//pwdn-gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_LOW>; //复位,默认拉高
rockchip,camera-module-index = <1>;
rockchip,camera-module-facing = "front";
//指定iq 例如:imx258_GD110_IR120-4MP.xml
rockchip,camera-module-name = "GD110";
rockchip,camera-module-lens-name = "IR120-4MP";
port {
ucam_out5: endpoint {
remote-endpoint = <&csi_dphy1_input>;
data-lanes = <1 2 3 4>;
};
};
};
};
//物理层
&csi_dphy0 {
status = "disabled";
ports {
port@0 {
mipi_in_ucam0: endpoint@1 {
//remote-endpoint;
remote-endpoint = <&ucam_out0>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
csidphy0_out: endpoint@0 {
// remote-endpoint;
remote-endpoint = <&isp_in>;
data-lanes = <1 2 3 4>;
};
};
};
};
&csi_dphy1 {
status = "okay";
ports {
port@0 {
csi_dphy1_input: endpoint@1 {
remote-endpoint = <&ucam_out5>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
csi_dphy1_output: endpoint@0 {
//remote-endpoint = <&isp_virt1_in>;
remote-endpoint = <&isp_in>;
data-lanes = <1 2 3 4>;
};
};
};
};
//kernel
&mipi_csi2 {
status = "disabled";
ports {
port@0 {
mipi_csi2_input: endpoint@1 {
remote-endpoint = <&csi_dphy1_output>;
//remote-endpoint;
data-lanes = <1 2 3 4>;
};
};
port@1 {
mipi_csi2_output: endpoint@0 {
remote-endpoint = <&cif_mipi_in>;
//remote-endpoint;
data-lanes = <1 2 3 4>;
};
};
};
};
//LVDS接口
&rkcif_mipi_lvds {
status = "disabled";
port {
cif_mipi_in: endpoint {
// remote-endpoint = <&mipi_csi2_output>;
/delete-property/ remote-endpoint;
data-lanes = <1 2 3 4>;
};
};
};
&rkcif_mipi_lvds_sditf {
status = "disabled";
port {
cif_sditf: endpoint {
// remote-endpoint = <&isp_virt1_in>;
/delete-property/ remote-endpoint;
data-lanes = <1 2 3 4>;
};
};
};
&rkisp_vir0 {
status = "okay";
ports {
port@0 {
isp_in: endpoint@0 {
// remote-endpoint;
//remote-endpoint = <&csidphy0_out>;
remote-endpoint = <&csi_dphy1_output>;
};
};
};
};
&rkisp_vir1 {
status = "disabled";
ports {
port@0 {
isp_virt1_in: endpoint@0 {
remote-endpoint = <&csi_dphy1_output>;
//remote-endpoint;
};
};
};
};
&rkispp_vir0 {
status = "okay";
};
&rkispp {
status = "okay";
/* the max input w h and fps of mulit sensor */
max-input = <4208 3120 30>;
};
2、驱动注册
代码路径:/kernel/drivers/media/i2c
(1)在代码路径中添加自己的sensor驱动
(2)修改代码路径中的Makefile
在Makefile中添加imx258配置
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
(3)修改代码路径中的Kconfig
在Kconfig中添加imx258配置
config VIDEO_IMX258
tristate "Sony IMX258 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
---help---
This is a Video4Linux2 sensor driver for the Sony
IMX258 camera.
To compile this driver as a module, choose M here: the
module will be called imx258.
(4)在kernel中添加imx258驱动
操作目录:rv1126_SDK/kernel
make ARCH=arm menuconfig
进入可视化配置界面
点击键盘上的 " / "按键,会跳出一个搜索框
输入 imx258 回车
选择1,可看到这个就是前面在Kconfig中写入的配置名字,把【Sony IMX258 sensor support】配置选中,标为*号,即可保存退出。
退出到kernel目录之后 ,进行配置文件同步
make ARCH=arm savedefconfig //保存当前配置,生产配置文件
cp defconfig arch/arm/configs/rv1126_defconfig //进行配置同步
(5)保存iq文件
操作目录:rv1126_SDK/buildroot/output/rockchip_rv1126_rv1109/target/etc/iqfiles
把供应商提供的iq文件或者自己修改适合当前sensor分辨率的iq文件拷贝到rv1126_SDK/buildroot/output/rockchip_rv1126_rv1109/target/etc/iqfiles目录
3、取raw数据
(1)进行链路激活
查找节点:
sensor的节点为 rkisp_mainpath 对应的 video 节点,video 节点名称可能会变,但是
rkisp_mainpath 名称不会变,使用 media-ctl 指令可以找到具体的 video 节点。
media-ctl -p -d /dev/media
内容过多,只展示部分内容,rkisp_mainpath 先找到这个节点,可以看到这个节点的状态不是
enabled
pad2: Source
[fmt:YUYV8_2X8/1920x1080 field:none
crop.bounds:(0,0)/1920x1080
crop:(0,0)/1920x1080]
-> "rkisp-bridge-ispp":0 [ENABLED]
-> "rkisp_mainpath":0 [] # 找到它
-> "rkisp_selfpath":0 [ENABLED]
pad3: Source
-> "rkisp-statistics":0 [ENABLED]
-> "rkisp-mipi-luma":0 [ENABLED]
然后找到 rkisp_mainpath 对应的video节点
- entity 13: rkisp-bridge-ispp (1 pad, 1 link)
type V4L2 subdev subtype Unknown flags 0
pad0: Sink
<- "rkisp-isp-subdev":2 [ENABLED]
- entity 17: rkisp_mainpath (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video5 # 对应video5 节点
pad0: Sink
<- "rkisp-isp-subdev":2 []
- entity 23: rkisp_selfpath (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video6
pad0: Sink
<- "rkisp-isp-subdev":2 [ENABLED]
然后激活 rkisp_mainpath 链路
media-ctl -d /dev/media1 -l '"rkisp-isp-subdev":2->"rkisp-bridge-ispp":0[0]'
media-ctl -d /dev/media1 -l '"rkisp-isp-subdev":2->"rkisp_mainpath":0[1]'
注:如果使用的是cif链路方式,则可以不需要进行链路激活,直接使用v4l2抓取图像就行;建议使用cif链路方式来测试raw数据。
(2)使用v4l2抓取图像
v4l2-ctl -d /dev/video5 --set-fmt-video=width=4208,height=3120,pixelformat=RG10 --stream-mmap=4 --stream-count=1 --stream-to=/tmp/cif2.out --stream-skip=2 --stream-poll
(3)查看图像
将 raw 添加 pgm 的文件头,就可以将其转成可以在 ubuntu 直接查看的 pgm 图像。可以根据如下操作生成文件头
cat > /tmp/cif2.pgm << EOF
P5
4280 3120
65535
EOF
---------------------------------------------------------------------------------------
行1为固定标识
行 2 为分辨率,与抓取的图像分辨率一致
行 3 标识深度,65535 即16bit ,如果是 8bit 则为 255。
然后将数据追加到 cif2.pgm
cat /tmp/cif2.out >> /tmp/cif2.pgm
4、取nv12数据
取nv12使用可以使用rv1126自带的rkmedia方式
因为在摄像头刚刚启动的时候可能开始几帧数据会过暗或者过亮,所以我们取13帧数据
rkmedia_vi_get_frame_test -a /etc/iqfiles --width 4208 --height 3120 -o /usr/4208p.nv12 -c 13
去除前面12帧,保留第13帧数据
dd if=4208p.nv12 of=3120p.nv12 bs=19693440 skip=12
在使用ffmpeg把nv12格式数据转换为jpg格式图片
ffmpeg -y -f rawvideo -pix_fmt nv12 -ss 00:01 -r 1 -s 4208x3120 -i 4208p.nv12 1.jpg
注:去除前面12帧数据的方式也可以在rkmedia_vi_get_frame_test代码中修改。
if (save_file) {
if(frame_id == 12){
fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), save_file);
printf("#Save frame-%d to %s\n", frame_id++, save_path);
}
else
frame_id++;
}
rkmedia_vi_get_frame_test.c修改参考dome:
https://download.csdn.net/download/qq_46030455/89603967
三、可能存在bug
1、驱动无法正常注册
(1)对比原理图,查找供电是否正常。
(2)查看数据手册,iic地址是否填写对。
(3)在驱动的的读写sensor的地方加入while(1),再量下iic各个管脚的波形,看波形是否正常,如果那个引脚不正常就分析那个管脚。查看是否被复用。
(4)无法获取模块信息:could not get module information!
[root@RV1126_RV1109:/]# dmesg |grep imx258
[ 0.945166] imx258 1-0034: driver version: 00.01.06
[ 0.945206] imx258_probe_11111111111111
[ 0.945231] imx258 1-0034: could not get module information!
[ 0.945411] imx258: probe of 1-0034 failed with error -22
分析imx258_probe()函数,查看返回值;看看是否在dts中漏掉某个配置,例如iq指向、各个引脚定义等
2、无法正常取raw数据 ,取raw数据时候超时
[root@RV1126_RV1109:/]# v4l2-ctl -d /dev/video0 --set-fmt-video=width=4208,heigh
t=3120,pixelformat=RG10 --stream-mmap=4 --stream-count=1 --stream-to=/tmp/cap.ra
w --stream-skip=2 --stream-poll
select timeout
[root@RV1126_RV1109:/]# ls -l /tmp/cap.raw
-rw-r--r-- 1 root root 0 Aug 4 09:44 /tmp/cap.raw
[root@RV1126_RV1109:/]#
解决方案:
(1)先查看sensor输出数据流此时使用示波器测量mipi_clk_p/n、mipi_data_p/n的波形、确认sensor是否真正发送数据出来;
(2)在链路代码中添加各种打印,保证链路都有正确连接上;
kernel/drivers/media/platform/rockchip/cif$ grep -nr ".start_streaming"
capture.c:6984:static int rkcif_start_streaming(struct vb2_queue *queue, unsigned int count)
capture.c:6999: .start_streaming = rkcif_start_streaming,
cif-tools.c:547:rkcif_tools_vb2_start_streaming(struct vb2_queue *queue,
cif-tools.c:565: .start_streaming = rkcif_tools_vb2_start_streaming,
cif-scale.c:873:rkcif_scale_vb2_start_streaming(struct vb2_queue *queue,
cif-scale.c:897: .start_streaming = rkcif_scale_vb2_start_streaming,
cif-luma.c:182:rkcif_luma_vb2_start_streaming(struct vb2_queue *queue,
cif-luma.c:204: .start_streaming = rkcif_luma_vb2_start_streaming,
kernel/drivers/phy/rockchip$ grep -nr "stream"
phy-rockchip-csi2-dphy.c:549:static int csi2_dphy_s_stream(struct v4l2_subdev *sd, int on)
phy-rockchip-csi2-dphy.c:761: .s_stream = csi2_dphy_s_stream,
kernel/drivers/media/i2c$ grep -nr "imx215_s_stream"
imx215.c:2448:static int imx215_s_stream(struct v4l2_subdev *sd, int on)
imx215.c:2781: .s_stream = imx215_s_stream,
(3)查看硬件接口是否有正常添加阻抗,如果是转接板子,查看是否排线过长或者板子为加阻抗;(注:我有多个项目都是因为转接板子线过长或者为加阻抗而堵塞)。
3、使用rkmedia取流时候堵塞不动
(1)使用rkmedia取流时候一直堵塞不动,切换到cif链路去取raw数据,保证当前链路是对的。
(2)dts配置不对,最后的isp道路不对;rkisp_vir0 和rkisp_vir1开启错误,建议对着当前上面的dts配置修改。
4、无法正常调用iq
(1)iq文件格式不对;
(2)iq文件像素不对;
(3)找不到iq文件
注:建议iq文件找原厂提供,或者找主控厂家提供适配的iq文件;后期在自行进行调优,可节省很大开发时间
5、图像偏色、曝光等问题
图像偏色:只能进行二次调试iq文件;
图像曝光:可以使用rkisp2x_tuner工具开启自动曝光或者手动曝光并且在驱动中调节曝光率;驱动代码不做详细讲解
gc2093_probe() //对应dts寻找模块
--> gc2093_initialize_controls() //初始化
-->gc2093_ctrl_ops() //设备操作函数
-->gc2053_set_ctrl() //设置sensor的所有属性
-->V4L2_CID_EXPOSURE //曝光时间
-->V4L2_CID_ANALOGUE_GAIN //曝光增益
-->4L2_CID_VBLANK // /* The exposure goes up and reduces the frame rate, no need to write vb */
-->V4L2_CID_HFLIP //成像翻转 0号寄存器
-->V4L2_CID_VFLIP //成像翻转 1号寄存器
注:翻转是10寄存器组合决定 四种状态
黑白成像:如果使用的是gc2053、gc2093 默认是黑白图像;修改iq中的【COLOR_AS_GREY】 配置 0 为彩色, 1 则为黑白;
注:如果iq文件不适配可能会存在多屏分层、蓝白条纹、黑屏等情况;
6、 ispserver 问题
如果需要开启ispserver服务,需要设置export HDR_MODE=0;如果不进行设置的话开启ispserver服务会存在曝光设置失败问题,并且再驱动中强制写入曝光参数的话也只是第一帧有效,后面帧数无效。
留言:创作不易,如果哪里写的不对,请及时指出;求赞!!!