完成初始化序列配置
配置初始化序列,建议参考版本发布包里面的Sensor驱动,以便于快速开发。为了方便调试,此时要排除AE配置及帧率配置的干扰,建议暂时空实现驱动中cmos_get_sns_regs_info函数。
- 准备Sensor驱动
- 依据sensor datasheet 或基于一款规格相近 Sensor(master/slave, i2c/spi, wdr/linear)驱动修改,尝试编译出 Sensor 库。具体可参看xxx_cmos.c(主要实现ISP需要的回调函数,包括ISP、AE、AWB等)、xxx_cmos.h 和 xxx_sensor_ctl.c(主要实现Sensor的读写初始化)文件进行修改,
- 申明并初始化对应的Sensor实例
hi_isp_sns_obj g_sns_xxx_obj = { .pfn_register_callback = sensor_register_callback, .pfn_un_register_callback = sensor_unregister_callback, .pfn_standby = xxx_standby, .pfn_restart = xxx_restart, .pfn_write_reg = xxx_write_register, .pfn_read_reg = xxx_read_register, .pfn_set_bus_info = xxx_set_bus_info, .pfn_set_init = sensor_set_init };
其中hi_isp_sns_obj 结构体可以由用户增加或减少对应的函数及功能,目前的实现为:
typedef struct { hi_s32 (*pfn_register_callback)(hi_vi_pipe vi_pipe, hi_isp_3a_alg_lib *ae_lib, hi_isp_3a_alg_lib *awb_lib); hi_s32 (*pfn_un_register_callback)(hi_vi_pipe vi_pipe, hi_isp_3a_alg_lib *ae_lib, hi_isp_3a_alg_lib *awb_lib); hi_s32 (*pfn_set_bus_info)(hi_vi_pipe vi_pipe, hi_isp_sns_commbus sns_bus_info); hi_void (*pfn_standby)(hi_vi_pipe vi_pipe); hi_void (*pfn_restart)(hi_vi_pipe vi_pipe); hi_void (*pfn_mirror_flip)(hi_vi_pipe vi_pipe, hi_isp_sns_mirrorflip_type sns_mirror_flip); hi_s32 (*pfn_write_reg)(hi_vi_pipe vi_pipe, hi_u32 addr, hi_u32 data); hi_s32 (*pfn_read_reg)(hi_vi_pipe vi_pipe, hi_u32 addr); hi_s32 (*pfn_set_init)(hi_vi_pipe vi_pipe, hi_isp_init_attr *init_attr); } hi_isp_sns_obj;
- 实现ISP回调函数指针注册,并依据需要实现部分函数或者设置为NULL,具体函数功能及说明请参见《CANN AscendCL应用软件开发指南(C&C++)》,本节主要实现Sensor初始化.
static hi_s32 cmos_init_ae_exp_function(hi_isp_ae_sensor_exp_func *pstExpFuncs) { memset_s(pstExpFuncs, sizeof(hi_isp_ae_sensor_exp_func), 0, sizeof(hi_isp_ae_sensor_exp_func)); 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; pstExpFuncs->pfn_cmos_dgain_calc_table = cmos_dgain_calc_table; pstExpFuncs->pfn_cmos_get_inttime_max = cmos_get_inttime_max; pstExpFuncs->pfn_cmos_ae_fswdr_attr_set = cmos_ae_fswdr_attr_set; pstExpFuncs->pfn_cmos_ae_quick_start_status_set = cmos_ae_quick_start_status_set; pstExpFuncs->pfn_cmos_exp_param_convert = cmos_exp_param_convert; return HI_SUCCESS; } static hi_s32 cmos_init_awb_exp_function(hi_isp_awb_sensor_exp_func *pstExpFuncs) { memset_s(pstExpFuncs, sizeof(hi_isp_awb_sensor_exp_func), 0, sizeof(hi_isp_awb_sensor_exp_func)); pstExpFuncs->pfn_cmos_get_awb_default = cmos_get_awb_default; pstExpFuncs->pfn_cmos_get_awb_spec_default = cmos_get_awb_spec_default; return HI_SUCCESS; } static hi_s32 cmos_init_sensor_exp_function(hi_isp_sensor_exp_func *pstSensorExpFunc) { memset_s(pstSensorExpFunc, sizeof(hi_isp_sensor_exp_func), 0, sizeof(hi_isp_sensor_exp_func)); pstSensorExpFunc->pfn_cmos_sensor_init = xxx_init; pstSensorExpFunc->pfn_cmos_sensor_exit = xxx_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 HI_SUCCESS; } static hi_u32 sensor_register_callback(hi_vi_pipe viPipe, hi_isp_3a_alg_lib *pstAeLib, hi_isp_3a_alg_lib *pstAwbLib, hi_isp_3a_alg_lib *pstAfLib) { hi_isp_sensor_register stIspRegister; hi_isp_ae_sensor_register stAeRegister; hi_isp_awb_sensor_register stAwbRegister; hi_isp_sns_attr_info stSnsAttrInfo; sensor_ctx_init(viPipe); stSnsAttrInfo.sensor_id = xxx_ID; cmos_init_sensor_exp_function(&stIspRegister.sns_exp); hi_mpi_isp_sensor_reg_callback(viPipe, &stSnsAttrInfo, &stIspRegister); cmos_init_ae_exp_function(&stAeRegister.sns_exp); hi_mpi_ae_sensor_reg_callback(viPipe, pstAeLib, &stSnsAttrInfo, &stAeRegister); cmos_init_awb_exp_function(&stAwbRegister.sns_exp); hi_mpi_awb_sensor_reg_callback(viPipe, pstAwbLib, &stSnsAttrInfo, &stAwbRegister); return HI_SUCCESS; }
- 实现Sensor对寄存器操作
- 查阅Sensor手册了解Sensor寄存器配置方式并确认Sensor与芯片的硬件连接通信总线号。如I2C类Sensor需确认Sensor与芯片连接的I2C总线号,Sensor的I2C从地址等;如SPI类Sensor需确认Sensor与芯片连接的SPI总线号、片选号以及Sensor的传输芯片ID号等信息。
- 实现I2C或SPI接口的初始化,以及寄存器写函数
- 在xxx_sensor_ctl.c中实现Sensor的i2c接口初始化函数,指定对应的i2c总线号及i2c设备从地址并初始化对应的i2c接口。如:
static hi_s32 g_fd[ISP_MAX_PIPE_NUM] = {[0 ... (ISP_MAX_PIPE_NUM -1)] = -1}; int xxx_i2c_init(VI_PIPE vi_pipe) { char acDevFile[I2C_DEV_FILE_NUM] = {0}; hi_u8 u8DevNum;// i2c 总线号 hi_u8 xxx_I2C_ADDR; // sensor 7位 i2c 从地址 snprintf_s(acDevFile, sizeof(acDevFile), sizeof(acDevFile) - 1, "/dev/i2c-%u", u8DevNum); g_fd[vi_pipe] = open(acDevFile, O_RDWR, S_IRUSR | S_IWUSR); ioctl(g_fd[vi_pipe], I2C_SLAVE_FORCE, (xxx_I2C_ADDR >> 1)); return HI_SUCCESS; }
- 在xxx_sensor_ctl.c中实现通过I2C实现对Sensor寄存器写操作。如:
#define xxx_ADDR_BYTE 2 // i2c 发送寄存器长度 #define xxx_DATA_BYTE 1 // i2c 发送数据长度 int xxx_write_register(VI_PIPE vi_pipe, HI_U32 addr, HI_U32 data) { HI_U32 idx = 0; HI_U8 buf[I2C_BUF_NUM]; if (xxx_ADDR_BYTE == 2) { /* 2 byte */ buf[idx] = (addr >> 8) & 0xff; /* shift 8 */ idx++; } buf[idx] = addr & 0xff; idx++; buf[idx] = data & 0xff; idx++; write(g_fd[vi_pipe], buf, xxx_ADDR_BYTE + xxx_DATA_BYTE); return HI_SUCCESS; }
- 在xxx_sensor_ctl.c中实现Sensor的i2c接口初始化函数,指定对应的i2c总线号及i2c设备从地址并初始化对应的i2c接口。如:
- 对于spi类型的Sensor
- 在xxx_sensor_ctl.c中实现Sensor的spi接口初始化函数,指定对应的spi总线并初始化对应的spi接口。如:
static hi_s32 g_fd[ISP_MAX_PIPE_NUM] = {[0 ... (ISP_MAX_PIPE_NUM -1)] = -1}; int xxx_spi_init(VI_PIPE vi_pipe) { HI_U8 u8DevNum; // Sensor 对应的spi总线号 hi_u8 u8CS; // Sensor 对应的spi片选号 char spi_device[DEV_FILE_NUM] = {0}; // 打开SPI设备 snprintf_s(spi_device, sizeof(spi_device), sizeof(spi_device) - 1, "/dev/spidev%u.%u", u8DevNum, u8CS); g_fd[vi_pipe] = open(spi_device, O_RDWR, S_IRUSR | S_IWUSR); // 配置SPI工作模式 staticchar mode; mode |= SPI_CPOL; mode |= SPI_CPHA; mode |= SPI_LSB_FIRST; staticchar bpw = 8; staticint speed = 200000; ioctl(g_fd[vi_pipe], SPI_IOC_WR_MODE, &mode); ioctl(g_fd[vi_pipe], SPI_IOC_WR_BITS_PER_WORD, &bpw); ioctl(g_fd[vi_pipe], SPI_IOC_WR_MAX_SPEED_HZ, &speed); return HI_SUCCESS; }
- 在xxx_sensor_ctl.c中实现通过spi实现对Sensor寄存器写操作。如:
int xxx_write_register(VI_PIPE vi_pipe, HI_U32 addr, HI_U32 data) { char tx[4] = {0}; tx[0] = 0xXX; // SPI Chip ID tx[1] = (char)((addr & 0xff00) >> 8) ; // Register Address tx[2] = (char)(addr & 0xff); // Register Address tx[3] = (char)data; // Register Data staticchar bpw = 8; staticint speed = 200000; struct spi_ioc_transfer trans[1]; memset_s(&trans[0], sizeof(trans[0]), 0, sizeof(trans[0])); trans[0].tx_buf = (unsigned long)tx, trans[0].len = 4, trans[0].speed_hz = speed, trans[0].bits_per_word = bpw, ioctl(g_fd[vi_pipe], SPI_IOC_MESSAGE(1), trans); return HI_SUCCESS; }
- 在xxx_sensor_ctl.c中实现Sensor的spi接口初始化函数,指定对应的spi总线并初始化对应的spi接口。如:
- 在xxx_sensor_ctl.c中实现Sensor 初始化序列
- 实现 void pfn_cmos_sensor_init函数。参考 Sensor 手册或者 Sensor 厂家提供的 Sensor 序列实现这个函数。对于从模式 Sensor,在 pfn_cmos_sensor_init函数中需要调用hi_mpi_isp_set_sns_slave_attr /hi_mpi_isp_get_sns_slave_attr接口来实现从模式参数的适配,相关接口及结构体说明见应用开发指南。如:
void xxx_init(VI_PIPE vi_pipe) { // 调用i2c或者spi初始化函数 xxx_i2c_init(vi_pipe);/xxx_spi_init(vi_pipe); // 如果是工作在从模式的Sensor, 需要配置对应的行场同步信号 hi_u8 SlaveDev; hi_isp_slave_sns_sync sns_sync; hi_mpi_isp_get_sns_slave_attr(SlaveDev, sns_sync); // 配置需要的sns_sync属性 hi_mpi_isp_set_sns_slave_attr(SlaveDev, sns_sync); // 根据需要的Sensor工作状态配置初始化寄存器 xxx_write_register(vi_pipe, address, value); ... return; }
- 实现 void pfn_cmos_sensor_init函数。参考 Sensor 手册或者 Sensor 厂家提供的 Sensor 序列实现这个函数。对于从模式 Sensor,在 pfn_cmos_sensor_init函数中需要调用hi_mpi_isp_set_sns_slave_attr /hi_mpi_isp_get_sns_slave_attr接口来实现从模式参数的适配,相关接口及结构体说明见应用开发指南。如:
父主题: 采集图像