一、前言
开发使用的摄像头为sc132gs,板级编号18。
二、开发记录
1.Sensor驱动
1).驱动编译
瑞芯微sdk包提供了非常多的摄像头驱动,可支持的摄像头驱动在/rockchip/sysdrv/source/kernel/drivers/media/i2c/目录下查看。可以在该目录下找到我们需要的sc132gs.c文件。
而sdk包中已经提供且支持的摄像头有"imx415 os04a10 sc4336 sc3336 sc530ai gc2053 sc200ai sc401ai sc450ai sc4336p sc850sl gc4653 gc4023"等,正常编译后不会生成我们需要的sc132gs.ko,所以要先做一下内核配置。
cd rockchip/sysdrv/source/kernel
make menuconfig
找到sc132gs,=m,编译为模块。
问题:瑞芯微sdk的内核配置生成的.config并未使用,所以按如上配置是无效的。找到实际使用的config文件,添加CONFIG_VIDEO_SC132GS=m即可。瑞芯微内核有多个config文件共同作用,其中关于摄像头驱动部分的配置在如下config文件中:
sysdrv/source/kernel/arch/arm/configs/rv1103b-evb.config
重新编译后会生成sc132gs.ko。
2).加载驱动
烧录到板子上,加载内核。(可能需要指定sc132gs.ko的实际路径)
# insmod ./oem/usr/ko/sc132gs.ko
sc132gs 4-0030-9:driver version:00.01.07
sc132gs 4-0030-9:supply avdd not found, using dummy regulator
sc132gs 4-0030-9: supply dovdd not found, using dummy regulator
sc132gs 4-0030-9:supply dvdd not found, using dummy regulator
sc132gs;4-0030-9:could not get default pinstate
sc132gs4-0030-9:could not get sleep pinstate
s4-0030-9:Unexpected sensor id(0000),ret(-5)
根据信息,加载内核没有获取到sensor id。以及设备树中找不到配置avdd,dovdd,dvdd,default-pinctl,sleep-pinctl。
3).加载驱动时的初始化代码
以上信息可以在sc132gs.c文件中找到对应的输出代码。执行insmod sc132gs.ko时会执行一部分初始化函数。
//初始化,把sensor add到i2c上
static int __init sensor_mod_init(void)
{
return i2c_add_driver(&sc132gs_i2c_driver);
}
//注册函数,其中sc132gs_probe函数负责了初始化的内容。加载驱动时报的信息也在这个函数中。
static struct i2c_driver sc132gs_i2c_driver = {
.driver = {
.name = SC132GS_NAME,
.pm = &sc132gs_pm_ops,
.of_match_table = of_match_ptr(sc132gs_of_match),
},
.probe = &sc132gs_probe,
.remove = &sc132gs_remove,
.id_table = sc132gs_match_id,
};
可以查看sc132gs_probe函数,最后通过i2c查找sensor id,返回失败。说明i2c没有通。
2.设备树
1).设备树中添加sensor
设备树文件: /rockchip/sysdrv/source/kernel/arch/arm/boot/dts/rv1103b-evb1-v10.dts
其中sysdrv/source/kernel/arch/arm/boot/dts/rv1103b-evb-cam.dtsi是sensor相关的设备树头文件,所以修改rv1103b-evb-cam.dtsi文件即可。设备树中已经支持了imx415 os04a10......等之前提到过的sensor,所以我们按照原有的设备树添加自己的sensor即可。
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
//... (其他支持的sensor)
//添加sc132gs
csi_dphy_input12: endpoint@c {
reg = <0x0c>;
remote-endpoint = <&sc132gs_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csi_dphy_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi_csi2_input>;
};
};
};
};
&i2c4 {
status = "okay";
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&i2c4m1_xfer_pins>;
//添加sc132gs
sc132gs: sc132gs@30 {
compatible = "smartsens,sc132gs";
status = "okay";
reg = <0x30>;
clocks = <&cru CLK_MIPI0_OUT2IO>;
clock-names = "xvclk";
reset-gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>;
pwdn-gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "rockchip,camera_default", "rockchip,camera_sleep";
pinctrl-0 = <&cam_clk0_pins>;// pinctl setting
pinctrl-1 = <&cam_clk0_sleep_pins>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "default";
rockchip,camera-module-lens-name = "default";
port {
sc132gs_out: endpoint {
remote-endpoint = <&csi_dphy_input1>;
data-lanes = <1 2>;
};
};
};
};
2).部分字段参数解读
1. I2C通信线SDA,SCL
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&i2c4m1_xfer_pins>;
可以查看i2c4m1_xfer_pins定义,在in rv1103b-pinctrl.dtsi文件中
i2c4m1_xfer_pins: i2c4m1-xfer-pins {
rockchip,pins =
/* i2c4_scl_m1 */
<1 RK_PB7 2 &pcfg_pull_none_smt>,
/* i2c4_sda_m1 */
<1 RK_PC0 2 &pcfg_pull_none_smt>;
};
确认RK_PB7和RK_PC0两个引脚是不是SCL,SDA。(硬件发开提供GPIO引脚编号)
2. Sensor在I2C上的通信地址
sc132gs@30 {
compatible = "smartsens,sc132gs";
status = "okay";
reg = <0x30>;
}
sc132gs@30和reg=<0x30>,即sc132gs在i2c上的通信地址。该地址需要查看sc132gs硬件手册,或者在sc132gs的驱动中查看。
可以查到地址为0x60。但根据rv1103b提供的文档中描述"8bits 中的最低位 (LSB) 表示 R/W,高 7bits 即是我们需要的 i2c slave id。",所以根据转换,得到地址为0x30。
3. 时钟频率24MHz
clocks = <&cru CLK_MIPI0_OUT2IO>;
clock-names = "xvclk";
cat /sys/kernel/debug/clk/clk_summary | grep -E "mipi0"可以查看CLK_MIPI0_OUT2I0的频率(24000000)
其次在驱动初始化中power on时会调用ret = clk_set_rate(sc132gs->xvclk, SC132GS_XVCLK_FREQ)设置24MHz。
4. gpio & pinctr
reset-gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>;
pwdn-gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "rockchip,camera_default", "rockchip,camera_sleep";
pinctrl-0 = <&cam_clk0_pins>;// pinctl setting
pinctrl-1 = <&cam_clk0_sleep_pins>;
根据硬件提供的引脚编号,得到reset引脚GPIO1_B6_D,pwdn引脚GPIO1_C1_U。
根据驱动初始化代码,需要获取pinctr中的default和sleep。可以写也可不写,只是加载驱动时会提示not find。如果要写,以下这两个名字要去看sc132gs.c初始化中查找defult和sleep时的匹配字段,要一致。
pinctrl-names = "rockchip,camera_default", "rockchip,camera_sleep";
3.点亮Sensor
1).检查snesor与i2c是否通信
如果insmod sc132gs.ko可以获取Sensor id,或者执行i2cdetect -y 4,如果通信显示如下:(显示UU表示驱动被内核占用,属于正常)
# i2cdetect -y 4
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
表明Sensor和i2c已经连通。
很可惜,我到这一步时并没有点亮。在设备树中已经排除了通信地址不对,时钟频率不对等问题,还有一个可能,就是Sensor未供电。硬件同事帮忙分析,供电三个信号由一个GPIO引脚控制,需要把这个GPIO引脚拉高后才可以供电。引脚号GPIO2_A1。
2).拉GPIO引脚
计算引脚号:GPIO2_A1
# cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 0-31, parent: platform/20520000.gpio, gpio0:
gpio-3 ( |vccio_sd ) out hi
gpio-4 ( |vcc3v3-sd ) out hi ACTIVE LOWgpiochip1: GPIOs 32-63, parent: platform/20d80000.gpio, gpio1:
gpiochip2: GPIOs 64-95, parent: platform/20840000.gpio, gpio2:
gpio-65 ( |sysfs ) out hi
gpio-74 ( |reset ) out lo ACTIVE LOW
GPIO2的范围是64~95,所以GPIO2_A1 = 64 + 1,65 (64是GPIO2_A0)
echo 65 >> /sys/class/gpio/export
echo out >> /sys/class/gpio/gpio65/direction
echo 1 >> /sys/class/gpio/gpio65/value
设置为输出,值为1。
再执行 i2cdetect -y 4,sensor和i2c已连通。
4.抓图测试
1).编译v4l-utils工具
RV1103B默认没有配置v4l-utils,工具提供指令v4l2-ctl和media-ctl。
修改配置media/cfg/cfg.mk,export CONFIG_LIBV4L=y
2).查看摄像头信息
media-ctl -p -d /dev/media0
3).抓图
查看支持格式:v4l2-ctl -d /dev/video7 --list-formats-ext
/# v4l2-ctl -d /dev/video7 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture Multiplanar[0]: 'UYVY' (UYVY 4:2:2)
Size: Stepwise 32x32 - 1080x1280 with step 8/8
[1]: 'NV16' (Y/CbCr 4:2:2)
Size: Stepwise 32x32 - 1080x1280 with step 8/8
[2]: 'NV61' (Y/CrCb 4:2:2)
Size: Stepwise 32x32 - 1080x1280 with step 8/8
[3]: 'NV21' (Y/CrCb 4:2:0)
Size: Stepwise 32x32 - 1080x1280 with step 8/8
[4]: 'NV12' (Y/CbCr 4:2:0)
Size: Stepwise 32x32 - 1080x1280 with step 8/8
[5]: 'NM21' (Y/CrCb 4:2:0 (N-C))
Size: Stepwise 32x32 - 1080x1280 with step 8/8
[6]: 'NM12' (Y/CbCr 4:2:0 (N-C))
Size: Stepwise 32x32 - 1080x1280 with step 8/8
选择NV12格式抓图:
v4l2-ctl -d /dev/video7 --set-fmt-video=width=1080,height=1280,pixelformat=NV12 --stream-mmap --stream-to=frame.raw --stream-count=1
可能遇到问题:抓图指令阻塞,数据流没有到达isp,输出不了图片。根据摄像头修改驱动中的参数。
4).预览图片和手动曝光
需要下载工具可支持预览以上几种格式图片。确认分辨率一致。如果图片一片漆黑,是因为默认曝光很低,可以用手电对着镜头抓图试试。
如需要手动曝光,通过指令v4l2-ctl -d /dev/v4l-subdev2 --list-ctrls查看曝光参数。
其中设备不一定是v4l-subdev2,从video0~video14,v4l-subdev0~v4l-subdev4依次查看。
/# v4l2-ctl -d /dev/v4l-subdev2 --list-ctrls
User Controls
exposure 0x00980911 (int) : min=6 max=2116 step=1 default=328 value=500
Image Source Controls
vertical_blanking 0x009e0901 (int) : min=842 max=64255 step=1 default=842 value=842
horizontal_blanking 0x009e0902 (int) : min=616 max=616 step=1 default=616 value=616 flags=read-only
analogue_gain 0x009e0903 (int) : min=32 max=913 step=1 default=32 value=100Image Processing Controls
link_frequency 0x009f0901 (intmenu): min=0 max=1 default=0 value=0
pixel_rate 0x009f0902 (int64) : min=0 max=90000000 step=1 default=72000000 value=72000000 flags=read-only
test_pattern 0x009f0903 (menu) : min=0 max=4 default=0 value=0
输出类似exposure和anaiogue_gain则是曝光和曝光增益参数。
设置曝光:
v4l2-ctl -d /dev/v4l-subdev2 --set-ctrl exposure=500
设置曝光增益:
v4l2-ctl -d /dev/v4l-subdev2 --set-ctrl analogue_gain=913
如上两条指令设置时,都会调用sc132gs.c驱动中的sc132gs_set_ctrl函数。
2353





