飞道的博客

记一次和摄像头的摩擦经历

266人阅读  评论(0)

因为时间的原因,这次点亮摄像头的时间特别短,昨天下午模组到公司,今天下午点亮。

几个人一起调试,发现的问题也很多,今天下午发现有一个怀疑的问题,我马上驱车几十公里去模组厂调试,回来的时候,同事已经把摄像头点亮了。时间虽然很短,但是我觉得应该把排查的问题点总结一下,避免下次调试摄像头的时候遇到同样的问题。

也希望大家看了我的文章后,如果遇到调试摄像头相关的工作,可以迎刃而解。

#模组供电电压

  • 模拟供电电源可以理解为里面有ADC转换相关的电路,需要一个基准电压,这个就是模拟电源电压。

  • IOVDD ,这个是I2C通信的GPIO口电压,有的GPIO口电压是3.3V,而摄像头芯片的IOVDD是1.8V,就需要转换电路把电压转换成1.8V。

  • DVDD 是数字电压这个需要按照模组规格书提供正确供电。

这三路电压是供电要求,一定要按照摄像头模组设计要求。

3.3V转1.8V的电路复位脚和PWDN脚电平转换电路

#时钟MCLK

摄像头模组里面是有芯片的,有芯片就需要有时钟,没有时钟的芯片是不能工作的。就好像一个人,没了心跳的话也是不能正常工作的。

时钟这个问题非常关键,我们刚开始有点忽略时钟的问题。实话说,我也很长时间没有调试摄像头了。我2013年在ZTE调过摄像头,到现在也已经很长时间了,经验这个东西还是很有必要的。但是排除经验的话,就是基础的问题了。没有基础的话,根本就不知道其中的原因,只知道需要这个,却不知道为什么需要这个,知所以,但不知所以然。

但是这个时钟是什么时候产生也是很有必要说明的,我跟硬件沟通,这个时钟硬件是直接从CPU连接出来的,中间就加了一个电阻。但是我们开机后还是量不到MCLK。所以这部分应该是软件问题。

从软件流程上可以看出,在开机的时候,我们会打开MCLK,然后去读CHIP ID,如果读到ID,就保持MCLK打开状态,如果读不到,就退出关闭MCLK。所以在开机后去测量MCLK是有可能量不到的。

MCLK在dts里面设置如下


   
  1. gc5025: gc5025@ 37 {
  2. status = "okay";
  3. compatible = "galaxycore,gc5025";
  4. reg = < 0x37>;
  5. clock-frequency = < 400000>;
  6. pinctrl-names = "default";
  7. pinctrl -0 = <&cif_clkout_m0>;
  8. clocks = <&cru SCLK_CIF_OUT>;
  9. clock-names = "xvclk";
  10. avdd-supply = <&vcc2v8_dvp>;
  11. dovdd-supply = <&vcc1v8_dvp>;
  12. dvdd-supply = <&vdd1v2_dvp>;
  13. reset-gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>;
  14. pwdn-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
  15. rockchip,camera-module-index = < 0>;
  16. rockchip,camera-module-facing = "front";
  17. rockchip,camera-module-name = "CMK-CW4191-FG1";
  18. rockchip,camera-module-lens-name = "CK5502";
  19. port {
  20. ucam_out: endpoint {
  21. remote-endpoint = <&mipi_in_ucam>;
  22. data-lanes = < 1 2>;
  23. };
  24. };
  25. };

对应的dts位置


   
  1. cif_clkout_m0: cif-clkout-m0 {
  2. rockchip,pins = < 2 RK_PB3 RK_FUNC_1 &pcfg_pull_none_12ma>; /* cif_clkout */
  3. };

这个GPIO口对应原理图我们开机后会打开MCLK,然后读取CHIP ID。如果读不到呢?就会关闭MCLK。看看代码 获取DTS里面的配置设置MCLK


   
  1. gc5025->xvclk = devm_clk_get(dev, "xvclk");
  2. if (IS_ERR(gc5025->xvclk)) {
  3. dev_err(dev, "Failed to get xvclk\n");
  4. return -EINVAL;
  5. }
  6. ret = clk_set_rate(gc5025->xvclk, GC5025_XVCLK_FREQ);
  7. if (ret < 0) {
  8. dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
  9. return ret;
  10. }
  11. if (clk_get_rate(gc5025->xvclk) != GC5025_XVCLK_FREQ)
  12. dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");

如果没有读到CHIP ID 会进入这里


   
  1. static void __gc5025_power_off( struct gc5025 *gc5025)
  2. {
  3. int ret;
  4. if (!IS_ERR(gc5025->pwdn_gpio))
  5. gpiod_set_value_cansleep(gc5025->pwdn_gpio, 1);
  6. clk_disable_unprepare(gc5025->xvclk);
  7. if (!IS_ERR(gc5025->reset_gpio))
  8. gpiod_set_value_cansleep(gc5025->reset_gpio, 1);
  9. if (!IS_ERR_OR_NULL(gc5025->pins_sleep)) {
  10. ret = pinctrl_select_state(gc5025->pinctrl,
  11. gc5025->pins_sleep);
  12. if (ret < 0)
  13. dev_dbg(&gc5025->client->dev, "could not set pins\n");
  14. }
  15. regulator_bulk_disable(GC5025_NUM_SUPPLIES, gc5025->supplies);
  16. }

里面有一句

clk_disable_unprepare(gc5025->xvclk);

就是用来关闭时钟的。

如果时钟不是问题,那就是其他的问题了,我们开机后,打开时钟,读取CHIP ID,读不到后,就关闭时钟。读不到的原因就应该从其他地方排查了。

#上电时序

上电时序是很重要的,做单片机的同学应该都有调时序的经验。每个芯片都有自己的脾气,有的芯片对时序严格,有的对时序不够严格。但是如果通信不成功。就需要排查这方面的问题。

GC5025要求的上电时序是。三路电开启后,MCLK开启后,需要先拉高PWDN,再拉高reset脚。我们正好在这个问题上做错了。修改后的代码如下

#异常问题

还没调通前,我们摄像头在开机后,我使用命令「如下图」读写I2C寄存器0x37 是手册上写的 GC5025 的器件地址。但是用这个地址是读不出内容的。但是我把器件地址修改成0x24,却能看到应答信号,而且读寄存器都能正常成功。

你们可能想知道我是如何找到这个0x24的,因为我写了一个脚本。


   
  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set /a ii= 3
  4. for /l %%i in ( 1, 1, 116) do (
  5. echo "adb shell i2cget -y -f 2 !ii! 0xf0 w"
  6. adb shell "i2cget -y -f 2 !ii! 0xf0 w"
  7. set /a ii+= 1
  8. )
  9. pause

还有i2c-tools的链接 https://github.com/weiqifa0/i2c-tool

今天去模组厂的一个原因就是因为这个问题,为什么我写0x37的器件地址,芯片没有应答。但是我写0x24的器件地址,芯片有应答信号。这真的是百思不得姐啊。

正常I2C有应答的波形

调通后,我想了下,这个现象刚好说明了。因为没有正常的上电时序,芯片里面也没有正常工作了。而且这个不正常工作还让我怀疑这个芯片是不是坏掉了。

#总结

看看深圳的夜景

  回复「 篮球的大肚子」进入技术群聊

回复「1024」获取1000G学习资料


转载:https://blog.csdn.net/weiqifa0/article/details/104935295
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场