什么是sensor :光电转换+AD+ISP+并口/MIPI/LVDS
sensor是一个很多功能的集合,sensor可以实现光电转换,将光信号转化成模拟量的电信号,然后经过AD模块,将模拟量的电信号转化成数字量的电信号,一般来说sensor内部还有一个isp单元,它将刚转出来的数字信号做一些简单的处理,将处理过后的信息通过sensor的接口(有三种接口分别是并口/MIPI/LVDS,接口的功能与区别将见。。。。。。。。)传入到与之相连的主SOC。
在海思的MPP系统里面已经事先规定好了sensor要实现什么功能,并且已经定义好了所有的功能函数名字以及函数原型,这些函数的实体就是要在具体的sensor提供,并且不同的sensor驱动中的函数名与函数原型都是一样的,因为MPP系统中已经定义好了并且在一些地方调用。所以要实现MPP与具体sensor驱动的挂接的方法就是使用注册回调的机制,这个注册接口函数就是sensor_register_callback(void),
函数层次调用关系
/******************************************
step 3: start vi dev & chn to capture
******************************************/
SAMPLE_COMM_VI_StartVi
SAMPLE_COMM_VI_StartIspAndVi
SAMPLE_COMM_ISP_Init
sensor_register_callback
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注册ISP库。*/
/**下面是挂接的具体的函数实体,这些函数的实体是在***Hi3518E_SDK_V1.0.3.0\package\mpp\component\isp\sensor目录这个目录中包含了mpp支持的所有**sensor的驱动,这些驱动实现了对硬件的实质操作
**/
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;
}
/*Sensor 注册 AWB 算法库*/
/*下面是挂接的具体的函数实体,实现了对硬件的实质操作*/
HI_S32 cmos_init_ae_exp_function(AE_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
memset(pstExpFuncs, 0, sizeof(AE_SENSOR_EXP_FUNC_S));
pstExpFuncs->pfn_cmos_get_ae_default = cmos_get_ae_default;
pstExpFuncs->pfn_cmos_fps_set = cmos_fps_set;
pstExpFuncs->pfn_cmos_slow_framerate_set= cmos_slow_framerate_set;
pstExpFuncs->pfn_cmos_inttime_update = cmos_inttime_update;
pstExpFuncs->pfn_cmos_gains_update = cmos_gains_update;
pstExpFuncs->pfn_cmos_again_calc_table = cmos_again_calc_table;
return 0;
}
/*Sensor 注册 AF 算法库调用 HI_MPI_AF_SensorRegCallBack, AF 库暂未实现*/
/*下面是挂接的具体的函数实体,实现了对硬件的实质操作*/
HI_S32 cmos_init_awb_exp_function(AWB_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
memset(pstExpFuncs, 0, sizeof(AWB_SENSOR_EXP_FUNC_S));
pstExpFuncs->pfn_cmos_get_awb_default = cmos_get_awb_default;
return 0;
}
ISP Firmware 的文件组织结构如图所示, 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 文件对应去雾算法程序,该部分代码不开
源。
Hi3518EV200_ISP_3A 版本依赖于相应的 SDK 大版本,通过一系列数字图像处理算法完成对数字图像的效果处理。主要包含 Firmware 框架及海思 3A 库, Firmware 提供算法的基本框架,处理统计信息,驱动数字图像处理算法,并包含坏点校正、去噪、色彩增强、镜头阴影校正等处理。 3A 库以注册的方式,添加到 Firmware 中,完成曝光、白平衡、色彩还原等处理。
ISP 通过一系列数字图像处理算法完成对数字图像的效果处理。主要包括 3A、坏点校正、去噪、强光抑制、背光补偿、色彩增强、镜头阴影校正等处理
ISP 由 ISP 逻辑及运行在其上的 Firmware 组成,逻辑单元除了完成一部分算法处理外,还可以统计出当前图像的实时信息。 Firmware 通过获取 ISP 逻辑的图像统计信息,重新计算,反馈控制 lens、 sensor 和 ISP 逻辑,以达到自动调节图像质量的目的。
ISP 的 Firmware 包含三部分:
Firmware 设计的基本思想是单独提供 3A 算法库,由 ISP 控制单元调度基础算法单元和 3A 算法库,同时 sensor 库分别向ISP 库和 3A 算法库注册函数回调,以实现差异化的 sensor 适配。 ISP firmware 设计思路如图所示。
不同的 sensor 都向 ISP 库和 3A 算法库注册控制函数,这些函数都以回调函数的形式存在。 ISP 控制单元调度基础算法单元和 3A 算法库时,将通过这些回调函数获取初始化参数,并控制 sensor,如调节曝光时间、模拟增益、数字增益,控制 lens 步进聚焦或旋转光圈等。
注意:Sensor 3A只是为3A lib 提供最基本的操作,而不是一个完整的3A算法。
首先完成 Firmware 控制单元的初始化、基础算法单元的初始化、 3A 算法库的初始化,包括调用 sensor 的回调获取 sensor 差异化的初始
化参数。当初始化完成之后, Firmware 由中断驱动,每帧从内核态获取统计信息,并驱动基础算法单元和 3A 算法库完成计算,并反馈计算结果,配置 ISP 寄存器和 sensor寄存器。
同时用户可以通过 ISP 的 MPI,控制和改变 Firmware 中包含的基础算法单元的内部数据和状态,定制自己的图像质量效果。如果用户使用海思提供的 3A 算法库,可以通过3A 算法库的 MPI,改变 3A 算法库的内部数据和状态,调节曝光、白平衡和色彩还原。
ISP 作为图像前处理部分,需要和视频采集单元(VIU)协同工作。 ISP 初始化和基本配置完成后,需要 VIU 进行接口时序匹配。一是为了匹配不同 sensor 的输入时序,二是为 ISP 配置正确的输入时序。待时序配置完成后, ISP 就可以启动 Run 来进行动态图像质量调节。此时输出的图像被 VIU 采集,进而送去显示或编码。软件使用流程如图所示。
示例代码:
SAMPLE_COMM_ISP_Init()
{
HI_S32 s32Ret;
ALG_LIB_S stLib;
ISP_PUB_ATTR_S stPubAttr;
pthread_t isp_pid;
/* 注册sensor库 */
s32Ret = sensor_register_callback();
if (HI_SUCCESS != s32Ret)
{
printf(”register sensor failed!\n”);
return s32Ret;
}
/* 注册海思AE算法库 */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AE_LIB_NAME);
s32Ret = HI_MPI_AE_Register(&stLib);
if (HI_SUCCESS != s32Ret)
{
printf(”register ae lib failed!\n”);
return s32Ret;
}
/* 注册海思AWB算法库 */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AWB_LIB_NAME);
s32Ret = HI_MPI_AWB_Register(&stLib);
if (HI_SUCCESS != s32Ret)
{
printf(”register awb lib failed!\n”);
return s32Ret;
}
/* 注册海思AF算法库 */
stLib.s32Id = 0;
strcpy(stLib.acLibName, HI_AF_LIB_NAME);
s32Ret = HI_MPI_AF_Register(&stLib);
if (HI_SUCCESS != s32Ret)
{
printf(”register af lib failed!\n”);
return s32Ret;
}
/* 初始化ISP外部寄存器 */
s32Ret = HI_MPI_ISP_MemInit(IspDev);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_ISP_Init failed!\n", __FUNCTION__);
return s32Ret;
}
/* 配置ISP宽动态模式 */
ISP_WDR_MODE_S stWdrMode;
stWdrMode.enWDRMode = enWDRMode;
s32Ret = HI_MPI_ISP_SetWDRMode(0, &stWdrMode);
if (HI_SUCCESS != s32Ret)
{
printf("start ISP WDR failed!\n");
return s32Ret;
}
/* 配置图像公共属性 */
s32Ret = HI_MPI_ISP_SetPubAttr(IspDev, &stPubAttr);
if (s32Ret != HI_SUCCESS)
{
printf("%s: HI_MPI_ISP_SetPubAttr failed with %#x!\n", __FUNCTION__,
s32Ret);
return s32Ret;
}
/* 初始化ISP Firmware */
s32Ret = HI_MPI_ISP_Init();
if (HI_SUCCESS != s32Ret)
{
printf(”isp init failed!\n”);
return s32Ret;
}
/* 启动VI/VO等业务 */
……
/* 停止VI/VO等业务 */
s32Ret = HI_MPI_ISP_Exit();
if (HI_SUCCESS != s32Ret)
{
printf(”isp exit failed!\n”);
return s32Ret;
}
pthread_join(isp_pid, 0);
return HI_SUCCESS;
}
SAMPLE_COMM_ISP_Run()
{
...
/* HI_MPI_ISP_Run单独启动线程运行 */
if (0 != pthread_create(&isp_pid, 0, ISP_Run, NULL))
{
printf("create isp running thread failed!\n");
return HI_FAILURE;
}
}