瑞芯微Rockchip开发者社区
直播中

韩刚龙

7年用户 1011经验值
私信 关注
[经验]

RK平台5640 camera预览界面帧率过低是什么原因

hal 层

/hardware/rockchip/camera
├── AAL Android Abstraction Layer, 负责与 framework 交互
├── common 公用文件,如线程,消息处理,Log 打印等实现
├── etc 配置文件目录
├── include Control loop 的头文件,buffer_manager 相关头文件
├── lib 3a engine 相关库
├── psl Physical Layer,物理实现层,所有的实现逻辑基本都在这里
│ └── rkisp1 目前只有 Rkisp1 一套实现方案
│ ├── tasks 基本只用到了里面的几个 Notify 的接口类和 JpegEncodeTask
│ └── workers 数据的获取处理都在这里

Driver层:
Linux Kernel-4.4:
|
|arch/arm64/boot/dts/rockchip DTS 配置文件
|phy/rockchip/phy-rockchip-mipi-rx.c mipi dphy 驱动,独立于 cif 驱动
|drivers/media
|
|platform/rockchip/cif
|── capture.c RKCIF 驱动 主要完成硬件配置,v4l2、vb2 框架下的相关回调,帧中断处理
|── dev.c 主要完成 probe,sub-device 异步(Async)注册,
iommu 及 clk 管理
|── dev.h 驱动相关结构体定义
|── regs.h 寄存器宏定义
|i2c/ Camera Sensor 驱动

打开前摄配置:

device/rockchip/common/device.mk
device/rockchip/common/device_tab10_rk66.mk
hardware/rockchip/camera/etc/camera/camera3_profiles_rk356x.xml

替换文件命令:

adb push camera3_profiles_rk356x.xml /vendor/etc/camera/camera3_profiles.xml
adb push camera3_profiles_rk356x.xml /vendor/etc/camera/

打开hal和driver相关debug log:
adb shell
setprop persist.vendor.camera.hal.debug 5 && echo 1 > /sys/module/video_rkcif/parameters/debug && echo 1 > /sys/module/video_rkisp1/parameters/debug
adb reboot

hal层向驱动下发的分辨率及帧率,是正常的,driver层设置给Sensor的也是30帧。log如下:

04-18 22:21:36.168 0 0 I ov5640 2-003c: ov5640_s_stream: on: 1, 800x600@30

kernal/drivers/media/i2c/ov5640.c:1383

static int ov5640_s_stream(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov5640 ov5640 = to_ov5640(sd);
int ret = 0;
dev_info(&client->dev, "%s: on: %d, %dx%d@%d\n", func, on,
ov5640->frame_size->width,
ov5640->frame_size->height,
ov5640->frame_size->fps);
mutex_lock(&ov5640->lock);
on = !!on;
if (ov5640->streaming == on)
goto unlock;
if (!on) {
/
Stop Streaming Sequence */
ov5640_set_streaming(ov5640, on);
ov5640->streaming = on;
goto unlock;
}
ret = ov5640_write_array(client, ov5640->frame_size->regs);
if (ret)
goto unlock;
ov5640_set_streaming(ov5640, on);
ov5640->streaming = on;
unlock:
mutex_unlock(&ov5640->lock);
return ret;
}

但是实际只有不到15帧,帧率减半。

04-18 22:21:55.858 336 2043 I RkCamera: Stream: showDebugFPS: Preview FPS : 14.2126: mFrameCount=281
04-18 22:21:56.900 336 2043 I RkCamera: Stream: showDebugFPS: Preview FPS : 14.3890: mFrameCount=296

疑点1怀疑是否是单帧模式,查询RK相关问题,发现在单帧(单buffer)模式下最高只有15帧。

/rk3566/tab10-rk66-gms/kernel/drivers/media$ grep -nr RKCIF_WORKMODE_PINGPONG
platform/rockchip/cif/dev.h:86: RKCIF_WORKMODE_PINGPONG = 0x01,
platform/rockchip/cif/procfs.c:225: dev->workmode == RKCIF_WORKMODE_PINGPONG ? “ping pong” : “line loop”);
添加如下log验证,是否走到pingpong,双buffer模式的方法。
/kernel/drivers/media/drivers/media/platform/rockchip/cif/capture.c添加log:

static void rkcif_assign_new_buffer_pingpong(struct rkcif_stream *stream,
int init, int channel_id)
{

  • struct rkcif_device *dev = stream->cifdev;
    
  • v4l2_info(&dev->v4l2_dev,"rkcif_assign_new_buffer_pingpong!\n");
      if (init)
              rkcif_assign_new_buffer_init(stream, channel_id);
    

可以发现使用的是双buffer模式,dmesg log如下:

[ 766.474865] ov5640 2-003c: ov5640_s_stream: on: 1, 800x600@30
[ 766.499639] ov5640 2-003c: ov5640_set_streaming: on: 1
[ 766.500305] rkcif_dvp: set dual edge mode(off,0x2000000)!!!
[ 766.500337] rkcif_dvp: rkcif_assign_new_buffer_pingpong!
[ 766.545358] rkcif_dvp: rkcif_irq_pingpong!
[ 766.610300] rkcif_dvp: rkcif_irq_pingpong!
[ 766.610345] rkcif_dvp: rkcif_assign_new_buffer_pingpong!

疑点2 跟 MCLK 有关

逻辑上 Sensor 输出的帧率只跟写入 OV5640的寄存器配置一样,驱动及配置一样的话,帧率应该一样的,分析可能跟 MCLK 有关。

在xxxx_power_on 或 xxxx_s_power 中重新设置 clk,
/kernel/drivers/media/i2c/ov5640.c

ret = clk_set_rate(ov5640->xvclk, OV5640_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(ov5640->xvclk) != OV5640_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(ov5640->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}

经验证仅仅添加如上代码验证失败。

将OV5640_XVCLK_FREQ设置为27000000后帧率提高到16.5帧
/kernel/drivers/media/i2c/ov5640.c
#define OV5640_XVCLK_FREQ 27000000
于是考虑提高时钟频率,查看ov5640文档:

24Mzh时钟倍频寄存器0x3036的值 0x21增加为0x69(10进制:105)后帧率提高到24帧。

kernel/drivers/media/i2c/ov5640.c

[url=home.php?mod=space&uid=1999721]@@[/url] -142,8 +142,8 @@ static const struct sensor_register ov5640_dvp_init_regs[] = {
{0x3017, 0xff},
{0x3018, 0xff},
{0x3034, 0x1a},

  • {0x3036, 0x46},
    
  • {0x3036, 0x69},
      {0x3037, 0x13},
      {0x3108, 0x01},
      {0x3630, 0x36},
    

@@ -426,8 +426,8 @@ static const struct sensor_register ov5640_dvp_init_regs[] = {
{0x4004, 0x02},
{0x3002, 0x1c},
{0x4713, 0x03},

  • {0x3035, 0x21},
    
  • {0x3036, 0x46},
    
  • {0x3035, 0x11},
    
  • {0x3036, 0x69},
      {0x4837, 0x22},
      {0x3824, 0x02},
      {0x5001, 0xa3},
    

@@ -518,8 +518,8 @@ static const struct sensor_register ov5640_dvp_svga_30fps[] = {
{0x4004, 0x02},
{0x3002, 0x1c},
{0x4713, 0x03},

  • {0x3036, 0x46},
    
  • {0x3036, 0x69},
      {0x4837, 0x22},
      {0x3824, 0x02},
      {0x5001, 0xa3},
    

@@ -1644,6 +1644,18 @@ static int ov5640_power(struct v4l2_subdev *sd, int on)
usleep_range(2000, 5000);
}
}

  • ret = clk_set_rate(ov5640->xvclk, OV5640_XVCLK_FREQ);
    
  • if (ret < 0) {
    
  • dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
    
  • return ret;
    
  • }
    
  • if (clk_get_rate(ov5640->xvclk) != OV5640_XVCLK_FREQ)
    
  • dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
    
  • ret = clk_prepare_enable(ov5640->xvclk);
    
  • if (ret < 0) {
    
  • dev_err(dev, "Failed to enable xvclk\n");
    
  • return ret;
    
  • }
      return 0;
    

}

将寄存器{0x3035, 0x21}改为{0x3035, 0x11}后,预览几秒中会出现dvp overflow err错误,应该是时钟太快导致。

[ 1471.425173] rkcif_dvp: ERROR: DVP_ALL_ERROR_INTEN:0xa!!
[ 1471.425206] rkcif_dvp: dvp pix err
[ 1471.425211] rkcif_dvp: ERROR: DVP_ALL_ERROR_INTEN:0x40a!!
[ 1471.425220] rkcif_dvp: dvp overflow err
[ 1471.425225] rkcif_dvp: ERROR: DVP_ALL_ERROR_INTEN:0x420!!
[ 1471.425391] rkcif_dvp: dvp pix err
[ 1471.425401] rkcif_dvp: ERROR: DVP_ALL_ERROR_INTEN:0x40a!!

24Mzh时钟倍频寄存器0x3036 0x21增加为0x7d (10进制:125)后,帧率提高到26.5帧,显示正常。

24Mzh时钟倍频寄存器0x3036 0x21增加为0x84 (10进制:132)后,预览几秒后花屏,帧率达到26.9。

24Mzh时钟倍频寄存器0x3036 0x21增加为0x8c(10进制:140)后,帧率预览几秒后花屏,帧率达到28.6。

于是设置为0x7d ,26.5帧这个结果暂时满足GMS认证需求。

在1.0.6 版本时,前摄主要报出的fail项主要是帧率过低相关,
将帧率提升到26.5帧,目前重测pass的cts有:

android.hardware.cts.CameraGLTest pass
android.hardware.cts.CameraTest#testPreviewFpsRange pass
android.camera.cts android.hardware.camera2.cts.RecordingTest pass

driver修改分辨率1296×968 如下

@@ -492,10 +492,10 @@ static const struct sensor_register ov5640_dvp_svga_30fps[] = {
{0x3803, 0x04},
{0x3806, 0x07},///
{0x3807, 0x9b},

  • {0x3808, 0x03},
    
  • {0x3809, 0x20},
    
  • {0x380a, 0x02},
    
  • {0x380b, 0x58},
    
  • {0x3808, 0x05},
    
  • {0x3809, 0x10},
    
  • {0x380a, 0x03},
    
  • {0x380b, 0xc8},
      {0x380c, 0x07},
      {0x380d, 0x68},
      {0x380e, 0x04},//0x03
    

@@ -519,7 +519,7 @@ static const struct sensor_register ov5640_dvp_svga_30fps[] = {
{0x3002, 0x1c},
{0x4713, 0x03},
{0x3035, 0x21},

  • {0x3036, 0x46},
    
  • {0x3036, 0x84},
      {0x4837, 0x22},
      {0x3824, 0x02},
      {0x5001, 0xa3},
    

@@ -1022,8 +1022,8 @@ static const struct sensor_register ov5640_mipi_full[] = {

static const struct ov5640_framesize ov5640_dvp_framesizes[] = {
{ /* SVGA */

  • .width          = 800,
    
  • .height         = 600,
    
  • .width          = 1296,
    
  • .height         = 968,
    

原作者:小陈博客

更多回帖

发帖
×
20
完善资料,
赚取积分