(1)从sample入手,开始分析代码调用流程,将sample文件夹以及下图中的两个文件夹通过sourceinsight软件建立工程,分析代码
(2)sensor层驱动在component/isp中(Hi3518E_SDK_V1.0.3.0/mpp/component/isp/sensor)
(3)底层i2c驱动在kernel中
(1)mpp定义了一套sensor驱动的实现和封装
main 主函数
SAMPLE_VENC_1080P_CLASSIC 视频采集函数
SAMPLE_COMM_VI_StartVi(step3) 开启视频视频输入设备并进行采集
IsSensorInput 判断是否传统还是现在的sensor
SAMPLE_COMM_VI_StartIspAndVi
SAMPLE_COMM_ISP_Init(2)配置传感器并且进行信号处理,包括宽动态模式
sensor_register_callback 注册回调函数,这个函数ar0130_cmos.c与ov9712_cmos.c中都有
sensor_register_callback //ar0130_cmos.c
cmos_init_sensor_exp_function(&stIspRegister.stSnsExp);
sensor_init() //这个以及下面的函数均在ar0130_sensor_ctl.c
sensor_init_720p_30fps();
sensor_write_register() //通过IIC进行通信发送控制信号
#ifdef HI_GPIO_I2C //是否使用软件IIC,通过GPIO进行模拟
ret = ioctl(g_fd, GPIO_I2C_WRITE, &i2c_data);
sensor_i2c_init //使用硬件IIC则调用该函数
g_fd = open("/dev/i2c-0", O_RDWR);
ret = ioctl(g_fd, I2C_SLAVE_FORCE, sensor_i2c_addr);
(2)xxxx_cmos.c中定义回调和上层函数,是应用层和驱动层的接口
sensor_register_callback
HI_MPI_ISP_SensorRegCallBack Sensor 注册 ISP 库
cmos_init_ae_exp_function
HI_MPI_AE_SensorRegCallBack Sensor 注册 AE 算法库
cmos_init_awb_exp_function
HI_MPI_AWB_SensorRegCallBack Sensor 注册 AWB 算法库
(3)xxxx_sensor_ctl.c中定义底层硬件相关的寄存器值配置函数
(4)kernel中的I2C驱动提供i2c层面的物理层操作接口
回调函数就是允许用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。
Hi3518EV200_ISP_3A 版本依赖于相应的 SDK 大版本,通过一系列数字图像处理算法完成对数字图像的效果处理。主要包含 Firmware 框架及海思 3A 库, Firmware 提供算法的基本框架,处理统计信息,驱动数字图像处理算法,并包含坏点校正、去噪、色彩增强、镜头阴影校正等处理。 3A 库以注册的方式,添加到 Firmware 中,完成曝光、白平衡、色彩还原等处理。
知识补充:3A是那三个?
AE 自动曝光:光圈优先AE式是由拍摄者人为选择拍摄时的光圈大小,由相机根据景物亮
度、CCD感光度以及人为选择的光圈等信息自动选择合适曝光所要求的快门时间的自动曝光模
式,也即光圈手动、快门时间自动的曝光方式。这种曝光方式主要用在需优先考虑景深的拍摄
场合,如拍摄风景、肖像或微距摄影等。
AF 自动对焦:是利用物体光反射的原理,将反射的光被相机上的传感器CCD接受,通过计
算机处理,带动电动对焦装置进行对焦的方式叫自动对焦。它多分为二类:一是主动式,另一
个则是被动式。
AWB 自动白平衡:通常为数码相机的默认设置,相机中有一结构复杂的矩形图,它可决定
画面中的白平衡基准点,以此来达到白平衡调校。这种自动白平衡的准确率是非常高的,但是
在光线不足条件下下拍摄时,效果较差,例如多云天气下,许多自动白平衡系统的效果极差,
它可能会导致偏蓝。
海思SDK:
HiISP AE 模块实现的功能是:根据自动测光系统获得当前图像的曝光量,再自动配置
镜头光圈、 sensor 快门及增益来获得最佳的图像质量。
海思 AF 算法没有实现具体算法,只实现了一个注册框架,示例和 AE 算法库注册类
似。用户需要在自开发定制的 AF 库中实现以下回调函数:
AWB 算法的功能是降低外界光源对物体真实颜色的影响,使得我们采集的颜色信息转变
为在理想日光光源下的无偏色信息。
Hi3518E V200R001C01SPC030\01.software\board\document_cn\ HiISP 开发参考.pdf
Hi3518E V200R001C01SPC030\01.software\board\document_cn\ ISP_3A开发指南.pdf
ISP Firmware 的文件组织结构如图 1-2 所示, ISP 库和 3A 库、 sensor 库、 iniparser 库、defog 库分别独立。 Firmware 中的 drv 生成的驱动程序向用户态上报 ISP 中断,并以该中断驱动 Firmware 的 ISP 控制单元运转。 ISP 控制单元从驱动程序中获取统计信息,并调度基础算法单元和 3A 算法库,最后通过驱动程序配置寄存器。Src 文件夹中包含 ISP 控制单元和基础算法单元,编译后生成 libisp.a,即 ISP 库。 3a文件夹中包含 AE/AWB/AF 算法库,用户也可以基于统一的接口界面开发自己的 3a 算法。 Sensor 文件夹中包含了各个 sensor 的驱动程序,该部分代码开源。 hi_cmoscfg 文件夹中包含解析 ini 文件所需的公共程序,该部分代码开源。 iniparser 文件夹包含 ini解析函数库,也可用于其它应用开发。 defog 文件对应去雾算法程序,该部分代码不开源。
Firmware 内部流程分两部分,如图 1-3 所示。一部分是初始化任务,主要完成 ISP 控制单元的初始化、 ISP 基础算法库的初始化、 3A 算法库的初始化,包括调用 sensor 的回调获取 sensor 差异化的初始化参数;另一部分是动态调节过程,在这个过程中,firmware 中的 ISP 控制单元调度 ISP 基础算法库和 3A 算法库,实时计算并进行相应控制。
ISP 作为前端采集部分,需要和视频采集单元( VIU)协同工作。 ISP 初始化和基本配置完成后,需要 VIU 进行接口时序匹配。一是为了匹配不同 sensor 的输入时序,二是为 ISP 配置正确的输入时序。待时序配置完成后, ISP 就可以启动 Run 来进行动态图像质量调节。此时输出的图像被 VIU 采集,进而送去显示或编码。软件使用流程如图1-5 示:
如果用户调试好图像效果后,可以使用 PQ Tools 工具提供的配置文件保存功能进行配置参数保存。在下次启动时系统可以使用 PQ Tools 工具提供的配置文件加载功能加载已经调节好的图像参数。
更多细节请阅读文档《ISP_3A开发指南.pdf》
int sensor_register_callback(void)
{
ISP_DEV IspDev = 0;
HI_S32 s32Ret;
ALG_LIB_S stLib;
ISP_SENSOR_REGISTER_S stIspRegister;
AE_SENSOR_REGISTER_S stAeRegister;
AWB_SENSOR_REGISTER_S stAwbRegister;
cmos_init_sensor_exp_function(&stIspRegister.stSnsExp);
s32Ret = HI_MPI_ISP_SensorRegCallBack(IspDev, AR0130_ID, &stIspRegister);
if (s32Ret)
{
printf("sensor register callback function failed!\n");
return s32Ret;
}
stLib.s32Id = 0;
strncpy(stLib.acLibName, HI_AE_LIB_NAME, sizeof(HI_AE_LIB_NAME));
cmos_init_ae_exp_function(&stAeRegister.stSnsExp);
s32Ret = HI_MPI_AE_SensorRegCallBack(IspDev, &stLib, AR0130_ID, &stAeRegister);
if (s32Ret)
{
printf("sensor register callback function to ae lib failed!\n");
return s32Ret;
}
stLib.s32Id = 0;
strncpy(stLib.acLibName, HI_AWB_LIB_NAME, sizeof(HI_AWB_LIB_NAME));
cmos_init_awb_exp_function(&stAwbRegister.stSnsExp);
s32Ret = HI_MPI_AWB_SensorRegCallBack(IspDev, &stLib, AR0130_ID, &stAwbRegister);
if (s32Ret)
{
printf("sensor register callback function to awb lib failed!\n");
return s32Ret;
}
return 0;
}
Sensor 注册 AE 算法库调用 HI_MPI_AE_SensorRegCallBack
Sensor 注册 AWB 算法库调用 HI_MPI_AWB_SensorRegCallBack
Sensor 注册 AF 算法库调用 HI_MPI_AF_SensorRegCallBack, AF 库暂未实现
AE 算法注册 ISP 库调用 HI_MPI_ISP_AeLibRegCallBack,海思 AE 算法实现了一个
HI_MPI_AE_Register 的注册函数,在这个函数中调用 ISP 提供的 HI_MPI_ISP_AeLibRegCallBack
回调接口,用户调用注册函数以实现向 ISP 注册AE 算法。
AWB、AF算法注册ISP库的方式与AE类似,分别调用HI_MPI_AF_Register、
HI_MPI_AWB_Register函数。
HI_S32 cmos_init_sensor_exp_function(ISP_SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
memset(pstSensorExpFunc, 0, sizeof(ISP_SENSOR_EXP_FUNC_S));
pstSensorExpFunc->pfn_cmos_sensor_init = sensor_init;
pstSensorExpFunc->pfn_cmos_sensor_exit = sensor_exit;
pstSensorExpFunc->pfn_cmos_sensor_global_init = sensor_global_init;
pstSensorExpFunc->pfn_cmos_set_image_mode = cmos_set_image_mode;
pstSensorExpFunc->pfn_cmos_set_wdr_mode = cmos_set_wdr_mode;
pstSensorExpFunc->pfn_cmos_get_isp_default = cmos_get_isp_default;
pstSensorExpFunc->pfn_cmos_get_isp_black_level = cmos_get_isp_black_level;
pstSensorExpFunc->pfn_cmos_set_pixel_detect = cmos_set_pixel_detect;
pstSensorExpFunc->pfn_cmos_get_sns_reg_info = cmos_get_sns_regs_info;
return 0;
}
cmos_init_sensor_exp_function
pstSensorExpFunc->pfn_cmos_get_isp_black_level = cmos_get_isp_black_level;
黑电平(black level)指在经过一定校准的显示装置上,没有一行光亮输出的视频信号电平。定义图像数据为0时对应的信号电平,调节黑电平不影响信号的放大倍数,而仅仅是对信号进行上下平移。如果向上调节黑电平,图像将变暗,如果向下调节黑电平图像将变亮。黑电平为0时,对应0V以下的电平都转换为图像数据0,0V以上的电平则按照增益定义的放大倍数转换,最大数值为255。
HI_U32 cmos_get_isp_black_level(ISP_CMOS_BLACK_LEVEL_S *pstBlackLevel)
{
HI_S32 i;
if (HI_NULL == pstBlackLevel)
{
printf("null pointer when get isp black level value!\n");
return -1;
}
/* Don't need to update black level when iso change */
pstBlackLevel->bUpdate = HI_FALSE;
switch (genSensorMode)
{
default :
case WDR_MODE_NONE :
for (i=0; i<4; i++)
{
pstBlackLevel->au16BlackLevel[i] = 0xC8;
}
break;
}
return 0;
}
(1)修改驱动源码(可以修改黑电平的值进行试验,比如0xC8改为0x00,观察改变前后的效果,我们可以把摄像头换成ar0130进行试验,我们上边分析的代码也是以其为主,当然使用ov9712也可以,二者代码与设置操作类似,当然换回摄像头也要机进行一定的配置,可参考上篇文章是如何将摄像头更换为ov9712的)
(2)清除,并重新编译
在ISP文件夹下执行,make clean, make
(3)确认mpp中lib目录下的libsnsxxx.a/so已经被更新
(4)重新编译sample/venc中的例程并运行查看效果
(1)sensor内部有若干寄存器,可以通过I2C接口来读写
(2)数据手册有对寄存器的基本说明
数据手册下载链接:
链接:https://pan.baidu.com/s/1rQA1lmLOBpmkkMI6jK5YUQ
提取码:sjey
–来自百度网盘超级会员V5的分享
(3)经验:大部分寄存器设置厂家会给,偶尔需要自己调一些
int sensor_write_register(int addr, int data)
{
#ifdef HI_GPIO_I2C
i2c_data.dev_addr = sensor_i2c_addr;
i2c_data.reg_addr = addr;
i2c_data.addr_byte_num = sensor_addr_byte;
i2c_data.data = data;
i2c_data.data_byte_num = sensor_data_byte;
ret = ioctl(g_fd, GPIO_I2C_WRITE, &i2c_data);
if (ret)
{
printf("GPIO-I2C write faild!\n");
return ret;
}
#else
if(flag_init == 0)//第一次进入时需要初始化,第二次就不需要了
{
sensor_i2c_init();
flag_init = 1;
}
int idx = 0;
int ret;
char buf[8];
buf[idx++] = addr & 0xFF;
if (sensor_addr_byte == 2)//16位的地址
{
ret = ioctl(g_fd, I2C_16BIT_REG, 1);
buf[idx++] = addr >> 8;
}
else
{
ret = ioctl(g_fd, I2C_16BIT_REG, 0);
}
if (ret < 0)
{
printf("CMD_SET_REG_WIDTH error!\n");
return -1;
}
buf[idx++] = data;
if (sensor_data_byte == 2)//16位的数据
{
ret = ioctl(g_fd, I2C_16BIT_DATA, 1);
buf[idx++] = data >> 8;
}
else
{
ret = ioctl(g_fd, I2C_16BIT_DATA, 0);
}
if (ret)
{
printf("hi_i2c write faild!\n");
return -1;
}
ret = write(g_fd, buf, idx);
if(ret < 0)
{
printf("I2C_WRITE error!\n");
return -1;
}
#endif
return 0;
}
(1)查sensor数据手册的寄存器列表
(2)改sensor驱动代码
ar0130_sensor_ctl.c的源码中并未进行这个设置(应该有个默认的设置在),我们可以自己添加进行试验:
(3)重新编译isp
(4)确认sensor库已经更新到mpp中
(5)重新编译sample/venc中的例程,运行测试
未flip时(即未修改时):
flip时:
可以看出发生了变化,灯的位置从图片上边变到了下边。
(1)成熟的商业解决方案都是一整套设计好的模式
(2)第一步是理解,第二步是用起来,第三步是小修改,第四步是大修改,第五步是创造
(1)搞清楚sensor的本质:光电转换+AD+ISP+并口/MIPI/LVDS
(2)ISP有多种实现:sensor内置、主SoC内置(如我们使用的HI3518E)、外接专用ISP芯片
(3)3A是为最终图像效果负责的,3A的实现有赖于镜头、sensor、isp等各部门协同工作
(4)海思的体系中把sensor和3A、ISP实现为:指针挂接注册的各自独立模块
(1)sensor的各种参数
(2)其他几种sensor的驱动和对比实现
(3)isp的firmware
(4)3A算法相关知识(一般都不会提供源码)
注:本资料大部分由朱老师物联网大讲堂课程笔记整理而来,也参考了华为海思SDK中提供的开发手册,并且引用了部分网络文章,如有侵权,联系删除!水平有限,如有错误,欢迎各位在评论区交流。