camera调试:RK3588如何点亮一个sensor?

2024-02-26 14:21:42 浏览数 (1)

(1)如何才能算点亮一个sensor?

①sensor的chipID可以通过i2c正确读取到,也就是i2c可以正常通信;

②使用media-ctl工具可以看到pipeline,可以看到sensor具体的分辨率和格式;

③使用V4L2工具抓图没有报错,有正常的数据输出,且使用V4L2的命令可以实现曝光增益等的控制,即可认为驱动没问题;

④xml配置SOC模式下,使用apk可以预览出图(图像可能会偏暗偏绿,后续再讲xml如何配置),到这一步可认为HAL没问题;

⑤自行移植其他sensor的效果文件,可以出图(图像效果可能会有异常,后续再讲如何初步修改效果文件),到这一步接下去就可以开始sensor的效果调试,如果需要找RK调试效果,也必须进行到这一步。

(2)SENSOR_TYPE_RAW和SENSOR_TYPE_SOC:

这是配置给cameraHAL,确认sensor是什么类型。

SENSOR_TYPE_RAW:一般是RAWRGB的sensor,需要turnning 3A效果才能正常出图,需要正确的效果文件路径,才可以使用;

SENSOR_TYPE_SOC:一般是输出YUV或者RGB888/RGB565之类的sensor,不需要跑3A效果,一般用于自带ISP的sensor,不需要效果文件就可以使用;

一般调试RAW sensor过程中,如果使用V4L2已经可以抓图,那么可以先将sensor配置成SENSOR_TYPE_SOC模式,确认不跑3A情况下是否可以出图。

(3)sensor驱动移植

sensor的驱动位于drivers/media/i2c下,sensor驱动和RKCIF、RKISP控制器的驱动独立,二者异步注册,通过v4l2和media-framework框架,将pipeline连接。这里主要介绍一下sensor驱动的代码,dts配置等。sensor驱动主要分为几个部分:

①sensor寄存器配置:

在supported_modes来定义不同的初始化mode,主要配置分辨率、图像格式、帧率、寄存器初始化列表等等,寄存器初始化列表,可直接按照厂家提供的填写。hts_def和vts_def可直接按照寄存器初始化列表填入值即可,exp_def可以看下datesheet是否有默认值,或者一般填写比vts略小。

代码语言:javascript复制
static const struct imx577_mode supported_modes[] = {
 {
  .width = 4056,
  .height = 3040,
  .max_fps = {
   .numerator = 10000,
   .denominator = 300000,
  },
  .exp_def = 0x0c10,
  .hts_def = 0x2318,
  .vts_def = 0x0c2c,
  .bpp = 10,
  .bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10,
  .reg_list = imx577_linear_10bit_4056x3040_30fps_regs,
  .hdr_mode = NO_HDR,
  .link_freq_idx = 1,
  .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
 },

②sensor上电时序:

不同的sensor上电时序不同,有的sensor对时序要求不严格,有的sensor则需要严格按照时序进行上电,否则可能会出现i2c不通的现象。

sensor的datasheet一般都有上电时序图,驱动代码中,按照时序配置即可,imx577上电时序如下,同样的,下电时序也需要按照datasheet描述实现。

代码语言:javascript复制
static int __imx577_power_on(struct imx577 *imx577)
{
 int ret;
 u32 delay_us;
 struct device *dev = &imx577->client->dev;
 
 if (!IS_ERR(imx577->power_gpio))
  gpiod_set_value_cansleep(imx577->power_gpio, 1);
 
 usleep_range(1000, 2000);
 
 if (!IS_ERR_OR_NULL(imx577->pins_default)) {
  ret = pinctrl_select_state(imx577->pinctrl,
        imx577->pins_default);
  if (ret < 0)
   dev_err(dev, "could not set pinsn");
 }
 ret = clk_set_rate(imx577->xvclk, IMX577_XVCLK_FREQ);
 if (ret < 0)
  dev_warn(dev, "Failed to set xvclk rate (24MHz)n");
 if (clk_get_rate(imx577->xvclk) != IMX577_XVCLK_FREQ)
  dev_warn(dev, "xvclk mismatched, modes are based on 24MHzn");
 ret = clk_prepare_enable(imx577->xvclk);
 if (ret < 0) {
  dev_err(dev, "Failed to enable xvclkn");
  return ret;
 }
 if (!IS_ERR(imx577->reset_gpio))
  gpiod_set_value_cansleep(imx577->reset_gpio, 0);
 
 ret = regulator_bulk_enable(IMX577_NUM_SUPPLIES, imx577->supplies);
 if (ret < 0) {
  dev_err(dev, "Failed to enable regulatorsn");
  goto disable_clk;
 }
 
 if (!IS_ERR(imx577->reset_gpio))
  gpiod_set_value_cansleep(imx577->reset_gpio, 1);
 
 usleep_range(500, 1000);
 if (!IS_ERR(imx577->pwdn_gpio))
  gpiod_set_value_cansleep(imx577->pwdn_gpio, 1);
 
 /* 8192 cycles prior to first SCCB transaction */
 delay_us = imx577_cal_delay(8192);
 usleep_range(delay_us, delay_us * 2);
 
 return 0;
 
disable_clk:
 clk_disable_unprepare(imx577->xvclk);
 
 return ret;
}

③v4l2_subdev_ops相关回调函数实现

v4l2_subdev_ops是框架控制sensor驱动的核心,这里介绍一下几个必不可少的回调函数:

  • .s_power,上下电函数,camera上下电的时候会调用这个地方。一般会用到pm_rntime来管理。
  • .ioctl,提供ioctl的接口。
  • s_stream,开关数据流的接口,包括stream on和stream off
  • .enum_mbus_code,枚举驱动支持的图像格式。
  • .enum_frame_size,枚举驱动支持的分辨率
  • .enum_frame_interval,这里除了反馈驱动支持的格式分辨率帧率以外,还有HDR模式的时候,也需要通过fie->reserved[0]成员进行反馈。
  • .get_fmt,获取sensor当前的format
  • .set_fmt,设置sensor的format
  • .get_selection,获取裁减信息
  • .get_mbus_config,获取bus配置,包括mipi/dvp接口,lane数,极性等等。

④V4L2控制:

一般raw sensor需要控制exposure、gain、vblank等等,所以需要实现对应的接口函数

imx577_initialize_controls声明该驱动需要哪些control,并设置调整范围等信息。

imx577_set_ctrl接口,实现对exposure、gain、vblank的控制。

⑤驱动注册入口函数probe:

在驱动注册的函数中,除了对dts的解析,获取时钟电源等等,比较重要的是media entity、V4L2 subdev的注册。关键点如下:

  • v4l2_i2c_subdev_init(),注册为一个 v4l2 subdev,参数中提供回调函数。
  • imx577_initialize_controls 初始化 v4l2 controls。
  • media_entity_init(),注册成为一个 media entity。
  • v4l2_async_register_subdev(),声明 Sensor 需要异步注册。因为 RKISP 及 RKCIF 都采用异步注册Sub Device,所以需要这个调用。

(4)dts配置解析:

代码语言:javascript复制
&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 = <&imx577_out0>;
    data-lanes = <1 2 3 4>;
   };
  };
  port@1 {
   reg = <1>;
   #address-cells = <1>;
   #size-cells = <0>;
 
   csidphy0_out: endpoint@0 {
    reg = <0>;
    remote-endpoint = <&mipi2_csi2_input>;
    data-lanes = <1 2 3 4>;
   };
  };
 };
};
 
&i2c3 {
 status = "okay";
 pinctrl-0 = <&i2c3m0_xfer>;
 
 imx577: imx577@1a {
  compatible = "sony,imx577";
  reg = <0x1a>;
  clocks = <&cru CLK_MIPI_CAMARAOUT_M3>;
  clock-names = "xvclk";
  pinctrl-names = "default";
  pinctrl-0 = <&mipim0_camera3_clk>;
  power-domains = <&power RK3588_PD_VI>;
  pwdn-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
  // reset-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
  // power-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
  avdd-supply = <&vcc_mipicsi0>;
  rockchip,camera-module-index = <0>;
  rockchip,camera-module-facing = "back";
  rockchip,camera-module-name = "default";
  rockchip,camera-module-lens-name = "default";
  port {
   imx577_out0: endpoint {
    remote-endpoint = <&mipi_in_ucam0>;
    data-lanes = <1 2 3 4>;
   };
  };
 };
};
 
&csi2_dphy0_hw {
 status = "okay";
};
 
&mipi2_csi2 {
 status = "okay";
 
 ports {
  #address-cells = <1>;
  #size-cells = <0>;
 
  port@0 {
   reg = <0>;
   #address-cells = <1>;
   #size-cells = <0>;
 
   mipi2_csi2_input: endpoint@1 {
    reg = <1>;
    remote-endpoint = <&csidphy0_out>;
    data-lanes = <1 2 3 4>;
   };
  };
 
  port@1 {
   reg = <1>;
   #address-cells = <1>;
   #size-cells = <0>;
 
   mipi2_csi2_output: endpoint@0 {
    reg = <0>;
    remote-endpoint = <&cif_mipi_in2>;
    data-lanes = <1 2 3 4>;
   };
  };
 };
};
&rkcif {
 status = "okay";
};
&rkcif_mipi_lvds2 {
 status = "okay";
 
 port {
  cif_mipi_in2: endpoint {
   remote-endpoint = <&mipi2_csi2_output>;
  };
 };
};
 
&rkcif_mipi_lvds2_sditf {
 status = "okay";
 
 port {
  mipi_lvds2_sditf: endpoint {
   remote-endpoint = <&isp0_vir0>;
  };
 };
};
 
&rkcif_mmu {
 status = "okay";
};
 
&rkisp0 {
 status = "okay";
 
};
 
&isp0_mmu {
 status = "okay";
};
 
&rkisp0_vir0 {
 status = "okay";
 // rockchip,hw = <&rkisp_unite>;
 
 port {
  #address-cells = <1>;
  #size-cells = <0>;
 
  isp0_vir0: endpoint@0 {
   reg = <0>;
   remote-endpoint = <&mipi_lvds2_sditf>;
  };
 };
};

dts的配置主要是pipeline的配置,可参考RK官方的描述,7路camera对应的配置如下:

(5)驱动调试:

sensor的驱动调试主要有以下关键点:

①移植sensor驱动:参考上述的介绍进行驱动代码的移植;

②根据使用的mipi接口来配置对应的dts,rk3588支持多个camera,因此这个步骤必须正确;

③确认i2c是否通讯成功,i2c通信成功才能正确设置sensor的寄存器;

④media-ctl 工具查看拓扑结构是否正常

⑤使用V4L2抓取图像,设置exp、gain等参数可以生效。

参考:http://t.csdnimg.cn/nsp0h

0 人点赞