平台:展讯SC7730
Camera IC:前GC0329后GC0328
近日,在解决项目BUG的过程中,测试部门有报:在进入Camera的时候,第一次第二次点击Camera图标都是打开失败(无法连接的相机),第三次就可以正常打开了。
解决思路:
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。