1.定时器timer的setup
经常看到vicap数据发生异常时,在rkcif_mipi_lvds节点下面配置该属性rockchip,cif-monitor 来进行检测异常并复位,驱动是在该文件中进行解析设置drivers\media\platform\rockchip\cif\dev.c;该属性需要在dts中配置,是针对1126,3568,3399等平台;3588平台复位机制使能,就不用去修改dts,直接把这个宏定义打开就行ROCKCHIP_CIF_USE_MONITOR;以下以3588平台为例
上面箭头的描述如下,也都在drivers\media\platform\rockchip\cif目录下的Kconfig文件中定义了;这个也就是356x平台中rockchip,cif-monitor里面的参数index0-index4;
当然这些宏定义也可以在rockchip_defconfig文件中进行添加 如下所示
timer定时器相关的3个函数如下:
1.rkcif_reset_watchdog_timer_handler 重置看门狗定时器处理程序
2.rkcif_detect_reset_event 检测复位事件
该函数里面要知道这两个变量last_buf_wakeup_cnt和buf_wake_up_cnt,这个是用来判断数据是否一直走,是否断流用的。所以该函数的实现如下;如果断流的话,buf_wake_up_cnt是不会在增加的,即last_buf_wakeup_cnt = buf_wake_up_cnt;
if (timer->last_buf_wakeup_cnt[stream->id] < stream->buf_wake_up_cnt && check_cnt == 0) {
............
}
else if (timer->last_buf_wakeup_cnt[stream->id] == stream->buf_wake_up_cnt) { //断流了
............
v4l2_info(&dev->v4l2_dev,"do reset work due to frame end is stopped, run_cnt:%d\n", timer->run_cnt);
}
针对监测的三种模式,其中HOTPLUG和CONTINUE模式都是调用is_reset = rkcif_is_csi2_err_trigger_reset(即引起复位的原因),为true的话,则调用rkcif_init_reset_work(timer); 而TRIGGER即协议层的报错处理调用timer->is_csi2_err_occurred;为true的话,则调用rkcif_init_reset_work(timer);
3.rkcif_init_reset_work(timer)函数主要实现如下:
for (i = 0; i < dev->num_channels; i++) {
stream = &dev->stream[i];
if (stream->state == RKCIF_STATE_STREAMING)
timer->last_buf_wakeup_cnt[stream->id] = stream->buf_wake_up_cnt;
}
理解4种监测模式的具体含义,如下表:
2.复位的操作
摄像头开启出流调用rkcif_do_start_stream,然后该函数里面会调rkcif_monitor_reset_event函数;
rkcif_monitor_reset_event 调用rkcif_is_triggered_monitoring,该函数的作用是先判断定时器的监测模式,如果是CONTINUE或HOTPLUG,那么当满足如下条件时,定时器被触发;
if (stream->frame_idx >= timer->triggered_frame_num)
/*triggered_frame_num 这个就是从哪一帧起开始检测,默认为0,
即开启数据流时就开始检测;*/
如果监测模式是TRIGGER,那么就会调用该函数rkcif_is_csi2_err_trigger_reset(timer); 判断两次报错的时间diff_time是否大于等于err_time_interval(发现错误后继续监视的超时,单位(ms)),是的话,定时器触发 is_triggered = true;
if (timer->csi2_err_triggered_cnt >= 1) {
cur_time = ktime_get_ns();
diff_time = cur_time - timer->csi2_first_err_timestamp;
diff_time = div_u64(diff_time, 1000000);
if (diff_time >= timer->err_time_interval) {
is_triggered = true;
v4l2_info(&dev->v4l2_dev, "trigger reset for time out of csi err\n");
goto end_judge;
}
接下来就完成定时器的启动
1.
timer->is_triggered = rkcif_is_triggered_monitoring(dev);
...........
2.
cycle = fps * timer->frm_num_of_monitor_cycle;
timer->cycle = msecs_to_jiffies(cycle);
...........
timer->run_cnt = 0;
timer->is_running = true;
timer->is_buf_stop_update = false;
...........
3.
timer->timer.expires = jiffies + timer->cycle;
mod_timer(&timer->timer, timer->timer.expires);
//启动定时器,不加这句的话,定时器不工作,不会调用rkcif_reset_watchdog_timer_handler。
rkcif_detect_reset_event会调用函数rkcif_init_reset_work
执行工作队列schedule_work(&dev->reset_work.work),去调用
rkcif_reset_work实现复位->rkcif_do_reset_work->rkcif_monitor_reset_event;
在rkcif_do_reset_work中通过ioctl调用sensor驱动的RKMODULE_SET_QUICK_STREAM
ret = v4l2_subdev_call(p->subdevs[i], core, ioctl,RKMODULE_SET_QUICK_STREAM, &on);
cif复位成功后,会打印如下log:
v4l2_dbg(1, rkcif_debug, &cif_dev->v4l2_dev, "do rkcif reset successfully!\n");