zoukankan      html  css  js  c++  java
  • Camera兼容引起的打开失败问题

    平台:展讯SC7730

    Camera IC:前GC0329后GC0328

    近日,在解决项目BUG的过程中,测试部门有报:下载完版本第一次开机后,第一次和第二次进Camera会出现打开失败的BUG,第三次就可以正常打开了。

    解决思路:

    1、首先是硬件主板电路存在问题,给Camera上电电压不对,但经过示波器测量,发现供给电压(AVDD,IOVDD,DVDD)都是正确的,主板没有问题。

    2、怀疑Camera 没有焊好,重新焊接,此问题还是会复现,说明不是焊接问题。

    3、得出结论:问题出自软件的可能性最大。

    软件解决思路:

    1、首先打log,查看log,看是否能读到Camera的ID,来判断主板是否给Camera上电成功。通过log,看到能正确读到Camera的ID。

      说明Camera需要的几个电压(AVDD,IOVDD,DVDD)都正确配置,之前用示波器测量电压也再次说明主板供电没问题。

    2、是不是兼容出现问题。其它IC引起了GC0328+GC0329的不能正常打开。在sensor_cfg.c里,先临时把兼容的其它IC去掉,后Camera只保留GC0328前只保留  GC0329,经验证发现,此种方法是有效的,不存在前2次打不开Camera问题。

    3、问题就出在了兼容上,问题还是集中在上电函数上,因为尽管电压设置正确,但影响Camera打开的还有PWN和RESET这个两个引脚。而这两个引脚恰恰在上电函  数中进行配置。

    4、首先怀疑PWN设置不对,尝试在Camera打开之前,先把PWN拉高,在sensor_drv_k.c的probe函数里,在申请MAIN Camera和SUB Camera的PWN的GPIO  时,顺便把PWN拉高,发现此种方法没有作用。

    5、回到IC的上电函数,去排查兼容GC0328的前一个IC GC0308的上电函数,POWEROFF的代码,在PWN的设置上没有问题。兼容GC0329的前一个IC GC0309  的上电函数,POWEROFF的代码,在PWN的设置上也没有问题。

    6、期间还尝试了加大上电的延时,看Camera的上电timing等,PWN的设置确实没有什么问题。

    7、这时就开始怀疑Reset引脚,经对比发现GC038和GC0328的对reset引脚的配置函数不一样:

      GC0328:

    Sensor_SetResetLevel((BOOLEAN)!reset_level);

     GC0308:

    Sensor_Reset(reset_level);    

    继续跟踪这两个函数:

    第一个Reset函数:sensor_drv_u.c定义:

    BOOLEAN Sensor_SetResetLevel(BOOLEAN plus_level)
    {
        if (-1 ==_Sensor_Device_ResetLevel((uint32_t)plus_level))
            return SENSOR_FAIL;
    
        return SENSOR_SUCCESS;
    }
    LOCAL int _Sensor_Device_ResetLevel(uint32_t level)
    {
        int ret = SENSOR_SUCCESS;
        SENSOR_DRV_CHECK_ZERO(s_p_sensor_cxt);
    
        ret = xioctl(s_p_sensor_cxt->fd_sensor, SENSOR_IO_RST_LEVEL, &level);
        if (0 != ret)
        {
            CMR_LOGE("_Sensor_Device_Reset failed,  level = %d, ret=%d 
    ", level, ret);
            ret = -1;
        }
    
        return ret;
    }

    最后通过ioctl进入kernel:sensor_drv_k.c

        case SENSOR_IO_RST_LEVEL:
            {
                uint32_t level;
                ret = copy_from_user(&level, (uint32_t *) arg, sizeof(uint32_t));
                if (0 == ret)
                    ret = _sensor_k_set_rst_level(level);
            }
            break;
    LOCAL int _sensor_k_set_rst_level(uint32_t plus_level)
    {
        SENSOR_PRINT("sensor set rst lvl: lvl %d, rst pin %d 
    ", plus_level, GPIO_SENSOR_RESET);
    
        gpio_direction_output(GPIO_SENSOR_RESET, plus_level);
        gpio_set_value(GPIO_SENSOR_RESET, plus_level);
    
    
        return SENSOR_K_SUCCESS;
    }

    而第二个reset函数:

    void Sensor_Reset(uint32_t level)
    {
        int err = 0xff;
        uint32_t rst_val[2];
        SENSOR_IOCTL_FUNC_PTR reset_func;
    
        CMR_LOGI("in.
    ");
        SENSOR_DRV_CHECK_ZERO_VOID(s_p_sensor_cxt);
    
        if (PNULL == s_p_sensor_cxt->sensor_info_ptr) {
            CMR_LOGE("Sensor_SetI2CClock: No sensor info 
    ");
            return;
        }
    
        reset_func = s_p_sensor_cxt->sensor_info_ptr->ioctl_func_tab_ptr->reset;
    
        if (PNULL != reset_func) {
            reset_func(level);
        } else {
            rst_val[0] = level;
            rst_val[1] = s_p_sensor_cxt->sensor_info_ptr->reset_pulse_width;
            if (rst_val[1] < SENSOR_RESET_PULSE_WIDTH_DEFAULT) {
                rst_val[1] = SENSOR_RESET_PULSE_WIDTH_DEFAULT;
            } else if (rst_val[1] > SENSOR_RESET_PULSE_WIDTH_MAX) {
                rst_val[1] = SENSOR_RESET_PULSE_WIDTH_MAX;
            }
            _Sensor_Device_Reset(rst_val); 
        }
        CMR_LOGI("OK out.
    ");
    }
    LOCAL int _Sensor_Device_Reset(uint32_t *reset_val)
    {
        int ret = SENSOR_SUCCESS;
        SENSOR_DRV_CHECK_ZERO(s_p_sensor_cxt);
    
        CMR_LOGI("level %d, width %d",reset_val[0],reset_val[1]);
    
        ret = xioctl(s_p_sensor_cxt->fd_sensor, SENSOR_IO_RST, reset_val);
        if (ret) {
            ret = -1;
        }
    
        return ret;
    }
        case SENSOR_IO_RST:
            {
                uint32_t rst_val[2];
                ret = copy_from_user(rst_val, (uint32_t *) arg, 2*sizeof(uint32_t));
                if (0 == ret)
                    ret = _sensor_k_reset(rst_val[0], rst_val[1]);
            }
            break;
    LOCAL int _sensor_k_reset(uint32_t level, uint32_t width)
    {
        SENSOR_PRINT("SENSOR:_sensor_k_reset, reset_val=%d  camera:%d (0:main 1:sub)
    ",level, _sensor_K_get_curId());
    
        switch (_sensor_K_get_curId()) {
        case SENSOR_MAIN:
        {
            gpio_direction_output(GPIO_SENSOR_RESET, level);
            gpio_set_value(GPIO_SENSOR_RESET, level);
            SLEEP_MS(width);
            gpio_set_value(GPIO_SENSOR_RESET, !level);
            mdelay(1);
            break;
        }
        case SENSOR_SUB:
        {
            gpio_direction_output(GPIO_SUB_SENSOR_RESET, level);
            gpio_set_value(GPIO_SUB_SENSOR_RESET, level);
            SLEEP_MS(width);
            gpio_set_value(GPIO_SUB_SENSOR_RESET, !level);
            mdelay(1);
            break;
        }
        default:
            break;
        }
    
        return SENSOR_K_SUCCESS;
    }
    Sensor_SetResetLevel((BOOLEAN)!reset_level); //就是把reset 设置成想要的高或低
    Sensor_Reset(reset_level);    //反而把reset 设置成相反的高低位了

    问题就是出在

    Sensor_Reset(reset_level);    

    然后把GC0308和GC0329的上电函数里的 (同时检查其它IC GC5004, OV5648都有此问题)

    Sensor_Reset(reset_level);    

    换成 

    Sensor_SetResetLevel(reset_level);

    就解决了此BUG。

    补充:

    今天重新NEW了一个版本,发现上述的改法还是有问题,还是存在下载完版本第一次开机后,第一次和第二次进Camera会出现打开失败的BUG。

    再次进行分析:

    一、发现GC0328的上电函数里,

    Sensor_SetResetLevel((BOOLEAN)!reset_level);

    设置完电压和clk后是把reset拉高(默认是低电平:SENSOR_LOW_PULSE_RESET )。而GC0308 设置完电压和clk后是把reset拉低,设想在identify GC0308

    读ID不对后会有一个 POWEROFF的函数,尝试在POWEROFF里 加一句 把reset拉高 

    Sensor_SetResetLevel((BOOLEAN)!reset_level);

    经验证此方法还是不行。下载完版本后第一次开机,第一次打开Camera还是会失败,但如果下载完版本后第一次开机,不做打开Camera的操作,然后重启手机,

    再open Camera,发现是OK的。

    二、上述操作不行后,既然在POWEROFF函数再进入reset拉高不行,不如在POWERON函数直接把reset拉高,把

    Sensor_SetResetLevel(reset_level);

    直接改成

    Sensor_SetResetLevel((BOOLEAN)!reset_level);

    经验证此方法是可行的。兼容的很多Camera IC的POWERON函数里reset都一个操作方式。

    但这时就有一个疑问:

    最初的 

    Sensor_Reset(reset_level);

    不也是把reset 拉高吗?怎么换个函数就可以了呢?分析可能的原因就是 

    Sensor_SetResetLevel((BOOLEAN)!reset_level);//仅仅对pin的GPIO操作
    Sensor_Reset(reset_level);    //随着平台的升级,这个函数更像是对IC的reset。

     附上GC0308的时序图:

    设置完电压后,reset要拉高。

  • 相关阅读:
    《Three.js 入门指南》3.1.1
    《Three.js 入门指南》3.1.1
    《Three.js 入门指南》3.1.1
    Spring 框架基础(04):AOP切面编程概念,几种实现方式演示
    微服务架构案例(01):项目技术选型简介,架构图解说明
    Java描述设计模式(15):责任链模式
    数据安全管理:RSA加密算法,签名验签流程详解
    Java描述设计模式(14):解释器模式
    SpringBoot2 配置多数据源,整合MybatisPlus增强插件
    SpringBoot2 整合 Drools规则引擎,实现高效的业务规则
  • 原文地址:https://www.cnblogs.com/aceheart/p/3746761.html
Copyright © 2011-2022 走看看