平台:展訊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 \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。
再次進行分析:
一、發現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要拉高。