MTK pdaf bring up

一、开发环境

平台:mt6833

主摄sensor: s5kjn1sq

模组厂:qtech

马达:dw9800

二、前期准备工作

  1. 在MOL上download 官方bring up文档,01_02_Driver_Check-PDAF_Driver_Porting_Guide_release_V1.4.pdf(最新).
  2. 问模组厂提供.ini文档,该文档记录了pdaf的相关参数,我们参考该文档配置sensor驱动
  3. OTP map,需要确认otp烧录了af和pdaf的数据
  4. 问sensor原厂提供pdaf PDMAP guide文档,该文档记录了PD Tail数据的存储格式,后续做pd buf的L,R分离时需要参考该文档
  5. pd_s5kjn1sqmipiraw.cpp文件,如果有现成的就问供应商拿现成的,如果没有则需要自己coding

三、前期需确认事项

1. 确认af是正常工作的,找相关bringup人员确认或在main log中搜索关键字"MoveLensTo"

image.png

2. 确认otp数据读取正常,日志搜索关键字"CamCalCamCal"

09-08 03:39:48.696 12049 31376 D CamCalCamCal: ver0923 ======================AWB CAM_CAL==================
09-08 03:39:48.696 12049 31376 D CamCalHelper: CamCalHelper Read data from memory[0]
09-08 03:39:48.696 12049 31413 D IspDrv_CAM: IspDrv_CAM[CQ_Allocate_method1] [0x0][21_0]:virtIspAddr:virt[0x79eb9e3000]/phy[0x2fcb90000]
09-08 03:39:48.696 12049 31376 D CamCalHelper: CamCalHelper Read data from memory[0]
09-08 03:39:48.696 12049 31414 D awb_mgr : [AWBInit()][AI NVRAM] AISAindex(0) revision(0) enable(0) , AIMAindex(0) revision(0) enable(0) [AWB NVRAM] index(1), SEGenable(0) SEGisothr(0) SEGcnt(0), E2Eenable(0) E2Eisothr(0) E2Ecnt(0)
09-08 03:39:48.696 12049 31376 D CamCalCamCal: ver0923 ======================AF CAM_CAL==================
09-08 03:39:48.696 12049 31376 D CamCalCamCal: ver0923 [AF] Inf=488 Marco=758
09-08 03:39:48.696 12049 31376 D CamCalCamCal: ver0923 ======================AF CAM_CAL==================

pdaf的数据我们需要看解析后的数据,porting的时候确认,需要确保pdaf是support状态,然后搜索关键字"parseStep3"


image.png

确保otp数据跟模组厂提供的ini文档中的参数应该是一致的。

3. 找sensor vendor确认pdaf type


image.png

4. 确认mirror filp

1.确认模组厂ini文档中烧录坐标点是否mirrorfilp

2. 确认preview(pdaf的使用场景)出图的mirrorflip

如果preview方向与模组厂烧录方向一致,则imgsensor_pd_info.iMirrorFlip = 0,如果preview方向为mirrorflip,模组厂烧录方向为normal,则imgsensor_pd_info.iMirrorFlip = 3,这块最好找供应商确认。

四、对应pd type走官方文档porting工作

五、debug问题

1.检索关键字"SensorModeSupport("

image.png

发现BufType为0(NOTDEF),需要走查代码vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/isp_6s/af_assist_mgr/af_assist_mgr.cpp的AFAssisMgr::config实现:

image.png

看实际走了哪条else分支导致的BufType为0,

如果打印"Instance is not ready"表示pd_s5kjn1sqmipiraw.cpp中IsSupport函数返回值为false

如果打印"set PD calibration and tuning data fail"表示未成功设置好校准数据,可能是由于otp未导通

2. pd_s5kjn1sqmipiraw.cpp文件中ConvertPDBufFormat修改。当camsv收到sensor传输过来的tail数据后,经过ConvertPDBufFormat函数转换,生成一张pd L,R组成的raw图。

抓取转换后的图片如下:


image.png
image.png

转换后的图像上下应该是亮度一致,并且图案相同的。拍摄的pd图并不是跟原图案一样的,会有拉伸效果,因为pd的tail数据只是部分raw点,如上图,单看L的tail点,X方向是每2个像素取一个pd点,Y方向上是每8个像素取一个pd点,所以pd tail buf可看作是部分typical pixel组成的图,由于XY方向取点数量不同,会造成图像有拉伸的效果,这是正常的。

MUINT16* PD_S5KJN1SQMIPIRAW::ConvertPDBufFormat( MUINT32 /*i4Size*/, MUINT32 i4Stride, MUINT8 *ptrBufAddr, MUINT32 u4BitDepth, PD_AREA_T* /*ptrPDRegion*/)
{
if (m_eBufType == EPDBUF_VC) {
MUINT32 xSz = m_PDXSz ; // pixel
MUINT32 ySz = m_PDYSz ; // line
MUINT16 **ptr = NULL;
MUINT16 *ptrL = m_PDBuf;
MUINT16 *ptrR =m_PDBuf + m_PDBufSz/2 ;
MUINT32 xSzInByte = xSz * 10 / 8;
MUINT32 i, j;

AAA_LOGE("----------------------k19a------ConvertPDBufFormat------");

#if NEON_OPT
MUINT8 ucTbl0[5][8] = { { 4,0,1,2,3,5,6,7 },{ 0,1,6,2,3,4,5,7 },{ 0,1,2,3,4,5,6,7 },{ 1,2,3,4,0,5,6,7 },{ 0,1,3,4,5,6,2,7 } };
MUINT8 ucTbl1[2][8] = { { 0,9,10,19,0xFF,0xFF,0xFF,0xFF } ,{ 0xFF,0xFF,0xFF,0xFF,4,5,14,15 } };
MUINT8 ucTblShfit[16] = { 6,4,2,0, 6,4,2,0, 6,4,2,0, 6,4,2,0 };

uint8x8_t vu1x8Tbl0_0 = vld1_u8(ucTbl0[0]);
uint8x8_t vu1x8Tbl0_1 = vld1_u8(ucTbl0[1]);
uint8x8_t vu1x8Tbl0_3 = vld1_u8(ucTbl0[3]);
uint8x8_t vu1x8Tbl0_4 = vld1_u8(ucTbl0[4]);

uint8x8_t vu1x8Tbl1_0 = vld1_u8(ucTbl1[0]);
uint8x8_t vu1x8Tbl1_1 = vld1_u8(ucTbl1[1]);

uint8x16_t vu1x16TblShift = vld1q_u8(ucTblShfit);
#endif

for( j=0; j<ySz; j++)
{
MUINT32 idx = j * i4Stride;//Stride=width from raw file

if (j % 2 == 1)
ptr = &ptrL;
else
ptr = &ptrR;
i = 0;
#if NEON_OPT
unsigned char *ptr_src = (unsigned char *)(ptrBufAddr + idx);

uint8x8x3_t vu1x8x3Buf0;
uint8x8x2_t vu1x8x2Buf1, vu1x8x2TmpBuf;
uint8x8_t vu1x8LL, vu1x8LH, vu1x8HL, vu1x8HH, vu1x8LSB;
uint16x8_t vu2x8x1Buf3;
uint16x8_t vu2x8x1Buf4;

//uint16x8x2_t vu2x8x2Buf5;

uint8x16_t vu1x16Low2BitL, vu1x16Low2BitH;

for (; i <= xSzInByte - 40; i += 40, (*ptr) += 32, ptr_src += 40)
{
//if(j == 0)
// AAA_LOGD("ConvertPDBufFormat with neon");

//Step.1 Loading data from memory to register
vu1x8x3Buf0.val[0] = vld1_u8(ptr_src); //[M0 0, N0 1, M1 2, N1 3, D01 4, M2 5, N2 6, M3 7]
vu1x8x3Buf0.val[1] = vld1_u8(ptr_src + 8); //[N3 8, D23 9, M4 10, N4 11, M5 12, N5 13, D45 14, M6 15]
vu1x8x3Buf0.val[2] = vld1_u8(ptr_src + 16); //[N6 16, M7 17, N7 18, D67 19, M8 20, N8 21, M9 22, N9 23]
vu1x8x2Buf1.val[0] = vld1_u8(ptr_src + 24); //[D89 24, M10 25, N10 26, M11 27, N11 28, D1011 29, M12 30, N12 31]
vu1x8x2Buf1.val[1] = vld1_u8(ptr_src + 32); //[M13 32, N13 33, D1213 34, M14 35, N14 36, M15 37, N15 38, D1415 39]

vu1x8x3Buf0.val[0] = vtbl1_u8(vu1x8x3Buf0.val[0], vu1x8Tbl0_0); //[D01 4, 0, 1, 2, 3, 5, 6, 7]
vu1x8x3Buf0.val[1] = vtbl1_u8(vu1x8x3Buf0.val[1], vu1x8Tbl0_1); //[ 8,D23 9,D45 14, 10, 11, 12, 13, 15]
//vu1x8x3Buf0.val[2] [ 16, 17, 18,D67 19, 20, 21, 22, 23]
vu1x8x2Buf1.val[0] = vtbl1_u8(vu1x8x2Buf1.val[0], vu1x8Tbl0_3); //[ 25, 26, 27, 28,D89 24,D1011 29, 30, 31]
vu1x8x2Buf1.val[1] = vtbl1_u8(vu1x8x2Buf1.val[1], vu1x8Tbl0_4); //[ 32, 33, 35, 36, 37, 38,D1213 34,D1415 39]

//Step.2 Separate the upper 8-bit data
vu1x8LL = vext_u8(vu1x8x3Buf0.val[0], vu1x8x3Buf0.val[1], 1); //[M0 0,N0 1,M1 2,N1 3,M2 5,N2 6,M3 7,N3 8]
vu1x8LH = vext_u8(vu1x8x3Buf0.val[1], vu1x8x3Buf0.val[2], 3); //[M4 10,N4 11,M5 12,N5 13,M6 15,N6 16,M7 17,N7 18]
vu1x8HL = vext_u8(vu1x8x3Buf0.val[2], vu1x8x2Buf1.val[0], 4); //[M8 20,N8 21,M9 22,N9 23,M10 25,N10 26,M11 27,N11 28]
vu1x8HH = vext_u8(vu1x8x2Buf1.val[0], vu1x8x2Buf1.val[1], 6); //[M12 30,N12 31,M13 32,N13 33,M14 35,N14 36,M15 37,N15 38]

//Step.3 Separate the lower 2-bit data
// [4,9,14,19, 24,29,34,39] == [D01,D23,D45,D67,D89,D1011,D1213,D1415]
vu1x8LSB = vorr_u8(vtbl3_u8(vu1x8x3Buf0, vu1x8Tbl1_0), vtbl2_u8(vu1x8x2Buf1, vu1x8Tbl1_1));
// [D01,D23,D45,D67,D89,D1011,D1213,D1415] => val[0]: [D01,D01, D23,D23, D45,D45, D67,D67], val[1]: [D89,D89, D1011,D1011, D1213,D1213, D1415,D1415]
vu1x8x2Buf1 = vzip_u8(vu1x8LSB, vu1x8LSB);

// Low: [D01,D01, D23,D23, D45,D45, D67,D67]
// => val[0]: [D01,D01,D01,D01, D23,D23,D23,D23], val[1]: [D45,D45,D45,D45, D67,D67,D67,D67]
vu1x8x2TmpBuf = vzip_u8(vu1x8x2Buf1.val[0], vu1x8x2Buf1.val[0]);
// [(D01<<6)>>6, (D01<<4)>>6, (D01<<2)>>6, (D01<<0)>>6, (D23<<6)>>6 ,(D23<<4)>>6,(D23<<2)>>6,(D23<<0)>>6,
// (D45<<6)>>6, (D45<<4)>>6, (D45<<2)>>6, (D45<<0)>>6, (D67<<6)>>6 ,(D67<<4)>>6,(D67<<2)>>6,(D67<<0)>>6]
vu1x16Low2BitL = vshrq_n_u8(vshlq_u8(vcombine_u8(vu1x8x2TmpBuf.val[0], vu1x8x2TmpBuf.val[1]), vu1x16TblShift), 6);

// High: [D89,D89, D1011,D1011, D1213,D1213, D1415,D1415]
// Same as low
vu1x8x2TmpBuf = vzip_u8(vu1x8x2Buf1.val[1], vu1x8x2Buf1.val[1]);
vu1x16Low2BitH = vshrq_n_u8(vshlq_u8(vcombine_u8(vu1x8x2TmpBuf.val[0], vu1x8x2TmpBuf.val[1]), vu1x16TblShift), 6);

//Step.4 upper 8-bit data + lower 2-bit data
vu2x8x1Buf3 = vorrq_u16(vshlq_n_u16(vmovl_u8(vu1x8LL), 2), vmovl_u8(vget_low_u8(vu1x16Low2BitL))); //[M0,N0,M1,N1,M2,N2,M3,N3]
vu2x8x1Buf4 = vorrq_u16(vshlq_n_u16(vmovl_u8(vu1x8LH), 2), vmovl_u8(vget_high_u8(vu1x16Low2BitL))); //[M4,N4,M5,N5,M6,N6,M7,N7]

// unzip MNMNMNMN data => val[0]: [M0,M1,M2,M3,M4,M5,M6,M7] val[1]: [N0,N1,N2,N3,N4,N5,N6,N7]
//vu2x8x2Buf5 = vuzpq_u16(vu2x8x1Buf3, vu2x8x1Buf4);

vst1q_u16((*ptr), vu2x8x1Buf3);
vst1q_u16((*ptr) + 8, vu2x8x1Buf4);

vu2x8x1Buf3 = vorrq_u16(vshlq_n_u16(vmovl_u8(vu1x8HL), 2), vmovl_u8(vget_low_u8(vu1x16Low2BitH))); //[M8,N8,M9,N9,M10,N10,M11,N11]
vu2x8x1Buf4 = vorrq_u16(vshlq_n_u16(vmovl_u8(vu1x8HH), 2), vmovl_u8(vget_high_u8(vu1x16Low2BitH)));//[M12,N12,M13,N13,M14,N14,M15,N15]

// unzip MNMNMNMN data => val[0]: [M8,M9,M10,M11,M12,M13,M14,M15] val[1]: [N8,N9,N10,N11,N12,N13,N14,N15]
//vu2x8x2Buf5 = vuzpq_u16(vu2x8x1Buf3, vu2x8x1Buf4);

vst1q_u16((*ptr) + 16, vu2x8x1Buf3);
vst1q_u16((*ptr) + 24, vu2x8x1Buf4);
}
#endif
for(;i<xSzInByte;i+=5)
{
char val0 = ptrBufAddr[ idx + (i )];
char val1 = ptrBufAddr[ idx + (i+1)];
char val2 = ptrBufAddr[ idx + (i+2)];
char val3 = ptrBufAddr[ idx + (i+3)];
char val4 = ptrBufAddr[ idx + (i+4)];

if(j%2==1)
{
*ptrL++ =((val0 << 2)&0x3FC) | ((val4 >> 0) & 0x3);
*ptrL++ =((val1 << 2)&0x3FC) | ((val4 >> 2) & 0x3);
*ptrL++ =((val2 << 2)&0x3FC) | ((val4 >> 4) & 0x3);
*ptrL++ =((val3 << 2)&0x3FC) | ((val4 >> 6) & 0x3);
}
else
{
*ptrR++ =((val0 << 2)&0x3FC) | ((val4 >> 0) & 0x3);
*ptrR++ =((val1 << 2)&0x3FC) | ((val4 >> 2) & 0x3);
*ptrR++ =((val2 << 2)&0x3FC) | ((val4 >> 4) & 0x3);
*ptrR++ =((val3 << 2)&0x3FC) | ((val4 >> 6) & 0x3);
}
}
}
//ALOGD("m_PDBufSz %d, Stride %d\n", m_PDBufSz, i4Stride);
}
else
{
m_PDBuf = NULL;
}
return m_PDBuf;
}

NEON_OPT宏开启后有节省功耗的作用,为便于分析,可以只看NEON_OPT未定义情况。函数的主要功能有两个,一个是将原始的raw数据由原先的10bit存储转换为2byte存储,第二个是将L跟R的buf分开存储,需要注意的是DT=0x2b时L在前R在后,DT/=0x2b时R在前L在后。

image.png

ptrBufAddr即是tail数据的buffer地址,mode3下,sensor输出binning的预览数据,vc传输tail数据,所以tail数据的提取已经在sensor端做好了。

image.png

i4Stride表示tail一行数据的字节数,因为存在字节对齐,所以实际存储长度比xSzInByte大,buffer的偏移量计算应以实际为准。

image.png

3.曲线拉取线性度异常

拉取曲线步骤:

1.下载好菱形图并打印

2. 下载录入数据的表格

3. 读取otp中af的远近焦值,得出镜头手动停留的位置

4. 按指令跑一遍fullscan,然后求peak平均值

5. 再手动推动镜头到上述计算位置,抓取日志

6. 搜索关键字”handleAFS“

image.png

依次录入block0-8的数据,算法将图像分割为九块区域,分别计算相位差值,录入pd值需要*1000.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • 前言 OTP加载是摄像头驱动开发中必不可少的一部分,初学者可能会觉得这一概念晦涩难懂,或者不知道其具体用途,本章节...
    窝窝蜗牛阅读 6,338评论 0 5
  • 系列文章【Camera专题】Qcom-你应该掌握的Camera调试技巧1[https://www.jianshu....
    c枫_撸码的日子阅读 3,812评论 0 5
  • OTP数据的获取方式可参数模组厂提供的OTPguide OTP数据的存储位置1)otp数据如果不大,为了节省成本,...
    窝窝蜗牛阅读 1,966评论 0 0
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,520评论 28 53
  • 首先介绍下自己的背景: 我11年左右入市到现在,也差不多有4年时间,看过一些关于股票投资的书籍,对于巴菲特等股神的...
    瞎投资阅读 5,656评论 3 8