Camera兼容引發的打開失敗問題

平臺:展訊SC7730ide

Camera IC:前GC0329後GC0328函數

近日,在解決項目BUG的過程當中,測試部門有報:下載完版本第一次開機後,第一次和第二次進Camera會出現打開失敗的BUG,第三次就能夠正常打開了。測試

 

解決思路:ui

一、首先是硬件主板電路存在問題,給Camera上電電壓不對,但通過示波器測量,發現供給電壓(AVDD,IOVDD,DVDD)都是正確的,主板沒有問題。spa

二、懷疑Camera 沒有焊好,從新焊接,此問題仍是會復現,說明不是焊接問題。3d

三、得出結論:問題出自軟件的可能性最大。code

 

軟件解決思路:blog

一、首先打log,查看log,看是否能讀到Camera的ID,來判斷主板是否給Camera上電成功。經過log,看到能正確讀到Camera的ID。get

  說明Camera須要的幾個電壓(AVDD,IOVDD,DVDD)都正確配置,以前用示波器測量電壓也再次說明主板供電沒問題。it

二、是否是兼容出現問題。其它IC引發了GC0328+GC0329的不能正常打開。在sensor_cfg.c裏,先臨時把兼容的其它IC去掉,後Camera只保留GC0328前只保留  GC0329,經驗證發現,此種方法是有效的,不存在前2次打不開Camera問題。

三、問題就出在了兼容上,問題仍是集中在上電函數上,由於儘管電壓設置正確,但影響Camera打開的還有PWN和RESET這個兩個引腳。而這兩個引腳偏偏在上電函  數中進行配置。

四、首先懷疑PWN設置不對,嘗試在Camera打開以前,先把PWN拉高,在sensor_drv_k.c的probe函數裏,在申請MAIN Camera和SUB Camera的PWN的GPIO  時,順便把PWN拉高,發現此種方法沒有做用。

五、回到IC的上電函數,去排查兼容GC0328的前一個IC GC0308的上電函數,POWEROFF的代碼,在PWN的設置上沒有問題。兼容GC0329的前一個IC GC0309  的上電函數,POWEROFF的代碼,在PWN的設置上也沒有問題。

六、期間還嘗試了加大上電的延時,看Camera的上電timing等,PWN的設置確實沒有什麼問題。

七、這時就開始懷疑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 \n", 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 \n", 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.\n");
    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 \n");
        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.\n");
}
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)\n",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。

再次進行分析:

1、發現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的。

2、上述操做不行後,既然在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要拉高。

相關文章
相關標籤/搜索