0


RK3568驱动OV13850摄像头模组调试过程

  1. 摄像头介绍

  • 品牌:Omnivision

  • 型号:CMK-OV13850

  • 接口:MIPI

像素:1320W

OV13850彩色图像传感器是一款低电压、高性能1/3.06英寸1320万像素CMOS图像传感器,使用OmniBSI+?技术提供了单-1320万像素(4224×3136)摄像头的功能。通过串行摄像头控制总线(SCCB)接口的控制,它提供了全帧、下采样、开窗的10位MIPI图像。

OV13850拥有一个能够在10位1320万像素分辨率下以每秒24帧(fps)的速度运行的图像阵列,用户可以完全控制图像质量、格式和输出数据传输。所有需要的图像处理功能,包括曝光控制、白平衡、缺陷像素消除等,都可以通过SCCB接口进行编程。

此外,OmniBSI图像传感器使用专有的传感器技术,通过减少或消除固定图案噪声、污迹等常见的图像污染光源来提高图像质量,从而产生干净、完全稳定的彩色图像。

为了提供定制信息,OV13850包括一个单编程(OPT)存储器。OV13850拥有最多4车道的MIPI接口。

硬件连接方式如下图:摄像头的I2C接口使用RK3568的I2C4引脚,RESET, PWRDOWN使用普通IO口,三路电源供电使用LDO,LDO由普通IO来控制使能,用于控制上电时序。图像传输接口使用CSI2, 4lan MIPI接口。

  1. RK3568设备树修改

OV13850的设备树修改可以参考其他芯片的设备树,在RK3568 Linux SDK中可以搜索到很多,主要是就是配置OV13850使用的复位控制引脚,I2C通信引脚,PWDNB引脚,三路电源上电控制引脚,CIF_CLK时钟引脚,如下面的I2C部分的设备树,调试OV13850时应首先从I2C调试开始,I2C通了后才会加载MIPI部分的驱动。

  1. &i2c4 {
  2. status = "okay";
  3. clock-frequency = <400000>;
  4. ov13850: ov13850@10 {
  5. compatible = "ovti,ov13850";
  6. status = "okay";
  7. reg = <0x10>;
  8. clocks = <&cru CLK_CIF_OUT>;
  9. clock-names = "xvclk";
  10. power-domains = <&power RK3568_PD_VI>;
  11. pinctrl-names = "rockchip,camera_default","rockchip,camera_sleep";
  12. pinctrl-0 = <&cif_clk>;
  13. pinctrl-1 = <&cam0_sleep_pins>;
  14. //pinctrl-2 = <&cif_clk>;
  15. avdd-supply = <&avdd_2v8_camera_power>; /* 2.8v */
  16. dvdd-supply = <&dvdd_1v2_camera_power>; /* 1.2v */
  17. dovdd-supply = <&dovdd_1v8_camera_power>; /* 1.8v */
  18. /* reset and pwdn */
  19. reset-gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>;
  20. pwdn-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
  21. rockchip,camera-module-index = <0>;
  22. rockchip,camera-module-facing = "back";
  23. rockchip,camera-module-name = "CMK-CT0116";
  24. rockchip,camera-module-lens-name = "Largan-50013A1";
  25. lens-focus = <&vm149c>;
  26. port {
  27. ov13850_out0: endpoint {
  28. remote-endpoint = <&mipi_in_ucam0>;
  29. data-lanes = <1 2 3 4>;
  30. };
  31. };
  32. };
  33. vm149c: vm149c@0c {
  34. compatible = "silicon touch,vm149c";
  35. status = "okay";
  36. reg = <0x0c>;
  37. rockchip,camera-module-index = <0>;
  38. rockchip,camera-module-facing = "back";
  39. rockchip,vcm-start-current = <20>; // 马达的启动电流
  40. rockchip,vcm-rated-current = <80>; // 马达的额定电流
  41. rockchip,vcm-step-mode = <13>; // 马达驱动 ic 的电流输出模式
  42. };
  43. };
  44. /*camera avdd 2.8V LDO poweren*/
  45. avdd_2v8_camera_power:avdd-2v8-camera-regulator {
  46. compatible = "regulator-fixed";
  47. regulator-name = "avdd_2v8_camera_power";
  48. enable-active-high;
  49. gpio = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>;
  50. pinctrl-names = "default";
  51. pinctrl-0 = <&avdd2v8_camera_en_pin>;
  52. //regulator-always-on;
  53. };
  54. /*camera dvdd 1.2V LDO poweren*/
  55. dvdd_1v2_camera_power:dvdd-1v2-camera-regulator {
  56. compatible = "regulator-fixed";
  57. regulator-name = "dvdd_1v2_camera_power";
  58. enable-active-high;
  59. gpio = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
  60. pinctrl-names = "default";
  61. pinctrl-0 = <&dvdd1v2_camera_en_pin>;
  62. //regulator-always-on;
  63. };
  64. /*camera dovdd 1.8V LDO poweren*/
  65. dovdd_1v8_camera_power:dovdd-1v8-camera_regulator {
  66. compatible = "regulator-fixed";
  67. regulator-name = "dovdd_1v8_camera_power";
  68. enable-active-high;
  69. gpio = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>;
  70. pinctrl-names = "default";
  71. pinctrl-0 = <&dovdd1v8_camera_en_pin>;
  72. //regulator-always-on;
  73. };

MIPI部分的设备树可以参考原来开发板上提供的XC7160摄像头来修改,使用full mode ,即4lan CSI2接口,最后修改的如下。

  1. &csi2_dphy_hw {
  2. status = "okay";
  3. };
  4. &csi2_dphy0 {
  5. status = "okay";
  6. ports {
  7. #address-cells = <1>;
  8. #size-cells = <0>;
  9. port@0 {
  10. reg = <0>;
  11. #address-cells = <1>;
  12. #size-cells = <0>;
  13. mipi_in_ucam0: endpoint@0 {
  14. reg = <0>;
  15. remote-endpoint = <&ov13850_out0>;
  16. data-lanes = <1 2 3 4>;
  17. };
  18. };
  19. port@1 {
  20. reg = <1>;
  21. #address-cells = <1>;
  22. #size-cells = <0>;
  23. csidphy_out: endpoint@0 {
  24. reg = <0>;
  25. remote-endpoint = <&isp0_in>;
  26. };
  27. };
  28. };
  29. };
  30. &rkisp_vir0 {
  31. status = "okay";
  32. port {
  33. #address-cells = <1>;
  34. #size-cells = <0>;
  35. isp0_in: endpoint@0 {
  36. reg = <0>;
  37. remote-endpoint = <&csidphy_out>;
  38. };
  39. };
  40. };
  41. &rkisp_vir1 {
  42. status = "disabled";
  43. };
  44. &csi2_dphy1 {
  45. status = "disabled";
  46. /*
  47. * dphy1 only used for split mode,
  48. * can be used concurrently with dphy2
  49. * full mode and split mode are mutually exclusive
  50. */
  51. };
  52. &csi2_dphy2 {
  53. status = "disabled";
  54. /*
  55. * dphy2 only used for split mode,
  56. * can be used concurrently with dphy1
  57. * full mode and split mode are mutually exclusive
  58. */
  59. };
  60. &rkisp {
  61. status = "okay";
  62. };
  63. &rkisp_mmu {
  64. status = "okay";
  65. };

硬件由于是公司第一次做,驱动第一次调,所以调试过程中肯定会遇到问题。果不然,设备树改好后,上电I2C通信不上,即无法使用0x10的地址来识别摄像头。而且识别的摄像头I2C从机地址是0x0b,0x0C,其中0x0C是摄像头内的一个芯片AD5823, 对应的驱动程序就是设备树中的vm149c。

经过使用 sudo i2ctransfer -f -y 4 w2@0x0c 0x30 0x0a r2 读取摄像头ID寄存器0x300A 测试,发现摄像头返回的是0x30 0x0A,总结出来的规律就是读任何寄存器,都返回的是寄存器的地址。

由于一时找不到软件的问题,就让硬件使用示波器测试了一下,三路电源上电的时序是avdd先上,之后是dovdd和dvdd,根据手册上电之间的延时大于0ns即可,如下图。示波器测量显示上电顺序是按照avdd,dovdd,dvdd的顺序,之间的延时为50us, 这个延时就是程序执行先后打开各路电源的运行时间。

之后又测量了I2C的时钟,数据线也未发现问题,测量了一下CIF_CLKOUT信号,这个信号是由RK3568输出给摄像头的,时钟频率是24M,由于摄像头I2C初始读取ID失败后,会关闭电源与时钟,所以24M的时钟只是在初始化时有,一会就没有了。

硬件测试也没有找到问题,那看来还得接着找软件的问题,当然看了不少csdn文章,之后又研究了一下ov13850的驱动程序,ov13850.c,重点看了一下__ov13850_power_on函数,这个函数。

  1. static const char * const ov13850_supply_names[] = {
  2. "avdd", /* Analog power */
  3. "dovdd", /* Digital I/O power */
  4. "dvdd", /* Digital core power */
  5. };
  6. static int __ov13850_power_on(struct ov13850 *ov13850)
  7. {
  8. int ret;
  9. u32 delay_us;
  10. struct device *dev = &ov13850->client->dev;
  11. //硬件设计中摄像头的三路电源全是分别控制的,所以此power_gpio没有引脚对应,也没有设备树
  12. if (!IS_ERR(ov13850->power_gpio))
  13. gpiod_set_value_cansleep(ov13850->power_gpio, 1);
  14. usleep_range(1000, 2000);
  15. //pins_default对应设备树中的cif_clk,用于初始RK3568输出的24M时钟,此程序用于配置时钟引脚的为时钟输出功能
  16. if (!IS_ERR_OR_NULL(ov13850->pins_default)) {
  17. ret = pinctrl_select_state(ov13850->pinctrl,
  18. ov13850->pins_default);
  19. if (ret < 0)
  20. dev_err(dev, "could not set pins\n");
  21. }
  22. //设置xvclk时钟为24M
  23. ret = clk_set_rate(ov13850->xvclk, OV13850_XVCLK_FREQ);
  24. if (ret < 0)
  25. dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
  26. if (clk_get_rate(ov13850->xvclk) != OV13850_XVCLK_FREQ)
  27. dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
  28. ret = clk_prepare_enable(ov13850->xvclk);
  29. if (ret < 0) {
  30. dev_err(dev, "Failed to enable xvclk\n");
  31. return ret;
  32. }
  33. if (!IS_ERR(ov13850->reset_gpio))
  34. //复位信号输出为无效,即如果设备树中reset-gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>,此时输出的电源就是低电平
  35. gpiod_set_value_cansleep(ov13850->reset_gpio, 0);
  36. //打开摄像头供电的三路电源,电源的打开的顺序按照ov13850_supply_names数组中定义的顺序,由于设备树中使用的regulaor来控制电源,所以这部分代码有效
  37. ret = regulator_bulk_enable(OV13850_NUM_SUPPLIES, ov13850->supplies);
  38. if (ret < 0) {
  39. dev_err(dev, "Failed to enable regulators\n");
  40. goto disable_clk;
  41. }
  42. if (!IS_ERR(ov13850->reset_gpio))
  43. //复位信号输出为有效,即如果设备树中reset-gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>,此时输出的电源就是高电平
  44. gpiod_set_value_cansleep(ov13850->reset_gpio, 1);
  45. usleep_range(500, 1000);
  46. if (!IS_ERR(ov13850->pwdn_gpio))
  47. //pwdn_gpio信号输出为有效,即如果设备树中pwdn-gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>,此时输出的电源就是高电平
  48. gpiod_set_value_cansleep(ov13850->pwdn_gpio, 1);
  49. /* 8192 cycles prior to first SCCB transaction */
  50. delay_us = ov13850_cal_delay(8192);
  51. usleep_range(delay_us, delay_us * 2);
  52. return 0;
  53. disable_clk:
  54. clk_disable_unprepare(ov13850->xvclk);
  55. return ret;
  56. }

上面的程序看懂了,下面开始使用万用表来测量reset,pwdn这两个引脚的状态,由于摄像头初始化失败后会进行power_off操作,所以为了测量上电时电平是否正常,把__ov13850_power_off函数中代码关闭,使之一直保持在上电状态。

程序改好后,下载,测量,果然发现pwdn这个信号电平不对,这个信号串联了一个22欧姆的电阻,测量这两个电阻两边的电压一端是0V, 一端是1.8V,电阻坏了,换一个新的,同时检查了一下其他电阻有也坏的,一起更换。换好后,发现电平信号是低电平,电阻两端都是低电平,对着上电时序一下,上电后应该为高电平才对,修改设备树pwdn-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_LOW>; -->pwdn-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;同样对比了一个reset管脚,也是设备树的配置成低电平了。编译程序,开机,摄像头驱动成功加载了,能够识别到摄像头芯片的ID, 加载了视频驱动设备video0-video8, media0。

总结调试遇到的问题,硬件问题与软件问题都有,所以一定要2方面都去查找。硬件问题就是电阻坏了。软件问题是开始设备树写的并不对,先后调整了很多次最后才调试出来的。其他要说的一点就是OV13850驱动程序的reset,pwrdn引脚的有效电平问题与其他芯片驱动的有效电平的意思正好相反,reset信号是在低电平时复位,pwrdn信号是在低电平时有效,所以原来设备树中写成GPIO_ACTIVE_LOW的方式是符合常理的,是驱动程序中把电平的高低有效用反了,实际最应该修改驱动程序ov13850.c中的程序的reset, pwrdn信号的控制电平。

  1. 显示效果

显示效果如下,此时摄像头只能显示天花板上面的灯,其他物体无法成像,只有在强光照射下才能成像,因此还需要做进一步的调试。

  1. 特别鸣谢

在调试摄像头的过程中,参考了很多csdn朋友写的文章,感谢各位的分享,我也以分享的方式回馈大家。具体参考链接如下:

RK3566调试GC2053_火柴棍mcu的博客-CSDN博客

(24条消息) 摄像头ov13850移植笔记_布道师Peter的博客-CSDN博客

(7条消息) 关于RK3399平台OV13850摄像头调试的问题_ov13850摄像头好吗_溯之源的博客-CSDN博客


本文转载自: https://blog.csdn.net/fhqlongteng/article/details/129366781
版权归原作者 fhqlongteng 所有, 如有侵权,请联系我们删除。

“RK3568驱动OV13850摄像头模组调试过程”的评论:

还没有评论